From 3e0dd820f07f264d904690295e72e63c90b7be85 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:17:51 +0300 Subject: ath10k: htc: made static function public Changed ath10k_htc_notify_tx_completion and ath10k_htc_process_trailer from static to non static. These functions are needed by SDIO/mbox. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 14 ++++++++------ drivers/net/wireless/ath/ath10k/htc.h | 6 ++++++ 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index b7669b2e94aa..f3dbce6ea0da 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -57,8 +57,8 @@ static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc, skb_pull(skb, sizeof(struct ath10k_htc_hdr)); } -static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, - struct sk_buff *skb) +void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, + struct sk_buff *skb) { struct ath10k *ar = ep->htc->ar; @@ -75,6 +75,7 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, ep->ep_ops.ep_tx_complete(ep->htc->ar, skb); } +EXPORT_SYMBOL(ath10k_htc_notify_tx_completion); static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep, struct sk_buff *skb) @@ -230,10 +231,10 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc, spin_unlock_bh(&htc->tx_lock); } -static int ath10k_htc_process_trailer(struct ath10k_htc *htc, - u8 *buffer, - int length, - enum ath10k_htc_ep_id src_eid) +int ath10k_htc_process_trailer(struct ath10k_htc *htc, + u8 *buffer, + int length, + enum ath10k_htc_ep_id src_eid) { struct ath10k *ar = htc->ar; int status = 0; @@ -294,6 +295,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc, return status; } +EXPORT_SYMBOL(ath10k_htc_process_trailer); void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) { diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index 6ababa345e2b..f728ce7124cf 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -351,5 +351,11 @@ int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid, struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size); void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb); void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb); +void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, + struct sk_buff *skb); +int ath10k_htc_process_trailer(struct ath10k_htc *htc, + u8 *buffer, + int length, + enum ath10k_htc_ep_id src_eid); #endif -- cgit v1.2.3 From 680ebb4e797751e8ffb000d63feb96e7bc9e4dc3 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:17:52 +0300 Subject: ath10k: htc: rx trailer lookahead support The RX trailer parsing is now capable of parsing lookahead reports. A lookahead contains the first 4 bytes of the next HTC message (that will be read in the next SDIO read operation). Lookaheads are used by the SDIO/mbox HIF layer to determine if the next message is part of a bundle, which endpoint it belongs to and how long it is. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 95 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/htc.h | 30 +++++++++-- 2 files changed, 120 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index f3dbce6ea0da..0a06562c0d32 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -231,11 +231,78 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc, spin_unlock_bh(&htc->tx_lock); } +static int +ath10k_htc_process_lookahead(struct ath10k_htc *htc, + const struct ath10k_htc_lookahead_report *report, + int len, + enum ath10k_htc_ep_id eid, + void *next_lookaheads, + int *next_lookaheads_len) +{ + struct ath10k *ar = htc->ar; + + /* Invalid lookahead flags are actually transmitted by + * the target in the HTC control message. + * Since this will happen at every boot we silently ignore + * the lookahead in this case + */ + if (report->pre_valid != ((~report->post_valid) & 0xFF)) + return 0; + + if (next_lookaheads && next_lookaheads_len) { + ath10k_dbg(ar, ATH10K_DBG_HTC, + "htc rx lookahead found pre_valid 0x%x post_valid 0x%x\n", + report->pre_valid, report->post_valid); + + /* look ahead bytes are valid, copy them over */ + memcpy((u8 *)next_lookaheads, report->lookahead, 4); + + *next_lookaheads_len = 1; + } + + return 0; +} + +static int +ath10k_htc_process_lookahead_bundle(struct ath10k_htc *htc, + const struct ath10k_htc_lookahead_bundle *report, + int len, + enum ath10k_htc_ep_id eid, + void *next_lookaheads, + int *next_lookaheads_len) +{ + struct ath10k *ar = htc->ar; + int bundle_cnt = len / sizeof(*report); + + if (!bundle_cnt || (bundle_cnt > HTC_HOST_MAX_MSG_PER_BUNDLE)) { + ath10k_warn(ar, "Invalid lookahead bundle count: %d\n", + bundle_cnt); + return -EINVAL; + } + + if (next_lookaheads && next_lookaheads_len) { + int i; + + for (i = 0; i < bundle_cnt; i++) { + memcpy(((u8 *)next_lookaheads) + 4 * i, + report->lookahead, 4); + report++; + } + + *next_lookaheads_len = bundle_cnt; + } + + return 0; +} + int ath10k_htc_process_trailer(struct ath10k_htc *htc, u8 *buffer, int length, - enum ath10k_htc_ep_id src_eid) + enum ath10k_htc_ep_id src_eid, + void *next_lookaheads, + int *next_lookaheads_len) { + struct ath10k_htc_lookahead_bundle *bundle; struct ath10k *ar = htc->ar; int status = 0; struct ath10k_htc_record *record; @@ -275,6 +342,29 @@ int ath10k_htc_process_trailer(struct ath10k_htc *htc, record->hdr.len, src_eid); break; + case ATH10K_HTC_RECORD_LOOKAHEAD: + len = sizeof(struct ath10k_htc_lookahead_report); + if (record->hdr.len < len) { + ath10k_warn(ar, "Lookahead report too long\n"); + status = -EINVAL; + break; + } + status = ath10k_htc_process_lookahead(htc, + record->lookahead_report, + record->hdr.len, + src_eid, + next_lookaheads, + next_lookaheads_len); + break; + case ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE: + bundle = record->lookahead_bundle; + status = ath10k_htc_process_lookahead_bundle(htc, + bundle, + record->hdr.len, + src_eid, + next_lookaheads, + next_lookaheads_len); + break; default: ath10k_warn(ar, "Unhandled record: id:%d length:%d\n", record->hdr.id, record->hdr.len); @@ -362,7 +452,8 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) trailer += payload_len; trailer -= trailer_len; status = ath10k_htc_process_trailer(htc, trailer, - trailer_len, hdr->eid); + trailer_len, hdr->eid, + NULL, NULL); if (status) goto out; diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index f728ce7124cf..ae6003495649 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -50,6 +50,8 @@ struct ath10k; * 4-byte aligned. */ +#define HTC_HOST_MAX_MSG_PER_BUNDLE 8 + enum ath10k_htc_tx_flags { ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01, ATH10K_HTC_FLAG_SEND_BUNDLE = 0x02 @@ -174,8 +176,10 @@ struct ath10k_htc_msg { } __packed __aligned(4); enum ath10k_ath10k_htc_record_id { - ATH10K_HTC_RECORD_NULL = 0, - ATH10K_HTC_RECORD_CREDITS = 1 + ATH10K_HTC_RECORD_NULL = 0, + ATH10K_HTC_RECORD_CREDITS = 1, + ATH10K_HTC_RECORD_LOOKAHEAD = 2, + ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE = 3, }; struct ath10k_ath10k_htc_record_hdr { @@ -192,10 +196,28 @@ struct ath10k_htc_credit_report { u8 pad1; } __packed; +struct ath10k_htc_lookahead_report { + u8 pre_valid; + u8 pad0; + u8 pad1; + u8 pad2; + u8 lookahead[4]; + u8 post_valid; + u8 pad3; + u8 pad4; + u8 pad5; +} __packed; + +struct ath10k_htc_lookahead_bundle { + u8 lookahead[4]; +} __packed; + struct ath10k_htc_record { struct ath10k_ath10k_htc_record_hdr hdr; union { struct ath10k_htc_credit_report credit_report[0]; + struct ath10k_htc_lookahead_report lookahead_report[0]; + struct ath10k_htc_lookahead_bundle lookahead_bundle[0]; u8 pauload[0]; }; } __packed __aligned(4); @@ -356,6 +378,8 @@ void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep, int ath10k_htc_process_trailer(struct ath10k_htc *htc, u8 *buffer, int length, - enum ath10k_htc_ep_id src_eid); + enum ath10k_htc_ep_id src_eid, + void *next_lookaheads, + int *next_lookaheads_len); #endif -- cgit v1.2.3 From ea1a3ddf6273fec3e4d5299e7c9bcdcd612577b6 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:17:53 +0300 Subject: ath10k: htc: move htc ctrl ep connect to htc_init This patch moves the HTC ctrl service connect from htc_wait_target to htc_init. This is done in order to make sure the htc ctrl service is setup properly before hif_start is called. The reason for this is that we want the HTC ctrl service callback to be initialized before the target sends the HTC ready message. The ready message will always be transmitted on endpoint 0 (which is always assigned to the HTC control service) so it makes more sense if HTC control has been connected before the ready message is received. Since the service to pipe mapping is done as a part of the service connect, the get_default_pipe call is redundant and was removed. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 39 +++++++++++++++-------------------- 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 0a06562c0d32..04e355207a2d 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -590,8 +590,6 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) struct ath10k *ar = htc->ar; int i, status = 0; unsigned long time_left; - struct ath10k_htc_svc_conn_req conn_req; - struct ath10k_htc_svc_conn_resp conn_resp; struct ath10k_htc_msg *msg; u16 message_id; u16 credit_count; @@ -654,22 +652,6 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) return -ECOMM; } - /* setup our pseudo HTC control endpoint connection */ - memset(&conn_req, 0, sizeof(conn_req)); - memset(&conn_resp, 0, sizeof(conn_resp)); - conn_req.ep_ops.ep_tx_complete = ath10k_htc_control_tx_complete; - conn_req.ep_ops.ep_rx_complete = ath10k_htc_control_rx_complete; - conn_req.max_send_queue_depth = ATH10K_NUM_CONTROL_TX_BUFFERS; - conn_req.service_id = ATH10K_HTC_SVC_ID_RSVD_CTRL; - - /* connect fake service */ - status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp); - if (status) { - ath10k_err(ar, "could not connect to htc service (%d)\n", - status); - return status; - } - return 0; } @@ -879,8 +861,10 @@ int ath10k_htc_start(struct ath10k_htc *htc) /* registered target arrival callback from the HIF layer */ int ath10k_htc_init(struct ath10k *ar) { - struct ath10k_htc_ep *ep = NULL; + int status; struct ath10k_htc *htc = &ar->htc; + struct ath10k_htc_svc_conn_req conn_req; + struct ath10k_htc_svc_conn_resp conn_resp; spin_lock_init(&htc->tx_lock); @@ -888,10 +872,21 @@ int ath10k_htc_init(struct ath10k *ar) htc->ar = ar; - /* Get HIF default pipe for HTC message exchange */ - ep = &htc->endpoint[ATH10K_HTC_EP_0]; + /* setup our pseudo HTC control endpoint connection */ + memset(&conn_req, 0, sizeof(conn_req)); + memset(&conn_resp, 0, sizeof(conn_resp)); + conn_req.ep_ops.ep_tx_complete = ath10k_htc_control_tx_complete; + conn_req.ep_ops.ep_rx_complete = ath10k_htc_control_rx_complete; + conn_req.max_send_queue_depth = ATH10K_NUM_CONTROL_TX_BUFFERS; + conn_req.service_id = ATH10K_HTC_SVC_ID_RSVD_CTRL; - ath10k_hif_get_default_pipe(ar, &ep->ul_pipe_id, &ep->dl_pipe_id); + /* connect fake service */ + status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp); + if (status) { + ath10k_err(ar, "could not connect to htc service (%d)\n", + status); + return status; + } init_completion(&htc->ctl_resp); -- cgit v1.2.3 From fcd2113363ddf057224ddf03c1ec3713455eec4e Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:17:54 +0300 Subject: ath10k: htc: refactorization Code refactorization: Moved the code for ep 0 in ath10k_htc_rx_completion_handler to ath10k_htc_control_rx_complete. This eases the implementation of SDIO/mbox significantly since the ep_rx_complete cb is invoked directly from the SDIO/mbox hif layer. Since the ath10k_htc_control_rx_complete already is present (only containing a warning message) there is no reason for not using it (instead of having a special case for ep 0 in ath10k_htc_rx_completion_handler). Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 74 ++++++++++++++++------------------- 1 file changed, 34 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 04e355207a2d..15b805629336 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -464,42 +464,6 @@ void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb) /* zero length packet with trailer data, just drop these */ goto out; - if (eid == ATH10K_HTC_EP_0) { - struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data; - - switch (__le16_to_cpu(msg->hdr.message_id)) { - case ATH10K_HTC_MSG_READY_ID: - case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID: - /* handle HTC control message */ - if (completion_done(&htc->ctl_resp)) { - /* - * this is a fatal error, target should not be - * sending unsolicited messages on the ep 0 - */ - ath10k_warn(ar, "HTC rx ctrl still processing\n"); - complete(&htc->ctl_resp); - goto out; - } - - htc->control_resp_len = - min_t(int, skb->len, - ATH10K_HTC_MAX_CTRL_MSG_LEN); - - memcpy(htc->control_resp_buffer, skb->data, - htc->control_resp_len); - - complete(&htc->ctl_resp); - break; - case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE: - htc->htc_ops.target_send_suspend_complete(ar); - break; - default: - ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n"); - break; - } - goto out; - } - ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %pK\n", eid, skb); ep->ep_ops.ep_rx_complete(ar, skb); @@ -514,10 +478,40 @@ EXPORT_SYMBOL(ath10k_htc_rx_completion_handler); static void ath10k_htc_control_rx_complete(struct ath10k *ar, struct sk_buff *skb) { - /* This is unexpected. FW is not supposed to send regular rx on this - * endpoint. - */ - ath10k_warn(ar, "unexpected htc rx\n"); + struct ath10k_htc *htc = &ar->htc; + struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data; + + switch (__le16_to_cpu(msg->hdr.message_id)) { + case ATH10K_HTC_MSG_READY_ID: + case ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID: + /* handle HTC control message */ + if (completion_done(&htc->ctl_resp)) { + /* this is a fatal error, target should not be + * sending unsolicited messages on the ep 0 + */ + ath10k_warn(ar, "HTC rx ctrl still processing\n"); + complete(&htc->ctl_resp); + goto out; + } + + htc->control_resp_len = + min_t(int, skb->len, + ATH10K_HTC_MAX_CTRL_MSG_LEN); + + memcpy(htc->control_resp_buffer, skb->data, + htc->control_resp_len); + + complete(&htc->ctl_resp); + break; + case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE: + htc->htc_ops.target_send_suspend_complete(ar); + break; + default: + ath10k_warn(ar, "ignoring unsolicited htc ep0 event\n"); + break; + } + +out: kfree_skb(skb); } -- cgit v1.2.3 From 01d6fd6965eaf8d4b3aab681d30e77c53a834162 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:17:55 +0300 Subject: ath10k: various sdio related definitions Debug masks for SDIO HIF layer. Address definitions for SDIO/mbox based chipsets. Augmented struct host_interest with more members. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 3 ++ drivers/net/wireless/ath/ath10k/debug.h | 2 ++ drivers/net/wireless/ath/ath10k/hw.h | 53 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/targaddrs.h | 24 +++++++++++++ 4 files changed, 82 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index bf091514ecc6..8fc08a5043db 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -91,6 +91,7 @@ struct ath10k; enum ath10k_bus { ATH10K_BUS_PCI, ATH10K_BUS_AHB, + ATH10K_BUS_SDIO, }; static inline const char *ath10k_bus_str(enum ath10k_bus bus) @@ -100,6 +101,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) return "pci"; case ATH10K_BUS_AHB: return "ahb"; + case ATH10K_BUS_SDIO: + return "sdio"; } return "unknown"; diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 2368f47314ae..257d10985c6e 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -38,6 +38,8 @@ enum ath10k_debug_mask { ATH10K_DBG_WMI_PRINT = 0x00002000, ATH10K_DBG_PCI_PS = 0x00004000, ATH10K_DBG_AHB = 0x00008000, + ATH10K_DBG_SDIO = 0x00010000, + ATH10K_DBG_SDIO_DUMP = 0x00020000, ATH10K_DBG_ANY = 0xffffffff, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 5b1e90bb2a4d..d34272803fd7 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -863,6 +863,59 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw, #define QCA9887_EEPROM_ADDR_LO_MASK 0x00ff0000 #define QCA9887_EEPROM_ADDR_LO_LSB 16 +#define MBOX_RESET_CONTROL_ADDRESS 0x00000000 +#define MBOX_HOST_INT_STATUS_ADDRESS 0x00000800 +#define MBOX_HOST_INT_STATUS_ERROR_LSB 7 +#define MBOX_HOST_INT_STATUS_ERROR_MASK 0x00000080 +#define MBOX_HOST_INT_STATUS_CPU_LSB 6 +#define MBOX_HOST_INT_STATUS_CPU_MASK 0x00000040 +#define MBOX_HOST_INT_STATUS_COUNTER_LSB 4 +#define MBOX_HOST_INT_STATUS_COUNTER_MASK 0x00000010 +#define MBOX_CPU_INT_STATUS_ADDRESS 0x00000801 +#define MBOX_ERROR_INT_STATUS_ADDRESS 0x00000802 +#define MBOX_ERROR_INT_STATUS_WAKEUP_LSB 2 +#define MBOX_ERROR_INT_STATUS_WAKEUP_MASK 0x00000004 +#define MBOX_ERROR_INT_STATUS_RX_UNDERFLOW_LSB 1 +#define MBOX_ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00000002 +#define MBOX_ERROR_INT_STATUS_TX_OVERFLOW_LSB 0 +#define MBOX_ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00000001 +#define MBOX_COUNTER_INT_STATUS_ADDRESS 0x00000803 +#define MBOX_COUNTER_INT_STATUS_COUNTER_LSB 0 +#define MBOX_COUNTER_INT_STATUS_COUNTER_MASK 0x000000ff +#define MBOX_RX_LOOKAHEAD_VALID_ADDRESS 0x00000805 +#define MBOX_INT_STATUS_ENABLE_ADDRESS 0x00000828 +#define MBOX_INT_STATUS_ENABLE_ERROR_LSB 7 +#define MBOX_INT_STATUS_ENABLE_ERROR_MASK 0x00000080 +#define MBOX_INT_STATUS_ENABLE_CPU_LSB 6 +#define MBOX_INT_STATUS_ENABLE_CPU_MASK 0x00000040 +#define MBOX_INT_STATUS_ENABLE_INT_LSB 5 +#define MBOX_INT_STATUS_ENABLE_INT_MASK 0x00000020 +#define MBOX_INT_STATUS_ENABLE_COUNTER_LSB 4 +#define MBOX_INT_STATUS_ENABLE_COUNTER_MASK 0x00000010 +#define MBOX_INT_STATUS_ENABLE_MBOX_DATA_LSB 0 +#define MBOX_INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f +#define MBOX_CPU_INT_STATUS_ENABLE_ADDRESS 0x00000819 +#define MBOX_CPU_INT_STATUS_ENABLE_BIT_LSB 0 +#define MBOX_CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff +#define MBOX_ERROR_STATUS_ENABLE_ADDRESS 0x0000081a +#define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1 +#define MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002 +#define MBOX_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 0 +#define MBOX_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00000001 +#define MBOX_COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000081b +#define MBOX_COUNTER_INT_STATUS_ENABLE_BIT_LSB 0 +#define MBOX_COUNTER_INT_STATUS_ENABLE_BIT_MASK 0x000000ff +#define MBOX_COUNT_ADDRESS 0x00000820 +#define MBOX_COUNT_DEC_ADDRESS 0x00000840 +#define MBOX_WINDOW_DATA_ADDRESS 0x00000874 +#define MBOX_WINDOW_WRITE_ADDR_ADDRESS 0x00000878 +#define MBOX_WINDOW_READ_ADDR_ADDRESS 0x0000087c +#define MBOX_CPU_DBG_SEL_ADDRESS 0x00000883 +#define MBOX_CPU_DBG_ADDRESS 0x00000884 +#define MBOX_RTC_BASE_ADDRESS 0x00000000 +#define MBOX_GPIO_BASE_ADDRESS 0x00005000 +#define MBOX_MBOX_BASE_ADDRESS 0x00008000 + #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB) /* Register definitions for first generation ath10k cards. These cards include diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index cbac9e4252d6..8bded5da9d0d 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -205,6 +205,24 @@ struct host_interest { */ /* Bit 1 - unused */ u32 hi_fw_swap; /* 0x104 */ + + /* global arenas pointer address, used by host driver debug */ + u32 hi_dynamic_mem_arenas_addr; /* 0x108 */ + + /* allocated bytes of DRAM use by allocated */ + u32 hi_dynamic_mem_allocated; /* 0x10C */ + + /* remaining bytes of DRAM */ + u32 hi_dynamic_mem_remaining; /* 0x110 */ + + /* memory track count, configured by host */ + u32 hi_dynamic_mem_track_max; /* 0x114 */ + + /* minidump buffer */ + u32 hi_minidump; /* 0x118 */ + + /* bdata's sig and key addr */ + u32 hi_bd_sig_key; /* 0x11c */ } __packed; #define HI_ITEM(item) offsetof(struct host_interest, item) @@ -319,6 +337,12 @@ struct host_interest { #define HI_ACS_FLAGS_USE_WWAN (1 << 1) /* Use test VAP */ #define HI_ACS_FLAGS_TEST_VAP (1 << 2) +/* SDIO/mailbox ACS flag definitions */ +#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET (1 << 0) +#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET (1 << 1) +#define HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE (1 << 2) +#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK (1 << 16) +#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK (1 << 17) /* * CONSOLE FLAGS -- cgit v1.2.3 From 60bdfffa1254ae634c9e1aa8f8f746274aae037e Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:17:56 +0300 Subject: ath10k: add sdio extra initializations Extra initializations needed by all sdio boards. Derived from qcacld. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 5a0638915874..4857fbcd1e1b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -389,6 +389,21 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) complete(&ar->target_suspend); } +static void ath10k_init_sdio(struct ath10k *ar) +{ + u32 param = 0; + + ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256); + ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99); + ath10k_bmi_read32(ar, hi_acs_flags, ¶m); + + param |= (HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET | + HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET | + HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE); + + ath10k_bmi_write32(ar, hi_acs_flags, param); +} + static int ath10k_init_configure_target(struct ath10k *ar) { u32 param_host; @@ -1953,6 +1968,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (status) goto err; + if (ar->hif.bus == ATH10K_BUS_SDIO) + ath10k_init_sdio(ar); + ar->htc.htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; -- cgit v1.2.3 From 34dd398a55ffb99db12f7775d9867336450845eb Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:17:57 +0300 Subject: ath10k: sdio get target info Special BMI get target info function for SDIO. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.c | 71 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/bmi.h | 2 + drivers/net/wireless/ath/ath10k/core.c | 5 ++- 3 files changed, 77 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index abeee200310b..2d3a2f31123d 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -97,6 +97,77 @@ int ath10k_bmi_get_target_info(struct ath10k *ar, return 0; } +#define TARGET_VERSION_SENTINAL 0xffffffffu + +int ath10k_bmi_get_target_info_sdio(struct ath10k *ar, + struct bmi_target_info *target_info) +{ + struct bmi_cmd cmd; + union bmi_resp resp; + u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info); + u32 resplen, ver_len; + __le32 tmp; + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info SDIO\n"); + + if (ar->bmi.done_sent) { + ath10k_warn(ar, "BMI Get Target Info Command disallowed\n"); + return -EBUSY; + } + + cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO); + + /* Step 1: Read 4 bytes of the target info and check if it is + * the special sentinal version word or the first word in the + * version response. + */ + resplen = sizeof(u32); + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &tmp, &resplen); + if (ret) { + ath10k_warn(ar, "unable to read from device\n"); + return ret; + } + + /* Some SDIO boards have a special sentinal byte before the real + * version response. + */ + if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) { + /* Step 1b: Read the version length */ + resplen = sizeof(u32); + ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, &tmp, + &resplen); + if (ret) { + ath10k_warn(ar, "unable to read from device\n"); + return ret; + } + } + + ver_len = __le32_to_cpu(tmp); + + /* Step 2: Check the target info length */ + if (ver_len != sizeof(resp.get_target_info)) { + ath10k_warn(ar, "Unexpected target info len: %u. Expected: %zu\n", + ver_len, sizeof(resp.get_target_info)); + return -EINVAL; + } + + /* Step 3: Read the rest of the version response */ + resplen = sizeof(resp.get_target_info) - sizeof(u32); + ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, + &resp.get_target_info.version, + &resplen); + if (ret) { + ath10k_warn(ar, "unable to read from device\n"); + return ret; + } + + target_info->version = __le32_to_cpu(resp.get_target_info.version); + target_info->type = __le32_to_cpu(resp.get_target_info.type); + + return 0; +} + int ath10k_bmi_read_memory(struct ath10k *ar, u32 address, void *buffer, u32 length) { diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index cc45b63ade15..0342073ed397 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -198,6 +198,8 @@ void ath10k_bmi_start(struct ath10k *ar); int ath10k_bmi_done(struct ath10k *ar); int ath10k_bmi_get_target_info(struct ath10k *ar, struct bmi_target_info *target_info); +int ath10k_bmi_get_target_info_sdio(struct ath10k *ar, + struct bmi_target_info *target_info); int ath10k_bmi_read_memory(struct ath10k *ar, u32 address, void *buffer, u32 length); int ath10k_bmi_write_memory(struct ath10k *ar, u32 address, diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 4857fbcd1e1b..84487b176c3f 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2218,7 +2218,10 @@ static int ath10k_core_probe_fw(struct ath10k *ar) } memset(&target_info, 0, sizeof(target_info)); - ret = ath10k_bmi_get_target_info(ar, &target_info); + if (ar->hif.bus == ATH10K_BUS_SDIO) + ret = ath10k_bmi_get_target_info_sdio(ar, &target_info); + else + ret = ath10k_bmi_get_target_info(ar, &target_info); if (ret) { ath10k_err(ar, "could not get target info (%d)\n", ret); goto err_power_down; -- cgit v1.2.3 From 04ff79467ec27eec6891542ca200f65883635eaf Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:17:58 +0300 Subject: ath10k: htc: ready_ext msg support Added support for extended ready message. The extended ready message contains the maximum bundle count supported by SDIO chipsets. It is transmitted by SDIO chipset only and replaces the "standard" ready message in this case. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 28 ++++++++++++++++++++++------ drivers/net/wireless/ath/ath10k/htc.h | 5 +++++ 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 15b805629336..e5c80f582ff5 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -586,8 +586,6 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) unsigned long time_left; struct ath10k_htc_msg *msg; u16 message_id; - u16 credit_count; - u16 credit_size; time_left = wait_for_completion_timeout(&htc->ctl_resp, ATH10K_HTC_WAIT_TIMEOUT_HZ); @@ -624,16 +622,14 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) msg = (struct ath10k_htc_msg *)htc->control_resp_buffer; message_id = __le16_to_cpu(msg->hdr.message_id); - credit_count = __le16_to_cpu(msg->ready.credit_count); - credit_size = __le16_to_cpu(msg->ready.credit_size); if (message_id != ATH10K_HTC_MSG_READY_ID) { ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id); return -ECOMM; } - htc->total_transmit_credits = credit_count; - htc->target_credit_size = credit_size; + htc->total_transmit_credits = __le16_to_cpu(msg->ready.credit_count); + htc->target_credit_size = __le16_to_cpu(msg->ready.credit_size); ath10k_dbg(ar, ATH10K_DBG_HTC, "Target ready! transmit resources: %d size:%d\n", @@ -646,6 +642,19 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) return -ECOMM; } + /* The only way to determine if the ready message is an extended + * message is from the size. + */ + if (htc->control_resp_len >= + sizeof(msg->hdr) + sizeof(msg->ready_ext)) { + htc->max_msgs_per_htc_bundle = + min_t(u8, msg->ready_ext.max_msgs_per_htc_bundle, + HTC_HOST_MAX_MSG_PER_BUNDLE); + ath10k_dbg(ar, ATH10K_DBG_HTC, + "Extended ready message. RX bundle size: %d\n", + htc->max_msgs_per_htc_bundle); + } + return 0; } @@ -841,6 +850,13 @@ int ath10k_htc_start(struct ath10k_htc *htc) msg->hdr.message_id = __cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID); + if (ar->hif.bus == ATH10K_BUS_SDIO) { + /* Extra setup params used by SDIO */ + msg->setup_complete_ext.flags = + __cpu_to_le32(ATH10K_HTC_SETUP_COMPLETE_FLAGS_RX_BNDL_EN); + msg->setup_complete_ext.max_msgs_per_bundled_recv = + htc->max_msgs_per_htc_bundle; + } ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n"); status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb); diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h index ae6003495649..24663b07eeac 100644 --- a/drivers/net/wireless/ath/ath10k/htc.h +++ b/drivers/net/wireless/ath/ath10k/htc.h @@ -112,6 +112,10 @@ enum ath10k_htc_conn_svc_status { ATH10K_HTC_CONN_SVC_STATUS_NO_MORE_EP = 4 }; +enum ath10k_htc_setup_complete_flags { + ATH10K_HTC_SETUP_COMPLETE_FLAGS_RX_BNDL_EN = 1 +}; + struct ath10k_ath10k_htc_msg_hdr { __le16 message_id; /* @enum htc_message_id */ } __packed; @@ -360,6 +364,7 @@ struct ath10k_htc { int total_transmit_credits; int target_credit_size; + u8 max_msgs_per_htc_bundle; }; int ath10k_htc_init(struct ath10k *ar); -- cgit v1.2.3 From f008d1537bf88396cf41a7c7a831e3acd1ee92a1 Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:17:59 +0300 Subject: ath10k: different fw file name for sdio Since both SDIO based chipsets will use different firmware from the PCIe and AHB chipsets, the fw file name must be different depending on bus type. The new firmware names are: For PCIe and AHB: firmware-.bin (same as before) For SDIO: firmware-sdio-.bin Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 84487b176c3f..eea111d704c5 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1410,7 +1410,18 @@ err: static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name, size_t fw_name_len, int fw_api) { - scnprintf(fw_name, fw_name_len, "%s-%d.bin", ATH10K_FW_FILE_BASE, fw_api); + switch (ar->hif.bus) { + case ATH10K_BUS_SDIO: + scnprintf(fw_name, fw_name_len, "%s-%s-%d.bin", + ATH10K_FW_FILE_BASE, ath10k_bus_str(ar->hif.bus), + fw_api); + break; + case ATH10K_BUS_PCI: + case ATH10K_BUS_AHB: + scnprintf(fw_name, fw_name_len, "%s-%d.bin", + ATH10K_FW_FILE_BASE, fw_api); + break; + } } static int ath10k_core_fetch_firmware_files(struct ath10k *ar) -- cgit v1.2.3 From d96db25d20256208ce47d71b9f673a1de4c6fd7e Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Wed, 26 Apr 2017 12:18:00 +0300 Subject: ath10k: add initial SDIO support Chipsets like QCA6584 have support for SDIO so add initial SDIO bus support to ath10k. With this patch we have the low level HTC protocol working and it's possible to boot the firmware, but it's still not possible to connect or anything like. More changes are needed for full functionality. For that reason we print during initialisation: WARNING: ath10k SDIO support is incomplete, don't expect anything to work! Signed-off-by: Erik Stromdahl [kvalo@qca.qualcomm.com: refactoring, cleanup, commit log] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Kconfig | 7 + drivers/net/wireless/ath/ath10k/Makefile | 3 + drivers/net/wireless/ath/ath10k/sdio.c | 2113 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/sdio.h | 229 ++++ 4 files changed, 2352 insertions(+) create mode 100644 drivers/net/wireless/ath/ath10k/sdio.c create mode 100644 drivers/net/wireless/ath/ath10k/sdio.h (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index b4241cf9b7ed..412eb1380dcc 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -22,6 +22,13 @@ config ATH10K_AHB ---help--- This module adds support for AHB bus +config ATH10K_SDIO + tristate "Atheros ath10k SDIO support (EXPERIMENTAL)" + depends on ATH10K && MMC + ---help--- + This module adds experimental support for SDIO/MMC bus. Currently + work in progress and will not fully work. + config ATH10K_DEBUG bool "Atheros ath10k debugging" depends on ATH10K diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 930fadd940d8..b0b19a7eb98b 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -27,5 +27,8 @@ ath10k_pci-y += pci.o \ ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o +obj-$(CONFIG_ATH10K_SDIO) += ath10k_sdio.o +ath10k_sdio-y += sdio.o + # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c new file mode 100644 index 000000000000..9e78fbae8413 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -0,0 +1,2113 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc. + * Copyright (c) 2016-2017 Erik Stromdahl + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "bmi.h" +#include "debug.h" +#include "hif.h" +#include "htc.h" +#include "targaddrs.h" +#include "trace.h" +#include "sdio.h" + +/* inlined helper functions */ + +static inline int ath10k_sdio_calc_txrx_padded_len(struct ath10k_sdio *ar_sdio, + size_t len) +{ + return __ALIGN_MASK((len), ar_sdio->mbox_info.block_mask); +} + +static inline enum ath10k_htc_ep_id pipe_id_to_eid(u8 pipe_id) +{ + return (enum ath10k_htc_ep_id)pipe_id; +} + +static inline void ath10k_sdio_mbox_free_rx_pkt(struct ath10k_sdio_rx_data *pkt) +{ + dev_kfree_skb(pkt->skb); + pkt->skb = NULL; + pkt->alloc_len = 0; + pkt->act_len = 0; + pkt->trailer_only = false; +} + +static inline int ath10k_sdio_mbox_alloc_rx_pkt(struct ath10k_sdio_rx_data *pkt, + size_t act_len, size_t full_len, + bool part_of_bundle, + bool last_in_bundle) +{ + pkt->skb = dev_alloc_skb(full_len); + if (!pkt->skb) + return -ENOMEM; + + pkt->act_len = act_len; + pkt->alloc_len = full_len; + pkt->part_of_bundle = part_of_bundle; + pkt->last_in_bundle = last_in_bundle; + pkt->trailer_only = false; + + return 0; +} + +static inline bool is_trailer_only_msg(struct ath10k_sdio_rx_data *pkt) +{ + bool trailer_only = false; + struct ath10k_htc_hdr *htc_hdr = + (struct ath10k_htc_hdr *)pkt->skb->data; + u16 len = __le16_to_cpu(htc_hdr->len); + + if (len == htc_hdr->trailer_len) + trailer_only = true; + + return trailer_only; +} + +/* sdio/mmc functions */ + +static inline void ath10k_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw, + unsigned int address, + unsigned char val) +{ + *arg = FIELD_PREP(BIT(31), write) | + FIELD_PREP(BIT(27), raw) | + FIELD_PREP(BIT(26), 1) | + FIELD_PREP(GENMASK(25, 9), address) | + FIELD_PREP(BIT(8), 1) | + FIELD_PREP(GENMASK(7, 0), val); +} + +static int ath10k_sdio_func0_cmd52_wr_byte(struct mmc_card *card, + unsigned int address, + unsigned char byte) +{ + struct mmc_command io_cmd; + + memset(&io_cmd, 0, sizeof(io_cmd)); + ath10k_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte); + io_cmd.opcode = SD_IO_RW_DIRECT; + io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + return mmc_wait_for_cmd(card->host, &io_cmd, 0); +} + +static int ath10k_sdio_func0_cmd52_rd_byte(struct mmc_card *card, + unsigned int address, + unsigned char *byte) +{ + struct mmc_command io_cmd; + int ret; + + memset(&io_cmd, 0, sizeof(io_cmd)); + ath10k_sdio_set_cmd52_arg(&io_cmd.arg, 0, 0, address, 0); + io_cmd.opcode = SD_IO_RW_DIRECT; + io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + ret = mmc_wait_for_cmd(card->host, &io_cmd, 0); + if (!ret) + *byte = io_cmd.resp[0]; + + return ret; +} + +static int ath10k_sdio_config(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + unsigned char byte, asyncintdelay = 2; + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio configuration\n"); + + sdio_claim_host(func); + + byte = 0; + ret = ath10k_sdio_func0_cmd52_rd_byte(func->card, + SDIO_CCCR_DRIVE_STRENGTH, + &byte); + + byte &= ~ATH10K_SDIO_DRIVE_DTSX_MASK; + byte |= FIELD_PREP(ATH10K_SDIO_DRIVE_DTSX_MASK, + ATH10K_SDIO_DRIVE_DTSX_TYPE_D); + + ret = ath10k_sdio_func0_cmd52_wr_byte(func->card, + SDIO_CCCR_DRIVE_STRENGTH, + byte); + + byte = 0; + ret = ath10k_sdio_func0_cmd52_rd_byte( + func->card, + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR, + &byte); + + byte |= (CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D); + + ret = ath10k_sdio_func0_cmd52_wr_byte(func->card, + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR, + byte); + if (ret) { + ath10k_warn(ar, "failed to enable driver strength: %d\n", ret); + goto out; + } + + byte = 0; + ret = ath10k_sdio_func0_cmd52_rd_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_SDIO3, + &byte); + + byte |= SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_SDIO3; + + ret = ath10k_sdio_func0_cmd52_wr_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_SDIO3, + byte); + if (ret) { + ath10k_warn(ar, "failed to enable 4-bit async irq mode: %d\n", + ret); + goto out; + } + + byte = 0; + ret = ath10k_sdio_func0_cmd52_rd_byte(func->card, + CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS, + &byte); + + byte &= ~CCCR_SDIO_ASYNC_INT_DELAY_MASK; + byte |= FIELD_PREP(CCCR_SDIO_ASYNC_INT_DELAY_MASK, asyncintdelay); + + ret = ath10k_sdio_func0_cmd52_wr_byte(func->card, + CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS, + byte); + + /* give us some time to enable, in ms */ + func->enable_timeout = 100; + + ret = sdio_set_block_size(func, ar_sdio->mbox_info.block_size); + if (ret) { + ath10k_warn(ar, "failed to set sdio block size to %d: %d\n", + ar_sdio->mbox_info.block_size, ret); + goto out; + } + +out: + sdio_release_host(func); + return ret; +} + +static int ath10k_sdio_write32(struct ath10k *ar, u32 addr, u32 val) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + + sdio_writel(func, val, addr, &ret); + if (ret) { + ath10k_warn(ar, "failed to write 0x%x to address 0x%x: %d\n", + val, addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio write32 addr 0x%x val 0x%x\n", + addr, val); + +out: + sdio_release_host(func); + + return ret; +} + +static int ath10k_sdio_writesb32(struct ath10k *ar, u32 addr, u32 val) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + __le32 *buf; + int ret; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + *buf = cpu_to_le32(val); + + sdio_claim_host(func); + + ret = sdio_writesb(func, addr, buf, sizeof(*buf)); + if (ret) { + ath10k_warn(ar, "failed to write value 0x%x to fixed sb address 0x%x: %d\n", + val, addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio writesb32 addr 0x%x val 0x%x\n", + addr, val); + +out: + sdio_release_host(func); + + kfree(buf); + + return ret; +} + +static int ath10k_sdio_read32(struct ath10k *ar, u32 addr, u32 *val) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + *val = sdio_readl(func, addr, &ret); + if (ret) { + ath10k_warn(ar, "failed to read from address 0x%x: %d\n", + addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio read32 addr 0x%x val 0x%x\n", + addr, *val); + +out: + sdio_release_host(func); + + return ret; +} + +static int ath10k_sdio_read(struct ath10k *ar, u32 addr, void *buf, size_t len) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + + ret = sdio_memcpy_fromio(func, buf, addr, len); + if (ret) { + ath10k_warn(ar, "failed to read from address 0x%x: %d\n", + addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio read addr 0x%x buf 0x%p len %zu\n", + addr, buf, len); + ath10k_dbg_dump(ar, ATH10K_DBG_SDIO_DUMP, NULL, "sdio read ", buf, len); + +out: + sdio_release_host(func); + + return ret; +} + +static int ath10k_sdio_write(struct ath10k *ar, u32 addr, const void *buf, size_t len) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + + /* For some reason toio() doesn't have const for the buffer, need + * an ugly hack to workaround that. + */ + ret = sdio_memcpy_toio(func, addr, (void *)buf, len); + if (ret) { + ath10k_warn(ar, "failed to write to address 0x%x: %d\n", + addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio write addr 0x%x buf 0x%p len %zu\n", + addr, buf, len); + ath10k_dbg_dump(ar, ATH10K_DBG_SDIO_DUMP, NULL, "sdio write ", buf, len); + +out: + sdio_release_host(func); + + return ret; +} + +static int ath10k_sdio_readsb(struct ath10k *ar, u32 addr, void *buf, size_t len) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + sdio_claim_host(func); + + len = round_down(len, ar_sdio->mbox_info.block_size); + + ret = sdio_readsb(func, buf, addr, len); + if (ret) { + ath10k_warn(ar, "failed to read from fixed (sb) address 0x%x: %d\n", + addr, ret); + goto out; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio readsb addr 0x%x buf 0x%p len %zu\n", + addr, buf, len); + ath10k_dbg_dump(ar, ATH10K_DBG_SDIO_DUMP, NULL, "sdio readsb ", buf, len); + +out: + sdio_release_host(func); + + return ret; +} + +/* HIF mbox functions */ + +static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar, + struct ath10k_sdio_rx_data *pkt, + u32 *lookaheads, + int *n_lookaheads) +{ + struct ath10k_htc *htc = &ar->htc; + struct sk_buff *skb = pkt->skb; + struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data; + bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT; + enum ath10k_htc_ep_id eid; + u16 payload_len; + u8 *trailer; + int ret; + + payload_len = le16_to_cpu(htc_hdr->len); + + if (trailer_present) { + trailer = skb->data + sizeof(*htc_hdr) + + payload_len - htc_hdr->trailer_len; + + eid = pipe_id_to_eid(htc_hdr->eid); + + ret = ath10k_htc_process_trailer(htc, + trailer, + htc_hdr->trailer_len, + eid, + lookaheads, + n_lookaheads); + if (ret) + return ret; + + if (is_trailer_only_msg(pkt)) + pkt->trailer_only = true; + + skb_trim(skb, skb->len - htc_hdr->trailer_len); + } + + skb_pull(skb, sizeof(*htc_hdr)); + + return 0; +} + +static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar, + u32 lookaheads[], + int *n_lookahead) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_htc *htc = &ar->htc; + struct ath10k_sdio_rx_data *pkt; + struct ath10k_htc_ep *ep; + enum ath10k_htc_ep_id id; + int ret, i, *n_lookahead_local; + u32 *lookaheads_local; + + for (i = 0; i < ar_sdio->n_rx_pkts; i++) { + lookaheads_local = lookaheads; + n_lookahead_local = n_lookahead; + + id = ((struct ath10k_htc_hdr *)&lookaheads[i])->eid; + + if (id >= ATH10K_HTC_EP_COUNT) { + ath10k_warn(ar, "invalid endpoint in look-ahead: %d\n", + id); + ret = -ENOMEM; + goto out; + } + + ep = &htc->endpoint[id]; + + if (ep->service_id == 0) { + ath10k_warn(ar, "ep %d is not connected\n", id); + ret = -ENOMEM; + goto out; + } + + pkt = &ar_sdio->rx_pkts[i]; + + if (pkt->part_of_bundle && !pkt->last_in_bundle) { + /* Only read lookahead's from RX trailers + * for the last packet in a bundle. + */ + lookaheads_local = NULL; + n_lookahead_local = NULL; + } + + ret = ath10k_sdio_mbox_rx_process_packet(ar, + pkt, + lookaheads_local, + n_lookahead_local); + if (ret) + goto out; + + if (!pkt->trailer_only) + ep->ep_ops.ep_rx_complete(ar_sdio->ar, pkt->skb); + else + kfree_skb(pkt->skb); + + /* The RX complete handler now owns the skb...*/ + pkt->skb = NULL; + pkt->alloc_len = 0; + } + + ret = 0; + +out: + /* Free all packets that was not passed on to the RX completion + * handler... + */ + for (; i < ar_sdio->n_rx_pkts; i++) + ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]); + + return ret; +} + +static int ath10k_sdio_mbox_alloc_pkt_bundle(struct ath10k *ar, + struct ath10k_sdio_rx_data *rx_pkts, + struct ath10k_htc_hdr *htc_hdr, + size_t full_len, size_t act_len, + size_t *bndl_cnt) +{ + int ret, i; + + *bndl_cnt = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, htc_hdr->flags); + + if (*bndl_cnt > HTC_HOST_MAX_MSG_PER_BUNDLE) { + ath10k_warn(ar, + "HTC bundle length %u exceeds maximum %u\n", + le16_to_cpu(htc_hdr->len), + HTC_HOST_MAX_MSG_PER_BUNDLE); + return -ENOMEM; + } + + /* Allocate bndl_cnt extra skb's for the bundle. + * The package containing the + * ATH10K_HTC_FLAG_BUNDLE_MASK flag is not included + * in bndl_cnt. The skb for that packet will be + * allocated separately. + */ + for (i = 0; i < *bndl_cnt; i++) { + ret = ath10k_sdio_mbox_alloc_rx_pkt(&rx_pkts[i], + act_len, + full_len, + true, + false); + if (ret) + return ret; + } + + return 0; +} + +static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar, + u32 lookaheads[], int n_lookaheads) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_htc_hdr *htc_hdr; + size_t full_len, act_len; + bool last_in_bundle; + int ret, i; + + if (n_lookaheads > ATH10K_SDIO_MAX_RX_MSGS) { + ath10k_warn(ar, + "the total number of pkgs to be fetched (%u) exceeds maximum %u\n", + n_lookaheads, + ATH10K_SDIO_MAX_RX_MSGS); + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < n_lookaheads; i++) { + htc_hdr = (struct ath10k_htc_hdr *)&lookaheads[i]; + last_in_bundle = false; + + if (le16_to_cpu(htc_hdr->len) > + ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH) { + ath10k_warn(ar, + "payload length %d exceeds max htc length: %zu\n", + le16_to_cpu(htc_hdr->len), + ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH); + ret = -ENOMEM; + goto err; + } + + act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr); + full_len = ath10k_sdio_calc_txrx_padded_len(ar_sdio, act_len); + + if (full_len > ATH10K_SDIO_MAX_BUFFER_SIZE) { + ath10k_warn(ar, + "rx buffer requested with invalid htc_hdr length (%d, 0x%x): %d\n", + htc_hdr->eid, htc_hdr->flags, + le16_to_cpu(htc_hdr->len)); + ret = -EINVAL; + goto err; + } + + if (htc_hdr->flags & ATH10K_HTC_FLAG_BUNDLE_MASK) { + /* HTC header indicates that every packet to follow + * has the same padded length so that it can be + * optimally fetched as a full bundle. + */ + size_t bndl_cnt; + + ret = ath10k_sdio_mbox_alloc_pkt_bundle(ar, + &ar_sdio->rx_pkts[i], + htc_hdr, + full_len, + act_len, + &bndl_cnt); + + n_lookaheads += bndl_cnt; + i += bndl_cnt; + /*Next buffer will be the last in the bundle */ + last_in_bundle = true; + } + + /* Allocate skb for packet. If the packet had the + * ATH10K_HTC_FLAG_BUNDLE_MASK flag set, all bundled + * packet skb's have been allocated in the previous step. + */ + ret = ath10k_sdio_mbox_alloc_rx_pkt(&ar_sdio->rx_pkts[i], + act_len, + full_len, + last_in_bundle, + last_in_bundle); + } + + ar_sdio->n_rx_pkts = i; + + return 0; + +err: + for (i = 0; i < ATH10K_SDIO_MAX_RX_MSGS; i++) { + if (!ar_sdio->rx_pkts[i].alloc_len) + break; + ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]); + } + + return ret; +} + +static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar, + struct ath10k_sdio_rx_data *pkt) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sk_buff *skb = pkt->skb; + int ret; + + ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr, + skb->data, pkt->alloc_len); + pkt->status = ret; + if (!ret) + skb_put(skb, pkt->act_len); + + return ret; +} + +static int ath10k_sdio_mbox_rx_fetch(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + int ret, i; + + for (i = 0; i < ar_sdio->n_rx_pkts; i++) { + ret = ath10k_sdio_mbox_rx_packet(ar, + &ar_sdio->rx_pkts[i]); + if (ret) + goto err; + } + + return 0; + +err: + /* Free all packets that was not successfully fetched. */ + for (; i < ar_sdio->n_rx_pkts; i++) + ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]); + + return ret; +} + +/* This is the timeout for mailbox processing done in the sdio irq + * handler. The timeout is deliberately set quite high since SDIO dump logs + * over serial port can/will add a substantial overhead to the processing + * (if enabled). + */ +#define SDIO_MBOX_PROCESSING_TIMEOUT_HZ (20 * HZ) + +static int ath10k_sdio_mbox_rxmsg_pending_handler(struct ath10k *ar, + u32 msg_lookahead, bool *done) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + u32 lookaheads[ATH10K_SDIO_MAX_RX_MSGS]; + int n_lookaheads = 1; + unsigned long timeout; + int ret; + + *done = true; + + /* Copy the lookahead obtained from the HTC register table into our + * temp array as a start value. + */ + lookaheads[0] = msg_lookahead; + + timeout = jiffies + SDIO_MBOX_PROCESSING_TIMEOUT_HZ; + while (time_before(jiffies, timeout)) { + /* Try to allocate as many HTC RX packets indicated by + * n_lookaheads. + */ + ret = ath10k_sdio_mbox_rx_alloc(ar, lookaheads, + n_lookaheads); + if (ret) + break; + + if (ar_sdio->n_rx_pkts >= 2) + /* A recv bundle was detected, force IRQ status + * re-check again. + */ + *done = false; + + ret = ath10k_sdio_mbox_rx_fetch(ar); + + /* Process fetched packets. This will potentially update + * n_lookaheads depending on if the packets contain lookahead + * reports. + */ + n_lookaheads = 0; + ret = ath10k_sdio_mbox_rx_process_packets(ar, + lookaheads, + &n_lookaheads); + + if (!n_lookaheads || ret) + break; + + /* For SYNCH processing, if we get here, we are running + * through the loop again due to updated lookaheads. Set + * flag that we should re-check IRQ status registers again + * before leaving IRQ processing, this can net better + * performance in high throughput situations. + */ + *done = false; + } + + if (ret && (ret != -ECANCELED)) + ath10k_warn(ar, "failed to get pending recv messages: %d\n", + ret); + + return ret; +} + +static int ath10k_sdio_mbox_proc_dbg_intr(struct ath10k *ar) +{ + u32 val; + int ret; + + /* TODO: Add firmware crash handling */ + ath10k_warn(ar, "firmware crashed\n"); + + /* read counter to clear the interrupt, the debug error interrupt is + * counter 0. + */ + ret = ath10k_sdio_read32(ar, MBOX_COUNT_DEC_ADDRESS, &val); + if (ret) + ath10k_warn(ar, "failed to clear debug interrupt: %d\n", ret); + + return ret; +} + +static int ath10k_sdio_mbox_proc_counter_intr(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + u8 counter_int_status; + int ret; + + mutex_lock(&irq_data->mtx); + counter_int_status = irq_data->irq_proc_reg->counter_int_status & + irq_data->irq_en_reg->cntr_int_status_en; + + /* NOTE: other modules like GMBOX may use the counter interrupt for + * credit flow control on other counters, we only need to check for + * the debug assertion counter interrupt. + */ + if (counter_int_status & ATH10K_SDIO_TARGET_DEBUG_INTR_MASK) + ret = ath10k_sdio_mbox_proc_dbg_intr(ar); + else + ret = 0; + + mutex_unlock(&irq_data->mtx); + + return ret; +} + +static int ath10k_sdio_mbox_proc_err_intr(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + u8 error_int_status; + int ret; + + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio error interrupt\n"); + + error_int_status = irq_data->irq_proc_reg->error_int_status & 0x0F; + if (!error_int_status) { + ath10k_warn(ar, "invalid error interrupt status: 0x%x\n", + error_int_status); + return -EIO; + } + + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio error_int_status 0x%x\n", error_int_status); + + if (FIELD_GET(MBOX_ERROR_INT_STATUS_WAKEUP_MASK, + error_int_status)) + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio interrupt error wakeup\n"); + + if (FIELD_GET(MBOX_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + error_int_status)) + ath10k_warn(ar, "rx underflow interrupt error\n"); + + if (FIELD_GET(MBOX_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + error_int_status)) + ath10k_warn(ar, "tx overflow interrupt error\n"); + + /* Clear the interrupt */ + irq_data->irq_proc_reg->error_int_status &= ~error_int_status; + + /* set W1C value to clear the interrupt, this hits the register first */ + ret = ath10k_sdio_writesb32(ar, MBOX_ERROR_INT_STATUS_ADDRESS, + error_int_status); + if (ret) { + ath10k_warn(ar, "unable to write to error int status address: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ath10k_sdio_mbox_proc_cpu_intr(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + u8 cpu_int_status; + int ret; + + mutex_lock(&irq_data->mtx); + cpu_int_status = irq_data->irq_proc_reg->cpu_int_status & + irq_data->irq_en_reg->cpu_int_status_en; + if (!cpu_int_status) { + ath10k_warn(ar, "CPU interrupt status is zero\n"); + ret = -EIO; + goto out; + } + + /* Clear the interrupt */ + irq_data->irq_proc_reg->cpu_int_status &= ~cpu_int_status; + + /* Set up the register transfer buffer to hit the register 4 times, + * this is done to make the access 4-byte aligned to mitigate issues + * with host bus interconnects that restrict bus transfer lengths to + * be a multiple of 4-bytes. + * + * Set W1C value to clear the interrupt, this hits the register first. + */ + ret = ath10k_sdio_writesb32(ar, MBOX_CPU_INT_STATUS_ADDRESS, + cpu_int_status); + if (ret) { + ath10k_warn(ar, "unable to write to cpu interrupt status address: %d\n", + ret); + goto out; + } + +out: + mutex_unlock(&irq_data->mtx); + return ret; +} + +static int ath10k_sdio_mbox_read_int_status(struct ath10k *ar, + u8 *host_int_status, + u32 *lookahead) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + struct ath10k_sdio_irq_proc_regs *irq_proc_reg = irq_data->irq_proc_reg; + struct ath10k_sdio_irq_enable_regs *irq_en_reg = irq_data->irq_en_reg; + u8 htc_mbox = FIELD_PREP(ATH10K_HTC_MAILBOX_MASK, 1); + int ret; + + mutex_lock(&irq_data->mtx); + + *lookahead = 0; + *host_int_status = 0; + + /* int_status_en is supposed to be non zero, otherwise interrupts + * shouldn't be enabled. There is however a short time frame during + * initialization between the irq register and int_status_en init + * where this can happen. + * We silently ignore this condition. + */ + if (!irq_en_reg->int_status_en) { + ret = 0; + goto out; + } + + /* Read the first sizeof(struct ath10k_irq_proc_registers) + * bytes of the HTC register table. This + * will yield us the value of different int status + * registers and the lookahead registers. + */ + ret = ath10k_sdio_read(ar, MBOX_HOST_INT_STATUS_ADDRESS, + irq_proc_reg, sizeof(*irq_proc_reg)); + if (ret) + goto out; + + /* Update only those registers that are enabled */ + *host_int_status = irq_proc_reg->host_int_status & + irq_en_reg->int_status_en; + + /* Look at mbox status */ + if (!(*host_int_status & htc_mbox)) { + *lookahead = 0; + ret = 0; + goto out; + } + + /* Mask out pending mbox value, we use look ahead as + * the real flag for mbox processing. + */ + *host_int_status &= ~htc_mbox; + if (irq_proc_reg->rx_lookahead_valid & htc_mbox) { + *lookahead = le32_to_cpu( + irq_proc_reg->rx_lookahead[ATH10K_HTC_MAILBOX]); + if (!*lookahead) + ath10k_warn(ar, "sdio mbox lookahead is zero\n"); + } + +out: + mutex_unlock(&irq_data->mtx); + return ret; +} + +static int ath10k_sdio_mbox_proc_pending_irqs(struct ath10k *ar, + bool *done) +{ + u8 host_int_status; + u32 lookahead; + int ret; + + /* NOTE: HIF implementation guarantees that the context of this + * call allows us to perform SYNCHRONOUS I/O, that is we can block, + * sleep or call any API that can block or switch thread/task + * contexts. This is a fully schedulable context. + */ + + ret = ath10k_sdio_mbox_read_int_status(ar, + &host_int_status, + &lookahead); + if (ret) { + *done = true; + goto out; + } + + if (!host_int_status && !lookahead) { + ret = 0; + *done = true; + goto out; + } + + if (lookahead) { + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio pending mailbox msg lookahead 0x%08x\n", + lookahead); + + ret = ath10k_sdio_mbox_rxmsg_pending_handler(ar, + lookahead, + done); + if (ret) + goto out; + } + + /* now, handle the rest of the interrupts */ + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio host_int_status 0x%x\n", host_int_status); + + if (FIELD_GET(MBOX_HOST_INT_STATUS_CPU_MASK, host_int_status)) { + /* CPU Interrupt */ + ret = ath10k_sdio_mbox_proc_cpu_intr(ar); + if (ret) + goto out; + } + + if (FIELD_GET(MBOX_HOST_INT_STATUS_ERROR_MASK, host_int_status)) { + /* Error Interrupt */ + ret = ath10k_sdio_mbox_proc_err_intr(ar); + if (ret) + goto out; + } + + if (FIELD_GET(MBOX_HOST_INT_STATUS_COUNTER_MASK, host_int_status)) + /* Counter Interrupt */ + ret = ath10k_sdio_mbox_proc_counter_intr(ar); + + ret = 0; + +out: + /* An optimization to bypass reading the IRQ status registers + * unecessarily which can re-wake the target, if upper layers + * determine that we are in a low-throughput mode, we can rely on + * taking another interrupt rather than re-checking the status + * registers which can re-wake the target. + * + * NOTE : for host interfaces that makes use of detecting pending + * mbox messages at hif can not use this optimization due to + * possible side effects, SPI requires the host to drain all + * messages from the mailbox before exiting the ISR routine. + */ + + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio pending irqs done %d status %d", + *done, ret); + + return ret; +} + +static void ath10k_sdio_set_mbox_info(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_mbox_info *mbox_info = &ar_sdio->mbox_info; + u16 device = ar_sdio->func->device, dev_id_base, dev_id_chiprev; + + mbox_info->htc_addr = ATH10K_HIF_MBOX_BASE_ADDR; + mbox_info->block_size = ATH10K_HIF_MBOX_BLOCK_SIZE; + mbox_info->block_mask = ATH10K_HIF_MBOX_BLOCK_SIZE - 1; + mbox_info->gmbox_addr = ATH10K_HIF_GMBOX_BASE_ADDR; + mbox_info->gmbox_sz = ATH10K_HIF_GMBOX_WIDTH; + + mbox_info->ext_info[0].htc_ext_addr = ATH10K_HIF_MBOX0_EXT_BASE_ADDR; + + dev_id_base = FIELD_GET(QCA_MANUFACTURER_ID_BASE, device); + dev_id_chiprev = FIELD_GET(QCA_MANUFACTURER_ID_REV_MASK, device); + switch (dev_id_base) { + case QCA_MANUFACTURER_ID_AR6005_BASE: + if (dev_id_chiprev < 4) + mbox_info->ext_info[0].htc_ext_sz = + ATH10K_HIF_MBOX0_EXT_WIDTH; + else + /* from QCA6174 2.0(0x504), the width has been extended + * to 56K + */ + mbox_info->ext_info[0].htc_ext_sz = + ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0; + break; + case QCA_MANUFACTURER_ID_QCA9377_BASE: + mbox_info->ext_info[0].htc_ext_sz = + ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0; + break; + default: + mbox_info->ext_info[0].htc_ext_sz = + ATH10K_HIF_MBOX0_EXT_WIDTH; + } + + mbox_info->ext_info[1].htc_ext_addr = + mbox_info->ext_info[0].htc_ext_addr + + mbox_info->ext_info[0].htc_ext_sz + + ATH10K_HIF_MBOX_DUMMY_SPACE_SIZE; + mbox_info->ext_info[1].htc_ext_sz = ATH10K_HIF_MBOX1_EXT_WIDTH; +} + +/* BMI functions */ + +static int ath10k_sdio_bmi_credits(struct ath10k *ar) +{ + u32 addr, cmd_credits; + unsigned long timeout; + int ret; + + /* Read the counter register to get the command credits */ + addr = MBOX_COUNT_DEC_ADDRESS + ATH10K_HIF_MBOX_NUM_MAX * 4; + timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ; + cmd_credits = 0; + + while (time_before(jiffies, timeout) && !cmd_credits) { + /* Hit the credit counter with a 4-byte access, the first byte + * read will hit the counter and cause a decrement, while the + * remaining 3 bytes has no effect. The rationale behind this + * is to make all HIF accesses 4-byte aligned. + */ + ret = ath10k_sdio_read32(ar, addr, &cmd_credits); + if (ret) { + ath10k_warn(ar, + "unable to decrement the command credit count register: %d\n", + ret); + return ret; + } + + /* The counter is only 8 bits. + * Ignore anything in the upper 3 bytes + */ + cmd_credits &= 0xFF; + } + + if (!cmd_credits) { + ath10k_warn(ar, "bmi communication timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int ath10k_sdio_bmi_get_rx_lookahead(struct ath10k *ar) +{ + unsigned long timeout; + u32 rx_word; + int ret; + + timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ; + rx_word = 0; + + while ((time_before(jiffies, timeout)) && !rx_word) { + ret = ath10k_sdio_read32(ar, + MBOX_HOST_INT_STATUS_ADDRESS, + &rx_word); + if (ret) { + ath10k_warn(ar, "unable to read RX_LOOKAHEAD_VALID: %d\n", ret); + return ret; + } + + /* all we really want is one bit */ + rx_word &= 1; + } + + if (!rx_word) { + ath10k_warn(ar, "bmi_recv_buf FIFO empty\n"); + return -EINVAL; + } + + return ret; +} + +static int ath10k_sdio_bmi_exchange_msg(struct ath10k *ar, + void *req, u32 req_len, + void *resp, u32 *resp_len) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + u32 addr; + int ret; + + if (req) { + ret = ath10k_sdio_bmi_credits(ar); + if (ret) + return ret; + + addr = ar_sdio->mbox_info.htc_addr; + + memcpy(ar_sdio->bmi_buf, req, req_len); + ret = ath10k_sdio_write(ar, addr, ar_sdio->bmi_buf, req_len); + if (ret) { + ath10k_warn(ar, + "unable to send the bmi data to the device: %d\n", + ret); + return ret; + } + } + + if (!resp || !resp_len) + /* No response expected */ + return 0; + + /* During normal bootup, small reads may be required. + * Rather than issue an HIF Read and then wait as the Target + * adds successive bytes to the FIFO, we wait here until + * we know that response data is available. + * + * This allows us to cleanly timeout on an unexpected + * Target failure rather than risk problems at the HIF level. + * In particular, this avoids SDIO timeouts and possibly garbage + * data on some host controllers. And on an interconnect + * such as Compact Flash (as well as some SDIO masters) which + * does not provide any indication on data timeout, it avoids + * a potential hang or garbage response. + * + * Synchronization is more difficult for reads larger than the + * size of the MBOX FIFO (128B), because the Target is unable + * to push the 129th byte of data until AFTER the Host posts an + * HIF Read and removes some FIFO data. So for large reads the + * Host proceeds to post an HIF Read BEFORE all the data is + * actually available to read. Fortunately, large BMI reads do + * not occur in practice -- they're supported for debug/development. + * + * So Host/Target BMI synchronization is divided into these cases: + * CASE 1: length < 4 + * Should not happen + * + * CASE 2: 4 <= length <= 128 + * Wait for first 4 bytes to be in FIFO + * If CONSERVATIVE_BMI_READ is enabled, also wait for + * a BMI command credit, which indicates that the ENTIRE + * response is available in the the FIFO + * + * CASE 3: length > 128 + * Wait for the first 4 bytes to be in FIFO + * + * For most uses, a small timeout should be sufficient and we will + * usually see a response quickly; but there may be some unusual + * (debug) cases of BMI_EXECUTE where we want an larger timeout. + * For now, we use an unbounded busy loop while waiting for + * BMI_EXECUTE. + * + * If BMI_EXECUTE ever needs to support longer-latency execution, + * especially in production, this code needs to be enhanced to sleep + * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently + * a function of Host processor speed. + */ + ret = ath10k_sdio_bmi_get_rx_lookahead(ar); + if (ret) + return ret; + + /* We always read from the start of the mbox address */ + addr = ar_sdio->mbox_info.htc_addr; + ret = ath10k_sdio_read(ar, addr, ar_sdio->bmi_buf, *resp_len); + if (ret) { + ath10k_warn(ar, + "unable to read the bmi data from the device: %d\n", + ret); + return ret; + } + + memcpy(resp, ar_sdio->bmi_buf, *resp_len); + + return 0; +} + +/* sdio async handling functions */ + +static struct ath10k_sdio_bus_request +*ath10k_sdio_alloc_busreq(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_bus_request *bus_req; + + spin_lock_bh(&ar_sdio->lock); + + if (list_empty(&ar_sdio->bus_req_freeq)) { + bus_req = NULL; + goto out; + } + + bus_req = list_first_entry(&ar_sdio->bus_req_freeq, + struct ath10k_sdio_bus_request, list); + list_del(&bus_req->list); + +out: + spin_unlock_bh(&ar_sdio->lock); + return bus_req; +} + +static void ath10k_sdio_free_bus_req(struct ath10k *ar, + struct ath10k_sdio_bus_request *bus_req) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + + memset(bus_req, 0, sizeof(*bus_req)); + + spin_lock_bh(&ar_sdio->lock); + list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq); + spin_unlock_bh(&ar_sdio->lock); +} + +static void __ath10k_sdio_write_async(struct ath10k *ar, + struct ath10k_sdio_bus_request *req) +{ + struct ath10k_htc_ep *ep; + struct sk_buff *skb; + int ret; + + skb = req->skb; + ret = ath10k_sdio_write(ar, req->address, skb->data, skb->len); + if (ret) + ath10k_warn(ar, "failed to write skb to 0x%x asynchronously: %d", + req->address, ret); + + if (req->htc_msg) { + ep = &ar->htc.endpoint[req->eid]; + ath10k_htc_notify_tx_completion(ep, skb); + } else if (req->comp) { + complete(req->comp); + } + + ath10k_sdio_free_bus_req(ar, req); +} + +static void ath10k_sdio_write_async_work(struct work_struct *work) +{ + struct ath10k_sdio *ar_sdio = container_of(work, struct ath10k_sdio, + wr_async_work); + struct ath10k *ar = ar_sdio->ar; + struct ath10k_sdio_bus_request *req, *tmp_req; + + spin_lock_bh(&ar_sdio->wr_async_lock); + + list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) { + list_del(&req->list); + spin_unlock_bh(&ar_sdio->wr_async_lock); + __ath10k_sdio_write_async(ar, req); + spin_lock_bh(&ar_sdio->wr_async_lock); + } + + spin_unlock_bh(&ar_sdio->wr_async_lock); +} + +static int ath10k_sdio_prep_async_req(struct ath10k *ar, u32 addr, + struct sk_buff *skb, + struct completion *comp, + bool htc_msg, enum ath10k_htc_ep_id eid) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_bus_request *bus_req; + + /* Allocate a bus request for the message and queue it on the + * SDIO workqueue. + */ + bus_req = ath10k_sdio_alloc_busreq(ar); + if (!bus_req) { + ath10k_warn(ar, + "unable to allocate bus request for async request\n"); + return -ENOMEM; + } + + bus_req->skb = skb; + bus_req->eid = eid; + bus_req->address = addr; + bus_req->htc_msg = htc_msg; + bus_req->comp = comp; + + spin_lock_bh(&ar_sdio->wr_async_lock); + list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq); + spin_unlock_bh(&ar_sdio->wr_async_lock); + + return 0; +} + +/* IRQ handler */ + +static void ath10k_sdio_irq_handler(struct sdio_func *func) +{ + struct ath10k_sdio *ar_sdio = sdio_get_drvdata(func); + struct ath10k *ar = ar_sdio->ar; + unsigned long timeout; + bool done = false; + int ret; + + /* Release the host during interrupts so we can pick it back up when + * we process commands. + */ + sdio_release_host(ar_sdio->func); + + timeout = jiffies + ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ; + while (time_before(jiffies, timeout) && !done) { + ret = ath10k_sdio_mbox_proc_pending_irqs(ar, &done); + if (ret) + break; + } + + sdio_claim_host(ar_sdio->func); + + wake_up(&ar_sdio->irq_wq); + + if (ret && ret != -ECANCELED) + ath10k_warn(ar, "failed to process pending SDIO interrupts: %d\n", + ret); +} + +/* sdio HIF functions */ + +static int ath10k_sdio_hif_disable_intrs(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + struct ath10k_sdio_irq_enable_regs *regs = irq_data->irq_en_reg; + int ret; + + mutex_lock(&irq_data->mtx); + + memset(regs, 0, sizeof(*regs)); + ret = ath10k_sdio_write(ar, MBOX_INT_STATUS_ENABLE_ADDRESS, + ®s->int_status_en, sizeof(*regs)); + if (ret) + ath10k_warn(ar, "unable to disable sdio interrupts: %d\n", ret); + + mutex_unlock(&irq_data->mtx); + + return ret; +} + +static int ath10k_sdio_hif_power_up(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + int ret; + + if (!ar_sdio->is_disabled) + return 0; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio power on\n"); + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) { + ath10k_warn(ar, "unable to enable sdio function: %d)\n", ret); + sdio_release_host(func); + return ret; + } + + sdio_release_host(func); + + /* Wait for hardware to initialise. It should take a lot less than + * 20 ms but let's be conservative here. + */ + msleep(20); + + ar_sdio->is_disabled = false; + + ret = ath10k_sdio_hif_disable_intrs(ar); + if (ret) + return ret; + + return 0; +} + +static void ath10k_sdio_hif_power_down(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + int ret; + + if (ar_sdio->is_disabled) + return; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio power off\n"); + + /* Disable the card */ + sdio_claim_host(ar_sdio->func); + ret = sdio_disable_func(ar_sdio->func); + sdio_release_host(ar_sdio->func); + + if (ret) + ath10k_warn(ar, "unable to disable sdio function: %d\n", ret); + + ar_sdio->is_disabled = true; +} + +static int ath10k_sdio_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + enum ath10k_htc_ep_id eid; + struct sk_buff *skb; + int ret, i; + + eid = pipe_id_to_eid(pipe_id); + + for (i = 0; i < n_items; i++) { + size_t padded_len; + u32 address; + + skb = items[i].transfer_context; + padded_len = ath10k_sdio_calc_txrx_padded_len(ar_sdio, + skb->len); + skb_trim(skb, padded_len); + + /* Write TX data to the end of the mbox address space */ + address = ar_sdio->mbox_addr[eid] + ar_sdio->mbox_size[eid] - + skb->len; + ret = ath10k_sdio_prep_async_req(ar, address, skb, + NULL, true, eid); + if (ret) + return ret; + } + + queue_work(ar_sdio->workqueue, &ar_sdio->wr_async_work); + + return 0; +} + +static int ath10k_sdio_hif_enable_intrs(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + struct ath10k_sdio_irq_enable_regs *regs = irq_data->irq_en_reg; + int ret; + + mutex_lock(&irq_data->mtx); + + /* Enable all but CPU interrupts */ + regs->int_status_en = FIELD_PREP(MBOX_INT_STATUS_ENABLE_ERROR_MASK, 1) | + FIELD_PREP(MBOX_INT_STATUS_ENABLE_CPU_MASK, 1) | + FIELD_PREP(MBOX_INT_STATUS_ENABLE_COUNTER_MASK, 1); + + /* NOTE: There are some cases where HIF can do detection of + * pending mbox messages which is disabled now. + */ + regs->int_status_en |= + FIELD_PREP(MBOX_INT_STATUS_ENABLE_MBOX_DATA_MASK, 1); + + /* Set up the CPU Interrupt status Register */ + regs->cpu_int_status_en = 0; + + /* Set up the Error Interrupt status Register */ + regs->err_int_status_en = + FIELD_PREP(MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, 1) | + FIELD_PREP(MBOX_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, 1); + + /* Enable Counter interrupt status register to get fatal errors for + * debugging. + */ + regs->cntr_int_status_en = + FIELD_PREP(MBOX_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + ATH10K_SDIO_TARGET_DEBUG_INTR_MASK); + + ret = ath10k_sdio_write(ar, MBOX_INT_STATUS_ENABLE_ADDRESS, + ®s->int_status_en, sizeof(*regs)); + if (ret) + ath10k_warn(ar, + "failed to update mbox interrupt status register : %d\n", + ret); + + mutex_unlock(&irq_data->mtx); + return ret; +} + +static int ath10k_sdio_hif_set_mbox_sleep(struct ath10k *ar, bool enable_sleep) +{ + u32 val; + int ret; + + ret = ath10k_sdio_read32(ar, ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL, &val); + if (ret) { + ath10k_warn(ar, "failed to read fifo/chip control register: %d\n", + ret); + return ret; + } + + if (enable_sleep) + val &= ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF; + else + val |= ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON; + + ret = ath10k_sdio_write32(ar, ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL, val); + if (ret) { + ath10k_warn(ar, "failed to write to FIFO_TIMEOUT_AND_CHIP_CONTROL: %d", + ret); + return ret; + } + + return 0; +} + +/* HIF diagnostics */ + +static int ath10k_sdio_hif_diag_read(struct ath10k *ar, u32 address, void *buf, + size_t buf_len) +{ + int ret; + + /* set window register to start read cycle */ + ret = ath10k_sdio_write32(ar, MBOX_WINDOW_READ_ADDR_ADDRESS, address); + if (ret) { + ath10k_warn(ar, "failed to set mbox window read address: %d", ret); + return ret; + } + + /* read the data */ + ret = ath10k_sdio_read(ar, MBOX_WINDOW_DATA_ADDRESS, buf, buf_len); + if (ret) { + ath10k_warn(ar, "failed to read from mbox window data addrress: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ath10k_sdio_hif_diag_read32(struct ath10k *ar, u32 address, + u32 *value) +{ + __le32 *val; + int ret; + + val = kzalloc(sizeof(*val), GFP_KERNEL); + if (!val) + return -ENOMEM; + + ret = ath10k_sdio_hif_diag_read(ar, address, val, sizeof(*val)); + if (ret) + goto out; + + *value = __le32_to_cpu(*val); + +out: + kfree(val); + + return ret; +} + +static int ath10k_sdio_hif_diag_write_mem(struct ath10k *ar, u32 address, + const void *data, int nbytes) +{ + int ret; + + /* set write data */ + ret = ath10k_sdio_write(ar, MBOX_WINDOW_DATA_ADDRESS, data, nbytes); + if (ret) { + ath10k_warn(ar, + "failed to write 0x%p to mbox window data addrress: %d\n", + data, ret); + return ret; + } + + /* set window register, which starts the write cycle */ + ret = ath10k_sdio_write32(ar, MBOX_WINDOW_WRITE_ADDR_ADDRESS, address); + if (ret) { + ath10k_warn(ar, "failed to set mbox window write address: %d", ret); + return ret; + } + + return 0; +} + +/* HIF start/stop */ + +static int ath10k_sdio_hif_start(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + u32 addr, val; + int ret; + + /* Sleep 20 ms before HIF interrupts are disabled. + * This will give target plenty of time to process the BMI done + * request before interrupts are disabled. + */ + msleep(20); + ret = ath10k_sdio_hif_disable_intrs(ar); + if (ret) + return ret; + + /* eid 0 always uses the lower part of the extended mailbox address + * space (ext_info[0].htc_ext_addr). + */ + ar_sdio->mbox_addr[0] = ar_sdio->mbox_info.ext_info[0].htc_ext_addr; + ar_sdio->mbox_size[0] = ar_sdio->mbox_info.ext_info[0].htc_ext_sz; + + sdio_claim_host(ar_sdio->func); + + /* Register the isr */ + ret = sdio_claim_irq(ar_sdio->func, ath10k_sdio_irq_handler); + if (ret) { + ath10k_warn(ar, "failed to claim sdio interrupt: %d\n", ret); + sdio_release_host(ar_sdio->func); + return ret; + } + + sdio_release_host(ar_sdio->func); + + ret = ath10k_sdio_hif_enable_intrs(ar); + if (ret) + ath10k_warn(ar, "failed to enable sdio interrupts: %d\n", ret); + + addr = host_interest_item_address(HI_ITEM(hi_acs_flags)); + + ret = ath10k_sdio_hif_diag_read32(ar, addr, &val); + if (ret) { + ath10k_warn(ar, "unable to read hi_acs_flags address: %d\n", ret); + return ret; + } + + if (val & HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK) { + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio mailbox swap service enabled\n"); + ar_sdio->swap_mbox = true; + } + + /* Enable sleep and then disable it again */ + ret = ath10k_sdio_hif_set_mbox_sleep(ar, true); + if (ret) + return ret; + + /* Wait for 20ms for the written value to take effect */ + msleep(20); + + ret = ath10k_sdio_hif_set_mbox_sleep(ar, false); + if (ret) + return ret; + + return 0; +} + +#define SDIO_IRQ_DISABLE_TIMEOUT_HZ (3 * HZ) + +static void ath10k_sdio_irq_disable(struct ath10k *ar) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_sdio_irq_data *irq_data = &ar_sdio->irq_data; + struct ath10k_sdio_irq_enable_regs *regs = irq_data->irq_en_reg; + struct sk_buff *skb; + struct completion irqs_disabled_comp; + int ret; + + skb = dev_alloc_skb(sizeof(*regs)); + if (!skb) + return; + + mutex_lock(&irq_data->mtx); + + memset(regs, 0, sizeof(*regs)); /* disable all interrupts */ + memcpy(skb->data, regs, sizeof(*regs)); + skb_put(skb, sizeof(*regs)); + + mutex_unlock(&irq_data->mtx); + + init_completion(&irqs_disabled_comp); + ret = ath10k_sdio_prep_async_req(ar, MBOX_INT_STATUS_ENABLE_ADDRESS, + skb, &irqs_disabled_comp, false, 0); + if (ret) + goto out; + + queue_work(ar_sdio->workqueue, &ar_sdio->wr_async_work); + + /* Wait for the completion of the IRQ disable request. + * If there is a timeout we will try to disable irq's anyway. + */ + ret = wait_for_completion_timeout(&irqs_disabled_comp, + SDIO_IRQ_DISABLE_TIMEOUT_HZ); + if (!ret) + ath10k_warn(ar, "sdio irq disable request timed out\n"); + + sdio_claim_host(ar_sdio->func); + + ret = sdio_release_irq(ar_sdio->func); + if (ret) + ath10k_warn(ar, "failed to release sdio interrupt: %d\n", ret); + + sdio_release_host(ar_sdio->func); + +out: + kfree_skb(skb); +} + +static void ath10k_sdio_hif_stop(struct ath10k *ar) +{ + struct ath10k_sdio_bus_request *req, *tmp_req; + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + + ath10k_sdio_irq_disable(ar); + + cancel_work_sync(&ar_sdio->wr_async_work); + + spin_lock_bh(&ar_sdio->wr_async_lock); + + /* Free all bus requests that have not been handled */ + list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) { + struct ath10k_htc_ep *ep; + + list_del(&req->list); + + if (req->htc_msg) { + ep = &ar->htc.endpoint[req->eid]; + ath10k_htc_notify_tx_completion(ep, req->skb); + } else if (req->skb) { + kfree_skb(req->skb); + } + ath10k_sdio_free_bus_req(ar, req); + } + + spin_unlock_bh(&ar_sdio->wr_async_lock); +} + +#ifdef CONFIG_PM + +static int ath10k_sdio_hif_suspend(struct ath10k *ar) +{ + return -EOPNOTSUPP; +} + +static int ath10k_sdio_hif_resume(struct ath10k *ar) +{ + switch (ar->state) { + case ATH10K_STATE_OFF: + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio resume configuring sdio\n"); + + /* need to set sdio settings after power is cut from sdio */ + ath10k_sdio_config(ar); + break; + + case ATH10K_STATE_ON: + default: + break; + } + + return 0; +} +#endif + +static int ath10k_sdio_hif_map_service_to_pipe(struct ath10k *ar, + u16 service_id, + u8 *ul_pipe, u8 *dl_pipe) +{ + struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct ath10k_htc *htc = &ar->htc; + u32 htt_addr, wmi_addr, htt_mbox_size, wmi_mbox_size; + enum ath10k_htc_ep_id eid; + bool ep_found = false; + int i; + + /* For sdio, we are interested in the mapping between eid + * and pipeid rather than service_id to pipe_id. + * First we find out which eid has been allocated to the + * service... + */ + for (i = 0; i < ATH10K_HTC_EP_COUNT; i++) { + if (htc->endpoint[i].service_id == service_id) { + eid = htc->endpoint[i].eid; + ep_found = true; + break; + } + } + + if (!ep_found) + return -EINVAL; + + /* Then we create the simplest mapping possible between pipeid + * and eid + */ + *ul_pipe = *dl_pipe = (u8)eid; + + /* Normally, HTT will use the upper part of the extended + * mailbox address space (ext_info[1].htc_ext_addr) and WMI ctrl + * the lower part (ext_info[0].htc_ext_addr). + * If fw wants swapping of mailbox addresses, the opposite is true. + */ + if (ar_sdio->swap_mbox) { + htt_addr = ar_sdio->mbox_info.ext_info[0].htc_ext_addr; + wmi_addr = ar_sdio->mbox_info.ext_info[1].htc_ext_addr; + htt_mbox_size = ar_sdio->mbox_info.ext_info[0].htc_ext_sz; + wmi_mbox_size = ar_sdio->mbox_info.ext_info[1].htc_ext_sz; + } else { + htt_addr = ar_sdio->mbox_info.ext_info[1].htc_ext_addr; + wmi_addr = ar_sdio->mbox_info.ext_info[0].htc_ext_addr; + htt_mbox_size = ar_sdio->mbox_info.ext_info[1].htc_ext_sz; + wmi_mbox_size = ar_sdio->mbox_info.ext_info[0].htc_ext_sz; + } + + switch (service_id) { + case ATH10K_HTC_SVC_ID_RSVD_CTRL: + /* HTC ctrl ep mbox address has already been setup in + * ath10k_sdio_hif_start + */ + break; + case ATH10K_HTC_SVC_ID_WMI_CONTROL: + ar_sdio->mbox_addr[eid] = wmi_addr; + ar_sdio->mbox_size[eid] = wmi_mbox_size; + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio wmi ctrl mbox_addr 0x%x mbox_size %d\n", + ar_sdio->mbox_addr[eid], ar_sdio->mbox_size[eid]); + break; + case ATH10K_HTC_SVC_ID_HTT_DATA_MSG: + ar_sdio->mbox_addr[eid] = htt_addr; + ar_sdio->mbox_size[eid] = htt_mbox_size; + ath10k_dbg(ar, ATH10K_DBG_SDIO, + "sdio htt data mbox_addr 0x%x mbox_size %d\n", + ar_sdio->mbox_addr[eid], ar_sdio->mbox_size[eid]); + break; + default: + ath10k_warn(ar, "unsupported HTC service id: %d\n", + service_id); + return -EINVAL; + } + + return 0; +} + +static void ath10k_sdio_hif_get_default_pipe(struct ath10k *ar, + u8 *ul_pipe, u8 *dl_pipe) +{ + ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio hif get default pipe\n"); + + /* HTC ctrl ep (SVC id 1) always has eid (and pipe_id in our + * case) == 0 + */ + *ul_pipe = 0; + *dl_pipe = 0; +} + +/* This op is currently only used by htc_wait_target if the HTC ready + * message times out. It is not applicable for SDIO since there is nothing + * we can do if the HTC ready message does not arrive in time. + * TODO: Make this op non mandatory by introducing a NULL check in the + * hif op wrapper. + */ +static void ath10k_sdio_hif_send_complete_check(struct ath10k *ar, + u8 pipe, int force) +{ +} + +static const struct ath10k_hif_ops ath10k_sdio_hif_ops = { + .tx_sg = ath10k_sdio_hif_tx_sg, + .diag_read = ath10k_sdio_hif_diag_read, + .diag_write = ath10k_sdio_hif_diag_write_mem, + .exchange_bmi_msg = ath10k_sdio_bmi_exchange_msg, + .start = ath10k_sdio_hif_start, + .stop = ath10k_sdio_hif_stop, + .map_service_to_pipe = ath10k_sdio_hif_map_service_to_pipe, + .get_default_pipe = ath10k_sdio_hif_get_default_pipe, + .send_complete_check = ath10k_sdio_hif_send_complete_check, + .power_up = ath10k_sdio_hif_power_up, + .power_down = ath10k_sdio_hif_power_down, +#ifdef CONFIG_PM + .suspend = ath10k_sdio_hif_suspend, + .resume = ath10k_sdio_hif_resume, +#endif +}; + +#ifdef CONFIG_PM_SLEEP + +/* Empty handlers so that mmc subsystem doesn't remove us entirely during + * suspend. We instead follow cfg80211 suspend/resume handlers. + */ +static int ath10k_sdio_pm_suspend(struct device *device) +{ + return 0; +} + +static int ath10k_sdio_pm_resume(struct device *device) +{ + return 0; +} + +static SIMPLE_DEV_PM_OPS(ath10k_sdio_pm_ops, ath10k_sdio_pm_suspend, + ath10k_sdio_pm_resume); + +#define ATH10K_SDIO_PM_OPS (&ath10k_sdio_pm_ops) + +#else + +#define ATH10K_SDIO_PM_OPS NULL + +#endif /* CONFIG_PM_SLEEP */ + +static int ath10k_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct ath10k_sdio *ar_sdio; + struct ath10k *ar; + enum ath10k_hw_rev hw_rev; + u32 chip_id, dev_id_base; + int ret, i; + + /* Assumption: All SDIO based chipsets (so far) are QCA6174 based. + * If there will be newer chipsets that does not use the hw reg + * setup as defined in qca6174_regs and qca6174_values, this + * assumption is no longer valid and hw_rev must be setup differently + * depending on chipset. + */ + hw_rev = ATH10K_HW_QCA6174; + + ar = ath10k_core_create(sizeof(*ar_sdio), &func->dev, ATH10K_BUS_SDIO, + hw_rev, &ath10k_sdio_hif_ops); + if (!ar) { + dev_err(&func->dev, "failed to allocate core\n"); + return -ENOMEM; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n", + func->num, func->vendor, func->device, + func->max_blksize, func->cur_blksize); + + ar_sdio = ath10k_sdio_priv(ar); + + ar_sdio->irq_data.irq_proc_reg = + kzalloc(sizeof(struct ath10k_sdio_irq_proc_regs), + GFP_KERNEL); + if (!ar_sdio->irq_data.irq_proc_reg) { + ret = -ENOMEM; + goto err_core_destroy; + } + + ar_sdio->irq_data.irq_en_reg = + kzalloc(sizeof(struct ath10k_sdio_irq_enable_regs), + GFP_KERNEL); + if (!ar_sdio->irq_data.irq_en_reg) { + ret = -ENOMEM; + goto err_free_proc_reg; + } + + ar_sdio->bmi_buf = kzalloc(BMI_MAX_CMDBUF_SIZE, GFP_KERNEL); + if (!ar_sdio->bmi_buf) { + ret = -ENOMEM; + goto err_free_en_reg; + } + + ar_sdio->func = func; + sdio_set_drvdata(func, ar_sdio); + + ar_sdio->is_disabled = true; + ar_sdio->ar = ar; + + spin_lock_init(&ar_sdio->lock); + spin_lock_init(&ar_sdio->wr_async_lock); + mutex_init(&ar_sdio->irq_data.mtx); + + INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); + INIT_LIST_HEAD(&ar_sdio->wr_asyncq); + + INIT_WORK(&ar_sdio->wr_async_work, ath10k_sdio_write_async_work); + ar_sdio->workqueue = create_singlethread_workqueue("ath10k_sdio_wq"); + if (!ar_sdio->workqueue) { + ret = -ENOMEM; + goto err_free_bmi_buf; + } + + init_waitqueue_head(&ar_sdio->irq_wq); + + for (i = 0; i < ATH10K_SDIO_BUS_REQUEST_MAX_NUM; i++) + ath10k_sdio_free_bus_req(ar, &ar_sdio->bus_req[i]); + + dev_id_base = FIELD_GET(QCA_MANUFACTURER_ID_BASE, id->device); + switch (dev_id_base) { + case QCA_MANUFACTURER_ID_AR6005_BASE: + case QCA_MANUFACTURER_ID_QCA9377_BASE: + ar->dev_id = QCA9377_1_0_DEVICE_ID; + break; + default: + ret = -ENODEV; + ath10k_err(ar, "unsupported device id %u (0x%x)\n", + dev_id_base, id->device); + goto err_free_bmi_buf; + } + + ar->id.vendor = id->vendor; + ar->id.device = id->device; + + ath10k_sdio_set_mbox_info(ar); + + ret = ath10k_sdio_config(ar); + if (ret) { + ath10k_err(ar, "failed to config sdio: %d\n", ret); + goto err_free_wq; + } + + /* TODO: don't know yet how to get chip_id with SDIO */ + chip_id = 0; + ret = ath10k_core_register(ar, chip_id); + if (ret) { + ath10k_err(ar, "failed to register driver core: %d\n", ret); + goto err_free_wq; + } + + /* TODO: remove this once SDIO support is fully implemented */ + ath10k_warn(ar, "WARNING: ath10k SDIO support is incomplete, don't expect anything to work!\n"); + + return 0; + +err_free_wq: + destroy_workqueue(ar_sdio->workqueue); +err_free_bmi_buf: + kfree(ar_sdio->bmi_buf); +err_free_en_reg: + kfree(ar_sdio->irq_data.irq_en_reg); +err_free_proc_reg: + kfree(ar_sdio->irq_data.irq_proc_reg); +err_core_destroy: + ath10k_core_destroy(ar); + + return ret; +} + +static void ath10k_sdio_remove(struct sdio_func *func) +{ + struct ath10k_sdio *ar_sdio = sdio_get_drvdata(func); + struct ath10k *ar = ar_sdio->ar; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "sdio removed func %d vendor 0x%x device 0x%x\n", + func->num, func->vendor, func->device); + + (void)ath10k_sdio_hif_disable_intrs(ar); + cancel_work_sync(&ar_sdio->wr_async_work); + ath10k_core_unregister(ar); + ath10k_core_destroy(ar); +} + +static const struct sdio_device_id ath10k_sdio_devices[] = { + {SDIO_DEVICE(QCA_MANUFACTURER_CODE, + (QCA_SDIO_ID_AR6005_BASE | 0xA))}, + {SDIO_DEVICE(QCA_MANUFACTURER_CODE, + (QCA_SDIO_ID_QCA9377_BASE | 0x1))}, + {}, +}; + +MODULE_DEVICE_TABLE(sdio, ath10k_sdio_devices); + +static struct sdio_driver ath10k_sdio_driver = { + .name = "ath10k_sdio", + .id_table = ath10k_sdio_devices, + .probe = ath10k_sdio_probe, + .remove = ath10k_sdio_remove, + .drv.pm = ATH10K_SDIO_PM_OPS, +}; + +static int __init ath10k_sdio_init(void) +{ + int ret; + + ret = sdio_register_driver(&ath10k_sdio_driver); + if (ret) + pr_err("sdio driver registration failed: %d\n", ret); + + return ret; +} + +static void __exit ath10k_sdio_exit(void) +{ + sdio_unregister_driver(&ath10k_sdio_driver); +} + +module_init(ath10k_sdio_init); +module_exit(ath10k_sdio_exit); + +MODULE_AUTHOR("Qualcomm Atheros"); +MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN SDIO devices"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h new file mode 100644 index 000000000000..3f61c67c601d --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/sdio.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. + * Copyright (c) 2016-2017 Erik Stromdahl + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDIO_H_ +#define _SDIO_H_ + +#define ATH10K_HIF_MBOX_BLOCK_SIZE 256 + +#define QCA_MANUFACTURER_ID_BASE GENMASK(11, 8) +#define QCA_MANUFACTURER_ID_AR6005_BASE 0x5 +#define QCA_MANUFACTURER_ID_QCA9377_BASE 0x7 +#define QCA_SDIO_ID_AR6005_BASE 0x500 +#define QCA_SDIO_ID_QCA9377_BASE 0x700 +#define QCA_MANUFACTURER_ID_REV_MASK 0x00FF +#define QCA_MANUFACTURER_CODE 0x271 /* Qualcomm/Atheros */ + +#define ATH10K_SDIO_MAX_BUFFER_SIZE 4096 /*Unsure of this constant*/ + +/* Mailbox address in SDIO address space */ +#define ATH10K_HIF_MBOX_BASE_ADDR 0x1000 +#define ATH10K_HIF_MBOX_WIDTH 0x800 + +#define ATH10K_HIF_MBOX_TOT_WIDTH \ + (ATH10K_HIF_MBOX_NUM_MAX * ATH10K_HIF_MBOX_WIDTH) + +#define ATH10K_HIF_MBOX0_EXT_BASE_ADDR 0x5000 +#define ATH10K_HIF_MBOX0_EXT_WIDTH (36 * 1024) +#define ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0 (56 * 1024) +#define ATH10K_HIF_MBOX1_EXT_WIDTH (36 * 1024) +#define ATH10K_HIF_MBOX_DUMMY_SPACE_SIZE (2 * 1024) + +#define ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH \ + (ATH10K_SDIO_MAX_BUFFER_SIZE - sizeof(struct ath10k_htc_hdr)) + +#define ATH10K_HIF_MBOX_NUM_MAX 4 +#define ATH10K_SDIO_BUS_REQUEST_MAX_NUM 64 + +#define ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ (100 * HZ) + +/* HTC runs over mailbox 0 */ +#define ATH10K_HTC_MAILBOX 0 +#define ATH10K_HTC_MAILBOX_MASK BIT(ATH10K_HTC_MAILBOX) + +/* GMBOX addresses */ +#define ATH10K_HIF_GMBOX_BASE_ADDR 0x7000 +#define ATH10K_HIF_GMBOX_WIDTH 0x4000 + +/* Modified versions of the sdio.h macros. + * The macros in sdio.h can't be used easily with the FIELD_{PREP|GET} + * macros in bitfield.h, so we define our own macros here. + */ +#define ATH10K_SDIO_DRIVE_DTSX_MASK \ + (SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT) + +#define ATH10K_SDIO_DRIVE_DTSX_TYPE_B 0 +#define ATH10K_SDIO_DRIVE_DTSX_TYPE_A 1 +#define ATH10K_SDIO_DRIVE_DTSX_TYPE_C 2 +#define ATH10K_SDIO_DRIVE_DTSX_TYPE_D 3 + +/* SDIO CCCR register definitions */ +#define CCCR_SDIO_IRQ_MODE_REG 0xF0 +#define CCCR_SDIO_IRQ_MODE_REG_SDIO3 0x16 + +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR 0xF2 + +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A 0x02 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C 0x04 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D 0x08 + +#define CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS 0xF0 +#define CCCR_SDIO_ASYNC_INT_DELAY_MASK 0xC0 + +/* mode to enable special 4-bit interrupt assertion without clock */ +#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ BIT(0) +#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_SDIO3 BIT(1) + +#define ATH10K_SDIO_TARGET_DEBUG_INTR_MASK 0x01 + +/* The theoretical maximum number of RX messages that can be fetched + * from the mbox interrupt handler in one loop is derived in the following + * way: + * + * Let's assume that each packet in a bundle of the maximum bundle size + * (HTC_HOST_MAX_MSG_PER_BUNDLE) has the HTC header bundle count set + * to the maximum value (HTC_HOST_MAX_MSG_PER_BUNDLE). + * + * in this case the driver must allocate + * (HTC_HOST_MAX_MSG_PER_BUNDLE * HTC_HOST_MAX_MSG_PER_BUNDLE) skb's. + */ +#define ATH10K_SDIO_MAX_RX_MSGS \ + (HTC_HOST_MAX_MSG_PER_BUNDLE * HTC_HOST_MAX_MSG_PER_BUNDLE) + +#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868u +#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF +#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000 + +struct ath10k_sdio_bus_request { + struct list_head list; + + /* sdio address */ + u32 address; + + struct sk_buff *skb; + enum ath10k_htc_ep_id eid; + int status; + /* Specifies if the current request is an HTC message. + * If not, the eid is not applicable an the TX completion handler + * associated with the endpoint will not be invoked. + */ + bool htc_msg; + /* Completion that (if set) will be invoked for non HTC requests + * (htc_msg == false) when the request has been processed. + */ + struct completion *comp; +}; + +struct ath10k_sdio_rx_data { + struct sk_buff *skb; + size_t alloc_len; + size_t act_len; + enum ath10k_htc_ep_id eid; + bool part_of_bundle; + bool last_in_bundle; + bool trailer_only; + int status; +}; + +struct ath10k_sdio_irq_proc_regs { + u8 host_int_status; + u8 cpu_int_status; + u8 error_int_status; + u8 counter_int_status; + u8 mbox_frame; + u8 rx_lookahead_valid; + u8 host_int_status2; + u8 gmbox_rx_avail; + __le32 rx_lookahead[2]; + __le32 rx_gmbox_lookahead_alias[2]; +}; + +struct ath10k_sdio_irq_enable_regs { + u8 int_status_en; + u8 cpu_int_status_en; + u8 err_int_status_en; + u8 cntr_int_status_en; +}; + +struct ath10k_sdio_irq_data { + /* protects irq_proc_reg and irq_en_reg below. + * We use a mutex here and not a spinlock since we will have the + * mutex locked while calling the sdio_memcpy_ functions. + * These function require non atomic context, and hence, spinlocks + * can be held while calling these functions. + */ + struct mutex mtx; + struct ath10k_sdio_irq_proc_regs *irq_proc_reg; + struct ath10k_sdio_irq_enable_regs *irq_en_reg; +}; + +struct ath10k_mbox_ext_info { + u32 htc_ext_addr; + u32 htc_ext_sz; +}; + +struct ath10k_mbox_info { + u32 htc_addr; + struct ath10k_mbox_ext_info ext_info[2]; + u32 block_size; + u32 block_mask; + u32 gmbox_addr; + u32 gmbox_sz; +}; + +struct ath10k_sdio { + struct sdio_func *func; + + struct ath10k_mbox_info mbox_info; + bool swap_mbox; + u32 mbox_addr[ATH10K_HTC_EP_COUNT]; + u32 mbox_size[ATH10K_HTC_EP_COUNT]; + + /* available bus requests */ + struct ath10k_sdio_bus_request bus_req[ATH10K_SDIO_BUS_REQUEST_MAX_NUM]; + /* free list of bus requests */ + struct list_head bus_req_freeq; + /* protects access to bus_req_freeq */ + spinlock_t lock; + + struct ath10k_sdio_rx_data rx_pkts[ATH10K_SDIO_MAX_RX_MSGS]; + size_t n_rx_pkts; + + struct ath10k *ar; + struct ath10k_sdio_irq_data irq_data; + + /* temporary buffer for BMI requests */ + u8 *bmi_buf; + + wait_queue_head_t irq_wq; + + bool is_disabled; + + struct workqueue_struct *workqueue; + struct work_struct wr_async_work; + struct list_head wr_asyncq; + /* protects access to wr_asyncq */ + spinlock_t wr_async_lock; +}; + +static inline struct ath10k_sdio *ath10k_sdio_priv(struct ath10k *ar) +{ + return (struct ath10k_sdio *)ar->drv_priv; +} + +#endif -- cgit v1.2.3 From a16703aaeaedec7a8bee5be5522c7c3e75478951 Mon Sep 17 00:00:00 2001 From: Michael Mera Date: Mon, 24 Apr 2017 16:11:57 +0900 Subject: ath10k: fix out of bounds access to local buffer During write to debugfs file simulate_fw_crash, fixed-size local buffer 'buf' is accessed and modified at index 'count-1', where 'count' is the size of the write (so potentially out of bounds). This patch fixes this problem. Signed-off-by: Michael Mera Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 4cd2a0fd49d6..389fcb7a9fd0 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -625,17 +625,21 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - char buf[32]; + char buf[32] = {0}; + ssize_t rc; int ret; - simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + /* filter partial writes and invalid commands */ + if (*ppos != 0 || count >= sizeof(buf) || count == 0) + return -EINVAL; - /* make sure that buf is null terminated */ - buf[sizeof(buf) - 1] = 0; + rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + if (rc < 0) + return rc; /* drop the possible '\n' from the end */ - if (buf[count - 1] == '\n') - buf[count - 1] = 0; + if (buf[*ppos - 1] == '\n') + buf[*ppos - 1] = '\0'; mutex_lock(&ar->conf_mutex); -- cgit v1.2.3 From 4dcb78085d569438e9616bf86d2a64e1acdc5e4a Mon Sep 17 00:00:00 2001 From: Ryan Hsu Date: Tue, 25 Apr 2017 14:19:16 -0700 Subject: ath10k: append the wmi_op_version to testmode get_version cmd QCA9xxx and QCA61x4/QCA93xx are using different wmi operation, in order for userspace to differentiate it, appends the wmi_op_version information alone with the get_version command. Signed-off-by: Ryan Hsu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/testmode.c | 7 +++++++ drivers/net/wireless/ath/ath10k/testmode_i.h | 1 + 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c index d8564624415c..9d3eb258ac2f 100644 --- a/drivers/net/wireless/ath/ath10k/testmode.c +++ b/drivers/net/wireless/ath/ath10k/testmode.c @@ -137,6 +137,13 @@ static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[]) return ret; } + ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION, + ar->normal_mode_fw.fw_file.wmi_op_version); + if (ret) { + kfree_skb(skb); + return ret; + } + return cfg80211_testmode_reply(skb); } diff --git a/drivers/net/wireless/ath/ath10k/testmode_i.h b/drivers/net/wireless/ath/ath10k/testmode_i.h index ba81bf66ce85..191a8f34c8ea 100644 --- a/drivers/net/wireless/ath/ath10k/testmode_i.h +++ b/drivers/net/wireless/ath/ath10k/testmode_i.h @@ -33,6 +33,7 @@ enum ath10k_tm_attr { ATH10K_TM_ATTR_WMI_CMDID = 3, ATH10K_TM_ATTR_VERSION_MAJOR = 4, ATH10K_TM_ATTR_VERSION_MINOR = 5, + ATH10K_TM_ATTR_WMI_OP_VERSION = 6, /* keep last */ __ATH10K_TM_ATTR_AFTER_LAST, -- cgit v1.2.3 From 1b9a07ee25049724ab7f7c32282fbf5452530cea Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 10 May 2017 21:32:18 +0300 Subject: {net, IB}/mlx5: Replace mlx5_vzalloc with kvzalloc Commit a7c3e901a46f ("mm: introduce kv[mz]alloc helpers") added proper implementation of mlx5_vzalloc function to the MM core. This made the mlx5_vzalloc function useless, so let's remove it. Signed-off-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- drivers/infiniband/hw/mlx5/cq.c | 6 ++-- drivers/infiniband/hw/mlx5/mad.c | 4 +-- drivers/infiniband/hw/mlx5/main.c | 6 ++-- drivers/infiniband/hw/mlx5/mr.c | 2 +- drivers/infiniband/hw/mlx5/qp.c | 32 ++++++++++---------- drivers/infiniband/hw/mlx5/srq.c | 4 +-- drivers/net/ethernet/mellanox/mlx5/core/debugfs.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c | 8 ++--- .../net/ethernet/mellanox/mlx5/core/en_common.c | 4 +-- .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_fs.c | 24 ++++++--------- .../ethernet/mellanox/mlx5/core/en_fs_ethtool.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 33 ++++++++++----------- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eq.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 24 ++++++--------- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 13 ++++----- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 6 ++-- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 10 +++---- drivers/net/ethernet/mellanox/mlx5/core/ipoib.c | 2 +- .../net/ethernet/mellanox/mlx5/core/pagealloc.c | 4 +-- drivers/net/ethernet/mellanox/mlx5/core/port.c | 6 ++-- drivers/net/ethernet/mellanox/mlx5/core/qp.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/srq.c | 14 ++++----- drivers/net/ethernet/mellanox/mlx5/core/transobj.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 34 +++++++++------------- 26 files changed, 111 insertions(+), 139 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 94c049b62c2f..a384d72ea3cd 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -788,7 +788,7 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata, *inlen = MLX5_ST_SZ_BYTES(create_cq_in) + MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) * ncont; - *cqb = mlx5_vzalloc(*inlen); + *cqb = kvzalloc(*inlen, GFP_KERNEL); if (!*cqb) { err = -ENOMEM; goto err_db; @@ -884,7 +884,7 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, *inlen = MLX5_ST_SZ_BYTES(create_cq_in) + MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) * cq->buf.buf.npages; - *cqb = mlx5_vzalloc(*inlen); + *cqb = kvzalloc(*inlen, GFP_KERNEL); if (!*cqb) { err = -ENOMEM; goto err_buf; @@ -1314,7 +1314,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) inlen = MLX5_ST_SZ_BYTES(modify_cq_in) + MLX5_FLD_SZ_BYTES(modify_cq_in, pas[0]) * npas; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto ex_resize; diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index f1b56de64871..95db929bdc34 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -218,7 +218,7 @@ static int process_pma_cmd(struct ib_device *ibdev, u8 port_num, (struct ib_pma_portcounters_ext *)(out_mad->data + 40); int sz = MLX5_ST_SZ_BYTES(query_vport_counter_out); - out_cnt = mlx5_vzalloc(sz); + out_cnt = kvzalloc(sz, GFP_KERNEL); if (!out_cnt) return IB_MAD_RESULT_FAILURE; @@ -231,7 +231,7 @@ static int process_pma_cmd(struct ib_device *ibdev, u8 port_num, (struct ib_pma_portcounters *)(out_mad->data + 40); int sz = MLX5_ST_SZ_BYTES(ppcnt_reg); - out_cnt = mlx5_vzalloc(sz); + out_cnt = kvzalloc(sz, GFP_KERNEL); if (!out_cnt) return IB_MAD_RESULT_FAILURE; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index d45772da0963..b6991204e5df 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2263,7 +2263,7 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev, if (!is_valid_attr(dev->mdev, flow_attr)) return ERR_PTR(-EINVAL); - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); handler = kzalloc(sizeof(*handler), GFP_KERNEL); if (!handler || !spec) { err = -ENOMEM; @@ -3456,7 +3456,7 @@ static int mlx5_ib_query_q_counters(struct mlx5_ib_dev *dev, __be32 val; int ret, i; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -3485,7 +3485,7 @@ static int mlx5_ib_query_cong_counters(struct mlx5_ib_dev *dev, int ret, i; int offset = port->cnts.num_q_counters; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 366433f71b58..763bb5b36144 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1110,7 +1110,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_mr *ibmr, struct ib_pd *pd, inlen = MLX5_ST_SZ_BYTES(create_mkey_in) + sizeof(*pas) * ((npages + 1) / 2) * 2; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto err_1; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 93959e1e43a3..d17aad0f54c0 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -823,7 +823,7 @@ static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, *inlen = MLX5_ST_SZ_BYTES(create_qp_in) + MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * ncont; - *in = mlx5_vzalloc(*inlen); + *in = kvzalloc(*inlen, GFP_KERNEL); if (!*in) { err = -ENOMEM; goto err_umem; @@ -931,7 +931,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, qp->sq.qend = mlx5_get_send_wqe(qp, qp->sq.wqe_cnt); *inlen = MLX5_ST_SZ_BYTES(create_qp_in) + MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * qp->buf.npages; - *in = mlx5_vzalloc(*inlen); + *in = kvzalloc(*inlen, GFP_KERNEL); if (!*in) { err = -ENOMEM; goto err_buf; @@ -1060,7 +1060,7 @@ static int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev, return err; inlen = MLX5_ST_SZ_BYTES(create_sq_in) + sizeof(u64) * ncont; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto err_umem; @@ -1140,7 +1140,7 @@ static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev, u32 rq_pas_size = get_rq_pas_size(qpc); inlen = MLX5_ST_SZ_BYTES(create_rq_in) + rq_pas_size; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1193,7 +1193,7 @@ static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(create_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1372,7 +1372,7 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, } inlen = MLX5_ST_SZ_BYTES(create_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1633,7 +1633,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, if (err) return err; } else { - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2164,7 +2164,7 @@ static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(modify_tis_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2189,7 +2189,7 @@ static int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(modify_tis_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2434,7 +2434,7 @@ static int modify_raw_packet_qp_rq(struct mlx5_ib_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2479,7 +2479,7 @@ static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(modify_sq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -4294,7 +4294,7 @@ static int query_raw_packet_qp_sq_state(struct mlx5_ib_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(query_sq_out); - out = mlx5_vzalloc(inlen); + out = kvzalloc(inlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -4321,7 +4321,7 @@ static int query_raw_packet_qp_rq_state(struct mlx5_ib_dev *dev, int err; inlen = MLX5_ST_SZ_BYTES(query_rq_out); - out = mlx5_vzalloc(inlen); + out = kvzalloc(inlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -4625,7 +4625,7 @@ static int create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd, dev = to_mdev(pd->device); inlen = MLX5_ST_SZ_BYTES(create_rq_in) + sizeof(u64) * rwq->rq_num_pas; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -4855,7 +4855,7 @@ struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device, return ERR_PTR(-ENOMEM); inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto err; @@ -4934,7 +4934,7 @@ int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr, return -EOPNOTSUPP; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 7cb145f9a6db..43707b101f47 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -127,7 +127,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, goto err_umem; } - in->pas = mlx5_vzalloc(sizeof(*in->pas) * ncont); + in->pas = kvzalloc(sizeof(*in->pas) * ncont, GFP_KERNEL); if (!in->pas) { err = -ENOMEM; goto err_umem; @@ -189,7 +189,7 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, } mlx5_ib_dbg(dev, "srq->buf.page_shift = %d\n", srq->buf.page_shift); - in->pas = mlx5_vzalloc(sizeof(*in->pas) * srq->buf.npages); + in->pas = kvzalloc(sizeof(*in->pas) * srq->buf.npages, GFP_KERNEL); if (!in->pas) { err = -ENOMEM; goto err_buf; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index e94a9532e218..de40b6cfee95 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -405,7 +405,7 @@ static u64 cq_read_field(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, u32 *out; int err; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return param; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index c8a005326e30..f4017c06ddd2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -180,9 +180,8 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); err = -ENOMEM; goto out; } @@ -237,7 +236,7 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft, ft->g = kcalloc(MLX5E_ARFS_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in || !ft->g) { kvfree(ft->g); kvfree(in); @@ -481,9 +480,8 @@ static struct mlx5_flow_handle *arfs_add_rule(struct mlx5e_priv *priv, struct mlx5_flow_table *ft; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); err = -ENOMEM; goto out; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c index f1f17f7a3cd0..46e56ec4c26f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c @@ -65,7 +65,7 @@ static int mlx5e_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, u32 *in; int err; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -147,7 +147,7 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb) inlen = MLX5_ST_SZ_BYTES(modify_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) goto out; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index ce7b09d72ff6..e0dd1048c966 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -1045,7 +1045,7 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, (hfunc != ETH_RSS_HASH_TOP)) return -EINVAL; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c index 576d6787b484..936fc6d96c18 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c @@ -218,11 +218,9 @@ static int mlx5e_add_vlan_rule(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); - if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) return -ENOMEM; - } if (rule_type == MLX5E_VLAN_RULE_TYPE_MATCH_VID) mlx5e_vport_context_update_vlans(priv); @@ -660,11 +658,9 @@ mlx5e_generate_ttc_rule(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); - if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) return ERR_PTR(-ENOMEM); - } if (proto) { spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; @@ -742,7 +738,7 @@ static int mlx5e_create_ttc_table_groups(struct mlx5e_ttc_table *ttc) sizeof(*ft->g), GFP_KERNEL); if (!ft->g) return -ENOMEM; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { kfree(ft->g); return -ENOMEM; @@ -853,11 +849,9 @@ static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, u8 *mc_dmac; u8 *mv_dmac; - spec = mlx5_vzalloc(sizeof(*spec)); - if (!spec) { - netdev_err(priv->netdev, "%s: alloc failed\n", __func__); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) return -ENOMEM; - } mc_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers.dmac_47_16); @@ -917,7 +911,7 @@ static int mlx5e_create_l2_table_groups(struct mlx5e_l2_table *l2_table) ft->g = kcalloc(MLX5E_NUM_L2_GROUPS, sizeof(*ft->g), GFP_KERNEL); if (!ft->g) return -ENOMEM; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { kfree(ft->g); return -ENOMEM; @@ -1072,7 +1066,7 @@ static int mlx5e_create_vlan_table_groups(struct mlx5e_flow_table *ft) int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); int err; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c index 85bf4a389295..bdd82c9b3992 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c @@ -296,7 +296,7 @@ add_ethtool_flow_rule(struct mlx5e_priv *priv, struct mlx5_flow_handle *rule; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return ERR_PTR(-ENOMEM); err = set_flow_attrs(spec->match_criteria, spec->match_value, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index a61b71b6fff3..edc485e489cc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -252,9 +252,9 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) void *out; u32 *in; - in = mlx5_vzalloc(sz); + in = kvzalloc(sz, GFP_KERNEL); if (!in) - goto free_out; + return; MLX5_SET(ppcnt_reg, in, local_port, 1); @@ -288,7 +288,6 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) MLX5_REG_PPCNT, 0, 0); } -free_out: kvfree(in); } @@ -314,7 +313,7 @@ static void mlx5e_update_pcie_counters(struct mlx5e_priv *priv) if (!MLX5_CAP_MCAM_FEATURE(mdev, pcie_performance_group)) return; - in = mlx5_vzalloc(sz); + in = kvzalloc(sz, GFP_KERNEL); if (!in) return; @@ -503,7 +502,7 @@ static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev, if (!MLX5E_VALID_NUM_MTTS(npages)) return -EINVAL; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -711,7 +710,7 @@ static int mlx5e_create_rq(struct mlx5e_rq *rq, inlen = MLX5_ST_SZ_BYTES(create_rq_in) + sizeof(u64) * rq->wq_ctrl.buf.npages; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -748,7 +747,7 @@ static int mlx5e_modify_rq_state(struct mlx5e_rq *rq, int curr_state, int err; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -776,7 +775,7 @@ static int mlx5e_modify_rq_scatter_fcs(struct mlx5e_rq *rq, bool enable) int err; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -805,7 +804,7 @@ static int mlx5e_modify_rq_vsd(struct mlx5e_rq *rq, bool vsd) int err; inlen = MLX5_ST_SZ_BYTES(modify_rq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1134,7 +1133,7 @@ static int mlx5e_create_sq(struct mlx5_core_dev *mdev, inlen = MLX5_ST_SZ_BYTES(create_sq_in) + sizeof(u64) * csp->wq_ctrl->buf.npages; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1182,7 +1181,7 @@ static int mlx5e_modify_sq(struct mlx5_core_dev *mdev, u32 sqn, int err; inlen = MLX5_ST_SZ_BYTES(modify_sq_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -1496,7 +1495,7 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param) inlen = MLX5_ST_SZ_BYTES(create_cq_in) + sizeof(u64) * cq->wq_ctrl.frag_buf.npages; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2091,7 +2090,7 @@ mlx5e_create_rqt(struct mlx5e_priv *priv, int sz, struct mlx5e_rqt *rqt) int i; inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2210,7 +2209,7 @@ int mlx5e_redirect_rqt(struct mlx5e_priv *priv, u32 rqtn, int sz, int err; inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + sizeof(u32) * sz; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2433,7 +2432,7 @@ static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv) int ix; inlen = MLX5_ST_SZ_BYTES(modify_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2850,7 +2849,7 @@ int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv) int tt; inlen = MLX5_ST_SZ_BYTES(create_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -2889,7 +2888,7 @@ int mlx5e_create_direct_tirs(struct mlx5e_priv *priv) int ix; inlen = MLX5_ST_SZ_BYTES(create_tir_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 11c27e4fadf6..66a9bd635176 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1738,7 +1738,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, } flow = kzalloc(sizeof(*flow) + attr_size, GFP_KERNEL); - parse_attr = mlx5_vzalloc(sizeof(*parse_attr)); + parse_attr = kvzalloc(sizeof(*parse_attr), GFP_KERNEL); if (!parse_attr || !flow) { err = -ENOMEM; goto err_free; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index ea5d8d37a75c..df0034d8f48c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -548,7 +548,7 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, inlen = MLX5_ST_SZ_BYTES(create_eq_in) + MLX5_FLD_SZ_BYTES(create_eq_in, pas[0]) * eq->buf.npages; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; goto err_buf; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 2e34d95ea776..81dfcd90b1f5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -248,11 +248,10 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule, if (rx_rule) match_header |= MLX5_MATCH_MISC_PARAMETERS; - spec = mlx5_vzalloc(sizeof(*spec)); - if (!spec) { - esw_warn(esw->dev, "FDB: Failed to alloc match parameters\n"); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) return NULL; - } + dmac_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.dmac_47_16); dmac_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, @@ -350,10 +349,9 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw, int nvports) return -EOPNOTSUPP; } - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; - memset(flow_group_in, 0, inlen); table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size)); @@ -961,7 +959,7 @@ static int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, return -EOPNOTSUPP; } - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; @@ -1078,7 +1076,7 @@ static int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, return -EOPNOTSUPP; } - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; @@ -1241,11 +1239,9 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n", vport->vport, vport->info.vlan, vport->info.qos); - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { err = -ENOMEM; - esw_warn(esw->dev, "vport[%d] configure ingress rules failed, err(%d)\n", - vport->vport, err); goto out; } @@ -1322,11 +1318,9 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", vport->vport, vport->info.vlan, vport->info.qos); - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { err = -ENOMEM; - esw_warn(esw->dev, "vport[%d] configure egress rules failed, err(%d)\n", - vport->vport, err); goto out; } @@ -2158,7 +2152,7 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw, if (!LEGAL_VPORT(esw, vport)) return -EINVAL; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index f991f669047e..3795943ef2d1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -311,9 +311,8 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn struct mlx5_flow_spec *spec; void *misc; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - esw_warn(esw->dev, "FDB: Failed to alloc match parameters\n"); flow_rule = ERR_PTR(-ENOMEM); goto out; } @@ -401,9 +400,8 @@ static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw) struct mlx5_flow_spec *spec; int err = 0; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - esw_warn(esw->dev, "FDB: Failed to alloc match parameters\n"); err = -ENOMEM; goto out; } @@ -488,7 +486,7 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports) u32 *flow_group_in; esw_debug(esw->dev, "Create offloads FDB Tables\n"); - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; @@ -631,7 +629,7 @@ static int esw_create_vport_rx_group(struct mlx5_eswitch *esw) int err = 0; int nvports = priv->sriov.num_vfs + 2; - flow_group_in = mlx5_vzalloc(inlen); + flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; @@ -675,9 +673,8 @@ mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn) struct mlx5_flow_spec *spec; void *misc; - spec = mlx5_vzalloc(sizeof(*spec)); + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { - esw_warn(esw->dev, "Failed to alloc match parameters\n"); flow_rule = ERR_PTR(-ENOMEM); goto out; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 19e3d2fc2099..b27c59af9640 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -235,11 +235,9 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev, u32 *in; int err; - in = mlx5_vzalloc(inlen); - if (!in) { - mlx5_core_warn(dev, "failed to allocate inbox\n"); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) return -ENOMEM; - } MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); MLX5_SET(set_fte_in, in, op_mod, opmod); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index b8a176503d38..20a50f23fb1b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -376,11 +376,9 @@ static void del_rule(struct fs_node *node) int err; bool update_fte = false; - match_value = mlx5_vzalloc(match_len); - if (!match_value) { - mlx5_core_warn(dev, "failed to allocate inbox\n"); + match_value = kvzalloc(match_len, GFP_KERNEL); + if (!match_value) return; - } fs_get_obj(rule, node); fs_get_obj(fte, rule->node.parent); @@ -1159,7 +1157,7 @@ static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft, if (!ft->autogroup.active) return ERR_PTR(-ENOENT); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return ERR_PTR(-ENOMEM); @@ -1778,7 +1776,7 @@ static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_flow_steering struct mlx5_flow_namespace *ns; /* Create the root namespace */ - root_ns = mlx5_vzalloc(sizeof(*root_ns)); + root_ns = kvzalloc(sizeof(*root_ns), GFP_KERNEL); if (!root_ns) return NULL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c index 019c230da498..9b397fe3f159 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c @@ -98,7 +98,7 @@ static int mlx5i_create_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core void *qpc; inlen = MLX5_ST_SZ_BYTES(create_qp_in); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index a57d5a81eb05..efcded7ca27a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -279,7 +279,7 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages, int i; inlen += npages * MLX5_FLD_SZ_BYTES(manage_pages_in, pas[0]); - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) { err = -ENOMEM; mlx5_core_warn(dev, "vzalloc failed %d\n", inlen); @@ -376,7 +376,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, *nclaimed = 0; outlen += npages * MLX5_FLD_SZ_BYTES(manage_pages_out, pas[0]); - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 141583daf5a2..1975d4388d4f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -47,8 +47,8 @@ int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, u32 *in = NULL; void *data; - in = mlx5_vzalloc(inlen); - out = mlx5_vzalloc(outlen); + in = kvzalloc(inlen, GFP_KERNEL); + out = kvzalloc(outlen, GFP_KERNEL); if (!in || !out) goto out; @@ -454,7 +454,7 @@ int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev, u32 *in; int err; - in = mlx5_vzalloc(sz); + in = kvzalloc(sz, GFP_KERNEL); if (!in) { err = -ENOMEM; return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index cbbcef2884be..573a6b27fed8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -527,7 +527,7 @@ int mlx5_core_query_out_of_buffer(struct mlx5_core_dev *dev, u16 counter_id, void *out; int err; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c index 3099630015d7..f774de6f5fcb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c @@ -162,7 +162,7 @@ static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, pas_size = get_pas_size(in); inlen = MLX5_ST_SZ_BYTES(create_srq_in) + pas_size; - create_in = mlx5_vzalloc(inlen); + create_in = kvzalloc(inlen, GFP_KERNEL); if (!create_in) return -ENOMEM; @@ -221,7 +221,7 @@ static int query_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, void *srqc; int err; - srq_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_srq_out)); + srq_out = kvzalloc(MLX5_ST_SZ_BYTES(query_srq_out), GFP_KERNEL); if (!srq_out) return -ENOMEM; @@ -256,7 +256,7 @@ static int create_xrc_srq_cmd(struct mlx5_core_dev *dev, pas_size = get_pas_size(in); inlen = MLX5_ST_SZ_BYTES(create_xrc_srq_in) + pas_size; - create_in = mlx5_vzalloc(inlen); + create_in = kvzalloc(inlen, GFP_KERNEL); if (!create_in) return -ENOMEM; @@ -320,7 +320,7 @@ static int query_xrc_srq_cmd(struct mlx5_core_dev *dev, void *xrc_srqc; int err; - xrcsrq_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_xrc_srq_out)); + xrcsrq_out = kvzalloc(MLX5_ST_SZ_BYTES(query_xrc_srq_out), GFP_KERNEL); if (!xrcsrq_out) return -ENOMEM; memset(xrcsrq_in, 0, sizeof(xrcsrq_in)); @@ -357,7 +357,7 @@ static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, pas_size = get_pas_size(in); inlen = MLX5_ST_SZ_BYTES(create_rmp_in) + pas_size; - create_in = mlx5_vzalloc(inlen); + create_in = kvzalloc(inlen, GFP_KERNEL); if (!create_in) return -ENOMEM; @@ -390,7 +390,7 @@ static int arm_rmp_cmd(struct mlx5_core_dev *dev, void *bitmask; int err; - in = mlx5_vzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in)); + in = kvzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in), GFP_KERNEL); if (!in) return -ENOMEM; @@ -417,7 +417,7 @@ static int query_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, void *rmpc; int err; - rmp_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_rmp_out)); + rmp_out = kvzalloc(MLX5_ST_SZ_BYTES(query_rmp_out), GFP_KERNEL); if (!rmp_out) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c index a00ff49eec18..5e128d7a9ffd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c @@ -284,7 +284,7 @@ int mlx5_core_arm_rmp(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm) void *bitmask; int err; - in = mlx5_vzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in)); + in = kvzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in), GFP_KERNEL); if (!in) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 15c2294dd2b4..06019d00ab7b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -172,7 +172,7 @@ int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, u8 *out_addr; int err; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -197,11 +197,9 @@ int mlx5_modify_nic_vport_mac_address(struct mlx5_core_dev *mdev, void *nic_vport_ctx; u8 *perm_mac; - in = mlx5_vzalloc(inlen); - if (!in) { - mlx5_core_warn(mdev, "failed to allocate inbox\n"); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) return -ENOMEM; - } MLX5_SET(modify_nic_vport_context_in, in, field_select.permanent_address, 1); @@ -231,7 +229,7 @@ int mlx5_query_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 *mtu) u32 *out; int err; - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -251,7 +249,7 @@ int mlx5_modify_nic_vport_mtu(struct mlx5_core_dev *mdev, u16 mtu) void *in; int err; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -501,7 +499,7 @@ int mlx5_query_nic_vport_system_image_guid(struct mlx5_core_dev *mdev, u32 *out; int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -521,7 +519,7 @@ int mlx5_query_nic_vport_node_guid(struct mlx5_core_dev *mdev, u64 *node_guid) u32 *out; int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -551,7 +549,7 @@ int mlx5_modify_nic_vport_node_guid(struct mlx5_core_dev *mdev, if (!MLX5_CAP_ESW(mdev, nic_vport_node_guid_modify)) return -EOPNOTSUPP; - in = mlx5_vzalloc(inlen); + in = kvzalloc(inlen, GFP_KERNEL); if (!in) return -ENOMEM; @@ -577,7 +575,7 @@ int mlx5_query_nic_vport_qkey_viol_cntr(struct mlx5_core_dev *mdev, u32 *out; int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); - out = mlx5_vzalloc(outlen); + out = kvzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; @@ -879,11 +877,9 @@ int mlx5_modify_nic_vport_promisc(struct mlx5_core_dev *mdev, int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); int err; - in = mlx5_vzalloc(inlen); - if (!in) { - mlx5_core_err(mdev, "failed to allocate inbox\n"); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) return -ENOMEM; - } MLX5_SET(modify_nic_vport_context_in, in, field_select.promisc, 1); MLX5_SET(modify_nic_vport_context_in, in, @@ -913,11 +909,9 @@ static int mlx5_nic_vport_update_roce_state(struct mlx5_core_dev *mdev, int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); int err; - in = mlx5_vzalloc(inlen); - if (!in) { - mlx5_core_warn(mdev, "failed to allocate inbox\n"); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) return -ENOMEM; - } MLX5_SET(modify_nic_vport_context_in, in, field_select.roce_en, 1); MLX5_SET(modify_nic_vport_context_in, in, nic_vport_context.roce_en, @@ -952,7 +946,7 @@ int mlx5_core_query_vport_counter(struct mlx5_core_dev *dev, u8 other_vport, int err; is_group_manager = MLX5_CAP_GEN(dev, vport_group_manager); - in = mlx5_vzalloc(in_sz); + in = kvzalloc(in_sz, GFP_KERNEL); if (!in) { err = -ENOMEM; return err; -- cgit v1.2.3 From 2e9d3e83ab82ceae965ee6abd58305886df94ab9 Mon Sep 17 00:00:00 2001 From: Noa Osherovich Date: Wed, 19 Apr 2017 13:12:23 +0300 Subject: net/mlx5: Update the list of the PCI supported devices Add the BlueField device and VF IDs to the supported devices list. Signed-off-by: Noa Osherovich Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 0c123d571b4c..f933922d5cca 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1520,6 +1520,8 @@ static const struct pci_device_id mlx5_core_pci_table[] = { { PCI_VDEVICE(MELLANOX, 0x101a), MLX5_PCI_DEV_IS_VF}, /* ConnectX-5 Ex VF */ { PCI_VDEVICE(MELLANOX, 0x101b) }, /* ConnectX-6 */ { PCI_VDEVICE(MELLANOX, 0x101c), MLX5_PCI_DEV_IS_VF}, /* ConnectX-6 VF */ + { PCI_VDEVICE(MELLANOX, 0xa2d2) }, /* BlueField integrated ConnectX-5 network controller */ + { PCI_VDEVICE(MELLANOX, 0xa2d3), MLX5_PCI_DEV_IS_VF}, /* BlueField integrated ConnectX-5 network controller VF */ { 0, } }; -- cgit v1.2.3 From 0179720d6be2096b8d0a4d143254ff9e77747daa Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Sun, 7 May 2017 13:48:31 +0300 Subject: net/mlx5: Introduce trigger_health_work function Introduce new function for entering bad-health state. This function will be called from FPGA-related logic in a later patch from asynchronous event (IRQ) context, for that we change the spin lock to an IRQ-safe one. Signed-off-by: Ilan Tayari Reviewed-by: Boris Pismenny Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/health.c | 32 ++++++++++++++++-------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index d0515391d33b..c3cedb6cec3f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -185,6 +185,7 @@ static void health_care(struct work_struct *work) struct mlx5_core_health *health; struct mlx5_core_dev *dev; struct mlx5_priv *priv; + unsigned long flags; health = container_of(work, struct mlx5_core_health, work); priv = container_of(health, struct mlx5_priv, health); @@ -192,13 +193,13 @@ static void health_care(struct work_struct *work) mlx5_core_warn(dev, "handling bad device here\n"); mlx5_handle_bad_state(dev); - spin_lock(&health->wq_lock); + spin_lock_irqsave(&health->wq_lock, flags); if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) schedule_delayed_work(&health->recover_work, recover_delay); else dev_err(&dev->pdev->dev, "new health works are not permitted at this stage\n"); - spin_unlock(&health->wq_lock); + spin_unlock_irqrestore(&health->wq_lock, flags); } static const char *hsynd_str(u8 synd) @@ -269,6 +270,20 @@ static unsigned long get_next_poll_jiffies(void) return next; } +void mlx5_trigger_health_work(struct mlx5_core_dev *dev) +{ + struct mlx5_core_health *health = &dev->priv.health; + unsigned long flags; + + spin_lock_irqsave(&health->wq_lock, flags); + if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) + queue_work(health->wq, &health->work); + else + dev_err(&dev->pdev->dev, + "new health works are not permitted at this stage\n"); + spin_unlock_irqrestore(&health->wq_lock, flags); +} + static void poll_health(unsigned long data) { struct mlx5_core_dev *dev = (struct mlx5_core_dev *)data; @@ -297,13 +312,7 @@ static void poll_health(unsigned long data) if (in_fatal(dev) && !health->sick) { health->sick = true; print_health_info(dev); - spin_lock(&health->wq_lock); - if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) - queue_work(health->wq, &health->work); - else - dev_err(&dev->pdev->dev, - "new health works are not permitted at this stage\n"); - spin_unlock(&health->wq_lock); + mlx5_trigger_health_work(dev); } } @@ -333,10 +342,11 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev) void mlx5_drain_health_wq(struct mlx5_core_dev *dev) { struct mlx5_core_health *health = &dev->priv.health; + unsigned long flags; - spin_lock(&health->wq_lock); + spin_lock_irqsave(&health->wq_lock, flags); set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); - spin_unlock(&health->wq_lock); + spin_unlock_irqrestore(&health->wq_lock, flags); cancel_delayed_work_sync(&health->recover_work); cancel_work_sync(&health->work); } -- cgit v1.2.3 From e29341fb3a5b885a4bb5b9a38f2814ca07d3382c Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Mon, 13 Mar 2017 20:05:45 +0200 Subject: net/mlx5: FPGA, Add basic support for Innova Mellanox Innova is a NIC with ConnectX and an FPGA on the same board. The FPGA is a bump-on-the-wire and thus affects operation of the mlx5_core driver on the ConnectX ASIC. Add basic support for Innova in mlx5_core. This allows using the Innova card as a regular NIC, by detecting the FPGA capability bit, and verifying its load state before initializing ConnectX interfaces. Also detect FPGA fatal runtime failures and enter error state if they ever happen. All new FPGA-related logic is placed in its own subdirectory 'fpga', which may be built by selecting CONFIG_MLX5_FPGA. This prepares for further support of various Innova features in later patchsets. Additional details about hardware architecture will be provided as more features get submitted. Signed-off-by: Ilan Tayari Reviewed-by: Boris Pismenny Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Kconfig | 10 + drivers/net/ethernet/mellanox/mlx5/core/Makefile | 3 + drivers/net/ethernet/mellanox/mlx5/core/eq.c | 11 ++ drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c | 64 +++++++ drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h | 59 ++++++ .../net/ethernet/mellanox/mlx5/core/fpga/core.c | 202 +++++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/fpga/core.h | 99 ++++++++++ drivers/net/ethernet/mellanox/mlx5/core/main.c | 19 +- 8 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig index fc52d742b7f7..28cf88483ca4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig @@ -11,6 +11,16 @@ config MLX5_CORE Core driver for low level functionality of the ConnectX-4 and Connect-IB cards by Mellanox Technologies. +config MLX5_FPGA + bool "Mellanox Technologies Innova support" + depends on MLX5_CORE + ---help--- + Build support for the Innova family of network cards by Mellanox + Technologies. Innova network cards are comprised of a ConnectX chip + and an FPGA chip on one board. If you select this option, the + mlx5_core driver will include the Innova FPGA core and allow building + sandbox-specific client drivers. + config MLX5_CORE_EN bool "Mellanox Technologies ConnectX-4 Ethernet support" depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 9e644615f07a..12556c03eec4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -1,10 +1,13 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o +subdir-ccflags-y += -I$(src) mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \ mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ fs_counters.o rl.o lag.o dev.o +mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o + mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \ en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index df0034d8f48c..01d2cd7e4746 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -35,6 +35,7 @@ #include #include #include "mlx5_core.h" +#include "fpga/core.h" #ifdef CONFIG_MLX5_CORE_EN #include "eswitch.h" #endif @@ -156,6 +157,8 @@ static const char *eqe_type_str(u8 type) return "MLX5_EVENT_TYPE_PAGE_FAULT"; case MLX5_EVENT_TYPE_PPS_EVENT: return "MLX5_EVENT_TYPE_PPS_EVENT"; + case MLX5_EVENT_TYPE_FPGA_ERROR: + return "MLX5_EVENT_TYPE_FPGA_ERROR"; default: return "Unrecognized event"; } @@ -476,6 +479,11 @@ static irqreturn_t mlx5_eq_int(int irq, void *eq_ptr) if (dev->event) dev->event(dev, MLX5_DEV_EVENT_PPS, (unsigned long)eqe); break; + + case MLX5_EVENT_TYPE_FPGA_ERROR: + mlx5_fpga_event(dev, eqe->type, &eqe->data.raw); + break; + default: mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n", eqe->type, eq->eqn); @@ -693,6 +701,9 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev) if (MLX5_CAP_GEN(dev, pps)) async_event_mask |= (1ull << MLX5_EVENT_TYPE_PPS_EVENT); + if (MLX5_CAP_GEN(dev, fpga)) + async_event_mask |= (1ull << MLX5_EVENT_TYPE_FPGA_ERROR); + err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD, MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD, "mlx5_cmd_eq", MLX5_EQ_TYPE_ASYNC); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c new file mode 100644 index 000000000000..99cba644b4fc --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "mlx5_core.h" +#include "fpga/cmd.h" + +int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps) +{ + u32 in[MLX5_ST_SZ_DW(fpga_cap)] = {0}; + + return mlx5_core_access_reg(dev, in, sizeof(in), caps, + MLX5_ST_SZ_BYTES(fpga_cap), + MLX5_REG_FPGA_CAP, 0, 0); +} + +int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query) +{ + u32 in[MLX5_ST_SZ_DW(fpga_ctrl)] = {0}; + u32 out[MLX5_ST_SZ_DW(fpga_ctrl)]; + int err; + + err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), + MLX5_REG_FPGA_CTRL, 0, false); + if (err) + return err; + + query->status = MLX5_GET(fpga_ctrl, out, status); + query->admin_image = MLX5_GET(fpga_ctrl, out, flash_select_admin); + query->oper_image = MLX5_GET(fpga_ctrl, out, flash_select_oper); + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h new file mode 100644 index 000000000000..a74396a61bc3 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __MLX5_FPGA_H__ +#define __MLX5_FPGA_H__ + +#include + +enum mlx5_fpga_image { + MLX5_FPGA_IMAGE_USER = 0, + MLX5_FPGA_IMAGE_FACTORY, +}; + +enum mlx5_fpga_status { + MLX5_FPGA_STATUS_SUCCESS = 0, + MLX5_FPGA_STATUS_FAILURE = 1, + MLX5_FPGA_STATUS_IN_PROGRESS = 2, + MLX5_FPGA_STATUS_NONE = 0xFFFF, +}; + +struct mlx5_fpga_query { + enum mlx5_fpga_image admin_image; + enum mlx5_fpga_image oper_image; + enum mlx5_fpga_status status; +}; + +int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps); +int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query); + +#endif /* __MLX5_FPGA_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c new file mode 100644 index 000000000000..d88b332e9669 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2017, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "mlx5_core.h" +#include "fpga/core.h" + +static const char *const mlx5_fpga_error_strings[] = { + "Null Syndrome", + "Corrupted DDR", + "Flash Timeout", + "Internal Link Error", + "Watchdog HW Failure", + "I2C Failure", + "Image Changed", + "Temperature Critical", +}; + +static struct mlx5_fpga_device *mlx5_fpga_device_alloc(void) +{ + struct mlx5_fpga_device *fdev = NULL; + + fdev = kzalloc(sizeof(*fdev), GFP_KERNEL); + if (!fdev) + return NULL; + + spin_lock_init(&fdev->state_lock); + fdev->state = MLX5_FPGA_STATUS_NONE; + return fdev; +} + +static const char *mlx5_fpga_image_name(enum mlx5_fpga_image image) +{ + switch (image) { + case MLX5_FPGA_IMAGE_USER: + return "user"; + case MLX5_FPGA_IMAGE_FACTORY: + return "factory"; + default: + return "unknown"; + } +} + +static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev) +{ + struct mlx5_fpga_query query; + int err; + + err = mlx5_fpga_query(fdev->mdev, &query); + if (err) { + mlx5_fpga_err(fdev, "Failed to query status: %d\n", err); + return err; + } + + fdev->last_admin_image = query.admin_image; + fdev->last_oper_image = query.oper_image; + + mlx5_fpga_dbg(fdev, "Status %u; Admin image %u; Oper image %u\n", + query.status, query.admin_image, query.oper_image); + + if (query.status != MLX5_FPGA_STATUS_SUCCESS) { + mlx5_fpga_err(fdev, "%s image failed to load; status %u\n", + mlx5_fpga_image_name(fdev->last_oper_image), + query.status); + return -EIO; + } + + return 0; +} + +int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) +{ + struct mlx5_fpga_device *fdev = mdev->fpga; + unsigned long flags; + int err; + + if (!fdev) + return 0; + + err = mlx5_fpga_device_load_check(fdev); + if (err) + goto out; + + err = mlx5_fpga_caps(fdev->mdev, + fdev->mdev->caps.hca_cur[MLX5_CAP_FPGA]); + if (err) + goto out; + + mlx5_fpga_info(fdev, "device %u; %s image, version %u\n", + MLX5_CAP_FPGA(fdev->mdev, fpga_device), + mlx5_fpga_image_name(fdev->last_oper_image), + MLX5_CAP_FPGA(fdev->mdev, image_version)); + +out: + spin_lock_irqsave(&fdev->state_lock, flags); + fdev->state = err ? MLX5_FPGA_STATUS_FAILURE : MLX5_FPGA_STATUS_SUCCESS; + spin_unlock_irqrestore(&fdev->state_lock, flags); + return err; +} + +int mlx5_fpga_device_init(struct mlx5_core_dev *mdev) +{ + struct mlx5_fpga_device *fdev = NULL; + + if (!MLX5_CAP_GEN(mdev, fpga)) { + mlx5_core_dbg(mdev, "FPGA capability not present\n"); + return 0; + } + + mlx5_core_dbg(mdev, "Initializing FPGA\n"); + + fdev = mlx5_fpga_device_alloc(); + if (!fdev) + return -ENOMEM; + + fdev->mdev = mdev; + mdev->fpga = fdev; + + return 0; +} + +void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev) +{ + kfree(mdev->fpga); + mdev->fpga = NULL; +} + +static const char *mlx5_fpga_syndrome_to_string(u8 syndrome) +{ + if (syndrome < ARRAY_SIZE(mlx5_fpga_error_strings)) + return mlx5_fpga_error_strings[syndrome]; + return "Unknown"; +} + +void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data) +{ + struct mlx5_fpga_device *fdev = mdev->fpga; + const char *event_name; + bool teardown = false; + unsigned long flags; + u8 syndrome; + + if (event != MLX5_EVENT_TYPE_FPGA_ERROR) { + mlx5_fpga_warn_ratelimited(fdev, "Unexpected event %u\n", + event); + return; + } + + syndrome = MLX5_GET(fpga_error_event, data, syndrome); + event_name = mlx5_fpga_syndrome_to_string(syndrome); + + spin_lock_irqsave(&fdev->state_lock, flags); + switch (fdev->state) { + case MLX5_FPGA_STATUS_SUCCESS: + mlx5_fpga_warn(fdev, "Error %u: %s\n", syndrome, event_name); + teardown = true; + break; + default: + mlx5_fpga_warn_ratelimited(fdev, "Unexpected error event %u: %s\n", + syndrome, event_name); + } + spin_unlock_irqrestore(&fdev->state_lock, flags); + /* We tear-down the card's interfaces and functionality because + * the FPGA bump-on-the-wire is misbehaving and we lose ability + * to communicate with the network. User may still be able to + * recover by re-programming or debugging the FPGA + */ + if (teardown) + mlx5_trigger_health_work(fdev->mdev); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h new file mode 100644 index 000000000000..c55044d66778 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __MLX5_FPGA_CORE_H__ +#define __MLX5_FPGA_CORE_H__ + +#ifdef CONFIG_MLX5_FPGA + +#include "fpga/cmd.h" + +/* Represents an Innova device */ +struct mlx5_fpga_device { + struct mlx5_core_dev *mdev; + spinlock_t state_lock; /* Protects state transitions */ + enum mlx5_fpga_status state; + enum mlx5_fpga_image last_admin_image; + enum mlx5_fpga_image last_oper_image; +}; + +#define mlx5_fpga_dbg(__adev, format, ...) \ + dev_dbg(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \ + __func__, __LINE__, current->pid, ##__VA_ARGS__) + +#define mlx5_fpga_err(__adev, format, ...) \ + dev_err(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \ + __func__, __LINE__, current->pid, ##__VA_ARGS__) + +#define mlx5_fpga_warn(__adev, format, ...) \ + dev_warn(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \ + __func__, __LINE__, current->pid, ##__VA_ARGS__) + +#define mlx5_fpga_warn_ratelimited(__adev, format, ...) \ + dev_warn_ratelimited(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d: " \ + format, __func__, __LINE__, ##__VA_ARGS__) + +#define mlx5_fpga_notice(__adev, format, ...) \ + dev_notice(&(__adev)->mdev->pdev->dev, "FPGA: " format, ##__VA_ARGS__) + +#define mlx5_fpga_info(__adev, format, ...) \ + dev_info(&(__adev)->mdev->pdev->dev, "FPGA: " format, ##__VA_ARGS__) + +int mlx5_fpga_device_init(struct mlx5_core_dev *mdev); +void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev); +int mlx5_fpga_device_start(struct mlx5_core_dev *mdev); +void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data); + +#else + +static inline int mlx5_fpga_device_init(struct mlx5_core_dev *mdev) +{ + return 0; +} + +static inline void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev) +{ +} + +static inline int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) +{ + return 0; +} + +static inline void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, + void *data) +{ +} + +#endif + +#endif /* __MLX5_FPGA_CORE_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index f933922d5cca..ad0202cef203 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -56,6 +56,7 @@ #ifdef CONFIG_MLX5_CORE_EN #include "eswitch.h" #endif +#include "fpga/core.h" MODULE_AUTHOR("Eli Cohen "); MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver"); @@ -1113,10 +1114,16 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, goto err_disable_msix; } + err = mlx5_fpga_device_init(dev); + if (err) { + dev_err(&pdev->dev, "fpga device init failed %d\n", err); + goto err_put_uars; + } + err = mlx5_start_eqs(dev); if (err) { dev_err(&pdev->dev, "Failed to start pages and async EQs\n"); - goto err_put_uars; + goto err_fpga_init; } err = alloc_comp_eqs(dev); @@ -1147,6 +1154,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, goto err_sriov; } + err = mlx5_fpga_device_start(dev); + if (err) { + dev_err(&pdev->dev, "fpga device start failed %d\n", err); + goto err_reg_dev; + } + if (mlx5_device_registered(dev)) { mlx5_attach_device(dev); } else { @@ -1182,6 +1195,9 @@ err_affinity_hints: err_stop_eqs: mlx5_stop_eqs(dev); +err_fpga_init: + mlx5_fpga_device_cleanup(dev); + err_put_uars: mlx5_put_uars_page(dev, priv->uar); @@ -1246,6 +1262,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, mlx5_irq_clear_affinity_hints(dev); free_comp_eqs(dev); mlx5_stop_eqs(dev); + mlx5_fpga_device_cleanup(dev); mlx5_put_uars_page(dev, priv->uar); mlx5_disable_msix(dev); if (cleanup) -- cgit v1.2.3 From 7913d2059645a2ba54dfe5e50c388d5689fe3cd6 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Wed, 22 Feb 2017 17:43:50 +0200 Subject: net/mlx5: Bump driver version Remove date and bump version for mlx5_core driver. Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index e0dd1048c966..afa89dcf30a5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -39,7 +39,7 @@ static void mlx5e_get_drvinfo(struct net_device *dev, struct mlx5_core_dev *mdev = priv->mdev; strlcpy(drvinfo->driver, DRIVER_NAME, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, DRIVER_VERSION " (" DRIVER_RELDATE ")", + strlcpy(drvinfo->version, DRIVER_VERSION, sizeof(drvinfo->version)); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%04d (%.16s)", diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index fbc6e9e9e305..cf69b42278df 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -39,8 +39,7 @@ #include #define DRIVER_NAME "mlx5_core" -#define DRIVER_VERSION "3.0-1" -#define DRIVER_RELDATE "January 2015" +#define DRIVER_VERSION "5.0-0" #define MLX5_TOTAL_VPORTS(mdev) (1 + pci_sriov_get_totalvfs(mdev->pdev)) -- cgit v1.2.3 From b359911d6608bd16888466184e8e8faeb63bd9eb Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Wed, 22 Feb 2017 17:45:46 +0200 Subject: IB/mlx5: Bump driver version Remove date and bump version for mlx5_ib driver. Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/infiniband/hw/mlx5/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index b6991204e5df..42defaa0d6c6 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -60,8 +60,7 @@ #include "cmd.h" #define DRIVER_NAME "mlx5_ib" -#define DRIVER_VERSION "2.2-1" -#define DRIVER_RELDATE "Feb 2014" +#define DRIVER_VERSION "5.0-0" MODULE_AUTHOR("Eli Cohen "); MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver"); @@ -70,7 +69,7 @@ MODULE_VERSION(DRIVER_VERSION); static char mlx5_version[] = DRIVER_NAME ": Mellanox Connect-IB Infiniband driver v" - DRIVER_VERSION " (" DRIVER_RELDATE ")\n"; + DRIVER_VERSION "\n"; enum { MLX5_ATOMIC_SIZE_QP_8BYTES = 1 << 3, -- cgit v1.2.3 From ae1aed95d0255aafdffc48c3a077c7980adc1168 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Wed, 10 May 2017 13:44:59 -0700 Subject: drivers: net: xgene: Protect indirect MAC access This patch, - refactors mac read/write functions - adds lock to protect indirect mac access Signed-off-by: Iyappan Subramanian Signed-off-by: Quan Nguyen Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 119 +++++++++------------- drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 3 + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 1 + drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 1 + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 71 ------------- drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 44 ++------ 6 files changed, 62 insertions(+), 177 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 2a835e07adfb..2050c58eddfd 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -270,42 +270,32 @@ static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata, iowrite32(val, addr); } -static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, - void __iomem *cmd, void __iomem *cmd_done, - u32 wr_addr, u32 wr_data) +void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr, u32 wr_data) { - u32 done; + void __iomem *addr, *wr, *cmd, *cmd_done; + struct net_device *ndev = pdata->ndev; u8 wait = 10; + u32 done; + addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; + wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; + cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; + + spin_lock(&pdata->mac_lock); iowrite32(wr_addr, addr); iowrite32(wr_data, wr); iowrite32(XGENE_ENET_WR_CMD, cmd); - /* wait for write command to complete */ while (!(done = ioread32(cmd_done)) && wait--) udelay(1); if (!done) - return false; + netdev_err(ndev, "mac write failed, addr: %04x data: %08x\n", + wr_addr, wr_data); iowrite32(0, cmd); - - return true; -} - -static void xgene_enet_wr_mcx_mac(struct xgene_enet_pdata *pdata, - u32 wr_addr, u32 wr_data) -{ - void __iomem *addr, *wr, *cmd, *cmd_done; - - addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; - wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; - cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; - - if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) - netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", - wr_addr); + spin_unlock(&pdata->mac_lock); } static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata, @@ -332,42 +322,33 @@ static void xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *pdata, *val = ioread32(addr); } -static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, - void __iomem *cmd, void __iomem *cmd_done, - u32 rd_addr, u32 *rd_data) +u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr) { - u32 done; + void __iomem *addr, *rd, *cmd, *cmd_done; + u32 done, rd_data; u8 wait = 10; + addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; + rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; + cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; + + spin_lock(&pdata->mac_lock); iowrite32(rd_addr, addr); iowrite32(XGENE_ENET_RD_CMD, cmd); - /* wait for read command to complete */ while (!(done = ioread32(cmd_done)) && wait--) udelay(1); if (!done) - return false; + netdev_err(pdata->ndev, "mac read failed, addr: %04x\n", + rd_addr); - *rd_data = ioread32(rd); + rd_data = ioread32(rd); iowrite32(0, cmd); + spin_unlock(&pdata->mac_lock); - return true; -} - -static void xgene_enet_rd_mcx_mac(struct xgene_enet_pdata *pdata, - u32 rd_addr, u32 *rd_data) -{ - void __iomem *addr, *rd, *cmd, *cmd_done; - - addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; - rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; - cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; - - if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) - netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", - rd_addr); + return rd_data; } static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) @@ -379,8 +360,8 @@ static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) (dev_addr[1] << 8) | dev_addr[0]; addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16); - xgene_enet_wr_mcx_mac(pdata, STATION_ADDR0_ADDR, addr0); - xgene_enet_wr_mcx_mac(pdata, STATION_ADDR1_ADDR, addr1); + xgene_enet_wr_mac(pdata, STATION_ADDR0_ADDR, addr0); + xgene_enet_wr_mac(pdata, STATION_ADDR1_ADDR, addr1); } static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) @@ -405,8 +386,8 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) static void xgene_gmac_reset(struct xgene_enet_pdata *pdata) { - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, 0); } static void xgene_enet_configure_clock(struct xgene_enet_pdata *pdata) @@ -456,8 +437,8 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0); xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2); - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_2_ADDR, &mc2); - xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl); + mc2 = xgene_enet_rd_mac(pdata, MAC_CONFIG_2_ADDR); + intf_ctl = xgene_enet_rd_mac(pdata, INTERFACE_CONTROL_ADDR); xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii); switch (pdata->phy_speed) { @@ -495,8 +476,8 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) } mc2 |= FULL_DUPLEX2 | PAD_CRC | LENGTH_CHK; - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); - xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); + xgene_enet_wr_mac(pdata, MAC_CONFIG_2_ADDR, mc2); + xgene_enet_wr_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); xgene_enet_configure_clock(pdata); @@ -506,7 +487,7 @@ static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) static void xgene_enet_set_frame_size(struct xgene_enet_pdata *pdata, int size) { - xgene_enet_wr_mcx_mac(pdata, MAX_FRAME_LEN_ADDR, size); + xgene_enet_wr_mac(pdata, MAX_FRAME_LEN_ADDR, size); } static void xgene_gmac_enable_tx_pause(struct xgene_enet_pdata *pdata, @@ -528,14 +509,14 @@ static void xgene_gmac_flowctl_tx(struct xgene_enet_pdata *pdata, bool enable) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); if (enable) data |= TX_FLOW_EN; else data &= ~TX_FLOW_EN; - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data); pdata->mac_ops->enable_tx_pause(pdata, enable); } @@ -544,14 +525,14 @@ static void xgene_gmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); if (enable) data |= RX_FLOW_EN; else data &= ~RX_FLOW_EN; - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data); } static void xgene_gmac_init(struct xgene_enet_pdata *pdata) @@ -565,9 +546,9 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) xgene_gmac_set_mac_addr(pdata); /* Adjust MDC clock frequency */ - xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &value); + value = xgene_enet_rd_mac(pdata, MII_MGMT_CONFIG_ADDR); MGMT_CLOCK_SEL_SET(&value, 7); - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, value); + xgene_enet_wr_mac(pdata, MII_MGMT_CONFIG_ADDR, value); /* Enable drop if bufpool not available */ xgene_enet_rd_csr(pdata, RSIF_CONFIG_REG_ADDR, &value); @@ -637,32 +618,32 @@ static void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN); } static void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN); } static void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN); } static void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); - xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN); + data = xgene_enet_rd_mac(pdata, MAC_CONFIG_1_ADDR); + xgene_enet_wr_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN); } bool xgene_ring_mgr_init(struct xgene_enet_pdata *p) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index d250bfe94d24..057f9515c2a8 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -388,6 +388,9 @@ void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); bool xgene_ring_mgr_init(struct xgene_enet_pdata *p); int xgene_enet_phy_connect(struct net_device *ndev); void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata); +u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr); +void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr, + u32 wr_data); extern const struct xgene_mac_ops xgene_gmac_ops; extern const struct xgene_port_ops xgene_gport_ops; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 5f37ed3506d5..9a28ac3b7687 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -2055,6 +2055,7 @@ static int xgene_enet_probe(struct platform_device *pdev) goto err; xgene_enet_setup_ops(pdata); + spin_lock_init(&pdata->mac_lock); if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { ndev->features |= NETIF_F_TSO | NETIF_F_RXCSUM; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 0d4be2425ebc..827b33da6384 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -221,6 +221,7 @@ struct xgene_enet_pdata { struct xgene_enet_cle cle; struct rtnl_link_stats64 stats; const struct xgene_mac_ops *mac_ops; + spinlock_t mac_lock; /* mac lock */ const struct xgene_port_ops *port_ops; struct xgene_ring_ops *ring_ops; const struct xgene_cle_ops *cle_ops; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index a8e063bdee3b..cb6350f7e137 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -54,41 +54,6 @@ static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata, iowrite32(val, addr); } -static bool xgene_enet_wr_indirect(struct xgene_indirect_ctl *ctl, - u32 wr_addr, u32 wr_data) -{ - int i; - - iowrite32(wr_addr, ctl->addr); - iowrite32(wr_data, ctl->ctl); - iowrite32(XGENE_ENET_WR_CMD, ctl->cmd); - - /* wait for write command to complete */ - for (i = 0; i < 10; i++) { - if (ioread32(ctl->cmd_done)) { - iowrite32(0, ctl->cmd); - return true; - } - udelay(1); - } - - return false; -} - -static void xgene_enet_wr_mac(struct xgene_enet_pdata *p, - u32 wr_addr, u32 wr_data) -{ - struct xgene_indirect_ctl ctl = { - .addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET, - .ctl = p->mcx_mac_addr + MAC_WRITE_REG_OFFSET, - .cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET, - .cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET - }; - - if (!xgene_enet_wr_indirect(&ctl, wr_addr, wr_data)) - netdev_err(p->ndev, "mac write failed, addr: %04x\n", wr_addr); -} - static u32 xgene_enet_rd_csr(struct xgene_enet_pdata *p, u32 offset) { return ioread32(p->eth_csr_addr + offset); @@ -104,42 +69,6 @@ static u32 xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *p, u32 offset) return ioread32(p->mcx_mac_csr_addr + offset); } -static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr) -{ - u32 rd_data; - int i; - - iowrite32(rd_addr, ctl->addr); - iowrite32(XGENE_ENET_RD_CMD, ctl->cmd); - - /* wait for read command to complete */ - for (i = 0; i < 10; i++) { - if (ioread32(ctl->cmd_done)) { - rd_data = ioread32(ctl->ctl); - iowrite32(0, ctl->cmd); - - return rd_data; - } - udelay(1); - } - - pr_err("%s: mac read failed, addr: %04x\n", __func__, rd_addr); - - return 0; -} - -static u32 xgene_enet_rd_mac(struct xgene_enet_pdata *p, u32 rd_addr) -{ - struct xgene_indirect_ctl ctl = { - .addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET, - .ctl = p->mcx_mac_addr + MAC_READ_REG_OFFSET, - .cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET, - .cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET - }; - - return xgene_enet_rd_indirect(&ctl, rd_addr); -} - static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) { struct net_device *ndev = p->ndev; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c index 423240c97d39..c6a5dac3a126 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c @@ -71,21 +71,6 @@ static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, return true; } -static void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, - u32 wr_addr, u32 wr_data) -{ - void __iomem *addr, *wr, *cmd, *cmd_done; - - addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; - wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; - cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; - - if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) - netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", - wr_addr); -} - static void xgene_enet_wr_pcs(struct xgene_enet_pdata *pdata, u32 wr_addr, u32 wr_data) { @@ -148,21 +133,6 @@ static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, return true; } -static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, - u32 rd_addr, u32 *rd_data) -{ - void __iomem *addr, *rd, *cmd, *cmd_done; - - addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; - rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; - cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; - - if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) - netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", - rd_addr); -} - static bool xgene_enet_rd_pcs(struct xgene_enet_pdata *pdata, u32 rd_addr, u32 *rd_data) { @@ -300,7 +270,7 @@ static void xgene_xgmac_flowctl_tx(struct xgene_enet_pdata *pdata, bool enable) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); if (enable) data |= HSTTCTLEN; @@ -316,7 +286,7 @@ static void xgene_xgmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); if (enable) data |= HSTRCTLEN; @@ -332,7 +302,7 @@ static void xgene_xgmac_init(struct xgene_enet_pdata *pdata) xgene_xgmac_reset(pdata); - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); data |= HSTPPEN; data &= ~HSTLENCHK; xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data); @@ -379,7 +349,7 @@ static void xgene_xgmac_rx_enable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTRFEN); } @@ -387,7 +357,7 @@ static void xgene_xgmac_tx_enable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTTFEN); } @@ -395,7 +365,7 @@ static void xgene_xgmac_rx_disable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTRFEN); } @@ -403,7 +373,7 @@ static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) { u32 data; - xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); + data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1); xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN); } -- cgit v1.2.3 From 8ec7074a6bf74e12f67c0dc90cdaa7969bb49c74 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 10 May 2017 13:45:00 -0700 Subject: drivers: net: phy: xgene: Add lock to protect mac access This patch, - refactors mac access routine - adds lock to protect mac indirect access Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/phy/mdio-xgene.c | 74 ++++++++++++++++++++++---------------------- drivers/net/phy/mdio-xgene.h | 3 ++ 2 files changed, 40 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c index 3e2ac07b6e37..bfd3090fb055 100644 --- a/drivers/net/phy/mdio-xgene.c +++ b/drivers/net/phy/mdio-xgene.c @@ -34,76 +34,73 @@ static bool xgene_mdio_status; -static u32 xgene_enet_rd_mac(void __iomem *base_addr, u32 rd_addr) +u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr) { void __iomem *addr, *rd, *cmd, *cmd_done; u32 done, rd_data = BUSY_MASK; u8 wait = 10; - addr = base_addr + MAC_ADDR_REG_OFFSET; - rd = base_addr + MAC_READ_REG_OFFSET; - cmd = base_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET; + addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET; + rd = pdata->mac_csr_addr + MAC_READ_REG_OFFSET; + cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET; + spin_lock(&pdata->mac_lock); iowrite32(rd_addr, addr); iowrite32(XGENE_ENET_RD_CMD, cmd); - while (wait--) { - done = ioread32(cmd_done); - if (done) - break; + while (!(done = ioread32(cmd_done)) && wait--) udelay(1); - } - if (!done) - return rd_data; + if (done) + rd_data = ioread32(rd); - rd_data = ioread32(rd); iowrite32(0, cmd); + spin_unlock(&pdata->mac_lock); return rd_data; } +EXPORT_SYMBOL(xgene_mdio_rd_mac); -static void xgene_enet_wr_mac(void __iomem *base_addr, u32 wr_addr, u32 wr_data) +void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data) { void __iomem *addr, *wr, *cmd, *cmd_done; u8 wait = 10; u32 done; - addr = base_addr + MAC_ADDR_REG_OFFSET; - wr = base_addr + MAC_WRITE_REG_OFFSET; - cmd = base_addr + MAC_COMMAND_REG_OFFSET; - cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET; + addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET; + wr = pdata->mac_csr_addr + MAC_WRITE_REG_OFFSET; + cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET; + cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET; + spin_lock(&pdata->mac_lock); iowrite32(wr_addr, addr); - iowrite32(wr_data, wr); + iowrite32(data, wr); iowrite32(XGENE_ENET_WR_CMD, cmd); - while (wait--) { - done = ioread32(cmd_done); - if (done) - break; + while (!(done = ioread32(cmd_done)) && wait--) udelay(1); - } if (!done) pr_err("MCX mac write failed, addr: 0x%04x\n", wr_addr); iowrite32(0, cmd); + spin_unlock(&pdata->mac_lock); } +EXPORT_SYMBOL(xgene_mdio_wr_mac); int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg) { - void __iomem *addr = (void __iomem *)bus->priv; + struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv; u32 data, done; u8 wait = 10; data = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); - xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, data); - xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); + xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, data); + xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); do { usleep_range(5, 10); - done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR); + done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR); } while ((done & BUSY_MASK) && wait--); if (done & BUSY_MASK) { @@ -111,8 +108,8 @@ int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg) return -EBUSY; } - data = xgene_enet_rd_mac(addr, MII_MGMT_STATUS_ADDR); - xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, 0); + data = xgene_mdio_rd_mac(pdata, MII_MGMT_STATUS_ADDR); + xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, 0); return data; } @@ -120,17 +117,17 @@ EXPORT_SYMBOL(xgene_mdio_rgmii_read); int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data) { - void __iomem *addr = (void __iomem *)bus->priv; + struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv; u32 val, done; u8 wait = 10; val = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); - xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, val); + xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, val); - xgene_enet_wr_mac(addr, MII_MGMT_CONTROL_ADDR, data); + xgene_mdio_wr_mac(pdata, MII_MGMT_CONTROL_ADDR, data); do { usleep_range(5, 10); - done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR); + done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR); } while ((done & BUSY_MASK) && wait--); if (done & BUSY_MASK) { @@ -174,8 +171,8 @@ static int xgene_enet_ecc_init(struct xgene_mdio_pdata *pdata) static void xgene_gmac_reset(struct xgene_mdio_pdata *pdata) { - xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, SOFT_RESET); - xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, 0); + xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET); + xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, 0); } static int xgene_mdio_reset(struct xgene_mdio_pdata *pdata) @@ -375,6 +372,9 @@ static int xgene_mdio_probe(struct platform_device *pdev) pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET; pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET; + if (mdio_id == XGENE_MDIO_RGMII) + spin_lock_init(&pdata->mac_lock); + if (dev->of_node) { pdata->clk = devm_clk_get(dev, NULL); if (IS_ERR(pdata->clk)) { @@ -396,7 +396,7 @@ static int xgene_mdio_probe(struct platform_device *pdev) if (mdio_id == XGENE_MDIO_RGMII) { mdio_bus->read = xgene_mdio_rgmii_read; mdio_bus->write = xgene_mdio_rgmii_write; - mdio_bus->priv = (void __force *)pdata->mac_csr_addr; + mdio_bus->priv = (void __force *)pdata; snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", "xgene-mii-rgmii"); } else { diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h index 594a11d42401..3c85f3e30baa 100644 --- a/drivers/net/phy/mdio-xgene.h +++ b/drivers/net/phy/mdio-xgene.h @@ -102,6 +102,7 @@ struct xgene_mdio_pdata { void __iomem *mdio_csr_addr; struct mii_bus *mdio_bus; int mdio_id; + spinlock_t mac_lock; /* mac lock */ }; /* Set the specified value into a bit-field defined by its starting position @@ -132,6 +133,8 @@ static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) #define GET_BIT(field, src) \ xgene_enet_get_field_value(field ## _POS, 1, src) +u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr); +void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data); int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg); int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data); struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr); -- cgit v1.2.3 From d09d3629b6f60bd5df5303eb2f4b26c52571388a Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 10 May 2017 13:45:01 -0700 Subject: drivers: net: xgene: Use rgmii mdio mac access This patch switches to use rgmii mdio mac access routines if available, as they share the same HW. Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 2050c58eddfd..47c5b754068d 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -277,6 +277,13 @@ void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr, u32 wr_data) u8 wait = 10; u32 done; + if (pdata->mdio_driver && ndev->phydev && + pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + struct mii_bus *bus = ndev->phydev->mdio.bus; + + return xgene_mdio_wr_mac(bus->priv, wr_addr, wr_data); + } + addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; @@ -328,6 +335,13 @@ u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr) u32 done, rd_data; u8 wait = 10; + if (pdata->mdio_driver && pdata->ndev->phydev && + pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + struct mii_bus *bus = pdata->ndev->phydev->mdio.bus; + + return xgene_mdio_rd_mac(bus->priv, rd_addr); + } + addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; -- cgit v1.2.3 From 3f5a2ef1825db4079bef945d33c84a230cdbba32 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 10 May 2017 13:45:02 -0700 Subject: drivers: net: xgene: Remove redundant local stats Commit 5944701df90d ("net: remove useless memset's in drivers get_stats64") makes the pdata->stats redundant. This patch removes pdata->stats and updates get_stats64() callback accordingly. Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c | 7 ++++--- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 4 +--- drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 1 - 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 28fdedc30b74..217cde86e117 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -25,7 +25,7 @@ struct xgene_gstrings_stats { int offset; }; -#define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) } +#define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) } static const struct xgene_gstrings_stats gstrings_stats[] = { XGENE_STAT(rx_packets), @@ -156,11 +156,12 @@ static void xgene_get_ethtool_stats(struct net_device *ndev, struct ethtool_stats *dummy, u64 *data) { - void *pdata = netdev_priv(ndev); + struct rtnl_link_stats64 stats; int i; + dev_get_stats(ndev, &stats); for (i = 0; i < XGENE_STATS_LEN; i++) - *data++ = *(u64 *)(pdata + gstrings_stats[i].offset); + data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset); } static void xgene_get_pauseparam(struct net_device *ndev, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 9a28ac3b7687..e4f2ef2d750b 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -1466,10 +1466,9 @@ err: static void xgene_enet_get_stats64( struct net_device *ndev, - struct rtnl_link_stats64 *storage) + struct rtnl_link_stats64 *stats) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); - struct rtnl_link_stats64 *stats = &pdata->stats; struct xgene_enet_desc_ring *ring; int i; @@ -1493,7 +1492,6 @@ static void xgene_enet_get_stats64( stats->rx_dropped += ring->rx_dropped; } } - memcpy(storage, stats, sizeof(struct rtnl_link_stats64)); } static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 827b33da6384..5e6fd718b685 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -219,7 +219,6 @@ struct xgene_enet_pdata { int phy_mode; enum xgene_enet_rm rm; struct xgene_enet_cle cle; - struct rtnl_link_stats64 stats; const struct xgene_mac_ops *mac_ops; spinlock_t mac_lock; /* mac lock */ const struct xgene_port_ops *port_ops; -- cgit v1.2.3 From 089f97c7de365bdbb68c2ad922529c101c5a2901 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 10 May 2017 13:45:03 -0700 Subject: drivers: net: xgene: Refactor statistics error parsing code This patch fixes the tx error counters and adds more rx error counters. Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 6 ------ drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 2 -- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 26 +++++++++++++++--------- drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 2 ++ 4 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 47c5b754068d..02df5776e942 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -205,30 +205,24 @@ static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring) } void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, - struct xgene_enet_pdata *pdata, enum xgene_enet_err_code status) { switch (status) { case INGRESS_CRC: ring->rx_crc_errors++; - ring->rx_dropped++; break; case INGRESS_CHECKSUM: case INGRESS_CHECKSUM_COMPUTE: ring->rx_errors++; - ring->rx_dropped++; break; case INGRESS_TRUNC_FRAME: ring->rx_frame_errors++; - ring->rx_dropped++; break; case INGRESS_PKT_LEN: ring->rx_length_errors++; - ring->rx_dropped++; break; case INGRESS_PKT_UNDER: ring->rx_frame_errors++; - ring->rx_dropped++; break; case INGRESS_FIFO_OVERRUN: ring->rx_fifo_errors++; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 057f9515c2a8..3ce349f96c8d 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -380,9 +380,7 @@ static inline u16 xgene_enet_get_numslots(u16 id, u32 size) } void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, - struct xgene_enet_pdata *pdata, enum xgene_enet_err_code status); - int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); bool xgene_ring_mgr_init(struct xgene_enet_pdata *p); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index e4f2ef2d750b..3f24b83a6c55 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -246,9 +246,9 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, skb_frag_t *frag; dma_addr_t *frag_dma_addr; u16 skb_index; - u8 status; - int i, ret = 0; u8 mss_index; + u8 status; + int i; skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); skb = cp_ring->cp_skb[skb_index]; @@ -275,19 +275,17 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, /* Checking for error */ status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); if (unlikely(status > 2)) { - xgene_enet_parse_error(cp_ring, netdev_priv(cp_ring->ndev), - status); - ret = -EIO; + cp_ring->tx_dropped++; + cp_ring->tx_errors++; } if (likely(skb)) { dev_kfree_skb_any(skb); } else { netdev_err(cp_ring->ndev, "completion skb is NULL\n"); - ret = -EIO; } - return ret; + return 0; } static int xgene_enet_setup_mss(struct net_device *ndev, u32 mss) @@ -711,7 +709,8 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, if (!xgene_enet_errata_10GE_8(skb, datalen, status)) { dev_kfree_skb_any(skb); xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc); - xgene_enet_parse_error(rx_ring, pdata, status); + xgene_enet_parse_error(rx_ring, status); + rx_ring->rx_dropped++; goto out; } } @@ -1477,6 +1476,8 @@ static void xgene_enet_get_stats64( if (ring) { stats->tx_packets += ring->tx_packets; stats->tx_bytes += ring->tx_bytes; + stats->tx_dropped += ring->tx_dropped; + stats->tx_errors += ring->tx_errors; } } @@ -1485,11 +1486,16 @@ static void xgene_enet_get_stats64( if (ring) { stats->rx_packets += ring->rx_packets; stats->rx_bytes += ring->rx_bytes; - stats->rx_errors += ring->rx_length_errors + + stats->rx_dropped += ring->rx_dropped; + stats->rx_errors += ring->rx_errors + + ring->rx_length_errors + ring->rx_crc_errors + ring->rx_frame_errors + ring->rx_fifo_errors; - stats->rx_dropped += ring->rx_dropped; + stats->rx_length_errors += ring->rx_length_errors; + stats->rx_crc_errors += ring->rx_crc_errors; + stats->rx_frame_errors += ring->rx_frame_errors; + stats->rx_fifo_errors += ring->rx_fifo_errors; } } } diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 5e6fd718b685..3bf66385dbdf 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -138,6 +138,8 @@ struct xgene_enet_desc_ring { __le64 *exp_bufs; u64 tx_packets; u64 tx_bytes; + u64 tx_dropped; + u64 tx_errors; u64 rx_packets; u64 rx_bytes; u64 rx_dropped; -- cgit v1.2.3 From 6f22a7ad15decf15bdd34532c69102a48e985d93 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 10 May 2017 13:45:04 -0700 Subject: drivers: net: xgene: Remove unused macros This patch cleans up unused macros to improve readability. Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 3ce349f96c8d..ed5100529cff 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -217,12 +217,6 @@ enum xgene_enet_rm { #define FULL_DUPLEX2 BIT(0) #define PAD_CRC BIT(2) #define LENGTH_CHK BIT(4) -#define SCAN_AUTO_INCR BIT(5) -#define TBYT_ADDR 0x38 -#define TPKT_ADDR 0x39 -#define TDRP_ADDR 0x45 -#define TFCS_ADDR 0x47 -#define TUND_ADDR 0x4a #define TSO_IPPROTO_TCP 1 -- cgit v1.2.3 From 2d07d8e4f0536e82d5c194239ed0eaa0f2c47ab1 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 10 May 2017 13:45:05 -0700 Subject: drivers: net: xgene: Extend ethtool statistics This patch adds extended ethtool statistics support. Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- .../net/ethernet/apm/xgene/xgene_enet_ethtool.c | 89 +++++++++++++++++++++- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 29 +++++++ drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 51 +++++++++++++ drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 8 ++ drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 4 + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 1 + 6 files changed, 181 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 217cde86e117..a7eed3b83912 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -23,9 +23,17 @@ struct xgene_gstrings_stats { char name[ETH_GSTRING_LEN]; int offset; + u32 addr; + u32 mask; }; #define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) } +#define XGENE_EXTD_STAT(s, a, m) \ + { \ + .name = #s, \ + .addr = a ## _ADDR, \ + .mask = m \ + } static const struct xgene_gstrings_stats gstrings_stats[] = { XGENE_STAT(rx_packets), @@ -40,7 +48,51 @@ static const struct xgene_gstrings_stats gstrings_stats[] = { XGENE_STAT(rx_fifo_errors) }; +static const struct xgene_gstrings_stats gstrings_extd_stats[] = { + XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31), + XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31), + XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31), + XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31), + XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31), + XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31), + XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31), + XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16), + XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31), + XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31), + XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16), + XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16), + XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16), + XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16), + XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16), + XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16), + XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16), + XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16), + XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16), + XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16), + XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16), + XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16), + XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31), + XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31), + XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16), + XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31), + XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31), + XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31), + XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31), + XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31), + XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31), + XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31), + XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16), + XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16), + XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12), + XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12), + XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12), + XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12), + XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12), + XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12) +}; + #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) +#define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats) static void xgene_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) @@ -142,6 +194,11 @@ static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } + + for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { + memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } } static int xgene_get_sset_count(struct net_device *ndev, int sset) @@ -149,19 +206,49 @@ static int xgene_get_sset_count(struct net_device *ndev, int sset) if (sset != ETH_SS_STATS) return -EINVAL; - return XGENE_STATS_LEN; + return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN; +} + +static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata) +{ + u32 tmp; + int i; + + for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { + tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr); + pdata->extd_stats[i] += tmp & + GENMASK(gstrings_extd_stats[i].mask - 1, 0); + } +} + +int xgene_extd_stats_init(struct xgene_enet_pdata *pdata) +{ + pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev, + XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL); + if (!pdata->extd_stats) + return -ENOMEM; + + xgene_get_extd_stats(pdata); + memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64)); + + return 0; } static void xgene_get_ethtool_stats(struct net_device *ndev, struct ethtool_stats *dummy, u64 *data) { + struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct rtnl_link_stats64 stats; int i; dev_get_stats(ndev, &stats); for (i = 0; i < XGENE_STATS_LEN; i++) data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset); + + xgene_get_extd_stats(pdata); + for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) + data[i + XGENE_STATS_LEN] = pdata->extd_stats[i]; } static void xgene_get_pauseparam(struct net_device *ndev, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 02df5776e942..9e891939fcf8 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -359,6 +359,35 @@ u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr) return rd_data; } +u32 xgene_enet_rd_stat(struct xgene_enet_pdata *pdata, u32 rd_addr) +{ + void __iomem *addr, *rd, *cmd, *cmd_done; + u32 done, rd_data; + u8 wait = 10; + + addr = pdata->mcx_stats_addr + STAT_ADDR_REG_OFFSET; + rd = pdata->mcx_stats_addr + STAT_READ_REG_OFFSET; + cmd = pdata->mcx_stats_addr + STAT_COMMAND_REG_OFFSET; + cmd_done = pdata->mcx_stats_addr + STAT_COMMAND_DONE_REG_OFFSET; + + spin_lock(&pdata->stats_lock); + iowrite32(rd_addr, addr); + iowrite32(XGENE_ENET_RD_CMD, cmd); + + while (!(done = ioread32(cmd_done)) && wait--) + udelay(1); + + if (!done) + netdev_err(pdata->ndev, "mac stats read failed, addr: %04x\n", + rd_addr); + + rd_data = ioread32(rd); + iowrite32(0, cmd); + spin_unlock(&pdata->stats_lock); + + return rd_data; +} + static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) { u32 addr0, addr1; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index ed5100529cff..f1a4cfa641ae 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -115,6 +115,7 @@ enum xgene_enet_rm { #define BLOCK_ETH_CLKRST_CSR_OFFSET 0xc000 #define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000 #define BLOCK_ETH_MAC_OFFSET 0x0000 +#define BLOCK_ETH_STATS_OFFSET 0x0000 #define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 #define CLKEN_ADDR 0xc208 @@ -126,6 +127,12 @@ enum xgene_enet_rm { #define MAC_READ_REG_OFFSET 0x0c #define MAC_COMMAND_DONE_REG_OFFSET 0x10 +#define STAT_ADDR_REG_OFFSET 0x14 +#define STAT_COMMAND_REG_OFFSET 0x18 +#define STAT_WRITE_REG_OFFSET 0x1c +#define STAT_READ_REG_OFFSET 0x20 +#define STAT_COMMAND_DONE_REG_OFFSET 0x24 + #define PCS_ADDR_REG_OFFSET 0x00 #define PCS_COMMAND_REG_OFFSET 0x04 #define PCS_WRITE_REG_OFFSET 0x08 @@ -218,6 +225,49 @@ enum xgene_enet_rm { #define PAD_CRC BIT(2) #define LENGTH_CHK BIT(4) +#define TR64_ADDR 0x20 +#define TR127_ADDR 0x21 +#define TR255_ADDR 0x22 +#define TR511_ADDR 0x23 +#define TR1K_ADDR 0x24 +#define TRMAX_ADDR 0x25 +#define TRMGV_ADDR 0x26 + +#define RFCS_ADDR 0x29 +#define RMCA_ADDR 0x2a +#define RBCA_ADDR 0x2b +#define RXCF_ADDR 0x2c +#define RXPF_ADDR 0x2d +#define RXUO_ADDR 0x2e +#define RALN_ADDR 0x2f +#define RFLR_ADDR 0x30 +#define RCDE_ADDR 0x31 +#define RCSE_ADDR 0x32 +#define RUND_ADDR 0x33 +#define ROVR_ADDR 0x34 +#define RFRG_ADDR 0x35 +#define RJBR_ADDR 0x36 +#define RDRP_ADDR 0x37 + +#define TMCA_ADDR 0x3a +#define TBCA_ADDR 0x3b +#define TXPF_ADDR 0x3c +#define TDFR_ADDR 0x3d +#define TEDF_ADDR 0x3e +#define TSCL_ADDR 0x3f +#define TMCL_ADDR 0x40 +#define TLCL_ADDR 0x41 +#define TXCL_ADDR 0x42 +#define TNCL_ADDR 0x43 +#define TPFH_ADDR 0x44 +#define TDRP_ADDR 0x45 +#define TJBR_ADDR 0x46 +#define TFCS_ADDR 0x47 +#define TXCF_ADDR 0x48 +#define TOVR_ADDR 0x49 +#define TUND_ADDR 0x4a +#define TFRG_ADDR 0x4b + #define TSO_IPPROTO_TCP 1 #define USERINFO_POS 0 @@ -383,6 +433,7 @@ void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata); u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr); void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr, u32 wr_data); +u32 xgene_enet_rd_stat(struct xgene_enet_pdata *pdata, u32 rd_addr); extern const struct xgene_mac_ops xgene_gmac_ops; extern const struct xgene_port_ops xgene_gport_ops; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 3f24b83a6c55..bd2486e30653 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -1792,12 +1792,15 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII || pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { pdata->mcx_mac_addr = pdata->base_addr + BLOCK_ETH_MAC_OFFSET; + pdata->mcx_stats_addr = + pdata->base_addr + BLOCK_ETH_STATS_OFFSET; offset = (pdata->enet_id == XGENE_ENET1) ? BLOCK_ETH_MAC_CSR_OFFSET : X2_BLOCK_ETH_MAC_CSR_OFFSET; pdata->mcx_mac_csr_addr = base_addr + offset; } else { pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET; + pdata->mcx_stats_addr = base_addr + BLOCK_AXG_STATS_OFFSET; pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET; pdata->pcs_addr = base_addr + BLOCK_PCS_OFFSET; } @@ -2090,6 +2093,11 @@ static int xgene_enet_probe(struct platform_device *pdev) goto err1; } + spin_lock_init(&pdata->stats_lock); + ret = xgene_extd_stats_init(pdata); + if (ret) + goto err2; + xgene_enet_napi_add(pdata); ret = register_netdev(ndev); if (ret) { diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 3bf66385dbdf..cbdc09c1d0d7 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -214,6 +214,7 @@ struct xgene_enet_pdata { void __iomem *eth_diag_csr_addr; void __iomem *mcx_mac_addr; void __iomem *mcx_mac_csr_addr; + void __iomem *mcx_stats_addr; void __iomem *base_addr; void __iomem *pcs_addr; void __iomem *ring_csr_addr; @@ -221,6 +222,8 @@ struct xgene_enet_pdata { int phy_mode; enum xgene_enet_rm rm; struct xgene_enet_cle cle; + u64 *extd_stats; + spinlock_t stats_lock; /* statistics lock */ const struct xgene_mac_ops *mac_ops; spinlock_t mac_lock; /* mac lock */ const struct xgene_port_ops *port_ops; @@ -265,5 +268,6 @@ static inline u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring) } void xgene_enet_set_ethtool_ops(struct net_device *netdev); +int xgene_extd_stats_init(struct xgene_enet_pdata *pdata); #endif /* __XGENE_ENET_MAIN_H__ */ diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h index e644a429ebf4..9b98c83951a3 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h @@ -23,6 +23,7 @@ #define X2_BLOCK_ETH_MAC_CSR_OFFSET 0x3000 #define BLOCK_AXG_MAC_OFFSET 0x0800 +#define BLOCK_AXG_STATS_OFFSET 0x0800 #define BLOCK_AXG_MAC_CSR_OFFSET 0x2000 #define BLOCK_PCS_OFFSET 0x3800 -- cgit v1.2.3 From ca6d550c5dbe66e9e26eb52b7b1713b801f86c4f Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Wed, 10 May 2017 13:45:06 -0700 Subject: drivers: net: xgene: Add rx_overrun/tx_underrun statistics This patch adds rx_overrun and tx_underrun ethtool statistic counters. Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c | 16 +++++++++++++--- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 11 +++++++++++ drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 8 ++++++++ drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 1 + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 14 ++++++++++++++ drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 11 +++++++++++ drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 4 ++++ 7 files changed, 62 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index a7eed3b83912..6b2a4b917c10 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -71,6 +71,7 @@ static const struct xgene_gstrings_stats gstrings_extd_stats[] = { XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16), XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16), XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16), + XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0), XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31), XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31), XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16), @@ -88,11 +89,14 @@ static const struct xgene_gstrings_stats gstrings_extd_stats[] = { XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12), XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12), XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12), - XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12) + XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12), + XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0) }; #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) #define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats) +#define RX_OVERRUN_IDX 22 +#define TX_UNDERRUN_IDX 41 static void xgene_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) @@ -211,14 +215,20 @@ static int xgene_get_sset_count(struct net_device *ndev, int sset) static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata) { + u32 rx_drop, tx_drop; u32 tmp; int i; for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr); - pdata->extd_stats[i] += tmp & - GENMASK(gstrings_extd_stats[i].mask - 1, 0); + if (gstrings_extd_stats[i].mask) + pdata->extd_stats[i] += tmp & + GENMASK(gstrings_extd_stats[i].mask - 1, 0); } + + pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop); + pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop; + pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop; } int xgene_extd_stats_init(struct xgene_enet_pdata *pdata) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 9e891939fcf8..5278d62d5b57 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -618,6 +618,16 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) xgene_enet_wr_csr(pdata, CFG_BYPASS_ADDR, RESUME_TX); } +static void xgene_gmac_get_drop_cnt(struct xgene_enet_pdata *pdata, + u32 *rx, u32 *tx) +{ + u32 count; + + xgene_enet_rd_mcx_csr(pdata, ICM_ECM_DROP_COUNT_REG0_ADDR, &count); + *rx = ICM_DROP_COUNT(count); + *tx = ECM_DROP_COUNT(count); +} + static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) { u32 val = 0xffffffff; @@ -1027,6 +1037,7 @@ const struct xgene_mac_ops xgene_gmac_ops = { .tx_enable = xgene_gmac_tx_enable, .rx_disable = xgene_gmac_rx_disable, .tx_disable = xgene_gmac_tx_disable, + .get_drop_cnt = xgene_gmac_get_drop_cnt, .set_speed = xgene_gmac_set_speed, .set_mac_addr = xgene_gmac_set_mac_addr, .set_framesize = xgene_enet_set_frame_size, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index f1a4cfa641ae..5d3e18d3c94c 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -192,6 +192,10 @@ enum xgene_enet_rm { #define CFG_CLE_NXTFPSEL0(val) (((val) << 20) & GENMASK(23, 20)) #define ICM_CONFIG0_REG_0_ADDR 0x0400 #define ICM_CONFIG2_REG_0_ADDR 0x0410 +#define ECM_CONFIG0_REG_0_ADDR 0x0500 +#define ECM_CONFIG0_REG_1_ADDR 0x0504 +#define ICM_ECM_DROP_COUNT_REG0_ADDR 0x0508 +#define ICM_ECM_DROP_COUNT_REG1_ADDR 0x050c #define RX_DV_GATE_REG_0_ADDR 0x05fc #define TX_DV_GATE_EN0 BIT(2) #define RX_DV_GATE_EN0 BIT(1) @@ -267,6 +271,10 @@ enum xgene_enet_rm { #define TOVR_ADDR 0x49 #define TUND_ADDR 0x4a #define TFRG_ADDR 0x4b +#define DUMP_ADDR 0x27 + +#define ECM_DROP_COUNT(src) xgene_get_bits(src, 0, 15) +#define ICM_DROP_COUNT(src) xgene_get_bits(src, 16, 31) #define TSO_IPPROTO_TCP 1 diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index cbdc09c1d0d7..cabe54edb17c 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -157,6 +157,7 @@ struct xgene_mac_ops { void (*rx_enable)(struct xgene_enet_pdata *pdata); void (*tx_disable)(struct xgene_enet_pdata *pdata); void (*rx_disable)(struct xgene_enet_pdata *pdata); + void (*get_drop_cnt)(struct xgene_enet_pdata *pdata, u32 *rx, u32 *tx); void (*set_speed)(struct xgene_enet_pdata *pdata); void (*set_mac_addr)(struct xgene_enet_pdata *pdata); void (*set_framesize)(struct xgene_enet_pdata *pdata, int framesize); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index cb6350f7e137..2919d3e36fad 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -95,6 +95,19 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) return -ENODEV; } +static void xgene_sgmac_get_drop_cnt(struct xgene_enet_pdata *pdata, + u32 *rx, u32 *tx) +{ + u32 addr, count; + + addr = (pdata->enet_id != XGENE_ENET1) ? + XG_MCX_ICM_ECM_DROP_COUNT_REG0_ADDR : + ICM_ECM_DROP_COUNT_REG0_ADDR + pdata->port_id * OFFSET_4; + count = xgene_enet_rd_mcx_csr(pdata, addr); + *rx = ICM_DROP_COUNT(count); + *tx = ECM_DROP_COUNT(count); +} + static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *p) { u32 val; @@ -600,6 +613,7 @@ const struct xgene_mac_ops xgene_sgmac_ops = { .tx_enable = xgene_sgmac_tx_enable, .rx_disable = xgene_sgmac_rx_disable, .tx_disable = xgene_sgmac_tx_disable, + .get_drop_cnt = xgene_sgmac_get_drop_cnt, .set_speed = xgene_sgmac_set_speed, .set_mac_addr = xgene_sgmac_set_mac_addr, .set_framesize = xgene_sgmac_set_frame_size, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c index c6a5dac3a126..56dff380cbb7 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c @@ -180,6 +180,16 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) return 0; } +static void xgene_xgmac_get_drop_cnt(struct xgene_enet_pdata *pdata, + u32 *rx, u32 *tx) +{ + u32 count; + + xgene_enet_rd_axg_csr(pdata, XGENET_ICM_ECM_DROP_COUNT_REG0, &count); + *rx = ICM_DROP_COUNT(count); + *tx = ECM_DROP_COUNT(count); +} + static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) { xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, 0); @@ -537,6 +547,7 @@ const struct xgene_mac_ops xgene_xgmac_ops = { .set_mac_addr = xgene_xgmac_set_mac_addr, .set_framesize = xgene_xgmac_set_frame_size, .set_mss = xgene_xgmac_set_mss, + .get_drop_cnt = xgene_xgmac_get_drop_cnt, .link_state = xgene_enet_link_state, .enable_tx_pause = xgene_xgmac_enable_tx_pause, .flowctl_rx = xgene_xgmac_flowctl_rx, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h index 9b98c83951a3..a3b45517df45 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h @@ -71,6 +71,8 @@ #define XG_RSIF_CONFIG1_REG_ADDR 0x00b8 #define XG_RSIF_PLC_CLE_BUFF_THRESH 0x1 #define RSIF_PLC_CLE_BUFF_THRESH_SET(dst, val) xgene_set_bits(dst, val, 0, 2) +#define XG_MCX_ECM_CONFIG0_REG_0_ADDR 0x0070 +#define XG_MCX_ICM_ECM_DROP_COUNT_REG0_ADDR 0x0124 #define XCLE_BYPASS_REG0_ADDR 0x0160 #define XCLE_BYPASS_REG1_ADDR 0x0164 #define XG_CFG_BYPASS_ADDR 0x0204 @@ -81,6 +83,8 @@ #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 +#define XGENET_ECM_CONFIG0_REG_0 0x0870 +#define XGENET_ICM_ECM_DROP_COUNT_REG0 0x0924 #define XGENET_CSR_ECM_CFG_0_ADDR 0x0880 #define XGENET_CSR_MULTI_DPF0_ADDR 0x0888 #define XGENET_CSR_MULTI_DPF1_ADDR 0x088c -- cgit v1.2.3 From a844e7d1fa24660dd17a78e5165210a3da112e73 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 10 May 2017 13:45:07 -0700 Subject: drivers: net: xgene: Workaround for HW errata 10GE_4 This patch adds workaround for HW errata 10GE_4: "XGENET_ICM_ECM_DROP_COUNT_REG_0 reg not clear on read". Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 2 ++ drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 5 +++++ drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 2 ++ 3 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 5278d62d5b57..3235d0cf3942 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -626,6 +626,8 @@ static void xgene_gmac_get_drop_cnt(struct xgene_enet_pdata *pdata, xgene_enet_rd_mcx_csr(pdata, ICM_ECM_DROP_COUNT_REG0_ADDR, &count); *rx = ICM_DROP_COUNT(count); *tx = ECM_DROP_COUNT(count); + /* Errata: 10GE_4 - Fix ICM_ECM_DROP_COUNT not clear-on-read */ + xgene_enet_rd_mcx_csr(pdata, ECM_CONFIG0_REG_0_ADDR, &count); } static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index 2919d3e36fad..31df8f32c214 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -106,6 +106,11 @@ static void xgene_sgmac_get_drop_cnt(struct xgene_enet_pdata *pdata, count = xgene_enet_rd_mcx_csr(pdata, addr); *rx = ICM_DROP_COUNT(count); *tx = ECM_DROP_COUNT(count); + /* Errata: 10GE_4 - ICM_ECM_DROP_COUNT not clear-on-read */ + addr = (pdata->enet_id != XGENE_ENET1) ? + XG_MCX_ECM_CONFIG0_REG_0_ADDR : + ECM_CONFIG0_REG_0_ADDR + pdata->port_id * OFFSET_4; + xgene_enet_rd_mcx_csr(pdata, addr); } static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *p) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c index 56dff380cbb7..eab6f1c12f1c 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c @@ -188,6 +188,8 @@ static void xgene_xgmac_get_drop_cnt(struct xgene_enet_pdata *pdata, xgene_enet_rd_axg_csr(pdata, XGENET_ICM_ECM_DROP_COUNT_REG0, &count); *rx = ICM_DROP_COUNT(count); *tx = ECM_DROP_COUNT(count); + /* Errata: 10GE_4 - ICM_ECM_DROP_COUNT not clear-on-read */ + xgene_enet_rd_axg_csr(pdata, XGENET_ECM_CONFIG0_REG_0, &count); } static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) -- cgit v1.2.3 From eaef62a42db15f2833c9e6af18067b02b6089336 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 10 May 2017 13:45:08 -0700 Subject: drivers: net: xgene: Add frame recovered statistics counter for errata 10GE_8/ENET_11 This patch adds statistic counter for frames recovered from HW errata 10GE_8 and ENET_11: "HW reports Length error for valid 64 byte frames with len <46 bytes". Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c | 9 +++++++-- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 2 ++ drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 6b2a4b917c10..5c2c84a8b690 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -64,6 +64,7 @@ static const struct xgene_gstrings_stats gstrings_extd_stats[] = { XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16), XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16), XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16), + XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0), XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16), XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16), XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16), @@ -95,8 +96,9 @@ static const struct xgene_gstrings_stats gstrings_extd_stats[] = { #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) #define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats) -#define RX_OVERRUN_IDX 22 -#define TX_UNDERRUN_IDX 41 +#define FALSE_RFLR_IDX 15 +#define RX_OVERRUN_IDX 23 +#define TX_UNDERRUN_IDX 42 static void xgene_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) @@ -229,6 +231,9 @@ static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata) pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop); pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop; pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop; + + /* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */ + pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr; } int xgene_extd_stats_init(struct xgene_enet_pdata *pdata) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index bd2486e30653..c2d38da88084 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -712,6 +712,8 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, xgene_enet_parse_error(rx_ring, status); rx_ring->rx_dropped++; goto out; + } else { + pdata->false_rflr++; } } diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index cabe54edb17c..0f5f0b07c482 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -224,6 +224,7 @@ struct xgene_enet_pdata { enum xgene_enet_rm rm; struct xgene_enet_cle cle; u64 *extd_stats; + u64 false_rflr; spinlock_t stats_lock; /* statistics lock */ const struct xgene_mac_ops *mac_ops; spinlock_t mac_lock; /* mac lock */ -- cgit v1.2.3 From 61c759cdf48a21e0a0794d30c509c49cbdbac752 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 10 May 2017 13:45:09 -0700 Subject: drivers: net: xgene: Workaround for HW errata 10GE_10/ENET_15 This patch adds workaround for HW errata 10GE_10 and ENET_15: "HW statistic counters value are duplicated". - RFCS duplicates RALN counter - RFLR duplicates RUND counter - TFCS duplicates TFRG counter - RALN should be intepreted as 0 in 10G mode Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- .../net/ethernet/apm/xgene/xgene_enet_ethtool.c | 33 ++++++++++++++++++---- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 20 +++++++++++-- drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 2 ++ 3 files changed, 46 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 5c2c84a8b690..0fdec78c5399 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -71,6 +71,7 @@ static const struct xgene_gstrings_stats gstrings_extd_stats[] = { XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16), XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16), XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16), + XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0), XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16), XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0), XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31), @@ -96,9 +97,16 @@ static const struct xgene_gstrings_stats gstrings_extd_stats[] = { #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) #define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats) +#define RFCS_IDX 7 +#define RALN_IDX 13 +#define RFLR_IDX 14 #define FALSE_RFLR_IDX 15 -#define RX_OVERRUN_IDX 23 -#define TX_UNDERRUN_IDX 42 +#define RUND_IDX 18 +#define FALSE_RJBR_IDX 22 +#define RX_OVERRUN_IDX 24 +#define TFCS_IDX 38 +#define TFRG_IDX 42 +#define TX_UNDERRUN_IDX 43 static void xgene_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) @@ -218,14 +226,25 @@ static int xgene_get_sset_count(struct net_device *ndev, int sset) static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata) { u32 rx_drop, tx_drop; - u32 tmp; + u32 mask, tmp; int i; for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr); - if (gstrings_extd_stats[i].mask) - pdata->extd_stats[i] += tmp & - GENMASK(gstrings_extd_stats[i].mask - 1, 0); + if (gstrings_extd_stats[i].mask) { + mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0); + pdata->extd_stats[i] += (tmp & mask); + } + } + + if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { + /* Errata 10GE_10 - SW should intepret RALN as 0 */ + pdata->extd_stats[RALN_IDX] = 0; + } else { + /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */ + pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX]; + pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX]; + pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX]; } pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop); @@ -234,6 +253,8 @@ static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata) /* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */ pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr; + /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */ + pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr; } int xgene_extd_stats_init(struct xgene_enet_pdata *pdata) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index c2d38da88084..01e389df3aff 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -656,6 +656,18 @@ static void xgene_enet_free_pagepool(struct xgene_enet_desc_ring *buf_pool, buf_pool->head = head; } +/* Errata 10GE_10 and ENET_15 - Fix duplicated HW statistic counters */ +static bool xgene_enet_errata_10GE_10(struct sk_buff *skb, u32 len, u8 status) +{ + if (status == INGRESS_CRC && + len >= (ETHER_STD_PACKET + 1) && + len <= (ETHER_STD_PACKET + 4) && + skb->protocol == htons(ETH_P_8021Q)) + return true; + + return false; +} + /* Errata 10GE_8 and ENET_11 - allow packet with length <=64B */ static bool xgene_enet_errata_10GE_8(struct sk_buff *skb, u32 len, u8 status) { @@ -706,14 +718,16 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) | GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); if (unlikely(status)) { - if (!xgene_enet_errata_10GE_8(skb, datalen, status)) { + if (xgene_enet_errata_10GE_8(skb, datalen, status)) { + pdata->false_rflr++; + } else if (xgene_enet_errata_10GE_10(skb, datalen, status)) { + pdata->vlan_rjbr++; + } else { dev_kfree_skb_any(skb); xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc); xgene_enet_parse_error(rx_ring, status); rx_ring->rx_dropped++; goto out; - } else { - pdata->false_rflr++; } } diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 0f5f0b07c482..985768596900 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -42,6 +42,7 @@ #define XGENE_DRV_VERSION "v1.0" #define ETHER_MIN_PACKET 64 +#define ETHER_STD_PACKET 1518 #define XGENE_ENET_STD_MTU 1536 #define XGENE_ENET_MAX_MTU 9600 #define SKB_BUFFER_SIZE (XGENE_ENET_STD_MTU - NET_IP_ALIGN) @@ -225,6 +226,7 @@ struct xgene_enet_pdata { struct xgene_enet_cle cle; u64 *extd_stats; u64 false_rflr; + u64 vlan_rjbr; spinlock_t stats_lock; /* statistics lock */ const struct xgene_mac_ops *mac_ops; spinlock_t mac_lock; /* mac lock */ -- cgit v1.2.3 From 8aba8474181070a30f56ffd19359f5d80665175e Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Wed, 10 May 2017 13:45:10 -0700 Subject: drivers: net: xgene: Fix redundant prefetch buffer cleanup Prefetch buffer cleanup code was called twice, causing EDAC to report errors during reboot. [ 1130.972475] xgene-edac 78800000.edac: IOB bridge agent (BA) transaction error [ 1130.979584] xgene-edac 78800000.edac: IOB BA write response error [ 1130.985648] xgene-edac 78800000.edac: IOB BA write access at 0x00.00000000 () [ 1130.993612] xgene-edac 78800000.edac: IOB BA requestor ID 0x00002400 [ 1131.000242] xgene-edac 78800000.edac: IOB bridge agent (BA) transaction error ... This patch fixes the errors by, - removing the redundant prefetch buffer cleanup from port_ops->shutdown() - moving port_ops->shutdown() after delete_rings() Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 21 --------------------- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 2 +- drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 20 -------------------- drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 20 -------------------- 4 files changed, 1 insertion(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 3235d0cf3942..6ac27c7522a7 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -763,27 +763,6 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata, static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) { struct device *dev = &pdata->pdev->dev; - struct xgene_enet_desc_ring *ring; - u32 pb; - int i; - - pb = 0; - for (i = 0; i < pdata->rxq_cnt; i++) { - ring = pdata->rx_ring[i]->buf_pool; - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - ring = pdata->rx_ring[i]->page_pool; - if (ring) - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - - } - xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb); - - pb = 0; - for (i = 0; i < pdata->txq_cnt; i++) { - ring = pdata->tx_ring[i]; - pb |= BIT(xgene_enet_ring_bufnum(ring->id)); - } - xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); if (dev->of_node) { if (!IS_ERR(pdata->clk)) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 01e389df3aff..21cd4ef3e5eb 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -2159,8 +2159,8 @@ static int xgene_enet_remove(struct platform_device *pdev) xgene_enet_mdio_remove(pdata); unregister_netdev(ndev); - pdata->port_ops->shutdown(pdata); xgene_enet_delete_desc_rings(pdata); + pdata->port_ops->shutdown(pdata); free_netdev(ndev); return 0; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index 31df8f32c214..b1a83fdbefb8 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -534,26 +534,6 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata, static void xgene_enet_shutdown(struct xgene_enet_pdata *p) { struct device *dev = &p->pdev->dev; - struct xgene_enet_desc_ring *ring; - u32 pb; - int i; - - pb = 0; - for (i = 0; i < p->rxq_cnt; i++) { - ring = p->rx_ring[i]->buf_pool; - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - ring = p->rx_ring[i]->page_pool; - if (ring) - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - } - xgene_enet_wr_ring_if(p, ENET_CFGSSQMIFPRESET_ADDR, pb); - - pb = 0; - for (i = 0; i < p->txq_cnt; i++) { - ring = p->tx_ring[i]; - pb |= BIT(xgene_enet_ring_bufnum(ring->id)); - } - xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQRESET_ADDR, pb); if (dev->of_node) { if (!IS_ERR(p->clk)) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c index eab6f1c12f1c..b7d75d067c7a 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c @@ -446,26 +446,6 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) { struct device *dev = &pdata->pdev->dev; - struct xgene_enet_desc_ring *ring; - u32 pb; - int i; - - pb = 0; - for (i = 0; i < pdata->rxq_cnt; i++) { - ring = pdata->rx_ring[i]->buf_pool; - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - ring = pdata->rx_ring[i]->page_pool; - if (ring) - pb |= BIT(xgene_enet_get_fpsel(ring->id)); - } - xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb); - - pb = 0; - for (i = 0; i < pdata->txq_cnt; i++) { - ring = pdata->tx_ring[i]; - pb |= BIT(xgene_enet_ring_bufnum(ring->id)); - } - xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); if (dev->of_node) { if (!IS_ERR(pdata->clk)) -- cgit v1.2.3 From c519fe9a4f0d1a1c559529c404589b8e346143f3 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Tue, 9 May 2017 18:30:12 -0700 Subject: bnxt: add dma mapping attributes On the SPARC platform we need to use the DMA_ATTR_WEAK_ORDERING attribute in our Rx path dma mapping in order to get the expected performance out of the receive path. Adding it to the Tx path has little effect, so that's not a part of this patch. Signed-off-by: Shannon Nelson Reviewed-by: Tushar Dave Reviewed-by: Tom Saeger Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 56 +++++++++++++++++++------------ 1 file changed, 34 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b56c54d68d5e..707d92f7ebb1 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -582,7 +582,8 @@ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping, if (!page) return NULL; - *mapping = dma_map_page(dev, page, 0, PAGE_SIZE, bp->rx_dir); + *mapping = dma_map_page_attrs(dev, page, 0, PAGE_SIZE, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); if (dma_mapping_error(dev, *mapping)) { __free_page(page); return NULL; @@ -601,8 +602,9 @@ static inline u8 *__bnxt_alloc_rx_data(struct bnxt *bp, dma_addr_t *mapping, if (!data) return NULL; - *mapping = dma_map_single(&pdev->dev, data + bp->rx_dma_offset, - bp->rx_buf_use_size, bp->rx_dir); + *mapping = dma_map_single_attrs(&pdev->dev, data + bp->rx_dma_offset, + bp->rx_buf_use_size, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); if (dma_mapping_error(&pdev->dev, *mapping)) { kfree(data); @@ -705,8 +707,9 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp, return -ENOMEM; } - mapping = dma_map_page(&pdev->dev, page, offset, BNXT_RX_PAGE_SIZE, - PCI_DMA_FROMDEVICE); + mapping = dma_map_page_attrs(&pdev->dev, page, offset, + BNXT_RX_PAGE_SIZE, PCI_DMA_FROMDEVICE, + DMA_ATTR_WEAK_ORDERING); if (dma_mapping_error(&pdev->dev, mapping)) { __free_page(page); return -EIO; @@ -799,7 +802,8 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp, return NULL; } dma_addr -= bp->rx_dma_offset; - dma_unmap_page(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir); + dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); if (unlikely(!payload)) payload = eth_get_headlen(data_ptr, len); @@ -841,8 +845,8 @@ static struct sk_buff *bnxt_rx_skb(struct bnxt *bp, } skb = build_skb(data, 0); - dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, - bp->rx_dir); + dma_unmap_single_attrs(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, + bp->rx_dir, DMA_ATTR_WEAK_ORDERING); if (!skb) { kfree(data); return NULL; @@ -909,8 +913,9 @@ static struct sk_buff *bnxt_rx_pages(struct bnxt *bp, struct bnxt_napi *bnapi, return NULL; } - dma_unmap_page(&pdev->dev, mapping, BNXT_RX_PAGE_SIZE, - PCI_DMA_FROMDEVICE); + dma_unmap_page_attrs(&pdev->dev, mapping, BNXT_RX_PAGE_SIZE, + PCI_DMA_FROMDEVICE, + DMA_ATTR_WEAK_ORDERING); skb->data_len += frag_len; skb->len += frag_len; @@ -1329,8 +1334,9 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, tpa_info->mapping = new_mapping; skb = build_skb(data, 0); - dma_unmap_single(&bp->pdev->dev, mapping, bp->rx_buf_use_size, - bp->rx_dir); + dma_unmap_single_attrs(&bp->pdev->dev, mapping, + bp->rx_buf_use_size, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); if (!skb) { kfree(data); @@ -1971,9 +1977,11 @@ static void bnxt_free_rx_skbs(struct bnxt *bp) if (!data) continue; - dma_unmap_single(&pdev->dev, tpa_info->mapping, - bp->rx_buf_use_size, - bp->rx_dir); + dma_unmap_single_attrs(&pdev->dev, + tpa_info->mapping, + bp->rx_buf_use_size, + bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); tpa_info->data = NULL; @@ -1993,13 +2001,15 @@ static void bnxt_free_rx_skbs(struct bnxt *bp) if (BNXT_RX_PAGE_MODE(bp)) { mapping -= bp->rx_dma_offset; - dma_unmap_page(&pdev->dev, mapping, - PAGE_SIZE, bp->rx_dir); + dma_unmap_page_attrs(&pdev->dev, mapping, + PAGE_SIZE, bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); __free_page(data); } else { - dma_unmap_single(&pdev->dev, mapping, - bp->rx_buf_use_size, - bp->rx_dir); + dma_unmap_single_attrs(&pdev->dev, mapping, + bp->rx_buf_use_size, + bp->rx_dir, + DMA_ATTR_WEAK_ORDERING); kfree(data); } } @@ -2012,8 +2022,10 @@ static void bnxt_free_rx_skbs(struct bnxt *bp) if (!page) continue; - dma_unmap_page(&pdev->dev, rx_agg_buf->mapping, - BNXT_RX_PAGE_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_page_attrs(&pdev->dev, rx_agg_buf->mapping, + BNXT_RX_PAGE_SIZE, + PCI_DMA_FROMDEVICE, + DMA_ATTR_WEAK_ORDERING); rx_agg_buf->page = NULL; __clear_bit(j, rxr->rx_agg_bmap); -- cgit v1.2.3 From 05eb9e5336cec824a071d2fdc971a008c4a9ecd8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 15 May 2017 17:55:15 -0700 Subject: nfp: don't enable TSO on the device when disabled We advertise TSO to the stack but leave it disabled by default. Make sure it's not only disabled in the netdev features but also on the device itself. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 82bd6b0935f1..76251a09a1f3 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3286,6 +3286,7 @@ int nfp_net_netdev_init(struct net_device *netdev) /* Advertise but disable TSO by default. */ netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO; /* Allow L2 Broadcast and Multicast through by default, if supported */ if (nn->cap & NFP_NET_CFG_CTRL_L2BC) -- cgit v1.2.3 From e53fc9fa0ce12df32004dd05b9735a00c4ac5d04 Mon Sep 17 00:00:00 2001 From: Edwin Peer Date: Mon, 15 May 2017 17:55:16 -0700 Subject: nfp: rename l4_offset in struct nfp_net_tx_desc to lso_hdrlen The l4_offset field referred to by NFD is confusingly named. It is not the offset of the L4 transport header, but rather the L4 payload. The LSO2 capability supported by alternative device firmware requires the actual L4 offset, thus the rename seems prudent. Signed-off-by: Edwin Peer Reviewed-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 2 +- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index fcf81b3be830..6bad11e5b845 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -153,7 +153,7 @@ struct nfp_net_tx_desc { __le32 dma_addr_lo; /* Low 32bit of host buf addr */ __le16 mss; /* MSS to be used for LSO */ - u8 l4_offset; /* LSO, where the L4 data starts */ + u8 lso_hdrlen; /* LSO, TCP payload offset */ u8 flags; /* TX Flags, see @PCIE_DESC_TX_* */ __le16 vlan; /* VLAN tag to add if indicated */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 76251a09a1f3..0cebe9098451 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -677,7 +677,7 @@ static void nfp_net_tx_tso(struct nfp_net_r_vector *r_vec, txbuf->real_len += hdrlen * (txbuf->pkt_cnt - 1); mss = skb_shinfo(skb)->gso_size & PCIE_DESC_TX_MSS_MASK; - txd->l4_offset = hdrlen; + txd->lso_hdrlen = hdrlen; txd->mss = cpu_to_le16(mss); txd->flags |= PCIE_DESC_TX_LSO; @@ -823,7 +823,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) txd->flags = 0; txd->mss = 0; - txd->l4_offset = 0; + txd->lso_hdrlen = 0; nfp_net_tx_tso(r_vec, txbuf, txd, skb); @@ -1515,7 +1515,7 @@ nfp_net_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring, txd->flags = 0; txd->mss = 0; - txd->l4_offset = 0; + txd->lso_hdrlen = 0; tx_ring->wr_p++; tx_ring->wr_ptr_add++; -- cgit v1.2.3 From 28063be693c23340a17164a8e4bb347f0d9d1440 Mon Sep 17 00:00:00 2001 From: Edwin Peer Date: Mon, 15 May 2017 17:55:17 -0700 Subject: nfp: support LSO2 capability Firmware advertising the LSO2 capability exploits driver provided L3 and L4 offsets in order to avoid parsing packet headers in the TX path. The vlan field in struct nfp_net_tx_desc is repurposed, making TXVLAN a mutually exclusive configuration to LSO2. Signed-off-by: Edwin Peer Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 9 +++-- .../net/ethernet/netronome/nfp/nfp_net_common.c | 38 ++++++++++++++-------- drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h | 7 +++- 3 files changed, 38 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 6bad11e5b845..c6b7141dc50d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -155,8 +155,13 @@ struct nfp_net_tx_desc { __le16 mss; /* MSS to be used for LSO */ u8 lso_hdrlen; /* LSO, TCP payload offset */ u8 flags; /* TX Flags, see @PCIE_DESC_TX_* */ - - __le16 vlan; /* VLAN tag to add if indicated */ + union { + struct { + u8 l3_offset; /* L3 header offset */ + u8 l4_offset; /* L4 header offset */ + }; + __le16 vlan; /* VLAN tag to add if indicated */ + }; __le16 data_len; /* Length of frame + meta data */ } __packed; __le32 vals[4]; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 0cebe9098451..5e8049a84d16 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -667,11 +667,16 @@ static void nfp_net_tx_tso(struct nfp_net_r_vector *r_vec, if (!skb_is_gso(skb)) return; - if (!skb->encapsulation) + if (!skb->encapsulation) { + txd->l3_offset = skb_network_offset(skb); + txd->l4_offset = skb_transport_offset(skb); hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb); - else + } else { + txd->l3_offset = skb_inner_network_offset(skb); + txd->l4_offset = skb_inner_transport_offset(skb); hdrlen = skb_inner_transport_header(skb) - skb->data + inner_tcp_hdrlen(skb); + } txbuf->pkt_cnt = skb_shinfo(skb)->gso_segs; txbuf->real_len += hdrlen * (txbuf->pkt_cnt - 1); @@ -825,10 +830,9 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) txd->mss = 0; txd->lso_hdrlen = 0; + /* Do not reorder - tso may adjust pkt cnt, vlan may override fields */ nfp_net_tx_tso(r_vec, txbuf, txd, skb); - nfp_net_tx_csum(dp, r_vec, txbuf, txd, skb); - if (skb_vlan_tag_present(skb) && dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN) { txd->flags |= PCIE_DESC_TX_VLAN; txd->vlan = cpu_to_le16(skb_vlan_tag_get(skb)); @@ -2724,9 +2728,10 @@ static int nfp_net_set_features(struct net_device *netdev, if (changed & (NETIF_F_TSO | NETIF_F_TSO6)) { if (features & (NETIF_F_TSO | NETIF_F_TSO6)) - new_ctrl |= NFP_NET_CFG_CTRL_LSO; + new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_LSO2 ?: + NFP_NET_CFG_CTRL_LSO; else - new_ctrl &= ~NFP_NET_CFG_CTRL_LSO; + new_ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY; } if (changed & NETIF_F_HW_VLAN_CTAG_RX) { @@ -3032,7 +3037,7 @@ void nfp_net_info(struct nfp_net *nn) nn->fw_ver.resv, nn->fw_ver.class, nn->fw_ver.major, nn->fw_ver.minor, nn->max_mtu); - nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", nn->cap, nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "", nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "", @@ -3043,7 +3048,8 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_TXVLAN ? "TXVLAN " : "", nn->cap & NFP_NET_CFG_CTRL_SCATTER ? "SCATTER " : "", nn->cap & NFP_NET_CFG_CTRL_GATHER ? "GATHER " : "", - nn->cap & NFP_NET_CFG_CTRL_LSO ? "TSO " : "", + nn->cap & NFP_NET_CFG_CTRL_LSO ? "TSO1 " : "", + nn->cap & NFP_NET_CFG_CTRL_LSO2 ? "TSO2 " : "", nn->cap & NFP_NET_CFG_CTRL_RSS ? "RSS " : "", nn->cap & NFP_NET_CFG_CTRL_L2SWITCH ? "L2SWITCH " : "", nn->cap & NFP_NET_CFG_CTRL_MSIXAUTO ? "AUTOMASK " : "", @@ -3249,9 +3255,11 @@ int nfp_net_netdev_init(struct net_device *netdev) netdev->hw_features |= NETIF_F_SG; nn->dp.ctrl |= NFP_NET_CFG_CTRL_GATHER; } - if ((nn->cap & NFP_NET_CFG_CTRL_LSO) && nn->fw_ver.major > 2) { + if ((nn->cap & NFP_NET_CFG_CTRL_LSO && nn->fw_ver.major > 2) || + nn->cap & NFP_NET_CFG_CTRL_LSO2) { netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; - nn->dp.ctrl |= NFP_NET_CFG_CTRL_LSO; + nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_LSO2 ?: + NFP_NET_CFG_CTRL_LSO; } if (nn->cap & NFP_NET_CFG_CTRL_RSS) { netdev->hw_features |= NETIF_F_RXHASH; @@ -3275,8 +3283,12 @@ int nfp_net_netdev_init(struct net_device *netdev) nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXVLAN; } if (nn->cap & NFP_NET_CFG_CTRL_TXVLAN) { - netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX; - nn->dp.ctrl |= NFP_NET_CFG_CTRL_TXVLAN; + if (nn->cap & NFP_NET_CFG_CTRL_LSO2) { + nn_warn(nn, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n"); + } else { + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX; + nn->dp.ctrl |= NFP_NET_CFG_CTRL_TXVLAN; + } } netdev->features = netdev->hw_features; @@ -3286,7 +3298,7 @@ int nfp_net_netdev_init(struct net_device *netdev) /* Advertise but disable TSO by default. */ netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO; + nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY; /* Allow L2 Broadcast and Multicast through by default, if supported */ if (nn->cap & NFP_NET_CFG_CTRL_L2BC) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index d04ccc9f6116..1575e8fdb541 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -119,7 +119,7 @@ #define NFP_NET_CFG_CTRL_TXVLAN (0x1 << 7) /* Enable VLAN insert */ #define NFP_NET_CFG_CTRL_SCATTER (0x1 << 8) /* Scatter DMA */ #define NFP_NET_CFG_CTRL_GATHER (0x1 << 9) /* Gather DMA */ -#define NFP_NET_CFG_CTRL_LSO (0x1 << 10) /* LSO/TSO */ +#define NFP_NET_CFG_CTRL_LSO (0x1 << 10) /* LSO/TSO (version 1) */ #define NFP_NET_CFG_CTRL_RINGCFG (0x1 << 16) /* Ring runtime changes */ #define NFP_NET_CFG_CTRL_RSS (0x1 << 17) /* RSS */ #define NFP_NET_CFG_CTRL_IRQMOD (0x1 << 18) /* Interrupt moderation */ @@ -131,6 +131,11 @@ #define NFP_NET_CFG_CTRL_VXLAN (0x1 << 24) /* VXLAN tunnel support */ #define NFP_NET_CFG_CTRL_NVGRE (0x1 << 25) /* NVGRE tunnel support */ #define NFP_NET_CFG_CTRL_BPF (0x1 << 27) /* BPF offload capable */ +#define NFP_NET_CFG_CTRL_LSO2 (0x1 << 28) /* LSO/TSO (version 2) */ + +#define NFP_NET_CFG_CTRL_LSO_ANY (NFP_NET_CFG_CTRL_LSO | \ + NFP_NET_CFG_CTRL_LSO2) + #define NFP_NET_CFG_UPDATE 0x0004 #define NFP_NET_CFG_UPDATE_GEN (0x1 << 0) /* General update */ #define NFP_NET_CFG_UPDATE_RING (0x1 << 1) /* Ring config change */ -- cgit v1.2.3 From ad50451e9a3a1a99fa94c4955efd43b79a517747 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 15 May 2017 17:55:18 -0700 Subject: nfp: don't assume RSS and IRQ moderation are always enabled Even if capability for RSS and IRQ moderation are present we may have not initialized them for control vNIC. Depend on selected features mask (ctrl) rather than capabilities (cap) to determine which features should be enabled. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 5e8049a84d16..ae32c0e8d6e6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2201,17 +2201,15 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn) new_ctrl = nn->dp.ctrl; - if (nn->cap & NFP_NET_CFG_CTRL_RSS) { + if (nn->dp.ctrl & NFP_NET_CFG_CTRL_RSS) { nfp_net_rss_write_key(nn); nfp_net_rss_write_itbl(nn); nn_writel(nn, NFP_NET_CFG_RSS_CTRL, nn->rss_cfg); update |= NFP_NET_CFG_UPDATE_RSS; } - if (nn->cap & NFP_NET_CFG_CTRL_IRQMOD) { + if (nn->dp.ctrl & NFP_NET_CFG_CTRL_IRQMOD) { nfp_net_coalesce_write_cfg(nn); - - new_ctrl |= NFP_NET_CFG_CTRL_IRQMOD; update |= NFP_NET_CFG_UPDATE_IRQMOD; } -- cgit v1.2.3 From 611bdd4928b0af3906510bb10fc609de1e48d959 Mon Sep 17 00:00:00 2001 From: Edwin Peer Date: Mon, 15 May 2017 17:55:19 -0700 Subject: nfp: version independent support for chained RSS metadata ABI version 4 introduced metadata chaining. Using the ABI version to signal metadata chaining precludes firmware that advertises new capabilities which rely on prepended metadata from working on older kernels. Capability bits are thus better suited to signalling the chained metadata format. A new version of the RSS capability is introduced to distinguish between the differing metadata formats for ABI versions other than 4. Signed-off-by: Edwin Peer Reviewed-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 20 +++++++++++++------- drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h | 6 +++++- drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 12 ++++++------ 3 files changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index ae32c0e8d6e6..cc5a2eaef156 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2201,7 +2201,7 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn) new_ctrl = nn->dp.ctrl; - if (nn->dp.ctrl & NFP_NET_CFG_CTRL_RSS) { + if (nn->dp.ctrl & NFP_NET_CFG_CTRL_RSS_ANY) { nfp_net_rss_write_key(nn); nfp_net_rss_write_itbl(nn); nn_writel(nn, NFP_NET_CFG_RSS_CTRL, nn->rss_cfg); @@ -3035,7 +3035,7 @@ void nfp_net_info(struct nfp_net *nn) nn->fw_ver.resv, nn->fw_ver.class, nn->fw_ver.major, nn->fw_ver.minor, nn->max_mtu); - nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", nn->cap, nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "", nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "", @@ -3048,7 +3048,8 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_GATHER ? "GATHER " : "", nn->cap & NFP_NET_CFG_CTRL_LSO ? "TSO1 " : "", nn->cap & NFP_NET_CFG_CTRL_LSO2 ? "TSO2 " : "", - nn->cap & NFP_NET_CFG_CTRL_RSS ? "RSS " : "", + nn->cap & NFP_NET_CFG_CTRL_RSS ? "RSS1 " : "", + nn->cap & NFP_NET_CFG_CTRL_RSS2 ? "RSS2 " : "", nn->cap & NFP_NET_CFG_CTRL_L2SWITCH ? "L2SWITCH " : "", nn->cap & NFP_NET_CFG_CTRL_MSIXAUTO ? "AUTOMASK " : "", nn->cap & NFP_NET_CFG_CTRL_IRQMOD ? "IRQMOD " : "", @@ -3202,14 +3203,18 @@ int nfp_net_netdev_init(struct net_device *netdev) struct nfp_net *nn = netdev_priv(netdev); int err; - nn->dp.chained_metadata_format = nn->fw_ver.major > 3; - nn->dp.rx_dma_dir = DMA_FROM_DEVICE; /* Get some of the read-only fields from the BAR */ nn->cap = nn_readl(nn, NFP_NET_CFG_CAP); nn->max_mtu = nn_readl(nn, NFP_NET_CFG_MAX_MTU); + /* Chained metadata is signalled by capabilities except in version 4 */ + nn->dp.chained_metadata_format = nn->fw_ver.major == 4 || + nn->cap & NFP_NET_CFG_CTRL_CHAIN_META; + if (nn->dp.chained_metadata_format && nn->fw_ver.major != 4) + nn->cap &= ~NFP_NET_CFG_CTRL_RSS; + nfp_net_write_mac_addr(nn); /* Determine RX packet/metadata boundary offset */ @@ -3259,10 +3264,11 @@ int nfp_net_netdev_init(struct net_device *netdev) nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_LSO2 ?: NFP_NET_CFG_CTRL_LSO; } - if (nn->cap & NFP_NET_CFG_CTRL_RSS) { + if (nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) { netdev->hw_features |= NETIF_F_RXHASH; nfp_net_rss_init(nn); - nn->dp.ctrl |= NFP_NET_CFG_CTRL_RSS; + nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_RSS2 ?: + NFP_NET_CFG_CTRL_RSS; } if (nn->cap & NFP_NET_CFG_CTRL_VXLAN && nn->cap & NFP_NET_CFG_CTRL_NVGRE) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 1575e8fdb541..a049c5d6839d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -121,7 +121,7 @@ #define NFP_NET_CFG_CTRL_GATHER (0x1 << 9) /* Gather DMA */ #define NFP_NET_CFG_CTRL_LSO (0x1 << 10) /* LSO/TSO (version 1) */ #define NFP_NET_CFG_CTRL_RINGCFG (0x1 << 16) /* Ring runtime changes */ -#define NFP_NET_CFG_CTRL_RSS (0x1 << 17) /* RSS */ +#define NFP_NET_CFG_CTRL_RSS (0x1 << 17) /* RSS (version 1) */ #define NFP_NET_CFG_CTRL_IRQMOD (0x1 << 18) /* Interrupt moderation */ #define NFP_NET_CFG_CTRL_RINGPRIO (0x1 << 19) /* Ring priorities */ #define NFP_NET_CFG_CTRL_MSIXAUTO (0x1 << 20) /* MSI-X auto-masking */ @@ -132,9 +132,13 @@ #define NFP_NET_CFG_CTRL_NVGRE (0x1 << 25) /* NVGRE tunnel support */ #define NFP_NET_CFG_CTRL_BPF (0x1 << 27) /* BPF offload capable */ #define NFP_NET_CFG_CTRL_LSO2 (0x1 << 28) /* LSO/TSO (version 2) */ +#define NFP_NET_CFG_CTRL_RSS2 (0x1 << 29) /* RSS (version 2) */ #define NFP_NET_CFG_CTRL_LSO_ANY (NFP_NET_CFG_CTRL_LSO | \ NFP_NET_CFG_CTRL_LSO2) +#define NFP_NET_CFG_CTRL_RSS_ANY (NFP_NET_CFG_CTRL_RSS | \ + NFP_NET_CFG_CTRL_RSS2) +#define NFP_NET_CFG_CTRL_CHAIN_META NFP_NET_CFG_CTRL_RSS2 #define NFP_NET_CFG_UPDATE 0x0004 #define NFP_NET_CFG_UPDATE_GEN (0x1 << 0) /* General update */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index abbb47e60cc3..70bb0a0152b9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -496,7 +496,7 @@ static int nfp_net_get_rss_hash_opts(struct nfp_net *nn, cmd->data = 0; - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return -EOPNOTSUPP; nfp_rss_flag = ethtool_flow_to_nfp_flag(cmd->flow_type); @@ -533,7 +533,7 @@ static int nfp_net_set_rss_hash_opt(struct nfp_net *nn, u32 nfp_rss_flag; int err; - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return -EOPNOTSUPP; /* RSS only supports IP SA/DA and L4 src/dst ports */ @@ -595,7 +595,7 @@ static u32 nfp_net_get_rxfh_indir_size(struct net_device *netdev) { struct nfp_net *nn = netdev_priv(netdev); - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return 0; return ARRAY_SIZE(nn->rss_itbl); @@ -605,7 +605,7 @@ static u32 nfp_net_get_rxfh_key_size(struct net_device *netdev) { struct nfp_net *nn = netdev_priv(netdev); - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return -EOPNOTSUPP; return nfp_net_rss_key_sz(nn); @@ -617,7 +617,7 @@ static int nfp_net_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, struct nfp_net *nn = netdev_priv(netdev); int i; - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS)) + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY)) return -EOPNOTSUPP; if (indir) @@ -641,7 +641,7 @@ static int nfp_net_set_rxfh(struct net_device *netdev, struct nfp_net *nn = netdev_priv(netdev); int i; - if (!(nn->cap & NFP_NET_CFG_CTRL_RSS) || + if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) || !(hfunc == ETH_RSS_HASH_NO_CHANGE || hfunc == nn->rss_hfunc)) return -EOPNOTSUPP; -- cgit v1.2.3 From ddb98d94e8e7dd9cc1c9dc76d36b5b60c54504c8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 15 May 2017 17:55:20 -0700 Subject: nfp: add CHECKSUM_COMPLETE support Introduce NFP_NET_CFG_CTRL_CSUM_COMPLETE capability and implement parsing of CHECKSUM_COMPLETE metadata. Signed-off-by: Jakub Kicinski Signed-off-by: Edwin Peer Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 4 ++- .../net/ethernet/netronome/nfp/nfp_net_common.c | 35 +++++++++++++++++----- drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h | 7 ++++- 3 files changed, 36 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index c6b7141dc50d..acd9811d08d1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -292,9 +292,11 @@ struct nfp_net_rx_desc { #define NFP_NET_META_FIELD_MASK GENMASK(NFP_NET_META_FIELD_SIZE - 1, 0) struct nfp_meta_parsed { - u32 hash_type; + u8 hash_type; + u8 csum_type; u32 hash; u32 mark; + __wsum csum; }; struct nfp_net_rx_hash { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index cc5a2eaef156..d640b3331741 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1354,17 +1354,28 @@ static int nfp_net_rx_csum_has_errors(u16 flags) * @dp: NFP Net data path struct * @r_vec: per-ring structure * @rxd: Pointer to RX descriptor + * @meta: Parsed metadata prepend * @skb: Pointer to SKB */ static void nfp_net_rx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec, - struct nfp_net_rx_desc *rxd, struct sk_buff *skb) + struct nfp_net_rx_desc *rxd, + struct nfp_meta_parsed *meta, struct sk_buff *skb) { skb_checksum_none_assert(skb); if (!(dp->netdev->features & NETIF_F_RXCSUM)) return; + if (meta->csum_type) { + skb->ip_summed = meta->csum_type; + skb->csum = meta->csum; + u64_stats_update_begin(&r_vec->rx_sync); + r_vec->hw_csum_rx_ok++; + u64_stats_update_end(&r_vec->rx_sync); + return; + } + if (nfp_net_rx_csum_has_errors(le16_to_cpu(rxd->rxd.flags))) { u64_stats_update_begin(&r_vec->rx_sync); r_vec->hw_csum_rx_error++; @@ -1449,6 +1460,12 @@ nfp_net_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, meta->mark = get_unaligned_be32(data); data += 4; break; + case NFP_NET_META_CSUM: + meta->csum_type = CHECKSUM_COMPLETE; + meta->csum = + (__force __wsum)__get_unaligned_cpu32(data); + data += 4; + break; default: return NULL; } @@ -1712,7 +1729,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) skb_record_rx_queue(skb, rx_ring->idx); skb->protocol = eth_type_trans(skb, dp->netdev); - nfp_net_rx_csum(dp, r_vec, rxd, skb); + nfp_net_rx_csum(dp, r_vec, rxd, &meta, skb); if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), @@ -2712,9 +2729,9 @@ static int nfp_net_set_features(struct net_device *netdev, if (changed & NETIF_F_RXCSUM) { if (features & NETIF_F_RXCSUM) - new_ctrl |= NFP_NET_CFG_CTRL_RXCSUM; + new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXCSUM_ANY; else - new_ctrl &= ~NFP_NET_CFG_CTRL_RXCSUM; + new_ctrl &= ~NFP_NET_CFG_CTRL_RXCSUM_ANY; } if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) { @@ -3035,7 +3052,7 @@ void nfp_net_info(struct nfp_net *nn) nn->fw_ver.resv, nn->fw_ver.class, nn->fw_ver.major, nn->fw_ver.minor, nn->max_mtu); - nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", nn->cap, nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "", nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "", @@ -3055,7 +3072,9 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_IRQMOD ? "IRQMOD " : "", nn->cap & NFP_NET_CFG_CTRL_VXLAN ? "VXLAN " : "", nn->cap & NFP_NET_CFG_CTRL_NVGRE ? "NVGRE " : "", - nfp_net_ebpf_capable(nn) ? "BPF " : ""); + nfp_net_ebpf_capable(nn) ? "BPF " : "", + nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ? + "RXCSUM_COMPLETE " : ""); } /** @@ -3246,9 +3265,9 @@ int nfp_net_netdev_init(struct net_device *netdev) * supported. By default we enable most features. */ netdev->hw_features = NETIF_F_HIGHDMA; - if (nn->cap & NFP_NET_CFG_CTRL_RXCSUM) { + if (nn->cap & NFP_NET_CFG_CTRL_RXCSUM_ANY) { netdev->hw_features |= NETIF_F_RXCSUM; - nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXCSUM; + nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXCSUM_ANY; } if (nn->cap & NFP_NET_CFG_CTRL_TXCSUM) { netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index a049c5d6839d..df75b8dc3617 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -71,6 +71,7 @@ #define NFP_NET_META_FIELD_SIZE 4 #define NFP_NET_META_HASH 1 /* next field carries hash type */ #define NFP_NET_META_MARK 2 +#define NFP_NET_META_CSUM 6 /* checksum complete type */ /** * Hash type pre-pended when a RSS hash was computed @@ -133,12 +134,16 @@ #define NFP_NET_CFG_CTRL_BPF (0x1 << 27) /* BPF offload capable */ #define NFP_NET_CFG_CTRL_LSO2 (0x1 << 28) /* LSO/TSO (version 2) */ #define NFP_NET_CFG_CTRL_RSS2 (0x1 << 29) /* RSS (version 2) */ +#define NFP_NET_CFG_CTRL_CSUM_COMPLETE (0x1 << 30) /* Checksum complete */ #define NFP_NET_CFG_CTRL_LSO_ANY (NFP_NET_CFG_CTRL_LSO | \ NFP_NET_CFG_CTRL_LSO2) #define NFP_NET_CFG_CTRL_RSS_ANY (NFP_NET_CFG_CTRL_RSS | \ NFP_NET_CFG_CTRL_RSS2) -#define NFP_NET_CFG_CTRL_CHAIN_META NFP_NET_CFG_CTRL_RSS2 +#define NFP_NET_CFG_CTRL_RXCSUM_ANY (NFP_NET_CFG_CTRL_RXCSUM | \ + NFP_NET_CFG_CTRL_CSUM_COMPLETE) +#define NFP_NET_CFG_CTRL_CHAIN_META (NFP_NET_CFG_CTRL_RSS2 | \ + NFP_NET_CFG_CTRL_CSUM_COMPLETE) #define NFP_NET_CFG_UPDATE 0x0004 #define NFP_NET_CFG_UPDATE_GEN (0x1 << 0) /* General update */ -- cgit v1.2.3 From abeeec4adf6a6fe71a6a4d8199ff0a533d73a57f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 15 May 2017 17:55:21 -0700 Subject: nfp: complete the XDP TX ring only when it's full Since XDP TX ring holds "spare" RX buffers anyway, we don't have to rush the completion. We can wait until ring fills up completely before trying to reclaim buffers. If RX poll has ended an no buffer has been queued for XDP TX we have no guarantee we will see another interrupt, so run the reclaim there as well, to make sure TX statistics won't become stale. This should help us reclaim more buffers per single queue controller register read. Note that the XDP completion is very trivial, it only adds up the sizes of transmitted frames for statistics so the latency spike should be acceptable. In case user sets the ring sizes to something crazy, limit the completion to 2k entries. The check if the ring is empty at the beginning of xdp_complete() is no longer needed - the callers will perform it. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 1 + .../net/ethernet/netronome/nfp/nfp_net_common.c | 52 ++++++++++++++-------- 2 files changed, 35 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index acd9811d08d1..66319a1026bb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -102,6 +102,7 @@ #define NFP_NET_RX_DESCS_DEFAULT 4096 /* Default # of Rx descs per ring */ #define NFP_NET_FL_BATCH 16 /* Add freelist in this Batch size */ +#define NFP_NET_XDP_MAX_COMPLETE 2048 /* XDP bufs to reclaim in NAPI poll */ /* Offload definitions */ #define NFP_NET_N_VXLAN_PORTS (NFP_NET_CFG_VXLAN_SZ / sizeof(__be16)) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index d640b3331741..a4c6878f1df1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1001,27 +1001,30 @@ static void nfp_net_tx_complete(struct nfp_net_tx_ring *tx_ring) tx_ring->rd_p, tx_ring->wr_p, tx_ring->cnt); } -static void nfp_net_xdp_complete(struct nfp_net_tx_ring *tx_ring) +static bool nfp_net_xdp_complete(struct nfp_net_tx_ring *tx_ring) { struct nfp_net_r_vector *r_vec = tx_ring->r_vec; u32 done_pkts = 0, done_bytes = 0; + bool done_all; int idx, todo; u32 qcp_rd_p; - if (tx_ring->wr_p == tx_ring->rd_p) - return; - /* Work out how many descriptors have been transmitted */ qcp_rd_p = nfp_qcp_rd_ptr_read(tx_ring->qcp_q); if (qcp_rd_p == tx_ring->qcp_rd_p) - return; + return true; if (qcp_rd_p > tx_ring->qcp_rd_p) todo = qcp_rd_p - tx_ring->qcp_rd_p; else todo = qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p; + done_all = todo <= NFP_NET_XDP_MAX_COMPLETE; + todo = min(todo, NFP_NET_XDP_MAX_COMPLETE); + + tx_ring->qcp_rd_p = (tx_ring->qcp_rd_p + todo) & (tx_ring->cnt - 1); + done_pkts = todo; while (todo--) { idx = tx_ring->rd_p & (tx_ring->cnt - 1); @@ -1030,16 +1033,16 @@ static void nfp_net_xdp_complete(struct nfp_net_tx_ring *tx_ring) done_bytes += tx_ring->txbufs[idx].real_len; } - tx_ring->qcp_rd_p = qcp_rd_p; - u64_stats_update_begin(&r_vec->tx_sync); r_vec->tx_bytes += done_bytes; r_vec->tx_pkts += done_pkts; u64_stats_update_end(&r_vec->tx_sync); WARN_ONCE(tx_ring->wr_p - tx_ring->rd_p > tx_ring->cnt, - "TX ring corruption rd_p=%u wr_p=%u cnt=%u\n", + "XDP TX ring corruption rd_p=%u wr_p=%u cnt=%u\n", tx_ring->rd_p, tx_ring->wr_p, tx_ring->cnt); + + return done_all; } /** @@ -1500,15 +1503,23 @@ static bool nfp_net_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring, struct nfp_net_tx_ring *tx_ring, struct nfp_net_rx_buf *rxbuf, unsigned int dma_off, - unsigned int pkt_len) + unsigned int pkt_len, bool *completed) { struct nfp_net_tx_buf *txbuf; struct nfp_net_tx_desc *txd; int wr_idx; if (unlikely(nfp_net_tx_full(tx_ring, 1))) { - nfp_net_rx_drop(dp, rx_ring->r_vec, rx_ring, rxbuf, NULL); - return false; + if (!*completed) { + nfp_net_xdp_complete(tx_ring); + *completed = true; + } + + if (unlikely(nfp_net_tx_full(tx_ring, 1))) { + nfp_net_rx_drop(dp, rx_ring->r_vec, rx_ring, rxbuf, + NULL); + return false; + } } wr_idx = tx_ring->wr_p & (tx_ring->cnt - 1); @@ -1580,6 +1591,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) struct nfp_net_dp *dp = &r_vec->nfp_net->dp; struct nfp_net_tx_ring *tx_ring; struct bpf_prog *xdp_prog; + bool xdp_tx_cmpl = false; unsigned int true_bufsz; struct sk_buff *skb; int pkts_polled = 0; @@ -1690,7 +1702,8 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) if (unlikely(!nfp_net_tx_xdp_buf(dp, rx_ring, tx_ring, rxbuf, dma_off, - pkt_len))) + pkt_len, + &xdp_tx_cmpl))) trace_xdp_exception(dp->netdev, xdp_prog, act); continue; @@ -1738,8 +1751,14 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) napi_gro_receive(&rx_ring->r_vec->napi, skb); } - if (xdp_prog && tx_ring->wr_ptr_add) - nfp_net_tx_xmit_more_flush(tx_ring); + if (xdp_prog) { + if (tx_ring->wr_ptr_add) + nfp_net_tx_xmit_more_flush(tx_ring); + else if (unlikely(tx_ring->wr_p != tx_ring->rd_p) && + !xdp_tx_cmpl) + if (!nfp_net_xdp_complete(tx_ring)) + pkts_polled = budget; + } rcu_read_unlock(); return pkts_polled; @@ -1760,11 +1779,8 @@ static int nfp_net_poll(struct napi_struct *napi, int budget) if (r_vec->tx_ring) nfp_net_tx_complete(r_vec->tx_ring); - if (r_vec->rx_ring) { + if (r_vec->rx_ring) pkts_polled = nfp_net_rx(r_vec->rx_ring, budget); - if (r_vec->xdp_ring) - nfp_net_xdp_complete(r_vec->xdp_ring); - } if (pkts_polled < budget) if (napi_complete_done(napi, pkts_polled)) -- cgit v1.2.3 From 4aa3b7660aa79bb030aaa887dc16a60e02fa4348 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 15 May 2017 17:55:22 -0700 Subject: nfp: add a helper for wrapping descriptor index We have a number of places where we calculate the descriptor index based on a value which may have overflown. Create a macro for masking with the ring size. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 3 +++ drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 21 ++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 66319a1026bb..7b9518cbe965 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -117,6 +117,9 @@ struct nfp_eth_table_port; struct nfp_net; struct nfp_net_r_vector; +/* Convenience macro for wrapping descriptor index on ring size */ +#define D_IDX(ring, idx) ((idx) & ((ring)->cnt - 1)) + /* Convenience macro for writing dma address into RX/TX descriptors */ #define nfp_desc_set_dma_addr(desc, dma_addr) \ do { \ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index a4c6878f1df1..c64514f8ee65 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -809,7 +809,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) if (dma_mapping_error(dp->dev, dma_addr)) goto err_free; - wr_idx = tx_ring->wr_p & (tx_ring->cnt - 1); + wr_idx = D_IDX(tx_ring, tx_ring->wr_p); /* Stash the soft descriptor of the head then initialize it */ txbuf = &tx_ring->txbufs[wr_idx]; @@ -852,7 +852,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) if (dma_mapping_error(dp->dev, dma_addr)) goto err_unmap; - wr_idx = (wr_idx + 1) & (tx_ring->cnt - 1); + wr_idx = D_IDX(tx_ring, wr_idx + 1); tx_ring->txbufs[wr_idx].skb = skb; tx_ring->txbufs[wr_idx].dma_addr = dma_addr; tx_ring->txbufs[wr_idx].fidx = f; @@ -946,8 +946,7 @@ static void nfp_net_tx_complete(struct nfp_net_tx_ring *tx_ring) todo = qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p; while (todo--) { - idx = tx_ring->rd_p & (tx_ring->cnt - 1); - tx_ring->rd_p++; + idx = D_IDX(tx_ring, tx_ring->rd_p++); skb = tx_ring->txbufs[idx].skb; if (!skb) @@ -1023,11 +1022,11 @@ static bool nfp_net_xdp_complete(struct nfp_net_tx_ring *tx_ring) done_all = todo <= NFP_NET_XDP_MAX_COMPLETE; todo = min(todo, NFP_NET_XDP_MAX_COMPLETE); - tx_ring->qcp_rd_p = (tx_ring->qcp_rd_p + todo) & (tx_ring->cnt - 1); + tx_ring->qcp_rd_p = D_IDX(tx_ring, tx_ring->qcp_rd_p + todo); done_pkts = todo; while (todo--) { - idx = tx_ring->rd_p & (tx_ring->cnt - 1); + idx = D_IDX(tx_ring, tx_ring->rd_p); tx_ring->rd_p++; done_bytes += tx_ring->txbufs[idx].real_len; @@ -1063,7 +1062,7 @@ nfp_net_tx_ring_reset(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring) struct sk_buff *skb; int idx, nr_frags; - idx = tx_ring->rd_p & (tx_ring->cnt - 1); + idx = D_IDX(tx_ring, tx_ring->rd_p); tx_buf = &tx_ring->txbufs[idx]; skb = tx_ring->txbufs[idx].skb; @@ -1216,7 +1215,7 @@ static void nfp_net_rx_give_one(const struct nfp_net_dp *dp, { unsigned int wr_idx; - wr_idx = rx_ring->wr_p & (rx_ring->cnt - 1); + wr_idx = D_IDX(rx_ring, rx_ring->wr_p); nfp_net_dma_sync_dev_rx(dp, dma_addr); @@ -1254,7 +1253,7 @@ static void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring) unsigned int wr_idx, last_idx; /* Move the empty entry to the end of the list */ - wr_idx = rx_ring->wr_p & (rx_ring->cnt - 1); + wr_idx = D_IDX(rx_ring, rx_ring->wr_p); last_idx = rx_ring->cnt - 1; rx_ring->rxbufs[wr_idx].dma_addr = rx_ring->rxbufs[last_idx].dma_addr; rx_ring->rxbufs[wr_idx].frag = rx_ring->rxbufs[last_idx].frag; @@ -1522,7 +1521,7 @@ nfp_net_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring, } } - wr_idx = tx_ring->wr_p & (tx_ring->cnt - 1); + wr_idx = D_IDX(tx_ring, tx_ring->wr_p); /* Stash the soft descriptor of the head then initialize it */ txbuf = &tx_ring->txbufs[wr_idx]; @@ -1610,7 +1609,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) dma_addr_t new_dma_addr; void *new_frag; - idx = rx_ring->rd_p & (rx_ring->cnt - 1); + idx = D_IDX(rx_ring, rx_ring->rd_p); rxd = &rx_ring->rxds[idx]; if (!(rxd->rxd.meta_len_dd & PCIE_DESC_RX_DD)) -- cgit v1.2.3 From 730b3ab54af4f816cdf541a23c879c9379a480db Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 15 May 2017 17:55:23 -0700 Subject: nfp: eliminate an if statement in calculation of completed frames Given that our rings are always a power of 2, we can simplify the calculation of number of completed TX descriptors by using masking instead of if statement based on whether the index have wrapped or not. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index c64514f8ee65..da83e17b8b20 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -940,10 +940,7 @@ static void nfp_net_tx_complete(struct nfp_net_tx_ring *tx_ring) if (qcp_rd_p == tx_ring->qcp_rd_p) return; - if (qcp_rd_p > tx_ring->qcp_rd_p) - todo = qcp_rd_p - tx_ring->qcp_rd_p; - else - todo = qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p; + todo = D_IDX(tx_ring, qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p); while (todo--) { idx = D_IDX(tx_ring, tx_ring->rd_p++); @@ -1014,10 +1011,7 @@ static bool nfp_net_xdp_complete(struct nfp_net_tx_ring *tx_ring) if (qcp_rd_p == tx_ring->qcp_rd_p) return true; - if (qcp_rd_p > tx_ring->qcp_rd_p) - todo = qcp_rd_p - tx_ring->qcp_rd_p; - else - todo = qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p; + todo = D_IDX(tx_ring, qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p); done_all = todo <= NFP_NET_XDP_MAX_COMPLETE; todo = min(todo, NFP_NET_XDP_MAX_COMPLETE); -- cgit v1.2.3 From 3fdd34c18e93d4a2d7609955d2e6f122e21216e1 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 16 May 2017 15:20:56 +0300 Subject: bnx2x: Remove open coded carrier check There is inline function to test if carrier present, so it makes open-coded solution redundant. Signed-off-by: Leon Romanovsky Acked-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index a851f95c307a..7414ffd70c90 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -10303,7 +10303,7 @@ sp_rtnl_not_reset: } if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN, &bp->sp_rtnl_state)){ - if (!test_bit(__LINK_STATE_NOCARRIER, &bp->dev->state)) { + if (netif_carrier_ok(bp->dev)) { bnx2x_tx_disable(bp); BNX2X_ERR("PF indicated channel is not servicable anymore. This means this VF device is no longer operational\n"); } -- cgit v1.2.3 From 1b86f702f80de32d555519e2c4c61385faeab710 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 16 May 2017 18:29:11 +0200 Subject: net: phy: Remove residual magic from PHY drivers commit fa8cddaf903c ("net phylib: Remove unnecessary condition check in phy") removed the only place where the PHY flag PHY_HAS_MAGICANEG was checked. But it left the flag being set in the drivers. Remove the flag. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 30 +++++++++++++++--------------- drivers/net/phy/micrel.c | 27 +++++++++++++-------------- drivers/net/phy/microchip.c | 2 +- drivers/net/phy/smsc.c | 12 ++++++------ 4 files changed, 35 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index a32dc5d11e89..1e9ad30a35c8 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -540,7 +540,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5411", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -551,7 +551,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5421", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -562,7 +562,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54210E", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -573,7 +573,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5461", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -584,7 +584,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54612E", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -595,7 +595,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54616S", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -606,7 +606,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5464", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -617,7 +617,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5481", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = bcm5481_config_aneg, .read_status = genphy_read_status, @@ -628,7 +628,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54810", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = bcm5481_config_aneg, .read_status = genphy_read_status, @@ -639,7 +639,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5482", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm5482_config_init, .config_aneg = genphy_config_aneg, .read_status = bcm5482_read_status, @@ -650,7 +650,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM50610", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -661,7 +661,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM50610M", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -672,7 +672,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM57780", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -683,7 +683,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCMAC131", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = brcm_fet_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -694,7 +694,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5241", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = brcm_fet_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 6a5fd18f062c..4cfd54182da2 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -779,7 +779,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KS8737", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ks8737_type, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, @@ -793,7 +793,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = 0x00ffffff, .name = "Micrel KSZ8021 or KSZ8031", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8021_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -811,7 +811,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = 0x00ffffff, .name = "Micrel KSZ8031", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8021_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -829,7 +829,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8041", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8041_type, .probe = kszphy_probe, .config_init = ksz8041_config_init, @@ -847,7 +847,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8041RNLI", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8041_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -865,7 +865,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8051", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8051_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -883,7 +883,7 @@ static struct phy_driver ksphy_driver[] = { .name = "Micrel KSZ8001 or KS8721", .phy_id_mask = 0x00fffffc, .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8041_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -901,7 +901,7 @@ static struct phy_driver ksphy_driver[] = { .name = "Micrel KSZ8081 or KSZ8091", .phy_id_mask = MICREL_PHY_ID_MASK, .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz8081_type, .probe = kszphy_probe, .config_init = kszphy_config_init, @@ -919,7 +919,7 @@ static struct phy_driver ksphy_driver[] = { .name = "Micrel KSZ8061", .phy_id_mask = MICREL_PHY_ID_MASK, .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -932,7 +932,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = 0x000ffffe, .name = "Micrel KSZ9021 Gigabit PHY", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz9021_type, .probe = kszphy_probe, .config_init = ksz9021_config_init, @@ -952,7 +952,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ9031 Gigabit PHY", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .driver_data = &ksz9021_type, .probe = kszphy_probe, .config_init = ksz9031_config_init, @@ -969,7 +969,6 @@ static struct phy_driver ksphy_driver[] = { .phy_id = PHY_ID_KSZ8873MLL, .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8873MLL Switch", - .flags = PHY_HAS_MAGICANEG, .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, @@ -980,7 +979,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ886X Switch", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -991,7 +990,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8795", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .flags = PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c index 2b2f543cf9f0..37ee856c7680 100644 --- a/drivers/net/phy/microchip.c +++ b/drivers/net/phy/microchip.c @@ -146,7 +146,7 @@ static struct phy_driver microchip_phy_driver[] = { .name = "Microchip LAN88xx", .features = PHY_GBIT_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = lan88xx_probe, .remove = lan88xx_remove, diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index cef6967b0396..67c9f2b26c8e 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -170,7 +170,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN83C185", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -192,7 +192,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8187", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -214,7 +214,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8700", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -236,7 +236,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN911x Internal PHY", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -257,7 +257,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8710/LAN8720", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, @@ -279,7 +279,7 @@ static struct phy_driver smsc_phy_driver[] = { .name = "SMSC LAN8740", .features = PHY_BASIC_FEATURES, - .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + .flags = PHY_HAS_INTERRUPT, .probe = smsc_phy_probe, -- cgit v1.2.3 From 9ad098037db5a327f60f763dc094fc3d053c07a9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 16 May 2017 16:21:46 +0200 Subject: liquidio: use pcie_flr instead of duplicating it Signed-off-by: Christoph Hellwig Tested-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_vf_main.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 34c77821fad9..d51c8d8d9a35 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -879,8 +879,6 @@ liquidio_vf_probe(struct pci_dev *pdev, */ static void octeon_pci_flr(struct octeon_device *oct) { - u16 status; - pci_save_state(oct->pci_dev); pci_cfg_access_lock(oct->pci_dev); @@ -889,20 +887,7 @@ static void octeon_pci_flr(struct octeon_device *oct) pci_write_config_word(oct->pci_dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); - /* Wait for Transaction Pending bit clean */ - msleep(100); - pcie_capability_read_word(oct->pci_dev, PCI_EXP_DEVSTA, &status); - if (status & PCI_EXP_DEVSTA_TRPND) { - dev_info(&oct->pci_dev->dev, "Function reset incomplete after 100ms, sleeping for 5 seconds\n"); - ssleep(5); - pcie_capability_read_word(oct->pci_dev, PCI_EXP_DEVSTA, - &status); - if (status & PCI_EXP_DEVSTA_TRPND) - dev_info(&oct->pci_dev->dev, "Function reset still incomplete after 5s, reset anyway\n"); - } - pcie_capability_set_word(oct->pci_dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_BCR_FLR); - mdelay(100); + pcie_flr(oct->pci_dev); pci_cfg_access_unlock(oct->pci_dev); -- cgit v1.2.3 From 85eacf3f42e8ba6ecce8c6d7c6c63a2f26cddd7d Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Tue, 16 May 2017 21:17:42 +0530 Subject: cxgb4: reduce resource allocation in kdump kernel When is_kdump_kernel() is true, reduce memory footprint of cxgb4 by using a single "Queue Set". Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 38a5c6764bb5..4249ffbc0427 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -891,7 +891,7 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, * The skb's priority is determined via the VLAN Tag Priority Code * Point field. */ - if (cxgb4_dcb_enabled(dev)) { + if (cxgb4_dcb_enabled(dev) && !is_kdump_kernel()) { u16 vlan_tci; int err; @@ -4007,10 +4007,7 @@ static void cfg_queues(struct adapter *adap) /* Reduce memory usage in kdump environment, disable all offload. */ - if (is_kdump_kernel()) { - adap->params.offload = 0; - adap->params.crypto = 0; - } else if (is_uld(adap) && t4_uld_mem_alloc(adap)) { + if (is_kdump_kernel() || (is_uld(adap) && t4_uld_mem_alloc(adap))) { adap->params.offload = 0; adap->params.crypto = 0; } @@ -4031,7 +4028,7 @@ static void cfg_queues(struct adapter *adap) struct port_info *pi = adap2pinfo(adap, i); pi->first_qset = qidx; - pi->nqsets = 8; + pi->nqsets = is_kdump_kernel() ? 1 : 8; qidx += pi->nqsets; } #else /* !CONFIG_CHELSIO_T4_DCB */ @@ -4044,6 +4041,9 @@ static void cfg_queues(struct adapter *adap) if (q10g > netif_get_num_default_rss_queues()) q10g = netif_get_num_default_rss_queues(); + if (is_kdump_kernel()) + q10g = 1; + for_each_port(adap, i) { struct port_info *pi = adap2pinfo(adap, i); -- cgit v1.2.3 From 29db39841896de99dcb3b1deaed61a13cb9d8036 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Tue, 16 May 2017 21:39:05 +0530 Subject: cxgb4: add new T5 pci device id Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index a323185507ec..9232becc965d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -172,6 +172,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x509e), /* Custom T520-CR */ CH_PCI_ID_TABLE_FENTRY(0x509f), /* Custom T540-CR */ CH_PCI_ID_TABLE_FENTRY(0x50a0), /* Custom T540-CR */ + CH_PCI_ID_TABLE_FENTRY(0x50a1), /* Custom T540-CR */ /* T6 adapters: */ -- cgit v1.2.3 From 33cbd87cc0099b3287cb24dc88b9c9abdedccd1e Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:24 +0200 Subject: mlxsw: spectrum_buffer: Reduce scope of shared buffer struct The shared buffer structure ('mlxsw_sp_sb') doesn't need to be accessible to anyone, but the shared buffer code located at spectrum_buffers.c Make this apparent and reduce its scope by defining it there. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 54 ++-------------- .../net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 73 +++++++++++++++++++--- 2 files changed, 68 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 0c23bc1e946d..976f5b643576 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -110,43 +110,6 @@ static inline bool mlxsw_sp_fid_is_vfid(u16 fid) return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_DUMMY_FID; } -struct mlxsw_sp_sb_pr { - enum mlxsw_reg_sbpr_mode mode; - u32 size; -}; - -struct mlxsw_cp_sb_occ { - u32 cur; - u32 max; -}; - -struct mlxsw_sp_sb_cm { - u32 min_buff; - u32 max_buff; - u8 pool; - struct mlxsw_cp_sb_occ occ; -}; - -struct mlxsw_sp_sb_pm { - u32 min_buff; - u32 max_buff; - struct mlxsw_cp_sb_occ occ; -}; - -#define MLXSW_SP_SB_POOL_COUNT 4 -#define MLXSW_SP_SB_TC_COUNT 8 - -struct mlxsw_sp_sb_port { - struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT]; - struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT]; -}; - -struct mlxsw_sp_sb { - struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT]; - struct mlxsw_sp_sb_port *ports; - u32 cell_size; -}; - #define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE) struct mlxsw_sp_prefix_usage { @@ -231,6 +194,7 @@ struct mlxsw_sp_router { bool aborted; }; +struct mlxsw_sp_sb; struct mlxsw_sp_acl; struct mlxsw_sp_counter_pool; @@ -261,7 +225,7 @@ struct mlxsw_sp { struct mlxsw_sp_upper master_bridge; struct mlxsw_sp_upper *lags; u8 *port_to_module; - struct mlxsw_sp_sb sb; + struct mlxsw_sp_sb *sb; struct mlxsw_sp_router router; struct mlxsw_sp_acl *acl; struct { @@ -282,18 +246,6 @@ mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id) return &mlxsw_sp->lags[lag_id]; } -static inline u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, - u32 cells) -{ - return mlxsw_sp->sb.cell_size * cells; -} - -static inline u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, - u32 bytes) -{ - return DIV_ROUND_UP(bytes, mlxsw_sp->sb.cell_size); -} - struct mlxsw_sp_port_pcpu_stats { u64 rx_packets; u64 rx_bytes; @@ -515,6 +467,8 @@ int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port, unsigned int sb_index, u16 tc_index, enum devlink_sb_pool_type pool_type, u32 *p_cur, u32 *p_max); +u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells); +u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes); int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 997189cfe7fd..93728c694e6d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -43,25 +43,72 @@ #include "port.h" #include "reg.h" +struct mlxsw_sp_sb_pr { + enum mlxsw_reg_sbpr_mode mode; + u32 size; +}; + +struct mlxsw_cp_sb_occ { + u32 cur; + u32 max; +}; + +struct mlxsw_sp_sb_cm { + u32 min_buff; + u32 max_buff; + u8 pool; + struct mlxsw_cp_sb_occ occ; +}; + +struct mlxsw_sp_sb_pm { + u32 min_buff; + u32 max_buff; + struct mlxsw_cp_sb_occ occ; +}; + +#define MLXSW_SP_SB_POOL_COUNT 4 +#define MLXSW_SP_SB_TC_COUNT 8 + +struct mlxsw_sp_sb_port { + struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT]; + struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT]; +}; + +struct mlxsw_sp_sb { + struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT]; + struct mlxsw_sp_sb_port *ports; + u32 cell_size; +}; + +u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells) +{ + return mlxsw_sp->sb->cell_size * cells; +} + +u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes) +{ + return DIV_ROUND_UP(bytes, mlxsw_sp->sb->cell_size); +} + static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp, u8 pool, enum mlxsw_reg_sbxx_dir dir) { - return &mlxsw_sp->sb.prs[dir][pool]; + return &mlxsw_sp->sb->prs[dir][pool]; } static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, u8 pg_buff, enum mlxsw_reg_sbxx_dir dir) { - return &mlxsw_sp->sb.ports[local_port].cms[dir][pg_buff]; + return &mlxsw_sp->sb->ports[local_port].cms[dir][pg_buff]; } static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, u8 pool, enum mlxsw_reg_sbxx_dir dir) { - return &mlxsw_sp->sb.ports[local_port].pms[dir][pool]; + return &mlxsw_sp->sb->ports[local_port].pms[dir][pool]; } static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u8 pool, @@ -215,16 +262,17 @@ static int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp) { unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); - mlxsw_sp->sb.ports = kcalloc(max_ports, sizeof(struct mlxsw_sp_sb_port), - GFP_KERNEL); - if (!mlxsw_sp->sb.ports) + mlxsw_sp->sb->ports = kcalloc(max_ports, + sizeof(struct mlxsw_sp_sb_port), + GFP_KERNEL); + if (!mlxsw_sp->sb->ports) return -ENOMEM; return 0; } static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) { - kfree(mlxsw_sp->sb.ports); + kfree(mlxsw_sp->sb->ports); } #define MLXSW_SP_SB_PR_INGRESS_SIZE 12440000 @@ -551,15 +599,19 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE)) return -EIO; - mlxsw_sp->sb.cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE)) return -EIO; sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE); + mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL); + if (!mlxsw_sp->sb) + return -ENOMEM; + mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); + err = mlxsw_sp_sb_ports_init(mlxsw_sp); if (err) - return err; + goto err_sb_ports_init; err = mlxsw_sp_sb_prs_init(mlxsw_sp); if (err) goto err_sb_prs_init; @@ -584,6 +636,8 @@ err_sb_mms_init: err_sb_cpu_port_sb_cms_init: err_sb_prs_init: mlxsw_sp_sb_ports_fini(mlxsw_sp); +err_sb_ports_init: + kfree(mlxsw_sp->sb); return err; } @@ -591,6 +645,7 @@ void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp) { devlink_sb_unregister(priv_to_devlink(mlxsw_sp->core), 0); mlxsw_sp_sb_ports_fini(mlxsw_sp); + kfree(mlxsw_sp->sb); } int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port) -- cgit v1.2.3 From 9011b677e7564ebd27e0bd8379ddd9d1649106b4 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:25 +0200 Subject: mlxsw: spectrum_router: Reduce scope of router struct In a similar fashion to previous patch, the router structure ('mlxsw_sp_router') doesn't need to be accessible to anyone, but the router code located at spectrum_router.c Make this apparent and reduce its scope by defining it there. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 49 +----- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 195 ++++++++++++++------- 2 files changed, 130 insertions(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 976f5b643576..2eb2230678ae 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -110,33 +110,6 @@ static inline bool mlxsw_sp_fid_is_vfid(u16 fid) return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_DUMMY_FID; } -#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE) - -struct mlxsw_sp_prefix_usage { - DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT); -}; - -enum mlxsw_sp_l3proto { - MLXSW_SP_L3_PROTO_IPV4, - MLXSW_SP_L3_PROTO_IPV6, -}; - -struct mlxsw_sp_lpm_tree { - u8 id; /* tree ID */ - unsigned int ref_count; - enum mlxsw_sp_l3proto proto; - struct mlxsw_sp_prefix_usage prefix_usage; -}; - -struct mlxsw_sp_fib; - -struct mlxsw_sp_vr { - u16 id; /* virtual router ID */ - u32 tb_id; /* kernel fib table id */ - unsigned int rif_count; - struct mlxsw_sp_fib *fib4; -}; - enum mlxsw_sp_span_type { MLXSW_SP_SPAN_EGRESS, MLXSW_SP_SPAN_INGRESS @@ -175,26 +148,8 @@ struct mlxsw_sp_port_mall_tc_entry { }; }; -struct mlxsw_sp_router { - struct mlxsw_sp_vr *vrs; - struct rhashtable neigh_ht; - struct rhashtable nexthop_group_ht; - struct rhashtable nexthop_ht; - struct { - struct mlxsw_sp_lpm_tree *trees; - unsigned int tree_count; - } lpm; - struct { - struct delayed_work dw; - unsigned long interval; /* ms */ - } neighs_update; - struct delayed_work nexthop_probe_dw; -#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ - struct list_head nexthop_neighs_list; - bool aborted; -}; - struct mlxsw_sp_sb; +struct mlxsw_sp_router; struct mlxsw_sp_acl; struct mlxsw_sp_counter_pool; @@ -226,7 +181,7 @@ struct mlxsw_sp { struct mlxsw_sp_upper *lags; u8 *port_to_module; struct mlxsw_sp_sb *sb; - struct mlxsw_sp_router router; + struct mlxsw_sp_router *router; struct mlxsw_sp_acl *acl; struct { DECLARE_BITMAP(usage, MLXSW_SP_KVD_LINEAR_SIZE); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 33cec1cc1642..28f7f54c76f9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -56,6 +56,29 @@ #include "spectrum_dpipe.h" #include "spectrum_router.h" +struct mlxsw_sp_vr; +struct mlxsw_sp_lpm_tree; + +struct mlxsw_sp_router { + struct mlxsw_sp *mlxsw_sp; + struct mlxsw_sp_vr *vrs; + struct rhashtable neigh_ht; + struct rhashtable nexthop_group_ht; + struct rhashtable nexthop_ht; + struct { + struct mlxsw_sp_lpm_tree *trees; + unsigned int tree_count; + } lpm; + struct { + struct delayed_work dw; + unsigned long interval; /* ms */ + } neighs_update; + struct delayed_work nexthop_probe_dw; +#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ + struct list_head nexthop_neighs_list; + bool aborted; +}; + struct mlxsw_sp_rif { struct list_head nexthop_list; struct list_head neigh_list; @@ -220,6 +243,12 @@ static struct mlxsw_sp_rif * mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, const struct net_device *dev); +#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE) + +struct mlxsw_sp_prefix_usage { + DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT); +}; + #define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \ for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT) @@ -284,6 +313,7 @@ enum mlxsw_sp_fib_entry_type { }; struct mlxsw_sp_nexthop_group; +struct mlxsw_sp_fib; struct mlxsw_sp_fib_node { struct list_head entry_list; @@ -310,6 +340,18 @@ struct mlxsw_sp_fib_entry { bool offloaded; }; +enum mlxsw_sp_l3proto { + MLXSW_SP_L3_PROTO_IPV4, + MLXSW_SP_L3_PROTO_IPV6, +}; + +struct mlxsw_sp_lpm_tree { + u8 id; /* tree ID */ + unsigned int ref_count; + enum mlxsw_sp_l3proto proto; + struct mlxsw_sp_prefix_usage prefix_usage; +}; + struct mlxsw_sp_fib { struct rhashtable ht; struct list_head node_list; @@ -320,6 +362,13 @@ struct mlxsw_sp_fib { enum mlxsw_sp_l3proto proto; }; +struct mlxsw_sp_vr { + u16 id; /* virtual router ID */ + u32 tb_id; /* kernel fib table id */ + unsigned int rif_count; + struct mlxsw_sp_fib *fib4; +}; + static const struct rhashtable_params mlxsw_sp_fib_ht_params; static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr, @@ -358,8 +407,8 @@ mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp) static struct mlxsw_sp_lpm_tree *lpm_tree; int i; - for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) { - lpm_tree = &mlxsw_sp->router.lpm.trees[i]; + for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { + lpm_tree = &mlxsw_sp->router->lpm.trees[i]; if (lpm_tree->ref_count == 0) return lpm_tree; } @@ -455,8 +504,8 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lpm_tree *lpm_tree; int i; - for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) { - lpm_tree = &mlxsw_sp->router.lpm.trees[i]; + for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { + lpm_tree = &mlxsw_sp->router->lpm.trees[i]; if (lpm_tree->ref_count != 0 && lpm_tree->proto == proto && mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage, @@ -493,15 +542,15 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp) return -EIO; max_trees = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LPM_TREES); - mlxsw_sp->router.lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN; - mlxsw_sp->router.lpm.trees = kcalloc(mlxsw_sp->router.lpm.tree_count, + mlxsw_sp->router->lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN; + mlxsw_sp->router->lpm.trees = kcalloc(mlxsw_sp->router->lpm.tree_count, sizeof(struct mlxsw_sp_lpm_tree), GFP_KERNEL); - if (!mlxsw_sp->router.lpm.trees) + if (!mlxsw_sp->router->lpm.trees) return -ENOMEM; - for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) { - lpm_tree = &mlxsw_sp->router.lpm.trees[i]; + for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { + lpm_tree = &mlxsw_sp->router->lpm.trees[i]; lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN; } @@ -510,7 +559,7 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp) { - kfree(mlxsw_sp->router.lpm.trees); + kfree(mlxsw_sp->router->lpm.trees); } static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr) @@ -524,7 +573,7 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp) int i; for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { - vr = &mlxsw_sp->router.vrs[i]; + vr = &mlxsw_sp->router->vrs[i]; if (!mlxsw_sp_vr_is_used(vr)) return vr; } @@ -570,7 +619,7 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp, tb_id = mlxsw_sp_fix_tb_id(tb_id); for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { - vr = &mlxsw_sp->router.vrs[i]; + vr = &mlxsw_sp->router->vrs[i]; if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id) return vr; } @@ -677,13 +726,13 @@ static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp) return -EIO; max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); - mlxsw_sp->router.vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr), - GFP_KERNEL); - if (!mlxsw_sp->router.vrs) + mlxsw_sp->router->vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr), + GFP_KERNEL); + if (!mlxsw_sp->router->vrs) return -ENOMEM; for (i = 0; i < max_vrs; i++) { - vr = &mlxsw_sp->router.vrs[i]; + vr = &mlxsw_sp->router->vrs[i]; vr->id = i; } @@ -703,7 +752,7 @@ static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp) */ mlxsw_core_flush_owq(); mlxsw_sp_router_fib_flush(mlxsw_sp); - kfree(mlxsw_sp->router.vrs); + kfree(mlxsw_sp->router->vrs); } struct mlxsw_sp_neigh_key { @@ -755,7 +804,7 @@ static int mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_neigh_entry *neigh_entry) { - return rhashtable_insert_fast(&mlxsw_sp->router.neigh_ht, + return rhashtable_insert_fast(&mlxsw_sp->router->neigh_ht, &neigh_entry->ht_node, mlxsw_sp_neigh_ht_params); } @@ -764,7 +813,7 @@ static void mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_neigh_entry *neigh_entry) { - rhashtable_remove_fast(&mlxsw_sp->router.neigh_ht, + rhashtable_remove_fast(&mlxsw_sp->router->neigh_ht, &neigh_entry->ht_node, mlxsw_sp_neigh_ht_params); } @@ -812,7 +861,7 @@ mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n) struct mlxsw_sp_neigh_key key; key.n = n; - return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht, + return rhashtable_lookup_fast(&mlxsw_sp->router->neigh_ht, &key, mlxsw_sp_neigh_ht_params); } @@ -821,7 +870,7 @@ mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp) { unsigned long interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME); - mlxsw_sp->router.neighs_update.interval = jiffies_to_msecs(interval); + mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval); } static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp, @@ -951,7 +1000,7 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp) /* Take RTNL mutex here to prevent lists from changes */ rtnl_lock(); - list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list, + list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list, nexthop_neighs_list_node) /* If this neigh have nexthops, make the kernel think this neigh * is active regardless of the traffic. @@ -963,33 +1012,35 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp *mlxsw_sp) { - unsigned long interval = mlxsw_sp->router.neighs_update.interval; + unsigned long interval = mlxsw_sp->router->neighs_update.interval; - mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw, + mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, msecs_to_jiffies(interval)); } static void mlxsw_sp_router_neighs_update_work(struct work_struct *work) { - struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp, - router.neighs_update.dw.work); + struct mlxsw_sp_router *router; int err; - err = mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp); + router = container_of(work, struct mlxsw_sp_router, + neighs_update.dw.work); + err = mlxsw_sp_router_neighs_update_rauhtd(router->mlxsw_sp); if (err) - dev_err(mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity"); + dev_err(router->mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity"); - mlxsw_sp_router_neighs_update_nh(mlxsw_sp); + mlxsw_sp_router_neighs_update_nh(router->mlxsw_sp); - mlxsw_sp_router_neighs_update_work_schedule(mlxsw_sp); + mlxsw_sp_router_neighs_update_work_schedule(router->mlxsw_sp); } static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work) { struct mlxsw_sp_neigh_entry *neigh_entry; - struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp, - router.nexthop_probe_dw.work); + struct mlxsw_sp_router *router; + router = container_of(work, struct mlxsw_sp_router, + nexthop_probe_dw.work); /* Iterate over nexthop neighbours, find those who are unresolved and * send arp on them. This solves the chicken-egg problem when * the nexthop wouldn't get offloaded until the neighbor is resolved @@ -999,13 +1050,13 @@ static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work) * Take RTNL mutex here to prevent lists from changes. */ rtnl_lock(); - list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list, + list_for_each_entry(neigh_entry, &router->nexthop_neighs_list, nexthop_neighs_list_node) if (!neigh_entry->connected) neigh_event_send(neigh_entry->key.n, NULL); rtnl_unlock(); - mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw, + mlxsw_core_schedule_dw(&router->nexthop_probe_dw, MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL); } @@ -1127,7 +1178,7 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused, mlxsw_sp = mlxsw_sp_port->mlxsw_sp; interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME)); - mlxsw_sp->router.neighs_update.interval = interval; + mlxsw_sp->router->neighs_update.interval = interval; mlxsw_sp_port_dev_put(mlxsw_sp_port); break; @@ -1168,7 +1219,7 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp) { int err; - err = rhashtable_init(&mlxsw_sp->router.neigh_ht, + err = rhashtable_init(&mlxsw_sp->router->neigh_ht, &mlxsw_sp_neigh_ht_params); if (err) return err; @@ -1179,20 +1230,20 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp) mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp); /* Create the delayed works for the activity_update */ - INIT_DELAYED_WORK(&mlxsw_sp->router.neighs_update.dw, + INIT_DELAYED_WORK(&mlxsw_sp->router->neighs_update.dw, mlxsw_sp_router_neighs_update_work); - INIT_DELAYED_WORK(&mlxsw_sp->router.nexthop_probe_dw, + INIT_DELAYED_WORK(&mlxsw_sp->router->nexthop_probe_dw, mlxsw_sp_router_probe_unresolved_nexthops); - mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw, 0); - mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw, 0); + mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, 0); + mlxsw_core_schedule_dw(&mlxsw_sp->router->nexthop_probe_dw, 0); return 0; } static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp) { - cancel_delayed_work_sync(&mlxsw_sp->router.neighs_update.dw); - cancel_delayed_work_sync(&mlxsw_sp->router.nexthop_probe_dw); - rhashtable_destroy(&mlxsw_sp->router.neigh_ht); + cancel_delayed_work_sync(&mlxsw_sp->router->neighs_update.dw); + cancel_delayed_work_sync(&mlxsw_sp->router->nexthop_probe_dw); + rhashtable_destroy(&mlxsw_sp->router->neigh_ht); } static int mlxsw_sp_neigh_rif_flush(struct mlxsw_sp *mlxsw_sp, @@ -1267,7 +1318,7 @@ static const struct rhashtable_params mlxsw_sp_nexthop_group_ht_params = { static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop_group *nh_grp) { - return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_group_ht, + return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_group_ht, &nh_grp->ht_node, mlxsw_sp_nexthop_group_ht_params); } @@ -1275,7 +1326,7 @@ static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop_group *nh_grp) { - rhashtable_remove_fast(&mlxsw_sp->router.nexthop_group_ht, + rhashtable_remove_fast(&mlxsw_sp->router->nexthop_group_ht, &nh_grp->ht_node, mlxsw_sp_nexthop_group_ht_params); } @@ -1284,7 +1335,7 @@ static struct mlxsw_sp_nexthop_group * mlxsw_sp_nexthop_group_lookup(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop_group_key key) { - return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_group_ht, &key, + return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht, &key, mlxsw_sp_nexthop_group_ht_params); } @@ -1297,14 +1348,14 @@ static const struct rhashtable_params mlxsw_sp_nexthop_ht_params = { static int mlxsw_sp_nexthop_insert(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh) { - return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_ht, + return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node, mlxsw_sp_nexthop_ht_params); } static void mlxsw_sp_nexthop_remove(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh) { - rhashtable_remove_fast(&mlxsw_sp->router.nexthop_ht, &nh->ht_node, + rhashtable_remove_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node, mlxsw_sp_nexthop_ht_params); } @@ -1312,7 +1363,7 @@ static struct mlxsw_sp_nexthop * mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop_key key) { - return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_ht, &key, + return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_ht, &key, mlxsw_sp_nexthop_ht_params); } @@ -1599,7 +1650,7 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp, */ if (list_empty(&neigh_entry->nexthop_list)) list_add_tail(&neigh_entry->nexthop_neighs_list_node, - &mlxsw_sp->router.nexthop_neighs_list); + &mlxsw_sp->router->nexthop_neighs_list); nh->neigh_entry = neigh_entry; list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list); @@ -1697,7 +1748,7 @@ static void mlxsw_sp_nexthop_event(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh; struct mlxsw_sp_rif *rif; - if (mlxsw_sp->router.aborted) + if (mlxsw_sp->router->aborted) return; key.fib_nh = fib_nh; @@ -2510,7 +2561,7 @@ mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_node *fib_node; int err; - if (mlxsw_sp->router.aborted) + if (mlxsw_sp->router->aborted) return 0; fib_node = mlxsw_sp_fib4_node_get(mlxsw_sp, fen_info); @@ -2550,7 +2601,7 @@ static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry *fib_entry; struct mlxsw_sp_fib_node *fib_node; - if (mlxsw_sp->router.aborted) + if (mlxsw_sp->router->aborted) return; fib_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info); @@ -2581,7 +2632,7 @@ static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp) return err; for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { - struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i]; + struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i]; char raltb_pl[MLXSW_REG_RALTB_LEN]; char ralue_pl[MLXSW_REG_RALUE_LEN]; @@ -2663,7 +2714,7 @@ static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp) int i; for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { - struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i]; + struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i]; if (!mlxsw_sp_vr_is_used(vr)) continue; @@ -2675,11 +2726,11 @@ static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp) { int err; - if (mlxsw_sp->router.aborted) + if (mlxsw_sp->router->aborted) return; dev_warn(mlxsw_sp->bus_info->dev, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n"); mlxsw_sp_router_fib_flush(mlxsw_sp); - mlxsw_sp->router.aborted = true; + mlxsw_sp->router->aborted = true; err = mlxsw_sp_router_set_abort_trap(mlxsw_sp); if (err) dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n"); @@ -3015,7 +3066,7 @@ static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport, struct mlxsw_sp_rif *rif) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; - struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id]; + struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; struct net_device *l3_dev = rif->dev; struct mlxsw_sp_fid *f = rif->f; u16 rif_index = rif->rif_index; @@ -3273,7 +3324,7 @@ err_port_flood_set: void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif) { - struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id]; + struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; struct net_device *l3_dev = rif->dev; struct mlxsw_sp_fid *f = rif->f; u16 rif_index = rif->rif_index; @@ -3545,19 +3596,26 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) { + struct mlxsw_sp_router *router; int err; - INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list); + router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL); + if (!router) + return -ENOMEM; + mlxsw_sp->router = router; + router->mlxsw_sp = mlxsw_sp; + + INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list); err = __mlxsw_sp_router_init(mlxsw_sp); if (err) - return err; + goto err_router_init; - err = rhashtable_init(&mlxsw_sp->router.nexthop_ht, + err = rhashtable_init(&mlxsw_sp->router->nexthop_ht, &mlxsw_sp_nexthop_ht_params); if (err) goto err_nexthop_ht_init; - err = rhashtable_init(&mlxsw_sp->router.nexthop_group_ht, + err = rhashtable_init(&mlxsw_sp->router->nexthop_group_ht, &mlxsw_sp_nexthop_group_ht_params); if (err) goto err_nexthop_group_ht_init; @@ -3589,11 +3647,13 @@ err_neigh_init: err_vrs_init: mlxsw_sp_lpm_fini(mlxsw_sp); err_lpm_init: - rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht); + rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht); err_nexthop_group_ht_init: - rhashtable_destroy(&mlxsw_sp->router.nexthop_ht); + rhashtable_destroy(&mlxsw_sp->router->nexthop_ht); err_nexthop_ht_init: __mlxsw_sp_router_fini(mlxsw_sp); +err_router_init: + kfree(mlxsw_sp->router); return err; } @@ -3603,7 +3663,8 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp); mlxsw_sp_lpm_fini(mlxsw_sp); - rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht); - rhashtable_destroy(&mlxsw_sp->router.nexthop_ht); + rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht); + rhashtable_destroy(&mlxsw_sp->router->nexthop_ht); __mlxsw_sp_router_fini(mlxsw_sp); + kfree(mlxsw_sp->router); } -- cgit v1.2.3 From 5f6935c6a4eafd853489c70d6ef3250296a4d534 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:26 +0200 Subject: mlxsw: spectrum_switchdev: Reduce scope of bridge struct Some attributes in the global chip struct are only relevant for bridge operation, so encapsulate them in their own struct that isn't exposed to non-bridge code. This will also help us later, when we add more bridge-specific attributes. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 20 ++++--- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 17 +----- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 4 +- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 65 +++++++++++++++++----- 4 files changed, 69 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 88357cee7679..166be1854111 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3312,7 +3312,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->bus_info = mlxsw_bus_info; INIT_LIST_HEAD(&mlxsw_sp->fids); INIT_LIST_HEAD(&mlxsw_sp->vfids.list); - INIT_LIST_HEAD(&mlxsw_sp->br_mids.list); err = mlxsw_sp_base_mac_get(mlxsw_sp); if (err) { @@ -3659,21 +3658,26 @@ static void mlxsw_sp_master_bridge_gone_sync(struct mlxsw_sp *mlxsw_sp) static bool mlxsw_sp_master_bridge_check(struct mlxsw_sp *mlxsw_sp, struct net_device *br_dev) { - return !mlxsw_sp->master_bridge.dev || - mlxsw_sp->master_bridge.dev == br_dev; + struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp); + + return !master_bridge->dev || master_bridge->dev == br_dev; } static void mlxsw_sp_master_bridge_inc(struct mlxsw_sp *mlxsw_sp, struct net_device *br_dev) { - mlxsw_sp->master_bridge.dev = br_dev; - mlxsw_sp->master_bridge.ref_count++; + struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp); + + master_bridge->dev = br_dev; + master_bridge->ref_count++; } static void mlxsw_sp_master_bridge_dec(struct mlxsw_sp *mlxsw_sp) { - if (--mlxsw_sp->master_bridge.ref_count == 0) { - mlxsw_sp->master_bridge.dev = NULL; + struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp); + + if (--master_bridge->ref_count == 0) { + master_bridge->dev = NULL; /* It's possible upper VLAN devices are still holding * references to underlying FIDs. Drop the reference * and release the resources if it was the last one. @@ -4272,7 +4276,7 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev, if (!is_vlan_dev(upper_dev)) return -EINVAL; if (is_vlan_dev(upper_dev) && - br_dev != mlxsw_sp->master_bridge.dev) + br_dev != mlxsw_sp_master_bridge(mlxsw_sp)->dev) return -EINVAL; break; case NETDEV_CHANGEUPPER: diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 2eb2230678ae..7c9e2f191b2e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -149,6 +149,7 @@ struct mlxsw_sp_port_mall_tc_entry { }; struct mlxsw_sp_sb; +struct mlxsw_sp_bridge; struct mlxsw_sp_router; struct mlxsw_sp_acl; struct mlxsw_sp_counter_pool; @@ -158,29 +159,16 @@ struct mlxsw_sp { struct list_head list; DECLARE_BITMAP(mapped, MLXSW_SP_VFID_MAX); } vfids; - struct { - struct list_head list; - DECLARE_BITMAP(mapped, MLXSW_SP_MID_MAX); - } br_mids; struct list_head fids; /* VLAN-aware bridge FIDs */ struct mlxsw_sp_rif **rifs; struct mlxsw_sp_port **ports; struct mlxsw_core *core; const struct mlxsw_bus_info *bus_info; unsigned char base_mac[ETH_ALEN]; - struct { - struct delayed_work dw; -#define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100 - unsigned int interval; /* ms */ - } fdb_notify; -#define MLXSW_SP_MIN_AGEING_TIME 10 -#define MLXSW_SP_MAX_AGEING_TIME 1000000 -#define MLXSW_SP_DEFAULT_AGEING_TIME 300 - u32 ageing_time; - struct mlxsw_sp_upper master_bridge; struct mlxsw_sp_upper *lags; u8 *port_to_module; struct mlxsw_sp_sb *sb; + struct mlxsw_sp_bridge *bridge; struct mlxsw_sp_router *router; struct mlxsw_sp_acl *acl; struct { @@ -425,6 +413,7 @@ int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port, u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells); u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes); +struct mlxsw_sp_upper *mlxsw_sp_master_bridge(const struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_port_vlan_init(struct mlxsw_sp_port *mlxsw_sp_port); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 28f7f54c76f9..434e091d340b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3193,7 +3193,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, if (is_vlan_dev(l3_dev)) fid = vlan_dev_vlan_id(l3_dev); - else if (mlxsw_sp->master_bridge.dev == l3_dev) + else if (mlxsw_sp_master_bridge(mlxsw_sp)->dev == l3_dev) fid = 1; else return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev); @@ -3389,7 +3389,7 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev, return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event, vid); else if (netif_is_bridge_master(real_dev) && - mlxsw_sp->master_bridge.dev == real_dev) + mlxsw_sp_master_bridge(mlxsw_sp)->dev == real_dev) return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev, event); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 0d8411f1f954..85790d38d2f0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -52,6 +52,27 @@ #include "core.h" #include "reg.h" +struct mlxsw_sp_bridge { + struct mlxsw_sp *mlxsw_sp; + struct { + struct delayed_work dw; +#define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100 + unsigned int interval; /* ms */ + } fdb_notify; +#define MLXSW_SP_MIN_AGEING_TIME 10 +#define MLXSW_SP_MAX_AGEING_TIME 1000000 +#define MLXSW_SP_DEFAULT_AGEING_TIME 300 + u32 ageing_time; + struct mlxsw_sp_upper master_bridge; + struct list_head mids_list; + DECLARE_BITMAP(mids_bitmap, MLXSW_SP_MID_MAX); +}; + +struct mlxsw_sp_upper *mlxsw_sp_master_bridge(const struct mlxsw_sp *mlxsw_sp) +{ + return &mlxsw_sp->bridge->master_bridge; +} + static u16 mlxsw_sp_port_vid_to_fid_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) { @@ -397,7 +418,7 @@ static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time) err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdat), sfdat_pl); if (err) return err; - mlxsw_sp->ageing_time = ageing_time; + mlxsw_sp->bridge->ageing_time = ageing_time; return 0; } @@ -428,7 +449,8 @@ static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; /* SWITCHDEV_TRANS_PREPARE phase */ - if ((!vlan_enabled) && (mlxsw_sp->master_bridge.dev == orig_dev)) { + if ((!vlan_enabled) && + (mlxsw_sp->bridge->master_bridge.dev == orig_dev)) { netdev_err(mlxsw_sp_port->dev, "Bridge must be vlan-aware\n"); return -EINVAL; } @@ -1006,7 +1028,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_mid *mid; - list_for_each_entry(mid, &mlxsw_sp->br_mids.list, list) { + list_for_each_entry(mid, &mlxsw_sp->bridge->mids_list, list) { if (ether_addr_equal(mid->addr, addr) && mid->fid == fid) return mid; } @@ -1020,7 +1042,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_mid *mid; u16 mid_idx; - mid_idx = find_first_zero_bit(mlxsw_sp->br_mids.mapped, + mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap, MLXSW_SP_MID_MAX); if (mid_idx == MLXSW_SP_MID_MAX) return NULL; @@ -1029,12 +1051,12 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp, if (!mid) return NULL; - set_bit(mid_idx, mlxsw_sp->br_mids.mapped); + set_bit(mid_idx, mlxsw_sp->bridge->mids_bitmap); ether_addr_copy(mid->addr, addr); mid->fid = fid; mid->mid = mid_idx; mid->ref_count = 0; - list_add_tail(&mid->list, &mlxsw_sp->br_mids.list); + list_add_tail(&mid->list, &mlxsw_sp->bridge->mids_list); return mid; } @@ -1044,7 +1066,7 @@ static int __mlxsw_sp_mc_dec_ref(struct mlxsw_sp *mlxsw_sp, { if (--mid->ref_count == 0) { list_del(&mid->list); - clear_bit(mid->mid, mlxsw_sp->br_mids.mapped); + clear_bit(mid->mid, mlxsw_sp->bridge->mids_bitmap); kfree(mid); return 1; } @@ -1600,12 +1622,15 @@ static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp) { - mlxsw_core_schedule_dw(&mlxsw_sp->fdb_notify.dw, - msecs_to_jiffies(mlxsw_sp->fdb_notify.interval)); + struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge; + + mlxsw_core_schedule_dw(&bridge->fdb_notify.dw, + msecs_to_jiffies(bridge->fdb_notify.interval)); } static void mlxsw_sp_fdb_notify_work(struct work_struct *work) { + struct mlxsw_sp_bridge *bridge; struct mlxsw_sp *mlxsw_sp; char *sfn_pl; u8 num_rec; @@ -1616,7 +1641,8 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work) if (!sfn_pl) return; - mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work); + bridge = container_of(work, struct mlxsw_sp_bridge, fdb_notify.dw.work); + mlxsw_sp = bridge->mlxsw_sp; rtnl_lock(); mlxsw_reg_sfn_pack(sfn_pl); @@ -1637,6 +1663,7 @@ out: static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) { + struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge; int err; err = mlxsw_sp_ageing_set(mlxsw_sp, MLXSW_SP_DEFAULT_AGEING_TIME); @@ -1644,25 +1671,37 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n"); return err; } - INIT_DELAYED_WORK(&mlxsw_sp->fdb_notify.dw, mlxsw_sp_fdb_notify_work); - mlxsw_sp->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL; + INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work); + bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL; mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); return 0; } static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp) { - cancel_delayed_work_sync(&mlxsw_sp->fdb_notify.dw); + cancel_delayed_work_sync(&mlxsw_sp->bridge->fdb_notify.dw); } int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp) { + struct mlxsw_sp_bridge *bridge; + + bridge = kzalloc(sizeof(*mlxsw_sp->bridge), GFP_KERNEL); + if (!bridge) + return -ENOMEM; + mlxsw_sp->bridge = bridge; + bridge->mlxsw_sp = mlxsw_sp; + + INIT_LIST_HEAD(&mlxsw_sp->bridge->mids_list); + return mlxsw_sp_fdb_init(mlxsw_sp); } void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp) { mlxsw_sp_fdb_fini(mlxsw_sp); + WARN_ON(!list_empty(&mlxsw_sp->bridge->mids_list)); + kfree(mlxsw_sp->bridge); } void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port) -- cgit v1.2.3 From 5f9efffbdb1722631714d7afce793379abd94c1f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:27 +0200 Subject: mlxsw: spectrum_router: Move RIFs array to its rightful place The router interfaces (RIFs) array is of no interest to code outside the routing realm, so declare it inside the router specific struct instead of the chip-wide one. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 - .../net/ethernet/mellanox/mlxsw/spectrum_dpipe.c | 17 +++++----- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 39 +++++++++++++--------- .../net/ethernet/mellanox/mlxsw/spectrum_router.h | 2 ++ 4 files changed, 35 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 7c9e2f191b2e..babaf1f5fa87 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -160,7 +160,6 @@ struct mlxsw_sp { DECLARE_BITMAP(mapped, MLXSW_SP_VFID_MAX); } vfids; struct list_head fids; /* VLAN-aware bridge FIDs */ - struct mlxsw_sp_rif **rifs; struct mlxsw_sp_port **ports; struct mlxsw_core *core; const struct mlxsw_bus_info *bus_info; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c index ea56f6ade6b4..ce2534df03ca 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c @@ -241,10 +241,11 @@ start_again: return err; j = 0; for (; i < rif_count; i++) { - if (!mlxsw_sp->rifs[i]) + struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); + + if (!rif) continue; - err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, - mlxsw_sp->rifs[i], + err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif, counters_enabled); if (err) goto err_entry_get; @@ -281,15 +282,15 @@ static int mlxsw_sp_table_erif_counters_update(void *priv, bool enable) rtnl_lock(); for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { - if (!mlxsw_sp->rifs[i]) + struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); + + if (!rif) continue; if (enable) - mlxsw_sp_rif_counter_alloc(mlxsw_sp, - mlxsw_sp->rifs[i], + mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); else - mlxsw_sp_rif_counter_free(mlxsw_sp, - mlxsw_sp->rifs[i], + mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); } rtnl_unlock(); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 434e091d340b..7b44389e5769 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -61,6 +61,7 @@ struct mlxsw_sp_lpm_tree; struct mlxsw_sp_router { struct mlxsw_sp *mlxsw_sp; + struct mlxsw_sp_rif **rifs; struct mlxsw_sp_vr *vrs; struct rhashtable neigh_ht; struct rhashtable nexthop_group_ht; @@ -885,13 +886,13 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp, mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip); - if (!mlxsw_sp->rifs[rif]) { + if (!mlxsw_sp->router->rifs[rif]) { dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n"); return; } dipn = htonl(dip); - dev = mlxsw_sp->rifs[rif]->dev; + dev = mlxsw_sp->router->rifs[rif]->dev; n = neigh_lookup(&arp_tbl, &dipn, dev); if (!n) { netdev_err(dev, "Failed to find matching neighbour for IP=%pI4h\n", @@ -2846,8 +2847,9 @@ mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, int i; for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) - if (mlxsw_sp->rifs[i] && mlxsw_sp->rifs[i]->dev == dev) - return mlxsw_sp->rifs[i]; + if (mlxsw_sp->router->rifs[i] && + mlxsw_sp->router->rifs[i]->dev == dev) + return mlxsw_sp->router->rifs[i]; return NULL; } @@ -2903,7 +2905,7 @@ static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp) int i; for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) - if (!mlxsw_sp->rifs[i]) + if (!mlxsw_sp->router->rifs[i]) return i; return MLXSW_SP_INVALID_INDEX_RIF; @@ -2983,6 +2985,12 @@ mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, return rif; } +struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp, + u16 rif_index) +{ + return mlxsw_sp->router->rifs[rif_index]; +} + u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif) { return rif->rif_index; @@ -3045,7 +3053,7 @@ mlxsw_sp_vport_rif_sp_create(struct mlxsw_sp_port *mlxsw_sp_vport, } f->rif = rif; - mlxsw_sp->rifs[rif_index] = rif; + mlxsw_sp->router->rifs[rif_index] = rif; vr->rif_count++; return rif; @@ -3078,7 +3086,7 @@ static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport, mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_INGRESS); vr->rif_count--; - mlxsw_sp->rifs[rif_index] = NULL; + mlxsw_sp->router->rifs[rif_index] = NULL; f->rif = NULL; kfree(rif); @@ -3302,7 +3310,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, } f->rif = rif; - mlxsw_sp->rifs[rif_index] = rif; + mlxsw_sp->router->rifs[rif_index] = rif; vr->rif_count++; netdev_dbg(l3_dev, "RIF=%d created\n", rif_index); @@ -3332,7 +3340,7 @@ void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); vr->rif_count--; - mlxsw_sp->rifs[rif_index] = NULL; + mlxsw_sp->router->rifs[rif_index] = NULL; f->rif = NULL; kfree(rif); @@ -3562,9 +3570,10 @@ static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) return -EIO; max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); - mlxsw_sp->rifs = kcalloc(max_rifs, sizeof(struct mlxsw_sp_rif *), - GFP_KERNEL); - if (!mlxsw_sp->rifs) + mlxsw_sp->router->rifs = kcalloc(max_rifs, + sizeof(struct mlxsw_sp_rif *), + GFP_KERNEL); + if (!mlxsw_sp->router->rifs) return -ENOMEM; mlxsw_reg_rgcr_pack(rgcr_pl, true); @@ -3576,7 +3585,7 @@ static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) return 0; err_rgcr_fail: - kfree(mlxsw_sp->rifs); + kfree(mlxsw_sp->router->rifs); return err; } @@ -3589,9 +3598,9 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) - WARN_ON_ONCE(mlxsw_sp->rifs[i]); + WARN_ON_ONCE(mlxsw_sp->router->rifs[i]); - kfree(mlxsw_sp->rifs); + kfree(mlxsw_sp->router->rifs); } int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index c3095fef6697..a3e8d2b25148 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -42,6 +42,8 @@ enum mlxsw_sp_rif_counter_dir { MLXSW_SP_RIF_COUNTER_EGRESS, }; +struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp, + u16 rif_index); u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif); int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif); int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp, -- cgit v1.2.3 From 7e39d1153de244fbdc57623a482f810bcf73a03f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:28 +0200 Subject: mlxsw: spectrum_router: Move FIB notification block to router struct The FIB notification block logically belongs inside the router specific struct, so move it there. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 - drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 17 ++++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index babaf1f5fa87..29db77f8bb6f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -179,7 +179,6 @@ struct mlxsw_sp { struct mlxsw_sp_span_entry *entries; int entries_count; } span; - struct notifier_block fib_nb; }; static inline struct mlxsw_sp_upper * diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 7b44389e5769..df4051f5a442 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -78,6 +78,7 @@ struct mlxsw_sp_router { #define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */ struct list_head nexthop_neighs_list; bool aborted; + struct notifier_block fib_nb; }; struct mlxsw_sp_rif { @@ -2797,9 +2798,9 @@ static void mlxsw_sp_router_fib_event_work(struct work_struct *work) static int mlxsw_sp_router_fib_event(struct notifier_block *nb, unsigned long event, void *ptr) { - struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb); struct mlxsw_sp_fib_event_work *fib_work; struct fib_notifier_info *info = ptr; + struct mlxsw_sp_router *router; if (!net_eq(info->net, &init_net)) return NOTIFY_DONE; @@ -2809,7 +2810,8 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, return NOTIFY_BAD; INIT_WORK(&fib_work->work, mlxsw_sp_router_fib_event_work); - fib_work->mlxsw_sp = mlxsw_sp; + router = container_of(nb, struct mlxsw_sp_router, fib_nb); + fib_work->mlxsw_sp = router->mlxsw_sp; fib_work->event = event; switch (event) { @@ -3550,14 +3552,15 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb) { - struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb); + struct mlxsw_sp_router *router; /* Flush pending FIB notifications and then flush the device's * table before requesting another dump. The FIB notification * block is unregistered, so no need to take RTNL. */ mlxsw_core_flush_owq(); - mlxsw_sp_router_fib_flush(mlxsw_sp); + router = container_of(nb, struct mlxsw_sp_router, fib_nb); + mlxsw_sp_router_fib_flush(router->mlxsw_sp); } static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) @@ -3641,8 +3644,8 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_neigh_init; - mlxsw_sp->fib_nb.notifier_call = mlxsw_sp_router_fib_event; - err = register_fib_notifier(&mlxsw_sp->fib_nb, + mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; + err = register_fib_notifier(&mlxsw_sp->router->fib_nb, mlxsw_sp_router_fib_dump_flush); if (err) goto err_register_fib_notifier; @@ -3668,7 +3671,7 @@ err_router_init: void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) { - unregister_fib_notifier(&mlxsw_sp->fib_nb); + unregister_fib_notifier(&mlxsw_sp->router->fib_nb); mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp); mlxsw_sp_lpm_fini(mlxsw_sp); -- cgit v1.2.3 From 348b8fc3cf3059ac151c693dac992947a3daa437 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:29 +0200 Subject: mlxsw: spectrum_router: Initialize RIFs in a separate function The router interfaces (RIFs) array is currently initialized together with the general router configuration. However, in a follow-up patchset we're going to introduce a common RIF core that will require us to initialize more RIF constructs, so move the RIF initialization to its own function. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 48 ++++++++++++++-------- 1 file changed, 30 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index df4051f5a442..aba33268af97 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3550,6 +3550,28 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, return err; } +static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp) +{ + u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); + + mlxsw_sp->router->rifs = kcalloc(max_rifs, + sizeof(struct mlxsw_sp_rif *), + GFP_KERNEL); + if (!mlxsw_sp->router->rifs) + return -ENOMEM; + return 0; +} + +static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp) +{ + int i; + + for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) + WARN_ON_ONCE(mlxsw_sp->router->rifs[i]); + + kfree(mlxsw_sp->router->rifs); +} + static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb) { struct mlxsw_sp_router *router; @@ -3571,39 +3593,22 @@ static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS)) return -EIO; - max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); - mlxsw_sp->router->rifs = kcalloc(max_rifs, - sizeof(struct mlxsw_sp_rif *), - GFP_KERNEL); - if (!mlxsw_sp->router->rifs) - return -ENOMEM; mlxsw_reg_rgcr_pack(rgcr_pl, true); mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); if (err) - goto err_rgcr_fail; - + return err; return 0; - -err_rgcr_fail: - kfree(mlxsw_sp->router->rifs); - return err; } static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) { char rgcr_pl[MLXSW_REG_RGCR_LEN]; - int i; mlxsw_reg_rgcr_pack(rgcr_pl, false); mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); - - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) - WARN_ON_ONCE(mlxsw_sp->router->rifs[i]); - - kfree(mlxsw_sp->router->rifs); } int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) @@ -3622,6 +3627,10 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_router_init; + err = mlxsw_sp_rifs_init(mlxsw_sp); + if (err) + goto err_rifs_init; + err = rhashtable_init(&mlxsw_sp->router->nexthop_ht, &mlxsw_sp_nexthop_ht_params); if (err) @@ -3663,6 +3672,8 @@ err_lpm_init: err_nexthop_group_ht_init: rhashtable_destroy(&mlxsw_sp->router->nexthop_ht); err_nexthop_ht_init: + mlxsw_sp_rifs_fini(mlxsw_sp); +err_rifs_init: __mlxsw_sp_router_fini(mlxsw_sp); err_router_init: kfree(mlxsw_sp->router); @@ -3677,6 +3688,7 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) mlxsw_sp_lpm_fini(mlxsw_sp); rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht); rhashtable_destroy(&mlxsw_sp->router->nexthop_ht); + mlxsw_sp_rifs_fini(mlxsw_sp); __mlxsw_sp_router_fini(mlxsw_sp); kfree(mlxsw_sp->router); } -- cgit v1.2.3 From d341e2ce6bf77250096d568f65be04466ace5d0e Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:30 +0200 Subject: mlxsw: spectrum_switchdev: Remove redundant check Since commit 97c242902c20 ("switchdev: Execute bridge ndos only for bridge ports") switchdev code checks that port is bridged, so no need to perform the same check in the driver. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 85790d38d2f0..d9393f7ff79f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -374,9 +374,6 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, unsigned long uc_flood = mlxsw_sp_port->uc_flood ? BR_FLOOD : 0; int err; - if (!mlxsw_sp_port->bridged) - return -EINVAL; - if (switchdev_trans_ph_prepare(trans)) return 0; @@ -796,9 +793,6 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, old_pvid; int err; - if (!mlxsw_sp_port->bridged) - return -EINVAL; - err = mlxsw_sp_port_fid_join(mlxsw_sp_port, vid_begin, vid_end); if (err) { netdev_err(dev, "Failed to join FIDs\n"); @@ -1162,9 +1156,6 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, { u16 vid, pvid; - if (!mlxsw_sp_port->bridged) - return -EINVAL; - mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, false); -- cgit v1.2.3 From fe9ccc785de5f8d0cb1b6113a0da387dfd8bf38c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:31 +0200 Subject: mlxsw: spectrum_switchdev: Don't batch VLAN operations switchdev's VLAN object has the ability to describe a range of VLAN IDs, but this is only used when VLAN operations are done using the SELF flag, which is something we would like to remove as it allows one to bypass the bridge driver. Do VLAN operations on a per-VLAN basis, thereby simplifying the code and preparing it for refactoring in a follow-up patchset. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 39 +++- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 4 + .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 217 ++++++++------------- 3 files changed, 121 insertions(+), 139 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 166be1854111..2f0e14974a08 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -210,6 +210,41 @@ static void mlxsw_sp_txhdr_construct(struct sk_buff *skb, mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL); } +int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + u8 state) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + enum mlxsw_reg_spms_state spms_state; + char *spms_pl; + int err; + + switch (state) { + case BR_STATE_FORWARDING: + spms_state = MLXSW_REG_SPMS_STATE_FORWARDING; + break; + case BR_STATE_LEARNING: + spms_state = MLXSW_REG_SPMS_STATE_LEARNING; + break; + case BR_STATE_LISTENING: /* fall-through */ + case BR_STATE_DISABLED: /* fall-through */ + case BR_STATE_BLOCKING: + spms_state = MLXSW_REG_SPMS_STATE_DISCARDING; + break; + default: + BUG(); + } + + spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); + if (!spms_pl) + return -ENOMEM; + mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port); + mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); + + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl); + kfree(spms_pl); + return err; +} + static int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp) { char spad_pl[MLXSW_REG_SPAD_LEN] = {0}; @@ -649,8 +684,8 @@ int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, return err; } -static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, bool learn_enable) +int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + bool learn_enable) { return __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, learn_enable); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 29db77f8bb6f..d96e9126262e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -445,6 +445,10 @@ int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, u16 vid_end, bool learn_enable); +int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + u8 state); +int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + bool learn_enable); #ifdef CONFIG_MLXSW_SPECTRUM_DCB diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index d9393f7ff79f..8a31bf9013f2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -650,61 +650,44 @@ static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid, return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, valid, fid, fid); } -static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid_begin, u16 fid_end) +static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid) { bool mc_flood; - int fid, err; + int err; - for (fid = fid_begin; fid <= fid_end; fid++) { - err = __mlxsw_sp_port_fid_join(mlxsw_sp_port, fid); - if (err) - goto err_port_fid_join; - } + err = __mlxsw_sp_port_fid_join(mlxsw_sp_port, fid); + if (err) + return err; mc_flood = mlxsw_sp_port->mc_disabled ? mlxsw_sp_port->mc_flood : mlxsw_sp_port->mc_router; - err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, + err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid, fid, mlxsw_sp_port->uc_flood, true, mc_flood); if (err) goto err_port_flood_set; - for (fid = fid_begin; fid <= fid_end; fid++) { - err = mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, true); - if (err) - goto err_port_fid_map; - } + err = mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, true); + if (err) + goto err_port_fid_map; return 0; err_port_fid_map: - for (fid--; fid >= fid_begin; fid--) - mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false); - __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false, - false, false); + __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid, fid, false, false, false); err_port_flood_set: - fid = fid_end; -err_port_fid_join: - for (fid--; fid >= fid_begin; fid--) - __mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid); + __mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid); return err; } static void mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid_begin, u16 fid_end) + u16 fid) { - int fid; - - for (fid = fid_begin; fid <= fid_end; fid++) - mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false); - - __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false, + mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false); + __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid, fid, false, false, false); - - for (fid = fid_begin; fid <= fid_end; fid++) - __mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid); + __mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid); } static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, @@ -764,104 +747,64 @@ err_port_allow_untagged_set: return err; } -static int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end, - bool learn_enable) +static u16 +mlxsw_sp_port_pvid_determine(const struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid, bool is_pvid) { - u16 vid, vid_e; - int err; - - for (vid = vid_begin; vid <= vid_end; - vid += MLXSW_REG_SPVMLR_REC_MAX_COUNT) { - vid_e = min((u16) (vid + MLXSW_REG_SPVMLR_REC_MAX_COUNT - 1), - vid_end); - - err = __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, - vid_e, learn_enable); - if (err) - return err; - } - - return 0; + if (is_pvid) + return vid; + else if (mlxsw_sp_port->pvid == vid) + return 0; /* Dis-allow untagged packets */ + else + return mlxsw_sp_port->pvid; } -static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end, - bool flag_untagged, bool flag_pvid) +static int mlxsw_sp_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + bool is_untagged, bool is_pvid) { - struct net_device *dev = mlxsw_sp_port->dev; - u16 vid, old_pvid; + u16 pvid = mlxsw_sp_port_pvid_determine(mlxsw_sp_port, vid, is_pvid); + u16 old_pvid = mlxsw_sp_port->pvid; int err; - err = mlxsw_sp_port_fid_join(mlxsw_sp_port, vid_begin, vid_end); - if (err) { - netdev_err(dev, "Failed to join FIDs\n"); + err = mlxsw_sp_port_fid_join(mlxsw_sp_port, vid); + if (err) return err; - } - err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid_begin, vid_end, - true, flag_untagged); - if (err) { - netdev_err(dev, "Unable to add VIDs %d-%d\n", vid_begin, - vid_end); - goto err_port_vlans_set; - } + err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, + is_untagged); + if (err) + goto err_port_vlan_set; - old_pvid = mlxsw_sp_port->pvid; - if (flag_pvid && old_pvid != vid_begin) { - err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid_begin); - if (err) { - netdev_err(dev, "Unable to add PVID %d\n", vid_begin); - goto err_port_pvid_set; - } - } else if (!flag_pvid && old_pvid >= vid_begin && old_pvid <= vid_end) { - err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0); - if (err) { - netdev_err(dev, "Unable to del PVID\n"); - goto err_port_pvid_set; - } - } + err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid); + if (err) + goto err_port_pvid_set; - err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, + err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, mlxsw_sp_port->learning); - if (err) { - netdev_err(dev, "Failed to set learning for VIDs %d-%d\n", - vid_begin, vid_end); + if (err) goto err_port_vid_learning_set; - } - /* Changing activity bits only if HW operation succeded */ - for (vid = vid_begin; vid <= vid_end; vid++) { - set_bit(vid, mlxsw_sp_port->active_vlans); - if (flag_untagged) - set_bit(vid, mlxsw_sp_port->untagged_vlans); - else - clear_bit(vid, mlxsw_sp_port->untagged_vlans); - } + err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, + mlxsw_sp_port->stp_state); + if (err) + goto err_port_vid_stp_set; - /* STP state change must be done after we set active VLANs */ - err = mlxsw_sp_port_stp_state_set(mlxsw_sp_port, - mlxsw_sp_port->stp_state); - if (err) { - netdev_err(dev, "Failed to set STP state\n"); - goto err_port_stp_state_set; - } + if (is_untagged) + __set_bit(vid, mlxsw_sp_port->untagged_vlans); + else + __clear_bit(vid, mlxsw_sp_port->untagged_vlans); + __set_bit(vid, mlxsw_sp_port->active_vlans); return 0; -err_port_stp_state_set: - for (vid = vid_begin; vid <= vid_end; vid++) - clear_bit(vid, mlxsw_sp_port->active_vlans); - mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, - false); +err_port_vid_stp_set: + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); err_port_vid_learning_set: - if (old_pvid != mlxsw_sp_port->pvid) - mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid); + mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid); err_port_pvid_set: - mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid_begin, vid_end, - false, false); -err_port_vlans_set: - mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid_begin, vid_end); + mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); +err_port_vlan_set: + mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid); return err; } @@ -871,13 +814,21 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, { bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + u16 vid; if (switchdev_trans_ph_prepare(trans)) return 0; - return __mlxsw_sp_port_vlans_add(mlxsw_sp_port, - vlan->vid_begin, vlan->vid_end, - flag_untagged, flag_pvid); + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + int err; + + err = mlxsw_sp_port_vlan_add(mlxsw_sp_port, vid, flag_untagged, + flag_pvid); + if (err) + return err; + } + + return 0; } static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic) @@ -1151,35 +1102,27 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, return err; } -static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end) +static void mlxsw_sp_port_vlan_del(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) { - u16 vid, pvid; - - mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end, - false); - - pvid = mlxsw_sp_port->pvid; - if (pvid >= vid_begin && pvid <= vid_end) - mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0); - - mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid_begin, vid_end, - false, false); + u16 pvid = mlxsw_sp_port->pvid == vid ? 0 : vid; - mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid_begin, vid_end); - - /* Changing activity bits only if HW operation succeded */ - for (vid = vid_begin; vid <= vid_end; vid++) - clear_bit(vid, mlxsw_sp_port->active_vlans); - - return 0; + __clear_bit(vid, mlxsw_sp_port->active_vlans); + mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED); + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); + mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid); + mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); + mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid); } static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_vlan *vlan) { - return __mlxsw_sp_port_vlans_del(mlxsw_sp_port, vlan->vid_begin, - vlan->vid_end); + u16 vid; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) + mlxsw_sp_port_vlan_del(mlxsw_sp_port, vid); + + return 0; } void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port) @@ -1187,7 +1130,7 @@ void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port) u16 vid; for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) - __mlxsw_sp_port_vlans_del(mlxsw_sp_port, vid, vid); + mlxsw_sp_port_vlan_del(mlxsw_sp_port, vid); } static int -- cgit v1.2.3 From 45bfe6b433e0b8c2528784360dbd390ffaea3c70 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:32 +0200 Subject: mlxsw: spectrum_switchdev: Don't batch STP operations Simplify the code by using the common function that sets an STP state for a Port-VLAN and remove the existing one that tries to batch it for several VLANs. This will help us in a follow-up patchset to introduce a unified infrastructure for bridge ports, regardless if the bridge is VLAN-aware or not. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 59 +++++++--------------- 1 file changed, 17 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 8a31bf9013f2..ad5eefa7d23b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -146,58 +146,33 @@ static int mlxsw_sp_port_attr_get(struct net_device *dev, return 0; } -static int mlxsw_sp_port_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port, - u8 state) +static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct switchdev_trans *trans, + u8 state) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - enum mlxsw_reg_spms_state spms_state; - char *spms_pl; u16 vid; int err; - switch (state) { - case BR_STATE_FORWARDING: - spms_state = MLXSW_REG_SPMS_STATE_FORWARDING; - break; - case BR_STATE_LEARNING: - spms_state = MLXSW_REG_SPMS_STATE_LEARNING; - break; - case BR_STATE_LISTENING: /* fall-through */ - case BR_STATE_DISABLED: /* fall-through */ - case BR_STATE_BLOCKING: - spms_state = MLXSW_REG_SPMS_STATE_DISCARDING; - break; - default: - BUG(); - } - - spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); - if (!spms_pl) - return -ENOMEM; - mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port); + if (switchdev_trans_ph_prepare(trans)) + return 0; if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); - } else { - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) - mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); - } - - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl); - kfree(spms_pl); - return err; -} - -static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port, - struct switchdev_trans *trans, - u8 state) -{ - if (switchdev_trans_ph_prepare(trans)) + err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, state); + if (err) + return err; + mlxsw_sp_port->stp_state = state; return 0; + } + for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { + err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, state); + if (err) + return err; + } mlxsw_sp_port->stp_state = state; - return mlxsw_sp_port_stp_state_set(mlxsw_sp_port, state); + + return 0; } static int __mlxsw_sp_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, -- cgit v1.2.3 From 7cbc4277c7e079dc941fb57c823aacb79160d14b Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:33 +0200 Subject: mlxsw: spectrum_switchdev: Don't batch learning operations We no longer batch VLAN operations, so there's no need to set the learning state for a range of VLANs. Use a common function to set the learning state for a Port-VLAN, thereby making the code saner more receptive for upcoming changes. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 16 ++++------------ drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 3 --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 8 +++----- 3 files changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 2f0e14974a08..da15819e75a9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -666,9 +666,8 @@ int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); } -int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end, - bool learn_enable) +int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, + bool learn_enable) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; char *spvmlr_pl; @@ -677,20 +676,13 @@ int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL); if (!spvmlr_pl) return -ENOMEM; - mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid_begin, - vid_end, learn_enable); + mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid, vid, + learn_enable); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl); kfree(spvmlr_pl); return err; } -int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, - bool learn_enable) -{ - return __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, - learn_enable); -} - static int mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index d96e9126262e..aea321eee47c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -442,9 +442,6 @@ int __mlxsw_sp_port_headroom_set(struct mlxsw_sp_port *mlxsw_sp_port, int mtu, int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index, u32 maxrate); -int __mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid_begin, u16 vid_end, - bool learn_enable); int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, u8 state); int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index ad5eefa7d23b..6fdcbcfddc8d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -322,13 +322,11 @@ static int mlxsw_sp_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - return __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, - set); + return mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, set); } for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, - set); + err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, set); if (err) goto err_port_vid_learning_set; } @@ -337,7 +335,7 @@ static int mlxsw_sp_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, err_port_vid_learning_set: for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) - __mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, vid, !set); + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, !set); return err; } -- cgit v1.2.3 From b02eae9b91771765921aa8f616cacb6bfee40afb Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:34 +0200 Subject: mlxsw: spectrum: Move PVID code to appropriate place PVID is a port attribute and should therefore reside in the main driver file and not the switchdev specific one. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 45 +++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 +- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 57 ---------------------- 3 files changed, 46 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index da15819e75a9..21227a8aab32 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -683,6 +683,51 @@ int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, return err; } +static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + char spvid_pl[MLXSW_REG_SPVID_LEN]; + + mlxsw_reg_spvid_pack(spvid_pl, mlxsw_sp_port->local_port, vid); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl); +} + +static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port, + bool allow) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + char spaft_pl[MLXSW_REG_SPAFT_LEN]; + + mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl); +} + +int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + int err; + + if (!vid) { + err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false); + if (err) + return err; + } else { + err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid); + if (err) + return err; + err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, true); + if (err) + goto err_port_allow_untagged_set; + } + + mlxsw_sp_port->pvid = vid; + return 0; + +err_port_allow_untagged_set: + __mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid); + return err; +} + static int mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index aea321eee47c..7caf175211a8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -425,7 +425,6 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, bool set); void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid); int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, bool adding); @@ -446,6 +445,7 @@ int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, u8 state); int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, bool learn_enable); +int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); #ifdef CONFIG_MLXSW_SPECTRUM_DCB diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 6fdcbcfddc8d..8bc79864c732 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -663,63 +663,6 @@ static void mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port, __mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid); } -static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char spvid_pl[MLXSW_REG_SPVID_LEN]; - - mlxsw_reg_spvid_pack(spvid_pl, mlxsw_sp_port->local_port, vid); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl); -} - -static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port, - bool allow) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char spaft_pl[MLXSW_REG_SPAFT_LEN]; - - mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl); -} - -int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) -{ - struct net_device *dev = mlxsw_sp_port->dev; - int err; - - if (!vid) { - err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false); - if (err) { - netdev_err(dev, "Failed to disallow untagged traffic\n"); - return err; - } - } else { - err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid); - if (err) { - netdev_err(dev, "Failed to set PVID\n"); - return err; - } - - /* Only allow if not already allowed. */ - if (!mlxsw_sp_port->pvid) { - err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, - true); - if (err) { - netdev_err(dev, "Failed to allow untagged traffic\n"); - goto err_port_allow_untagged_set; - } - } - } - - mlxsw_sp_port->pvid = vid; - return 0; - -err_port_allow_untagged_set: - __mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid); - return err; -} - static u16 mlxsw_sp_port_pvid_determine(const struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, bool is_pvid) -- cgit v1.2.3 From 45a4a16cdb0332ccf09064e22ba03e75c0cd3171 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 16 May 2017 19:38:35 +0200 Subject: mlxsw: spectrum: Default ports to non-virtual mode In virtual mode, packets are classified to FIDs based on their ingress port and VLAN whereas in non-virtual mode only the VLAN is taken into account. Currently ports are initialized to use virtual mode due to the presence of the PVID vPort. However, we're going to transition ports between both modes based on the FIDs they use and not merely based on the presence on a VLAN upper. Therefore, during initialization, no mode will be explicitly set. Since the Programmer's Reference Manual (PRM) doesn't specify a default, explicitly set the port to non-virtual mode and later transition the port between both modes based on the FIDs it uses. In a follow-up patchset, this step will be moved to the common FID core where it logically belongs. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 21227a8aab32..8a165bbfcedc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2619,6 +2619,13 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_port_dcb_init; } + err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set non-virtual mode\n", + mlxsw_sp_port->local_port); + goto err_port_vp_mode_set; + } + err = mlxsw_sp_port_pvid_vport_create(mlxsw_sp_port); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create PVID vPort\n", @@ -2646,6 +2653,7 @@ err_register_netdev: mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); mlxsw_sp_port_pvid_vport_destroy(mlxsw_sp_port); err_port_pvid_vport_create: +err_port_vp_mode_set: mlxsw_sp_port_dcb_fini(mlxsw_sp_port); err_port_dcb_init: err_port_ets_init: -- cgit v1.2.3 From 8b0d3ea555876533b6aa61479335be2c9bdb47e7 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 16 May 2017 14:10:33 -0400 Subject: net: dsa: store CPU port pointer in the tree A dsa_switch_tree instance holds a dsa_switch pointer and a port index to identify the switch port to which the CPU is attached. Now that the DSA layer has a dsa_port structure to hold this data, use it to point the switch CPU port. This patch simply substitutes s/dst->cpu_switch/dst->cpu_dp->ds/ and s/dst->cpu_port/dst->cpu_dp->index/. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 4 ++-- drivers/net/dsa/bcm_sf2.c | 4 ++-- drivers/net/dsa/mv88e6060.c | 2 +- drivers/net/dsa/qca8k.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index fa0eece21eef..658a12c888a8 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1344,7 +1344,7 @@ EXPORT_SYMBOL(b53_fdb_dump); int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; - s8 cpu_port = ds->dst->cpu_port; + s8 cpu_port = ds->dst->cpu_dp->index; u16 pvlan, reg; unsigned int i; @@ -1390,7 +1390,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; struct b53_vlan *vl = &dev->vlans[0]; - s8 cpu_port = ds->dst->cpu_port; + s8 cpu_port = ds->dst->cpu_dp->index; unsigned int i; u16 pvlan, reg, pvid; diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 2be963252ca5..215d41c1e71f 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -228,7 +228,7 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, struct phy_device *phy) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - s8 cpu_port = ds->dst[ds->index].cpu_port; + s8 cpu_port = ds->dst->cpu_dp->index; unsigned int i; u32 reg; @@ -832,7 +832,7 @@ static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, { struct net_device *p = ds->dst[ds->index].master_netdev; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - s8 cpu_port = ds->dst[ds->index].cpu_port; + s8 cpu_port = ds->dst->cpu_dp->index; struct ethtool_wolinfo pwol; p->ethtool_ops->get_wol(p, &pwol); diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index 5934b7a4c448..dce7fa57eb55 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c @@ -176,7 +176,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p) ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) | (dsa_is_cpu_port(ds, p) ? ds->enabled_port_mask : - BIT(ds->dst->cpu_port))); + BIT(ds->dst->cpu_dp->index))); /* Port Association Vector: when learning source addresses * of packets, add the address to the address database using diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index a4fd4ccf7b67..942b9ac7f92a 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -507,7 +507,7 @@ qca8k_setup(struct dsa_switch *ds) pr_warn("regmap initialization failed"); /* Initialize CPU port pad mode (xMII type, delays...) */ - phy_mode = of_get_phy_mode(ds->ports[ds->dst->cpu_port].dn); + phy_mode = of_get_phy_mode(ds->dst->cpu_dp->dn); if (phy_mode < 0) { pr_err("Can't find phy-mode for master device\n"); return phy_mode; -- cgit v1.2.3 From e1e3ce623699d0cd594fa69f69371a9dbc55aa9a Mon Sep 17 00:00:00 2001 From: Rick Farrington Date: Tue, 16 May 2017 11:14:50 -0700 Subject: liquidio: fix insmod failure when multiple NICs are plugged in When multiple liquidio NICs are plugged in, the first insmod of the PF driver succeeds. But after an rmmod, a subsequent insmod fails. Reason is during rmmod, the PF driver resets the Octeon of only one of the NICs; it neglects to reset the Octeons of the other NICs. Fix the insmod failure by adding the missing Octeon resets at rmmod. Keep a per-NIC refcount that indicates the number of active PFs in a given NIC. When the refcount goes to zero, then reset the Octeon of that NIC. Signed-off-by: Rick Farrington Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_main.c | 21 +++++- .../net/ethernet/cavium/liquidio/octeon_device.c | 87 ++++++++++++++++++++-- .../net/ethernet/cavium/liquidio/octeon_device.h | 25 +++++++ 3 files changed, 123 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 927617cbf6a9..360ddc8b2afb 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -1421,7 +1421,7 @@ static bool fw_type_is_none(void) */ static void octeon_destroy_resources(struct octeon_device *oct) { - int i; + int i, refcount; struct msix_entry *msix_entries; struct octeon_device_priv *oct_priv = (struct octeon_device_priv *)oct->priv; @@ -1556,10 +1556,14 @@ static void octeon_destroy_resources(struct octeon_device *oct) /* fallthrough */ case OCT_DEV_PCI_MAP_DONE: + refcount = octeon_deregister_device(oct); + if (!fw_type_is_none()) { - /* Soft reset the octeon device before exiting */ - if (!OCTEON_CN23XX_PF(oct) || - (OCTEON_CN23XX_PF(oct) && !oct->octeon_id)) + /* Soft reset the octeon device before exiting. + * Implementation note: here, we reset the device + * if it is a CN6XXX OR the last CN23XX device. + */ + if (OCTEON_CN6XXX(oct) || !refcount) oct->fn_list.soft_reset(oct); } @@ -4511,6 +4515,15 @@ static int octeon_device_init(struct octeon_device *octeon_dev) atomic_set(&octeon_dev->status, OCT_DEV_PCI_MAP_DONE); + /* Only add a reference after setting status 'OCT_DEV_PCI_MAP_DONE', + * since that is what is required for the reference to be removed + * during de-initialization (see 'octeon_destroy_resources'). + */ + octeon_register_device(octeon_dev, octeon_dev->pci_dev->bus->number, + PCI_SLOT(octeon_dev->pci_dev->devfn), + PCI_FUNC(octeon_dev->pci_dev->devfn), + true); + octeon_dev->app_mode = CVM_DRV_INVALID_APP; if (OCTEON_CN23XX_PF(octeon_dev)) { diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index e21b477d0159..3cc56675359a 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -543,7 +543,11 @@ static char oct_dev_app_str[CVM_DRV_APP_COUNT + 1][32] = { "BASE", "NIC", "UNKNOWN"}; static struct octeon_device *octeon_device[MAX_OCTEON_DEVICES]; +static atomic_t adapter_refcounts[MAX_OCTEON_DEVICES]; + static u32 octeon_device_count; +/* locks device array (i.e. octeon_device[]) */ +spinlock_t octeon_devices_lock; static struct octeon_core_setup core_setup[MAX_OCTEON_DEVICES]; @@ -561,6 +565,7 @@ void octeon_init_device_list(int conf_type) memset(octeon_device, 0, (sizeof(void *) * MAX_OCTEON_DEVICES)); for (i = 0; i < MAX_OCTEON_DEVICES; i++) oct_set_config_info(i, conf_type); + spin_lock_init(&octeon_devices_lock); } static void *__retrieve_octeon_config_info(struct octeon_device *oct, @@ -720,23 +725,27 @@ struct octeon_device *octeon_allocate_device(u32 pci_id, u32 oct_idx = 0; struct octeon_device *oct = NULL; + spin_lock(&octeon_devices_lock); + for (oct_idx = 0; oct_idx < MAX_OCTEON_DEVICES; oct_idx++) if (!octeon_device[oct_idx]) break; - if (oct_idx == MAX_OCTEON_DEVICES) - return NULL; + if (oct_idx < MAX_OCTEON_DEVICES) { + oct = octeon_allocate_device_mem(pci_id, priv_size); + if (oct) { + octeon_device_count++; + octeon_device[oct_idx] = oct; + } + } - oct = octeon_allocate_device_mem(pci_id, priv_size); + spin_unlock(&octeon_devices_lock); if (!oct) return NULL; spin_lock_init(&oct->pci_win_lock); spin_lock_init(&oct->mem_access_lock); - octeon_device_count++; - octeon_device[oct_idx] = oct; - oct->octeon_id = oct_idx; snprintf(oct->device_name, sizeof(oct->device_name), "LiquidIO%d", (oct->octeon_id)); @@ -744,6 +753,72 @@ struct octeon_device *octeon_allocate_device(u32 pci_id, return oct; } +/** Register a device's bus location at initialization time. + * @param octeon_dev - pointer to the octeon device structure. + * @param bus - PCIe bus # + * @param dev - PCIe device # + * @param func - PCIe function # + * @param is_pf - TRUE for PF, FALSE for VF + * @return reference count of device's adapter + */ +int octeon_register_device(struct octeon_device *oct, + int bus, int dev, int func, int is_pf) +{ + int idx, refcount; + + oct->loc.bus = bus; + oct->loc.dev = dev; + oct->loc.func = func; + + oct->adapter_refcount = &adapter_refcounts[oct->octeon_id]; + atomic_set(oct->adapter_refcount, 0); + + spin_lock(&octeon_devices_lock); + for (idx = (int)oct->octeon_id - 1; idx >= 0; idx--) { + if (!octeon_device[idx]) { + dev_err(&oct->pci_dev->dev, + "%s: Internal driver error, missing dev", + __func__); + spin_unlock(&octeon_devices_lock); + atomic_inc(oct->adapter_refcount); + return 1; /* here, refcount is guaranteed to be 1 */ + } + /* if another device is at same bus/dev, use its refcounter */ + if ((octeon_device[idx]->loc.bus == bus) && + (octeon_device[idx]->loc.dev == dev)) { + oct->adapter_refcount = + octeon_device[idx]->adapter_refcount; + break; + } + } + spin_unlock(&octeon_devices_lock); + + atomic_inc(oct->adapter_refcount); + refcount = atomic_read(oct->adapter_refcount); + + dev_dbg(&oct->pci_dev->dev, "%s: %02x:%02x:%d refcount %u", __func__, + oct->loc.bus, oct->loc.dev, oct->loc.func, refcount); + + return refcount; +} + +/** Deregister a device at de-initialization time. + * @param octeon_dev - pointer to the octeon device structure. + * @return reference count of device's adapter + */ +int octeon_deregister_device(struct octeon_device *oct) +{ + int refcount; + + atomic_dec(oct->adapter_refcount); + refcount = atomic_read(oct->adapter_refcount); + + dev_dbg(&oct->pci_dev->dev, "%s: %04d:%02d:%d refcount %u", __func__, + oct->loc.bus, oct->loc.dev, oct->loc.func, refcount); + + return refcount; +} + int octeon_allocate_ioq_vector(struct octeon_device *oct) { diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h index 92f67de111aa..c90ed48ae8ab 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h @@ -544,6 +544,14 @@ struct octeon_device { u32 tx_max_coalesced_frames; bool cores_crashed; + + struct { + int bus; + int dev; + int func; + } loc; + + atomic_t *adapter_refcount; /* reference count of adapter */ }; #define OCT_DRV_ONLINE 1 @@ -572,6 +580,23 @@ void octeon_free_device_mem(struct octeon_device *oct); struct octeon_device *octeon_allocate_device(u32 pci_id, u32 priv_size); +/** Register a device's bus location at initialization time. + * @param octeon_dev - pointer to the octeon device structure. + * @param bus - PCIe bus # + * @param dev - PCIe device # + * @param func - PCIe function # + * @param is_pf - TRUE for PF, FALSE for VF + * @return reference count of device's adapter + */ +int octeon_register_device(struct octeon_device *oct, + int bus, int dev, int func, int is_pf); + +/** Deregister a device at de-initialization time. + * @param octeon_dev - pointer to the octeon device structure. + * @return reference count of device's adapter + */ +int octeon_deregister_device(struct octeon_device *oct); + /** Initialize the driver's dispatch list which is a mix of a hash table * and a linked list. This is done at driver load time. * @param octeon_dev - pointer to the octeon device structure. -- cgit v1.2.3 From 0d9a5997842756f859032ae3efcaf79715a51883 Mon Sep 17 00:00:00 2001 From: Felix Manlunas Date: Tue, 16 May 2017 11:28:00 -0700 Subject: liquidio: fix PF falsely indicating success at setting MAC address of a nonexistent VF In the function assigned to .ndo_set_vf_mac, check the validity of the vfidx argument before proceeding to tell the firmware to set the VF MAC address. Signed-off-by: Felix Manlunas Signed-off-by: Derek Chickles Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 360ddc8b2afb..649f2aaf0afb 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -3698,6 +3698,9 @@ static int liquidio_set_vf_mac(struct net_device *netdev, int vfidx, u8 *mac) struct octeon_device *oct = lio->oct_dev; int retval; + if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) + return -EINVAL; + retval = __liquidio_set_vf_mac(netdev, vfidx, mac, true); if (!retval) cn23xx_tell_vf_its_macaddr_changed(oct, vfidx, mac); -- cgit v1.2.3 From ec34e93f99123c44ba93d5f36a64d1fb5d72b6c9 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 16 May 2017 22:40:08 +0200 Subject: drivers: net: DSA: Sort drivers With more drivers being added, it is time to sort the drivers to impose some order. Signed-off-by: Andrew Lunn Reviewed-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/Kconfig | 40 ++++++++++++++++++++-------------------- drivers/net/dsa/Makefile | 6 +++--- 2 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 862ee22303c2..68131a45ac5e 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -1,13 +1,7 @@ menu "Distributed Switch Architecture drivers" depends on HAVE_NET_DSA -config NET_DSA_MV88E6060 - tristate "Marvell 88E6060 ethernet switch chip support" - depends on NET_DSA - select NET_DSA_TAG_TRAILER - ---help--- - This enables support for the Marvell 88E6060 ethernet switch - chip. +source "drivers/net/dsa/b53/Kconfig" config NET_DSA_BCM_SF2 tristate "Broadcom Starfighter 2 Ethernet switch support" @@ -21,19 +15,6 @@ config NET_DSA_BCM_SF2 This enables support for the Broadcom Starfighter 2 Ethernet switch chips. -source "drivers/net/dsa/b53/Kconfig" - -source "drivers/net/dsa/mv88e6xxx/Kconfig" - -config NET_DSA_QCA8K - tristate "Qualcomm Atheros QCA8K Ethernet switch family support" - depends on NET_DSA - select NET_DSA_TAG_QCA - select REGMAP - ---help--- - This enables support for the Qualcomm Atheros QCA8K Ethernet - switch chips. - config NET_DSA_LOOP tristate "DSA mock-up Ethernet switch chip support" depends on NET_DSA @@ -50,6 +31,25 @@ config NET_DSA_MT7530 This enables support for the Mediatek MT7530 Ethernet switch chip. +config NET_DSA_MV88E6060 + tristate "Marvell 88E6060 ethernet switch chip support" + depends on NET_DSA + select NET_DSA_TAG_TRAILER + ---help--- + This enables support for the Marvell 88E6060 ethernet switch + chip. + +source "drivers/net/dsa/mv88e6xxx/Kconfig" + +config NET_DSA_QCA8K + tristate "Qualcomm Atheros QCA8K Ethernet switch family support" + depends on NET_DSA + select NET_DSA_TAG_QCA + select REGMAP + ---help--- + This enables support for the Qualcomm Atheros QCA8K Ethernet + switch chips. + config NET_DSA_SMSC_LAN9303 tristate select NET_DSA_TAG_LAN9303 diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index edd630361736..9613f36083a6 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -1,11 +1,11 @@ -obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm-sf2.o bcm-sf2-objs := bcm_sf2.o bcm_sf2_cfp.o -obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o +obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o dsa_loop_bdinfo.o obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o +obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o +obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o obj-y += b53/ obj-y += mv88e6xxx/ -obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o dsa_loop_bdinfo.o -- cgit v1.2.3 From 0c3439bc7773c583c2bcb27f69aa7f0692328489 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 17 May 2017 03:25:59 +0200 Subject: net: phy: Marvell: checkpatch - Comments Use net style comment blocks, and wrap one block with long lines. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 272b051a0199..2aacbf8e0eb3 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -257,7 +257,8 @@ static int marvell_config_aneg(struct phy_device *phydev) /* The Marvell PHY has an errata which requires * that certain registers get written in order - * to restart autonegotiation */ + * to restart autonegotiation + */ err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) @@ -299,8 +300,7 @@ static int marvell_config_aneg(struct phy_device *phydev) if (phydev->autoneg != AUTONEG_ENABLE) { int bmcr; - /* - * A write to speed/duplex bits (that is performed by + /* A write to speed/duplex bits (that is performed by * genphy_config_aneg() call above) must be followed by * a software reset. Otherwise, the write has no effect. */ @@ -359,8 +359,7 @@ static int m88e1111_config_aneg(struct phy_device *phydev) } #ifdef CONFIG_OF_MDIO -/* - * Set and/or override some configuration registers based on the +/* Set and/or override some configuration registers based on the * marvell,reg-init property stored in the of_node for the phydev. * * marvell,reg-init = ,...; @@ -1057,7 +1056,8 @@ static int marvell_update_link(struct phy_device *phydev, int fiber) int status; /* Use the generic register for copper link, or specific - * register for fiber case */ + * register for fiber case + */ if (fiber) { status = phy_read(phydev, MII_M1011_PHY_STATUS); if (status < 0) @@ -1092,7 +1092,8 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) int fiber; /* Detect and update the link, but return if there - * was an error */ + * was an error + */ if (page == MII_M1111_FIBER) fiber = 1; else @@ -1217,12 +1218,13 @@ static int marvell_read_status(struct phy_device *phydev) if (err < 0) goto error; - /* If the fiber link is up, it is the selected and used link. - * In this case, we need to stay in the fiber page. - * Please to be careful about that, avoid to restore Copper page - * in other functions which could break the behaviour - * for some fiber phy like 88E1512. - * */ + /* If the fiber link is up, it is the selected and + * used link. In this case, we need to stay in the + * fiber page. Please to be careful about that, avoid + * to restore Copper page in other functions which + * could break the behaviour for some fiber phy like + * 88E1512. + */ if (phydev->link) return 0; -- cgit v1.2.3 From e69d9ed4faa10a2b8d8e4d7e2b930d972642830b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 17 May 2017 03:26:00 +0200 Subject: net: phy: marvell: Checkpatch - Missing or extra blank lines Remove the extra blank lines, add one in where recommended. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 2aacbf8e0eb3..f52656ec618f 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -420,7 +420,6 @@ static int marvell_of_reg_init(struct phy_device *phydev) ret = phy_write(phydev, reg, val); if (ret < 0) goto err; - } err: if (current_page != saved_page) { @@ -449,7 +448,6 @@ static int m88e1121_config_aneg(struct phy_device *phydev) return err; if (phy_interface_is_rgmii(phydev)) { - mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & MII_88E1121_PHY_MSCR_DELAY_MASK; @@ -703,7 +701,6 @@ static int m88e1111_config_init(struct phy_device *phydev) int temp; if (phy_interface_is_rgmii(phydev)) { - temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); if (temp < 0) return temp; @@ -968,6 +965,7 @@ static int m88e1145_config_init(struct phy_device *phydev) if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); + if (temp < 0) return temp; @@ -1312,6 +1310,7 @@ error: static int marvell_aneg_done(struct phy_device *phydev) { int retval = phy_read(phydev, MII_M1011_PHY_STATUS); + return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); } -- cgit v1.2.3 From 4f48ed32fb62fc1546306c1488e259c0c4f4f462 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 17 May 2017 03:26:01 +0200 Subject: net: phy: marvell: Checkpatch - assignments and comparisons Avoid multiple assignments Comparisons should place the constant on the right side of the test Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f52656ec618f..e9632f576a24 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1101,7 +1101,7 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) if (err) return err; - if (AUTONEG_ENABLE == phydev->autoneg) { + if (phydev->autoneg == AUTONEG_ENABLE) { status = phy_read(phydev, MII_M1011_PHY_STATUS); if (status < 0) return status; @@ -1126,7 +1126,8 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) phydev->duplex = DUPLEX_HALF; status = status & MII_M1011_PHY_STATUS_SPD_MASK; - phydev->pause = phydev->asym_pause = 0; + phydev->pause = 0; + phydev->asym_pause = 0; switch (status) { case MII_M1011_PHY_STATUS_1000: @@ -1185,7 +1186,8 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) else phydev->speed = SPEED_10; - phydev->pause = phydev->asym_pause = 0; + phydev->pause = 0; + phydev->asym_pause = 0; phydev->lp_advertising = 0; } -- cgit v1.2.3 From e1dde8dc5b27ea578c96020c5c1e720faac87e1b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 17 May 2017 03:26:02 +0200 Subject: net: phy: marvell: Refactor some bigger functions Break big functions up by using a number of smaller helper function. Solves some of the over 80 lines warnings, by reducing the indentation level. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 484 ++++++++++++++++++++++++++-------------------- 1 file changed, 271 insertions(+), 213 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index e9632f576a24..b84380db945e 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -695,102 +695,133 @@ static int m88e3016_config_init(struct phy_device *phydev) return marvell_config_init(phydev); } -static int m88e1111_config_init(struct phy_device *phydev) +static int m88e1111_config_init_rgmii(struct phy_device *phydev) { int err; int temp; - if (phy_interface_is_rgmii(phydev)) { - temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); - if (temp < 0) - return temp; + temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); + if (temp < 0) + return temp; - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { - temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); - } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { - temp &= ~MII_M1111_TX_DELAY; - temp |= MII_M1111_RX_DELAY; - } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { - temp &= ~MII_M1111_RX_DELAY; - temp |= MII_M1111_TX_DELAY; - } + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { + temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); + } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + temp &= ~MII_M1111_TX_DELAY; + temp |= MII_M1111_RX_DELAY; + } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + temp &= ~MII_M1111_RX_DELAY; + temp |= MII_M1111_TX_DELAY; + } - err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); - if (err < 0) - return err; + err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); + if (err < 0) + return err; - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK); + temp &= ~(MII_M1111_HWCFG_MODE_MASK); - if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) - temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; - else - temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; + if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) + temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; + else + temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); - if (err < 0) - return err; - } + return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); +} - if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; +static int m88e1111_config_init_sgmii(struct phy_device *phydev) +{ + int err; + int temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK); - temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; - temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); - if (err < 0) - return err; + temp &= ~(MII_M1111_HWCFG_MODE_MASK); + temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; + temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; - /* make sure copper is selected */ - err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE); - if (err < 0) - return err; + err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (err < 0) + return err; - err = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, - err & (~0xff)); - if (err < 0) - return err; - } + /* make sure copper is selected */ + err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE); + if (err < 0) + return err; - if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { - temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); - if (temp < 0) - return temp; - temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); - err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); - if (err < 0) - return err; + return phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, err & (~0xff)); +} - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); - temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); - if (err < 0) +static int m88e1111_config_init_rtbi(struct phy_device *phydev) +{ + int err; + int temp; + + temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); + if (temp < 0) + return temp; + + temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); + err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); + if (err < 0) + return err; + + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; + + temp &= ~(MII_M1111_HWCFG_MODE_MASK | + MII_M1111_HWCFG_FIBER_COPPER_RES); + temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; + + err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (err < 0) + return err; + + /* soft reset */ + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + + do + temp = phy_read(phydev, MII_BMCR); + while (temp & BMCR_RESET); + + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; + + temp &= ~(MII_M1111_HWCFG_MODE_MASK | + MII_M1111_HWCFG_FIBER_COPPER_RES); + temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | + MII_M1111_HWCFG_FIBER_COPPER_AUTO; + + return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); +} + +static int m88e1111_config_init(struct phy_device *phydev) +{ + int err; + + if (phy_interface_is_rgmii(phydev)) { + err = m88e1111_config_init_rgmii(phydev); + if (err) return err; + } - /* soft reset */ - err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { + err = m88e1111_config_init_sgmii(phydev); if (err < 0) return err; - do - temp = phy_read(phydev, MII_BMCR); - while (temp & BMCR_RESET); + } - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); - temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { + err = m88e1111_config_init_rtbi(phydev); if (err < 0) return err; } @@ -941,10 +972,63 @@ static int m88e1149_config_init(struct phy_device *phydev) return phy_write(phydev, MII_BMCR, BMCR_RESET); } +static int m88e1145_config_init_rgmii(struct phy_device *phydev) +{ + int err; + int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); + + if (temp < 0) + return temp; + + temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); + + err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); + if (err < 0) + return err; + + if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { + err = phy_write(phydev, 0x1d, 0x0012); + if (err < 0) + return err; + + temp = phy_read(phydev, 0x1e); + if (temp < 0) + return temp; + + temp &= 0xf03f; + temp |= 2 << 9; /* 36 ohm */ + temp |= 2 << 6; /* 39 ohm */ + + err = phy_write(phydev, 0x1e, temp); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x3); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x8000); + } + return err; +} + +static int m88e1145_config_init_sgmii(struct phy_device *phydev) +{ + int temp = phy_read(phydev, MII_M1145_PHY_EXT_SR); + + if (temp < 0) + return temp; + + temp &= ~MII_M1145_HWCFG_MODE_MASK; + temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK; + temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO; + + return phy_write(phydev, MII_M1145_PHY_EXT_SR, temp); +} + static int m88e1145_config_init(struct phy_device *phydev) { int err; - int temp; /* Take care of errata E0 & E1 */ err = phy_write(phydev, 0x1d, 0x001b); @@ -964,54 +1048,13 @@ static int m88e1145_config_init(struct phy_device *phydev) return err; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { - int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); - - if (temp < 0) - return temp; - - temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); - - err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); + err = m88e1145_config_init_rgmii(phydev); if (err < 0) return err; - - if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { - err = phy_write(phydev, 0x1d, 0x0012); - if (err < 0) - return err; - - temp = phy_read(phydev, 0x1e); - if (temp < 0) - return temp; - - temp &= 0xf03f; - temp |= 2 << 9; /* 36 ohm */ - temp |= 2 << 6; /* 39 ohm */ - - err = phy_write(phydev, 0x1e, temp); - if (err < 0) - return err; - - err = phy_write(phydev, 0x1d, 0x3); - if (err < 0) - return err; - - err = phy_write(phydev, 0x1e, 0x8000); - if (err < 0) - return err; - } } if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { - temp = phy_read(phydev, MII_M1145_PHY_EXT_SR); - if (temp < 0) - return temp; - - temp &= ~MII_M1145_HWCFG_MODE_MASK; - temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK; - temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO; - - err = phy_write(phydev, MII_M1145_PHY_EXT_SR, temp); + err = m88e1145_config_init_sgmii(phydev); if (err < 0) return err; } @@ -1072,6 +1115,110 @@ static int marvell_update_link(struct phy_device *phydev, int fiber) return 0; } +static int marvell_read_status_page_an(struct phy_device *phydev, + int fiber) +{ + int status; + int lpa; + int lpagb; + int adv; + + status = phy_read(phydev, MII_M1011_PHY_STATUS); + if (status < 0) + return status; + + lpa = phy_read(phydev, MII_LPA); + if (lpa < 0) + return lpa; + + lpagb = phy_read(phydev, MII_STAT1000); + if (lpagb < 0) + return lpagb; + + adv = phy_read(phydev, MII_ADVERTISE); + if (adv < 0) + return adv; + + lpa &= adv; + + if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + status = status & MII_M1011_PHY_STATUS_SPD_MASK; + phydev->pause = 0; + phydev->asym_pause = 0; + + switch (status) { + case MII_M1011_PHY_STATUS_1000: + phydev->speed = SPEED_1000; + break; + + case MII_M1011_PHY_STATUS_100: + phydev->speed = SPEED_100; + break; + + default: + phydev->speed = SPEED_10; + break; + } + + if (!fiber) { + phydev->lp_advertising = + mii_stat1000_to_ethtool_lpa_t(lpagb) | + mii_lpa_to_ethtool_lpa_t(lpa); + + if (phydev->duplex == DUPLEX_FULL) { + phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; + } + } else { + /* The fiber link is only 1000M capable */ + phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); + + if (phydev->duplex == DUPLEX_FULL) { + if (!(lpa & LPA_PAUSE_FIBER)) { + phydev->pause = 0; + phydev->asym_pause = 0; + } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { + phydev->pause = 1; + phydev->asym_pause = 1; + } else { + phydev->pause = 1; + phydev->asym_pause = 0; + } + } + } + return 0; +} + +static int marvell_read_status_page_fixed(struct phy_device *phydev) +{ + int bmcr = phy_read(phydev, MII_BMCR); + + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (bmcr & BMCR_SPEED1000) + phydev->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phydev->speed = SPEED_100; + else + phydev->speed = SPEED_10; + + phydev->pause = 0; + phydev->asym_pause = 0; + phydev->lp_advertising = 0; + + return 0; +} + /* marvell_read_status_page * * Description: @@ -1082,12 +1229,8 @@ static int marvell_update_link(struct phy_device *phydev, int fiber) */ static int marvell_read_status_page(struct phy_device *phydev, int page) { - int adv; - int err; - int lpa; - int lpagb; - int status = 0; int fiber; + int err; /* Detect and update the link, but return if there * was an error @@ -1101,97 +1244,12 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) if (err) return err; - if (phydev->autoneg == AUTONEG_ENABLE) { - status = phy_read(phydev, MII_M1011_PHY_STATUS); - if (status < 0) - return status; - - lpa = phy_read(phydev, MII_LPA); - if (lpa < 0) - return lpa; - - lpagb = phy_read(phydev, MII_STAT1000); - if (lpagb < 0) - return lpagb; - - adv = phy_read(phydev, MII_ADVERTISE); - if (adv < 0) - return adv; - - lpa &= adv; - - if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; - - status = status & MII_M1011_PHY_STATUS_SPD_MASK; - phydev->pause = 0; - phydev->asym_pause = 0; - - switch (status) { - case MII_M1011_PHY_STATUS_1000: - phydev->speed = SPEED_1000; - break; - - case MII_M1011_PHY_STATUS_100: - phydev->speed = SPEED_100; - break; - - default: - phydev->speed = SPEED_10; - break; - } - - if (!fiber) { - phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) | - mii_lpa_to_ethtool_lpa_t(lpa); - - if (phydev->duplex == DUPLEX_FULL) { - phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; - phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; - } - } else { - /* The fiber link is only 1000M capable */ - phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); - - if (phydev->duplex == DUPLEX_FULL) { - if (!(lpa & LPA_PAUSE_FIBER)) { - phydev->pause = 0; - phydev->asym_pause = 0; - } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { - phydev->pause = 1; - phydev->asym_pause = 1; - } else { - phydev->pause = 1; - phydev->asym_pause = 0; - } - } - } - } else { - int bmcr = phy_read(phydev, MII_BMCR); - - if (bmcr < 0) - return bmcr; - - if (bmcr & BMCR_FULLDPLX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; - - if (bmcr & BMCR_SPEED1000) - phydev->speed = SPEED_1000; - else if (bmcr & BMCR_SPEED100) - phydev->speed = SPEED_100; - else - phydev->speed = SPEED_10; - - phydev->pause = 0; - phydev->asym_pause = 0; - phydev->lp_advertising = 0; - } + if (phydev->autoneg == AUTONEG_ENABLE) + err = marvell_read_status_page_an(phydev, fiber); + else + err = marvell_read_status_page_fixed(phydev); - return 0; + return err; } /* marvell_read_status -- cgit v1.2.3 From 6427bb2dfdc6e9055c9b6fc609a694fe4704c67c Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 17 May 2017 03:26:03 +0200 Subject: net: phy: marvell: Add helpers to get/set page Makes the code a bit more readable, and solves quite a few checkpatch warnings of lines longer than 80 characters. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 115 ++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index b84380db945e..d510eda92af5 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -189,6 +189,16 @@ struct marvell_priv { struct device *hwmon_dev; }; +static int marvell_get_page(struct phy_device *phydev) +{ + return phy_read(phydev, MII_MARVELL_PHY_PAGE); +} + +static int marvell_set_page(struct phy_device *phydev, int page) +{ + return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); +} + static int marvell_ack_interrupt(struct phy_device *phydev) { int err; @@ -385,7 +395,7 @@ static int marvell_of_reg_init(struct phy_device *phydev) if (!paddr || len < (4 * sizeof(*paddr))) return 0; - saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); + saved_page = marvell_get_page(phydev); if (saved_page < 0) return saved_page; current_page = saved_page; @@ -393,15 +403,15 @@ static int marvell_of_reg_init(struct phy_device *phydev) ret = 0; len /= sizeof(*paddr); for (i = 0; i < len - 3; i += 4) { - u16 reg_page = be32_to_cpup(paddr + i); + u16 page = be32_to_cpup(paddr + i); u16 reg = be32_to_cpup(paddr + i + 1); u16 mask = be32_to_cpup(paddr + i + 2); u16 val_bits = be32_to_cpup(paddr + i + 3); int val; - if (reg_page != current_page) { - current_page = reg_page; - ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page); + if (page != current_page) { + current_page = page; + ret = marvell_set_page(phydev, page); if (ret < 0) goto err; } @@ -423,7 +433,7 @@ static int marvell_of_reg_init(struct phy_device *phydev) } err: if (current_page != saved_page) { - i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); + i = marvell_set_page(phydev, saved_page); if (ret == 0) ret = i; } @@ -440,10 +450,9 @@ static int m88e1121_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); + oldpage = marvell_get_page(phydev); - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1121_PHY_MSCR_PAGE); + err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; @@ -464,7 +473,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev) return err; } - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + marvell_set_page(phydev, oldpage); err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) @@ -482,10 +491,9 @@ static int m88e1318_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); + oldpage = marvell_get_page(phydev); - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1121_PHY_MSCR_PAGE); + err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; @@ -496,7 +504,7 @@ static int m88e1318_config_aneg(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + err = marvell_set_page(phydev, oldpage); if (err < 0) return err; @@ -596,7 +604,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev) { int err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) goto error; @@ -606,7 +614,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev) goto error; /* Then the fiber link */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_M1111_FIBER); if (err < 0) goto error; @@ -614,10 +622,10 @@ static int m88e1510_config_aneg(struct phy_device *phydev) if (err < 0) goto error; - return phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + return marvell_set_page(phydev, MII_M1111_COPPER); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_M1111_COPPER); return err; } @@ -640,7 +648,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) mdelay(500); - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); + err = marvell_set_page(phydev, 0); if (err < 0) return err; @@ -652,7 +660,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2); + err = marvell_set_page(phydev, 2); if (err < 0) return err; temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC); @@ -661,7 +669,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp); if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); + err = marvell_set_page(phydev, 0); if (err < 0) return err; @@ -837,9 +845,9 @@ static int m88e1121_config_init(struct phy_device *phydev) { int err, oldpage; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); + oldpage = marvell_get_page(phydev); - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); + err = marvell_set_page(phydev, MII_88E1121_PHY_LED_PAGE); if (err < 0) return err; @@ -849,7 +857,7 @@ static int m88e1121_config_init(struct phy_device *phydev) if (err < 0) return err; - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + marvell_set_page(phydev, oldpage); /* Set marvell,reg-init configuration from device tree */ return marvell_config_init(phydev); @@ -863,7 +871,7 @@ static int m88e1510_config_init(struct phy_device *phydev) /* SGMII-to-Copper mode initialization */ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { /* Select page 18 */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18); + err = marvell_set_page(phydev, 18); if (err < 0) return err; @@ -882,7 +890,7 @@ static int m88e1510_config_init(struct phy_device *phydev) return err; /* Reset page selection */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); + err = marvell_set_page(phydev, 0); if (err < 0) return err; } @@ -912,7 +920,7 @@ static int m88e1118_config_init(struct phy_device *phydev) int err; /* Change address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); + err = marvell_set_page(phydev, 2); if (err < 0) return err; @@ -922,7 +930,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Change address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003); + err = marvell_set_page(phydev, 3); if (err < 0) return err; @@ -939,7 +947,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); + err = marvell_set_page(phydev, 0); if (err < 0) return err; @@ -951,7 +959,7 @@ static int m88e1149_config_init(struct phy_device *phydev) int err; /* Change address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); + err = marvell_set_page(phydev, 2); if (err < 0) return err; @@ -965,7 +973,7 @@ static int m88e1149_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); + err = marvell_set_page(phydev, 0); if (err < 0) return err; @@ -1268,7 +1276,7 @@ static int marvell_read_status(struct phy_device *phydev) /* Check the fiber mode first */ if (phydev->supported & SUPPORTED_FIBRE && phydev->interface != PHY_INTERFACE_MODE_SGMII) { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_M1111_FIBER); if (err < 0) goto error; @@ -1287,7 +1295,7 @@ static int marvell_read_status(struct phy_device *phydev) return 0; /* If fiber link is down, check and save copper mode state */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) goto error; } @@ -1295,7 +1303,7 @@ static int marvell_read_status(struct phy_device *phydev) return marvell_read_status_page(phydev, MII_M1111_COPPER); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_M1111_COPPER); return err; } @@ -1310,7 +1318,7 @@ static int marvell_suspend(struct phy_device *phydev) /* Suspend the fiber mode first */ if (!(phydev->supported & SUPPORTED_FIBRE)) { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_M1111_FIBER); if (err < 0) goto error; @@ -1320,7 +1328,7 @@ static int marvell_suspend(struct phy_device *phydev) goto error; /* Then, the copper link */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) goto error; } @@ -1329,7 +1337,7 @@ static int marvell_suspend(struct phy_device *phydev) return genphy_suspend(phydev); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_M1111_COPPER); return err; } @@ -1344,7 +1352,7 @@ static int marvell_resume(struct phy_device *phydev) /* Resume the fiber mode first */ if (!(phydev->supported & SUPPORTED_FIBRE)) { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_M1111_FIBER); if (err < 0) goto error; @@ -1354,7 +1362,7 @@ static int marvell_resume(struct phy_device *phydev) goto error; /* Then, the copper link */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) goto error; } @@ -1363,7 +1371,7 @@ static int marvell_resume(struct phy_device *phydev) return genphy_resume(phydev); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_M1111_COPPER); return err; } @@ -1391,15 +1399,14 @@ static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo * wol->supported = WAKE_MAGIC; wol->wolopts = 0; - if (phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_WOL_PAGE) < 0) + if (marvell_set_page(phydev, MII_88E1318S_PHY_WOL_PAGE) < 0) return; if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) wol->wolopts |= WAKE_MAGIC; - if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0) + if (marvell_set_page(phydev, 0x00) < 0) return; } @@ -1407,11 +1414,11 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w { int err, oldpage, temp; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); + oldpage = marvell_get_page(phydev); if (wol->wolopts & WAKE_MAGIC) { /* Explicitly switch to page 0x00, just to be sure */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00); + err = marvell_set_page(phydev, 0x00); if (err < 0) return err; @@ -1422,8 +1429,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_LED_PAGE); + err = marvell_set_page(phydev, MII_88E1318S_PHY_LED_PAGE); if (err < 0) return err; @@ -1436,8 +1442,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_WOL_PAGE); + err = marvell_set_page(phydev, MII_88E1318S_PHY_WOL_PAGE); if (err < 0) return err; @@ -1466,8 +1471,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; } else { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_WOL_PAGE); + err = marvell_set_page(phydev, MII_88E1318S_PHY_WOL_PAGE); if (err < 0) return err; @@ -1480,7 +1484,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w return err; } - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + err = marvell_set_page(phydev, oldpage); if (err < 0) return err; @@ -1515,9 +1519,8 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) int err, oldpage, val; u64 ret; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - stat.page); + oldpage = marvell_get_page(phydev); + err = marvell_set_page(phydev, stat.page); if (err < 0) return UINT64_MAX; @@ -1530,7 +1533,7 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) ret = priv->stats[i]; } - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + marvell_set_page(phydev, oldpage); return ret; } -- cgit v1.2.3 From 23beb38f1911a5d0dc54300a5cbed3cce69941de Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 17 May 2017 03:26:04 +0200 Subject: net: phy: marvell: checkpatch - Fix remaining long lines Fold lines longer than 80 characters Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index d510eda92af5..88cd97b44ba6 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -217,9 +217,11 @@ static int marvell_config_intr(struct phy_device *phydev) int err; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + err = phy_write(phydev, MII_M1011_IMASK, + MII_M1011_IMASK_INIT); else - err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + err = phy_write(phydev, MII_M1011_IMASK, + MII_M1011_IMASK_CLEAR); return err; } @@ -1394,7 +1396,8 @@ static int m88e1121_did_interrupt(struct phy_device *phydev) return 0; } -static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +static void m88e1318_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) { wol->supported = WAKE_MAGIC; wol->wolopts = 0; @@ -1410,7 +1413,8 @@ static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo * return; } -static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +static int m88e1318_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) { int err, oldpage, temp; -- cgit v1.2.3 From 6a792e8158a2597418a0833c7e350328e209f318 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Fri, 5 May 2017 15:50:30 +0200 Subject: can: m_can: move Message RAM initialization to function To avoid possible ECC/parity checksum errors when reading an uninitialized buffer, the entire Message RAM is initialized when probing the driver. This initialization is done in the same function reading the Device Tree properties. This patch moves the RAM initialization to a separate function so it can be called separately from device initialization from Device Tree. Signed-off-by: Quentin Schulz Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index bf8fdaeb955e..5da1bdb202a3 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1489,11 +1489,23 @@ static int register_m_can_dev(struct net_device *dev) return register_candev(dev); } +static void m_can_init_ram(struct m_can_priv *priv) +{ + int end, i, start; + + /* initialize the entire Message RAM in use to avoid possible + * ECC/parity checksum errors when reading an uninitialized buffer + */ + start = priv->mcfg[MRAM_SIDF].off; + end = priv->mcfg[MRAM_TXB].off + + priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE; + for (i = start; i < end; i += 4) + writel(0x0, priv->mram_base + i); +} + static void m_can_of_parse_mram(struct m_can_priv *priv, const u32 *mram_config_vals) { - int i, start, end; - priv->mcfg[MRAM_SIDF].off = mram_config_vals[0]; priv->mcfg[MRAM_SIDF].num = mram_config_vals[1]; priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off + @@ -1529,15 +1541,7 @@ static void m_can_of_parse_mram(struct m_can_priv *priv, priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num, priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num); - /* initialize the entire Message RAM in use to avoid possible - * ECC/parity checksum errors when reading an uninitialized buffer - */ - start = priv->mcfg[MRAM_SIDF].off; - end = priv->mcfg[MRAM_TXB].off + - priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE; - for (i = start; i < end; i += 4) - writel(0x0, priv->mram_base + i); - + m_can_init_ram(priv); } static int m_can_plat_probe(struct platform_device *pdev) -- cgit v1.2.3 From 8a3f3f24a829c80d8d451e75e887912c3905dfd0 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Fri, 5 May 2017 15:50:31 +0200 Subject: can: m_can: make m_can_start and m_can_stop symmetric This moves clocks gating outside of the m_can_stop function as the m_can_start function does not (and cannot, at least in current implementation) ungate clocks. This way, both functions can now be used symmetrically. Signed-off-by: Quentin Schulz Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 5da1bdb202a3..6115dede671e 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1324,9 +1324,6 @@ static void m_can_stop(struct net_device *dev) /* disable all interrupts */ m_can_disable_all_interrupts(priv); - clk_disable_unprepare(priv->hclk); - clk_disable_unprepare(priv->cclk); - /* set the state as STOPPED */ priv->can.state = CAN_STATE_STOPPED; } @@ -1338,6 +1335,8 @@ static int m_can_close(struct net_device *dev) netif_stop_queue(dev); napi_disable(&priv->napi); m_can_stop(dev); + clk_disable_unprepare(priv->hclk); + clk_disable_unprepare(priv->cclk); free_irq(dev->irq, dev); close_candev(dev); can_led_event(dev, CAN_LED_EVENT_STOP); -- cgit v1.2.3 From ef7b8aa8ca4acdd0541c622230de93bb3389ef41 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Fri, 5 May 2017 15:50:32 +0200 Subject: can: m_can: factorize clock gating and ungating This creates a function to ungate M_CAN clocks and another to gate the same clocks, then swaps all gating/ungating code with their respective function. Signed-off-by: Quentin Schulz Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 45 +++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 6115dede671e..653b304d7091 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -621,10 +621,8 @@ static int __m_can_get_berr_counter(const struct net_device *dev, return 0; } -static int m_can_get_berr_counter(const struct net_device *dev, - struct can_berr_counter *bec) +static int m_can_clk_start(struct m_can_priv *priv) { - struct m_can_priv *priv = netdev_priv(dev); int err; err = clk_prepare_enable(priv->hclk); @@ -632,15 +630,31 @@ static int m_can_get_berr_counter(const struct net_device *dev, return err; err = clk_prepare_enable(priv->cclk); - if (err) { + if (err) clk_disable_unprepare(priv->hclk); - return err; - } - __m_can_get_berr_counter(dev, bec); + return err; +} +static void m_can_clk_stop(struct m_can_priv *priv) +{ clk_disable_unprepare(priv->cclk); clk_disable_unprepare(priv->hclk); +} + +static int m_can_get_berr_counter(const struct net_device *dev, + struct can_berr_counter *bec) +{ + struct m_can_priv *priv = netdev_priv(dev); + int err; + + err = m_can_clk_start(priv); + if (err) + return err; + + __m_can_get_berr_counter(dev, bec); + + m_can_clk_stop(priv); return 0; } @@ -1276,19 +1290,15 @@ static int m_can_open(struct net_device *dev) struct m_can_priv *priv = netdev_priv(dev); int err; - err = clk_prepare_enable(priv->hclk); + err = m_can_clk_start(priv); if (err) return err; - err = clk_prepare_enable(priv->cclk); - if (err) - goto exit_disable_hclk; - /* open the can device */ err = open_candev(dev); if (err) { netdev_err(dev, "failed to open can device\n"); - goto exit_disable_cclk; + goto exit_disable_clks; } /* register interrupt handler */ @@ -1310,10 +1320,8 @@ static int m_can_open(struct net_device *dev) exit_irq_fail: close_candev(dev); -exit_disable_cclk: - clk_disable_unprepare(priv->cclk); -exit_disable_hclk: - clk_disable_unprepare(priv->hclk); +exit_disable_clks: + m_can_clk_stop(priv); return err; } @@ -1335,8 +1343,7 @@ static int m_can_close(struct net_device *dev) netif_stop_queue(dev); napi_disable(&priv->napi); m_can_stop(dev); - clk_disable_unprepare(priv->hclk); - clk_disable_unprepare(priv->cclk); + m_can_clk_stop(priv); free_irq(dev->irq, dev); close_candev(dev); can_led_event(dev, CAN_LED_EVENT_STOP); -- cgit v1.2.3 From d14ccea0e71a55ad02bf4e1cb378bbece282d5cf Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Fri, 5 May 2017 15:50:33 +0200 Subject: can: m_can: add deep Suspend/Resume support This adds Power Management deep Suspend/Resume support for Bosch M_CAN chip. When entering deep sleep, the clocks are gated, the interrupts are disabled. When resuming from deep sleep, the chip needs to be reinitialized, the clocks ungated and the interrupts enabled. Signed-off-by: Quentin Schulz Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 653b304d7091..f4947a74b65f 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1668,6 +1668,8 @@ failed_ret: return ret; } +/* TODO: runtime PM with power down or sleep mode */ + static __maybe_unused int m_can_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); @@ -1676,10 +1678,10 @@ static __maybe_unused int m_can_suspend(struct device *dev) if (netif_running(ndev)) { netif_stop_queue(ndev); netif_device_detach(ndev); + m_can_stop(ndev); + m_can_clk_stop(priv); } - /* TODO: enter low power */ - priv->can.state = CAN_STATE_SLEEPING; return 0; @@ -1690,11 +1692,18 @@ static __maybe_unused int m_can_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct m_can_priv *priv = netdev_priv(ndev); - /* TODO: exit low power */ + m_can_init_ram(priv); priv->can.state = CAN_STATE_ERROR_ACTIVE; if (netif_running(ndev)) { + int ret; + + ret = m_can_clk_start(priv); + if (ret) + return ret; + + m_can_start(ndev); netif_device_attach(ndev); netif_start_queue(ndev); } -- cgit v1.2.3 From 86a6129ae209156baef04f668a4fd13f2c9590a4 Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Mon, 1 May 2017 13:35:12 -0700 Subject: Bluetooth: Add support for Intel Bluetooth device 9460/9560 [8087:0aaa] This patch adds support for Intel Bluetooth device 9460/9560 also known as Jefferson Peak (JfP). The firmware downloading mechanism is same as previous generation. So include the new USB product identifier and whitelist the hardware variant. T: Bus=01 Lev=01 Prnt=01 Port=09 Cnt=04 Dev#= 5 Spd=12 MxCh= 0 D: Ver= 2.01 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=8087 ProdID=0aaa Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 64 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms Bootloader version: < HCI Command: Intel Read Version (0x3f|0x0005) plen 0 > HCI Event: Command Complete (0x0e) plen 13 Intel Read Version (0x3f|0x0005) ncmd 32 Status: Success (0x00) Hardware platform: 0x37 Hardware variant: 0x11 Hardware revision: 0.0 Firmware variant: 0x06 Firmware revision: 0.1 Firmware build: 42-52.2015 Firmware patch: 0 Signed-off-by: Tedd Ho-Jeong An Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7fa373b428f8..278e81186150 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -336,6 +336,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW }, { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL }, + { USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_NEW }, /* Other Intel Bluetooth devices */ { USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01), @@ -2036,6 +2037,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) switch (ver.hw_variant) { case 0x0b: /* SfP */ case 0x0c: /* WsP */ + case 0x11: /* JfP */ case 0x12: /* ThP */ break; default: @@ -2138,6 +2140,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) * Currently the supported hardware variants are: * 11 (0x0b) for iBT3.0 (LnP/SfP) * 12 (0x0c) for iBT3.5 (WsP) + * 17 (0x11) for iBT3.5 (JfP) + * 18 (0x12) for iBT3.5 (ThP) */ snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi", le16_to_cpu(ver.hw_variant), -- cgit v1.2.3 From 76c4969fecb174c37db4ec8a8e245e0e1c0b07ba Mon Sep 17 00:00:00 2001 From: Tobias Regnery Date: Tue, 2 May 2017 15:15:01 +0200 Subject: Bluetooth: hci_uart: fix kconfig dependency We see the following link error with CONFIG_BT_HCIUART=y, CONFIG_BT_HCIUART_LL=y and CONFIG_SERIAL_DEV_BUS=m: drivers/built-in.o: In function 'll_close': supp.c:(.text+0x55add4): undefined reference to 'serdev_device_close' supp.c:(.text+0x55add4): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol 'serdev_device_close' drivers/built-in.o: In function 'll_open': supp.c:(.text+0x55aed0): undefined reference to 'serdev_device_open' supp.c:(.text+0x55aed0): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol 'serdev_device_open' drivers/built-in.o: In function `hci_ti_probe': supp.c:(.text+0x55b00c): undefined reference to 'hci_uart_register_device' supp.c:(.text+0x55b00c): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol 'hci_uart_register_device' drivers/built-in.o: In function `ll_setup': supp.c:(.text+0x55b08c): undefined reference to 'serdev_device_set_flow_control' supp.c:(.text+0x55b08c): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol 'serdev_device_set_flow_control' supp.c:(.text+0x55b324): undefined reference to 'serdev_device_set_baudrate' supp.c:(.text+0x55b324): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol 'serdev_device_set_baudrate' drivers/built-in.o: In function 'll_init': supp.c:(.init.text+0x1b508): undefined reference to '__serdev_device_driver_register' supp.c:(.init.text+0x1b508): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol '__serdev_device_driver_register' Fix this by dependig BT_HCIUART_LL on the BT_HCIUART_SERDEV symbol. This implies a dependency on BT_HCIUART and hci_ll.c is only compiled in if SERIAl_DEV_BUS is built in or SERIAL_DEV_BUS and BT_HCIUART are modules. Fixes: 371805522f87 ("bluetooth: hci_uart: add LL protocol serdev driver support") Signed-off-by: Tobias Regnery Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 737d93ef27c5..e5fd24d90b0a 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -131,7 +131,7 @@ config BT_HCIUART_ATH3K config BT_HCIUART_LL bool "HCILL protocol support" - depends on BT_HCIUART + depends on BT_HCIUART_SERDEV help HCILL (HCI Low Level) is a serial protocol for communication between Bluetooth device and host. This protocol is required for -- cgit v1.2.3 From dec2c92880cc5435381d50e3045ef018a762a917 Mon Sep 17 00:00:00 2001 From: Dean Jenkins Date: Fri, 5 May 2017 16:27:06 +0100 Subject: Bluetooth: hci_ldisc: Use rwlocking to avoid closing proto races When HCI_UART_PROTO_READY is in the set state, the Data Link protocol layer (proto) is bound to the HCI UART driver. This state allows the registered proto function pointers to be used by the HCI UART driver. When unbinding (closing) the Data Link protocol layer, the proto function pointers much be prevented from being used immediately before running the proto close function pointer. Otherwise, there is a risk that a proto non-close function pointer is used during or after the proto close function pointer is used. The consequences are likely to be a kernel crash because the proto close function pointer will free resources used in the Data Link protocol layer. Therefore, add a reader writer lock (rwlock) solution to prevent the close proto function pointer from running by using write_lock_irqsave() whilst the other proto function pointers are protected using read_lock(). This means HCI_UART_PROTO_READY can safely be cleared in the knowledge that no proto function pointers are running. When flag HCI_UART_PROTO_READY is put into the clear state, proto close function pointer can safely be run. Note flag HCI_UART_PROTO_SET being in the set state prevents the proto open function pointer from being run so there is no race condition between proto open and close function pointers. Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_ldisc.c | 40 +++++++++++++++++++++++++++++++++++----- drivers/bluetooth/hci_uart.h | 1 + 2 files changed, 36 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 2edd30556956..8397b716fa65 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -114,8 +114,12 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) struct sk_buff *skb = hu->tx_skb; if (!skb) { + read_lock(&hu->proto_lock); + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) skb = hu->proto->dequeue(hu); + + read_unlock(&hu->proto_lock); } else { hu->tx_skb = NULL; } @@ -125,18 +129,23 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { + read_lock(&hu->proto_lock); + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) - return 0; + goto no_schedule; if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); - return 0; + goto no_schedule; } BT_DBG(""); schedule_work(&hu->write_work); +no_schedule: + read_unlock(&hu->proto_lock); + return 0; } EXPORT_SYMBOL_GPL(hci_uart_tx_wakeup); @@ -237,9 +246,13 @@ static int hci_uart_flush(struct hci_dev *hdev) tty_ldisc_flush(tty); tty_driver_flush_buffer(tty); + read_lock(&hu->proto_lock); + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) hu->proto->flush(hu); + read_unlock(&hu->proto_lock); + return 0; } @@ -261,10 +274,15 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb), skb->len); - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) + read_lock(&hu->proto_lock); + + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + read_unlock(&hu->proto_lock); return -EUNATCH; + } hu->proto->enqueue(hu, skb); + read_unlock(&hu->proto_lock); hci_uart_tx_wakeup(hu); @@ -460,6 +478,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->write_work, hci_uart_write_work); + rwlock_init(&hu->proto_lock); + /* Flush any pending characters in the driver */ tty_driver_flush_buffer(tty); @@ -475,6 +495,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) { struct hci_uart *hu = tty->disc_data; struct hci_dev *hdev; + unsigned long flags; BT_DBG("tty %p", tty); @@ -490,7 +511,11 @@ static void hci_uart_tty_close(struct tty_struct *tty) cancel_work_sync(&hu->write_work); - if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) { + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + write_lock_irqsave(&hu->proto_lock, flags); + clear_bit(HCI_UART_PROTO_READY, &hu->flags); + write_unlock_irqrestore(&hu->proto_lock, flags); + if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags)) hci_unregister_dev(hdev); @@ -549,13 +574,18 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, if (!hu || tty != hu->tty) return; - if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) + read_lock(&hu->proto_lock); + + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + read_unlock(&hu->proto_lock); return; + } /* It does not need a lock here as it is already protected by a mutex in * tty caller */ hu->proto->recv(hu, data, count); + read_unlock(&hu->proto_lock); if (hu->hdev) hu->hdev->stat.byte_rx += count; diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 2b05e557fad0..c6e9e1cf63f8 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -87,6 +87,7 @@ struct hci_uart { struct work_struct write_work; const struct hci_uart_proto *proto; + rwlock_t proto_lock; /* Stop work for proto close */ void *priv; struct sk_buff *tx_skb; -- cgit v1.2.3 From c42c88e6c84d081397965a024fa09ab9b11e7938 Mon Sep 17 00:00:00 2001 From: Tobias Regnery Date: Mon, 8 May 2017 11:39:11 +0200 Subject: Bluetooth: hci_nokia: select BT_HCIUART_H4 We see the following build failure with CONFIG_BT_HCIUART_NOKIA=y and CONFIG_BT_HCIUART_H4=n: drivers/bluetooth/hci_nokia.c: In function 'nokia_recv': drivers/bluetooth/hci_nokia.c:644:18: error: implicit declaration of function 'h4_recv_buf' [-Werror=implicit-function-declaration] ... Fix this by selecting the BT_HCIUART_H4 symbol like all the other users of the protocoll. Fixes: 7bb318680e86 ("Bluetooth: add nokia driver") Signed-off-by: Tobias Regnery Reviewed-by: Sebastian Reichel Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index e5fd24d90b0a..35952a94875e 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -97,6 +97,7 @@ config BT_HCIUART_NOKIA depends on BT_HCIUART depends on BT_HCIUART_SERDEV depends on PM + select BT_HCIUART_H4 help Nokia H4+ is serial protocol for communication between Bluetooth device and host. This protocol is required for Bluetooth devices -- cgit v1.2.3 From 9fe929aaace6a3019dd64a70063cc7b0bb956a4e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 21 Apr 2017 13:05:04 +0100 Subject: brcmfmac: add firmware feature detection for gscan feature Detect gscan support in firmware by doing pfn_gscan_cfg iovar with invalid version. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/feature.c | 22 +++++++- .../wireless/broadcom/brcm80211/brcmfmac/feature.h | 4 +- .../broadcom/brcm80211/brcmfmac/fwil_types.h | 59 ++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 62985f2c0853..8c7ef59944f0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -27,6 +27,7 @@ #include "feature.h" #include "common.h" +#define BRCMF_FW_UNSUPPORTED 23 /* * expand feature list to array of feature strings. @@ -113,6 +114,22 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, } } +static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp, + enum brcmf_feat_id id, char *name, + const void *data, size_t len) +{ + int err; + + err = brcmf_fil_iovar_data_set(ifp, name, data, len); + if (err != -BRCMF_FW_UNSUPPORTED) { + brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); + ifp->drvr->feat_flags |= BIT(id); + } else { + brcmf_dbg(TRACE, "%s feature check failed: %d\n", + brcmf_feat_names[id], err); + } +} + static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp) { char caps[256]; @@ -136,11 +153,14 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) { struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); struct brcmf_pno_macaddr_le pfn_mac; + struct brcmf_gscan_config gscan_cfg; u32 wowl_cap; s32 err; brcmf_feat_firmware_capabilities(ifp); - + memset(&gscan_cfg, 0, sizeof(gscan_cfg)); + brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN, "pfn_gscan_cfg", + &gscan_cfg, sizeof(gscan_cfg)); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn"); if (drvr->bus_if->wowl_supported) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index db4733a95e28..c1dbd17506aa 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -31,6 +31,7 @@ * WOWL_GTK: (WOWL) GTK rekeying offload * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL. * MFP: 802.11w Management Frame Protection. + * GSCAN: enhanced scan offload feature. */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -44,7 +45,8 @@ BRCMF_FEAT_DEF(WOWL_ND) \ BRCMF_FEAT_DEF(WOWL_GTK) \ BRCMF_FEAT_DEF(WOWL_ARP_ND) \ - BRCMF_FEAT_DEF(MFP) + BRCMF_FEAT_DEF(MFP) \ + BRCMF_FEAT_DEF(GSCAN) /* * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 9a1eb5ab6c4b..8c18fad3edc9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -835,4 +835,63 @@ struct brcmf_gtk_keyinfo_le { u8 replay_counter[BRCMF_RSN_REPLAY_LEN]; }; +/** + * struct brcmf_gscan_bucket_config - configuration data for channel bucket. + * + * @bucket_end_index: !unknown! + * @bucket_freq_multiple: !unknown! + * @flag: !unknown! + * @reserved: !unknown! + * @repeat: !unknown! + * @max_freq_multiple: !unknown! + */ +struct brcmf_gscan_bucket_config { + u8 bucket_end_index; + u8 bucket_freq_multiple; + u8 flag; + u8 reserved; + __le16 repeat; + __le16 max_freq_multiple; +}; + +/* version supported which must match firmware */ +#define BRCMF_GSCAN_CFG_VERSION 1 + +/** + * enum brcmf_gscan_cfg_flags - bit values for gscan flags. + * + * @BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS: send probe responses/beacons to host. + * @BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY: indicated only flags member is changed. + */ +enum brcmf_gscan_cfg_flags { + BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS = BIT(0), + BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY = BIT(7), +}; + +/** + * struct brcmf_gscan_config - configuration data for gscan. + * + * @version: version of the api to match firmware. + * @flags: flags according %enum brcmf_gscan_cfg_flags. + * @buffer_threshold: percentage threshold of buffer to generate an event. + * @swc_nbssid_threshold: number of BSSIDs with significant change that + * will generate an event. + * @swc_rssi_window_size: size of rssi cache buffer (max=8). + * @count_of_channel_buckets: number of array members in @bucket. + * @retry_threshold: !unknown! + * @lost_ap_window: !unknown! + * @bucket: array of channel buckets. + */ +struct brcmf_gscan_config { + __le16 version; + u8 flags; + u8 buffer_threshold; + u8 swc_nbssid_threshold; + u8 swc_rssi_window_size; + u8 count_of_channel_buckets; + u8 retry_threshold; + __le16 lost_ap_window; + struct brcmf_gscan_bucket_config bucket[1]; +}; + #endif /* FWIL_TYPES_H_ */ -- cgit v1.2.3 From 94ed6ffb7965aa09409a5ff7d17b2f84ed085c3c Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Fri, 21 Apr 2017 13:05:05 +0100 Subject: brcmfmac: move scheduled scan wiphy param setting to pno module As pno module is providing scheduled scan functionality have it taking care of setting related wiphy parameters as well. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 18 +++++------------- .../wireless/broadcom/brcm80211/brcmfmac/cfg80211.h | 2 ++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 10 ++++++++++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h | 8 ++++++++ 4 files changed, 25 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index cd1d6730eab7..2bf76bd765bd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6378,16 +6378,6 @@ err: return -ENOMEM; } -static void brcmf_wiphy_pno_params(struct wiphy *wiphy) -{ - /* scheduled scan settings */ - wiphy->max_sched_scan_reqs = 1; - wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; - wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; - wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; - wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD; -} - #ifdef CONFIG_PM static const struct wiphy_wowlan_support brcmf_wowlan_support = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -6434,6 +6424,7 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) const struct ieee80211_iface_combination *combo; struct ieee80211_supported_band *band; u16 max_interfaces = 0; + bool gscan; __le32 bandlist[3]; u32 n_bands; int err, i; @@ -6483,9 +6474,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) - brcmf_wiphy_pno_params(wiphy); - + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) { + gscan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_GSCAN); + brcmf_pno_wiphy_params(wiphy, gscan); + } /* vendor commands/events support */ wiphy->vendor_commands = brcmf_vendor_cmds; wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 8f19d95d4175..a1c2e0af1774 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -24,6 +24,8 @@ #include "fwil_types.h" #include "p2p.h" +#define BRCMF_SCAN_IE_LEN_MAX 2048 + #define WL_NUM_SCAN_MAX 10 #define WL_TLV_INFO_MAX 1024 #define WL_BSS_INFO_MAX 2048 diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c index 6c3bde83d070..a473445ed7c4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -239,3 +239,13 @@ int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, return ret; } +void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan) +{ + /* scheduled scan settings */ + wiphy->max_sched_scan_reqs = gscan ? 2 : 1; + wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; + wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; + wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; + wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD; +} + diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h index bae55b2af78c..07ec51f6bec1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h @@ -37,4 +37,12 @@ int brcmf_pno_clean(struct brcmf_if *ifp); int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, struct cfg80211_sched_scan_request *req); +/** + * brcmf_pno_wiphy_params - fill scheduled scan parameters in wiphy instance. + * + * @wiphy: wiphy instance to be used. + * @gscan: indicates whether the device has support for g-scan feature. + */ +void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan); + #endif /* _BRCMF_PNO_H */ -- cgit v1.2.3 From 83625a40165a01655db017fcc871c30e81e56ab4 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Wed, 26 Apr 2017 10:34:48 +0000 Subject: mwifiex: p2p client using same data path as station P2p client act as a station, data will be queued by DA instead of RA. This patch pass the sanity check, so that p2p client share the same data path with infrastruction station mode. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index bb2a467d8b13..6e76b302739b 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -1235,7 +1235,8 @@ mwifiex_queuing_ra_based(struct mwifiex_private *priv) * Currently we assume if we are in Infra, then DA=RA. This might not be * true in the future */ - if ((priv->bss_mode == NL80211_IFTYPE_STATION) && + if ((priv->bss_mode == NL80211_IFTYPE_STATION || + priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) && (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)) return false; -- cgit v1.2.3 From 21f569af9ab3608382482166ae9aba802b097e3f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 1 May 2017 12:36:59 -0700 Subject: mwifiex: initiate card-specific work atomically The non-atomic test + set is a little awkward here, and it technically means we might double-schedule work unnecessarily. AFAICT, this is not really a problem, since the extra "work" will be a no-op (the flag(s) will be cleared by then), but it's still an anti-pattern. Rewrite this to use the atomic test_and_set_bit() helper instead. Signed-off-by: Brian Norris Reviewed-by: Dmitry Torokhov Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 9 +++------ drivers/net/wireless/marvell/mwifiex/sdio.c | 16 +++++----------- 2 files changed, 8 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index ac62bce50e96..5f56e8e6d612 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2837,12 +2837,9 @@ static void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags)) - return; - - set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); - - schedule_work(&card->work); + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, + &card->work_flags)) + schedule_work(&card->work); } static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter) diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 0af1c6733c92..d38d31bb9b79 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -2533,12 +2533,8 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; - if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags)) - return; - - set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); - - schedule_work(&card->work); + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags)) + schedule_work(&card->work); } /* This function dumps FW information */ @@ -2546,11 +2542,9 @@ static void mwifiex_sdio_device_dump(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; - if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags)) - return; - - set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); - schedule_work(&card->work); + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, + &card->work_flags)) + schedule_work(&card->work); } /* Function to dump SDIO function registers and SDIO scratch registers in case -- cgit v1.2.3 From 6d7d579a8243b9db3a20e6a95ec726abae58aec4 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 1 May 2017 12:37:00 -0700 Subject: mwifiex: pcie: add card_reset() support Similar to the SDIO driver, we should implement this so that we will automatically reset the device whenever there's a command timeout or similar. Signed-off-by: Brian Norris Reviewed-by: Dmitry Torokhov Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 5f56e8e6d612..78688ff6ecd0 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2822,6 +2822,13 @@ static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter) mwifiex_upload_device_dump(adapter, drv_info, drv_info_size); } +static void mwifiex_pcie_card_reset_work(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + + pci_reset_function(card->dev); +} + static void mwifiex_pcie_work(struct work_struct *work) { struct pcie_service_card *card = @@ -2830,6 +2837,9 @@ static void mwifiex_pcie_work(struct work_struct *work) if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags)) mwifiex_pcie_device_dump_work(card->adapter); + if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, + &card->work_flags)) + mwifiex_pcie_card_reset_work(card->adapter); } /* This function dumps FW information */ @@ -2842,6 +2852,14 @@ static void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter) schedule_work(&card->work); } +static void mwifiex_pcie_card_reset(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + + if (!test_and_set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags)) + schedule_work(&card->work); +} + static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; @@ -3271,6 +3289,7 @@ static struct mwifiex_if_ops pcie_ops = { .cleanup_mpa_buf = NULL, .init_fw_port = mwifiex_pcie_init_fw_port, .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, + .card_reset = mwifiex_pcie_card_reset, .reg_dump = mwifiex_pcie_reg_dump, .device_dump = mwifiex_pcie_device_dump, .down_dev = mwifiex_pcie_down_dev, -- cgit v1.2.3 From 6a01d48d47c8985146e54a1f0ea57daf63d0f47b Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sat, 6 May 2017 23:42:20 +0800 Subject: wlcore: use memdup_user Use memdup_user() helper instead of open-coding to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/debugfs.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index de7e2a5fdffa..a2cb408be8aa 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -1149,15 +1149,9 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf, part.mem.start = *ppos; part.mem.size = bytes; - buf = kmalloc(bytes, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = copy_from_user(buf, user_buf, bytes); - if (ret) { - ret = -EFAULT; - goto err_out; - } + buf = memdup_user(user_buf, bytes); + if (IS_ERR(buf)) + return PTR_ERR(buf); mutex_lock(&wl->mutex); @@ -1197,7 +1191,6 @@ skip_write: if (ret == 0) *ppos += bytes; -err_out: kfree(buf); return ((ret == 0) ? bytes : ret); -- cgit v1.2.3 From aef9ae460742949e59453a03e5e0d5acb996be85 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 May 2017 13:46:58 -0500 Subject: rtlwifi: btcoex: Remove 21a 1ant configuration parameter In file halbtc8821a1ant.c, there are directives that depend on an undocumented configuration parameter BT_AUTO_REPORT_ONLY_8821A_1ANT that cannot be set from Kconfig. This parameter is replaced by a boolean in the main structure used by all routines. It still cannot be changed dynamically, but it is easier to document. Using a suggestion from Realtek, the auto report is turned on with this patch. Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 18 +++++++++--------- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.h | 2 -- .../wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 5 +++++ 3 files changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 5e9f3b0f7a25..bd5f752f153d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2116,6 +2116,7 @@ static void btc8821a1ant_init_hw_config(struct btc_coexist *btcoexist, void ex_btc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist, bool wifionly) { btc8821a1ant_init_hw_config(btcoexist, true, wifionly); + btcoexist->auto_report_1ant = true; } void ex_btc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist) @@ -2406,9 +2407,8 @@ void ex_btc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); -#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 1) - btc8821a1ant_monitor_bt_ctr(btcoexist); -#endif + if (btcoexist->auto_report_1ant) + btc8821a1ant_monitor_bt_ctr(btcoexist); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } @@ -2964,10 +2964,10 @@ void ex_btc8821a1ant_periodical(struct btc_coexist *btcoexist) "[BTCoex], ****************************************************************\n"); } -#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) - btc8821a1ant_query_bt_info(btcoexist); - btc8821a1ant_monitor_bt_ctr(btcoexist); -#else - coex_sta->special_pkt_period_cnt++; -#endif + if (!btcoexist->auto_report_1ant) { + btc8821a1ant_query_bt_info(btcoexist); + btc8821a1ant_monitor_bt_ctr(btcoexist); + } else { + coex_sta->special_pkt_period_cnt++; + } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h index 1bd1ebe3364e..d6dacf32a4c4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h @@ -27,8 +27,6 @@ * The following is for 8821A 1ANT BT Co-exist definition *=========================================== */ -#define BT_AUTO_REPORT_ONLY_8821A_1ANT 0 - #define BT_INFO_8821A_1ANT_B_FTP BIT7 #define BT_INFO_8821A_1ANT_B_A2DP BIT6 #define BT_INFO_8821A_1ANT_B_HID BIT5 diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index c8271135aaaa..ab2e31a44253 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -496,6 +496,11 @@ struct btc_coexist { enum btc_chip_interface chip_interface; struct btc_bt_link_info bt_link_info; + /* boolean variables to replace BT_AUTO_REPORT_ONLY_XXXXY_ZANT + * configuration parameters + */ + bool auto_report_1ant; + bool auto_report_2ant; bool initilized; bool stop_coex_dm; bool manual_control; -- cgit v1.2.3 From f66509e3d7c2ebbacfe1e9767e8e605ec7e9927b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 May 2017 13:46:59 -0500 Subject: rtlwifi: btcoex: Remove 23b 1ant configuration parameter In file halbtc8723b1ant.c, there are directives that depend on an undocumented configuration parameter BT_AUTO_REPORT_ONLY_8723B_1ANT that cannot be set from Kconfig. This parameter is replaced by a boolean in the main structure used by all routines. It still cannot be changed dynamically, but it is easier to document. The following routines are restored: halbtc8723b1ant_bt_auto_report() halbtc8723b1ant_set_bt_auto_report() halbtc8723b1ant_action_wifi_only() halbtc8723b1ant_monitor_bt_enable_disable() Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 122 +++++++++++++++++---- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 3 +- 2 files changed, 102 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 2003c8c51dcc..f23c9e3fbda1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -333,6 +333,35 @@ static void halbtc8723b1ant_update_bt_link_info(struct btc_coexist *btcoexist) bt_link_info->hid_only = false; } +static void halbtc8723b1ant_set_bt_auto_report(struct btc_coexist *btcoexist, + bool enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static void halbtc8723b1ant_bt_auto_report(struct btc_coexist *btcoexist, + bool force_exec, + bool enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723b1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + static void btc8723b1ant_set_sw_pen_tx_rate_adapt(struct btc_coexist *btcoexist, bool low_penalty_ra) { @@ -1099,6 +1128,57 @@ static void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist, } } +static void halbtc8723b1ant_action_wifi_only(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, false, false, BTC_ANT_PATH_PTA); +} + +/* check if BT is disabled */ +static void halbtc8723b1ant_monitor_bt_enable_disable(struct btc_coexist + *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static u32 bt_disable_cnt; + bool bt_active = true, bt_disabled; + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + } else { + bt_disable_cnt++; + if (bt_disable_cnt >= 2) + bt_disabled = true; + } + if (coex_sta->bt_disabled != bt_disabled) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + + coex_sta->bt_disabled = bt_disabled; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + if (bt_disabled) { + halbtc8723b1ant_action_wifi_only(btcoexist); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + } + } +} + /***************************************************** * * Non-Software Coex Mechanism start @@ -1638,6 +1718,7 @@ static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist, void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist) { halbtc8723b1ant_init_hw_config(btcoexist, true); + btcoexist->auto_report_1ant = true; } void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) @@ -1926,9 +2007,8 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); -#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 1) - halbtc8723b1ant_monitor_bt_ctr(btcoexist); -#endif + if (btcoexist->auto_report_1ant) + halbtc8723b1ant_monitor_bt_ctr(btcoexist); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } @@ -2247,14 +2327,15 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, } else { /* BT already NOT ignore Wlan active, do nothing here.*/ } -#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) - if (coex_sta->bt_info_ext & BIT4) { - /* BT auto report already enabled, do nothing */ - } else { - halbtc8723b1ant_bt_auto_report(btcoexist, FORCE_EXEC, - true); + if (!btcoexist->auto_report_1ant) { + if (coex_sta->bt_info_ext & BIT4) { + /* BT auto report already enabled, do nothing */ + } else { + halbtc8723b1ant_bt_auto_report(btcoexist, + FORCE_EXEC, + true); + } } -#endif } /* check BIT2 first ==> check if bt is under inquiry or page scan */ @@ -2425,16 +2506,15 @@ void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist) "[BTCoex], ****************************************************************\n"); } -#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) - halbtc8723b1ant_query_bt_info(btcoexist); - halbtc8723b1ant_monitor_bt_ctr(btcoexist); - halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); -#else - if (btc8723b1ant_is_wifi_status_changed(btcoexist) || - coex_dm->auto_tdma_adjust) { - halbtc8723b1ant_run_coexist_mechanism(btcoexist); + if (!btcoexist->auto_report_1ant) { + halbtc8723b1ant_query_bt_info(btcoexist); + halbtc8723b1ant_monitor_bt_ctr(btcoexist); + halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); + } else { + if (btc8723b1ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) { + halbtc8723b1ant_run_coexist_mechanism(btcoexist); + } + coex_sta->special_pkt_period_cnt++; } - - coex_sta->special_pkt_period_cnt++; -#endif } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 75f8094b7a34..7e91901122c3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -25,8 +25,6 @@ /********************************************************************** * The following is for 8723B 1ANT BT Co-exist definition **********************************************************************/ -#define BT_AUTO_REPORT_ONLY_8723B_1ANT 1 - #define BT_INFO_8723B_1ANT_B_FTP BIT7 #define BT_INFO_8723B_1ANT_B_A2DP BIT6 #define BT_INFO_8723B_1ANT_B_HID BIT5 @@ -138,6 +136,7 @@ struct coex_dm_8723b_1ant { }; struct coex_sta_8723b_1ant { + bool bt_disabled; bool bt_link_exist; bool sco_exist; bool a2dp_exist; -- cgit v1.2.3 From d6a82054f27b1af0c5b4e7377d9e8795f35a714c Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 May 2017 13:47:00 -0500 Subject: rtlwifi: btcoex: Remove 23b 2ant configuration parameter In file halbtc8723b2ant.c, there are directives that depend on an undocumented configuration parameter BT_AUTO_REPORT_ONLY_8723B_2ANT that cannot be set from Kconfig. This parameter is replaced by a boolean in the main structure used by all routines. It still cannot be changed dynamically, but it is easier to document. Routines halbtc8723b2ant_set_bt_auto_report(), and btc8723b2ant_bt_auto_report() are restored. Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 80 +++++++++++++++------- .../realtek/rtlwifi/btcoexist/halbtc8723b2ant.h | 2 - 2 files changed, 54 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 2f3946be4ce2..31965f0ef69d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -707,6 +707,36 @@ static void btc8723b2ant_dec_bt_pwr(struct btc_coexist *btcoexist, coex_dm->pre_dec_bt_pwr_lvl = coex_dm->cur_dec_bt_pwr_lvl; } +static +void halbtc8723b2ant_set_bt_auto_report(struct btc_coexist *btcoexist, + bool enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static +void btc8723b2ant_bt_auto_report(struct btc_coexist *btcoexist, + bool force_exec, bool enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723b2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + static void btc8723b2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, bool force_exec, u8 fw_dac_swing_lvl) { @@ -3666,6 +3696,7 @@ void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->auto_report_2ant = true; } void ex_btc8723b2ant_power_on_setting(struct btc_coexist *btcoexist) @@ -3966,9 +3997,8 @@ void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); -#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) - btc8723b2ant_monitor_bt_ctr(btcoexist); -#endif + if (btcoexist->auto_report_2ant) + btc8723b2ant_monitor_bt_ctr(btcoexist); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } @@ -4190,14 +4220,11 @@ void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, } else { /* BT already NOT ignore Wlan active, do nothing here.*/ } -#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) - if ((coex_sta->bt_info_ext & BIT4)) { - /* BT auto report already enabled, do nothing*/ - } else { - btc8723b2ant_bt_auto_report(btcoexist, FORCE_EXEC, - true); + if (!btcoexist->auto_report_2ant) { + if (!(coex_sta->bt_info_ext & BIT4)) + btc8723b2ant_bt_auto_report(btcoexist, + FORCE_EXEC, true); } -#endif } /* check BIT2 first ==> check if bt is under inquiry or page scan */ @@ -4347,21 +4374,22 @@ void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist) } } -#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) - btc8723b2ant_query_bt_info(btcoexist); -#else - btc8723b2ant_monitor_bt_ctr(btcoexist); - btc8723b2ant_monitor_wifi_ctr(btcoexist); + if (!btcoexist->auto_report_2ant) { + btc8723b2ant_query_bt_info(btcoexist); + } else { + btc8723b2ant_monitor_bt_ctr(btcoexist); + btc8723b2ant_monitor_wifi_ctr(btcoexist); - /* for some BT speakers that High-Priority pkts appear before - * playing, this will cause HID exist - */ - if ((coex_sta->high_priority_tx + coex_sta->high_priority_rx < 50) && - (bt_link_info->hid_exist)) - bt_link_info->hid_exist = false; - - if (btc8723b2ant_is_wifi_status_changed(btcoexist) || - coex_dm->auto_tdma_adjust) - btc8723b2ant_run_coexist_mechanism(btcoexist); -#endif + /* for some BT speakers that High-Priority pkts appear before + * playing, this will cause HID exist + */ + if ((coex_sta->high_priority_tx + + coex_sta->high_priority_rx < 50) && + (bt_link_info->hid_exist)) + bt_link_info->hid_exist = false; + + if (btc8723b2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + btc8723b2ant_run_coexist_mechanism(btcoexist); + } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index 18a35c7faba9..50726beaeead 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -28,8 +28,6 @@ /************************************************************************ * The following is for 8723B 2Ant BT Co-exist definition ************************************************************************/ -#define BT_AUTO_REPORT_ONLY_8723B_2ANT 1 - #define BT_INFO_8723B_2ANT_B_FTP BIT7 #define BT_INFO_8723B_2ANT_B_A2DP BIT6 #define BT_INFO_8723B_2ANT_B_HID BIT5 -- cgit v1.2.3 From 436e9c1bb77e7f9e50c63d32ad4238a8f723ebaf Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 May 2017 13:47:01 -0500 Subject: rtlwifi: btcoex: Remove 92e 2ant configuration parameter In file halbtc8192e2ant.c, there are directives that depend on an undocumented configuration parameter BT_AUTO_REPORT_ONLY_8192E_2ANT that cannot be set from Kconfig. This parameter is replaced by a boolean in the main structure used by all routines. It still cannot be changed dynamically, but it is easier to document. Upon the advice of Realtek, the auto report option is turned on with this patch. Routine btc8192e2ant_is_wifi_status_changed() is restored. Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8192e2ant.c | 68 ++++++++++++++++------ .../realtek/rtlwifi/btcoexist/halbtc8192e2ant.h | 2 - 2 files changed, 49 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c index 57e633dbf9a9..9015512ed647 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c @@ -456,6 +456,39 @@ static void btc8192e2ant_query_bt_info(struct btc_coexist *btcoexist) btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); } +static +bool btc8192e2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +{ + static bool pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + bool wifi_busy = false, under_4way = false, bt_hs_on = false; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + static void btc8192e2ant_update_bt_link_info(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; @@ -2886,9 +2919,8 @@ void ex_btc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", coex_sta->low_priority_rx, coex_sta->low_priority_tx); -#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 1) - btc8192e2ant_monitor_bt_ctr(btcoexist); -#endif + if (btcoexist->auto_report_2ant) + btc8192e2ant_monitor_bt_ctr(btcoexist); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } @@ -3078,14 +3110,12 @@ void ex_btc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, */ } -#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) - if ((coex_sta->bt_info_ext & BIT4)) { - /* BT auto report already enabled, do nothing */ - } else { - btc8192e2ant_bt_auto_report(btcoexist, FORCE_EXEC, - true); + if (!btcoexist->auto_report_2ant) { + if (!(coex_sta->bt_info_ext & BIT4)) + btc8192e2ant_bt_auto_report(btcoexist, + FORCE_EXEC, + true); } -#endif } /* check BIT2 first ==> check if bt is under inquiry or page scan */ @@ -3207,13 +3237,13 @@ void ex_btc8192e2ant_periodical(struct btc_coexist *btcoexist) "************************************************\n"); } -#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) - btc8192e2ant_query_bt_info(btcoexist); - btc8192e2ant_monitor_bt_ctr(btcoexist); - btc8192e2ant_monitor_bt_enable_disable(btcoexist); -#else - if (btc8192e2ant_is_wifi_status_changed(btcoexist) || - coex_dm->auto_tdma_adjust) - btc8192e2ant_run_coexist_mechanism(btcoexist); -#endif + if (!btcoexist->auto_report_2ant) { + btc8192e2ant_query_bt_info(btcoexist); + btc8192e2ant_monitor_bt_ctr(btcoexist); + btc8192e2ant_monitor_bt_enable_disable(btcoexist); + } else { + if (btc8192e2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + btc8192e2ant_run_coexist_mechanism(btcoexist); + } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h index fc0fa87ec404..a57d6947eaf7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h @@ -25,8 +25,6 @@ /***************************************************************** * The following is for 8192E 2Ant BT Co-exist definition *****************************************************************/ -#define BT_AUTO_REPORT_ONLY_8192E_2ANT 0 - #define BT_INFO_8192E_2ANT_B_FTP BIT7 #define BT_INFO_8192E_2ANT_B_A2DP BIT6 #define BT_INFO_8192E_2ANT_B_HID BIT5 -- cgit v1.2.3 From 7b5ca74959c31e16c1c9821a6249e777cd3a283f Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:10 -0500 Subject: rtlwifi: btcoex: 21a 2ant: set tdma with rssi states if bt rssi is high, adjust the duration of wifi to a longer period to let the wifi transmit under this bt profiling. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 91 +++++++--------------- 1 file changed, 28 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 841b4a83ab70..a0f2eb53a011 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3220,12 +3220,16 @@ static void btc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) /* HID+A2DP+PAN(EDR) */ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; - bt_info_ext = coex_sta->bt_info_ext; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); @@ -3235,44 +3239,32 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) else btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 14); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); - if (wifi_bw == BTC_WIFI_BW_LEGACY) { - /* for HID at 11b/g mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5a5a5a5a, 0xffff, 0x3); + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (wifi_bw == BTC_WIFI_BW_HT40) + btc8821a2ant_tdma_duration_adjust(btcoexist, true, + true, 3); + else + btc8821a2ant_tdma_duration_adjust(btcoexist, true, + false, 3); } else { - /* for HID quality & wifi performance balance at 11n mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5a5a5a5a, 0xffff, 0x3); + btc8821a2ant_tdma_duration_adjust(btcoexist, true, true, 3); } - if (BTC_WIFI_BW_HT40 == wifi_bw) { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, 3); - } - } else { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, 3); - } - } - - /* sw mechanism */ + /* sw mechanism */ + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, true, @@ -3286,33 +3278,6 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) false, 0x18); } } else { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, false, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, false, 3); - } - } else { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 3); - } - } - - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, true, -- cgit v1.2.3 From d86aa50608e1387cbd52ffc3905cf45e533e3991 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:11 -0500 Subject: rtlwifi: btcoex: 21a 2ant: refine btc8821a2ant_action_hid_a2dp For hid a2dp profiling, decrease the bt power because of the distance of bt is usually short, and do not adjust the wifi duration to a longer period since it may be interrupted by bt easily, set tdma instead. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 108 ++++++++------------- 1 file changed, 42 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index a0f2eb53a011..60386c7571e8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3295,19 +3295,46 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; u32 wifi_bw; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u8 ap_num = 0; - bt_info_ext = coex_sta->bt_info_ext; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 3, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 37); - if (BTC_RSSI_HIGH(bt_rssi_state)) - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); - else - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, 0x5); + btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (wifi_bw == BTC_WIFI_BW_LEGACY) { + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else if (BTC_RSSI_MEDIUM(bt_rssi_state)) + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } else { + /* only 802.11N mode we have to dec bt power to 4 degree */ + if (BTC_RSSI_HIGH(bt_rssi_state)) { + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &ap_num); + if (ap_num < 10) + btc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 4); + else + btc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 2); + } else if (BTC_RSSI_MEDIUM(bt_rssi_state)) { + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + } else { + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } + } if (wifi_bw == BTC_WIFI_BW_LEGACY) { btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); @@ -3319,36 +3346,15 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) 0x4); } - if (BTC_WIFI_BW_HT40 == wifi_bw) { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext & BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } - } else { - if (bt_info_ext & BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } - } + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + } else { + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + } - /* sw mechanism */ + /* sw mechanism */ + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, true, @@ -3362,36 +3368,6 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) false, 0x18); } } else { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext & BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } - } else { - if (bt_info_ext & BIT0) { - /*a2dp basic rate*/ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } else { - /*a2dp edr rate*/ - btc8821a2ant_tdma_duration_adjust(btcoexist, - true, true, - 2); - } - } - - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, true, -- cgit v1.2.3 From be04040108ae0520f21342e438b62c9d5bff859b Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:12 -0500 Subject: rtlwifi: btcoex: 21a 2ant: set wifi standby when halting of entering ips If the wifi is going to halt or entering power saving, set it standby and allocate resource to bt. Routine btc8821a2ant_wifi_off_hw_cfg() restored. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 60386c7571e8..162d40ddf06d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3555,6 +3555,26 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) } } +static void btc8821a2ant_wifi_off_hw_cfg(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[2] = {0}; + u32 fw_ver = 0; + + /* set wlan_act to low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* WiFi goto standby while GNT_BT 0-->1 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, h2c_parameter); + } else { + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + } +} + /************************************************************** * extern function start with ex_btc8821a2ant_ **************************************************************/ @@ -3841,6 +3861,7 @@ void ex_btc8821a2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], IPS ENTER notify\n"); coex_sta->under_ips = true; + btc8821a2ant_wifi_off_hw_cfg(btcoexist); btc8821a2ant_coex_all_off(btcoexist); } else if (BTC_IPS_LEAVE == type) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -4084,6 +4105,7 @@ void ex_btc8821a2ant_halt_notify(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Halt notify\n"); + btc8821a2ant_wifi_off_hw_cfg(btcoexist); btc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); ex_btc8821a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); } -- cgit v1.2.3 From 4a279c2b73fd1575f519b981bc8d5b9fe1392866 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:13 -0500 Subject: rtlwifi: btcoex: 21a 2ant: settings before wifi firmware is ready Before firmware is ready, set GNT_BT to high to let bt transmit. Routine ex_btc8821a2ant_pre_load_firmware() restored. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 162d40ddf06d..9aa140a46d46 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3609,6 +3609,43 @@ void ex_btc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist) btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); } +void ex_btc8821a2ant_pre_load_firmware(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ + + /** + * S0 or S1 setting and Local register setting(By the setting fw can get + * ant number, S0/S1, ... info) + * + * Local setting bit define + * BIT0: "0" for no antenna inverse; "1" for antenna inverse + * BIT1: "0" for internal switch; "1" for external switch + * BIT2: "0" for one antenna; "1" for two antenna + * NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and + * BIT2=0 + */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + u8tmp |= 0x1; /* antenna inverse */ + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x384, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + void ex_btc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; -- cgit v1.2.3 From eee87f26203f8157ee4bdcba8151169598ea7d26 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:14 -0500 Subject: rtlwifi: btcoex: 21a 2ant: add pnp notidy to avoid LPS/IPS mismatch When driver is going to sleep, it does not leave LPS/IPS, thus the BTCoex may have mismatch when driver wakes up. To avoid that, BTCoex needs to clear the IPS/LPS state when it receives a pnp notify, then it can properly set up the hw when driver wakes up. Routine ex_btc8821a2ant_pnp_notify() restored. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 9aa140a46d46..ca7649dca352 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -4147,6 +4147,24 @@ void ex_btc8821a2ant_halt_notify(struct btc_coexist *btcoexist) ex_btc8821a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); } +void ex_btc8821a2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify\n"); + + if (pnp_state == BTC_WIFI_PNP_SLEEP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to SLEEP\n"); + } else if (pnp_state == BTC_WIFI_PNP_WAKE_UP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to WAKE UP\n"); + ex_btc8821a2ant_init_hwconfig(btcoexist); + btc8821a2ant_init_coex_dm(btcoexist); + btc8821a2ant_query_bt_info(btcoexist); + } +} + void ex_btc8821a2ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; -- cgit v1.2.3 From 1f88d59e350eea7baadb657cb03f57f6816b3b95 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:15 -0500 Subject: rtlwifi: btcoex: 21a 2ant: run mechanism if status changes or auto adjust is set The driver will periodically ask the coex, and the coex only runs the mechanism when the status was changed or the auto adjust is set. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index ca7649dca352..0d97e214ee10 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3485,14 +3485,14 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) if (btc8821a2ant_is_common_action(btcoexist)) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Action 2-Ant common\n"); - coex_dm->reset_tdma_adjust = true; + coex_dm->auto_tdma_adjust = true; } else { if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], pre_algorithm = %d, cur_algorithm = %d\n", coex_dm->pre_algorithm, coex_dm->cur_algorithm); - coex_dm->reset_tdma_adjust = true; + coex_dm->auto_tdma_adjust = false; } switch (coex_dm->cur_algorithm) { case BT_8821A_2ANT_COEX_ALGO_SCO: @@ -4200,7 +4200,14 @@ void ex_btc8821a2ant_periodical(struct btc_coexist *btcoexist) "[BTCoex], ****************************************************************\n"); } - btc8821a2ant_query_bt_info(btcoexist); - btc8821a2ant_monitor_bt_ctr(btcoexist); - btc8821a2ant_monitor_wifi_ctr(btcoexist); + if (btcoexist->auto_report_2ant) { + btc8821a2ant_query_bt_info(btcoexist); + } else { + btc8821a2ant_monitor_bt_ctr(btcoexist); + btc8821a2ant_monitor_wifi_ctr(btcoexist); + + if (btc8821a2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + btc8821a2ant_run_coexist_mechanism(btcoexist); + } } -- cgit v1.2.3 From 728b610677012b3eb047641c80b3ef515130a177 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:16 -0500 Subject: rtlwifi: btcoex: 21a 2ant: init wlan when leave ips If the wifi is leaving ips, re-init the coex mechanisms, and before it is going into ips, the bt can just ignore the wifi activities. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 0d97e214ee10..cc354563cf35 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3899,11 +3899,15 @@ void ex_btc8821a2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], IPS ENTER notify\n"); coex_sta->under_ips = true; btc8821a2ant_wifi_off_hw_cfg(btcoexist); + btc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); btc8821a2ant_coex_all_off(btcoexist); } else if (BTC_IPS_LEAVE == type) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], IPS LEAVE notify\n"); coex_sta->under_ips = false; + ex_btc8821a2ant_init_hwconfig(btcoexist); + btc8821a2ant_init_coex_dm(btcoexist); + btc8821a2ant_query_bt_info(btcoexist); } } -- cgit v1.2.3 From a3b2ba8666b7947eb323368b5c6f751450e61766 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:17 -0500 Subject: rtlwifi: btcoex: 21a 2ant: refine bt info notify to have more profilings We add some profiling combinations when the bt notifies the coex mechanism to detect more situations and adjust the coex to fit to it. Also monitor if the wifi is under 5G mode, if so, the signals do net intefere each other, bt can just ignore it Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 167 +++++++++++++++------ .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.h | 4 + 2 files changed, 124 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index cc354563cf35..6c7023566802 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -4019,9 +4019,12 @@ void ex_btc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist, u8 bt_info = 0; u8 i, rsp_source = 0; bool bt_busy = false, limited_dig = false; - bool wifi_connected = false, bt_hs_on = false; + bool wifi_connected = false, wifi_under_5g = false; coex_sta->c2h_bt_info_req_sent = false; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); rsp_source = tmp_buf[0] & 0xf; if (rsp_source >= BT_INFO_SRC_8821A_2ANT_MAX) @@ -4044,16 +4047,35 @@ void ex_btc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist, } } + if (btcoexist->manual_control) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n"); + return; + } + if (BT_INFO_SRC_8821A_2ANT_WIFI_FW != rsp_source) { /* [3:0] */ coex_sta->bt_retry_cnt = coex_sta->bt_info_c2h[rsp_source][2]&0xf; coex_sta->bt_rssi = - coex_sta->bt_info_c2h[rsp_source][3]*2+10; + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; - coex_sta->bt_info_ext = - coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + + coex_sta->bt_tx_rx_mask = + (coex_sta->bt_info_c2h[rsp_source][2] & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + if (coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG 0x3C != + * 0x01 => Need to switch BT TRx Mask + */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x01\n"); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x01); + } /* Here we need to resend some wifi info to BT * because bt is reset and loss of the info @@ -4071,70 +4093,121 @@ void ex_btc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist, } - if ((coex_sta->bt_info_ext & BIT3)) { - btc8821a2ant_ignore_wlan_act(btcoexist, - FORCE_EXEC, false); - } else { - /* BT already NOT ignore Wlan active, do nothing here.*/ + if (!btcoexist->manual_control && !wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info = 0x%x!!\n", + coex_sta->bt_info_ext); + if ((coex_sta->bt_info_ext & BIT(3))) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit3=1, wifi_connected=%d\n", + wifi_connected); + if (wifi_connected) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + btc8821a2ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, + false); + } + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BT ext info bit3=0, wifi_connected=%d\n", + wifi_connected); + /* BT already NOT ignore Wlan active, do nothing + * here. + */ + if (!wifi_connected) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], BT ext info bit3 check, set BT to ignore Wlan active!!\n"); + btc8821a2ant_ignore_wlan_act( + btcoexist, FORCE_EXEC, true); + } + } } } - btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); /* check BIT2 first ==> check if bt is under inquiry or page scan*/ if (bt_info & BT_INFO_8821A_2ANT_B_INQ_PAGE) { coex_sta->c2h_bt_inquiry_page = true; - coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; } else { coex_sta->c2h_bt_inquiry_page = false; - if (bt_info == 0x1) { - /* connection exists but not busy*/ - coex_sta->bt_link_exist = true; - coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_CON_IDLE; - } else if (bt_info & BT_INFO_8821A_2ANT_B_CONNECTION) { - /* connection exists and some link is busy*/ - coex_sta->bt_link_exist = true; - if (bt_info & BT_INFO_8821A_2ANT_B_FTP) - coex_sta->pan_exist = true; - else - coex_sta->pan_exist = false; - if (bt_info & BT_INFO_8821A_2ANT_B_A2DP) - coex_sta->a2dp_exist = true; - else - coex_sta->a2dp_exist = false; - if (bt_info & BT_INFO_8821A_2ANT_B_HID) - coex_sta->hid_exist = true; - else - coex_sta->hid_exist = false; - if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) - coex_sta->sco_exist = true; - else - coex_sta->sco_exist = false; - coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; - } else { - coex_sta->bt_link_exist = false; + } + /* set link exist status */ + if (!(bt_info & BT_INFO_8821A_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8821A_2ANT_B_FTP) + coex_sta->pan_exist = true; + else coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_HID) + coex_sta->hid_exist = true; + else coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else coex_sta->sco_exist = false; - coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_IDLE; + + if ((!coex_sta->hid_exist) && + (!coex_sta->c2h_bt_inquiry_page) && + (!coex_sta->sco_exist)) { + if (coex_sta->high_priority_tx + + coex_sta->high_priority_rx >= 160) + coex_sta->hid_exist = true; } + } + + btc8821a2ant_update_bt_link_info(btcoexist); - btc8821a2ant_update_bt_link_info(btcoexist); + if (!(bt_info & BT_INFO_8821A_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_IDLE; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (bt_info == BT_INFO_8821A_2ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_CON_IDLE; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if ((bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8821A_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_SCO_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (bt_info & BT_INFO_8821A_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_ACL_BUSY; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_MAX; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); } - if (BT_8821A_2ANT_BT_STATUS_NON_IDLE == coex_dm->bt_status) + if ((coex_dm->bt_status == BT_8821A_2ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == BT_8821A_2ANT_BT_STATUS_SCO_BUSY) || + (coex_dm->bt_status == BT_8821A_2ANT_BT_STATUS_ACL_SCO_BUSY)) { bt_busy = true; - else + limited_dig = true; + } else { bt_busy = false; + limited_dig = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); - if (BT_8821A_2ANT_BT_STATUS_IDLE != coex_dm->bt_status) - limited_dig = true; - else - limited_dig = false; coex_dm->limited_dig = limited_dig; - btcoexist->btc_set(btcoexist, - BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); btc8821a2ant_run_coexist_mechanism(btcoexist); } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index 535ca10e910b..d268f424249f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -54,6 +54,9 @@ enum _BT_8821A_2ANT_BT_STATUS { BT_8821A_2ANT_BT_STATUS_IDLE = 0x0, BT_8821A_2ANT_BT_STATUS_CON_IDLE = 0x1, BT_8821A_2ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8821A_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8821A_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8821A_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, BT_8821A_2ANT_BT_STATUS_MAX }; @@ -143,6 +146,7 @@ struct coex_sta_8821a_2ant { u32 low_priority_tx; u32 low_priority_rx; u8 bt_rssi; + bool bt_tx_rx_mask; u8 pre_bt_rssi_state; u8 pre_wifi_rssi_state[4]; bool c2h_bt_info_req_sent; -- cgit v1.2.3 From e7dc3203337820effa8b442677693039dc8c3208 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:18 -0500 Subject: rtlwifi: btcoex: 21a 2ant: fix PTA unstable problem when hw init In the hardware initialisation stage, the PTA circuits may be unstable, so we reset it after 6 secs to fix the problem. dis_ver_info_cnt is used to indicate the time after init, and we can set PTA according to it. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 38 +++++++--------------- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.h | 2 ++ 2 files changed, 14 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 6c7023566802..acdba4268f71 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3598,6 +3598,7 @@ void ex_btc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist) /* Antenna config */ btc8821a2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, true, false); + coex_sta->dis_ver_info_cnt = 0; /* PTA parameter */ btc8821a2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); @@ -4245,36 +4246,21 @@ void ex_btc8821a2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) void ex_btc8821a2ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; - static u8 dis_ver_info_cnt; - struct btc_board_info *board_info = &btcoexist->board_info; - struct btc_stack_info *stack_info = &btcoexist->stack_info; - u32 fw_ver = 0, bt_patch_ver = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], ==========================Periodical===========================\n"); - if (dis_ver_info_cnt <= 5) { - dis_ver_info_cnt += 1; - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", - board_info->pg_ant_num, - board_info->btdm_ant_num, - board_info->btdm_ant_pos); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], BT stack/ hci ext ver = %s / %d\n", - stack_info->profile_notified ? "Yes" : "No", - stack_info->hci_version); - btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, - &bt_patch_ver); - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", - glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant, - fw_ver, bt_patch_ver, bt_patch_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); + if (coex_sta->dis_ver_info_cnt <= 5) { + coex_sta->dis_ver_info_cnt += 1; + if (coex_sta->dis_ver_info_cnt == 3) { + /* Antenna config to set 0x765 = 0x0 (GNT_BT control by + * PTA) after initial + */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Set GNT_BT control by PTA\n"); + btc8821a2ant_set_ant_path(btcoexist, + BTC_ANT_WIFI_AT_MAIN, false, false); + } } if (btcoexist->auto_report_2ant) { diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index d268f424249f..74edfd75875a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -168,6 +168,8 @@ struct coex_sta_8821a_2ant { u8 coex_table_type; bool force_lps_on; + + u8 dis_ver_info_cnt; }; /*=========================================== -- cgit v1.2.3 From 3acd1685d71e39f25bf9df9f389d45e71dda0718 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 14:01:19 -0500 Subject: rtlwifi: btcoex: 21a 2ant: remove unused antenna detection variables PSD and LNA are for antenna detection, but we do not use them for 8821A. Remove them and the corresponding display messages. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 13 ------------- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h | 4 ---- 2 files changed, 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index acdba4268f71..41943c34edff 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3747,14 +3747,6 @@ void ex_btc8821a2ant_display_coex_info(struct btc_coexist *btcoexist) ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? "uplink" : "downlink"))); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", - ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : - ((BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) - ? "idle" : ((BT_8821A_2ANT_BT_STATUS_CON_IDLE == - coex_dm->bt_status) ? "connected-idle" : "busy"))), - coex_sta->bt_rssi, coex_sta->bt_retry_cnt); - if (stack_info->profile_notified) { RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", @@ -3789,11 +3781,6 @@ void ex_btc8821a2ant_display_coex_info(struct btc_coexist *btcoexist) /* Sw mechanism*/ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Sw mechanism]============"); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "\r\n %-35s = %d/ %d/ %d/ %d ", - "SM1[ShRf/ LpRA/ LimDig/ btLna]", - coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, - coex_dm->limited_dig, coex_dm->cur_bt_lna_constrain); RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index 74edfd75875a..a1603e2d44e3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -79,10 +79,6 @@ struct coex_dm_8821a_2ant { /* fw mechanism */ bool pre_dec_bt_pwr_lvl; bool cur_dec_bt_pwr_lvl; - bool pre_bt_lna_constrain; - bool cur_bt_lna_constrain; - u8 pre_bt_psd_mode; - u8 cur_bt_psd_mode; u8 pre_fw_dac_swing_lvl; u8 cur_fw_dac_swing_lvl; bool cur_ignore_wlan_act; -- cgit v1.2.3 From 83339c6b159ea6429a1db40b0d9d1083ab574733 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 17 May 2017 12:14:41 +0800 Subject: tun: export skb_array This patch exports skb_array through tun_get_skb_array(). Caller can then manipulate skb array directly. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index bbd707b9ef7a..3cbfc5c707e3 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2626,6 +2626,19 @@ struct socket *tun_get_socket(struct file *file) } EXPORT_SYMBOL_GPL(tun_get_socket); +struct skb_array *tun_get_skb_array(struct file *file) +{ + struct tun_file *tfile; + + if (file->f_op != &tun_fops) + return ERR_PTR(-EINVAL); + tfile = file->private_data; + if (!tfile) + return ERR_PTR(-EBADFD); + return &tfile->tx_array; +} +EXPORT_SYMBOL_GPL(tun_get_skb_array); + module_init(tun_init); module_exit(tun_cleanup); MODULE_DESCRIPTION(DRV_DESCRIPTION); -- cgit v1.2.3 From 49f96fd0cb3808e5ff96573f28b3dceb16eb6998 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 17 May 2017 12:14:42 +0800 Subject: tap: export skb_array This patch exports skb_array through tap_get_skb_array(). Caller can then manipulate skb array directly. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tap.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 4d4173d25dd0..abdaf867774d 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -1193,6 +1193,19 @@ struct socket *tap_get_socket(struct file *file) } EXPORT_SYMBOL_GPL(tap_get_socket); +struct skb_array *tap_get_skb_array(struct file *file) +{ + struct tap_queue *q; + + if (file->f_op != &tap_fops) + return ERR_PTR(-EINVAL); + q = file->private_data; + if (!q) + return ERR_PTR(-EBADFD); + return &q->skb_array; +} +EXPORT_SYMBOL_GPL(tap_get_skb_array); + int tap_queue_resize(struct tap_dev *tap) { struct net_device *dev = tap->dev; -- cgit v1.2.3 From ac77cfd4258fb8174766a92d118436da7f9dabf1 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 17 May 2017 12:14:43 +0800 Subject: tun: support receiving skb through msg_control This patch makes tun_recvmsg() can receive from skb from its caller through msg_control. Vhost_net will be the first user. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3cbfc5c707e3..f8041f9c7e65 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1510,9 +1510,8 @@ out: static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, struct iov_iter *to, - int noblock) + int noblock, struct sk_buff *skb) { - struct sk_buff *skb; ssize_t ret; int err; @@ -1521,10 +1520,12 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, if (!iov_iter_count(to)) return 0; - /* Read frames from ring */ - skb = tun_ring_recv(tfile, noblock, &err); - if (!skb) - return err; + if (!skb) { + /* Read frames from ring */ + skb = tun_ring_recv(tfile, noblock, &err); + if (!skb) + return err; + } ret = tun_put_user(tun, tfile, skb, to); if (unlikely(ret < 0)) @@ -1544,7 +1545,7 @@ static ssize_t tun_chr_read_iter(struct kiocb *iocb, struct iov_iter *to) if (!tun) return -EBADFD; - ret = tun_do_read(tun, tfile, to, file->f_flags & O_NONBLOCK); + ret = tun_do_read(tun, tfile, to, file->f_flags & O_NONBLOCK, NULL); ret = min_t(ssize_t, ret, len); if (ret > 0) iocb->ki_pos = ret; @@ -1646,7 +1647,8 @@ static int tun_recvmsg(struct socket *sock, struct msghdr *m, size_t total_len, SOL_PACKET, TUN_TX_TIMESTAMP); goto out; } - ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT); + ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT, + m->msg_control); if (ret > (ssize_t)total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; -- cgit v1.2.3 From 3b4ba04acca8f98a62fd014a0826ea10bc93cde3 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 17 May 2017 12:14:44 +0800 Subject: tap: support receiving skb from msg_control This patch makes tap_recvmsg() can receive from skb from its caller through msg_control. Vhost_net will be the first user. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tap.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tap.c b/drivers/net/tap.c index abdaf867774d..9af3239d6ad5 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -824,15 +824,17 @@ done: static ssize_t tap_do_read(struct tap_queue *q, struct iov_iter *to, - int noblock) + int noblock, struct sk_buff *skb) { DEFINE_WAIT(wait); - struct sk_buff *skb; ssize_t ret = 0; if (!iov_iter_count(to)) return 0; + if (skb) + goto put; + while (1) { if (!noblock) prepare_to_wait(sk_sleep(&q->sk), &wait, @@ -856,6 +858,7 @@ static ssize_t tap_do_read(struct tap_queue *q, if (!noblock) finish_wait(sk_sleep(&q->sk), &wait); +put: if (skb) { ret = tap_put_user(q, skb, to); if (unlikely(ret < 0)) @@ -872,7 +875,7 @@ static ssize_t tap_read_iter(struct kiocb *iocb, struct iov_iter *to) struct tap_queue *q = file->private_data; ssize_t len = iov_iter_count(to), ret; - ret = tap_do_read(q, to, file->f_flags & O_NONBLOCK); + ret = tap_do_read(q, to, file->f_flags & O_NONBLOCK, NULL); ret = min_t(ssize_t, ret, len); if (ret > 0) iocb->ki_pos = ret; @@ -1155,7 +1158,8 @@ static int tap_recvmsg(struct socket *sock, struct msghdr *m, int ret; if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) return -EINVAL; - ret = tap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT); + ret = tap_do_read(q, &m->msg_iter, flags & MSG_DONTWAIT, + m->msg_control); if (ret > total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; -- cgit v1.2.3 From c67df11f6e48061e43e9bf9dade83fe268b47d27 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 17 May 2017 12:14:45 +0800 Subject: vhost_net: try batch dequing from skb array We used to dequeue one skb during recvmsg() from skb_array, this could be inefficient because of the bad cache utilization and spinlock touching for each packet. This patch tries to batch them by calling batch dequeuing helpers explicitly on the exported skb array and pass the skb back through msg_control for underlayer socket to finish the userspace copying. Batch dequeuing is also the requirement for more batching improvement on receive path. Tests were done by pktgen on tap with XDP1 in guest. Host is Intel(R) Xeon(R) CPU E5-2650 0 @ 2.00GHz. rx batch | pps 0 2.25Mpps 1 2.33Mpps (+3.56%) 4 2.33Mpps (+3.56%) 16 2.35Mpps (+4.44%) 64 2.42Mpps (+7.56%) <- Default rx batching 128 2.40Mpps (+6.67%) 256 2.38Mpps (+5.78%) Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/vhost/net.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index f61f852d6cfd..e3d7ea1288c6 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include @@ -85,6 +87,13 @@ struct vhost_net_ubuf_ref { struct vhost_virtqueue *vq; }; +#define VHOST_RX_BATCH 64 +struct vhost_net_buf { + struct sk_buff **queue; + int tail; + int head; +}; + struct vhost_net_virtqueue { struct vhost_virtqueue vq; size_t vhost_hlen; @@ -99,6 +108,8 @@ struct vhost_net_virtqueue { /* Reference counting for outstanding ubufs. * Protected by vq mutex. Writers must also take device mutex. */ struct vhost_net_ubuf_ref *ubufs; + struct skb_array *rx_array; + struct vhost_net_buf rxq; }; struct vhost_net { @@ -117,6 +128,71 @@ struct vhost_net { static unsigned vhost_net_zcopy_mask __read_mostly; +static void *vhost_net_buf_get_ptr(struct vhost_net_buf *rxq) +{ + if (rxq->tail != rxq->head) + return rxq->queue[rxq->head]; + else + return NULL; +} + +static int vhost_net_buf_get_size(struct vhost_net_buf *rxq) +{ + return rxq->tail - rxq->head; +} + +static int vhost_net_buf_is_empty(struct vhost_net_buf *rxq) +{ + return rxq->tail == rxq->head; +} + +static void *vhost_net_buf_consume(struct vhost_net_buf *rxq) +{ + void *ret = vhost_net_buf_get_ptr(rxq); + ++rxq->head; + return ret; +} + +static int vhost_net_buf_produce(struct vhost_net_virtqueue *nvq) +{ + struct vhost_net_buf *rxq = &nvq->rxq; + + rxq->head = 0; + rxq->tail = skb_array_consume_batched(nvq->rx_array, rxq->queue, + VHOST_RX_BATCH); + return rxq->tail; +} + +static void vhost_net_buf_unproduce(struct vhost_net_virtqueue *nvq) +{ + struct vhost_net_buf *rxq = &nvq->rxq; + + if (nvq->rx_array && !vhost_net_buf_is_empty(rxq)) { + skb_array_unconsume(nvq->rx_array, rxq->queue + rxq->head, + vhost_net_buf_get_size(rxq)); + rxq->head = rxq->tail = 0; + } +} + +static int vhost_net_buf_peek(struct vhost_net_virtqueue *nvq) +{ + struct vhost_net_buf *rxq = &nvq->rxq; + + if (!vhost_net_buf_is_empty(rxq)) + goto out; + + if (!vhost_net_buf_produce(nvq)) + return 0; + +out: + return __skb_array_len_with_tag(vhost_net_buf_get_ptr(rxq)); +} + +static void vhost_net_buf_init(struct vhost_net_buf *rxq) +{ + rxq->head = rxq->tail = 0; +} + static void vhost_net_enable_zcopy(int vq) { vhost_net_zcopy_mask |= 0x1 << vq; @@ -201,6 +277,7 @@ static void vhost_net_vq_reset(struct vhost_net *n) n->vqs[i].ubufs = NULL; n->vqs[i].vhost_hlen = 0; n->vqs[i].sock_hlen = 0; + vhost_net_buf_init(&n->vqs[i].rxq); } } @@ -503,15 +580,14 @@ out: mutex_unlock(&vq->mutex); } -static int peek_head_len(struct sock *sk) +static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk) { - struct socket *sock = sk->sk_socket; struct sk_buff *head; int len = 0; unsigned long flags; - if (sock->ops->peek_len) - return sock->ops->peek_len(sock); + if (rvq->rx_array) + return vhost_net_buf_peek(rvq); spin_lock_irqsave(&sk->sk_receive_queue.lock, flags); head = skb_peek(&sk->sk_receive_queue); @@ -537,10 +613,11 @@ static int sk_has_rx_data(struct sock *sk) static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) { + struct vhost_net_virtqueue *rvq = &net->vqs[VHOST_NET_VQ_RX]; struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX]; struct vhost_virtqueue *vq = &nvq->vq; unsigned long uninitialized_var(endtime); - int len = peek_head_len(sk); + int len = peek_head_len(rvq, sk); if (!len && vq->busyloop_timeout) { /* Both tx vq and rx socket were polled here */ @@ -561,7 +638,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) vhost_poll_queue(&vq->poll); mutex_unlock(&vq->mutex); - len = peek_head_len(sk); + len = peek_head_len(rvq, sk); } return len; @@ -699,6 +776,8 @@ static void handle_rx(struct vhost_net *net) /* On error, stop handling until the next kick. */ if (unlikely(headcount < 0)) goto out; + if (nvq->rx_array) + msg.msg_control = vhost_net_buf_consume(&nvq->rxq); /* On overrun, truncate and discard */ if (unlikely(headcount > UIO_MAXIOV)) { iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1); @@ -815,6 +894,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) struct vhost_net *n; struct vhost_dev *dev; struct vhost_virtqueue **vqs; + struct sk_buff **queue; int i; n = kvmalloc(sizeof *n, GFP_KERNEL | __GFP_REPEAT); @@ -826,6 +906,15 @@ static int vhost_net_open(struct inode *inode, struct file *f) return -ENOMEM; } + queue = kmalloc_array(VHOST_RX_BATCH, sizeof(struct sk_buff *), + GFP_KERNEL); + if (!queue) { + kfree(vqs); + kvfree(n); + return -ENOMEM; + } + n->vqs[VHOST_NET_VQ_RX].rxq.queue = queue; + dev = &n->dev; vqs[VHOST_NET_VQ_TX] = &n->vqs[VHOST_NET_VQ_TX].vq; vqs[VHOST_NET_VQ_RX] = &n->vqs[VHOST_NET_VQ_RX].vq; @@ -838,6 +927,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) n->vqs[i].done_idx = 0; n->vqs[i].vhost_hlen = 0; n->vqs[i].sock_hlen = 0; + vhost_net_buf_init(&n->vqs[i].rxq); } vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX); @@ -853,11 +943,14 @@ static struct socket *vhost_net_stop_vq(struct vhost_net *n, struct vhost_virtqueue *vq) { struct socket *sock; + struct vhost_net_virtqueue *nvq = + container_of(vq, struct vhost_net_virtqueue, vq); mutex_lock(&vq->mutex); sock = vq->private_data; vhost_net_disable_vq(n, vq); vq->private_data = NULL; + vhost_net_buf_unproduce(nvq); mutex_unlock(&vq->mutex); return sock; } @@ -912,6 +1005,7 @@ static int vhost_net_release(struct inode *inode, struct file *f) /* We do an extra flush before freeing memory, * since jobs can re-queue themselves. */ vhost_net_flush(n); + kfree(n->vqs[VHOST_NET_VQ_RX].rxq.queue); kfree(n->dev.vqs); kvfree(n); return 0; @@ -950,6 +1044,25 @@ err: return ERR_PTR(r); } +static struct skb_array *get_tap_skb_array(int fd) +{ + struct skb_array *array; + struct file *file = fget(fd); + + if (!file) + return NULL; + array = tun_get_skb_array(file); + if (!IS_ERR(array)) + goto out; + array = tap_get_skb_array(file); + if (!IS_ERR(array)) + goto out; + array = NULL; +out: + fput(file); + return array; +} + static struct socket *get_tap_socket(int fd) { struct file *file = fget(fd); @@ -1026,6 +1139,9 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) vhost_net_disable_vq(n, vq); vq->private_data = sock; + vhost_net_buf_unproduce(nvq); + if (index == VHOST_NET_VQ_RX) + nvq->rx_array = get_tap_skb_array(fd); r = vhost_vq_init_access(vq); if (r) goto err_used; -- cgit v1.2.3 From 8113b9c4000cd5027f4b4f39fba08c23a8dd9ef8 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:29 -0500 Subject: rtlwifi: btcoex: 21a 1ant: set tdma and coex table when wifi is idle When wifi is idle, bt could have more resources to transmit, so set the tdma and coex table to achieve this. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 34 +++++++++++++++------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index bd5f752f153d..087e3ffff2f0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1212,8 +1212,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x1a, 0, 0x58); break; case 32: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa, - 0x3, 0x10, 0x0); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35, + 0x3, 0x11, 0x11); break; case 33: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25, @@ -1231,6 +1231,10 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, btc8821a1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); break; + case 43: + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x30, + 0x3, 0x10, 0x11); + break; } } else { /* disable PS tdma */ @@ -1619,15 +1623,23 @@ static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist, return; } else if (bt_link_info->a2dp_only) { /* A2DP */ - if ((bt_rssi_state != BTC_RSSI_STATE_HIGH) && - (bt_rssi_state != BTC_RSSI_STATE_STAY_HIGH)) { + if (wifi_status == BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } else if ((bt_rssi_state != BTC_RSSI_STATE_HIGH) && + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { /* for low BT RSSI */ - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 11); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); coex_dm->auto_tdma_adjust = false; } - - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); } else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) { /* HID+A2DP */ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || @@ -1638,7 +1650,7 @@ static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist, } else { /*for low BT RSSI*/ btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 11); + true, 14); coex_dm->auto_tdma_adjust = false; } @@ -1647,13 +1659,13 @@ static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist, (bt_link_info->hid_exist && bt_link_info->pan_exist)) { /* PAN(OPP, FTP), HID+PAN(OPP, FTP) */ btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); coex_dm->auto_tdma_adjust = false; } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || (bt_link_info->hid_exist && bt_link_info->a2dp_exist && bt_link_info->pan_exist)) { /* A2DP+PAN(OPP, FTP), HID+A2DP+PAN(OPP, FTP) */ - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 43); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); coex_dm->auto_tdma_adjust = false; } else { -- cgit v1.2.3 From 2fb9ca230fc16889e6666525b5320d6aa050ee7e Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:30 -0500 Subject: rtlwifi: btcoex: 21a 1ant: more bt profiling when wifi receives special packet Consider bt profiling is sco or hid to set coex table and tdma. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 31 ++++++++++------------ 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 087e3ffff2f0..55cde3d85abd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1753,29 +1753,26 @@ void btc8821a1ant_action_wifi_connected_scan(struct btc_coexist *btcoexist) static void btc8821a1ant_act_wifi_conn_sp_pkt(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; - bool hs_connecting = false; - - btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); /* tdma and coex table */ - if (coex_dm->bt_status == BT_8821A_1ANT_BT_STATUS_ACL_BUSY) { - if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 22); - btc8821a1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); - } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 20); - btc8821a1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); - } - } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } + + if ((bt_link_info->hid_exist) && (bt_link_info->a2dp_exist)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if (bt_link_info->pan_exist) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } -- cgit v1.2.3 From bcd6f89c013cbf7575c31ad7ae4bdccfd8c70c70 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:31 -0500 Subject: rtlwifi: btcoex: 21a 1ant: shorten wifi slot when connected scan If the wifi is scanning when connected, it is better if the slot is shortened and the priority is increased. Otherwise bt a2dp may have low quality. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 55cde3d85abd..13d8ac23b17a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1730,23 +1730,23 @@ void btc8821a1ant_action_wifi_connected_scan(struct btc_coexist *btcoexist) /* tdma and coex table */ if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { - if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + if (bt_link_info->a2dp_exist) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); - } - } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == - coex_dm->bt_status) || - (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((coex_dm->bt_status == BT_8821A_1ANT_BT_STATUS_SCO_BUSY) || + (coex_dm->bt_status == + BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY)) { btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN); } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } -- cgit v1.2.3 From a4da86768a273bbfe69e18242c1dca475281a205 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:32 -0500 Subject: rtlwifi: btcoex: 21a 1ant: react to special packet when wifi is not scanning If wifi is not scanning, there may have some special and important packets such as DHCP or EAPOL or ARP packets. Set tdma and coex table to take care of them. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 13d8ac23b17a..f5a4640577c2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1799,7 +1799,11 @@ static void btc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); if (scan || link || roam) { - btc8821a1ant_action_wifi_connected_scan(btcoexist); + if (scan) + btc8821a1ant_action_wifi_connected_scan(btcoexist); + else + btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); return; -- cgit v1.2.3 From 24697534ffc06fb2847f10c6a2a9c5574583bb12 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:33 -0500 Subject: rtlwifi: btcoex: 21a 1ant: coex table and tdma settings for softap mode Monitor if the wifi is softap mode, and set the tdma and coex table accordingly. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 25 +++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index f5a4640577c2..6a434334a418 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1782,6 +1782,7 @@ static void btc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) bool wifi_busy = false; bool scan = false, link = false, roam = false; bool under_4way = false; + bool ap_enable = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], CoexForWifiConnect()===>\n"); @@ -1810,17 +1811,26 @@ static void btc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) } /* power save state*/ + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == - coex_dm->bt_status && !btcoexist->bt_link_info.hid_only) - btc8821a1ant_power_save_state(btcoexist, - BTC_PS_LPS_ON, 0x50, 0x4); - else + coex_dm->bt_status && !ap_enable && + !btcoexist->bt_link_info.hid_only) { + if (!wifi_busy && btcoexist->bt_link_info.a2dp_only) + /* A2DP */ + btc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + else + btc8821a1ant_power_save_state(btcoexist, BTC_PS_LPS_ON, + 0x50, 0x4); + } else { btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + } /* tdma and coex table */ - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); if (!wifi_busy) { if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist, @@ -1832,8 +1842,7 @@ static void btc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE); } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 5); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } @@ -1848,7 +1857,7 @@ static void btc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY); } else { - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } -- cgit v1.2.3 From 7f1045d0cf8748f38ac607ac7cf4d57428b235f8 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:34 -0500 Subject: rtlwifi: btcoex: 21a 1ant: wifi slot time adjustment Adjust wifi slot time to tune the performance of coexistence Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 38 ++++++++++++++++------ 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 6a434334a418..834cf08103b2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1107,8 +1107,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x3, 0x11, 0x10); break; case 6: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, - 0x3, 0x0, 0x0); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20, + 0x3, 0x11, 0x13); break; case 7: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc, @@ -1128,8 +1128,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0xa, 0x0, 0x40); break; case 11: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14, - 0x03, 0x10, 0x10); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, + 0x03, 0x10, 0x50); rssi_adjust_val = 20; break; case 12: @@ -1137,8 +1137,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x0a, 0x0, 0x50); break; case 13: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x18, - 0x18, 0x0, 0x10); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x12, + 0x12, 0x0, 0x50); break; case 14: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1e, @@ -1163,8 +1163,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x03, 0x11, 0x10); break; case 21: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15, - 0x03, 0x11, 0x10); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, + 0x03, 0x11, 0x11); break; case 22: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, @@ -1204,8 +1204,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x1a, 0x1, 0x10); break; case 30: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14, - 0x3, 0x10, 0x50); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x30, + 0x3, 0x10, 0x10); break; case 31: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a, @@ -1231,6 +1231,24 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, btc8821a1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); break; + case 40: + /* SoftAP only with no sta associated, BT disable, TDMA + * mode for power saving + * + * here softap mode screen off will cost 70-80mA for + * phone + */ + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18, + 0x00, 0x10, 0x24); + break; + case 41: + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, + 0x3, 0x11, 0x11); + break; + case 42: + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x20, + 0x3, 0x11, 0x11); + break; case 43: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x30, 0x3, 0x10, 0x11); -- cgit v1.2.3 From 93cfe89765ad017d3650c8b22be6aacd68189015 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:35 -0500 Subject: rtlwifi: btcoex: 21a 1ant: normal mode for retry limit when connected When wifi is connected, use normal mode to set retry limit. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 834cf08103b2..3d77d6bb48b1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2028,11 +2028,11 @@ static void btc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, - 1, 1); + 0, 1); } else { btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, - 1, 1); + 0, 1); } } else { btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, -- cgit v1.2.3 From af4295ad866e7c5182cc64065e6c2cf0eec965dc Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:36 -0500 Subject: rtlwifi: btcoex: 21a 1ant: mark packet high priority when scanning When the wifi notifies the coexistence it is going to scan, set the coex table to avoid issues when the scan result is empty. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 3d77d6bb48b1..13063f61e1f4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2524,6 +2524,19 @@ void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) return; } + if (type == BTC_SCAN_START) { + coex_sta->wifi_is_high_pri_task = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN START notify\n"); + + /* Force antenna setup for no scan result issue */ + btc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + } else { + coex_sta->wifi_is_high_pri_task = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN FINISH notify\n"); + } + if (coex_sta->bt_disabled) return; -- cgit v1.2.3 From 7ad6ff8897a8deb162b7d12adaa6c329748bf4f1 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:37 -0500 Subject: rtlwifi: btcoex: 21a 1ant: use default value when initiating coex For newer coex mechanism, it is not necessary to set a critical value to avoid the power on instability, just use default value for PTA. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 13063f61e1f4..ab6530cfb653 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2096,7 +2096,6 @@ static void btc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist) */ btc8821a1ant_sw_mechanism(btcoexist, false); - btc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); btc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); } -- cgit v1.2.3 From ee406cec878941d997d4e7e02493079cf21109ec Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 11 May 2017 18:24:38 -0500 Subject: rtlwifi: btcoex: 21a 1ant: re-init coex after wifi leaves IPS Before entering IPS, set the PTA control to default value and re-init it after it leaves IPS to avoid running some redundant code in run_coexist_mechanism. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index ab6530cfb653..84cc0bcc5f80 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2473,7 +2473,7 @@ void ex_btc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) btc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, true); /* set PTA control */ - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); } else if (BTC_IPS_LEAVE == type) { @@ -2481,7 +2481,9 @@ void ex_btc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], IPS LEAVE notify\n"); coex_sta->under_ips = false; - btc8821a1ant_run_coexist_mechanism(btcoexist); + btc8821a1ant_init_hw_config(btcoexist, false, false); + btc8821a1ant_init_coex_dm(btcoexist); + btc8821a1ant_query_bt_info(btcoexist); } } -- cgit v1.2.3 From de202ba39f0ed3468dc4bef019d9c9a6eb83518b Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 16 May 2017 08:19:48 -0500 Subject: rtlwifi: btcoex: 21a 1ant: treat ARP as special packet We need to pay attention to ARP packets to correctly establish connection, and reset the ARP counter when disconnected. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 49 ++++++++++++++++++++-- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.h | 1 + 2 files changed, 47 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 84cc0bcc5f80..a5ac07cf0dca 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2592,7 +2592,7 @@ void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) void ex_btc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; - bool wifi_connected = false, bt_hs_on = false; + bool wifi_connected = false, bt_hs_on = false; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; bool bt_ctrl_agg_buf_size = false; @@ -2610,6 +2610,18 @@ void ex_btc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) return; } + if (type == BTC_ASSOCIATE_START) { + coex_sta->wifi_is_high_pri_task = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT START notify\n"); + coex_dm->arp_cnt = 0; + } else { + coex_sta->wifi_is_high_pri_task = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT FINISH notify\n"); + coex_dm->arp_cnt = 0; + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); num_of_wifi_link = wifi_link_status >> 16; @@ -2675,6 +2687,7 @@ void ex_btc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], MEDIA disconnect notify\n"); + coex_dm->arp_cnt = 0; } /* only 2.4G we need to inform bt the chnl mask */ @@ -2728,6 +2741,24 @@ void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, return; } + if (type == BTC_PACKET_DHCP || type == BTC_PACKET_EAPOL || + type == BTC_PACKET_ARP) { + coex_sta->wifi_is_high_pri_task = true; + + if (type == BTC_PACKET_ARP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet ARP notify\n"); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet DHCP or EAPOL notify\n"); + } + } else { + coex_sta->wifi_is_high_pri_task = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], specific Packet [Type = %d] notify\n", + type); + } + coex_sta->special_pkt_period_cnt = 0; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, @@ -2750,8 +2781,20 @@ void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, return; } - if (BTC_PACKET_DHCP == type || - BTC_PACKET_EAPOL == type) { + if (type == BTC_PACKET_DHCP || type == BTC_PACKET_EAPOL || + type == BTC_PACKET_ARP) { + if (type == BTC_PACKET_ARP) { + coex_dm->arp_cnt++; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ARP Packet Count = %d\n", + coex_dm->arp_cnt); + if (coex_dm->arp_cnt >= 10) + /* if APR PKT > 10 after connect, do not go to + * btc8821a1ant_act_wifi_conn_sp_pkt + */ + return; + } + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], special Packet(%d) notify\n", type); btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h index d6dacf32a4c4..1eba3b0d32ae 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h @@ -133,6 +133,7 @@ struct coex_dm_8821a_1ant { u8 cur_retry_limit_type; u8 pre_ampdu_time_type; u8 cur_ampdu_time_type; + u32 arp_cnt; u8 error_condition; }; -- cgit v1.2.3 From 0ad7bd2d1b642d382b8f8ff9eb74fbfdf9e12f4e Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 16 May 2017 08:19:49 -0500 Subject: rtlwifi: btcoex: 21a 1ant: fix some coding style issues Fix alignment for coding style consistency. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index a5ac07cf0dca..93644bedaa0f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2839,14 +2839,14 @@ void ex_btc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, } if (BT_INFO_SRC_8821A_1ANT_WIFI_FW != rsp_source) { - coex_sta->bt_retry_cnt = /* [3:0]*/ - coex_sta->bt_info_c2h[rsp_source][2]&0xf; + /* [3:0] */ + coex_sta->bt_retry_cnt = + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; coex_sta->bt_rssi = - coex_sta->bt_info_c2h[rsp_source][3]*2+10; + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; - coex_sta->bt_info_ext = - coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; /* Here we need to resend some wifi info to BT * because bt is reset and lost the info @@ -2928,11 +2928,11 @@ void ex_btc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); } else if ((bt_info&BT_INFO_8821A_1ANT_B_SCO_ESCO) || - (bt_info&BT_INFO_8821A_1ANT_B_SCO_BUSY)) { + (bt_info & BT_INFO_8821A_1ANT_B_SCO_BUSY)) { coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_SCO_BUSY; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); - } else if (bt_info&BT_INFO_8821A_1ANT_B_ACL_BUSY) { + } else if (bt_info & BT_INFO_8821A_1ANT_B_ACL_BUSY) { if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) coex_dm->auto_tdma_adjust = false; coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_ACL_BUSY; -- cgit v1.2.3 From 63ad6ea938bfc4726bf51eadf8c6019b0ce40a78 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 16 May 2017 08:19:50 -0500 Subject: rtlwifi: btcoex: 21a 1ant: add bt_tx_rx_mask into bt info Set rf register if the tx rx mask is switched. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 14 ++++++++++++++ .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h | 1 + 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 93644bedaa0f..4efac5fe9982 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2848,6 +2848,20 @@ void ex_btc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_tx_rx_mask = + (coex_sta->bt_info_c2h[rsp_source][2] & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + if (!coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG 0x3C != + * 0x15 => Need to switch BT TRx Mask + */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n"); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x15); + } + /* Here we need to resend some wifi info to BT * because bt is reset and lost the info */ diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h index 1eba3b0d32ae..cb32e7a64ae6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h @@ -154,6 +154,7 @@ struct coex_sta_8821a_1ant { u32 low_priority_tx; u32 low_priority_rx; u8 bt_rssi; + bool bt_tx_rx_mask; u8 pre_bt_rssi_state; u8 pre_wifi_rssi_state[4]; bool c2h_bt_info_req_sent; -- cgit v1.2.3 From 158707f9584c960c57f332570d43dedafbbee6f0 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 16 May 2017 08:19:51 -0500 Subject: rtlwifi: btcoex: Restore 23b 1ant routine for tdma adjustment Routine btc8723b1ant_tdma_dur_adj_for_acl() was removed in a set of Sparse fixes; however, this routine will be needed later. Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 177 ++++++++++++++++++++- 1 file changed, 176 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index f23c9e3fbda1..df0782c17905 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1066,8 +1066,183 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; } +void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, + u8 wifi_status) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + static s32 up, dn, m, n, wait_count; + /* 0: no change, +1: increase WiFi duration, + * -1: decrease WiFi duration + */ + s32 result; + u8 retry_count = 0, bt_info_ext; + bool wifi_busy = false; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], TdmaDurationAdjustForAcl()\n"); + + if (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY) + wifi_busy = true; + else + wifi_busy = false; + + if ((wifi_status == + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN) || + (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN) || + (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT)) { + if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 3 && coex_dm->cur_ps_tdma != 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } + return; + } + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->tdma_adj_type = 2; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + result = 0; + wait_count++; + /* no retry in the last 2-second duration */ + if (retry_count == 0) { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Increase wifi duration!!\n"); + } + } else if (retry_count <= 3) { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + if (wait_count <= 2) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Decrease wifi duration for retryCounter<3!!\n"); + } + } else { + if (wait_count == 1) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Decrease wifi duration for retryCounter>3!!\n"); + } + + if (result == -1) { + if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } + } else if (result == 1) { + if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } + } else { + /* if busy / idle change */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex],********* TDMA(on, %d) ********\n", + coex_dm->cur_ps_tdma); + } + + if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 9 && coex_dm->cur_ps_tdma != 11) { + /* recover to previous adjust type */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->tdma_adj_type); + } + } +} + static void halbtc8723b1ant_ps_tdma_chk_pwr_save(struct btc_coexist *btcoexist, - bool new_ps_state) + bool new_ps_state) { u8 lps_mode = 0x0; -- cgit v1.2.3 From 2d446a5653bd98c6f165749f64ff7ffdefb4731e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 16 May 2017 08:19:52 -0500 Subject: rtlwifi: btcoex: 23b 1ant: rename and coding style modification. Rename: * tdma_adj_type to ps_tdma_du_adj_type * wifiCentralChnl to wifi_central_chnl Coding style: * move constant from right to left side in if-statement Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 88 +++++++++++----------- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 2 +- 2 files changed, 44 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index df0782c17905..2e1ba8fed982 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1094,7 +1094,7 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, coex_dm->cur_ps_tdma != 3 && coex_dm->cur_ps_tdma != 9) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); - coex_dm->tdma_adj_type = 9; + coex_dm->ps_tdma_du_adj_type = 9; up = 0; dn = 0; @@ -1112,7 +1112,7 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, "[BTCoex], first run TdmaDurationAdjust()!!\n"); halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); - coex_dm->tdma_adj_type = 2; + coex_dm->ps_tdma_du_adj_type = 2; up = 0; dn = 0; @@ -1191,19 +1191,19 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, (coex_dm->cur_ps_tdma == 2))) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); - coex_dm->tdma_adj_type = 9; + coex_dm->ps_tdma_du_adj_type = 9; } else if (coex_dm->cur_ps_tdma == 1) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); - coex_dm->tdma_adj_type = 2; + coex_dm->ps_tdma_du_adj_type = 2; } else if (coex_dm->cur_ps_tdma == 2) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); - coex_dm->tdma_adj_type = 9; + coex_dm->ps_tdma_du_adj_type = 9; } else if (coex_dm->cur_ps_tdma == 9) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); - coex_dm->tdma_adj_type = 11; + coex_dm->ps_tdma_du_adj_type = 11; } } else if (result == 1) { if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && @@ -1211,19 +1211,19 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, (coex_dm->cur_ps_tdma == 2))) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); - coex_dm->tdma_adj_type = 9; + coex_dm->ps_tdma_du_adj_type = 9; } else if (coex_dm->cur_ps_tdma == 11) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); - coex_dm->tdma_adj_type = 9; + coex_dm->ps_tdma_du_adj_type = 9; } else if (coex_dm->cur_ps_tdma == 9) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); - coex_dm->tdma_adj_type = 2; + coex_dm->ps_tdma_du_adj_type = 2; } else if (coex_dm->cur_ps_tdma == 2) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); - coex_dm->tdma_adj_type = 1; + coex_dm->ps_tdma_du_adj_type = 1; } } else { /* if busy / idle change */ @@ -1236,7 +1236,7 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, coex_dm->cur_ps_tdma != 9 && coex_dm->cur_ps_tdma != 11) { /* recover to previous adjust type */ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, - coex_dm->tdma_adj_type); + coex_dm->ps_tdma_du_adj_type); } } } @@ -1501,7 +1501,7 @@ btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoexist) 0x0, 0x0); /* tdma and coex table */ - if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); @@ -1518,9 +1518,8 @@ btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoexist) halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); } - } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)){ + } else if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY){ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); } else { @@ -1556,7 +1555,7 @@ static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist) 0x0, 0x0); /* tdma and coex table */ - if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); @@ -1573,9 +1572,8 @@ static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist) halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); } - } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)) { + } else if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) { btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); } else { @@ -1646,7 +1644,7 @@ static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); /* power save state */ if (!ap_enable && - BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status && + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY && !btcoexist->bt_link_info.hid_only) { if (!wifi_busy && btcoexist->bt_link_info.a2dp_only) halbtc8723b1ant_power_save_state(btcoexist, @@ -1662,13 +1660,14 @@ static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) } /* tdma and coex table */ if (!wifi_busy) { - if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { - halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, - BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); - } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == - coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)) { + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if (coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) { btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); } else { @@ -1678,13 +1677,14 @@ static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) NORMAL_EXEC, 2); } } else { - if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { - halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, - BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); - } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == - coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == - coex_dm->bt_status)) { + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if (coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) { btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); } else { @@ -1728,11 +1728,10 @@ static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) return; } - if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || - (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY || + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY || + coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) increase_scan_dev_num = true; - } btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, &increase_scan_dev_num); @@ -2349,7 +2348,7 @@ void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, struct rtl_priv *rtlpriv = btcoexist->adapter; u8 h2c_parameter[3] = {0}; u32 wifi_bw; - u8 wifiCentralChnl; + u8 wifi_central_chnl; if (btcoexist->manual_control || btcoexist->stop_coex_dm || btcoexist->bt_info.bt_disabled) @@ -2364,12 +2363,11 @@ void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, /* only 2.4G we need to inform bt the chnl mask */ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, - &wifiCentralChnl); + &wifi_central_chnl); - if ((BTC_MEDIA_CONNECT == type) && - (wifiCentralChnl <= 14)) { + if (type == BTC_MEDIA_CONNECT && wifi_central_chnl <= 14) { h2c_parameter[0] = 0x0; - h2c_parameter[1] = wifiCentralChnl; + h2c_parameter[1] = wifi_central_chnl; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); if (BTC_WIFI_BW_HT40 == wifi_bw) h2c_parameter[2] = 0x30; @@ -2464,8 +2462,8 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, "0x%02x, ", tmp_buf[i]); } - if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rsp_source) { - coex_sta->bt_retry_cnt = /* [3:0] */ + if (rsp_source != BT_INFO_SRC_8723B_1ANT_WIFI_FW) { + coex_sta->bt_retry_cnt = /* [3:0] */ coex_sta->bt_info_c2h[rsp_source][2] & 0xf; coex_sta->bt_rssi = diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 7e91901122c3..cd6369ef0e3a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -88,7 +88,7 @@ struct coex_dm_8723b_1ant { u8 pre_ps_tdma; u8 cur_ps_tdma; u8 ps_tdma_para[5]; - u8 tdma_adj_type; + u8 ps_tdma_du_adj_type; bool auto_tdma_adjust; bool pre_ps_tdma_on; bool cur_ps_tdma_on; -- cgit v1.2.3 From 2622d7d86a57ed8c13df575e62c072eba4b2045a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 16 May 2017 08:19:53 -0500 Subject: rtlwifi: btcoex: 23b 1ant: TDMA duration for ACL busy BT ACL is a special case, so we create a routine to deal this case. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 54 +++++++++++++--------- 1 file changed, 31 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 2e1ba8fed982..523e1acfe1cf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1124,6 +1124,11 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, /* acquire the BT TRx retry count from BT_Info byte2 */ retry_count = coex_sta->bt_retry_cnt; bt_info_ext = coex_sta->bt_info_ext; + + if ((coex_sta->low_priority_tx) > 1050 || + (coex_sta->low_priority_rx) > 1250) + retry_count++; + result = 0; wait_count++; /* no retry in the last 2-second duration */ @@ -1135,6 +1140,9 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, dn = 0; if (up >= n) { + /* if retry count during continuous n*2 seconds + * is 0, enlarge WiFi duration + */ wait_count = 0; n = 3; up = 0; @@ -1144,6 +1152,7 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, "[BTCoex], Increase wifi duration!!\n"); } } else if (retry_count <= 3) { + /* <=3 retry in the last 2-second duration */ up--; dn++; @@ -1151,12 +1160,20 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, up = 0; if (dn == 2) { + /* if continuous 2 retry count(every 2 seconds) + * >0 and < 3, reduce WiFi duration + */ if (wait_count <= 2) + /* avoid loop between the two levels */ m++; else m = 1; if (m >= 20) + /* maximum of m = 20 ' will recheck if + * need to adjust wifi duration in + * maximum time interval 120 seconds + */ m = 20; n = 3 * m; @@ -1168,12 +1185,20 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, "[BTCoex], Decrease wifi duration for retryCounter<3!!\n"); } } else { + /* retry count > 3, once retry count > 3, to reduce + * WiFi duration + */ if (wait_count == 1) + /* to avoid loop between the two levels */ m++; else m = 1; if (m >= 20) + /* maximum of m = 20 ' will recheck if need to + * adjust wifi duration in maximum time interval + * 120 seconds + */ m = 20; n = 3 * m; @@ -1186,13 +1211,7 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, } if (result == -1) { - if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && - ((coex_dm->cur_ps_tdma == 1) || - (coex_dm->cur_ps_tdma == 2))) { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 9); - coex_dm->ps_tdma_du_adj_type = 9; - } else if (coex_dm->cur_ps_tdma == 1) { + if (coex_dm->cur_ps_tdma == 1) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); coex_dm->ps_tdma_du_adj_type = 2; @@ -1206,13 +1225,7 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, coex_dm->ps_tdma_du_adj_type = 11; } } else if (result == 1) { - if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && - ((coex_dm->cur_ps_tdma == 1) || - (coex_dm->cur_ps_tdma == 2))) { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 9); - coex_dm->ps_tdma_du_adj_type = 9; - } else if (coex_dm->cur_ps_tdma == 11) { + if (coex_dm->cur_ps_tdma == 11) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); coex_dm->ps_tdma_du_adj_type = 9; @@ -1225,11 +1238,6 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, true, 1); coex_dm->ps_tdma_du_adj_type = 1; } - } else { - /* if busy / idle change */ - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex],********* TDMA(on, %d) ********\n", - coex_dm->cur_ps_tdma); } if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && @@ -1448,12 +1456,12 @@ static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy( halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); coex_dm->auto_tdma_adjust = false; - } else { /* for low BT RSSI */ - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 11); + } else { + btc8723b1ant_tdma_dur_adj_for_acl(btcoexist, + wifi_status); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); - coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust = true; } } else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) { /* HID + A2DP */ -- cgit v1.2.3 From 37a5be0cfca6487bbdf423a09dfe70e9bfb049db Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 16 May 2017 08:19:54 -0500 Subject: rtlwifi: btcoex: 23b 1ant: monitor wifi and BT counter In field debug, we check wifi and BT counter to analyze problems. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 141 +++++++++++++++++++-- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 15 +++ 2 files changed, 145 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 523e1acfe1cf..437007dd0db0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -210,11 +210,24 @@ static void halbtc8723b1ant_limited_rx(struct btc_coexist *btcoexist, btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); } +static void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + /* trigger */ + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + static void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) { u32 reg_hp_txrx, reg_lp_txrx, u32tmp; u32 reg_hp_tx = 0, reg_hp_rx = 0; u32 reg_lp_tx = 0, reg_lp_rx = 0; + static u32 num_of_bt_counter_chk; reg_hp_txrx = 0x770; reg_lp_txrx = 0x774; @@ -232,25 +245,122 @@ static void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) coex_sta->low_priority_tx = reg_lp_tx; coex_sta->low_priority_rx = reg_lp_rx; + if ((coex_sta->low_priority_tx > 1050) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + /* reset counter */ btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + /* This part is for wifi FW and driver to update BT's status as + * disabled. + * + * The flow is as the following + * 1. disable BT + * 2. if all BT Tx/Rx counter = 0, after 6 sec we query bt info + * 3. Because BT will not rsp from mailbox, so wifi fw will know BT is + * disabled + * + * 4. FW will rsp c2h for BT that driver will know BT is disabled. + */ + if ((reg_hp_tx == 0) && (reg_hp_rx == 0) && (reg_lp_tx == 0) && + (reg_lp_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk == 3) + halbtc8723b1ant_query_bt_info(btcoexist); + } else { + num_of_bt_counter_chk = 0; + } } -static void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist) +static void halbtc8723b1ant_monitor_wifi_ctr(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - u8 h2c_parameter[1] = {0}; + s32 wifi_rssi = 0; + bool wifi_busy = false, wifi_under_b_mode = false; + static u8 cck_lock_counter; + u32 total_cnt; - coex_sta->c2h_bt_info_req_sent = true; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); - /* trigger */ - h2c_parameter[0] |= BIT0; + if (coex_sta->under_ips) { + coex_sta->crc_ok_cck = 0; + coex_sta->crc_ok_11g = 0; + coex_sta->crc_ok_11n = 0; + coex_sta->crc_ok_11n_agg = 0; + + coex_sta->crc_err_cck = 0; + coex_sta->crc_err_11g = 0; + coex_sta->crc_err_11n = 0; + coex_sta->crc_err_11n_agg = 0; + } else { + coex_sta->crc_ok_cck = + btcoexist->btc_read_4byte(btcoexist, 0xf88); + coex_sta->crc_ok_11g = + btcoexist->btc_read_2byte(btcoexist, 0xf94); + coex_sta->crc_ok_11n = + btcoexist->btc_read_2byte(btcoexist, 0xf90); + coex_sta->crc_ok_11n_agg = + btcoexist->btc_read_2byte(btcoexist, 0xfb8); + + coex_sta->crc_err_cck = + btcoexist->btc_read_4byte(btcoexist, 0xf84); + coex_sta->crc_err_11g = + btcoexist->btc_read_2byte(btcoexist, 0xf96); + coex_sta->crc_err_11n = + btcoexist->btc_read_2byte(btcoexist, 0xf92); + coex_sta->crc_err_11n_agg = + btcoexist->btc_read_2byte(btcoexist, 0xfba); + } - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", - h2c_parameter[0]); + /* reset counter */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xf16, 0x1, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xf16, 0x1, 0x0); + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + coex_sta->crc_ok_11n_agg; + + if ((coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > + (total_cnt - coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } - btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; } static bool btc8723b1ant_is_wifi_status_changed(struct btc_coexist *btcoexist) @@ -1818,6 +1928,7 @@ static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) } } +/* force coex mechanism to reset */ static void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) { /* sw all off */ @@ -1825,6 +1936,7 @@ static void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + coex_sta->pop_event_cnt = 0; } static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist, @@ -2655,6 +2767,7 @@ void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; static u8 dis_ver_info_cnt; @@ -2689,9 +2802,15 @@ void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist) if (!btcoexist->auto_report_1ant) { halbtc8723b1ant_query_bt_info(btcoexist); - halbtc8723b1ant_monitor_bt_ctr(btcoexist); halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); } else { + halbtc8723b1ant_monitor_bt_ctr(btcoexist); + halbtc8723b1ant_monitor_wifi_ctr(btcoexist); + + if ((coex_sta->high_priority_tx + coex_sta->high_priority_rx < 50) && + bt_link_info->hid_exist) + bt_link_info->hid_exist = false; + if (btc8723b1ant_is_wifi_status_changed(btcoexist) || coex_dm->auto_tdma_adjust) { halbtc8723b1ant_run_coexist_mechanism(btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index cd6369ef0e3a..cf14db5fa759 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -159,6 +159,21 @@ struct coex_sta_8723b_1ant { bool c2h_bt_inquiry_page; u8 bt_retry_cnt; u8 bt_info_ext; + bool cck_ever_lock; + u32 pop_event_cnt; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_agg; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_agg; + + bool cck_lock; + bool pre_ccklock; }; /************************************************************************* -- cgit v1.2.3 From 75717802c91b7164ce98ce17127ccf9d391a56f7 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 16 May 2017 08:19:55 -0500 Subject: rtlwifi: btcoex: 23b 1ant: check if BT high priority packet exist If there are BT high priority packets, we arrange more time to BT. To make user experience to be better, HID and SCO are also seen as high priority packet exist. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 11 +++++++++++ .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 1 + drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 1 + 3 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 437007dd0db0..9178cccb5ddf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -407,6 +407,7 @@ static void halbtc8723b1ant_update_bt_link_info(struct btc_coexist *btcoexist) bt_link_info->a2dp_exist = coex_sta->a2dp_exist; bt_link_info->pan_exist = coex_sta->pan_exist; bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->bt_hi_pri_link_exist = coex_sta->bt_hi_pri_link_exist; /* work around for HS mode. */ if (bt_hs_on) { @@ -2644,6 +2645,8 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, coex_sta->a2dp_exist = false; coex_sta->hid_exist = false; coex_sta->sco_exist = false; + + coex_sta->bt_hi_pri_link_exist = false; } else { /* connection exists */ coex_sta->bt_link_exist = true; @@ -2663,6 +2666,14 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, coex_sta->sco_exist = true; else coex_sta->sco_exist = false; + + /* Add Hi-Pri Tx/Rx counter to avoid false detection */ + if (((coex_sta->hid_exist) || (coex_sta->sco_exist)) && + (coex_sta->high_priority_tx + coex_sta->high_priority_rx >= + 160) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->bt_hi_pri_link_exist = true; + } halbtc8723b1ant_update_bt_link_info(btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index cf14db5fa759..0b7b9b2a8e12 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -142,6 +142,7 @@ struct coex_sta_8723b_1ant { bool a2dp_exist; bool hid_exist; bool pan_exist; + bool bt_hi_pri_link_exist; bool under_lps; bool under_ips; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index ab2e31a44253..6ce2fcadc144 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -468,6 +468,7 @@ struct btc_statistics { struct btc_bt_link_info { bool bt_link_exist; + bool bt_hi_pri_link_exist; bool sco_exist; bool sco_only; bool a2dp_exist; -- cgit v1.2.3 From 12e87c09cfad4cbbe7a465438af1e3d07e4ee1a6 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 16 May 2017 08:19:56 -0500 Subject: rtlwifi: btcoex: 23b 1ant: monitor bt is enabled or disabled Check BT's status, and record it in field bt_disabled. When BT is disabled, We do special action called wifi_only. Also, we move the field from 'struct btc_coexist' to 'struct coex_sta_8723b_1ant'. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 9178cccb5ddf..b07883eaec5e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2136,7 +2136,7 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", - ((btcoexist->bt_info.bt_disabled) ? ("disabled") : + ((coex_sta->bt_disabled) ? ("disabled") : ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) ? @@ -2422,7 +2422,7 @@ void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) u8 agg_buf_size = 5; if (btcoexist->manual_control || btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + coex_sta->bt_disabled) return; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, @@ -2472,7 +2472,7 @@ void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, u8 wifi_central_chnl; if (btcoexist->manual_control || btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + coex_sta->bt_disabled) return; if (BTC_MEDIA_CONNECT == type) @@ -2519,7 +2519,7 @@ void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, u8 agg_buf_size = 5; if (btcoexist->manual_control || btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + coex_sta->bt_disabled) return; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, -- cgit v1.2.3 From 12515a08e7b1c6fef83f7639b8922f625bcae093 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 16 May 2017 08:19:57 -0500 Subject: rtlwifi: btcoex: 23b 1ant: check PS state before setting tdma duration For time division multiple access, the wifi and bt take turns to transmit, but we need to let AP know that wifi is under standby mode by sending null data to "pretend" entering power saving state using lps rpwm. But, the fw does not know if it is the actual power saving mode or just a fake one to cheat to the AP. Hence, before fw setting the tdma duration, the fw needs the driver to check the power saving state first. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 3 +++ drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index b07883eaec5e..f3704d7db4d5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1401,6 +1401,7 @@ static void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist, btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + coex_sta->force_lps_on = false; break; case BTC_PS_LPS_ON: halbtc8723b1ant_ps_tdma_chk_pwr_save(btcoexist, true); @@ -1412,10 +1413,12 @@ static void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist, &low_pwr_disable); /* power save must executed before psTdma */ btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + coex_sta->force_lps_on = true; break; case BTC_PS_LPS_OFF: halbtc8723b1ant_ps_tdma_chk_pwr_save(btcoexist, false); btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + coex_sta->force_lps_on = false; break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 0b7b9b2a8e12..d502a31812ab 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -161,6 +161,7 @@ struct coex_sta_8723b_1ant { u8 bt_retry_cnt; u8 bt_info_ext; bool cck_ever_lock; + bool force_lps_on; u32 pop_event_cnt; u32 crc_ok_cck; -- cgit v1.2.3 From 6b9e6f62552ee164ff82c70e795dc9a06f5c6d29 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 3 May 2017 23:55:43 +0100 Subject: rtlwifi: fix spelling mistake: "Pairwiase" -> "Pairwise" trivial fixes to spelling mistakes in RT_TRACE messages. Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index 6f5098a18655..11d97fa0e921 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -2506,7 +2506,7 @@ void rtl92ee_set_key(struct ieee80211_hw *hw, u32 key_index, "add one entry\n"); if (is_pairwise) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - "set Pairwiase key\n"); + "set Pairwise key\n"); rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, enc_algo, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index 859c045bd37c..513c27be3868 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -2264,7 +2264,7 @@ void rtl8723e_set_key(struct ieee80211_hw *hw, u32 key_index, "add one entry\n"); if (is_pairwise) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - "set Pairwiase key\n"); + "set Pairwise key\n"); rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, enc_algo, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index 1acbfb86472c..a79f936bb394 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -2637,7 +2637,7 @@ void rtl8723be_set_key(struct ieee80211_hw *hw, u32 key_index, "add one entry\n"); if (is_pairwise) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - "set Pairwiase key\n"); + "set Pairwise key\n"); rtl_cam_add_one_entry(hw, macaddr, key_index, entry_id, enc_algo, -- cgit v1.2.3 From e8dc072dd50d89f012fa1b2d2c4914ae612c786a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 13 May 2017 23:37:02 +0100 Subject: rtlwifi: rtl8723ae: fix spelling mistake: "Coexistance" -> "Coexistence" Trivial fix to spelling mistake in RT_TRACE text Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index 513c27be3868..5ac7b815648a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -2313,7 +2313,7 @@ static void rtl8723e_bt_var_init(struct ieee80211_hw *hw) rtlpriv->btcoexist.eeprom_bt_radio_shared; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, - "BT Coexistance = 0x%x\n", + "BT Coexistence = 0x%x\n", rtlpriv->btcoexist.bt_coexistence); if (rtlpriv->btcoexist.bt_coexistence) { -- cgit v1.2.3 From 0cd2950357e31a96be03b531b4b11fe1df812c9f Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 17 May 2017 13:30:44 +0300 Subject: net: make struct net_device::tx_queue_len unsigned int 4 billion packet queue is something unthinkable so use 32-bit value for now. Space savings on x86_64: add/remove: 0/0 grow/shrink: 3/70 up/down: 16/-131 (-115) function old new delta change_tx_queue_len 94 108 +14 qdisc_create 1176 1177 +1 alloc_netdev_mqs 1124 1125 +1 xenvif_alloc 533 532 -1 x25_asy_setup 167 166 -1 ... tun_queue_resize 945 940 -5 pfifo_fast_enqueue 167 162 -5 qfq_init_qdisc 168 158 -10 tap_queue_resize 810 799 -11 transmit 719 698 -21 Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- drivers/net/wan/hdlc_raw_eth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 2f11836078ab..8bd3ed905813 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -57,7 +57,8 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) const size_t size = sizeof(raw_hdlc_proto); raw_hdlc_proto new_settings; hdlc_device *hdlc = dev_to_hdlc(dev); - int result, old_qlen; + unsigned int old_qlen; + int result; switch (ifr->ifr_settings.type) { case IF_GET_PROTO: -- cgit v1.2.3 From f0897854797d7b131f557f81bc4797e0812ac174 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Wed, 17 May 2017 17:24:32 +0200 Subject: net/wan/fsl_ucc_hdlc: cleanup debug traces Some of the tracing seems to be remaining traces for basic driver development. They can be removed now, as they cause noisy printouts. Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 33 --------------------------------- 1 file changed, 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 6742ae605660..0ae10a58ffca 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -36,7 +36,6 @@ #define DRV_NAME "ucc_hdlc" #define TDM_PPPOHT_SLIC_MAXIN -#define BROKEN_FRAME_INFO static struct ucc_tdm_info utdm_primary_info = { .uf_info = { @@ -314,8 +313,6 @@ static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev) struct qe_bd __iomem *bd; u16 bd_status; unsigned long flags; - u8 *send_buf; - int i; u16 *proto_head; switch (dev->type) { @@ -352,16 +349,6 @@ static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); return -ENOMEM; } - - pr_info("Tx data skb->len:%d ", skb->len); - send_buf = (u8 *)skb->data; - pr_info("\nTransmitted data:\n"); - for (i = 0; i < 16; i++) { - if (i == skb->len) - pr_info("++++"); - else - pr_info("%02x\n", send_buf[i]); - } spin_lock_irqsave(&priv->lock, flags); /* Start from the next BD that should be filled */ @@ -423,7 +410,6 @@ static int hdlc_tx_done(struct ucc_hdlc_private *priv) skb = priv->tx_skbuff[priv->skb_dirtytx]; if (!skb) break; - pr_info("TxBD: %x\n", bd_status); dev->stats.tx_packets++; memset(priv->tx_buffer + (be32_to_cpu(bd->buf) - priv->dma_tx_addr), @@ -460,8 +446,6 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) u16 bd_status; u16 length, howmany = 0; u8 *bdbuffer; - int i; - static int entry; bd = priv->currx_bd; bd_status = ioread16be(&bd->status); @@ -471,9 +455,6 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) if (bd_status & R_OV_S) dev->stats.rx_over_errors++; if (bd_status & R_CR_S) { -#ifdef BROKEN_FRAME_INFO - pr_info("Broken Frame with RxBD: %x\n", bd_status); -#endif dev->stats.rx_crc_errors++; dev->stats.rx_dropped++; goto recycle; @@ -482,17 +463,6 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) (priv->currx_bdnum * MAX_RX_BUF_LENGTH); length = ioread16be(&bd->length); - pr_info("Received data length:%d", length); - pr_info("while entry times:%d", entry++); - - pr_info("\nReceived data:\n"); - for (i = 0; (i < 16); i++) { - if (i == length) - pr_info("++++"); - else - pr_info("%02x\n", bdbuffer[i]); - } - switch (dev->type) { case ARPHRD_RAWHDLC: bdbuffer += HDLC_HEAD_LEN; @@ -531,7 +501,6 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) howmany++; if (hdlc->proto) skb->protocol = hdlc_type_trans(skb, dev); - pr_info("skb->protocol:%x\n", skb->protocol); netif_receive_skb(skb); recycle: @@ -597,7 +566,6 @@ static irqreturn_t ucc_hdlc_irq_handler(int irq, void *dev_id) uccm = ioread32be(uccf->p_uccm); ucce &= uccm; iowrite32be(ucce, uccf->p_ucce); - pr_info("irq ucce:%x\n", ucce); if (!ucce) return IRQ_NONE; @@ -855,7 +823,6 @@ static int uhdlc_suspend(struct device *dev) /* save power */ ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX); - dev_dbg(dev, "ucc hdlc suspend\n"); return 0; } -- cgit v1.2.3 From 66bb144bd9096dd5268ef736ba769b8b6f4ef100 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Wed, 17 May 2017 17:24:33 +0200 Subject: net/wan/fsl_ucc_hdlc: fix unitialized variable warnings This fixes the following compiler warnings: drivers/net/wan/fsl_ucc_hdlc.c: In function 'ucc_hdlc_poll': warning: 'skb' may be used uninitialized in this function [-Wmaybe-uninitialized] skb->mac_header = skb->data - skb->head; and drivers/net/wan/fsl_ucc_hdlc.c: In function 'ucc_hdlc_probe': drivers/net/wan/fsl_ucc_hdlc.c:1127:3: warning: 'utdm' may be used uninitialized in this function [-Wmaybe-uninitialized] kfree(utdm); Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 0ae10a58ffca..6ef6d719545d 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -440,7 +440,7 @@ static int hdlc_tx_done(struct ucc_hdlc_private *priv) static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) { struct net_device *dev = priv->ndev; - struct sk_buff *skb; + struct sk_buff *skb = NULL; hdlc_device *hdlc = dev_to_hdlc(dev); struct qe_bd *bd; u16 bd_status; @@ -968,7 +968,7 @@ static int ucc_hdlc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct ucc_hdlc_private *uhdlc_priv = NULL; struct ucc_tdm_info *ut_info; - struct ucc_tdm *utdm; + struct ucc_tdm *utdm = NULL; struct resource res; struct net_device *dev; hdlc_device *hdlc; -- cgit v1.2.3 From 10515db509780224bf48ea189cff989ebd01dd0e Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Wed, 17 May 2017 17:24:34 +0200 Subject: net/wan/fsl_ucc_hdlc: fix wrong indentation Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 6ef6d719545d..1a60897767d9 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -535,7 +535,7 @@ static int ucc_hdlc_poll(struct napi_struct *napi, int budget) /* Tx event processing */ spin_lock(&priv->lock); - hdlc_tx_done(priv); + hdlc_tx_done(priv); spin_unlock(&priv->lock); howmany = 0; -- cgit v1.2.3 From 5b8aad93c52bdda6a731cab8497998cfa0f2df07 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Wed, 17 May 2017 17:24:35 +0200 Subject: net/wan/fsl_ucc_hdlc: fix incorrect memory allocation We need space for the struct qe_bd and not for a pointer to this struct. Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 1a60897767d9..49b91b2c113c 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -136,7 +136,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) priv->tx_ring_size = TX_BD_RING_LEN; /* Alloc Rx BD */ priv->rx_bd_base = dma_alloc_coherent(priv->dev, - RX_BD_RING_LEN * sizeof(struct qe_bd *), + RX_BD_RING_LEN * sizeof(struct qe_bd), &priv->dma_rx_bd, GFP_KERNEL); if (!priv->rx_bd_base) { @@ -147,7 +147,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) /* Alloc Tx BD */ priv->tx_bd_base = dma_alloc_coherent(priv->dev, - TX_BD_RING_LEN * sizeof(struct qe_bd *), + TX_BD_RING_LEN * sizeof(struct qe_bd), &priv->dma_tx_bd, GFP_KERNEL); if (!priv->tx_bd_base) { @@ -294,11 +294,11 @@ free_ucc_pram: qe_muram_free(priv->ucc_pram_offset); free_tx_bd: dma_free_coherent(priv->dev, - TX_BD_RING_LEN * sizeof(struct qe_bd *), + TX_BD_RING_LEN * sizeof(struct qe_bd), priv->tx_bd_base, priv->dma_tx_bd); free_rx_bd: dma_free_coherent(priv->dev, - RX_BD_RING_LEN * sizeof(struct qe_bd *), + RX_BD_RING_LEN * sizeof(struct qe_bd), priv->rx_bd_base, priv->dma_rx_bd); free_uccf: ucc_fast_free(priv->uccf); @@ -656,7 +656,7 @@ static void uhdlc_memclean(struct ucc_hdlc_private *priv) if (priv->rx_bd_base) { dma_free_coherent(priv->dev, - RX_BD_RING_LEN * sizeof(struct qe_bd *), + RX_BD_RING_LEN * sizeof(struct qe_bd), priv->rx_bd_base, priv->dma_rx_bd); priv->rx_bd_base = NULL; @@ -665,7 +665,7 @@ static void uhdlc_memclean(struct ucc_hdlc_private *priv) if (priv->tx_bd_base) { dma_free_coherent(priv->dev, - TX_BD_RING_LEN * sizeof(struct qe_bd *), + TX_BD_RING_LEN * sizeof(struct qe_bd), priv->tx_bd_base, priv->dma_tx_bd); priv->tx_bd_base = NULL; -- cgit v1.2.3 From 54e9e0874938ba5b112b9352e280b4962590a57d Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Wed, 17 May 2017 17:24:36 +0200 Subject: net/wan/fsl_ucc_hdlc: call qe_setbrg only for loopback mode We can't assume that we are always in loopback mode if rx and tx clock have the same clock source. If we want to use HDLC busmode we also have the same clock source but we are not in loopback mode. So move the setting of the baudrate generator after the check for property for the loopback mode. Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 49b91b2c113c..4c93d561b18a 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -113,6 +113,9 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) /* Loopback mode */ if (priv->loopback) { dev_info(priv->dev, "Loopback Mode\n"); + /* use the same clock when work in loopback */ + qe_setbrg(ut_info->uf_info.rx_clock, 20000000, 1); + gumr = ioread32be(&priv->uf_regs->gumr); gumr |= (UCC_FAST_GUMR_LOOPBACK | UCC_FAST_GUMR_CDS | UCC_FAST_GUMR_TCI); @@ -1021,10 +1024,6 @@ static int ucc_hdlc_probe(struct platform_device *pdev) return -EINVAL; } - /* use the same clock when work in loopback */ - if (ut_info->uf_info.rx_clock == ut_info->uf_info.tx_clock) - qe_setbrg(ut_info->uf_info.rx_clock, 20000000, 1); - ret = of_address_to_resource(np, 0, &res); if (ret) return -EINVAL; -- cgit v1.2.3 From 067bb938dad61e58fc3d6a0e090b72ec011851cd Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Wed, 17 May 2017 17:24:38 +0200 Subject: net/wan/fsl_ucc_hdlc: add hdlc-bus support This adds support for hdlc-bus mode to the fsl_ucc_hdlc driver. This can be enabled with the "fsl,hdlc-bus" property in the DTS node of the corresponding ucc. This aligns the configuration of the UPSMR and GUMR registers to what is done in our ucc_hdlc driver (that only support hdlc-bus mode) and with the QuickEngine's documentation for hdlc-bus mode. GUMR/SYNL is set to AUTO for the busmode as in this case the CD signal is ignored. The brkpt_support is enabled to set the HBM1 bit in the CMXUCR register to configure an open-drain connected HDLC bus. Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 32 ++++++++++++++++++++++++++++++++ drivers/net/wan/fsl_ucc_hdlc.h | 1 + 2 files changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 4c93d561b18a..e9b2d687f150 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -98,6 +98,13 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) uf_info->tsa = 1; uf_info->ctsp = 1; } + + /* This sets HPM register in CMXUCR register which configures a + * open drain connected HDLC bus + */ + if (priv->hdlc_bus) + uf_info->brkpt_support = 1; + uf_info->uccm_mask = ((UCC_HDLC_UCCE_RXB | UCC_HDLC_UCCE_RXF | UCC_HDLC_UCCE_TXB) << 16); @@ -135,6 +142,28 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) /* Set UPSMR normal mode (need fixed)*/ iowrite32be(0, &priv->uf_regs->upsmr); + /* hdlc_bus mode */ + if (priv->hdlc_bus) { + u32 upsmr; + + dev_info(priv->dev, "HDLC bus Mode\n"); + upsmr = ioread32be(&priv->uf_regs->upsmr); + + /* bus mode and retransmit enable, with collision window + * set to 8 bytes + */ + upsmr |= UCC_HDLC_UPSMR_RTE | UCC_HDLC_UPSMR_BUS | + UCC_HDLC_UPSMR_CW8; + iowrite32be(upsmr, &priv->uf_regs->upsmr); + + /* explicitly disable CDS & CTSP */ + gumr = ioread32be(&priv->uf_regs->gumr); + gumr &= ~(UCC_FAST_GUMR_CDS | UCC_FAST_GUMR_CTSP); + /* set automatic sync to explicitly ignore CD signal */ + gumr |= UCC_FAST_GUMR_SYNL_AUTO; + iowrite32be(gumr, &priv->uf_regs->gumr); + } + priv->rx_ring_size = RX_BD_RING_LEN; priv->tx_ring_size = TX_BD_RING_LEN; /* Alloc Rx BD */ @@ -1046,6 +1075,9 @@ static int ucc_hdlc_probe(struct platform_device *pdev) if (of_get_property(np, "fsl,ucc-internal-loopback", NULL)) uhdlc_priv->loopback = 1; + if (of_get_property(np, "fsl,hdlc-bus", NULL)) + uhdlc_priv->hdlc_bus = 1; + if (uhdlc_priv->tsa == 1) { utdm = kzalloc(sizeof(*utdm), GFP_KERNEL); if (!utdm) { diff --git a/drivers/net/wan/fsl_ucc_hdlc.h b/drivers/net/wan/fsl_ucc_hdlc.h index 881ecdeef076..c21134c1f180 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.h +++ b/drivers/net/wan/fsl_ucc_hdlc.h @@ -78,6 +78,7 @@ struct ucc_hdlc_private { u16 tsa; bool hdlc_busy; bool loopback; + bool hdlc_bus; u8 *tx_buffer; u8 *rx_buffer; -- cgit v1.2.3 From f0c24ccf491b09de53cee32114c924551218f2bc Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 17 May 2017 15:46:04 -0400 Subject: net: dsa: include switchdev.h only once DSA drivers and core use switchdev. Include switchdev.h only once, in the dsa.h public header, so that inclusion in DSA drivers or forward declarations of switchdev structures in not necessary anymore. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 1 - drivers/net/dsa/bcm_sf2.c | 1 - drivers/net/dsa/dsa_loop.c | 1 - drivers/net/dsa/mt7530.c | 1 - drivers/net/dsa/mv88e6xxx/chip.c | 1 - drivers/net/dsa/qca8k.c | 1 - 6 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 658a12c888a8..fbc3eb17c7a3 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "b53_regs.h" #include "b53_priv.h" diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 215d41c1e71f..687a8bae5d73 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "bcm_sf2.h" diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index a19e1781e9bb..6afab16d13dd 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include "dsa_loop.h" diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index b070c167e70f..1bcbe15870ed 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "mt7530.h" diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index d034d8cd7d22..386d878569ed 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -32,7 +32,6 @@ #include #include #include -#include #include "mv88e6xxx.h" #include "global1.h" diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 942b9ac7f92a..149f109dbffb 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 438ff53739ee523de3755a98ae3a290e69752620 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 17 May 2017 15:46:05 -0400 Subject: net: dsa: use switchdev_obj_dump_cb_t everywhere Now that the DSA public header includes switchdev.h, use the provided switchdev_obj_dump_cb_t typedef for the object dump callback. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 6 +++--- drivers/net/dsa/b53/b53_priv.h | 4 ++-- drivers/net/dsa/dsa_loop.c | 2 +- drivers/net/dsa/mt7530.c | 2 +- drivers/net/dsa/mv88e6xxx/chip.c | 10 +++++----- drivers/net/dsa/qca8k.c | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index fbc3eb17c7a3..fa099ed41652 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1055,7 +1055,7 @@ EXPORT_SYMBOL(b53_vlan_del); int b53_vlan_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct b53_device *dev = ds->priv; u16 vid, vid_start = 0, pvid; @@ -1284,7 +1284,7 @@ static void b53_arl_search_rd(struct b53_device *dev, u8 idx, static int b53_fdb_copy(struct net_device *dev, int port, const struct b53_arl_entry *ent, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { if (!ent->is_valid) return 0; @@ -1301,7 +1301,7 @@ static int b53_fdb_copy(struct net_device *dev, int port, int b53_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct b53_device *priv = ds->priv; struct net_device *dev = ds->ports[port].netdev; diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index a9dc90a01438..155a9c48c317 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -395,7 +395,7 @@ int b53_vlan_del(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan); int b53_vlan_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)); + switchdev_obj_dump_cb_t *cb); int b53_fdb_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_fdb *fdb, struct switchdev_trans *trans); @@ -406,7 +406,7 @@ int b53_fdb_del(struct dsa_switch *ds, int port, const struct switchdev_obj_port_fdb *fdb); int b53_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)); + switchdev_obj_dump_cb_t *cb); int b53_mirror_add(struct dsa_switch *ds, int port, struct dsa_mall_mirror_tc_entry *mirror, bool ingress); void b53_mirror_del(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 6afab16d13dd..5edf07beb9d2 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -187,7 +187,7 @@ static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port, static int dsa_loop_port_vlan_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct dsa_loop_priv *ps = ds->priv; struct mii_bus *bus = ps->bus; diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 1bcbe15870ed..4d2f45153ede 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -853,7 +853,7 @@ mt7530_port_fdb_del(struct dsa_switch *ds, int port, static int mt7530_port_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mt7530_priv *priv = ds->priv; struct mt7530_fdb _fdb = { 0 }; diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 386d878569ed..41de250dbcc3 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1268,7 +1268,7 @@ static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_chip *chip = ds->priv; struct mv88e6xxx_vtu_entry next = { @@ -1699,7 +1699,7 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, u16 fid, u16 vid, int port, struct switchdev_obj *obj, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_atu_entry addr; int err; @@ -1754,7 +1754,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, struct switchdev_obj *obj, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_vtu_entry vlan = { .vid = chip->info->max_vid, @@ -1791,7 +1791,7 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port, static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_chip *chip = ds->priv; int err; @@ -4037,7 +4037,7 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, static int mv88e6xxx_port_mdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_mdb *mdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct mv88e6xxx_chip *chip = ds->priv; int err; diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 149f109dbffb..0f6a011d8ed1 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -872,7 +872,7 @@ qca8k_port_fdb_del(struct dsa_switch *ds, int port, static int qca8k_port_fdb_dump(struct dsa_switch *ds, int port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)) + switchdev_obj_dump_cb_t *cb) { struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; struct qca8k_fdb _fdb = { 0 }; -- cgit v1.2.3 From 9b910d29661c2765766282a1f58b9af6f703ca8c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 17 May 2017 17:32:12 -0700 Subject: net: dsa: b53: Add compatible strings for the Cygnus-family BCM11360. Cygnus is a small family of SoCs, of which we currently have devicetree for BCM11360 and BCM58300. The 11360's B53 is mostly the same as 58xx, just requiring a tiny bit of setup that was previously missing. Signed-off-by: Eric Anholt Reviewed-by: Florian Fainelli Acked-by: Rob Herring Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_srab.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index 8a62b6a69703..c37ffd1b6833 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c @@ -364,6 +364,7 @@ static const struct of_device_id b53_srab_of_match[] = { { .compatible = "brcm,bcm53018-srab" }, { .compatible = "brcm,bcm53019-srab" }, { .compatible = "brcm,bcm5301x-srab" }, + { .compatible = "brcm,bcm11360-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm58522-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm58525-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm58535-srab", .data = (void *)BCM58XX_DEVICE_ID }, @@ -371,6 +372,7 @@ static const struct of_device_id b53_srab_of_match[] = { { .compatible = "brcm,bcm58623-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm58625-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,bcm88312-srab", .data = (void *)BCM58XX_DEVICE_ID }, + { .compatible = "brcm,cygnus-srab", .data = (void *)BCM58XX_DEVICE_ID }, { .compatible = "brcm,nsp-srab", .data = (void *)BCM58XX_DEVICE_ID }, { /* sentinel */ }, }; -- cgit v1.2.3 From d5d6add01e952228576c1f048b449198a3e03ba8 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 18 May 2017 09:22:45 +0200 Subject: mlxsw: spectrum_dpipe: Fix sparse warnings drivers/net/ethernet/mellanox/mlxsw//spectrum_dpipe.c:221:52: warning: Using plain integer as NULL pointer drivers/net/ethernet/mellanox/mlxsw//spectrum_dpipe.c:221:74: warning: Using plain integer as NULL pointer Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c index ce2534df03ca..096212d6cd65 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c @@ -217,7 +217,7 @@ static int mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled, struct devlink_dpipe_dump_ctx *dump_ctx) { - struct devlink_dpipe_value match_value = {{0}}, action_value = {{0}}; + struct devlink_dpipe_value match_value, action_value; struct devlink_dpipe_action action = {0}; struct devlink_dpipe_match match = {0}; struct devlink_dpipe_entry entry = {0}; @@ -226,6 +226,9 @@ mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled, int i, j; int err; + memset(&match_value, 0, sizeof(match_value)); + memset(&action_value, 0, sizeof(action_value)); + mlxsw_sp_erif_match_action_prepare(&match, &action); err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match, &action_value, &action); -- cgit v1.2.3 From 4454e8661ffcb707ce1c405b6e112255629562da Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 18 May 2017 10:14:01 +0100 Subject: liquidio: make the spinlock octeon_devices_lock static octeon_devices_lock can be made static as it does not need to be in global scope. Cleans up sparse warning: "warning: symbol 'octeon_devices_lock' was not declared. Should it be static?" Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/octeon_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index 3cc56675359a..b5be7074f3de 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -547,7 +547,7 @@ static atomic_t adapter_refcounts[MAX_OCTEON_DEVICES]; static u32 octeon_device_count; /* locks device array (i.e. octeon_device[]) */ -spinlock_t octeon_devices_lock; +static spinlock_t octeon_devices_lock; static struct octeon_core_setup core_setup[MAX_OCTEON_DEVICES]; -- cgit v1.2.3 From 7b6859fbdcc4a590c8ef03bcc00d770b42d41c42 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 18 May 2017 19:41:04 +0300 Subject: qed: Utilize FW 8.20.0.0 This pushes qed [and as result, all qed* drivers] into using 8.20.0.0 firmware. The changes are mostly contained in qed with minor changes to qedi due to some HSI changes. Content-wise, the firmware contains fixes to various issues exposed since the release of the previous firmware, including: - Corrects iSCSI fast retransmit when data digest is enabled. - Stop draining packets when receiving several consecutive PFCs. - Prevent possible assertion when consecutively opening/closing many connections. - Prevent possible assertion due to too long BDQ fetch time. In addition, the new firmware would allow us to later add iWARP support in qed and qedr. Changes from previous version ----------------------------- - V2: Fix warning in qed_debug.c Signed-off-by: Chad Dupuis Signed-off-by: Ram Amrani Signed-off-by: Tomer Tayar Signed-off-by: Manish Rangankar Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 2 +- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 11 +- drivers/net/ethernet/qlogic/qed/qed_debug.c | 3332 +++++++++-------- drivers/net/ethernet/qlogic/qed/qed_debug.h | 3 + drivers/net/ethernet/qlogic/qed/qed_hsi.h | 3739 +++++++++++++------- .../net/ethernet/qlogic/qed/qed_init_fw_funcs.c | 267 +- drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 3 - drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 186 +- drivers/net/ethernet/qlogic/qed/qed_roce.c | 4 - drivers/net/ethernet/qlogic/qed/qed_sp_commands.c | 23 +- drivers/scsi/qedi/qedi_fw.c | 20 +- drivers/scsi/qedi/qedi_fw_api.c | 3 +- drivers/scsi/qedi/qedi_iscsi.c | 3 - 13 files changed, 4653 insertions(+), 2943 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 2ab1aab7c3fe..162cd7ff9a69 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -54,7 +54,7 @@ extern const struct qed_common_ops qed_common_ops_pass; #define QED_MAJOR_VERSION 8 #define QED_MINOR_VERSION 10 -#define QED_REVISION_VERSION 10 +#define QED_REVISION_VERSION 11 #define QED_ENGINEERING_VERSION 21 #define QED_VERSION \ diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index d883ad5bec6d..b7ca0e2181c4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -944,17 +944,18 @@ void qed_dcbx_set_pf_update_params(struct qed_dcbx_results *p_src, p_dest->pf_id = p_src->pf_id; update_flag = p_src->arr[DCBX_PROTOCOL_FCOE].update; - p_dest->update_fcoe_dcb_data_flag = update_flag; + p_dest->update_fcoe_dcb_data_mode = update_flag; update_flag = p_src->arr[DCBX_PROTOCOL_ROCE].update; - p_dest->update_roce_dcb_data_flag = update_flag; + p_dest->update_roce_dcb_data_mode = update_flag; + update_flag = p_src->arr[DCBX_PROTOCOL_ROCE_V2].update; - p_dest->update_roce_dcb_data_flag = update_flag; + p_dest->update_rroce_dcb_data_mode = update_flag; update_flag = p_src->arr[DCBX_PROTOCOL_ISCSI].update; - p_dest->update_iscsi_dcb_data_flag = update_flag; + p_dest->update_iscsi_dcb_data_mode = update_flag; update_flag = p_src->arr[DCBX_PROTOCOL_ETH].update; - p_dest->update_eth_dcb_data_flag = update_flag; + p_dest->update_eth_dcb_data_mode = update_flag; p_dcb_data = &p_dest->fcoe_dcb_data; qed_dcbx_update_protocol_data(p_dcb_data, p_src, DCBX_PROTOCOL_FCOE); diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index 483241b4b05d..87a1389fb4a8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -15,13 +15,6 @@ #include "qed_mcp.h" #include "qed_reg_addr.h" -/* Chip IDs enum */ -enum chip_ids { - CHIP_BB_B0, - CHIP_K2, - MAX_CHIP_IDS -}; - /* Memory groups enum */ enum mem_groups { MEM_GROUP_PXP_MEM, @@ -33,7 +26,6 @@ enum mem_groups { MEM_GROUP_BRB_MEM, MEM_GROUP_PRS_MEM, MEM_GROUP_SDM_MEM, - MEM_GROUP_PBUF, MEM_GROUP_IOR, MEM_GROUP_RAM, MEM_GROUP_BTB_RAM, @@ -45,6 +37,7 @@ enum mem_groups { MEM_GROUP_CAU_PI, MEM_GROUP_CAU_MEM, MEM_GROUP_PXP_ILT, + MEM_GROUP_PBUF, MEM_GROUP_MULD_MEM, MEM_GROUP_BTB_MEM, MEM_GROUP_IGU_MEM, @@ -66,7 +59,6 @@ static const char * const s_mem_group_names[] = { "BRB_MEM", "PRS_MEM", "SDM_MEM", - "PBUF", "IOR", "RAM", "BTB_RAM", @@ -78,6 +70,7 @@ static const char * const s_mem_group_names[] = { "CAU_PI", "CAU_MEM", "PXP_ILT", + "PBUF", "MULD_MEM", "BTB_MEM", "IGU_MEM", @@ -88,48 +81,59 @@ static const char * const s_mem_group_names[] = { }; /* Idle check conditions */ -static u32 cond4(const u32 *r, const u32 *imm) + +static u32 cond5(const u32 *r, const u32 *imm) { return ((r[0] & imm[0]) != imm[1]) && ((r[1] & imm[2]) != imm[3]); } -static u32 cond6(const u32 *r, const u32 *imm) +static u32 cond7(const u32 *r, const u32 *imm) { return ((r[0] >> imm[0]) & imm[1]) != imm[2]; } -static u32 cond5(const u32 *r, const u32 *imm) +static u32 cond14(const u32 *r, const u32 *imm) +{ + return (r[0] != imm[0]) && (((r[1] >> imm[1]) & imm[2]) == imm[3]); +} + +static u32 cond6(const u32 *r, const u32 *imm) { return (r[0] & imm[0]) != imm[1]; } -static u32 cond8(const u32 *r, const u32 *imm) +static u32 cond9(const u32 *r, const u32 *imm) { return ((r[0] & imm[0]) >> imm[1]) != (((r[0] & imm[2]) >> imm[3]) | ((r[1] & imm[4]) << imm[5])); } -static u32 cond9(const u32 *r, const u32 *imm) +static u32 cond10(const u32 *r, const u32 *imm) { return ((r[0] & imm[0]) >> imm[1]) != (r[0] & imm[2]); } -static u32 cond1(const u32 *r, const u32 *imm) +static u32 cond4(const u32 *r, const u32 *imm) { return (r[0] & ~imm[0]) != imm[1]; } static u32 cond0(const u32 *r, const u32 *imm) +{ + return (r[0] & ~r[1]) != imm[0]; +} + +static u32 cond1(const u32 *r, const u32 *imm) { return r[0] != imm[0]; } -static u32 cond10(const u32 *r, const u32 *imm) +static u32 cond11(const u32 *r, const u32 *imm) { return r[0] != r[1] && r[2] == imm[0]; } -static u32 cond11(const u32 *r, const u32 *imm) +static u32 cond12(const u32 *r, const u32 *imm) { return r[0] != r[1] && r[2] > imm[0]; } @@ -139,12 +143,12 @@ static u32 cond3(const u32 *r, const u32 *imm) return r[0] != r[1]; } -static u32 cond12(const u32 *r, const u32 *imm) +static u32 cond13(const u32 *r, const u32 *imm) { return r[0] & imm[0]; } -static u32 cond7(const u32 *r, const u32 *imm) +static u32 cond8(const u32 *r, const u32 *imm) { return r[0] < (r[1] - imm[0]); } @@ -169,6 +173,8 @@ static u32(*cond_arr[]) (const u32 *r, const u32 *imm) = { cond10, cond11, cond12, + cond13, + cond14, }; /******************************* Data Types **********************************/ @@ -181,11 +187,6 @@ enum platform_ids { MAX_PLATFORM_IDS }; -struct dbg_array { - const u32 *ptr; - u32 size_in_dwords; -}; - struct chip_platform_defs { u8 num_ports; u8 num_pfs; @@ -204,7 +205,9 @@ struct platform_defs { u32 delay_factor; }; -/* Storm constant definitions */ +/* Storm constant definitions. + * Addresses are in bytes, sizes are in quad-regs. + */ struct storm_defs { char letter; enum block_id block_id; @@ -218,13 +221,13 @@ struct storm_defs { u32 sem_sync_dbg_empty_addr; u32 sem_slow_dbg_empty_addr; u32 cm_ctx_wr_addr; - u32 cm_conn_ag_ctx_lid_size; /* In quad-regs */ + u32 cm_conn_ag_ctx_lid_size; u32 cm_conn_ag_ctx_rd_addr; - u32 cm_conn_st_ctx_lid_size; /* In quad-regs */ + u32 cm_conn_st_ctx_lid_size; u32 cm_conn_st_ctx_rd_addr; - u32 cm_task_ag_ctx_lid_size; /* In quad-regs */ + u32 cm_task_ag_ctx_lid_size; u32 cm_task_ag_ctx_rd_addr; - u32 cm_task_st_ctx_lid_size; /* In quad-regs */ + u32 cm_task_st_ctx_lid_size; u32 cm_task_st_ctx_rd_addr; }; @@ -233,17 +236,23 @@ struct block_defs { const char *name; bool has_dbg_bus[MAX_CHIP_IDS]; bool associated_to_storm; - u32 storm_id; /* Valid only if associated_to_storm is true */ + + /* Valid only if associated_to_storm is true */ + u32 storm_id; enum dbg_bus_clients dbg_client_id[MAX_CHIP_IDS]; u32 dbg_select_addr; - u32 dbg_cycle_enable_addr; + u32 dbg_enable_addr; u32 dbg_shift_addr; u32 dbg_force_valid_addr; u32 dbg_force_frame_addr; bool has_reset_bit; - bool unreset; /* If true, the block is taken out of reset before dump */ + + /* If true, block is taken out of reset before dump */ + bool unreset; enum dbg_reset_regs reset_reg; - u8 reset_bit_offset; /* Bit offset in reset register */ + + /* Bit offset in reset register */ + u8 reset_bit_offset; }; /* Reset register definitions */ @@ -262,12 +271,13 @@ struct grc_param_defs { u32 crash_preset_val; }; +/* Address is in 128b units. Width is in bits. */ struct rss_mem_defs { const char *mem_name; const char *type_name; - u32 addr; /* In 128b units */ + u32 addr; u32 num_entries[MAX_CHIP_IDS]; - u32 entry_width[MAX_CHIP_IDS]; /* In bits */ + u32 entry_width[MAX_CHIP_IDS]; }; struct vfc_ram_defs { @@ -289,10 +299,20 @@ struct big_ram_defs { struct phy_defs { const char *phy_name; + + /* PHY base GRC address */ u32 base_addr; + + /* Relative address of indirect TBUS address register (bits 0..7) */ u32 tbus_addr_lo_addr; + + /* Relative address of indirect TBUS address register (bits 8..10) */ u32 tbus_addr_hi_addr; + + /* Relative address of indirect TBUS data register (bits 0..7) */ u32 tbus_data_lo_addr; + + /* Relative address of indirect TBUS data register (bits 8..11) */ u32 tbus_data_hi_addr; }; @@ -300,9 +320,11 @@ struct phy_defs { #define MAX_LCIDS 320 #define MAX_LTIDS 320 + #define NUM_IOR_SETS 2 #define IORS_PER_SET 176 #define IOR_SET_OFFSET(set_id) ((set_id) * 256) + #define BYTES_IN_DWORD sizeof(u32) /* In the macros below, size and offset are specified in bits */ @@ -315,6 +337,7 @@ struct phy_defs { #define FIELD_BIT_MASK(type, field) \ (((1 << FIELD_BIT_SIZE(type, field)) - 1) << \ FIELD_DWORD_SHIFT(type, field)) + #define SET_VAR_FIELD(var, type, field, val) \ do { \ var[FIELD_DWORD_OFFSET(type, field)] &= \ @@ -322,31 +345,51 @@ struct phy_defs { var[FIELD_DWORD_OFFSET(type, field)] |= \ (val) << FIELD_DWORD_SHIFT(type, field); \ } while (0) + #define ARR_REG_WR(dev, ptt, addr, arr, arr_size) \ do { \ for (i = 0; i < (arr_size); i++) \ qed_wr(dev, ptt, addr, (arr)[i]); \ } while (0) + #define ARR_REG_RD(dev, ptt, addr, arr, arr_size) \ do { \ for (i = 0; i < (arr_size); i++) \ (arr)[i] = qed_rd(dev, ptt, addr); \ } while (0) +#ifndef DWORDS_TO_BYTES #define DWORDS_TO_BYTES(dwords) ((dwords) * BYTES_IN_DWORD) +#endif +#ifndef BYTES_TO_DWORDS #define BYTES_TO_DWORDS(bytes) ((bytes) / BYTES_IN_DWORD) +#endif + +/* extra lines include a signature line + optional latency events line */ +#ifndef NUM_DBG_LINES +#define NUM_EXTRA_DBG_LINES(block_desc) \ + (1 + ((block_desc)->has_latency_events ? 1 : 0)) +#define NUM_DBG_LINES(block_desc) \ + ((block_desc)->num_of_lines + NUM_EXTRA_DBG_LINES(block_desc)) +#endif + #define RAM_LINES_TO_DWORDS(lines) ((lines) * 2) #define RAM_LINES_TO_BYTES(lines) \ DWORDS_TO_BYTES(RAM_LINES_TO_DWORDS(lines)) + #define REG_DUMP_LEN_SHIFT 24 #define MEM_DUMP_ENTRY_SIZE_DWORDS \ BYTES_TO_DWORDS(sizeof(struct dbg_dump_mem)) + #define IDLE_CHK_RULE_SIZE_DWORDS \ BYTES_TO_DWORDS(sizeof(struct dbg_idle_chk_rule)) + #define IDLE_CHK_RESULT_HDR_DWORDS \ BYTES_TO_DWORDS(sizeof(struct dbg_idle_chk_result_hdr)) + #define IDLE_CHK_RESULT_REG_HDR_DWORDS \ BYTES_TO_DWORDS(sizeof(struct dbg_idle_chk_result_reg_hdr)) + #define IDLE_CHK_MAX_ENTRIES_SIZE 32 /* The sizes and offsets below are specified in bits */ @@ -363,62 +406,92 @@ struct phy_defs { #define VFC_RAM_ADDR_ROW_OFFSET 2 #define VFC_RAM_ADDR_ROW_SIZE 10 #define VFC_RAM_RESP_STRUCT_SIZE 256 + #define VFC_CAM_CMD_DWORDS CEIL_DWORDS(VFC_CAM_CMD_STRUCT_SIZE) #define VFC_CAM_ADDR_DWORDS CEIL_DWORDS(VFC_CAM_ADDR_STRUCT_SIZE) #define VFC_CAM_RESP_DWORDS CEIL_DWORDS(VFC_CAM_RESP_STRUCT_SIZE) #define VFC_RAM_CMD_DWORDS VFC_CAM_CMD_DWORDS #define VFC_RAM_ADDR_DWORDS CEIL_DWORDS(VFC_RAM_ADDR_STRUCT_SIZE) #define VFC_RAM_RESP_DWORDS CEIL_DWORDS(VFC_RAM_RESP_STRUCT_SIZE) + #define NUM_VFC_RAM_TYPES 4 + #define VFC_CAM_NUM_ROWS 512 + #define VFC_OPCODE_CAM_RD 14 #define VFC_OPCODE_RAM_RD 0 + #define NUM_RSS_MEM_TYPES 5 + #define NUM_BIG_RAM_TYPES 3 #define BIG_RAM_BLOCK_SIZE_BYTES 128 #define BIG_RAM_BLOCK_SIZE_DWORDS \ BYTES_TO_DWORDS(BIG_RAM_BLOCK_SIZE_BYTES) + #define NUM_PHY_TBUS_ADDRESSES 2048 #define PHY_DUMP_SIZE_DWORDS (NUM_PHY_TBUS_ADDRESSES / 2) + #define RESET_REG_UNRESET_OFFSET 4 + #define STALL_DELAY_MS 500 + #define STATIC_DEBUG_LINE_DWORDS 9 -#define NUM_DBG_BUS_LINES 256 + #define NUM_COMMON_GLOBAL_PARAMS 8 + #define FW_IMG_MAIN 1 -#define REG_FIFO_DEPTH_ELEMENTS 32 + +#ifndef REG_FIFO_ELEMENT_DWORDS #define REG_FIFO_ELEMENT_DWORDS 2 +#endif +#define REG_FIFO_DEPTH_ELEMENTS 32 #define REG_FIFO_DEPTH_DWORDS \ (REG_FIFO_ELEMENT_DWORDS * REG_FIFO_DEPTH_ELEMENTS) -#define IGU_FIFO_DEPTH_ELEMENTS 64 + +#ifndef IGU_FIFO_ELEMENT_DWORDS #define IGU_FIFO_ELEMENT_DWORDS 4 +#endif +#define IGU_FIFO_DEPTH_ELEMENTS 64 #define IGU_FIFO_DEPTH_DWORDS \ (IGU_FIFO_ELEMENT_DWORDS * IGU_FIFO_DEPTH_ELEMENTS) -#define PROTECTION_OVERRIDE_DEPTH_ELEMENTS 20 + +#ifndef PROTECTION_OVERRIDE_ELEMENT_DWORDS #define PROTECTION_OVERRIDE_ELEMENT_DWORDS 2 +#endif +#define PROTECTION_OVERRIDE_DEPTH_ELEMENTS 20 #define PROTECTION_OVERRIDE_DEPTH_DWORDS \ (PROTECTION_OVERRIDE_DEPTH_ELEMENTS * \ PROTECTION_OVERRIDE_ELEMENT_DWORDS) + #define MCP_SPAD_TRACE_OFFSIZE_ADDR \ (MCP_REG_SCRATCH + \ offsetof(struct static_init, sections[SPAD_SECTION_TRACE])) -#define MCP_TRACE_META_IMAGE_SIGNATURE 0x669955aa + #define EMPTY_FW_VERSION_STR "???_???_???_???" #define EMPTY_FW_IMAGE_STR "???????????????" /***************************** Constant Arrays *******************************/ +struct dbg_array { + const u32 *ptr; + u32 size_in_dwords; +}; + /* Debug arrays */ -static struct dbg_array s_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {0} }; +static struct dbg_array s_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {NULL} }; /* Chip constant definitions array */ static struct chip_defs s_chip_defs[MAX_CHIP_IDS] = { - { "bb_b0", - { {MAX_NUM_PORTS_BB, MAX_NUM_PFS_BB, MAX_NUM_VFS_BB}, {0, 0, 0}, - {0, 0, 0}, {0, 0, 0} } }, - { "k2", - { {MAX_NUM_PORTS_K2, MAX_NUM_PFS_K2, MAX_NUM_VFS_K2}, {0, 0, 0}, - {0, 0, 0}, {0, 0, 0} } } + { "bb", + {{MAX_NUM_PORTS_BB, MAX_NUM_PFS_BB, MAX_NUM_VFS_BB}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} } }, + { "ah", + {{MAX_NUM_PORTS_K2, MAX_NUM_PFS_K2, MAX_NUM_VFS_K2}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} } } }; /* Storm constant definitions array */ @@ -427,69 +500,74 @@ static struct storm_defs s_storm_defs[] = { {'T', BLOCK_TSEM, {DBG_BUS_CLIENT_RBCT, DBG_BUS_CLIENT_RBCT}, true, TSEM_REG_FAST_MEMORY, - TSEM_REG_DBG_FRAME_MODE, TSEM_REG_SLOW_DBG_ACTIVE, - TSEM_REG_SLOW_DBG_MODE, TSEM_REG_DBG_MODE1_CFG, - TSEM_REG_SYNC_DBG_EMPTY, TSEM_REG_SLOW_DBG_EMPTY, + TSEM_REG_DBG_FRAME_MODE_BB_K2, TSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + TSEM_REG_SLOW_DBG_MODE_BB_K2, TSEM_REG_DBG_MODE1_CFG_BB_K2, + TSEM_REG_SYNC_DBG_EMPTY, TSEM_REG_SLOW_DBG_EMPTY_BB_K2, TCM_REG_CTX_RBC_ACCS, 4, TCM_REG_AGG_CON_CTX, 16, TCM_REG_SM_CON_CTX, 2, TCM_REG_AGG_TASK_CTX, 4, TCM_REG_SM_TASK_CTX}, + /* Mstorm */ {'M', BLOCK_MSEM, {DBG_BUS_CLIENT_RBCT, DBG_BUS_CLIENT_RBCM}, false, MSEM_REG_FAST_MEMORY, - MSEM_REG_DBG_FRAME_MODE, MSEM_REG_SLOW_DBG_ACTIVE, - MSEM_REG_SLOW_DBG_MODE, MSEM_REG_DBG_MODE1_CFG, - MSEM_REG_SYNC_DBG_EMPTY, MSEM_REG_SLOW_DBG_EMPTY, + MSEM_REG_DBG_FRAME_MODE_BB_K2, MSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + MSEM_REG_SLOW_DBG_MODE_BB_K2, MSEM_REG_DBG_MODE1_CFG_BB_K2, + MSEM_REG_SYNC_DBG_EMPTY, MSEM_REG_SLOW_DBG_EMPTY_BB_K2, MCM_REG_CTX_RBC_ACCS, 1, MCM_REG_AGG_CON_CTX, 10, MCM_REG_SM_CON_CTX, 2, MCM_REG_AGG_TASK_CTX, 7, MCM_REG_SM_TASK_CTX}, + /* Ustorm */ {'U', BLOCK_USEM, {DBG_BUS_CLIENT_RBCU, DBG_BUS_CLIENT_RBCU}, false, USEM_REG_FAST_MEMORY, - USEM_REG_DBG_FRAME_MODE, USEM_REG_SLOW_DBG_ACTIVE, - USEM_REG_SLOW_DBG_MODE, USEM_REG_DBG_MODE1_CFG, - USEM_REG_SYNC_DBG_EMPTY, USEM_REG_SLOW_DBG_EMPTY, + USEM_REG_DBG_FRAME_MODE_BB_K2, USEM_REG_SLOW_DBG_ACTIVE_BB_K2, + USEM_REG_SLOW_DBG_MODE_BB_K2, USEM_REG_DBG_MODE1_CFG_BB_K2, + USEM_REG_SYNC_DBG_EMPTY, USEM_REG_SLOW_DBG_EMPTY_BB_K2, UCM_REG_CTX_RBC_ACCS, 2, UCM_REG_AGG_CON_CTX, 13, UCM_REG_SM_CON_CTX, 3, UCM_REG_AGG_TASK_CTX, 3, UCM_REG_SM_TASK_CTX}, + /* Xstorm */ {'X', BLOCK_XSEM, {DBG_BUS_CLIENT_RBCX, DBG_BUS_CLIENT_RBCX}, false, XSEM_REG_FAST_MEMORY, - XSEM_REG_DBG_FRAME_MODE, XSEM_REG_SLOW_DBG_ACTIVE, - XSEM_REG_SLOW_DBG_MODE, XSEM_REG_DBG_MODE1_CFG, - XSEM_REG_SYNC_DBG_EMPTY, XSEM_REG_SLOW_DBG_EMPTY, + XSEM_REG_DBG_FRAME_MODE_BB_K2, XSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + XSEM_REG_SLOW_DBG_MODE_BB_K2, XSEM_REG_DBG_MODE1_CFG_BB_K2, + XSEM_REG_SYNC_DBG_EMPTY, XSEM_REG_SLOW_DBG_EMPTY_BB_K2, XCM_REG_CTX_RBC_ACCS, 9, XCM_REG_AGG_CON_CTX, 15, XCM_REG_SM_CON_CTX, 0, 0, 0, 0}, + /* Ystorm */ {'Y', BLOCK_YSEM, {DBG_BUS_CLIENT_RBCX, DBG_BUS_CLIENT_RBCY}, false, YSEM_REG_FAST_MEMORY, - YSEM_REG_DBG_FRAME_MODE, YSEM_REG_SLOW_DBG_ACTIVE, - YSEM_REG_SLOW_DBG_MODE, YSEM_REG_DBG_MODE1_CFG, - YSEM_REG_SYNC_DBG_EMPTY, TSEM_REG_SLOW_DBG_EMPTY, + YSEM_REG_DBG_FRAME_MODE_BB_K2, YSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + YSEM_REG_SLOW_DBG_MODE_BB_K2, YSEM_REG_DBG_MODE1_CFG_BB_K2, + YSEM_REG_SYNC_DBG_EMPTY, TSEM_REG_SLOW_DBG_EMPTY_BB_K2, YCM_REG_CTX_RBC_ACCS, 2, YCM_REG_AGG_CON_CTX, 3, YCM_REG_SM_CON_CTX, 2, YCM_REG_AGG_TASK_CTX, 12, YCM_REG_SM_TASK_CTX}, + /* Pstorm */ {'P', BLOCK_PSEM, {DBG_BUS_CLIENT_RBCS, DBG_BUS_CLIENT_RBCS}, true, PSEM_REG_FAST_MEMORY, - PSEM_REG_DBG_FRAME_MODE, PSEM_REG_SLOW_DBG_ACTIVE, - PSEM_REG_SLOW_DBG_MODE, PSEM_REG_DBG_MODE1_CFG, - PSEM_REG_SYNC_DBG_EMPTY, PSEM_REG_SLOW_DBG_EMPTY, + PSEM_REG_DBG_FRAME_MODE_BB_K2, PSEM_REG_SLOW_DBG_ACTIVE_BB_K2, + PSEM_REG_SLOW_DBG_MODE_BB_K2, PSEM_REG_DBG_MODE1_CFG_BB_K2, + PSEM_REG_SYNC_DBG_EMPTY, PSEM_REG_SLOW_DBG_EMPTY_BB_K2, PCM_REG_CTX_RBC_ACCS, 0, 0, 10, PCM_REG_SM_CON_CTX, @@ -498,6 +576,7 @@ static struct storm_defs s_storm_defs[] = { }; /* Block definitions array */ + static struct block_defs block_grc_defs = { "grc", {true, true}, false, 0, @@ -587,9 +666,11 @@ static struct block_defs block_pcie_defs = { "pcie", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCH}, - PCIE_REG_DBG_COMMON_SELECT, PCIE_REG_DBG_COMMON_DWORD_ENABLE, - PCIE_REG_DBG_COMMON_SHIFT, PCIE_REG_DBG_COMMON_FORCE_VALID, - PCIE_REG_DBG_COMMON_FORCE_FRAME, + PCIE_REG_DBG_COMMON_SELECT_K2, + PCIE_REG_DBG_COMMON_DWORD_ENABLE_K2, + PCIE_REG_DBG_COMMON_SHIFT_K2, + PCIE_REG_DBG_COMMON_FORCE_VALID_K2, + PCIE_REG_DBG_COMMON_FORCE_FRAME_K2, false, false, MAX_DBG_RESET_REGS, 0 }; @@ -691,9 +772,9 @@ static struct block_defs block_pglcs_defs = { "pglcs", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCH}, - PGLCS_REG_DBG_SELECT, PGLCS_REG_DBG_DWORD_ENABLE, - PGLCS_REG_DBG_SHIFT, PGLCS_REG_DBG_FORCE_VALID, - PGLCS_REG_DBG_FORCE_FRAME, + PGLCS_REG_DBG_SELECT_K2, PGLCS_REG_DBG_DWORD_ENABLE_K2, + PGLCS_REG_DBG_SHIFT_K2, PGLCS_REG_DBG_FORCE_VALID_K2, + PGLCS_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV, 2 }; @@ -991,10 +1072,11 @@ static struct block_defs block_yuld_defs = { "yuld", {true, true}, false, 0, {DBG_BUS_CLIENT_RBCU, DBG_BUS_CLIENT_RBCU}, - YULD_REG_DBG_SELECT, YULD_REG_DBG_DWORD_ENABLE, - YULD_REG_DBG_SHIFT, YULD_REG_DBG_FORCE_VALID, - YULD_REG_DBG_FORCE_FRAME, - true, true, DBG_RESET_REG_MISC_PL_PDA_VMAIN_2, 15 + YULD_REG_DBG_SELECT_BB_K2, YULD_REG_DBG_DWORD_ENABLE_BB_K2, + YULD_REG_DBG_SHIFT_BB_K2, YULD_REG_DBG_FORCE_VALID_BB_K2, + YULD_REG_DBG_FORCE_FRAME_BB_K2, + true, true, DBG_RESET_REG_MISC_PL_PDA_VMAIN_2, + 15 }; static struct block_defs block_xyld_defs = { @@ -1143,9 +1225,9 @@ static struct block_defs block_umac_defs = { "umac", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCZ}, - UMAC_REG_DBG_SELECT, UMAC_REG_DBG_DWORD_ENABLE, - UMAC_REG_DBG_SHIFT, UMAC_REG_DBG_FORCE_VALID, - UMAC_REG_DBG_FORCE_FRAME, + UMAC_REG_DBG_SELECT_K2, UMAC_REG_DBG_DWORD_ENABLE_K2, + UMAC_REG_DBG_SHIFT_K2, UMAC_REG_DBG_FORCE_VALID_K2, + UMAC_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV, 6 }; @@ -1177,9 +1259,9 @@ static struct block_defs block_wol_defs = { "wol", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCZ}, - WOL_REG_DBG_SELECT, WOL_REG_DBG_DWORD_ENABLE, - WOL_REG_DBG_SHIFT, WOL_REG_DBG_FORCE_VALID, - WOL_REG_DBG_FORCE_FRAME, + WOL_REG_DBG_SELECT_K2, WOL_REG_DBG_DWORD_ENABLE_K2, + WOL_REG_DBG_SHIFT_K2, WOL_REG_DBG_FORCE_VALID_K2, + WOL_REG_DBG_FORCE_FRAME_K2, true, true, DBG_RESET_REG_MISC_PL_PDA_VAUX, 7 }; @@ -1187,9 +1269,9 @@ static struct block_defs block_bmbn_defs = { "bmbn", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCB}, - BMBN_REG_DBG_SELECT, BMBN_REG_DBG_DWORD_ENABLE, - BMBN_REG_DBG_SHIFT, BMBN_REG_DBG_FORCE_VALID, - BMBN_REG_DBG_FORCE_FRAME, + BMBN_REG_DBG_SELECT_K2, BMBN_REG_DBG_DWORD_ENABLE_K2, + BMBN_REG_DBG_SHIFT_K2, BMBN_REG_DBG_FORCE_VALID_K2, + BMBN_REG_DBG_FORCE_FRAME_K2, false, false, MAX_DBG_RESET_REGS, 0 }; @@ -1204,9 +1286,9 @@ static struct block_defs block_nwm_defs = { "nwm", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCW}, - NWM_REG_DBG_SELECT, NWM_REG_DBG_DWORD_ENABLE, - NWM_REG_DBG_SHIFT, NWM_REG_DBG_FORCE_VALID, - NWM_REG_DBG_FORCE_FRAME, + NWM_REG_DBG_SELECT_K2, NWM_REG_DBG_DWORD_ENABLE_K2, + NWM_REG_DBG_SHIFT_K2, NWM_REG_DBG_FORCE_VALID_K2, + NWM_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV_2, 0 }; @@ -1214,9 +1296,9 @@ static struct block_defs block_nws_defs = { "nws", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCW}, - NWS_REG_DBG_SELECT, NWS_REG_DBG_DWORD_ENABLE, - NWS_REG_DBG_SHIFT, NWS_REG_DBG_FORCE_VALID, - NWS_REG_DBG_FORCE_FRAME, + NWS_REG_DBG_SELECT_K2, NWS_REG_DBG_DWORD_ENABLE_K2, + NWS_REG_DBG_SHIFT_K2, NWS_REG_DBG_FORCE_VALID_K2, + NWS_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV, 12 }; @@ -1224,9 +1306,9 @@ static struct block_defs block_ms_defs = { "ms", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCZ}, - MS_REG_DBG_SELECT, MS_REG_DBG_DWORD_ENABLE, - MS_REG_DBG_SHIFT, MS_REG_DBG_FORCE_VALID, - MS_REG_DBG_FORCE_FRAME, + MS_REG_DBG_SELECT_K2, MS_REG_DBG_DWORD_ENABLE_K2, + MS_REG_DBG_SHIFT_K2, MS_REG_DBG_FORCE_VALID_K2, + MS_REG_DBG_FORCE_FRAME_K2, true, false, DBG_RESET_REG_MISCS_PL_HV, 13 }; @@ -1234,9 +1316,11 @@ static struct block_defs block_phy_pcie_defs = { "phy_pcie", {false, true}, false, 0, {MAX_DBG_BUS_CLIENTS, DBG_BUS_CLIENT_RBCH}, - PCIE_REG_DBG_COMMON_SELECT, PCIE_REG_DBG_COMMON_DWORD_ENABLE, - PCIE_REG_DBG_COMMON_SHIFT, PCIE_REG_DBG_COMMON_FORCE_VALID, - PCIE_REG_DBG_COMMON_FORCE_FRAME, + PCIE_REG_DBG_COMMON_SELECT_K2, + PCIE_REG_DBG_COMMON_DWORD_ENABLE_K2, + PCIE_REG_DBG_COMMON_SHIFT_K2, + PCIE_REG_DBG_COMMON_FORCE_VALID_K2, + PCIE_REG_DBG_COMMON_FORCE_FRAME_K2, false, false, MAX_DBG_RESET_REGS, 0 }; @@ -1261,6 +1345,13 @@ static struct block_defs block_rgfs_defs = { false, false, MAX_DBG_RESET_REGS, 0 }; +static struct block_defs block_rgsrc_defs = { + "rgsrc", {false, false}, false, 0, + {MAX_DBG_BUS_CLIENTS, MAX_DBG_BUS_CLIENTS}, + 0, 0, 0, 0, 0, + false, false, MAX_DBG_RESET_REGS, 0 +}; + static struct block_defs block_tgfs_defs = { "tgfs", {false, false}, false, 0, {MAX_DBG_BUS_CLIENTS, MAX_DBG_BUS_CLIENTS}, @@ -1268,6 +1359,13 @@ static struct block_defs block_tgfs_defs = { false, false, MAX_DBG_RESET_REGS, 0 }; +static struct block_defs block_tgsrc_defs = { + "tgsrc", {false, false}, false, 0, + {MAX_DBG_BUS_CLIENTS, MAX_DBG_BUS_CLIENTS}, + 0, 0, 0, 0, 0, + false, false, MAX_DBG_RESET_REGS, 0 +}; + static struct block_defs block_ptld_defs = { "ptld", {false, false}, false, 0, {MAX_DBG_BUS_CLIENTS, MAX_DBG_BUS_CLIENTS}, @@ -1350,6 +1448,8 @@ static struct block_defs *s_block_defs[MAX_BLOCK_ID] = { &block_muld_defs, &block_yuld_defs, &block_xyld_defs, + &block_ptld_defs, + &block_ypld_defs, &block_prm_defs, &block_pbf_pb1_defs, &block_pbf_pb2_defs, @@ -1363,6 +1463,10 @@ static struct block_defs *s_block_defs[MAX_BLOCK_ID] = { &block_tcfc_defs, &block_igu_defs, &block_cau_defs, + &block_rgfs_defs, + &block_rgsrc_defs, + &block_tgfs_defs, + &block_tgsrc_defs, &block_umac_defs, &block_xmac_defs, &block_dbg_defs, @@ -1376,10 +1480,6 @@ static struct block_defs *s_block_defs[MAX_BLOCK_ID] = { &block_phy_pcie_defs, &block_led_defs, &block_avs_wrap_defs, - &block_rgfs_defs, - &block_tgfs_defs, - &block_ptld_defs, - &block_ypld_defs, &block_misc_aeu_defs, &block_bar0_map_defs, }; @@ -1392,66 +1492,151 @@ static struct platform_defs s_platform_defs[] = { }; static struct grc_param_defs s_grc_param_defs[] = { - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_TSTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_MSTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_USTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_XSTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_YSTORM */ - {{1, 1}, 0, 1, false, 1, 1}, /* DBG_GRC_PARAM_DUMP_PSTORM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_REGS */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_RAM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_PBUF */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_IOR */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_VFC */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_CM_CTX */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_ILT */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_RSS */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_CAU */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_QM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_MCP */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_RESERVED */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_CFC */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_IGU */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_BRB */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_BTB */ - {{0, 0}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_BMB */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_NIG */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_MULD */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_PRS */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_DMAE */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_TM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_SDM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_DIF */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_STATIC */ - {{0, 0}, 0, 1, false, 0, 0}, /* DBG_GRC_PARAM_UNSTALL */ + /* DBG_GRC_PARAM_DUMP_TSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_MSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_USTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_XSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_YSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_PSTORM */ + {{1, 1}, 0, 1, false, 1, 1}, + + /* DBG_GRC_PARAM_DUMP_REGS */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_RAM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_PBUF */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_IOR */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_VFC */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_CM_CTX */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_ILT */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_RSS */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_CAU */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_QM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_MCP */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_RESERVED */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_CFC */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_IGU */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_BRB */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_BTB */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_BMB */ + {{0, 0}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_NIG */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_MULD */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_PRS */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_DMAE */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_TM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_SDM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_DIF */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_STATIC */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_UNSTALL */ + {{0, 0}, 0, 1, false, 0, 0}, + + /* DBG_GRC_PARAM_NUM_LCIDS */ {{MAX_LCIDS, MAX_LCIDS}, 1, MAX_LCIDS, false, MAX_LCIDS, - MAX_LCIDS}, /* DBG_GRC_PARAM_NUM_LCIDS */ + MAX_LCIDS}, + + /* DBG_GRC_PARAM_NUM_LTIDS */ {{MAX_LTIDS, MAX_LTIDS}, 1, MAX_LTIDS, false, MAX_LTIDS, - MAX_LTIDS}, /* DBG_GRC_PARAM_NUM_LTIDS */ - {{0, 0}, 0, 1, true, 0, 0}, /* DBG_GRC_PARAM_EXCLUDE_ALL */ - {{0, 0}, 0, 1, true, 0, 0}, /* DBG_GRC_PARAM_CRASH */ - {{0, 0}, 0, 1, false, 1, 0}, /* DBG_GRC_PARAM_PARITY_SAFE */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_CM */ - {{1, 1}, 0, 1, false, 0, 1}, /* DBG_GRC_PARAM_DUMP_PHY */ - {{0, 0}, 0, 1, false, 0, 0}, /* DBG_GRC_PARAM_NO_MCP */ - {{0, 0}, 0, 1, false, 0, 0} /* DBG_GRC_PARAM_NO_FW_VER */ + MAX_LTIDS}, + + /* DBG_GRC_PARAM_EXCLUDE_ALL */ + {{0, 0}, 0, 1, true, 0, 0}, + + /* DBG_GRC_PARAM_CRASH */ + {{0, 0}, 0, 1, true, 0, 0}, + + /* DBG_GRC_PARAM_PARITY_SAFE */ + {{0, 0}, 0, 1, false, 1, 0}, + + /* DBG_GRC_PARAM_DUMP_CM */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_DUMP_PHY */ + {{1, 1}, 0, 1, false, 0, 1}, + + /* DBG_GRC_PARAM_NO_MCP */ + {{0, 0}, 0, 1, false, 0, 0}, + + /* DBG_GRC_PARAM_NO_FW_VER */ + {{0, 0}, 0, 1, false, 0, 0} }; static struct rss_mem_defs s_rss_mem_defs[] = { { "rss_mem_cid", "rss_cid", 0, {256, 320}, {32, 32} }, + { "rss_mem_key_msb", "rss_key", 1024, {128, 208}, {256, 256} }, + { "rss_mem_key_lsb", "rss_key", 2048, {128, 208}, {64, 64} }, + { "rss_mem_info", "rss_info", 3072, {128, 208}, {16, 16} }, + { "rss_mem_ind", "rss_ind", 4096, - {(128 * 128), (128 * 208)}, + {16384, 26624}, {16, 16} } }; @@ -1466,50 +1651,71 @@ static struct big_ram_defs s_big_ram_defs[] = { { "BRB", MEM_GROUP_BRB_MEM, MEM_GROUP_BRB_RAM, DBG_GRC_PARAM_DUMP_BRB, BRB_REG_BIG_RAM_ADDRESS, BRB_REG_BIG_RAM_DATA, {4800, 5632} }, + { "BTB", MEM_GROUP_BTB_MEM, MEM_GROUP_BTB_RAM, DBG_GRC_PARAM_DUMP_BTB, BTB_REG_BIG_RAM_ADDRESS, BTB_REG_BIG_RAM_DATA, {2880, 3680} }, + { "BMB", MEM_GROUP_BMB_MEM, MEM_GROUP_BMB_RAM, DBG_GRC_PARAM_DUMP_BMB, BMB_REG_BIG_RAM_ADDRESS, BMB_REG_BIG_RAM_DATA, {1152, 1152} } }; static struct reset_reg_defs s_reset_regs_defs[] = { + /* DBG_RESET_REG_MISCS_PL_UA */ { MISCS_REG_RESET_PL_UA, 0x0, - {true, true} }, /* DBG_RESET_REG_MISCS_PL_UA */ + {true, true} }, + + /* DBG_RESET_REG_MISCS_PL_HV */ { MISCS_REG_RESET_PL_HV, 0x0, - {true, true} }, /* DBG_RESET_REG_MISCS_PL_HV */ - { MISCS_REG_RESET_PL_HV_2, 0x0, - {false, true} }, /* DBG_RESET_REG_MISCS_PL_HV_2 */ + {true, true} }, + + /* DBG_RESET_REG_MISCS_PL_HV_2 */ + { MISCS_REG_RESET_PL_HV_2_K2, 0x0, + {false, true} }, + + /* DBG_RESET_REG_MISC_PL_UA */ { MISC_REG_RESET_PL_UA, 0x0, - {true, true} }, /* DBG_RESET_REG_MISC_PL_UA */ + {true, true} }, + + /* DBG_RESET_REG_MISC_PL_HV */ { MISC_REG_RESET_PL_HV, 0x0, - {true, true} }, /* DBG_RESET_REG_MISC_PL_HV */ + {true, true} }, + + /* DBG_RESET_REG_MISC_PL_PDA_VMAIN_1 */ { MISC_REG_RESET_PL_PDA_VMAIN_1, 0x4404040, - {true, true} }, /* DBG_RESET_REG_MISC_PL_PDA_VMAIN_1 */ + {true, true} }, + + /* DBG_RESET_REG_MISC_PL_PDA_VMAIN_2 */ { MISC_REG_RESET_PL_PDA_VMAIN_2, 0x7c00007, - {true, true} }, /* DBG_RESET_REG_MISC_PL_PDA_VMAIN_2 */ + {true, true} }, + + /* DBG_RESET_REG_MISC_PL_PDA_VAUX */ { MISC_REG_RESET_PL_PDA_VAUX, 0x2, - {true, true} }, /* DBG_RESET_REG_MISC_PL_PDA_VAUX */ + {true, true} }, }; static struct phy_defs s_phy_defs[] = { - {"nw_phy", NWS_REG_NWS_CMU, PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_7_0, - PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_15_8, - PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_7_0, - PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_11_8}, - {"sgmii_phy", MS_REG_MS_CMU, PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X132, - PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X133, - PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X130, - PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X131}, - {"pcie_phy0", PHY_PCIE_REG_PHY0, PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131}, - {"pcie_phy1", PHY_PCIE_REG_PHY1, PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130, - PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131}, + {"nw_phy", NWS_REG_NWS_CMU_K2, + PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_7_0_K2, + PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_15_8_K2, + PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_7_0_K2, + PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_11_8_K2}, + {"sgmii_phy", MS_REG_MS_CMU_K2, + PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X132_K2, + PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X133_K2, + PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X130_K2, + PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X131_K2}, + {"pcie_phy0", PHY_PCIE_REG_PHY0_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131_K2}, + {"pcie_phy1", PHY_PCIE_REG_PHY1_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130_K2, + PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131_K2}, }; /**************************** Private Functions ******************************/ @@ -1556,7 +1762,7 @@ static enum dbg_status qed_dbg_dev_init(struct qed_hwfn *p_hwfn, dev_data->chip_id = CHIP_K2; dev_data->mode_enable[MODE_K2] = 1; } else if (QED_IS_BB_B0(p_hwfn->cdev)) { - dev_data->chip_id = CHIP_BB_B0; + dev_data->chip_id = CHIP_BB; dev_data->mode_enable[MODE_BB] = 1; } else { return DBG_STATUS_UNKNOWN_CHIP; @@ -1569,9 +1775,20 @@ static enum dbg_status qed_dbg_dev_init(struct qed_hwfn *p_hwfn, qed_dbg_grc_init_params(p_hwfn); dev_data->initialized = true; + return DBG_STATUS_OK; } +static struct dbg_bus_block *get_dbg_bus_block_desc(struct qed_hwfn *p_hwfn, + enum block_id block_id) +{ + struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; + + return (struct dbg_bus_block *)&dbg_bus_blocks[block_id * + MAX_CHIP_IDS + + dev_data->chip_id]; +} + /* Reads the FW info structure for the specified Storm from the chip, * and writes it to the specified fw_info pointer. */ @@ -1579,25 +1796,28 @@ static void qed_read_fw_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u8 storm_id, struct fw_info *fw_info) { - /* Read first the address that points to fw_info location. - * The address is located in the last line of the Storm RAM. - */ - u32 addr = s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_INT_RAM + - DWORDS_TO_BYTES(SEM_FAST_REG_INT_RAM_SIZE) - - sizeof(struct fw_info_location); + struct storm_defs *storm = &s_storm_defs[storm_id]; struct fw_info_location fw_info_location; - u32 *dest = (u32 *)&fw_info_location; - u32 i; + u32 addr, i, *dest; memset(&fw_info_location, 0, sizeof(fw_info_location)); memset(fw_info, 0, sizeof(*fw_info)); + + /* Read first the address that points to fw_info location. + * The address is located in the last line of the Storm RAM. + */ + addr = storm->sem_fast_mem_addr + SEM_FAST_REG_INT_RAM + + DWORDS_TO_BYTES(SEM_FAST_REG_INT_RAM_SIZE) - + sizeof(fw_info_location); + dest = (u32 *)&fw_info_location; + for (i = 0; i < BYTES_TO_DWORDS(sizeof(fw_info_location)); i++, addr += BYTES_IN_DWORD) dest[i] = qed_rd(p_hwfn, p_ptt, addr); + + /* Read FW version info from Storm RAM */ if (fw_info_location.size > 0 && fw_info_location.size <= sizeof(*fw_info)) { - /* Read FW version info from Storm RAM */ addr = fw_info_location.grc_addr; dest = (u32 *)fw_info; for (i = 0; i < BYTES_TO_DWORDS(fw_info_location.size); @@ -1606,27 +1826,30 @@ static void qed_read_fw_info(struct qed_hwfn *p_hwfn, } } -/* Dumps the specified string to the specified buffer. Returns the dumped size - * in bytes (actual length + 1 for the null character termination). +/* Dumps the specified string to the specified buffer. + * Returns the dumped size in bytes. */ static u32 qed_dump_str(char *dump_buf, bool dump, const char *str) { if (dump) strcpy(dump_buf, str); + return (u32)strlen(str) + 1; } -/* Dumps zeros to align the specified buffer to dwords. Returns the dumped size - * in bytes. +/* Dumps zeros to align the specified buffer to dwords. + * Returns the dumped size in bytes. */ static u32 qed_dump_align(char *dump_buf, bool dump, u32 byte_offset) { - u8 offset_in_dword = (u8)(byte_offset & 0x3), align_size; + u8 offset_in_dword, align_size; + offset_in_dword = (u8)(byte_offset & 0x3); align_size = offset_in_dword ? BYTES_IN_DWORD - offset_in_dword : 0; if (dump && align_size) memset(dump_buf, 0, align_size); + return align_size; } @@ -1653,6 +1876,7 @@ static u32 qed_dump_str_param(u32 *dump_buf, /* Align buffer to next dword */ offset += qed_dump_align(char_buf + offset, dump, offset); + return BYTES_TO_DWORDS(offset); } @@ -1681,6 +1905,7 @@ static u32 qed_dump_num_param(u32 *dump_buf, if (dump) *(dump_buf + offset) = param_val; offset++; + return offset; } @@ -1695,7 +1920,6 @@ static u32 qed_dump_fw_ver_param(struct qed_hwfn *p_hwfn, char fw_ver_str[16] = EMPTY_FW_VERSION_STR; char fw_img_str[16] = EMPTY_FW_IMAGE_STR; struct fw_info fw_info = { {0}, {0} }; - int printed_chars; u32 offset = 0; if (dump && !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_FW_VER)) { @@ -1705,37 +1929,32 @@ static u32 qed_dump_fw_ver_param(struct qed_hwfn *p_hwfn, for (storm_id = 0; storm_id < MAX_DBG_STORMS && !found; storm_id++) { - /* Read FW version/image */ - if (!dev_data->block_in_reset - [s_storm_defs[storm_id].block_id]) { - /* read FW info for the current Storm */ - qed_read_fw_info(p_hwfn, - p_ptt, storm_id, &fw_info); - - /* Create FW version/image strings */ - printed_chars = - snprintf(fw_ver_str, - sizeof(fw_ver_str), - "%d_%d_%d_%d", - fw_info.ver.num.major, - fw_info.ver.num.minor, - fw_info.ver.num.rev, - fw_info.ver.num.eng); - if (printed_chars < 0 || printed_chars >= - sizeof(fw_ver_str)) - DP_NOTICE(p_hwfn, - "Unexpected debug error: invalid FW version string\n"); - switch (fw_info.ver.image_id) { - case FW_IMG_MAIN: - strcpy(fw_img_str, "main"); - break; - default: - strcpy(fw_img_str, "unknown"); - break; - } + struct storm_defs *storm = &s_storm_defs[storm_id]; + + /* Read FW version/image */ + if (dev_data->block_in_reset[storm->block_id]) + continue; - found = true; + /* Read FW info for the current Storm */ + qed_read_fw_info(p_hwfn, p_ptt, storm_id, &fw_info); + + /* Create FW version/image strings */ + if (snprintf(fw_ver_str, sizeof(fw_ver_str), + "%d_%d_%d_%d", fw_info.ver.num.major, + fw_info.ver.num.minor, fw_info.ver.num.rev, + fw_info.ver.num.eng) < 0) + DP_NOTICE(p_hwfn, + "Unexpected debug error: invalid FW version string\n"); + switch (fw_info.ver.image_id) { + case FW_IMG_MAIN: + strcpy(fw_img_str, "main"); + break; + default: + strcpy(fw_img_str, "unknown"); + break; } + + found = true; } } @@ -1747,6 +1966,7 @@ static u32 qed_dump_fw_ver_param(struct qed_hwfn *p_hwfn, offset += qed_dump_num_param(dump_buf + offset, dump, "fw-timestamp", fw_info.ver.timestamp); + return offset; } @@ -1759,17 +1979,18 @@ static u32 qed_dump_mfw_ver_param(struct qed_hwfn *p_hwfn, { char mfw_ver_str[16] = EMPTY_FW_VERSION_STR; - if (dump && !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_FW_VER)) { + if (dump && + !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_FW_VER)) { u32 global_section_offsize, global_section_addr, mfw_ver; u32 public_data_addr, global_section_offsize_addr; - int printed_chars; - /* Find MCP public data GRC address. - * Needs to be ORed with MCP_REG_SCRATCH due to a HW bug. + /* Find MCP public data GRC address. Needs to be ORed with + * MCP_REG_SCRATCH due to a HW bug. */ - public_data_addr = qed_rd(p_hwfn, p_ptt, + public_data_addr = qed_rd(p_hwfn, + p_ptt, MISC_REG_SHARED_MEM_ADDR) | - MCP_REG_SCRATCH; + MCP_REG_SCRATCH; /* Find MCP public global section offset */ global_section_offsize_addr = public_data_addr + @@ -1778,9 +1999,9 @@ static u32 qed_dump_mfw_ver_param(struct qed_hwfn *p_hwfn, sizeof(offsize_t) * PUBLIC_GLOBAL; global_section_offsize = qed_rd(p_hwfn, p_ptt, global_section_offsize_addr); - global_section_addr = MCP_REG_SCRATCH + - (global_section_offsize & - OFFSIZE_OFFSET_MASK) * 4; + global_section_addr = + MCP_REG_SCRATCH + + (global_section_offsize & OFFSIZE_OFFSET_MASK) * 4; /* Read MFW version from MCP public global section */ mfw_ver = qed_rd(p_hwfn, p_ptt, @@ -1788,13 +2009,9 @@ static u32 qed_dump_mfw_ver_param(struct qed_hwfn *p_hwfn, offsetof(struct public_global, mfw_ver)); /* Dump MFW version param */ - printed_chars = snprintf(mfw_ver_str, sizeof(mfw_ver_str), - "%d_%d_%d_%d", - (u8) (mfw_ver >> 24), - (u8) (mfw_ver >> 16), - (u8) (mfw_ver >> 8), - (u8) mfw_ver); - if (printed_chars < 0 || printed_chars >= sizeof(mfw_ver_str)) + if (snprintf(mfw_ver_str, sizeof(mfw_ver_str), "%d_%d_%d_%d", + (u8)(mfw_ver >> 24), (u8)(mfw_ver >> 16), + (u8)(mfw_ver >> 8), (u8)mfw_ver) < 0) DP_NOTICE(p_hwfn, "Unexpected debug error: invalid MFW version string\n"); } @@ -1820,11 +2037,12 @@ static u32 qed_dump_common_global_params(struct qed_hwfn *p_hwfn, bool dump, u8 num_specific_global_params) { - u8 num_params = NUM_COMMON_GLOBAL_PARAMS + num_specific_global_params; struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; u32 offset = 0; + u8 num_params; - /* Find platform string and dump global params section header */ + /* Dump global params section header */ + num_params = NUM_COMMON_GLOBAL_PARAMS + num_specific_global_params; offset += qed_dump_section_hdr(dump_buf + offset, dump, "global_params", num_params); @@ -1846,25 +2064,29 @@ static u32 qed_dump_common_global_params(struct qed_hwfn *p_hwfn, offset += qed_dump_num_param(dump_buf + offset, dump, "pci-func", p_hwfn->abs_pf_id); + return offset; } -/* Writes the last section to the specified buffer at the given offset. - * Returns the dumped size in dwords. +/* Writes the "last" section (including CRC) to the specified buffer at the + * given offset. Returns the dumped size in dwords. */ -static u32 qed_dump_last_section(u32 *dump_buf, u32 offset, bool dump) +static u32 qed_dump_last_section(struct qed_hwfn *p_hwfn, + u32 *dump_buf, u32 offset, bool dump) { - u32 start_offset = offset, crc = ~0; + u32 start_offset = offset; /* Dump CRC section header */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "last", 0); - /* Calculate CRC32 and add it to the dword following the "last" section. - */ + /* Calculate CRC32 and add it to the dword after the "last" section */ if (dump) - *(dump_buf + offset) = ~crc32(crc, (u8 *)dump_buf, + *(dump_buf + offset) = ~crc32(0xffffffff, + (u8 *)dump_buf, DWORDS_TO_BYTES(offset)); + offset++; + return offset - start_offset; } @@ -1883,11 +2105,12 @@ static void qed_update_blocks_reset_state(struct qed_hwfn *p_hwfn, p_ptt, s_reset_regs_defs[i].addr); /* Check if blocks are in reset */ - for (i = 0; i < MAX_BLOCK_ID; i++) - dev_data->block_in_reset[i] = - s_block_defs[i]->has_reset_bit && - !(reg_val[s_block_defs[i]->reset_reg] & - BIT(s_block_defs[i]->reset_bit_offset)); + for (i = 0; i < MAX_BLOCK_ID; i++) { + struct block_defs *block = s_block_defs[i]; + + dev_data->block_in_reset[i] = block->has_reset_bit && + !(reg_val[block->reset_reg] & BIT(block->reset_bit_offset)); + } } /* Enable / disable the Debug block */ @@ -1902,12 +2125,12 @@ static void qed_bus_reset_dbg_block(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { u32 dbg_reset_reg_addr, old_reset_reg_val, new_reset_reg_val; + struct block_defs *dbg_block = s_block_defs[BLOCK_DBG]; - dbg_reset_reg_addr = - s_reset_regs_defs[s_block_defs[BLOCK_DBG]->reset_reg].addr; + dbg_reset_reg_addr = s_reset_regs_defs[dbg_block->reset_reg].addr; old_reset_reg_val = qed_rd(p_hwfn, p_ptt, dbg_reset_reg_addr); - new_reset_reg_val = old_reset_reg_val & - ~BIT(s_block_defs[BLOCK_DBG]->reset_bit_offset); + new_reset_reg_val = + old_reset_reg_val & ~BIT(dbg_block->reset_bit_offset); qed_wr(p_hwfn, p_ptt, dbg_reset_reg_addr, new_reset_reg_val); qed_wr(p_hwfn, p_ptt, dbg_reset_reg_addr, old_reset_reg_val); @@ -1920,8 +2143,8 @@ static void qed_bus_set_framing_mode(struct qed_hwfn *p_hwfn, qed_wr(p_hwfn, p_ptt, DBG_REG_FRAMING_MODE, (u8)mode); } -/* Enable / disable Debug Bus clients according to the specified mask. - * (1 = enable, 0 = disable) +/* Enable / disable Debug Bus clients according to the specified mask + * (1 = enable, 0 = disable). */ static void qed_bus_enable_clients(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 client_mask) @@ -1931,10 +2154,14 @@ static void qed_bus_enable_clients(struct qed_hwfn *p_hwfn, static bool qed_is_mode_match(struct qed_hwfn *p_hwfn, u16 *modes_buf_offset) { - const u32 *ptr = s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr; struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - u8 tree_val = ((u8 *)ptr)[(*modes_buf_offset)++]; bool arg1, arg2; + const u32 *ptr; + u8 tree_val; + + /* Get next element from modes tree buffer */ + ptr = s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr; + tree_val = ((u8 *)ptr)[(*modes_buf_offset)++]; switch (tree_val) { case INIT_MODE_OP_NOT: @@ -1974,75 +2201,81 @@ static bool qed_grc_is_storm_included(struct qed_hwfn *p_hwfn, static bool qed_grc_is_mem_included(struct qed_hwfn *p_hwfn, enum block_id block_id, u8 mem_group_id) { + struct block_defs *block = s_block_defs[block_id]; u8 i; /* Check Storm match */ - if (s_block_defs[block_id]->associated_to_storm && + if (block->associated_to_storm && !qed_grc_is_storm_included(p_hwfn, - (enum dbg_storms)s_block_defs[block_id]->storm_id)) + (enum dbg_storms)block->storm_id)) return false; - for (i = 0; i < NUM_BIG_RAM_TYPES; i++) - if (mem_group_id == s_big_ram_defs[i].mem_group_id || - mem_group_id == s_big_ram_defs[i].ram_mem_group_id) - return qed_grc_is_included(p_hwfn, - s_big_ram_defs[i].grc_param); - if (mem_group_id == MEM_GROUP_PXP_ILT || mem_group_id == - MEM_GROUP_PXP_MEM) + for (i = 0; i < NUM_BIG_RAM_TYPES; i++) { + struct big_ram_defs *big_ram = &s_big_ram_defs[i]; + + if (mem_group_id == big_ram->mem_group_id || + mem_group_id == big_ram->ram_mem_group_id) + return qed_grc_is_included(p_hwfn, big_ram->grc_param); + } + + switch (mem_group_id) { + case MEM_GROUP_PXP_ILT: + case MEM_GROUP_PXP_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_PXP); - if (mem_group_id == MEM_GROUP_RAM) + case MEM_GROUP_RAM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_RAM); - if (mem_group_id == MEM_GROUP_PBUF) + case MEM_GROUP_PBUF: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_PBUF); - if (mem_group_id == MEM_GROUP_CAU_MEM || - mem_group_id == MEM_GROUP_CAU_SB || - mem_group_id == MEM_GROUP_CAU_PI) + case MEM_GROUP_CAU_MEM: + case MEM_GROUP_CAU_SB: + case MEM_GROUP_CAU_PI: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CAU); - if (mem_group_id == MEM_GROUP_QM_MEM) + case MEM_GROUP_QM_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_QM); - if (mem_group_id == MEM_GROUP_CONN_CFC_MEM || - mem_group_id == MEM_GROUP_TASK_CFC_MEM) + case MEM_GROUP_CFC_MEM: + case MEM_GROUP_CONN_CFC_MEM: + case MEM_GROUP_TASK_CFC_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CFC); - if (mem_group_id == MEM_GROUP_IGU_MEM || mem_group_id == - MEM_GROUP_IGU_MSIX) + case MEM_GROUP_IGU_MEM: + case MEM_GROUP_IGU_MSIX: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_IGU); - if (mem_group_id == MEM_GROUP_MULD_MEM) + case MEM_GROUP_MULD_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_MULD); - if (mem_group_id == MEM_GROUP_PRS_MEM) + case MEM_GROUP_PRS_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_PRS); - if (mem_group_id == MEM_GROUP_DMAE_MEM) + case MEM_GROUP_DMAE_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_DMAE); - if (mem_group_id == MEM_GROUP_TM_MEM) + case MEM_GROUP_TM_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_TM); - if (mem_group_id == MEM_GROUP_SDM_MEM) + case MEM_GROUP_SDM_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_SDM); - if (mem_group_id == MEM_GROUP_TDIF_CTX || mem_group_id == - MEM_GROUP_RDIF_CTX) + case MEM_GROUP_TDIF_CTX: + case MEM_GROUP_RDIF_CTX: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_DIF); - if (mem_group_id == MEM_GROUP_CM_MEM) + case MEM_GROUP_CM_MEM: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CM); - if (mem_group_id == MEM_GROUP_IOR) + case MEM_GROUP_IOR: return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_IOR); - - return true; + default: + return true; + } } /* Stalls all Storms */ static void qed_grc_stall_storms(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool stall) { - u8 reg_val = stall ? 1 : 0; + u32 reg_addr; u8 storm_id; for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { - if (qed_grc_is_storm_included(p_hwfn, - (enum dbg_storms)storm_id)) { - u32 reg_addr = - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_STALL_0; + if (!qed_grc_is_storm_included(p_hwfn, + (enum dbg_storms)storm_id)) + continue; - qed_wr(p_hwfn, p_ptt, reg_addr, reg_val); - } + reg_addr = s_storm_defs[storm_id].sem_fast_mem_addr + + SEM_FAST_REG_STALL_0_BB_K2; + qed_wr(p_hwfn, p_ptt, reg_addr, stall ? 1 : 0); } msleep(STALL_DELAY_MS); @@ -2054,24 +2287,29 @@ static void qed_grc_unreset_blocks(struct qed_hwfn *p_hwfn, { struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; u32 reg_val[MAX_DBG_RESET_REGS] = { 0 }; - u32 i; + u32 block_id, i; /* Fill reset regs values */ - for (i = 0; i < MAX_BLOCK_ID; i++) - if (s_block_defs[i]->has_reset_bit && s_block_defs[i]->unreset) - reg_val[s_block_defs[i]->reset_reg] |= - BIT(s_block_defs[i]->reset_bit_offset); + for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { + struct block_defs *block = s_block_defs[block_id]; + + if (block->has_reset_bit && block->unreset) + reg_val[block->reset_reg] |= + BIT(block->reset_bit_offset); + } /* Write reset registers */ for (i = 0; i < MAX_DBG_RESET_REGS; i++) { - if (s_reset_regs_defs[i].exists[dev_data->chip_id]) { - reg_val[i] |= s_reset_regs_defs[i].unreset_val; - if (reg_val[i]) - qed_wr(p_hwfn, - p_ptt, - s_reset_regs_defs[i].addr + - RESET_REG_UNRESET_OFFSET, reg_val[i]); - } + if (!s_reset_regs_defs[i].exists[dev_data->chip_id]) + continue; + + reg_val[i] |= s_reset_regs_defs[i].unreset_val; + + if (reg_val[i]) + qed_wr(p_hwfn, + p_ptt, + s_reset_regs_defs[i].addr + + RESET_REG_UNRESET_OFFSET, reg_val[i]); } } @@ -2095,6 +2333,7 @@ qed_get_block_attn_regs(enum block_id block_id, enum dbg_attn_type attn_type, qed_get_block_attn_data(block_id, attn_type); *num_attn_regs = block_type_data->num_regs; + return &((const struct dbg_attn_reg *) s_dbg_arrays[BIN_BUF_DBG_ATTN_REGS].ptr)[block_type_data-> regs_offset]; @@ -2105,34 +2344,34 @@ static void qed_grc_clear_all_prty(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; + const struct dbg_attn_reg *attn_reg_arr; u8 reg_idx, num_attn_regs; u32 block_id; for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { - const struct dbg_attn_reg *attn_reg_arr; - if (dev_data->block_in_reset[block_id]) continue; attn_reg_arr = qed_get_block_attn_regs((enum block_id)block_id, ATTN_TYPE_PARITY, &num_attn_regs); + for (reg_idx = 0; reg_idx < num_attn_regs; reg_idx++) { const struct dbg_attn_reg *reg_data = &attn_reg_arr[reg_idx]; + u16 modes_buf_offset; + bool eval_mode; /* Check mode */ - bool eval_mode = GET_FIELD(reg_data->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; - u16 modes_buf_offset = + eval_mode = GET_FIELD(reg_data->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; + modes_buf_offset = GET_FIELD(reg_data->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); + /* If Mode match: clear parity status */ if (!eval_mode || qed_is_mode_match(p_hwfn, &modes_buf_offset)) - /* Mode match - read parity status read-clear - * register. - */ qed_rd(p_hwfn, p_ptt, DWORDS_TO_BYTES(reg_data-> sts_clr_address)); @@ -2142,11 +2381,11 @@ static void qed_grc_clear_all_prty(struct qed_hwfn *p_hwfn, /* Dumps GRC registers section header. Returns the dumped size in dwords. * The following parameters are dumped: - * - 'count' = num_dumped_entries - * - 'split' = split_type - * - 'id' = split_id (dumped only if split_id >= 0) - * - 'param_name' = param_val (user param, dumped only if param_name != NULL and - * param_val != NULL) + * - count: no. of dumped entries + * - split: split type + * - id: split ID (dumped only if split_id >= 0) + * - param_name: user parameter value (dumped only if param_name != NULL + * and param_val != NULL). */ static u32 qed_grc_dump_regs_hdr(u32 *dump_buf, bool dump, @@ -2170,84 +2409,100 @@ static u32 qed_grc_dump_regs_hdr(u32 *dump_buf, if (param_name && param_val) offset += qed_dump_str_param(dump_buf + offset, dump, param_name, param_val); + return offset; } /* Dumps the GRC registers in the specified address range. * Returns the dumped size in dwords. + * The addr and len arguments are specified in dwords. */ static u32 qed_grc_dump_addr_range(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u32 *dump_buf, - bool dump, u32 addr, u32 len) + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, u32 addr, u32 len, bool wide_bus) { u32 byte_addr = DWORDS_TO_BYTES(addr), offset = 0, i; - if (dump) - for (i = 0; i < len; i++, byte_addr += BYTES_IN_DWORD, offset++) - *(dump_buf + offset) = qed_rd(p_hwfn, p_ptt, byte_addr); - else - offset += len; + if (!dump) + return len; + + for (i = 0; i < len; i++, byte_addr += BYTES_IN_DWORD, offset++) + *(dump_buf + offset) = qed_rd(p_hwfn, p_ptt, byte_addr); + return offset; } -/* Dumps GRC registers sequence header. Returns the dumped size in dwords. */ -static u32 qed_grc_dump_reg_entry_hdr(u32 *dump_buf, bool dump, u32 addr, - u32 len) +/* Dumps GRC registers sequence header. Returns the dumped size in dwords. + * The addr and len arguments are specified in dwords. + */ +static u32 qed_grc_dump_reg_entry_hdr(u32 *dump_buf, + bool dump, u32 addr, u32 len) { if (dump) *dump_buf = addr | (len << REG_DUMP_LEN_SHIFT); + return 1; } -/* Dumps GRC registers sequence. Returns the dumped size in dwords. */ +/* Dumps GRC registers sequence. Returns the dumped size in dwords. + * The addr and len arguments are specified in dwords. + */ static u32 qed_grc_dump_reg_entry(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u32 *dump_buf, - bool dump, u32 addr, u32 len) + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, u32 addr, u32 len, bool wide_bus) { u32 offset = 0; offset += qed_grc_dump_reg_entry_hdr(dump_buf, dump, addr, len); offset += qed_grc_dump_addr_range(p_hwfn, p_ptt, - dump_buf + offset, dump, addr, len); + dump_buf + offset, + dump, addr, len, wide_bus); + return offset; } /* Dumps GRC registers sequence with skip cycle. * Returns the dumped size in dwords. + * - addr: start GRC address in dwords + * - total_len: total no. of dwords to dump + * - read_len: no. consecutive dwords to read + * - skip_len: no. of dwords to skip (and fill with zeros) */ static u32 qed_grc_dump_reg_entry_skip(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u32 *dump_buf, - bool dump, u32 addr, u32 total_len, + struct qed_ptt *p_ptt, + u32 *dump_buf, + bool dump, + u32 addr, + u32 total_len, u32 read_len, u32 skip_len) { u32 offset = 0, reg_offset = 0; offset += qed_grc_dump_reg_entry_hdr(dump_buf, dump, addr, total_len); - if (dump) { - while (reg_offset < total_len) { - u32 curr_len = min_t(u32, - read_len, - total_len - reg_offset); - offset += qed_grc_dump_addr_range(p_hwfn, - p_ptt, - dump_buf + offset, - dump, addr, curr_len); + + if (!dump) + return offset + total_len; + + while (reg_offset < total_len) { + u32 curr_len = min_t(u32, read_len, total_len - reg_offset); + + offset += qed_grc_dump_addr_range(p_hwfn, + p_ptt, + dump_buf + offset, + dump, addr, curr_len, false); + reg_offset += curr_len; + addr += curr_len; + + if (reg_offset < total_len) { + curr_len = min_t(u32, skip_len, total_len - skip_len); + memset(dump_buf + offset, 0, DWORDS_TO_BYTES(curr_len)); + offset += curr_len; reg_offset += curr_len; addr += curr_len; - if (reg_offset < total_len) { - curr_len = min_t(u32, - skip_len, - total_len - skip_len); - memset(dump_buf + offset, 0, - DWORDS_TO_BYTES(curr_len)); - offset += curr_len; - reg_offset += curr_len; - addr += curr_len; - } } - } else { - offset += total_len; } return offset; @@ -2266,43 +2521,48 @@ static u32 qed_grc_dump_regs_entries(struct qed_hwfn *p_hwfn, bool mode_match = true; *num_dumped_reg_entries = 0; + while (input_offset < input_regs_arr.size_in_dwords) { const struct dbg_dump_cond_hdr *cond_hdr = (const struct dbg_dump_cond_hdr *) &input_regs_arr.ptr[input_offset++]; - bool eval_mode = GET_FIELD(cond_hdr->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; + u16 modes_buf_offset; + bool eval_mode; /* Check mode/block */ + eval_mode = GET_FIELD(cond_hdr->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; if (eval_mode) { - u16 modes_buf_offset = + modes_buf_offset = GET_FIELD(cond_hdr->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); mode_match = qed_is_mode_match(p_hwfn, &modes_buf_offset); } - if (mode_match && block_enable[cond_hdr->block_id]) { - for (i = 0; i < cond_hdr->data_size; - i++, input_offset++) { - const struct dbg_dump_reg *reg = - (const struct dbg_dump_reg *) - &input_regs_arr.ptr[input_offset]; - u32 addr, len; - - addr = GET_FIELD(reg->data, - DBG_DUMP_REG_ADDRESS); - len = GET_FIELD(reg->data, DBG_DUMP_REG_LENGTH); - offset += - qed_grc_dump_reg_entry(p_hwfn, p_ptt, - dump_buf + offset, - dump, - addr, - len); - (*num_dumped_reg_entries)++; - } - } else { + if (!mode_match || !block_enable[cond_hdr->block_id]) { input_offset += cond_hdr->data_size; + continue; + } + + for (i = 0; i < cond_hdr->data_size; i++, input_offset++) { + const struct dbg_dump_reg *reg = + (const struct dbg_dump_reg *) + &input_regs_arr.ptr[input_offset]; + u32 addr, len; + bool wide_bus; + + addr = GET_FIELD(reg->data, DBG_DUMP_REG_ADDRESS); + len = GET_FIELD(reg->data, DBG_DUMP_REG_LENGTH); + wide_bus = GET_FIELD(reg->data, DBG_DUMP_REG_WIDE_BUS); + offset += qed_grc_dump_reg_entry(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + len, + wide_bus); + (*num_dumped_reg_entries)++; } } @@ -2350,8 +2610,8 @@ static u32 qed_grc_dump_split_data(struct qed_hwfn *p_hwfn, return num_dumped_reg_entries > 0 ? offset : 0; } -/* Dumps registers according to the input registers array. - * Returns the dumped size in dwords. +/* Dumps registers according to the input registers array. Returns the dumped + * size in dwords. */ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, @@ -2361,29 +2621,37 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, const char *param_name, const char *param_val) { struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - struct chip_platform_defs *p_platform_defs; + struct chip_platform_defs *chip_platform; u32 offset = 0, input_offset = 0; - struct chip_defs *p_chip_defs; + struct chip_defs *chip; u8 port_id, pf_id, vf_id; u16 fid; - p_chip_defs = &s_chip_defs[dev_data->chip_id]; - p_platform_defs = &p_chip_defs->per_platform[dev_data->platform_id]; + chip = &s_chip_defs[dev_data->chip_id]; + chip_platform = &chip->per_platform[dev_data->platform_id]; if (dump) DP_VERBOSE(p_hwfn, QED_MSG_DEBUG, "Dumping registers...\n"); + while (input_offset < s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].size_in_dwords) { - const struct dbg_dump_split_hdr *split_hdr = + const struct dbg_dump_split_hdr *split_hdr; + struct dbg_array curr_input_regs_arr; + u32 split_data_size; + u8 split_type_id; + + split_hdr = (const struct dbg_dump_split_hdr *) &s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr[input_offset++]; - u8 split_type_id = GET_FIELD(split_hdr->hdr, - DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID); - u32 split_data_size = GET_FIELD(split_hdr->hdr, - DBG_DUMP_SPLIT_HDR_DATA_SIZE); - struct dbg_array curr_input_regs_arr = { - &s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr[input_offset], - split_data_size}; + split_type_id = + GET_FIELD(split_hdr->hdr, + DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID); + split_data_size = + GET_FIELD(split_hdr->hdr, + DBG_DUMP_SPLIT_HDR_DATA_SIZE); + curr_input_regs_arr.ptr = + &s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr[input_offset]; + curr_input_regs_arr.size_in_dwords = split_data_size; switch (split_type_id) { case SPLIT_TYPE_NONE: @@ -2398,8 +2666,9 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, param_name, param_val); break; + case SPLIT_TYPE_PORT: - for (port_id = 0; port_id < p_platform_defs->num_ports; + for (port_id = 0; port_id < chip_platform->num_ports; port_id++) { if (dump) qed_port_pretend(p_hwfn, p_ptt, @@ -2414,9 +2683,10 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, param_val); } break; + case SPLIT_TYPE_PF: case SPLIT_TYPE_PORT_PF: - for (pf_id = 0; pf_id < p_platform_defs->num_pfs; + for (pf_id = 0; pf_id < chip_platform->num_pfs; pf_id++) { u8 pfid_shift = PXP_PRETEND_CONCRETE_FID_PFID_SHIFT; @@ -2427,17 +2697,21 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, } offset += - qed_grc_dump_split_data(p_hwfn, p_ptt, + qed_grc_dump_split_data(p_hwfn, + p_ptt, curr_input_regs_arr, dump_buf + offset, - dump, block_enable, - "pf", pf_id, + dump, + block_enable, + "pf", + pf_id, param_name, param_val); } break; + case SPLIT_TYPE_VF: - for (vf_id = 0; vf_id < p_platform_defs->num_vfs; + for (vf_id = 0; vf_id < chip_platform->num_vfs; vf_id++) { u8 vfvalid_shift = PXP_PRETEND_CONCRETE_FID_VFVALID_SHIFT; @@ -2460,6 +2734,7 @@ static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn, param_val); } break; + default: break; } @@ -2490,35 +2765,37 @@ static u32 qed_grc_dump_reset_regs(struct qed_hwfn *p_hwfn, /* Write reset registers */ for (i = 0; i < MAX_DBG_RESET_REGS; i++) { - if (s_reset_regs_defs[i].exists[dev_data->chip_id]) { - u32 addr = BYTES_TO_DWORDS(s_reset_regs_defs[i].addr); + if (!s_reset_regs_defs[i].exists[dev_data->chip_id]) + continue; - offset += qed_grc_dump_reg_entry(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - 1); - num_regs++; - } + offset += qed_grc_dump_reg_entry(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + BYTES_TO_DWORDS + (s_reset_regs_defs[i].addr), 1, + false); + num_regs++; } /* Write header */ if (dump) qed_grc_dump_regs_hdr(dump_buf, true, num_regs, "eng", -1, NULL, NULL); + return offset; } -/* Dump registers that are modified during GRC Dump and therefore must be dumped - * first. Returns the dumped size in dwords. +/* Dump registers that are modified during GRC Dump and therefore must be + * dumped first. Returns the dumped size in dwords. */ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - u32 offset = 0, num_reg_entries = 0, block_id; + u32 block_id, offset = 0, num_reg_entries = 0; + const struct dbg_attn_reg *attn_reg_arr; u8 storm_id, reg_idx, num_attn_regs; /* Calculate header size */ @@ -2527,14 +2804,13 @@ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, /* Write parity registers */ for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { - const struct dbg_attn_reg *attn_reg_arr; - if (dev_data->block_in_reset[block_id] && dump) continue; attn_reg_arr = qed_get_block_attn_regs((enum block_id)block_id, ATTN_TYPE_PARITY, &num_attn_regs); + for (reg_idx = 0; reg_idx < num_attn_regs; reg_idx++) { const struct dbg_attn_reg *reg_data = &attn_reg_arr[reg_idx]; @@ -2548,37 +2824,36 @@ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, modes_buf_offset = GET_FIELD(reg_data->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); - if (!eval_mode || - qed_is_mode_match(p_hwfn, &modes_buf_offset)) { - /* Mode match - read and dump registers */ - addr = reg_data->mask_address; - offset += - qed_grc_dump_reg_entry(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - 1); - addr = GET_FIELD(reg_data->data, - DBG_ATTN_REG_STS_ADDRESS); - offset += - qed_grc_dump_reg_entry(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - 1); - num_reg_entries += 2; - } + if (eval_mode && + !qed_is_mode_match(p_hwfn, &modes_buf_offset)) + continue; + + /* Mode match: read & dump registers */ + addr = reg_data->mask_address; + offset += qed_grc_dump_reg_entry(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + 1, false); + addr = GET_FIELD(reg_data->data, + DBG_ATTN_REG_STS_ADDRESS); + offset += qed_grc_dump_reg_entry(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + 1, false); + num_reg_entries += 2; } } - /* Write storm stall status registers */ + /* Write Storm stall status registers */ for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { + struct storm_defs *storm = &s_storm_defs[storm_id]; u32 addr; - if (dev_data->block_in_reset[s_storm_defs[storm_id].block_id] && - dump) + if (dev_data->block_in_reset[storm->block_id] && dump) continue; addr = @@ -2589,7 +2864,8 @@ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, addr, - 1); + 1, + false); num_reg_entries++; } @@ -2598,6 +2874,7 @@ static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn, qed_grc_dump_regs_hdr(dump_buf, true, num_reg_entries, "eng", -1, NULL, NULL); + return offset; } @@ -2637,17 +2914,17 @@ static u32 qed_grc_dump_special_regs(struct qed_hwfn *p_hwfn, return offset; } -/* Dumps a GRC memory header (section and params). - * The following parameters are dumped: - * name - name is dumped only if it's not NULL. - * addr - addr is dumped only if name is NULL. - * len - len is always dumped. - * width - bit_width is dumped if it's not zero. - * packed - packed=1 is dumped if it's not false. - * mem_group - mem_group is always dumped. - * is_storm - true only if the memory is related to a Storm. - * storm_letter - storm letter (valid only if is_storm is true). - * Returns the dumped size in dwords. +/* Dumps a GRC memory header (section and params). Returns the dumped size in + * dwords. The following parameters are dumped: + * - name: dumped only if it's not NULL. + * - addr: in dwords, dumped only if name is NULL. + * - len: in dwords, always dumped. + * - width: dumped if it's not zero. + * - packed: dumped only if it's not false. + * - mem_group: always dumped. + * - is_storm: true only if the memory is related to a Storm. + * - storm_letter: valid only if is_storm is true. + * */ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, u32 *dump_buf, @@ -2667,6 +2944,7 @@ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, if (!len) DP_NOTICE(p_hwfn, "Unexpected GRC Dump error: dumped memory size must be non-zero\n"); + if (bit_width) num_params++; if (packed) @@ -2675,6 +2953,7 @@ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, /* Dump section header */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "grc_mem", num_params); + if (name) { /* Dump name */ if (is_storm) { @@ -2694,14 +2973,15 @@ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, len, buf); } else { /* Dump address */ + u32 addr_in_bytes = DWORDS_TO_BYTES(addr); + offset += qed_dump_num_param(dump_buf + offset, - dump, "addr", - DWORDS_TO_BYTES(addr)); + dump, "addr", addr_in_bytes); if (dump && len > 64) DP_VERBOSE(p_hwfn, QED_MSG_DEBUG, "Dumping %d registers from address 0x%x...\n", - len, (u32)DWORDS_TO_BYTES(addr)); + len, addr_in_bytes); } /* Dump len */ @@ -2727,11 +3007,13 @@ static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn, } offset += qed_dump_str_param(dump_buf + offset, dump, "type", buf); + return offset; } /* Dumps a single GRC memory. If name is NULL, the memory is stored by address. * Returns the dumped size in dwords. + * The addr and len arguments are specified in dwords. */ static u32 qed_grc_dump_mem(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, @@ -2740,6 +3022,7 @@ static u32 qed_grc_dump_mem(struct qed_hwfn *p_hwfn, const char *name, u32 addr, u32 len, + bool wide_bus, u32 bit_width, bool packed, const char *mem_group, @@ -2758,7 +3041,9 @@ static u32 qed_grc_dump_mem(struct qed_hwfn *p_hwfn, mem_group, is_storm, storm_letter); offset += qed_grc_dump_addr_range(p_hwfn, p_ptt, - dump_buf + offset, dump, addr, len); + dump_buf + offset, + dump, addr, len, wide_bus); + return offset; } @@ -2773,20 +3058,21 @@ static u32 qed_grc_dump_mem_entries(struct qed_hwfn *p_hwfn, while (input_offset < input_mems_arr.size_in_dwords) { const struct dbg_dump_cond_hdr *cond_hdr; + u16 modes_buf_offset; u32 num_entries; bool eval_mode; cond_hdr = (const struct dbg_dump_cond_hdr *) &input_mems_arr.ptr[input_offset++]; - eval_mode = GET_FIELD(cond_hdr->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; + num_entries = cond_hdr->data_size / MEM_DUMP_ENTRY_SIZE_DWORDS; /* Check required mode */ + eval_mode = GET_FIELD(cond_hdr->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; if (eval_mode) { - u16 modes_buf_offset = + modes_buf_offset = GET_FIELD(cond_hdr->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); - mode_match = qed_is_mode_match(p_hwfn, &modes_buf_offset); } @@ -2796,81 +3082,87 @@ static u32 qed_grc_dump_mem_entries(struct qed_hwfn *p_hwfn, continue; } - num_entries = cond_hdr->data_size / MEM_DUMP_ENTRY_SIZE_DWORDS; for (i = 0; i < num_entries; i++, input_offset += MEM_DUMP_ENTRY_SIZE_DWORDS) { const struct dbg_dump_mem *mem = (const struct dbg_dump_mem *) &input_mems_arr.ptr[input_offset]; - u8 mem_group_id; + u8 mem_group_id = GET_FIELD(mem->dword0, + DBG_DUMP_MEM_MEM_GROUP_ID); + bool is_storm = false, mem_wide_bus; + enum dbg_grc_params grc_param; + char storm_letter = 'a'; + enum block_id block_id; + u32 mem_addr, mem_len; - mem_group_id = GET_FIELD(mem->dword0, - DBG_DUMP_MEM_MEM_GROUP_ID); if (mem_group_id >= MEM_GROUPS_NUM) { DP_NOTICE(p_hwfn, "Invalid mem_group_id\n"); return 0; } - if (qed_grc_is_mem_included(p_hwfn, - (enum block_id)cond_hdr->block_id, - mem_group_id)) { - u32 mem_addr = GET_FIELD(mem->dword0, - DBG_DUMP_MEM_ADDRESS); - u32 mem_len = GET_FIELD(mem->dword1, - DBG_DUMP_MEM_LENGTH); - enum dbg_grc_params grc_param; - char storm_letter = 'a'; - bool is_storm = false; - - /* Update memory length for CCFC/TCFC memories - * according to number of LCIDs/LTIDs. - */ - if (mem_group_id == MEM_GROUP_CONN_CFC_MEM) { - if (mem_len % MAX_LCIDS != 0) { - DP_NOTICE(p_hwfn, - "Invalid CCFC connection memory size\n"); - return 0; - } - - grc_param = DBG_GRC_PARAM_NUM_LCIDS; - mem_len = qed_grc_get_param(p_hwfn, - grc_param) * - (mem_len / MAX_LCIDS); - } else if (mem_group_id == - MEM_GROUP_TASK_CFC_MEM) { - if (mem_len % MAX_LTIDS != 0) { - DP_NOTICE(p_hwfn, - "Invalid TCFC task memory size\n"); - return 0; - } - - grc_param = DBG_GRC_PARAM_NUM_LTIDS; - mem_len = qed_grc_get_param(p_hwfn, - grc_param) * - (mem_len / MAX_LTIDS); + block_id = (enum block_id)cond_hdr->block_id; + if (!qed_grc_is_mem_included(p_hwfn, + block_id, + mem_group_id)) + continue; + + mem_addr = GET_FIELD(mem->dword0, DBG_DUMP_MEM_ADDRESS); + mem_len = GET_FIELD(mem->dword1, DBG_DUMP_MEM_LENGTH); + mem_wide_bus = GET_FIELD(mem->dword1, + DBG_DUMP_MEM_WIDE_BUS); + + /* Update memory length for CCFC/TCFC memories + * according to number of LCIDs/LTIDs. + */ + if (mem_group_id == MEM_GROUP_CONN_CFC_MEM) { + if (mem_len % MAX_LCIDS) { + DP_NOTICE(p_hwfn, + "Invalid CCFC connection memory size\n"); + return 0; } - /* If memory is associated with Storm, update - * Storm details. - */ - if (s_block_defs[cond_hdr->block_id]-> - associated_to_storm) { - is_storm = true; - storm_letter = - s_storm_defs[s_block_defs[ - cond_hdr->block_id]-> - storm_id].letter; + grc_param = DBG_GRC_PARAM_NUM_LCIDS; + mem_len = qed_grc_get_param(p_hwfn, grc_param) * + (mem_len / MAX_LCIDS); + } else if (mem_group_id == MEM_GROUP_TASK_CFC_MEM) { + if (mem_len % MAX_LTIDS) { + DP_NOTICE(p_hwfn, + "Invalid TCFC task memory size\n"); + return 0; } - /* Dump memory */ - offset += qed_grc_dump_mem(p_hwfn, p_ptt, - dump_buf + offset, dump, NULL, - mem_addr, mem_len, 0, + grc_param = DBG_GRC_PARAM_NUM_LTIDS; + mem_len = qed_grc_get_param(p_hwfn, grc_param) * + (mem_len / MAX_LTIDS); + } + + /* If memory is associated with Storm, update Storm + * details. + */ + if (s_block_defs + [cond_hdr->block_id]->associated_to_storm) { + is_storm = true; + storm_letter = + s_storm_defs[s_block_defs + [cond_hdr->block_id]-> + storm_id].letter; + } + + /* Dump memory */ + offset += qed_grc_dump_mem(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + NULL, + mem_addr, + mem_len, + mem_wide_bus, + 0, false, s_mem_group_names[mem_group_id], - is_storm, storm_letter); - } - } + is_storm, + storm_letter); + } } return offset; @@ -2887,16 +3179,22 @@ static u32 qed_grc_dump_memories(struct qed_hwfn *p_hwfn, while (input_offset < s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].size_in_dwords) { - const struct dbg_dump_split_hdr *split_hdr = - (const struct dbg_dump_split_hdr *) + const struct dbg_dump_split_hdr *split_hdr; + struct dbg_array curr_input_mems_arr; + u32 split_data_size; + u8 split_type_id; + + split_hdr = (const struct dbg_dump_split_hdr *) &s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].ptr[input_offset++]; - u8 split_type_id = GET_FIELD(split_hdr->hdr, - DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID); - u32 split_data_size = GET_FIELD(split_hdr->hdr, - DBG_DUMP_SPLIT_HDR_DATA_SIZE); - struct dbg_array curr_input_mems_arr = { - &s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].ptr[input_offset], - split_data_size}; + split_type_id = + GET_FIELD(split_hdr->hdr, + DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID); + split_data_size = + GET_FIELD(split_hdr->hdr, + DBG_DUMP_SPLIT_HDR_DATA_SIZE); + curr_input_mems_arr.ptr = + &s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].ptr[input_offset]; + curr_input_mems_arr.size_in_dwords = split_data_size; switch (split_type_id) { case SPLIT_TYPE_NONE: @@ -2906,6 +3204,7 @@ static u32 qed_grc_dump_memories(struct qed_hwfn *p_hwfn, dump_buf + offset, dump); break; + default: DP_NOTICE(p_hwfn, "Dumping split memories is currently not supported\n"); @@ -2920,6 +3219,7 @@ static u32 qed_grc_dump_memories(struct qed_hwfn *p_hwfn, /* Dumps GRC context data for the specified Storm. * Returns the dumped size in dwords. + * The lid_size argument is specified in quad-regs. */ static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, @@ -2931,13 +3231,15 @@ static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn, u32 rd_reg_addr, u8 storm_id) { - u32 i, lid, total_size; - u32 offset = 0; + struct storm_defs *storm = &s_storm_defs[storm_id]; + u32 i, lid, total_size, offset = 0; if (!lid_size) return 0; + lid_size *= BYTES_IN_DWORD; total_size = num_lids * lid_size; + offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, dump, @@ -2945,25 +3247,19 @@ static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn, 0, total_size, lid_size * 32, - false, - name, - true, s_storm_defs[storm_id].letter); + false, name, true, storm->letter); + + if (!dump) + return offset + total_size; /* Dump context data */ - if (dump) { - for (lid = 0; lid < num_lids; lid++) { - for (i = 0; i < lid_size; i++, offset++) { - qed_wr(p_hwfn, - p_ptt, - s_storm_defs[storm_id].cm_ctx_wr_addr, - BIT(9) | lid); - *(dump_buf + offset) = qed_rd(p_hwfn, - p_ptt, - rd_reg_addr); - } + for (lid = 0; lid < num_lids; lid++) { + for (i = 0; i < lid_size; i++, offset++) { + qed_wr(p_hwfn, + p_ptt, storm->cm_ctx_wr_addr, (i << 9) | lid); + *(dump_buf + offset) = qed_rd(p_hwfn, + p_ptt, rd_reg_addr); } - } else { - offset += total_size; } return offset; @@ -2973,15 +3269,19 @@ static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn, static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { + enum dbg_grc_params grc_param; u32 offset = 0; u8 storm_id; for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { + struct storm_defs *storm = &s_storm_defs[storm_id]; + if (!qed_grc_is_storm_included(p_hwfn, (enum dbg_storms)storm_id)) continue; /* Dump Conn AG context size */ + grc_param = DBG_GRC_PARAM_NUM_LCIDS; offset += qed_grc_dump_ctx_data(p_hwfn, p_ptt, @@ -2989,14 +3289,13 @@ static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, dump, "CONN_AG_CTX", qed_grc_get_param(p_hwfn, - DBG_GRC_PARAM_NUM_LCIDS), - s_storm_defs[storm_id]. - cm_conn_ag_ctx_lid_size, - s_storm_defs[storm_id]. - cm_conn_ag_ctx_rd_addr, + grc_param), + storm->cm_conn_ag_ctx_lid_size, + storm->cm_conn_ag_ctx_rd_addr, storm_id); /* Dump Conn ST context size */ + grc_param = DBG_GRC_PARAM_NUM_LCIDS; offset += qed_grc_dump_ctx_data(p_hwfn, p_ptt, @@ -3004,14 +3303,13 @@ static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, dump, "CONN_ST_CTX", qed_grc_get_param(p_hwfn, - DBG_GRC_PARAM_NUM_LCIDS), - s_storm_defs[storm_id]. - cm_conn_st_ctx_lid_size, - s_storm_defs[storm_id]. - cm_conn_st_ctx_rd_addr, + grc_param), + storm->cm_conn_st_ctx_lid_size, + storm->cm_conn_st_ctx_rd_addr, storm_id); /* Dump Task AG context size */ + grc_param = DBG_GRC_PARAM_NUM_LTIDS; offset += qed_grc_dump_ctx_data(p_hwfn, p_ptt, @@ -3019,14 +3317,13 @@ static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, dump, "TASK_AG_CTX", qed_grc_get_param(p_hwfn, - DBG_GRC_PARAM_NUM_LTIDS), - s_storm_defs[storm_id]. - cm_task_ag_ctx_lid_size, - s_storm_defs[storm_id]. - cm_task_ag_ctx_rd_addr, + grc_param), + storm->cm_task_ag_ctx_lid_size, + storm->cm_task_ag_ctx_rd_addr, storm_id); /* Dump Task ST context size */ + grc_param = DBG_GRC_PARAM_NUM_LTIDS; offset += qed_grc_dump_ctx_data(p_hwfn, p_ptt, @@ -3034,11 +3331,9 @@ static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn, dump, "TASK_ST_CTX", qed_grc_get_param(p_hwfn, - DBG_GRC_PARAM_NUM_LTIDS), - s_storm_defs[storm_id]. - cm_task_st_ctx_lid_size, - s_storm_defs[storm_id]. - cm_task_st_ctx_rd_addr, + grc_param), + storm->cm_task_st_ctx_lid_size, + storm->cm_task_st_ctx_rd_addr, storm_id); } @@ -3050,8 +3345,8 @@ static u32 qed_grc_dump_iors(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { char buf[10] = "IOR_SET_?"; + u32 addr, offset = 0; u8 storm_id, set_id; - u32 offset = 0; for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { struct storm_defs *storm = &s_storm_defs[storm_id]; @@ -3061,11 +3356,9 @@ static u32 qed_grc_dump_iors(struct qed_hwfn *p_hwfn, continue; for (set_id = 0; set_id < NUM_IOR_SETS; set_id++) { - u32 dwords, addr; - - dwords = storm->sem_fast_mem_addr + - SEM_FAST_REG_STORM_REG_FILE; - addr = BYTES_TO_DWORDS(dwords) + IOR_SET_OFFSET(set_id); + addr = BYTES_TO_DWORDS(storm->sem_fast_mem_addr + + SEM_FAST_REG_STORM_REG_FILE) + + IOR_SET_OFFSET(set_id); buf[strlen(buf) - 1] = '0' + set_id; offset += qed_grc_dump_mem(p_hwfn, p_ptt, @@ -3074,6 +3367,7 @@ static u32 qed_grc_dump_iors(struct qed_hwfn *p_hwfn, buf, addr, IORS_PER_SET, + false, 32, false, "ior", @@ -3091,10 +3385,10 @@ static u32 qed_grc_dump_vfc_cam(struct qed_hwfn *p_hwfn, u32 *dump_buf, bool dump, u8 storm_id) { u32 total_size = VFC_CAM_NUM_ROWS * VFC_CAM_RESP_DWORDS; + struct storm_defs *storm = &s_storm_defs[storm_id]; u32 cam_addr[VFC_CAM_ADDR_DWORDS] = { 0 }; u32 cam_cmd[VFC_CAM_CMD_DWORDS] = { 0 }; - u32 offset = 0; - u32 row, i; + u32 row, i, offset = 0; offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, @@ -3103,38 +3397,34 @@ static u32 qed_grc_dump_vfc_cam(struct qed_hwfn *p_hwfn, 0, total_size, 256, - false, - "vfc_cam", - true, s_storm_defs[storm_id].letter); - if (dump) { - /* Prepare CAM address */ - SET_VAR_FIELD(cam_addr, VFC_CAM_ADDR, OP, VFC_OPCODE_CAM_RD); - for (row = 0; row < VFC_CAM_NUM_ROWS; - row++, offset += VFC_CAM_RESP_DWORDS) { - /* Write VFC CAM command */ - SET_VAR_FIELD(cam_cmd, VFC_CAM_CMD, ROW, row); - ARR_REG_WR(p_hwfn, - p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_DATA_WR, - cam_cmd, VFC_CAM_CMD_DWORDS); + false, "vfc_cam", true, storm->letter); - /* Write VFC CAM address */ - ARR_REG_WR(p_hwfn, - p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_ADDR, - cam_addr, VFC_CAM_ADDR_DWORDS); + if (!dump) + return offset + total_size; - /* Read VFC CAM read response */ - ARR_REG_RD(p_hwfn, - p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_DATA_RD, - dump_buf + offset, VFC_CAM_RESP_DWORDS); - } - } else { - offset += total_size; + /* Prepare CAM address */ + SET_VAR_FIELD(cam_addr, VFC_CAM_ADDR, OP, VFC_OPCODE_CAM_RD); + + for (row = 0; row < VFC_CAM_NUM_ROWS; + row++, offset += VFC_CAM_RESP_DWORDS) { + /* Write VFC CAM command */ + SET_VAR_FIELD(cam_cmd, VFC_CAM_CMD, ROW, row); + ARR_REG_WR(p_hwfn, + p_ptt, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_DATA_WR, + cam_cmd, VFC_CAM_CMD_DWORDS); + + /* Write VFC CAM address */ + ARR_REG_WR(p_hwfn, + p_ptt, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_ADDR, + cam_addr, VFC_CAM_ADDR_DWORDS); + + /* Read VFC CAM read response */ + ARR_REG_RD(p_hwfn, + p_ptt, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_DATA_RD, + dump_buf + offset, VFC_CAM_RESP_DWORDS); } return offset; @@ -3148,10 +3438,10 @@ static u32 qed_grc_dump_vfc_ram(struct qed_hwfn *p_hwfn, u8 storm_id, struct vfc_ram_defs *ram_defs) { u32 total_size = ram_defs->num_rows * VFC_RAM_RESP_DWORDS; + struct storm_defs *storm = &s_storm_defs[storm_id]; u32 ram_addr[VFC_RAM_ADDR_DWORDS] = { 0 }; u32 ram_cmd[VFC_RAM_CMD_DWORDS] = { 0 }; - u32 offset = 0; - u32 row, i; + u32 row, i, offset = 0; offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, @@ -3162,7 +3452,7 @@ static u32 qed_grc_dump_vfc_ram(struct qed_hwfn *p_hwfn, 256, false, ram_defs->type_name, - true, s_storm_defs[storm_id].letter); + true, storm->letter); /* Prepare RAM address */ SET_VAR_FIELD(ram_addr, VFC_RAM_ADDR, OP, VFC_OPCODE_RAM_RD); @@ -3176,23 +3466,20 @@ static u32 qed_grc_dump_vfc_ram(struct qed_hwfn *p_hwfn, /* Write VFC RAM command */ ARR_REG_WR(p_hwfn, p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_DATA_WR, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_DATA_WR, ram_cmd, VFC_RAM_CMD_DWORDS); /* Write VFC RAM address */ SET_VAR_FIELD(ram_addr, VFC_RAM_ADDR, ROW, row); ARR_REG_WR(p_hwfn, p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_ADDR, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_ADDR, ram_addr, VFC_RAM_ADDR_DWORDS); /* Read VFC RAM read response */ ARR_REG_RD(p_hwfn, p_ptt, - s_storm_defs[storm_id].sem_fast_mem_addr + - SEM_FAST_REG_VFC_DATA_RD, + storm->sem_fast_mem_addr + SEM_FAST_REG_VFC_DATA_RD, dump_buf + offset, VFC_RAM_RESP_DWORDS); } @@ -3208,28 +3495,27 @@ static u32 qed_grc_dump_vfc(struct qed_hwfn *p_hwfn, u32 offset = 0; for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { - if (qed_grc_is_storm_included(p_hwfn, - (enum dbg_storms)storm_id) && - s_storm_defs[storm_id].has_vfc && - (storm_id != DBG_PSTORM_ID || - dev_data->platform_id == PLATFORM_ASIC)) { - /* Read CAM */ - offset += qed_grc_dump_vfc_cam(p_hwfn, + if (!qed_grc_is_storm_included(p_hwfn, + (enum dbg_storms)storm_id) || + !s_storm_defs[storm_id].has_vfc || + (storm_id == DBG_PSTORM_ID && dev_data->platform_id != + PLATFORM_ASIC)) + continue; + + /* Read CAM */ + offset += qed_grc_dump_vfc_cam(p_hwfn, + p_ptt, + dump_buf + offset, + dump, storm_id); + + /* Read RAM */ + for (i = 0; i < NUM_VFC_RAM_TYPES; i++) + offset += qed_grc_dump_vfc_ram(p_hwfn, p_ptt, dump_buf + offset, - dump, storm_id); - - /* Read RAM */ - for (i = 0; i < NUM_VFC_RAM_TYPES; i++) - offset += qed_grc_dump_vfc_ram(p_hwfn, - p_ptt, - dump_buf + - offset, - dump, - storm_id, - &s_vfc_ram_defs - [i]); - } + dump, + storm_id, + &s_vfc_ram_defs[i]); } return offset; @@ -3244,14 +3530,17 @@ static u32 qed_grc_dump_rss(struct qed_hwfn *p_hwfn, u8 rss_mem_id; for (rss_mem_id = 0; rss_mem_id < NUM_RSS_MEM_TYPES; rss_mem_id++) { - struct rss_mem_defs *rss_defs = &s_rss_mem_defs[rss_mem_id]; - u32 num_entries = rss_defs->num_entries[dev_data->chip_id]; - u32 entry_width = rss_defs->entry_width[dev_data->chip_id]; - u32 total_dwords = (num_entries * entry_width) / 32; - u32 size = RSS_REG_RSS_RAM_DATA_SIZE; - bool packed = (entry_width == 16); - u32 rss_addr = rss_defs->addr; - u32 i, addr; + u32 rss_addr, num_entries, entry_width, total_dwords, i; + struct rss_mem_defs *rss_defs; + u32 addr, size; + bool packed; + + rss_defs = &s_rss_mem_defs[rss_mem_id]; + rss_addr = rss_defs->addr; + num_entries = rss_defs->num_entries[dev_data->chip_id]; + entry_width = rss_defs->entry_width[dev_data->chip_id]; + total_dwords = (num_entries * entry_width) / 32; + packed = (entry_width == 16); offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, @@ -3263,23 +3552,23 @@ static u32 qed_grc_dump_rss(struct qed_hwfn *p_hwfn, packed, rss_defs->type_name, false, 0); + /* Dump RSS data */ if (!dump) { offset += total_dwords; continue; } - /* Dump RSS data */ - for (i = 0; i < total_dwords; - i += RSS_REG_RSS_RAM_DATA_SIZE, rss_addr++) { - addr = BYTES_TO_DWORDS(RSS_REG_RSS_RAM_DATA); + addr = BYTES_TO_DWORDS(RSS_REG_RSS_RAM_DATA); + size = RSS_REG_RSS_RAM_DATA_SIZE; + for (i = 0; i < total_dwords; i += size, rss_addr++) { qed_wr(p_hwfn, p_ptt, RSS_REG_RSS_RAM_ADDR, rss_addr); - offset += qed_grc_dump_addr_range(p_hwfn, - p_ptt, - dump_buf + - offset, - dump, - addr, - size); + offset += qed_grc_dump_addr_range(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + size, + false); } } @@ -3316,10 +3605,11 @@ static u32 qed_grc_dump_big_ram(struct qed_hwfn *p_hwfn, BIG_RAM_BLOCK_SIZE_BYTES * 8, false, type_name, false, 0); + /* Read and dump Big RAM data */ if (!dump) return offset + ram_size; - /* Read and dump Big RAM data */ + /* Dump Big RAM */ for (i = 0; i < total_blocks / 2; i++) { u32 addr, len; @@ -3331,7 +3621,8 @@ static u32 qed_grc_dump_big_ram(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, addr, - len); + len, + false); } return offset; @@ -3359,7 +3650,7 @@ static u32 qed_grc_dump_mcp(struct qed_hwfn *p_hwfn, NULL, BYTES_TO_DWORDS(MCP_REG_SCRATCH), MCP_REG_SCRATCH_SIZE, - 0, false, "MCP", false, 0); + false, 0, false, "MCP", false, 0); /* Dump MCP cpu_reg_file */ offset += qed_grc_dump_mem(p_hwfn, @@ -3369,7 +3660,7 @@ static u32 qed_grc_dump_mcp(struct qed_hwfn *p_hwfn, NULL, BYTES_TO_DWORDS(MCP_REG_CPU_REG_FILE), MCP_REG_CPU_REG_FILE_SIZE, - 0, false, "MCP", false, 0); + false, 0, false, "MCP", false, 0); /* Dump MCP registers */ block_enable[BLOCK_MCP] = true; @@ -3387,11 +3678,13 @@ static u32 qed_grc_dump_mcp(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, addr, - 1); + 1, + false); /* Release MCP */ if (halted && qed_mcp_resume(p_hwfn, p_ptt)) DP_NOTICE(p_hwfn, "Failed to resume MCP after halt!\n"); + return offset; } @@ -3404,14 +3697,26 @@ static u32 qed_grc_dump_phy(struct qed_hwfn *p_hwfn, u8 phy_id; for (phy_id = 0; phy_id < ARRAY_SIZE(s_phy_defs); phy_id++) { - struct phy_defs *phy_defs = &s_phy_defs[phy_id]; - int printed_chars; - - printed_chars = snprintf(mem_name, sizeof(mem_name), "tbus_%s", - phy_defs->phy_name); - if (printed_chars < 0 || printed_chars >= sizeof(mem_name)) + u32 addr_lo_addr, addr_hi_addr, data_lo_addr, data_hi_addr; + struct phy_defs *phy_defs; + u8 *bytes_buf; + + phy_defs = &s_phy_defs[phy_id]; + addr_lo_addr = phy_defs->base_addr + + phy_defs->tbus_addr_lo_addr; + addr_hi_addr = phy_defs->base_addr + + phy_defs->tbus_addr_hi_addr; + data_lo_addr = phy_defs->base_addr + + phy_defs->tbus_data_lo_addr; + data_hi_addr = phy_defs->base_addr + + phy_defs->tbus_data_hi_addr; + bytes_buf = (u8 *)(dump_buf + offset); + + if (snprintf(mem_name, sizeof(mem_name), "tbus_%s", + phy_defs->phy_name) < 0) DP_NOTICE(p_hwfn, "Unexpected debug error: invalid PHY memory name\n"); + offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, dump, @@ -3419,34 +3724,26 @@ static u32 qed_grc_dump_phy(struct qed_hwfn *p_hwfn, 0, PHY_DUMP_SIZE_DWORDS, 16, true, mem_name, false, 0); - if (dump) { - u32 addr_lo_addr = phy_defs->base_addr + - phy_defs->tbus_addr_lo_addr; - u32 addr_hi_addr = phy_defs->base_addr + - phy_defs->tbus_addr_hi_addr; - u32 data_lo_addr = phy_defs->base_addr + - phy_defs->tbus_data_lo_addr; - u32 data_hi_addr = phy_defs->base_addr + - phy_defs->tbus_data_hi_addr; - u8 *bytes_buf = (u8 *)(dump_buf + offset); - - for (tbus_hi_offset = 0; - tbus_hi_offset < (NUM_PHY_TBUS_ADDRESSES >> 8); - tbus_hi_offset++) { + + if (!dump) { + offset += PHY_DUMP_SIZE_DWORDS; + continue; + } + + for (tbus_hi_offset = 0; + tbus_hi_offset < (NUM_PHY_TBUS_ADDRESSES >> 8); + tbus_hi_offset++) { + qed_wr(p_hwfn, p_ptt, addr_hi_addr, tbus_hi_offset); + for (tbus_lo_offset = 0; tbus_lo_offset < 256; + tbus_lo_offset++) { qed_wr(p_hwfn, - p_ptt, addr_hi_addr, tbus_hi_offset); - for (tbus_lo_offset = 0; tbus_lo_offset < 256; - tbus_lo_offset++) { - qed_wr(p_hwfn, - p_ptt, - addr_lo_addr, tbus_lo_offset); - *(bytes_buf++) = - (u8)qed_rd(p_hwfn, p_ptt, - data_lo_addr); - *(bytes_buf++) = - (u8)qed_rd(p_hwfn, p_ptt, - data_hi_addr); - } + p_ptt, addr_lo_addr, tbus_lo_offset); + *(bytes_buf++) = (u8)qed_rd(p_hwfn, + p_ptt, + data_lo_addr); + *(bytes_buf++) = (u8)qed_rd(p_hwfn, + p_ptt, + data_hi_addr); } } @@ -3460,16 +3757,17 @@ static void qed_config_dbg_line(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, enum block_id block_id, u8 line_id, - u8 cycle_en, - u8 right_shift, u8 force_valid, u8 force_frame) + u8 enable_mask, + u8 right_shift, + u8 force_valid_mask, u8 force_frame_mask) { - struct block_defs *p_block_defs = s_block_defs[block_id]; + struct block_defs *block = s_block_defs[block_id]; - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_select_addr, line_id); - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_cycle_enable_addr, cycle_en); - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_shift_addr, right_shift); - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_force_valid_addr, force_valid); - qed_wr(p_hwfn, p_ptt, p_block_defs->dbg_force_frame_addr, force_frame); + qed_wr(p_hwfn, p_ptt, block->dbg_select_addr, line_id); + qed_wr(p_hwfn, p_ptt, block->dbg_enable_addr, enable_mask); + qed_wr(p_hwfn, p_ptt, block->dbg_shift_addr, right_shift); + qed_wr(p_hwfn, p_ptt, block->dbg_force_valid_addr, force_valid_mask); + qed_wr(p_hwfn, p_ptt, block->dbg_force_frame_addr, force_frame_mask); } /* Dumps Static Debug data. Returns the dumped size in dwords. */ @@ -3477,10 +3775,12 @@ static u32 qed_grc_dump_static_debug(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { - u32 block_dwords = NUM_DBG_BUS_LINES * STATIC_DEBUG_LINE_DWORDS; struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - u32 offset = 0, block_id, line_id; - struct block_defs *p_block_defs; + u32 block_id, line_id, offset = 0; + + /* Skip static debug if a debug bus recording is in progress */ + if (qed_rd(p_hwfn, p_ptt, DBG_REG_DBG_BLOCK_ON)) + return 0; if (dump) { DP_VERBOSE(p_hwfn, @@ -3488,11 +3788,11 @@ static u32 qed_grc_dump_static_debug(struct qed_hwfn *p_hwfn, /* Disable all blocks debug output */ for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { - p_block_defs = s_block_defs[block_id]; + struct block_defs *block = s_block_defs[block_id]; - if (p_block_defs->has_dbg_bus[dev_data->chip_id]) - qed_wr(p_hwfn, p_ptt, - p_block_defs->dbg_cycle_enable_addr, 0); + if (block->has_dbg_bus[dev_data->chip_id]) + qed_wr(p_hwfn, p_ptt, block->dbg_enable_addr, + 0); } qed_bus_reset_dbg_block(p_hwfn, p_ptt); @@ -3506,59 +3806,71 @@ static u32 qed_grc_dump_static_debug(struct qed_hwfn *p_hwfn, /* Dump all static debug lines for each relevant block */ for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) { - p_block_defs = s_block_defs[block_id]; + struct block_defs *block = s_block_defs[block_id]; + struct dbg_bus_block *block_desc; + u32 block_dwords, addr, len; + u8 dbg_client_id; - if (!p_block_defs->has_dbg_bus[dev_data->chip_id]) + if (!block->has_dbg_bus[dev_data->chip_id]) continue; + block_desc = + get_dbg_bus_block_desc(p_hwfn, + (enum block_id)block_id); + block_dwords = NUM_DBG_LINES(block_desc) * + STATIC_DEBUG_LINE_DWORDS; + /* Dump static section params */ offset += qed_grc_dump_mem_hdr(p_hwfn, dump_buf + offset, dump, - p_block_defs->name, 0, - block_dwords, 32, false, - "STATIC", false, 0); - - if (dump && !dev_data->block_in_reset[block_id]) { - u8 dbg_client_id = - p_block_defs->dbg_client_id[dev_data->chip_id]; - u32 addr = BYTES_TO_DWORDS(DBG_REG_CALENDAR_OUT_DATA); - u32 len = STATIC_DEBUG_LINE_DWORDS; - - /* Enable block's client */ - qed_bus_enable_clients(p_hwfn, p_ptt, - BIT(dbg_client_id)); - - for (line_id = 0; line_id < NUM_DBG_BUS_LINES; - line_id++) { - /* Configure debug line ID */ - qed_config_dbg_line(p_hwfn, - p_ptt, - (enum block_id)block_id, - (u8)line_id, - 0xf, 0, 0, 0); + block->name, + 0, + block_dwords, + 32, false, "STATIC", false, 0); - /* Read debug line info */ - offset += - qed_grc_dump_addr_range(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - len); - } + if (!dump) { + offset += block_dwords; + continue; + } - /* Disable block's client and debug output */ - qed_bus_enable_clients(p_hwfn, p_ptt, 0); - qed_wr(p_hwfn, p_ptt, - p_block_defs->dbg_cycle_enable_addr, 0); - } else { - /* All lines are invalid - dump zeros */ - if (dump) - memset(dump_buf + offset, 0, - DWORDS_TO_BYTES(block_dwords)); + /* If all lines are invalid - dump zeros */ + if (dev_data->block_in_reset[block_id]) { + memset(dump_buf + offset, 0, + DWORDS_TO_BYTES(block_dwords)); offset += block_dwords; + continue; + } + + /* Enable block's client */ + dbg_client_id = block->dbg_client_id[dev_data->chip_id]; + qed_bus_enable_clients(p_hwfn, + p_ptt, + BIT(dbg_client_id)); + + addr = BYTES_TO_DWORDS(DBG_REG_CALENDAR_OUT_DATA); + len = STATIC_DEBUG_LINE_DWORDS; + for (line_id = 0; line_id < (u32)NUM_DBG_LINES(block_desc); + line_id++) { + /* Configure debug line ID */ + qed_config_dbg_line(p_hwfn, + p_ptt, + (enum block_id)block_id, + (u8)line_id, 0xf, 0, 0, 0); + + /* Read debug line info */ + offset += qed_grc_dump_addr_range(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + len, + true); } + + /* Disable block's client and debug output */ + qed_bus_enable_clients(p_hwfn, p_ptt, 0); + qed_wr(p_hwfn, p_ptt, block->dbg_enable_addr, 0); } if (dump) { @@ -3584,8 +3896,8 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, *num_dumped_dwords = 0; - /* Find port mode */ if (dump) { + /* Find port mode */ switch (qed_rd(p_hwfn, p_ptt, MISC_REG_PORT_MODE)) { case 0: port_mode = 1; @@ -3597,11 +3909,10 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, port_mode = 4; break; } - } - /* Update reset state */ - if (dump) + /* Update reset state */ qed_update_blocks_reset_state(p_hwfn, p_ptt); + } /* Dump global params */ offset += qed_dump_common_global_params(p_hwfn, @@ -3635,7 +3946,8 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, } /* Disable all parities using MFW command */ - if (dump && !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP)) { + if (dump && + !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP)) { parities_masked = !qed_mcp_mask_parities(p_hwfn, p_ptt, 1); if (!parities_masked) { DP_NOTICE(p_hwfn, @@ -3661,9 +3973,9 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, /* Dump all regs */ if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_REGS)) { - /* Dump all blocks except MCP */ bool block_enable[MAX_BLOCK_ID]; + /* Dump all blocks except MCP */ for (i = 0; i < MAX_BLOCK_ID; i++) block_enable[i] = true; block_enable[BLOCK_MCP] = false; @@ -3732,7 +4044,8 @@ static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn, dump_buf + offset, dump); /* Dump last section */ - offset += qed_dump_last_section(dump_buf, offset, dump); + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); + if (dump) { /* Unstall storms */ if (qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_UNSTALL)) @@ -3763,19 +4076,20 @@ static u32 qed_idle_chk_dump_failure(struct qed_hwfn *p_hwfn, const struct dbg_idle_chk_rule *rule, u16 fail_entry_id, u32 *cond_reg_values) { - const union dbg_idle_chk_reg *regs = &((const union dbg_idle_chk_reg *) - s_dbg_arrays - [BIN_BUF_DBG_IDLE_CHK_REGS]. - ptr)[rule->reg_offset]; - const struct dbg_idle_chk_cond_reg *cond_regs = ®s[0].cond_reg; struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; - struct dbg_idle_chk_result_hdr *hdr = - (struct dbg_idle_chk_result_hdr *)dump_buf; - const struct dbg_idle_chk_info_reg *info_regs = - ®s[rule->num_cond_regs].info_reg; - u32 next_reg_offset = 0, i, offset = 0; + const struct dbg_idle_chk_cond_reg *cond_regs; + const struct dbg_idle_chk_info_reg *info_regs; + u32 i, next_reg_offset = 0, offset = 0; + struct dbg_idle_chk_result_hdr *hdr; + const union dbg_idle_chk_reg *regs; u8 reg_id; + hdr = (struct dbg_idle_chk_result_hdr *)dump_buf; + regs = &((const union dbg_idle_chk_reg *) + s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_REGS].ptr)[rule->reg_offset]; + cond_regs = ®s[0].cond_reg; + info_regs = ®s[rule->num_cond_regs].info_reg; + /* Dump rule data */ if (dump) { memset(hdr, 0, sizeof(*hdr)); @@ -3790,33 +4104,31 @@ static u32 qed_idle_chk_dump_failure(struct qed_hwfn *p_hwfn, /* Dump condition register values */ for (reg_id = 0; reg_id < rule->num_cond_regs; reg_id++) { const struct dbg_idle_chk_cond_reg *reg = &cond_regs[reg_id]; + struct dbg_idle_chk_result_reg_hdr *reg_hdr; - /* Write register header */ - if (dump) { - struct dbg_idle_chk_result_reg_hdr *reg_hdr = - (struct dbg_idle_chk_result_reg_hdr *)(dump_buf - + offset); - offset += IDLE_CHK_RESULT_REG_HDR_DWORDS; - memset(reg_hdr, 0, - sizeof(struct dbg_idle_chk_result_reg_hdr)); - reg_hdr->start_entry = reg->start_entry; - reg_hdr->size = reg->entry_size; - SET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM, - reg->num_entries > 1 || reg->start_entry > 0 - ? 1 : 0); - SET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID, reg_id); + reg_hdr = (struct dbg_idle_chk_result_reg_hdr *) + (dump_buf + offset); - /* Write register values */ - for (i = 0; i < reg_hdr->size; - i++, next_reg_offset++, offset++) - dump_buf[offset] = - cond_reg_values[next_reg_offset]; - } else { + /* Write register header */ + if (!dump) { offset += IDLE_CHK_RESULT_REG_HDR_DWORDS + reg->entry_size; + continue; } + + offset += IDLE_CHK_RESULT_REG_HDR_DWORDS; + memset(reg_hdr, 0, sizeof(*reg_hdr)); + reg_hdr->start_entry = reg->start_entry; + reg_hdr->size = reg->entry_size; + SET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM, + reg->num_entries > 1 || reg->start_entry > 0 ? 1 : 0); + SET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID, reg_id); + + /* Write register values */ + for (i = 0; i < reg_hdr->size; i++, next_reg_offset++, offset++) + dump_buf[offset] = cond_reg_values[next_reg_offset]; } /* Dump info register values */ @@ -3824,12 +4136,12 @@ static u32 qed_idle_chk_dump_failure(struct qed_hwfn *p_hwfn, const struct dbg_idle_chk_info_reg *reg = &info_regs[reg_id]; u32 block_id; + /* Check if register's block is in reset */ if (!dump) { offset += IDLE_CHK_RESULT_REG_HDR_DWORDS + reg->size; continue; } - /* Check if register's block is in reset */ block_id = GET_FIELD(reg->data, DBG_IDLE_CHK_INFO_REG_BLOCK_ID); if (block_id >= MAX_BLOCK_ID) { DP_NOTICE(p_hwfn, "Invalid block_id\n"); @@ -3837,47 +4149,50 @@ static u32 qed_idle_chk_dump_failure(struct qed_hwfn *p_hwfn, } if (!dev_data->block_in_reset[block_id]) { - bool eval_mode = GET_FIELD(reg->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; - bool mode_match = true; + struct dbg_idle_chk_result_reg_hdr *reg_hdr; + bool wide_bus, eval_mode, mode_match = true; + u16 modes_buf_offset; + u32 addr; + + reg_hdr = (struct dbg_idle_chk_result_reg_hdr *) + (dump_buf + offset); /* Check mode */ + eval_mode = GET_FIELD(reg->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; if (eval_mode) { - u16 modes_buf_offset = - GET_FIELD(reg->mode.data, - DBG_MODE_HDR_MODES_BUF_OFFSET); + modes_buf_offset = + GET_FIELD(reg->mode.data, + DBG_MODE_HDR_MODES_BUF_OFFSET); mode_match = qed_is_mode_match(p_hwfn, &modes_buf_offset); } - if (mode_match) { - u32 addr = - GET_FIELD(reg->data, - DBG_IDLE_CHK_INFO_REG_ADDRESS); - - /* Write register header */ - struct dbg_idle_chk_result_reg_hdr *reg_hdr = - (struct dbg_idle_chk_result_reg_hdr *) - (dump_buf + offset); - - offset += IDLE_CHK_RESULT_REG_HDR_DWORDS; - hdr->num_dumped_info_regs++; - memset(reg_hdr, 0, sizeof(*reg_hdr)); - reg_hdr->size = reg->size; - SET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID, - rule->num_cond_regs + reg_id); - - /* Write register values */ - offset += - qed_grc_dump_addr_range(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - addr, - reg->size); - } + if (!mode_match) + continue; + + addr = GET_FIELD(reg->data, + DBG_IDLE_CHK_INFO_REG_ADDRESS); + wide_bus = GET_FIELD(reg->data, + DBG_IDLE_CHK_INFO_REG_WIDE_BUS); + + /* Write register header */ + offset += IDLE_CHK_RESULT_REG_HDR_DWORDS; + hdr->num_dumped_info_regs++; + memset(reg_hdr, 0, sizeof(*reg_hdr)); + reg_hdr->size = reg->size; + SET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID, + rule->num_cond_regs + reg_id); + + /* Write register values */ + offset += qed_grc_dump_addr_range(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + addr, + reg->size, wide_bus); } } @@ -3898,6 +4213,7 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u8 reg_id; *num_failing_rules = 0; + for (i = 0; i < num_input_rules; i++) { const struct dbg_idle_chk_cond_reg *cond_regs; const struct dbg_idle_chk_rule *rule; @@ -3920,8 +4236,9 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, */ for (reg_id = 0; reg_id < rule->num_cond_regs && check_rule; reg_id++) { - u32 block_id = GET_FIELD(cond_regs[reg_id].data, - DBG_IDLE_CHK_COND_REG_BLOCK_ID); + u32 block_id = + GET_FIELD(cond_regs[reg_id].data, + DBG_IDLE_CHK_COND_REG_BLOCK_ID); if (block_id >= MAX_BLOCK_ID) { DP_NOTICE(p_hwfn, "Invalid block_id\n"); @@ -3936,48 +4253,47 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, if (!check_rule && dump) continue; - if (!dump) { - u32 entry_dump_size = - qed_idle_chk_dump_failure(p_hwfn, - p_ptt, - dump_buf + offset, - false, - rule->rule_id, - rule, - 0, - NULL); - - offset += num_reg_entries * entry_dump_size; - (*num_failing_rules) += num_reg_entries; - continue; - } - /* Go over all register entries (number of entries is the same * for all condition registers). */ for (entry_id = 0; entry_id < num_reg_entries; entry_id++) { - /* Read current entry of all condition registers */ u32 next_reg_offset = 0; + if (!dump) { + offset += qed_idle_chk_dump_failure(p_hwfn, + p_ptt, + dump_buf + offset, + false, + rule->rule_id, + rule, + entry_id, + NULL); + (*num_failing_rules)++; + break; + } + + /* Read current entry of all condition registers */ for (reg_id = 0; reg_id < rule->num_cond_regs; reg_id++) { const struct dbg_idle_chk_cond_reg *reg = - &cond_regs[reg_id]; + &cond_regs[reg_id]; + u32 padded_entry_size, addr; + bool wide_bus; - /* Find GRC address (if it's a memory,the + /* Find GRC address (if it's a memory, the * address of the specific entry is calculated). */ - u32 addr = + addr = GET_FIELD(reg->data, + DBG_IDLE_CHK_COND_REG_ADDRESS); + wide_bus = GET_FIELD(reg->data, - DBG_IDLE_CHK_COND_REG_ADDRESS); - + DBG_IDLE_CHK_COND_REG_WIDE_BUS); if (reg->num_entries > 1 || reg->start_entry > 0) { - u32 padded_entry_size = - reg->entry_size > 1 ? - roundup_pow_of_two(reg->entry_size) : - 1; - + padded_entry_size = + reg->entry_size > 1 ? + roundup_pow_of_two(reg->entry_size) + : 1; addr += (reg->start_entry + entry_id) * padded_entry_size; } @@ -3991,28 +4307,27 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, } next_reg_offset += - qed_grc_dump_addr_range(p_hwfn, - p_ptt, + qed_grc_dump_addr_range(p_hwfn, p_ptt, cond_reg_values + next_reg_offset, dump, addr, - reg->entry_size); + reg->entry_size, + wide_bus); } - /* Call rule's condition function - a return value of - * true indicates failure. + /* Call rule condition function. + * If returns true, it's a failure. */ - if ((*cond_arr[rule->cond_id])(cond_reg_values, - imm_values)) { - offset += - qed_idle_chk_dump_failure(p_hwfn, - p_ptt, - dump_buf + offset, - dump, - rule->rule_id, - rule, - entry_id, - cond_reg_values); + if ((*cond_arr[rule->cond_id]) (cond_reg_values, + imm_values)) { + offset += qed_idle_chk_dump_failure(p_hwfn, + p_ptt, + dump_buf + offset, + dump, + rule->rule_id, + rule, + entry_id, + cond_reg_values); (*num_failing_rules)++; break; } @@ -4028,8 +4343,8 @@ qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, static u32 qed_idle_chk_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *dump_buf, bool dump) { - u32 offset = 0, input_offset = 0, num_failing_rules = 0; - u32 num_failing_rules_offset; + u32 num_failing_rules_offset, offset = 0, input_offset = 0; + u32 num_failing_rules = 0; /* Dump global params */ offset += qed_dump_common_global_params(p_hwfn, @@ -4042,29 +4357,29 @@ static u32 qed_idle_chk_dump(struct qed_hwfn *p_hwfn, offset += qed_dump_section_hdr(dump_buf + offset, dump, "idle_chk", 1); num_failing_rules_offset = offset; offset += qed_dump_num_param(dump_buf + offset, dump, "num_rules", 0); + while (input_offset < s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_RULES].size_in_dwords) { const struct dbg_idle_chk_cond_hdr *cond_hdr = (const struct dbg_idle_chk_cond_hdr *) &s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_RULES].ptr [input_offset++]; - bool eval_mode = GET_FIELD(cond_hdr->mode.data, - DBG_MODE_HDR_EVAL_MODE) > 0; - bool mode_match = true; + bool eval_mode, mode_match = true; + u32 curr_failing_rules; + u16 modes_buf_offset; /* Check mode */ + eval_mode = GET_FIELD(cond_hdr->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; if (eval_mode) { - u16 modes_buf_offset = + modes_buf_offset = GET_FIELD(cond_hdr->mode.data, DBG_MODE_HDR_MODES_BUF_OFFSET); - mode_match = qed_is_mode_match(p_hwfn, &modes_buf_offset); } if (mode_match) { - u32 curr_failing_rules; - offset += qed_idle_chk_dump_rule_entries(p_hwfn, p_ptt, @@ -4086,10 +4401,13 @@ static u32 qed_idle_chk_dump(struct qed_hwfn *p_hwfn, qed_dump_num_param(dump_buf + num_failing_rules_offset, dump, "num_rules", num_failing_rules); + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); + return offset; } -/* Finds the meta data image in NVRAM. */ +/* Finds the meta data image in NVRAM */ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 image_type, @@ -4098,16 +4416,16 @@ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, { u32 ret_mcp_resp, ret_mcp_param, ret_txn_size; struct mcp_file_att file_att; + int nvm_result; /* Call NVRAM get file command */ - int nvm_result = qed_mcp_nvm_rd_cmd(p_hwfn, - p_ptt, - DRV_MSG_CODE_NVM_GET_FILE_ATT, - image_type, - &ret_mcp_resp, - &ret_mcp_param, - &ret_txn_size, - (u32 *)&file_att); + nvm_result = qed_mcp_nvm_rd_cmd(p_hwfn, + p_ptt, + DRV_MSG_CODE_NVM_GET_FILE_ATT, + image_type, + &ret_mcp_resp, + &ret_mcp_param, + &ret_txn_size, (u32 *)&file_att); /* Check response */ if (nvm_result || @@ -4117,6 +4435,7 @@ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, /* Update return values */ *nvram_offset_bytes = file_att.nvm_start_addr; *nvram_size_bytes = file_att.len; + DP_VERBOSE(p_hwfn, QED_MSG_DEBUG, "find_nvram_image: found NVRAM image of type %d in NVRAM offset %d bytes with size %d bytes\n", @@ -4125,22 +4444,25 @@ static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn, /* Check alignment */ if (*nvram_size_bytes & 0x3) return DBG_STATUS_NON_ALIGNED_NVRAM_IMAGE; + return DBG_STATUS_OK; } +/* Reads data from NVRAM */ static enum dbg_status qed_nvram_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 nvram_offset_bytes, u32 nvram_size_bytes, u32 *ret_buf) { - u32 ret_mcp_resp, ret_mcp_param, ret_read_size; - u32 bytes_to_copy, read_offset = 0; + u32 ret_mcp_resp, ret_mcp_param, ret_read_size, bytes_to_copy; s32 bytes_left = nvram_size_bytes; + u32 read_offset = 0; DP_VERBOSE(p_hwfn, QED_MSG_DEBUG, "nvram_read: reading image of size %d bytes from NVRAM\n", nvram_size_bytes); + do { bytes_to_copy = (bytes_left > @@ -4155,8 +4477,7 @@ static enum dbg_status qed_nvram_read(struct qed_hwfn *p_hwfn, DRV_MB_PARAM_NVM_LEN_SHIFT), &ret_mcp_resp, &ret_mcp_param, &ret_read_size, - (u32 *)((u8 *)ret_buf + - read_offset)) != 0) + (u32 *)((u8 *)ret_buf + read_offset))) return DBG_STATUS_NVRAM_READ_FAILED; /* Check response */ @@ -4172,24 +4493,20 @@ static enum dbg_status qed_nvram_read(struct qed_hwfn *p_hwfn, } /* Get info on the MCP Trace data in the scratchpad: - * - trace_data_grc_addr - the GRC address of the trace data - * - trace_data_size_bytes - the size in bytes of the MCP Trace data (without - * the header) + * - trace_data_grc_addr (OUT): trace data GRC address in bytes + * - trace_data_size (OUT): trace data size in bytes (without the header) */ static enum dbg_status qed_mcp_trace_get_data_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *trace_data_grc_addr, - u32 *trace_data_size_bytes) + u32 *trace_data_size) { - /* Read MCP trace section offsize structure from MCP scratchpad */ - u32 spad_trace_offsize = qed_rd(p_hwfn, - p_ptt, - MCP_SPAD_TRACE_OFFSIZE_ADDR); - u32 signature; + u32 spad_trace_offsize, signature; - /* Extract MCP trace section GRC address from offsize structure (within - * scratchpad). - */ + /* Read trace section offsize structure from MCP scratchpad */ + spad_trace_offsize = qed_rd(p_hwfn, p_ptt, MCP_SPAD_TRACE_OFFSIZE_ADDR); + + /* Extract trace section address from offsize (in scratchpad) */ *trace_data_grc_addr = MCP_REG_SCRATCH + SECTION_OFFSET(spad_trace_offsize); @@ -4197,42 +4514,41 @@ static enum dbg_status qed_mcp_trace_get_data_info(struct qed_hwfn *p_hwfn, signature = qed_rd(p_hwfn, p_ptt, *trace_data_grc_addr + offsetof(struct mcp_trace, signature)); + if (signature != MFW_TRACE_SIGNATURE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; /* Read trace size from MCP trace section */ - *trace_data_size_bytes = qed_rd(p_hwfn, - p_ptt, - *trace_data_grc_addr + - offsetof(struct mcp_trace, size)); + *trace_data_size = qed_rd(p_hwfn, + p_ptt, + *trace_data_grc_addr + + offsetof(struct mcp_trace, size)); + return DBG_STATUS_OK; } -/* Reads MCP trace meta data image from NVRAM. - * - running_bundle_id (OUT) - the running bundle ID (invalid when loaded from - * file) - * - trace_meta_offset_bytes (OUT) - the NVRAM offset in bytes in which the MCP - * Trace meta data starts (invalid when loaded from file) - * - trace_meta_size_bytes (OUT) - the size in bytes of the MCP Trace meta data +/* Reads MCP trace meta data image from NVRAM + * - running_bundle_id (OUT): running bundle ID (invalid when loaded from file) + * - trace_meta_offset (OUT): trace meta offset in NVRAM in bytes (invalid when + * loaded from file). + * - trace_meta_size (OUT): size in bytes of the trace meta data. */ static enum dbg_status qed_mcp_trace_get_meta_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 trace_data_size_bytes, u32 *running_bundle_id, - u32 *trace_meta_offset_bytes, - u32 *trace_meta_size_bytes) + u32 *trace_meta_offset, + u32 *trace_meta_size) { + u32 spad_trace_offsize, nvram_image_type, running_mfw_addr; + /* Read MCP trace section offsize structure from MCP scratchpad */ - u32 spad_trace_offsize = qed_rd(p_hwfn, - p_ptt, - MCP_SPAD_TRACE_OFFSIZE_ADDR); + spad_trace_offsize = qed_rd(p_hwfn, p_ptt, MCP_SPAD_TRACE_OFFSIZE_ADDR); /* Find running bundle ID */ - u32 running_mfw_addr = + running_mfw_addr = MCP_REG_SCRATCH + SECTION_OFFSET(spad_trace_offsize) + QED_SECTION_SIZE(spad_trace_offsize) + trace_data_size_bytes; - u32 nvram_image_type; - *running_bundle_id = qed_rd(p_hwfn, p_ptt, running_mfw_addr); if (*running_bundle_id > 1) return DBG_STATUS_INVALID_NVRAM_BUNDLE; @@ -4241,40 +4557,33 @@ static enum dbg_status qed_mcp_trace_get_meta_info(struct qed_hwfn *p_hwfn, nvram_image_type = (*running_bundle_id == DIR_ID_1) ? NVM_TYPE_MFW_TRACE1 : NVM_TYPE_MFW_TRACE2; - return qed_find_nvram_image(p_hwfn, p_ptt, nvram_image_type, - trace_meta_offset_bytes, - trace_meta_size_bytes); + trace_meta_offset, trace_meta_size); } -/* Reads the MCP Trace meta data (from NVRAM or buffer) into the specified - * buffer. - */ +/* Reads the MCP Trace meta data from NVRAM into the specified buffer */ static enum dbg_status qed_mcp_trace_read_meta(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 nvram_offset_in_bytes, u32 size_in_bytes, u32 *buf) { - u8 *byte_buf = (u8 *)buf; - u8 modules_num, i; + u8 modules_num, module_len, i, *byte_buf = (u8 *)buf; + enum dbg_status status; u32 signature; /* Read meta data from NVRAM */ - enum dbg_status status = qed_nvram_read(p_hwfn, - p_ptt, - nvram_offset_in_bytes, - size_in_bytes, - buf); - + status = qed_nvram_read(p_hwfn, + p_ptt, + nvram_offset_in_bytes, size_in_bytes, buf); if (status != DBG_STATUS_OK) return status; /* Extract and check first signature */ signature = qed_read_unaligned_dword(byte_buf); - byte_buf += sizeof(u32); - if (signature != MCP_TRACE_META_IMAGE_SIGNATURE) + byte_buf += sizeof(signature); + if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; /* Extract number of modules */ @@ -4282,16 +4591,16 @@ static enum dbg_status qed_mcp_trace_read_meta(struct qed_hwfn *p_hwfn, /* Skip all modules */ for (i = 0; i < modules_num; i++) { - u8 module_len = *(byte_buf++); - + module_len = *(byte_buf++); byte_buf += module_len; } /* Extract and check second signature */ signature = qed_read_unaligned_dword(byte_buf); - byte_buf += sizeof(u32); - if (signature != MCP_TRACE_META_IMAGE_SIGNATURE) + byte_buf += sizeof(signature); + if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; + return DBG_STATUS_OK; } @@ -4308,10 +4617,10 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, bool mcp_access; int halted = 0; - mcp_access = !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP); - *num_dumped_dwords = 0; + mcp_access = !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP); + /* Get trace data info */ status = qed_mcp_trace_get_data_info(p_hwfn, p_ptt, @@ -4328,7 +4637,7 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, dump, "dump-type", "mcp-trace"); /* Halt MCP while reading from scratchpad so the read data will be - * consistent if halt fails, MCP trace is taken anyway, with a small + * consistent. if halt fails, MCP trace is taken anyway, with a small * risk that it may be corrupt. */ if (dump && mcp_access) { @@ -4339,8 +4648,8 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, /* Find trace data size */ trace_data_size_dwords = - DIV_ROUND_UP(trace_data_size_bytes + sizeof(struct mcp_trace), - BYTES_IN_DWORD); + DIV_ROUND_UP(trace_data_size_bytes + sizeof(struct mcp_trace), + BYTES_IN_DWORD); /* Dump trace data section header and param */ offset += qed_dump_section_hdr(dump_buf + offset, @@ -4354,17 +4663,17 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, BYTES_TO_DWORDS(trace_data_grc_addr), - trace_data_size_dwords); + trace_data_size_dwords, false); /* Resume MCP (only if halt succeeded) */ - if (halted && qed_mcp_resume(p_hwfn, p_ptt) != 0) + if (halted && qed_mcp_resume(p_hwfn, p_ptt)) DP_NOTICE(p_hwfn, "Failed to resume MCP after halt!\n"); /* Dump trace meta section header */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "mcp_trace_meta", 1); - /* Read trace meta info */ + /* Read trace meta info (trace_meta_size_bytes is dword-aligned) */ if (mcp_access) { status = qed_mcp_trace_get_meta_info(p_hwfn, p_ptt, @@ -4391,6 +4700,9 @@ static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn, if (status == DBG_STATUS_OK) offset += trace_meta_size_dwords; + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); + *num_dumped_dwords = offset; /* If no mcp access, indicate that the dump doesn't contain the meta @@ -4405,7 +4717,7 @@ static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, bool dump, u32 *num_dumped_dwords) { - u32 offset = 0, dwords_read, size_param_offset; + u32 dwords_read, size_param_offset, offset = 0; bool fifo_has_data; *num_dumped_dwords = 0; @@ -4417,8 +4729,8 @@ static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, offset += qed_dump_str_param(dump_buf + offset, dump, "dump-type", "reg-fifo"); - /* Dump fifo data section header and param. The size param is 0 for now, - * and is overwritten after reading the FIFO. + /* Dump fifo data section header and param. The size param is 0 for + * now, and is overwritten after reading the FIFO. */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "reg_fifo_data", 1); @@ -4430,8 +4742,7 @@ static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, * test how much data is available, except for reading it. */ offset += REG_FIFO_DEPTH_DWORDS; - *num_dumped_dwords = offset; - return DBG_STATUS_OK; + goto out; } fifo_has_data = qed_rd(p_hwfn, p_ptt, @@ -4456,8 +4767,12 @@ static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn, qed_dump_num_param(dump_buf + size_param_offset, dump, "size", dwords_read); +out: + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); *num_dumped_dwords = offset; + return DBG_STATUS_OK; } @@ -4467,7 +4782,7 @@ static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, bool dump, u32 *num_dumped_dwords) { - u32 offset = 0, dwords_read, size_param_offset; + u32 dwords_read, size_param_offset, offset = 0; bool fifo_has_data; *num_dumped_dwords = 0; @@ -4479,8 +4794,8 @@ static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, offset += qed_dump_str_param(dump_buf + offset, dump, "dump-type", "igu-fifo"); - /* Dump fifo data section header and param. The size param is 0 for now, - * and is overwritten after reading the FIFO. + /* Dump fifo data section header and param. The size param is 0 for + * now, and is overwritten after reading the FIFO. */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "igu_fifo_data", 1); @@ -4492,8 +4807,7 @@ static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, * test how much data is available, except for reading it. */ offset += IGU_FIFO_DEPTH_DWORDS; - *num_dumped_dwords = offset; - return DBG_STATUS_OK; + goto out; } fifo_has_data = qed_rd(p_hwfn, p_ptt, @@ -4519,8 +4833,12 @@ static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn, qed_dump_num_param(dump_buf + size_param_offset, dump, "size", dwords_read); +out: + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); *num_dumped_dwords = offset; + return DBG_STATUS_OK; } @@ -4531,7 +4849,7 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, bool dump, u32 *num_dumped_dwords) { - u32 offset = 0, size_param_offset, override_window_dwords; + u32 size_param_offset, override_window_dwords, offset = 0; *num_dumped_dwords = 0; @@ -4542,8 +4860,8 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, offset += qed_dump_str_param(dump_buf + offset, dump, "dump-type", "protection-override"); - /* Dump data section header and param. The size param is 0 for now, and - * is overwritten after reading the data. + /* Dump data section header and param. The size param is 0 for now, + * and is overwritten after reading the data. */ offset += qed_dump_section_hdr(dump_buf + offset, dump, "protection_override_data", 1); @@ -4552,8 +4870,7 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, if (!dump) { offset += PROTECTION_OVERRIDE_DEPTH_DWORDS; - *num_dumped_dwords = offset; - return DBG_STATUS_OK; + goto out; } /* Add override window info to buffer */ @@ -4569,8 +4886,12 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, offset += override_window_dwords; qed_dump_num_param(dump_buf + size_param_offset, dump, "size", override_window_dwords); +out: + /* Dump last section */ + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); *num_dumped_dwords = offset; + return DBG_STATUS_OK; } @@ -4593,11 +4914,14 @@ static u32 qed_fw_asserts_dump(struct qed_hwfn *p_hwfn, dump_buf + offset, dump, 1); offset += qed_dump_str_param(dump_buf + offset, dump, "dump-type", "fw-asserts"); + + /* Find Storm dump size */ for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) { u32 fw_asserts_section_addr, next_list_idx_addr, next_list_idx; + struct storm_defs *storm = &s_storm_defs[storm_id]; u32 last_list_idx, addr; - if (dev_data->block_in_reset[s_storm_defs[storm_id].block_id]) + if (dev_data->block_in_reset[storm->block_id]) continue; /* Read FW info for the current Storm */ @@ -4606,26 +4930,26 @@ static u32 qed_fw_asserts_dump(struct qed_hwfn *p_hwfn, asserts = &fw_info.fw_asserts_section; /* Dump FW Asserts section header and params */ - storm_letter_str[0] = s_storm_defs[storm_id].letter; - offset += qed_dump_section_hdr(dump_buf + offset, dump, - "fw_asserts", 2); - offset += qed_dump_str_param(dump_buf + offset, dump, "storm", - storm_letter_str); - offset += qed_dump_num_param(dump_buf + offset, dump, "size", + storm_letter_str[0] = storm->letter; + offset += qed_dump_section_hdr(dump_buf + offset, + dump, "fw_asserts", 2); + offset += qed_dump_str_param(dump_buf + offset, + dump, "storm", storm_letter_str); + offset += qed_dump_num_param(dump_buf + offset, + dump, + "size", asserts->list_element_dword_size); + /* Read and dump FW Asserts data */ if (!dump) { offset += asserts->list_element_dword_size; continue; } - /* Read and dump FW Asserts data */ - fw_asserts_section_addr = - s_storm_defs[storm_id].sem_fast_mem_addr + + fw_asserts_section_addr = storm->sem_fast_mem_addr + SEM_FAST_REG_INT_RAM + RAM_LINES_TO_BYTES(asserts->section_ram_line_offset); - next_list_idx_addr = - fw_asserts_section_addr + + next_list_idx_addr = fw_asserts_section_addr + DWORDS_TO_BYTES(asserts->list_next_index_dword_offset); next_list_idx = qed_rd(p_hwfn, p_ptt, next_list_idx_addr); last_list_idx = (next_list_idx > 0 @@ -4638,11 +4962,13 @@ static u32 qed_fw_asserts_dump(struct qed_hwfn *p_hwfn, qed_grc_dump_addr_range(p_hwfn, p_ptt, dump_buf + offset, dump, addr, - asserts->list_element_dword_size); + asserts->list_element_dword_size, + false); } /* Dump last section */ - offset += qed_dump_section_hdr(dump_buf + offset, dump, "last", 0); + offset += qed_dump_last_section(p_hwfn, dump_buf, offset, dump); + return offset; } @@ -4650,10 +4976,10 @@ static u32 qed_fw_asserts_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_set_bin_ptr(const u8 * const bin_ptr) { - /* Convert binary data to debug arrays */ struct bin_buffer_hdr *buf_array = (struct bin_buffer_hdr *)bin_ptr; u8 buf_id; + /* convert binary data to debug arrays */ for (buf_id = 0; buf_id < MAX_BIN_DBG_BUFFER_TYPE; buf_id++) { s_dbg_arrays[buf_id].ptr = (u32 *)(bin_ptr + buf_array[buf_id].offset); @@ -4682,14 +5008,17 @@ enum dbg_status qed_dbg_grc_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + if (!s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr || !s_dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr || !s_dbg_arrays[BIN_BUF_DBG_DUMP_MEM].ptr || !s_dbg_arrays[BIN_BUF_DBG_ATTN_BLOCKS].ptr || !s_dbg_arrays[BIN_BUF_DBG_ATTN_REGS].ptr) return DBG_STATUS_DBG_ARRAY_NOT_SET; + return qed_grc_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4702,12 +5031,14 @@ enum dbg_status qed_dbg_grc_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_grc_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = qed_dbg_grc_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4724,25 +5055,31 @@ enum dbg_status qed_dbg_idle_chk_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size) { - enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); struct dbg_tools_data *dev_data = &p_hwfn->dbg_info; + struct idle_chk_data *idle_chk; + enum dbg_status status; + idle_chk = &dev_data->idle_chk; *buf_size = 0; + + status = qed_dbg_dev_init(p_hwfn, p_ptt); if (status != DBG_STATUS_OK) return status; + if (!s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr || !s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_REGS].ptr || !s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_IMMS].ptr || !s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_RULES].ptr) return DBG_STATUS_DBG_ARRAY_NOT_SET; - if (!dev_data->idle_chk.buf_size_set) { - dev_data->idle_chk.buf_size = qed_idle_chk_dump(p_hwfn, - p_ptt, - NULL, false); - dev_data->idle_chk.buf_size_set = true; + + if (!idle_chk->buf_size_set) { + idle_chk->buf_size = qed_idle_chk_dump(p_hwfn, + p_ptt, NULL, false); + idle_chk->buf_size_set = true; } - *buf_size = dev_data->idle_chk.buf_size; + *buf_size = idle_chk->buf_size; + return DBG_STATUS_OK; } @@ -4755,12 +5092,14 @@ enum dbg_status qed_dbg_idle_chk_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_idle_chk_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = qed_dbg_idle_chk_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4783,8 +5122,10 @@ enum dbg_status qed_dbg_mcp_trace_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + return qed_mcp_trace_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4797,13 +5138,12 @@ enum dbg_status qed_dbg_mcp_trace_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - /* validate buffer size */ status = - qed_dbg_mcp_trace_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - - if (status != DBG_STATUS_OK && - status != DBG_STATUS_NVRAM_GET_IMAGE_FAILED) + qed_dbg_mcp_trace_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); + if (status != DBG_STATUS_OK && status != + DBG_STATUS_NVRAM_GET_IMAGE_FAILED) return status; if (buf_size_in_dwords < needed_buf_size_in_dwords) @@ -4829,8 +5169,10 @@ enum dbg_status qed_dbg_reg_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + return qed_reg_fifo_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4843,12 +5185,14 @@ enum dbg_status qed_dbg_reg_fifo_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_reg_fifo_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = qed_dbg_reg_fifo_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4871,8 +5215,10 @@ enum dbg_status qed_dbg_igu_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + return qed_igu_fifo_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4885,12 +5231,14 @@ enum dbg_status qed_dbg_igu_fifo_dump(struct qed_hwfn *p_hwfn, u32 needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_igu_fifo_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = qed_dbg_igu_fifo_get_dump_buf_size(p_hwfn, + p_ptt, + &needed_buf_size_in_dwords); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4913,8 +5261,10 @@ qed_dbg_protection_override_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; + return qed_protection_override_dump(p_hwfn, p_ptt, NULL, false, buf_size); } @@ -4925,15 +5275,18 @@ enum dbg_status qed_dbg_protection_override_dump(struct qed_hwfn *p_hwfn, u32 buf_size_in_dwords, u32 *num_dumped_dwords) { - u32 needed_buf_size_in_dwords; + u32 needed_buf_size_in_dwords, *p_size = &needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_protection_override_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = + qed_dbg_protection_override_get_dump_buf_size(p_hwfn, + p_ptt, + p_size); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; @@ -4958,12 +5311,15 @@ enum dbg_status qed_dbg_fw_asserts_get_dump_buf_size(struct qed_hwfn *p_hwfn, enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); *buf_size = 0; + if (status != DBG_STATUS_OK) return status; /* Update reset state */ qed_update_blocks_reset_state(p_hwfn, p_ptt); + *buf_size = qed_fw_asserts_dump(p_hwfn, p_ptt, NULL, false); + return DBG_STATUS_OK; } @@ -4973,19 +5329,26 @@ enum dbg_status qed_dbg_fw_asserts_dump(struct qed_hwfn *p_hwfn, u32 buf_size_in_dwords, u32 *num_dumped_dwords) { - u32 needed_buf_size_in_dwords; + u32 needed_buf_size_in_dwords, *p_size = &needed_buf_size_in_dwords; enum dbg_status status; - status = qed_dbg_fw_asserts_get_dump_buf_size(p_hwfn, p_ptt, - &needed_buf_size_in_dwords); - *num_dumped_dwords = 0; + + status = + qed_dbg_fw_asserts_get_dump_buf_size(p_hwfn, + p_ptt, + p_size); if (status != DBG_STATUS_OK) return status; + if (buf_size_in_dwords < needed_buf_size_in_dwords) return DBG_STATUS_DUMP_BUF_TOO_SMALL; *num_dumped_dwords = qed_fw_asserts_dump(p_hwfn, p_ptt, dump_buf, true); + + /* Revert GRC params to their default */ + qed_dbg_grc_set_params_default(p_hwfn); + return DBG_STATUS_OK; } @@ -5005,9 +5368,14 @@ struct mcp_trace_format { #define MCP_TRACE_FORMAT_P3_SIZE_SHIFT 22 #define MCP_TRACE_FORMAT_LEN_MASK 0xff000000 #define MCP_TRACE_FORMAT_LEN_SHIFT 24 + char *format_str; }; +/* Meta data structure, generated by a perl script during MFW build. therefore, + * the structs mcp_trace_meta and mcp_trace_format are duplicated in the perl + * script. + */ struct mcp_trace_meta { u32 modules_num; char **modules; @@ -5015,7 +5383,7 @@ struct mcp_trace_meta { struct mcp_trace_format *formats; }; -/* Reg fifo element */ +/* REG fifo element */ struct reg_fifo_element { u64 data; #define REG_FIFO_ELEMENT_ADDRESS_SHIFT 0 @@ -5140,12 +5508,15 @@ struct igu_fifo_addr_data { /******************************** Constants **********************************/ #define MAX_MSG_LEN 1024 + #define MCP_TRACE_MAX_MODULE_LEN 8 #define MCP_TRACE_FORMAT_MAX_PARAMS 3 #define MCP_TRACE_FORMAT_PARAM_WIDTH \ (MCP_TRACE_FORMAT_P2_SIZE_SHIFT - MCP_TRACE_FORMAT_P1_SIZE_SHIFT) + #define REG_FIFO_ELEMENT_ADDR_FACTOR 4 #define REG_FIFO_ELEMENT_IS_PF_VF_VAL 127 + #define PROTECTION_OVERRIDE_ELEMENT_ADDR_FACTOR 4 /********************************* Macros ************************************/ @@ -5154,59 +5525,178 @@ struct igu_fifo_addr_data { /***************************** Constant Arrays *******************************/ +struct user_dbg_array { + const u32 *ptr; + u32 size_in_dwords; +}; + +/* Debug arrays */ +static struct user_dbg_array +s_user_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {NULL} }; + /* Status string array */ static const char * const s_status_str[] = { + /* DBG_STATUS_OK */ "Operation completed successfully", + + /* DBG_STATUS_APP_VERSION_NOT_SET */ "Debug application version wasn't set", + + /* DBG_STATUS_UNSUPPORTED_APP_VERSION */ "Unsupported debug application version", + + /* DBG_STATUS_DBG_BLOCK_NOT_RESET */ "The debug block wasn't reset since the last recording", + + /* DBG_STATUS_INVALID_ARGS */ "Invalid arguments", + + /* DBG_STATUS_OUTPUT_ALREADY_SET */ "The debug output was already set", + + /* DBG_STATUS_INVALID_PCI_BUF_SIZE */ "Invalid PCI buffer size", + + /* DBG_STATUS_PCI_BUF_ALLOC_FAILED */ "PCI buffer allocation failed", + + /* DBG_STATUS_PCI_BUF_NOT_ALLOCATED */ "A PCI buffer wasn't allocated", + + /* DBG_STATUS_TOO_MANY_INPUTS */ "Too many inputs were enabled. Enabled less inputs, or set 'unifyInputs' to true", - "GRC/Timestamp input overlap in cycle dword 0", + + /* DBG_STATUS_INPUT_OVERLAP */ + "Overlapping debug bus inputs", + + /* DBG_STATUS_HW_ONLY_RECORDING */ "Cannot record Storm data since the entire recording cycle is used by HW", + + /* DBG_STATUS_STORM_ALREADY_ENABLED */ "The Storm was already enabled", + + /* DBG_STATUS_STORM_NOT_ENABLED */ "The specified Storm wasn't enabled", + + /* DBG_STATUS_BLOCK_ALREADY_ENABLED */ "The block was already enabled", + + /* DBG_STATUS_BLOCK_NOT_ENABLED */ "The specified block wasn't enabled", + + /* DBG_STATUS_NO_INPUT_ENABLED */ "No input was enabled for recording", + + /* DBG_STATUS_NO_FILTER_TRIGGER_64B */ "Filters and triggers are not allowed when recording in 64b units", + + /* DBG_STATUS_FILTER_ALREADY_ENABLED */ "The filter was already enabled", + + /* DBG_STATUS_TRIGGER_ALREADY_ENABLED */ "The trigger was already enabled", + + /* DBG_STATUS_TRIGGER_NOT_ENABLED */ "The trigger wasn't enabled", + + /* DBG_STATUS_CANT_ADD_CONSTRAINT */ "A constraint can be added only after a filter was enabled or a trigger state was added", + + /* DBG_STATUS_TOO_MANY_TRIGGER_STATES */ "Cannot add more than 3 trigger states", + + /* DBG_STATUS_TOO_MANY_CONSTRAINTS */ "Cannot add more than 4 constraints per filter or trigger state", + + /* DBG_STATUS_RECORDING_NOT_STARTED */ "The recording wasn't started", + + /* DBG_STATUS_DATA_DIDNT_TRIGGER */ "A trigger was configured, but it didn't trigger", + + /* DBG_STATUS_NO_DATA_RECORDED */ "No data was recorded", + + /* DBG_STATUS_DUMP_BUF_TOO_SMALL */ "Dump buffer is too small", + + /* DBG_STATUS_DUMP_NOT_CHUNK_ALIGNED */ "Dumped data is not aligned to chunks", + + /* DBG_STATUS_UNKNOWN_CHIP */ "Unknown chip", + + /* DBG_STATUS_VIRT_MEM_ALLOC_FAILED */ "Failed allocating virtual memory", + + /* DBG_STATUS_BLOCK_IN_RESET */ "The input block is in reset", + + /* DBG_STATUS_INVALID_TRACE_SIGNATURE */ "Invalid MCP trace signature found in NVRAM", + + /* DBG_STATUS_INVALID_NVRAM_BUNDLE */ "Invalid bundle ID found in NVRAM", + + /* DBG_STATUS_NVRAM_GET_IMAGE_FAILED */ "Failed getting NVRAM image", + + /* DBG_STATUS_NON_ALIGNED_NVRAM_IMAGE */ "NVRAM image is not dword-aligned", + + /* DBG_STATUS_NVRAM_READ_FAILED */ "Failed reading from NVRAM", + + /* DBG_STATUS_IDLE_CHK_PARSE_FAILED */ "Idle check parsing failed", + + /* DBG_STATUS_MCP_TRACE_BAD_DATA */ "MCP Trace data is corrupt", - "Dump doesn't contain meta data - it must be provided in an image file", + + /* DBG_STATUS_MCP_TRACE_NO_META */ + "Dump doesn't contain meta data - it must be provided in image file", + + /* DBG_STATUS_MCP_COULD_NOT_HALT */ "Failed to halt MCP", + + /* DBG_STATUS_MCP_COULD_NOT_RESUME */ "Failed to resume MCP after halt", + + /* DBG_STATUS_DMAE_FAILED */ "DMAE transaction failed", + + /* DBG_STATUS_SEMI_FIFO_NOT_EMPTY */ "Failed to empty SEMI sync FIFO", + + /* DBG_STATUS_IGU_FIFO_BAD_DATA */ "IGU FIFO data is corrupt", + + /* DBG_STATUS_MCP_COULD_NOT_MASK_PRTY */ "MCP failed to mask parities", + + /* DBG_STATUS_FW_ASSERTS_PARSE_FAILED */ "FW Asserts parsing failed", + + /* DBG_STATUS_REG_FIFO_BAD_DATA */ "GRC FIFO data is corrupt", + + /* DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA */ "Protection Override data is corrupt", + + /* DBG_STATUS_DBG_ARRAY_NOT_SET */ "Debug arrays were not set (when using binary files, dbg_set_bin_ptr must be called)", - "When a block is filtered, no other blocks can be recorded unless inputs are unified (due to a HW bug)" + + /* DBG_STATUS_FILTER_BUG */ + "Debug Bus filtering requires the -unifyInputs option (due to a HW bug)", + + /* DBG_STATUS_NON_MATCHING_LINES */ + "Non-matching debug lines - all lines must be of the same type (either 128b or 256b)", + + /* DBG_STATUS_INVALID_TRIGGER_DWORD_OFFSET */ + "The selected trigger dword offset wasn't enabled in the recorded HW block", + + /* DBG_STATUS_DBG_BUS_IN_USE */ + "The debug bus is in use" }; /* Idle check severity names array */ @@ -5223,12 +5713,13 @@ static const char * const s_mcp_trace_level_str[] = { "DEBUG" }; -/* Parsing strings */ +/* Access type names array */ static const char * const s_access_strs[] = { "read", "write" }; +/* Privilege type names array */ static const char * const s_privilege_strs[] = { "VF", "PDA", @@ -5236,6 +5727,7 @@ static const char * const s_privilege_strs[] = { "UA" }; +/* Protection type names array */ static const char * const s_protection_strs[] = { "(default)", "(default)", @@ -5247,6 +5739,7 @@ static const char * const s_protection_strs[] = { "override UA" }; +/* Master type names array */ static const char * const s_master_strs[] = { "???", "pxp", @@ -5266,6 +5759,7 @@ static const char * const s_master_strs[] = { "???" }; +/* REG FIFO error messages array */ static const char * const s_reg_fifo_error_strs[] = { "grc timeout", "address doesn't belong to any block", @@ -5274,6 +5768,7 @@ static const char * const s_reg_fifo_error_strs[] = { "path isolation error" }; +/* IGU FIFO sources array */ static const char * const s_igu_fifo_source_strs[] = { "TSTORM", "MSTORM", @@ -5288,6 +5783,7 @@ static const char * const s_igu_fifo_source_strs[] = { "GRC", }; +/* IGU FIFO error messages */ static const char * const s_igu_fifo_error_strs[] = { "no error", "length error", @@ -5308,13 +5804,18 @@ static const char * const s_igu_fifo_error_strs[] = { /* IGU FIFO address data */ static const struct igu_fifo_addr_data s_igu_fifo_addr_data[] = { - {0x0, 0x101, "MSI-X Memory", NULL, IGU_ADDR_TYPE_MSIX_MEM}, - {0x102, 0x1ff, "reserved", NULL, IGU_ADDR_TYPE_RESERVED}, - {0x200, 0x200, "Write PBA[0:63]", NULL, IGU_ADDR_TYPE_WRITE_PBA}, + {0x0, 0x101, "MSI-X Memory", NULL, + IGU_ADDR_TYPE_MSIX_MEM}, + {0x102, 0x1ff, "reserved", NULL, + IGU_ADDR_TYPE_RESERVED}, + {0x200, 0x200, "Write PBA[0:63]", NULL, + IGU_ADDR_TYPE_WRITE_PBA}, {0x201, 0x201, "Write PBA[64:127]", "reserved", IGU_ADDR_TYPE_WRITE_PBA}, - {0x202, 0x202, "Write PBA[128]", "reserved", IGU_ADDR_TYPE_WRITE_PBA}, - {0x203, 0x3ff, "reserved", NULL, IGU_ADDR_TYPE_RESERVED}, + {0x202, 0x202, "Write PBA[128]", "reserved", + IGU_ADDR_TYPE_WRITE_PBA}, + {0x203, 0x3ff, "reserved", NULL, + IGU_ADDR_TYPE_RESERVED}, {0x400, 0x5ef, "Write interrupt acknowledgment", NULL, IGU_ADDR_TYPE_WRITE_INT_ACK}, {0x5f0, 0x5f0, "Attention bits update", NULL, @@ -5331,8 +5832,10 @@ static const struct igu_fifo_addr_data s_igu_fifo_addr_data[] = { IGU_ADDR_TYPE_READ_INT}, {0x5f6, 0x5f6, "Read interrupt 0:63 without mask", NULL, IGU_ADDR_TYPE_READ_INT}, - {0x5f7, 0x5ff, "reserved", NULL, IGU_ADDR_TYPE_RESERVED}, - {0x600, 0x7ff, "Producer update", NULL, IGU_ADDR_TYPE_WRITE_PROD_UPDATE} + {0x5f7, 0x5ff, "reserved", NULL, + IGU_ADDR_TYPE_RESERVED}, + {0x600, 0x7ff, "Producer update", NULL, + IGU_ADDR_TYPE_WRITE_PROD_UPDATE} }; /******************************** Variables **********************************/ @@ -5340,28 +5843,12 @@ static const struct igu_fifo_addr_data s_igu_fifo_addr_data[] = { /* MCP Trace meta data - used in case the dump doesn't contain the meta data * (e.g. due to no NVRAM access). */ -static struct dbg_array s_mcp_trace_meta = { NULL, 0 }; +static struct user_dbg_array s_mcp_trace_meta = { NULL, 0 }; /* Temporary buffer, used for print size calculations */ static char s_temp_buf[MAX_MSG_LEN]; -/***************************** Public Functions *******************************/ - -enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr) -{ - /* Convert binary data to debug arrays */ - struct bin_buffer_hdr *buf_array = (struct bin_buffer_hdr *)bin_ptr; - u8 buf_id; - - for (buf_id = 0; buf_id < MAX_BIN_DBG_BUFFER_TYPE; buf_id++) { - s_dbg_arrays[buf_id].ptr = - (u32 *)(bin_ptr + buf_array[buf_id].offset); - s_dbg_arrays[buf_id].size_in_dwords = - BYTES_TO_DWORDS(buf_array[buf_id].length); - } - - return DBG_STATUS_OK; -} +/**************************** Private Functions ******************************/ static u32 qed_cyclic_add(u32 a, u32 b, u32 size) { @@ -5381,10 +5868,8 @@ static u32 qed_read_from_cyclic_buf(void *buf, u32 *offset, u32 buf_size, u8 num_bytes_to_read) { - u8 *bytes_buf = (u8 *)buf; - u8 *val_ptr; + u8 i, *val_ptr, *bytes_buf = (u8 *)buf; u32 val = 0; - u8 i; val_ptr = (u8 *)&val; @@ -5412,6 +5897,7 @@ static u32 qed_read_dword_from_buf(void *buf, u32 *offset) u32 dword_val = *(u32 *)&((u8 *)buf)[*offset]; *offset += 4; + return dword_val; } @@ -5445,7 +5931,7 @@ static u32 qed_read_param(u32 *dump_buf, const char **param_str_val, u32 *param_num_val) { char *char_buf = (char *)dump_buf; - u32 offset = 0; /* In bytes */ + size_t offset = 0; /* Extract param name */ *param_name = char_buf; @@ -5493,37 +5979,31 @@ static u32 qed_print_section_params(u32 *dump_buf, u32 i, dump_offset = 0, results_offset = 0; for (i = 0; i < num_section_params; i++) { - const char *param_name; - const char *param_str_val; + const char *param_name, *param_str_val; u32 param_num_val = 0; dump_offset += qed_read_param(dump_buf + dump_offset, ¶m_name, ¶m_str_val, ¶m_num_val); + if (param_str_val) - /* String param */ results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "%s: %s\n", param_name, param_str_val); else if (strcmp(param_name, "fw-timestamp")) - /* Numeric param */ results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "%s: %d\n", param_name, param_num_val); } - results_offset += - sprintf(qed_get_buf_ptr(results_buf, results_offset), "\n"); + results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), + "\n"); + *num_chars_printed = results_offset; - return dump_offset; -} -const char *qed_dbg_get_status_str(enum dbg_status status) -{ - return (status < - MAX_DBG_STATUS) ? s_status_str[status] : "Invalid debug status"; + return dump_offset; } /* Parses the idle check rules and returns the number of characters printed. @@ -5537,7 +6017,10 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, char *results_buf, u32 *num_errors, u32 *num_warnings) { - u32 rule_idx, results_offset = 0; /* Offset in results_buf in bytes */ + /* Offset in results_buf in bytes */ + u32 results_offset = 0; + + u32 rule_idx; u16 i, j; *num_errors = 0; @@ -5548,16 +6031,15 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, rule_idx++) { const struct dbg_idle_chk_rule_parsing_data *rule_parsing_data; struct dbg_idle_chk_result_hdr *hdr; - const char *parsing_str; + const char *parsing_str, *lsi_msg; u32 parsing_str_offset; - const char *lsi_msg; - u8 curr_reg_id = 0; bool has_fw_msg; + u8 curr_reg_id; hdr = (struct dbg_idle_chk_result_hdr *)dump_buf; rule_parsing_data = (const struct dbg_idle_chk_rule_parsing_data *) - &s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA]. + &s_user_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA]. ptr[hdr->rule_id]; parsing_str_offset = GET_FIELD(rule_parsing_data->data, @@ -5565,16 +6047,18 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, has_fw_msg = GET_FIELD(rule_parsing_data->data, DBG_IDLE_CHK_RULE_PARSING_DATA_HAS_FW_MSG) > 0; - parsing_str = &((const char *) - s_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr) - [parsing_str_offset]; + parsing_str = + &((const char *) + s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr) + [parsing_str_offset]; lsi_msg = parsing_str; + curr_reg_id = 0; if (hdr->severity >= MAX_DBG_IDLE_CHK_SEVERITY_TYPES) return 0; /* Skip rule header */ - dump_buf += (sizeof(struct dbg_idle_chk_result_hdr) / 4); + dump_buf += BYTES_TO_DWORDS(sizeof(*hdr)); /* Update errors/warnings count */ if (hdr->severity == IDLE_CHK_SEVERITY_ERROR || @@ -5606,19 +6090,19 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, for (i = 0; i < hdr->num_dumped_cond_regs + hdr->num_dumped_info_regs; i++) { - struct dbg_idle_chk_result_reg_hdr *reg_hdr - = (struct dbg_idle_chk_result_reg_hdr *) - dump_buf; - bool is_mem = - GET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM); - u8 reg_id = - GET_FIELD(reg_hdr->data, - DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID); + struct dbg_idle_chk_result_reg_hdr *reg_hdr; + bool is_mem; + u8 reg_id; + + reg_hdr = + (struct dbg_idle_chk_result_reg_hdr *)dump_buf; + is_mem = GET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM); + reg_id = GET_FIELD(reg_hdr->data, + DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID); /* Skip reg header */ - dump_buf += - (sizeof(struct dbg_idle_chk_result_reg_hdr) / 4); + dump_buf += BYTES_TO_DWORDS(sizeof(*reg_hdr)); /* Skip register names until the required reg_id is * reached. @@ -5660,6 +6144,7 @@ static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn, /* Check if end of dump buffer was exceeded */ if (dump_buf > dump_buf_end) return 0; + return results_offset; } @@ -5680,13 +6165,16 @@ static enum dbg_status qed_parse_idle_chk_dump(struct qed_hwfn *p_hwfn, const char *section_name, *param_name, *param_str_val; u32 *dump_buf_end = dump_buf + num_dumped_dwords; u32 num_section_params = 0, num_rules; - u32 results_offset = 0; /* Offset in results_buf in bytes */ + + /* Offset in results_buf in bytes */ + u32 results_offset = 0; *parsed_results_bytes = 0; *num_errors = 0; *num_warnings = 0; - if (!s_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr || - !s_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA].ptr) + + if (!s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr || + !s_user_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA].ptr) return DBG_STATUS_DBG_ARRAY_NOT_SET; /* Read global_params section */ @@ -5705,10 +6193,9 @@ static enum dbg_status qed_parse_idle_chk_dump(struct qed_hwfn *p_hwfn, §ion_name, &num_section_params); if (strcmp(section_name, "idle_chk") || num_section_params != 1) return DBG_STATUS_IDLE_CHK_PARSE_FAILED; - dump_buf += qed_read_param(dump_buf, ¶m_name, ¶m_str_val, &num_rules); - if (strcmp(param_name, "num_rules") != 0) + if (strcmp(param_name, "num_rules")) return DBG_STATUS_IDLE_CHK_PARSE_FAILED; if (num_rules) { @@ -5728,7 +6215,7 @@ static enum dbg_status qed_parse_idle_chk_dump(struct qed_hwfn *p_hwfn, results_offset : NULL, num_errors, num_warnings); results_offset += rules_print_size; - if (rules_print_size == 0) + if (!rules_print_size) return DBG_STATUS_IDLE_CHK_PARSE_FAILED; /* Print LSI output */ @@ -5745,69 +6232,38 @@ static enum dbg_status qed_parse_idle_chk_dump(struct qed_hwfn *p_hwfn, results_offset : NULL, num_errors, num_warnings); results_offset += rules_print_size; - if (rules_print_size == 0) + if (!rules_print_size) return DBG_STATUS_IDLE_CHK_PARSE_FAILED; } /* Print errors/warnings count */ - if (*num_errors) { + if (*num_errors) results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "\nIdle Check failed!!! (with %d errors and %d warnings)\n", *num_errors, *num_warnings); - } else if (*num_warnings) { + else if (*num_warnings) results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), - "\nIdle Check completed successfuly (with %d warnings)\n", + "\nIdle Check completed successfully (with %d warnings)\n", *num_warnings); - } else { + else results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), - "\nIdle Check completed successfuly\n"); - } + "\nIdle Check completed successfully\n"); /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; + return DBG_STATUS_OK; } -enum dbg_status qed_get_idle_chk_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) -{ - u32 num_errors, num_warnings; - - return qed_parse_idle_chk_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, - results_buf_size, - &num_errors, &num_warnings); -} - -enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf, - u32 *num_errors, u32 *num_warnings) -{ - u32 parsed_buf_size; - - return qed_parse_idle_chk_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, - &parsed_buf_size, - num_errors, num_warnings); -} - -/* Frees the specified MCP Trace meta data */ -static void qed_mcp_trace_free_meta(struct qed_hwfn *p_hwfn, - struct mcp_trace_meta *meta) +/* Frees the specified MCP Trace meta data */ +static void qed_mcp_trace_free_meta(struct qed_hwfn *p_hwfn, + struct mcp_trace_meta *meta) { u32 i; @@ -5841,12 +6297,10 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, /* Read first signature */ signature = qed_read_dword_from_buf(meta_buf_bytes, &offset); - if (signature != MCP_TRACE_META_IMAGE_SIGNATURE) + if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; - /* Read number of modules and allocate memory for all the modules - * pointers. - */ + /* Read no. of modules and allocate memory for their pointers */ meta->modules_num = qed_read_byte_from_buf(meta_buf_bytes, &offset); meta->modules = kzalloc(meta->modules_num * sizeof(char *), GFP_KERNEL); if (!meta->modules) @@ -5871,7 +6325,7 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, /* Read second signature */ signature = qed_read_dword_from_buf(meta_buf_bytes, &offset); - if (signature != MCP_TRACE_META_IMAGE_SIGNATURE) + if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; /* Read number of formats and allocate memory for all formats */ @@ -5919,10 +6373,10 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, param_mask, param_shift, param_num_val; - u32 num_section_params, offset, end_offset, bytes_left; + u32 end_offset, bytes_left, trace_data_dwords, trace_meta_dwords; + u32 param_mask, param_shift, param_num_val, num_section_params; const char *section_name, *param_name, *param_str_val; - u32 trace_data_dwords, trace_meta_dwords; + u32 offset, results_offset = 0; struct mcp_trace_meta meta; struct mcp_trace *trace; enum dbg_status status; @@ -5955,7 +6409,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, /* Prepare trace info */ trace = (struct mcp_trace *)dump_buf; - trace_buf = (u8 *)dump_buf + sizeof(struct mcp_trace); + trace_buf = (u8 *)dump_buf + sizeof(*trace); offset = trace->trace_oldest; end_offset = trace->trace_prod; bytes_left = qed_cyclic_sub(end_offset, offset, trace->size); @@ -5968,7 +6422,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, return DBG_STATUS_MCP_TRACE_BAD_DATA; dump_buf += qed_read_param(dump_buf, ¶m_name, ¶m_str_val, ¶m_num_val); - if (strcmp(param_name, "size") != 0) + if (strcmp(param_name, "size")) return DBG_STATUS_MCP_TRACE_BAD_DATA; trace_meta_dwords = param_num_val; @@ -6028,6 +6482,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, } format_ptr = &meta.formats[format_idx]; + for (i = 0, param_mask = MCP_TRACE_FORMAT_P1_SIZE_MASK, param_shift = MCP_TRACE_FORMAT_P1_SIZE_SHIFT; @@ -6050,6 +6505,7 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, */ if (param_size == 3) param_size = 4; + if (bytes_left < param_size) { status = DBG_STATUS_MCP_TRACE_BAD_DATA; goto free_mem; @@ -6059,13 +6515,14 @@ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, &offset, trace->size, param_size); + bytes_left -= param_size; } format_level = (u8)((format_ptr->data & MCP_TRACE_FORMAT_LEVEL_MASK) >> - MCP_TRACE_FORMAT_LEVEL_SHIFT); + MCP_TRACE_FORMAT_LEVEL_SHIFT); format_module = (u8)((format_ptr->data & MCP_TRACE_FORMAT_MODULE_MASK) >> @@ -6094,30 +6551,6 @@ free_mem: return status; } -enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) -{ - return qed_parse_mcp_trace_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, results_buf_size); -} - -enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf) -{ - u32 parsed_buf_size; - - return qed_parse_mcp_trace_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, &parsed_buf_size); -} - /* Parses a Reg FIFO dump buffer. * If result_buf is not NULL, the Reg FIFO results are printed to it. * In any case, the required results buffer size is assigned to @@ -6130,10 +6563,11 @@ static enum dbg_status qed_parse_reg_fifo_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, param_num_val, num_section_params, num_elements; const char *section_name, *param_name, *param_str_val; + u32 param_num_val, num_section_params, num_elements; struct reg_fifo_element *elements; u8 i, j, err_val, vf_val; + u32 results_offset = 0; char vf_str[4]; /* Read global_params section */ @@ -6179,17 +6613,17 @@ static enum dbg_status qed_parse_reg_fifo_dump(struct qed_hwfn *p_hwfn, "raw: 0x%016llx, address: 0x%07x, access: %-5s, pf: %2d, vf: %s, port: %d, privilege: %-3s, protection: %-12s, master: %-4s, errors: ", elements[i].data, (u32)GET_FIELD(elements[i].data, - REG_FIFO_ELEMENT_ADDRESS) * - REG_FIFO_ELEMENT_ADDR_FACTOR, - s_access_strs[GET_FIELD(elements[i].data, + REG_FIFO_ELEMENT_ADDRESS) * + REG_FIFO_ELEMENT_ADDR_FACTOR, + s_access_strs[GET_FIELD(elements[i].data, REG_FIFO_ELEMENT_ACCESS)], (u32)GET_FIELD(elements[i].data, - REG_FIFO_ELEMENT_PF), vf_str, + REG_FIFO_ELEMENT_PF), + vf_str, (u32)GET_FIELD(elements[i].data, - REG_FIFO_ELEMENT_PORT), - s_privilege_strs[GET_FIELD(elements[i]. - data, - REG_FIFO_ELEMENT_PRIVILEGE)], + REG_FIFO_ELEMENT_PORT), + s_privilege_strs[GET_FIELD(elements[i].data, + REG_FIFO_ELEMENT_PRIVILEGE)], s_protection_strs[GET_FIELD(elements[i].data, REG_FIFO_ELEMENT_PROTECTION)], s_master_strs[GET_FIELD(elements[i].data, @@ -6201,18 +6635,18 @@ static enum dbg_status qed_parse_reg_fifo_dump(struct qed_hwfn *p_hwfn, REG_FIFO_ELEMENT_ERROR); j < ARRAY_SIZE(s_reg_fifo_error_strs); j++, err_val >>= 1) { - if (!(err_val & 0x1)) - continue; - if (err_printed) + if (err_val & 0x1) { + if (err_printed) + results_offset += + sprintf(qed_get_buf_ptr + (results_buf, + results_offset), ", "); results_offset += - sprintf(qed_get_buf_ptr(results_buf, - results_offset), - ", "); - results_offset += - sprintf(qed_get_buf_ptr(results_buf, - results_offset), "%s", - s_reg_fifo_error_strs[j]); - err_printed = true; + sprintf(qed_get_buf_ptr + (results_buf, results_offset), "%s", + s_reg_fifo_error_strs[j]); + err_printed = true; + } } results_offset += @@ -6225,31 +6659,140 @@ static enum dbg_status qed_parse_reg_fifo_dump(struct qed_hwfn *p_hwfn, /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; + return DBG_STATUS_OK; } -enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) +static enum dbg_status qed_parse_igu_fifo_element(struct igu_fifo_element + *element, char + *results_buf, + u32 *results_offset, + u32 *parsed_results_bytes) { - return qed_parse_reg_fifo_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, results_buf_size); -} + const struct igu_fifo_addr_data *found_addr = NULL; + u8 source, err_type, i, is_cleanup; + char parsed_addr_data[32]; + char parsed_wr_data[256]; + u32 wr_data, prod_cons; + bool is_wr_cmd, is_pf; + u16 cmd_addr; + u64 dword12; -enum dbg_status qed_print_reg_fifo_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf) -{ - u32 parsed_buf_size; + /* Dword12 (dword index 1 and 2) contains bits 32..95 of the + * FIFO element. + */ + dword12 = ((u64)element->dword2 << 32) | element->dword1; + is_wr_cmd = GET_FIELD(dword12, IGU_FIFO_ELEMENT_DWORD12_IS_WR_CMD); + is_pf = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_IS_PF); + cmd_addr = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_CMD_ADDR); + source = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_SOURCE); + err_type = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_ERR_TYPE); + + if (source >= ARRAY_SIZE(s_igu_fifo_source_strs)) + return DBG_STATUS_IGU_FIFO_BAD_DATA; + if (err_type >= ARRAY_SIZE(s_igu_fifo_error_strs)) + return DBG_STATUS_IGU_FIFO_BAD_DATA; - return qed_parse_reg_fifo_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, &parsed_buf_size); + /* Find address data */ + for (i = 0; i < ARRAY_SIZE(s_igu_fifo_addr_data) && !found_addr; i++) { + const struct igu_fifo_addr_data *curr_addr = + &s_igu_fifo_addr_data[i]; + + if (cmd_addr >= curr_addr->start_addr && cmd_addr <= + curr_addr->end_addr) + found_addr = curr_addr; + } + + if (!found_addr) + return DBG_STATUS_IGU_FIFO_BAD_DATA; + + /* Prepare parsed address data */ + switch (found_addr->type) { + case IGU_ADDR_TYPE_MSIX_MEM: + sprintf(parsed_addr_data, " vector_num = 0x%x", cmd_addr / 2); + break; + case IGU_ADDR_TYPE_WRITE_INT_ACK: + case IGU_ADDR_TYPE_WRITE_PROD_UPDATE: + sprintf(parsed_addr_data, + " SB = 0x%x", cmd_addr - found_addr->start_addr); + break; + default: + parsed_addr_data[0] = '\0'; + } + + if (!is_wr_cmd) { + parsed_wr_data[0] = '\0'; + goto out; + } + + /* Prepare parsed write data */ + wr_data = GET_FIELD(dword12, IGU_FIFO_ELEMENT_DWORD12_WR_DATA); + prod_cons = GET_FIELD(wr_data, IGU_FIFO_WR_DATA_PROD_CONS); + is_cleanup = GET_FIELD(wr_data, IGU_FIFO_WR_DATA_CMD_TYPE); + + if (source == IGU_SRC_ATTN) { + sprintf(parsed_wr_data, "prod: 0x%x, ", prod_cons); + } else { + if (is_cleanup) { + u8 cleanup_val, cleanup_type; + + cleanup_val = + GET_FIELD(wr_data, + IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_VAL); + cleanup_type = + GET_FIELD(wr_data, + IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_TYPE); + + sprintf(parsed_wr_data, + "cmd_type: cleanup, cleanup_val: %s, cleanup_type : %d, ", + cleanup_val ? "set" : "clear", + cleanup_type); + } else { + u8 update_flag, en_dis_int_for_sb, segment; + u8 timer_mask; + + update_flag = GET_FIELD(wr_data, + IGU_FIFO_WR_DATA_UPDATE_FLAG); + en_dis_int_for_sb = + GET_FIELD(wr_data, + IGU_FIFO_WR_DATA_EN_DIS_INT_FOR_SB); + segment = GET_FIELD(wr_data, + IGU_FIFO_WR_DATA_SEGMENT); + timer_mask = GET_FIELD(wr_data, + IGU_FIFO_WR_DATA_TIMER_MASK); + + sprintf(parsed_wr_data, + "cmd_type: prod/cons update, prod/cons: 0x%x, update_flag: %s, en_dis_int_for_sb : %s, segment : %s, timer_mask = %d, ", + prod_cons, + update_flag ? "update" : "nop", + en_dis_int_for_sb + ? (en_dis_int_for_sb == 1 ? "disable" : "nop") + : "enable", + segment ? "attn" : "regular", + timer_mask); + } + } +out: + /* Add parsed element to parsed buffer */ + *results_offset += sprintf(qed_get_buf_ptr(results_buf, + *results_offset), + "raw: 0x%01x%08x%08x, %s: %d, source : %s, type : %s, cmd_addr : 0x%x(%s%s), %serror: %s\n", + element->dword2, element->dword1, + element->dword0, + is_pf ? "pf" : "vf", + GET_FIELD(element->dword0, + IGU_FIFO_ELEMENT_DWORD0_FID), + s_igu_fifo_source_strs[source], + is_wr_cmd ? "wr" : "rd", + cmd_addr, + (!is_pf && found_addr->vf_desc) + ? found_addr->vf_desc + : found_addr->desc, + parsed_addr_data, + parsed_wr_data, + s_igu_fifo_error_strs[err_type]); + + return DBG_STATUS_OK; } /* Parses an IGU FIFO dump buffer. @@ -6264,12 +6807,12 @@ static enum dbg_status qed_parse_igu_fifo_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, param_num_val, num_section_params, num_elements; const char *section_name, *param_name, *param_str_val; + u32 param_num_val, num_section_params, num_elements; struct igu_fifo_element *elements; - char parsed_addr_data[32]; - char parsed_wr_data[256]; - u8 i, j; + enum dbg_status status; + u32 results_offset = 0; + u8 i; /* Read global_params section */ dump_buf += qed_read_section_hdr(dump_buf, @@ -6298,118 +6841,12 @@ static enum dbg_status qed_parse_igu_fifo_dump(struct qed_hwfn *p_hwfn, /* Decode elements */ for (i = 0; i < num_elements; i++) { - /* dword12 (dword index 1 and 2) contains bits 32..95 of the - * FIFO element. - */ - u64 dword12 = - ((u64)elements[i].dword2 << 32) | elements[i].dword1; - bool is_wr_cmd = GET_FIELD(dword12, - IGU_FIFO_ELEMENT_DWORD12_IS_WR_CMD); - bool is_pf = GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_IS_PF); - u16 cmd_addr = GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_CMD_ADDR); - u8 source = GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_SOURCE); - u8 err_type = GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_ERR_TYPE); - const struct igu_fifo_addr_data *addr_data = NULL; - - if (source >= ARRAY_SIZE(s_igu_fifo_source_strs)) - return DBG_STATUS_IGU_FIFO_BAD_DATA; - if (err_type >= ARRAY_SIZE(s_igu_fifo_error_strs)) - return DBG_STATUS_IGU_FIFO_BAD_DATA; - - /* Find address data */ - for (j = 0; j < ARRAY_SIZE(s_igu_fifo_addr_data) && !addr_data; - j++) - if (cmd_addr >= s_igu_fifo_addr_data[j].start_addr && - cmd_addr <= s_igu_fifo_addr_data[j].end_addr) - addr_data = &s_igu_fifo_addr_data[j]; - if (!addr_data) - return DBG_STATUS_IGU_FIFO_BAD_DATA; - - /* Prepare parsed address data */ - switch (addr_data->type) { - case IGU_ADDR_TYPE_MSIX_MEM: - sprintf(parsed_addr_data, - " vector_num=0x%x", cmd_addr / 2); - break; - case IGU_ADDR_TYPE_WRITE_INT_ACK: - case IGU_ADDR_TYPE_WRITE_PROD_UPDATE: - sprintf(parsed_addr_data, - " SB=0x%x", cmd_addr - addr_data->start_addr); - break; - default: - parsed_addr_data[0] = '\0'; - } - - /* Prepare parsed write data */ - if (is_wr_cmd) { - u32 wr_data = GET_FIELD(dword12, - IGU_FIFO_ELEMENT_DWORD12_WR_DATA); - u32 prod_cons = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_PROD_CONS); - u8 is_cleanup = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_CMD_TYPE); - - if (source == IGU_SRC_ATTN) { - sprintf(parsed_wr_data, - "prod: 0x%x, ", prod_cons); - } else { - if (is_cleanup) { - u8 cleanup_val = GET_FIELD(wr_data, - IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_VAL); - u8 cleanup_type = GET_FIELD(wr_data, - IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_TYPE); - - sprintf(parsed_wr_data, - "cmd_type: cleanup, cleanup_val: %s, cleanup_type: %d, ", - cleanup_val ? "set" : "clear", - cleanup_type); - } else { - u8 update_flag = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_UPDATE_FLAG); - u8 en_dis_int_for_sb = - GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_EN_DIS_INT_FOR_SB); - u8 segment = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_SEGMENT); - u8 timer_mask = GET_FIELD(wr_data, - IGU_FIFO_WR_DATA_TIMER_MASK); - - sprintf(parsed_wr_data, - "cmd_type: prod/cons update, prod/cons: 0x%x, update_flag: %s, en_dis_int_for_sb: %s, segment: %s, timer_mask=%d, ", - prod_cons, - update_flag ? "update" : "nop", - en_dis_int_for_sb - ? (en_dis_int_for_sb == - 1 ? "disable" : "nop") : - "enable", - segment ? "attn" : "regular", - timer_mask); - } - } - } else { - parsed_wr_data[0] = '\0'; - } - - /* Add parsed element to parsed buffer */ - results_offset += - sprintf(qed_get_buf_ptr(results_buf, - results_offset), - "raw: 0x%01x%08x%08x, %s: %d, source: %s, type: %s, cmd_addr: 0x%x (%s%s), %serror: %s\n", - elements[i].dword2, elements[i].dword1, - elements[i].dword0, - is_pf ? "pf" : "vf", - GET_FIELD(elements[i].dword0, - IGU_FIFO_ELEMENT_DWORD0_FID), - s_igu_fifo_source_strs[source], - is_wr_cmd ? "wr" : "rd", cmd_addr, - (!is_pf && addr_data->vf_desc) - ? addr_data->vf_desc : addr_data->desc, - parsed_addr_data, parsed_wr_data, - s_igu_fifo_error_strs[err_type]); + status = qed_parse_igu_fifo_element(&elements[i], + results_buf, + &results_offset, + parsed_results_bytes); + if (status != DBG_STATUS_OK) + return status; } results_offset += sprintf(qed_get_buf_ptr(results_buf, @@ -6418,31 +6855,8 @@ static enum dbg_status qed_parse_igu_fifo_dump(struct qed_hwfn *p_hwfn, /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; - return DBG_STATUS_OK; -} - -enum dbg_status qed_get_igu_fifo_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) -{ - return qed_parse_igu_fifo_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, results_buf_size); -} - -enum dbg_status qed_print_igu_fifo_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf) -{ - u32 parsed_buf_size; - return qed_parse_igu_fifo_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, &parsed_buf_size); + return DBG_STATUS_OK; } static enum dbg_status @@ -6452,9 +6866,10 @@ qed_parse_protection_override_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, param_num_val, num_section_params, num_elements; const char *section_name, *param_name, *param_str_val; + u32 param_num_val, num_section_params, num_elements; struct protection_override_element *elements; + u32 results_offset = 0; u8 i; /* Read global_params section */ @@ -6477,7 +6892,7 @@ qed_parse_protection_override_dump(struct qed_hwfn *p_hwfn, ¶m_name, ¶m_str_val, ¶m_num_val); if (strcmp(param_name, "size")) return DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA; - if (param_num_val % PROTECTION_OVERRIDE_ELEMENT_DWORDS != 0) + if (param_num_val % PROTECTION_OVERRIDE_ELEMENT_DWORDS) return DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA; num_elements = param_num_val / PROTECTION_OVERRIDE_ELEMENT_DWORDS; elements = (struct protection_override_element *)dump_buf; @@ -6486,7 +6901,7 @@ qed_parse_protection_override_dump(struct qed_hwfn *p_hwfn, for (i = 0; i < num_elements; i++) { u32 address = GET_FIELD(elements[i].data, PROTECTION_OVERRIDE_ELEMENT_ADDRESS) * - PROTECTION_OVERRIDE_ELEMENT_ADDR_FACTOR; + PROTECTION_OVERRIDE_ELEMENT_ADDR_FACTOR; results_offset += sprintf(qed_get_buf_ptr(results_buf, @@ -6512,33 +6927,8 @@ qed_parse_protection_override_dump(struct qed_hwfn *p_hwfn, /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; - return DBG_STATUS_OK; -} - -enum dbg_status -qed_get_protection_override_results_buf_size(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - u32 *results_buf_size) -{ - return qed_parse_protection_override_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - NULL, results_buf_size); -} -enum dbg_status qed_print_protection_override_results(struct qed_hwfn *p_hwfn, - u32 *dump_buf, - u32 num_dumped_dwords, - char *results_buf) -{ - u32 parsed_buf_size; - - return qed_parse_protection_override_dump(p_hwfn, - dump_buf, - num_dumped_dwords, - results_buf, - &parsed_buf_size); + return DBG_STATUS_OK; } /* Parses a FW Asserts dump buffer. @@ -6553,7 +6943,7 @@ static enum dbg_status qed_parse_fw_asserts_dump(struct qed_hwfn *p_hwfn, char *results_buf, u32 *parsed_results_bytes) { - u32 results_offset = 0, num_section_params, param_num_val, i; + u32 num_section_params, param_num_val, i, results_offset = 0; const char *param_name, *param_str_val, *section_name; bool last_section_found = false; @@ -6569,54 +6959,216 @@ static enum dbg_status qed_parse_fw_asserts_dump(struct qed_hwfn *p_hwfn, dump_buf += qed_print_section_params(dump_buf, num_section_params, results_buf, &results_offset); - while (!last_section_found) { - const char *storm_letter = NULL; - u32 storm_dump_size = 0; + while (!last_section_found) { dump_buf += qed_read_section_hdr(dump_buf, §ion_name, &num_section_params); - if (!strcmp(section_name, "last")) { - last_section_found = true; - continue; - } else if (strcmp(section_name, "fw_asserts")) { - return DBG_STATUS_FW_ASSERTS_PARSE_FAILED; - } + if (!strcmp(section_name, "fw_asserts")) { + /* Extract params */ + const char *storm_letter = NULL; + u32 storm_dump_size = 0; + + for (i = 0; i < num_section_params; i++) { + dump_buf += qed_read_param(dump_buf, + ¶m_name, + ¶m_str_val, + ¶m_num_val); + if (!strcmp(param_name, "storm")) + storm_letter = param_str_val; + else if (!strcmp(param_name, "size")) + storm_dump_size = param_num_val; + else + return + DBG_STATUS_FW_ASSERTS_PARSE_FAILED; + } - /* Extract params */ - for (i = 0; i < num_section_params; i++) { - dump_buf += qed_read_param(dump_buf, - ¶m_name, - ¶m_str_val, - ¶m_num_val); - if (!strcmp(param_name, "storm")) - storm_letter = param_str_val; - else if (!strcmp(param_name, "size")) - storm_dump_size = param_num_val; - else + if (!storm_letter || !storm_dump_size) return DBG_STATUS_FW_ASSERTS_PARSE_FAILED; - } - - if (!storm_letter || !storm_dump_size) - return DBG_STATUS_FW_ASSERTS_PARSE_FAILED; - /* Print data */ - results_offset += sprintf(qed_get_buf_ptr(results_buf, - results_offset), - "\n%sSTORM_ASSERT: size=%d\n", - storm_letter, storm_dump_size); - for (i = 0; i < storm_dump_size; i++, dump_buf++) + /* Print data */ results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), - "%08x\n", *dump_buf); + "\n%sSTORM_ASSERT: size=%d\n", + storm_letter, storm_dump_size); + for (i = 0; i < storm_dump_size; i++, dump_buf++) + results_offset += + sprintf(qed_get_buf_ptr(results_buf, + results_offset), + "%08x\n", *dump_buf); + } else if (!strcmp(section_name, "last")) { + last_section_found = true; + } else { + return DBG_STATUS_FW_ASSERTS_PARSE_FAILED; + } } /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; + + return DBG_STATUS_OK; +} + +/***************************** Public Functions *******************************/ + +enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr) +{ + struct bin_buffer_hdr *buf_array = (struct bin_buffer_hdr *)bin_ptr; + u8 buf_id; + + /* Convert binary data to debug arrays */ + for (buf_id = 0; buf_id < MAX_BIN_DBG_BUFFER_TYPE; buf_id++) { + s_user_dbg_arrays[buf_id].ptr = + (u32 *)(bin_ptr + buf_array[buf_id].offset); + s_user_dbg_arrays[buf_id].size_in_dwords = + BYTES_TO_DWORDS(buf_array[buf_id].length); + } + return DBG_STATUS_OK; } +const char *qed_dbg_get_status_str(enum dbg_status status) +{ + return (status < + MAX_DBG_STATUS) ? s_status_str[status] : "Invalid debug status"; +} + +enum dbg_status qed_get_idle_chk_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + u32 num_errors, num_warnings; + + return qed_parse_idle_chk_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, + results_buf_size, + &num_errors, &num_warnings); +} + +enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf, + u32 *num_errors, u32 *num_warnings) +{ + u32 parsed_buf_size; + + return qed_parse_idle_chk_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, + &parsed_buf_size, + num_errors, num_warnings); +} + +void qed_dbg_mcp_trace_set_meta_data(u32 *data, u32 size) +{ + s_mcp_trace_meta.ptr = data; + s_mcp_trace_meta.size_in_dwords = size; +} + +enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + return qed_parse_mcp_trace_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, results_buf_size); +} + +enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf) +{ + u32 parsed_buf_size; + + return qed_parse_mcp_trace_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, &parsed_buf_size); +} + +enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + return qed_parse_reg_fifo_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, results_buf_size); +} + +enum dbg_status qed_print_reg_fifo_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf) +{ + u32 parsed_buf_size; + + return qed_parse_reg_fifo_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, &parsed_buf_size); +} + +enum dbg_status qed_get_igu_fifo_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + return qed_parse_igu_fifo_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, results_buf_size); +} + +enum dbg_status qed_print_igu_fifo_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf) +{ + u32 parsed_buf_size; + + return qed_parse_igu_fifo_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, &parsed_buf_size); +} + +enum dbg_status +qed_get_protection_override_results_buf_size(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + u32 *results_buf_size) +{ + return qed_parse_protection_override_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + NULL, results_buf_size); +} + +enum dbg_status qed_print_protection_override_results(struct qed_hwfn *p_hwfn, + u32 *dump_buf, + u32 num_dumped_dwords, + char *results_buf) +{ + u32 parsed_buf_size; + + return qed_parse_protection_override_dump(p_hwfn, + dump_buf, + num_dumped_dwords, + results_buf, + &parsed_buf_size); +} + enum dbg_status qed_get_fw_asserts_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.h b/drivers/net/ethernet/qlogic/qed/qed_debug.h index f872d7324814..ea1cc8eaa125 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.h +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.h @@ -20,6 +20,9 @@ enum qed_dbg_features { DBG_FEATURE_NUM }; +/* Forward Declaration */ +struct qed_dev; + int qed_dbg_grc(struct qed_dev *cdev, void *buffer, u32 *num_dumped_bytes); int qed_dbg_grc_size(struct qed_dev *cdev); int qed_dbg_idle_chk(struct qed_dev *cdev, void *buffer, diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 858a57a73589..eedf79a026a2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -346,7 +346,7 @@ struct xstorm_core_conn_ag_ctx { u8 byte13; u8 byte14; u8 byte15; - u8 byte16; + u8 e5_reserved; __le16 word11; __le32 reg10; __le32 reg11; @@ -368,85 +368,85 @@ struct tstorm_core_conn_ag_ctx { u8 byte0; u8 byte1; u8 flags0; -#define TSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 -#define TSTORM_CORE_CONN_AG_CTX_BIT2_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT2_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_BIT3_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT3_SHIFT 3 -#define TSTORM_CORE_CONN_AG_CTX_BIT4_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT4_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_BIT5_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_BIT5_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_BIT2_MASK 0x1 /* bit2 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_BIT3_MASK 0x1 /* bit3 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_BIT4_MASK 0x1 /* bit4 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_BIT5_MASK 0x1 /* bit5 */ +#define TSTORM_CORE_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ +#define TSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 6 u8 flags1; -#define TSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ +#define TSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ +#define TSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 /* timer_stop_all */ +#define TSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ +#define TSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 6 u8 flags2; -#define TSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ +#define TSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ +#define TSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ +#define TSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ +#define TSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 6 u8 flags3; -#define TSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 -#define TSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 6 -#define TSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 7 +#define TSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ +#define TSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ +#define TSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ +#define TSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ +#define TSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ +#define TSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ +#define TSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 7 u8 flags4; -#define TSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 1 -#define TSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 3 -#define TSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 6 -#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 +#define TSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ +#define TSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ +#define TSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ +#define TSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ +#define TSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ +#define TSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ +#define TSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ +#define TSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 u8 flags5; -#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 -#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 -#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 -#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 -#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 +#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ +#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 __le32 reg0; __le32 reg1; __le32 reg2; @@ -681,7 +681,9 @@ struct core_rx_fast_path_cqe { __le16 packet_length; __le16 vlan; struct core_rx_cqe_opaque_data opaque_data; - __le32 reserved[4]; + struct parsing_err_flags err_flags; + __le16 reserved0; + __le32 reserved1[3]; }; struct core_rx_gsi_offload_cqe { @@ -692,7 +694,7 @@ struct core_rx_gsi_offload_cqe { __le16 vlan; __le32 src_mac_addrhi; __le16 src_mac_addrlo; - u8 reserved1[2]; + __le16 qp_id; __le32 gid_dst[4]; }; @@ -774,15 +776,15 @@ struct core_tx_bd { __le16 bitfield1; #define CORE_TX_BD_L4_HDR_OFFSET_W_MASK 0x3FFF #define CORE_TX_BD_L4_HDR_OFFSET_W_SHIFT 0 -#define CORE_TX_BD_TX_DST_MASK 0x1 -#define CORE_TX_BD_TX_DST_SHIFT 14 -#define CORE_TX_BD_RESERVED_MASK 0x1 -#define CORE_TX_BD_RESERVED_SHIFT 15 +#define CORE_TX_BD_TX_DST_MASK 0x3 +#define CORE_TX_BD_TX_DST_SHIFT 14 }; enum core_tx_dest { CORE_TX_DEST_NW, CORE_TX_DEST_LB, + CORE_TX_DEST_RESERVED, + CORE_TX_DEST_DROP, MAX_CORE_TX_DEST }; @@ -804,12 +806,12 @@ struct core_tx_stop_ramrod_data { __le32 reserved0[2]; }; -enum dcb_dhcp_update_flag { - DONT_UPDATE_DCB_DHCP, +enum dcb_dscp_update_mode { + DONT_UPDATE_DCB_DSCP, UPDATE_DCB, UPDATE_DSCP, UPDATE_DCB_DSCP, - MAX_DCB_DHCP_UPDATE_FLAG + MAX_DCB_DSCP_UPDATE_MODE }; struct eth_mstorm_per_pf_stat { @@ -917,6 +919,14 @@ struct hsi_fp_ver_struct { u8 major_ver_arr[2]; }; +enum iwarp_ll2_tx_queues { + IWARP_LL2_IN_ORDER_TX_QUEUE = 1, + IWARP_LL2_ALIGNED_TX_QUEUE, + IWARP_LL2_ALIGNED_RIGHT_TRIMMED_TX_QUEUE, + IWARP_LL2_ERROR, + MAX_IWARP_LL2_TX_QUEUES +}; + /* Mstorm non-triggering VF zone */ enum malicious_vf_error_id { MALICIOUS_VF_NO_ERROR, @@ -960,7 +970,7 @@ enum personality_type { PERSONALITY_ISCSI, PERSONALITY_FCOE, PERSONALITY_RDMA_AND_ETH, - PERSONALITY_RESERVED3, + PERSONALITY_RDMA, PERSONALITY_CORE, PERSONALITY_ETH, PERSONALITY_RESERVED4, @@ -971,16 +981,12 @@ enum personality_type { struct pf_start_tunnel_config { u8 set_vxlan_udp_port_flg; u8 set_geneve_udp_port_flg; - u8 tx_enable_vxlan; - u8 tx_enable_l2geneve; - u8 tx_enable_ipgeneve; - u8 tx_enable_l2gre; - u8 tx_enable_ipgre; u8 tunnel_clss_vxlan; u8 tunnel_clss_l2geneve; u8 tunnel_clss_ipgeneve; u8 tunnel_clss_l2gre; u8 tunnel_clss_ipgre; + u8 reserved; __le16 vxlan_udp_port; __le16 geneve_udp_port; }; @@ -990,6 +996,7 @@ struct pf_start_ramrod_data { struct regpair event_ring_pbl_addr; struct regpair consolid_q_pbl_addr; struct pf_start_tunnel_config tunnel_config; + __le32 reserved; __le16 event_ring_sb_id; u8 base_vf_id; u8 num_vfs; @@ -1007,7 +1014,6 @@ struct pf_start_ramrod_data { u8 pri_map_valid; __le32 outer_tag; struct hsi_fp_ver_struct hsi_fp_ver; - }; struct protocol_dcb_data { @@ -1023,14 +1029,8 @@ struct pf_update_tunnel_config { u8 update_rx_pf_clss; u8 update_rx_def_ucast_clss; u8 update_rx_def_non_ucast_clss; - u8 update_tx_pf_clss; u8 set_vxlan_udp_port_flg; u8 set_geneve_udp_port_flg; - u8 tx_enable_vxlan; - u8 tx_enable_l2geneve; - u8 tx_enable_ipgeneve; - u8 tx_enable_l2gre; - u8 tx_enable_ipgre; u8 tunnel_clss_vxlan; u8 tunnel_clss_l2geneve; u8 tunnel_clss_ipgeneve; @@ -1038,17 +1038,17 @@ struct pf_update_tunnel_config { u8 tunnel_clss_ipgre; __le16 vxlan_udp_port; __le16 geneve_udp_port; - __le16 reserved[2]; + __le16 reserved; }; struct pf_update_ramrod_data { u8 pf_id; - u8 update_eth_dcb_data_flag; - u8 update_fcoe_dcb_data_flag; - u8 update_iscsi_dcb_data_flag; - u8 update_roce_dcb_data_flag; - u8 update_rroce_dcb_data_flag; - u8 update_iwarp_dcb_data_flag; + u8 update_eth_dcb_data_mode; + u8 update_fcoe_dcb_data_mode; + u8 update_iscsi_dcb_data_mode; + u8 update_roce_dcb_data_mode; + u8 update_rroce_dcb_data_mode; + u8 update_iwarp_dcb_data_mode; u8 update_mf_vlan_flag; struct protocol_dcb_data eth_dcb_data; struct protocol_dcb_data fcoe_dcb_data; @@ -1127,7 +1127,7 @@ struct tstorm_per_port_stat { struct regpair iscsi_irregular_pkt; struct regpair fcoe_irregular_pkt; struct regpair roce_irregular_pkt; - struct regpair reserved; + struct regpair iwarp_irregular_pkt; struct regpair eth_irregular_pkt; struct regpair reserved1; struct regpair preroce_irregular_pkt; @@ -1326,6 +1326,87 @@ enum dmae_cmd_src_enum { MAX_DMAE_CMD_SRC_ENUM }; +struct mstorm_core_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define MSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define MSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; +}; + +struct ystorm_core_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define YSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 +#define YSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 +#define YSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le32 reg0; + __le32 reg1; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; +}; + /* IGU cleanup command */ struct igu_cleanup { __le32 sb_id_and_flags; @@ -1389,44 +1470,6 @@ struct igu_msix_vector { #define IGU_MSIX_VECTOR_RESERVED1_MASK 0xFF #define IGU_MSIX_VECTOR_RESERVED1_SHIFT 24 }; - -struct mstorm_core_conn_ag_ctx { - u8 byte0; - u8 byte1; - u8 flags0; -#define MSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 -#define MSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 -#define MSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 -#define MSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 -#define MSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 -#define MSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 -#define MSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 -#define MSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 - u8 flags1; -#define MSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 -#define MSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 -#define MSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 -#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 -#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 -#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 -#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 -#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 - __le16 word0; - __le16 word1; - __le32 reg0; - __le32 reg1; -}; - /* per encapsulation type enabling flags */ struct prs_reg_encapsulation_type_en { u8 flags; @@ -1541,50 +1584,6 @@ struct sdm_op_gen { #define SDM_OP_GEN_RESERVED_SHIFT 20 }; -struct ystorm_core_conn_ag_ctx { - u8 byte0; - u8 byte1; - u8 flags0; -#define YSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 -#define YSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 -#define YSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 -#define YSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 -#define YSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 -#define YSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 -#define YSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 -#define YSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 - u8 flags1; -#define YSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 -#define YSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 -#define YSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 -#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 -#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 -#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 -#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 -#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 - u8 byte2; - u8 byte3; - __le16 word0; - __le32 reg0; - __le32 reg1; - __le16 word1; - __le16 word2; - __le16 word3; - __le16 word4; - __le32 reg2; - __le32 reg3; -}; - /****************************************/ /* Debug Tools HSI constants and macros */ /****************************************/ @@ -1643,6 +1642,8 @@ enum block_addr { GRCBASE_MULD = 0x4e0000, GRCBASE_YULD = 0x4c8000, GRCBASE_XYLD = 0x4c0000, + GRCBASE_PTLD = 0x590000, + GRCBASE_YPLD = 0x5b0000, GRCBASE_PRM = 0x230000, GRCBASE_PBF_PB1 = 0xda0000, GRCBASE_PBF_PB2 = 0xda4000, @@ -1656,6 +1657,10 @@ enum block_addr { GRCBASE_TCFC = 0x2d0000, GRCBASE_IGU = 0x180000, GRCBASE_CAU = 0x1c0000, + GRCBASE_RGFS = 0xf00000, + GRCBASE_RGSRC = 0x320000, + GRCBASE_TGFS = 0xd00000, + GRCBASE_TGSRC = 0x322000, GRCBASE_UMAC = 0x51000, GRCBASE_XMAC = 0x210000, GRCBASE_DBG = 0x10000, @@ -1669,10 +1674,6 @@ enum block_addr { GRCBASE_PHY_PCIE = 0x620000, GRCBASE_LED = 0x6b8000, GRCBASE_AVS_WRAP = 0x6b0000, - GRCBASE_RGFS = 0x19d0000, - GRCBASE_TGFS = 0x19e0000, - GRCBASE_PTLD = 0x19f0000, - GRCBASE_YPLD = 0x1a10000, GRCBASE_MISC_AEU = 0x8000, GRCBASE_BAR0_MAP = 0x1c00000, MAX_BLOCK_ADDR @@ -1732,6 +1733,8 @@ enum block_id { BLOCK_MULD, BLOCK_YULD, BLOCK_XYLD, + BLOCK_PTLD, + BLOCK_YPLD, BLOCK_PRM, BLOCK_PBF_PB1, BLOCK_PBF_PB2, @@ -1745,6 +1748,10 @@ enum block_id { BLOCK_TCFC, BLOCK_IGU, BLOCK_CAU, + BLOCK_RGFS, + BLOCK_RGSRC, + BLOCK_TGFS, + BLOCK_TGSRC, BLOCK_UMAC, BLOCK_XMAC, BLOCK_DBG, @@ -1758,10 +1765,6 @@ enum block_id { BLOCK_PHY_PCIE, BLOCK_LED, BLOCK_AVS_WRAP, - BLOCK_RGFS, - BLOCK_TGFS, - BLOCK_PTLD, - BLOCK_YPLD, BLOCK_MISC_AEU, BLOCK_BAR0_MAP, MAX_BLOCK_ID @@ -1780,6 +1783,10 @@ enum bin_dbg_buffer_type { BIN_BUF_DBG_ATTN_REGS, BIN_BUF_DBG_ATTN_INDEXES, BIN_BUF_DBG_ATTN_NAME_OFFSETS, + BIN_BUF_DBG_BUS_BLOCKS, + BIN_BUF_DBG_BUS_LINES, + BIN_BUF_DBG_BUS_BLOCKS_USER_DATA, + BIN_BUF_DBG_BUS_LINE_NAME_OFFSETS, BIN_BUF_DBG_PARSING_STRINGS, MAX_BIN_DBG_BUFFER_TYPE }; @@ -1862,6 +1869,29 @@ enum dbg_attn_type { MAX_DBG_ATTN_TYPE }; +struct dbg_bus_block { + u8 num_of_lines; + u8 has_latency_events; + __le16 lines_offset; +}; + +struct dbg_bus_block_user_data { + u8 num_of_lines; + u8 has_latency_events; + __le16 names_offset; +}; + +struct dbg_bus_line { + u8 data; +#define DBG_BUS_LINE_NUM_OF_GROUPS_MASK 0xF +#define DBG_BUS_LINE_NUM_OF_GROUPS_SHIFT 0 +#define DBG_BUS_LINE_IS_256B_MASK 0x1 +#define DBG_BUS_LINE_IS_256B_SHIFT 4 +#define DBG_BUS_LINE_RESERVED_MASK 0x7 +#define DBG_BUS_LINE_RESERVED_SHIFT 5 + u8 group_sizes; +}; + /* condition header for registers dump */ struct dbg_dump_cond_hdr { struct dbg_mode_hdr mode; /* Mode header */ @@ -1879,17 +1909,21 @@ struct dbg_dump_mem { __le32 dword1; #define DBG_DUMP_MEM_LENGTH_MASK 0xFFFFFF #define DBG_DUMP_MEM_LENGTH_SHIFT 0 -#define DBG_DUMP_MEM_RESERVED_MASK 0xFF -#define DBG_DUMP_MEM_RESERVED_SHIFT 24 +#define DBG_DUMP_MEM_WIDE_BUS_MASK 0x1 +#define DBG_DUMP_MEM_WIDE_BUS_SHIFT 24 +#define DBG_DUMP_MEM_RESERVED_MASK 0x7F +#define DBG_DUMP_MEM_RESERVED_SHIFT 25 }; /* register data for registers dump */ struct dbg_dump_reg { __le32 data; -#define DBG_DUMP_REG_ADDRESS_MASK 0xFFFFFF /* register address (in dwords) */ +#define DBG_DUMP_REG_ADDRESS_MASK 0x7FFFFF /* register address (in dwords) */ #define DBG_DUMP_REG_ADDRESS_SHIFT 0 -#define DBG_DUMP_REG_LENGTH_MASK 0xFF /* register size (in dwords) */ -#define DBG_DUMP_REG_LENGTH_SHIFT 24 +#define DBG_DUMP_REG_WIDE_BUS_MASK 0x1 /* indicates register is wide-bus */ +#define DBG_DUMP_REG_WIDE_BUS_SHIFT 23 +#define DBG_DUMP_REG_LENGTH_MASK 0xFF /* register size (in dwords) */ +#define DBG_DUMP_REG_LENGTH_SHIFT 24 }; /* split header for registers dump */ @@ -1910,20 +1944,24 @@ struct dbg_idle_chk_cond_hdr { /* Idle Check condition register */ struct dbg_idle_chk_cond_reg { __le32 data; -#define DBG_IDLE_CHK_COND_REG_ADDRESS_MASK 0xFFFFFF +#define DBG_IDLE_CHK_COND_REG_ADDRESS_MASK 0x7FFFFF #define DBG_IDLE_CHK_COND_REG_ADDRESS_SHIFT 0 +#define DBG_IDLE_CHK_COND_REG_WIDE_BUS_MASK 0x1 +#define DBG_IDLE_CHK_COND_REG_WIDE_BUS_SHIFT 23 #define DBG_IDLE_CHK_COND_REG_BLOCK_ID_MASK 0xFF #define DBG_IDLE_CHK_COND_REG_BLOCK_ID_SHIFT 24 - __le16 num_entries; /* number of registers entries to check */ - u8 entry_size; /* size of registers entry (in dwords) */ - u8 start_entry; /* index of the first entry to check */ + __le16 num_entries; + u8 entry_size; + u8 start_entry; }; /* Idle Check info register */ struct dbg_idle_chk_info_reg { __le32 data; -#define DBG_IDLE_CHK_INFO_REG_ADDRESS_MASK 0xFFFFFF +#define DBG_IDLE_CHK_INFO_REG_ADDRESS_MASK 0x7FFFFF #define DBG_IDLE_CHK_INFO_REG_ADDRESS_SHIFT 0 +#define DBG_IDLE_CHK_INFO_REG_WIDE_BUS_MASK 0x1 +#define DBG_IDLE_CHK_INFO_REG_WIDE_BUS_SHIFT 23 #define DBG_IDLE_CHK_INFO_REG_BLOCK_ID_MASK 0xFF #define DBG_IDLE_CHK_INFO_REG_BLOCK_ID_SHIFT 24 __le16 size; /* register size in dwords */ @@ -1996,15 +2034,17 @@ enum dbg_idle_chk_severity_types { /* Debug Bus block data */ struct dbg_bus_block_data { - u8 enabled; /* Indicates if the block is enabled for recording (0/1) */ - u8 hw_id; /* HW ID associated with the block */ - u8 line_num; /* Debug line number to select */ - u8 right_shift; /* Number of units to right the debug data (0-3) */ - u8 cycle_en; /* 4-bit value: bit i set -> unit i is enabled. */ - u8 force_valid; /* 4-bit value: bit i set -> unit i is forced valid. */ - u8 force_frame; /* 4-bit value: bit i set -> unit i frame bit is forced. - */ - u8 reserved; + __le16 data; +#define DBG_BUS_BLOCK_DATA_ENABLE_MASK_MASK 0xF +#define DBG_BUS_BLOCK_DATA_ENABLE_MASK_SHIFT 0 +#define DBG_BUS_BLOCK_DATA_RIGHT_SHIFT_MASK 0xF +#define DBG_BUS_BLOCK_DATA_RIGHT_SHIFT_SHIFT 4 +#define DBG_BUS_BLOCK_DATA_FORCE_VALID_MASK_MASK 0xF +#define DBG_BUS_BLOCK_DATA_FORCE_VALID_MASK_SHIFT 8 +#define DBG_BUS_BLOCK_DATA_FORCE_FRAME_MASK_MASK 0xF +#define DBG_BUS_BLOCK_DATA_FORCE_FRAME_MASK_SHIFT 12 + u8 line_num; + u8 hw_id; }; /* Debug Bus Clients */ @@ -2045,6 +2085,14 @@ enum dbg_bus_constraint_ops { MAX_DBG_BUS_CONSTRAINT_OPS }; +struct dbg_bus_trigger_state_data { + u8 data; +#define DBG_BUS_TRIGGER_STATE_DATA_BLOCK_SHIFTED_ENABLE_MASK_MASK 0xF +#define DBG_BUS_TRIGGER_STATE_DATA_BLOCK_SHIFTED_ENABLE_MASK_SHIFT 0 +#define DBG_BUS_TRIGGER_STATE_DATA_CONSTRAINT_DWORD_MASK_MASK 0xF +#define DBG_BUS_TRIGGER_STATE_DATA_CONSTRAINT_DWORD_MASK_SHIFT 4 +}; + /* Debug Bus memory address */ struct dbg_bus_mem_addr { __le32 lo; @@ -2078,66 +2126,42 @@ union dbg_bus_storm_eid_params { /* Debug Bus Storm data */ struct dbg_bus_storm_data { - u8 fast_enabled; - u8 fast_mode; - u8 slow_enabled; - u8 slow_mode; + u8 enabled; + u8 mode; u8 hw_id; u8 eid_filter_en; u8 eid_range_not_mask; u8 cid_filter_en; union dbg_bus_storm_eid_params eid_filter_params; - __le16 reserved; __le32 cid; }; /* Debug Bus data */ struct dbg_bus_data { - __le32 app_version; /* The tools version number of the application */ - u8 state; /* The current debug bus state */ - u8 hw_dwords; /* HW dwords per cycle */ - u8 next_hw_id; /* Next HW ID to be associated with an input */ - u8 num_enabled_blocks; /* Number of blocks enabled for recording */ - u8 num_enabled_storms; /* Number of Storms enabled for recording */ - u8 target; /* Output target */ - u8 next_trigger_state; /* ID of next trigger state to be added */ - u8 next_constraint_id; /* ID of next filter/trigger constraint to be - * added. - */ - u8 one_shot_en; /* Indicates if one-shot mode is enabled (0/1) */ - u8 grc_input_en; /* Indicates if GRC recording is enabled (0/1) */ - u8 timestamp_input_en; /* Indicates if timestamp recording is enabled - * (0/1). - */ - u8 filter_en; /* Indicates if the recording filter is enabled (0/1) */ - u8 trigger_en; /* Indicates if the recording trigger is enabled (0/1) */ - u8 adding_filter; /* If true, the next added constraint belong to the - * filter. Otherwise, it belongs to the last added - * trigger state. Valid only if either filter or - * triggers are enabled. - */ - u8 filter_pre_trigger; /* Indicates if the recording filter should be - * applied before the trigger. Valid only if both - * filter and trigger are enabled (0/1). - */ - u8 filter_post_trigger; /* Indicates if the recording filter should be - * applied after the trigger. Valid only if both - * filter and trigger are enabled (0/1). - */ - u8 unify_inputs; /* If true, all inputs are associated with HW ID 0. - * Otherwise, each input is assigned a different HW ID - * (0/1). - */ - u8 rcv_from_other_engine; /* Indicates if the other engine sends it NW - * recording to this engine (0/1). - */ - struct dbg_bus_pci_buf_data pci_buf; /* Debug Bus PCI buffer data. Valid - * only when the target is - * DBG_BUS_TARGET_ID_PCI. - */ + __le32 app_version; + u8 state; + u8 hw_dwords; + __le16 hw_id_mask; + u8 num_enabled_blocks; + u8 num_enabled_storms; + u8 target; + u8 one_shot_en; + u8 grc_input_en; + u8 timestamp_input_en; + u8 filter_en; + u8 adding_filter; + u8 filter_pre_trigger; + u8 filter_post_trigger; __le16 reserved; - struct dbg_bus_block_data blocks[88];/* Debug Bus data for each block */ - struct dbg_bus_storm_data storms[6]; /* Debug Bus data for each block */ + u8 trigger_en; + struct dbg_bus_trigger_state_data trigger_states[3]; + u8 next_trigger_state; + u8 next_constraint_id; + u8 unify_inputs; + u8 rcv_from_other_engine; + struct dbg_bus_pci_buf_data pci_buf; + struct dbg_bus_block_data blocks[88]; + struct dbg_bus_storm_data storms[6]; }; enum dbg_bus_filter_types { @@ -2156,12 +2180,6 @@ enum dbg_bus_frame_modes { MAX_DBG_BUS_FRAME_MODES }; -enum dbg_bus_input_types { - DBG_BUS_INPUT_TYPE_STORM, - DBG_BUS_INPUT_TYPE_BLOCK, - MAX_DBG_BUS_INPUT_TYPES -}; - enum dbg_bus_other_engine_modes { DBG_BUS_OTHER_ENGINE_MODE_NONE, DBG_BUS_OTHER_ENGINE_MODE_DOUBLE_BW_TX, @@ -2185,19 +2203,19 @@ enum dbg_bus_pre_trigger_types { }; enum dbg_bus_semi_frame_modes { - DBG_BUS_SEMI_FRAME_MODE_0SLOW_4FAST = 0, - DBG_BUS_SEMI_FRAME_MODE_4SLOW_0FAST = 3, + DBG_BUS_SEMI_FRAME_MODE_0SLOW_4FAST = + 0, + DBG_BUS_SEMI_FRAME_MODE_4SLOW_0FAST = + 3, MAX_DBG_BUS_SEMI_FRAME_MODES }; /* Debug bus states */ enum dbg_bus_states { - DBG_BUS_STATE_IDLE, /* debug bus idle state (not recording) */ - DBG_BUS_STATE_READY, /* debug bus is ready for configuration and - * recording. - */ - DBG_BUS_STATE_RECORDING, /* debug bus is currently recording */ - DBG_BUS_STATE_STOPPED, /* debug bus recording has stopped */ + DBG_BUS_STATE_IDLE, + DBG_BUS_STATE_READY, + DBG_BUS_STATE_RECORDING, + DBG_BUS_STATE_STOPPED, MAX_DBG_BUS_STATES }; @@ -2216,11 +2234,8 @@ enum dbg_bus_storm_modes { /* Debug bus target IDs */ enum dbg_bus_targets { - /* records debug bus to DBG block internal buffer */ DBG_BUS_TARGET_ID_INT_BUF, - /* records debug bus to the NW */ DBG_BUS_TARGET_ID_NIG, - /* records debug bus to a PCI buffer */ DBG_BUS_TARGET_ID_PCI, MAX_DBG_BUS_TARGETS }; @@ -2235,48 +2250,45 @@ struct dbg_grc_data { /* Debug GRC params */ enum dbg_grc_params { - DBG_GRC_PARAM_DUMP_TSTORM, /* dump Tstorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_MSTORM, /* dump Mstorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_USTORM, /* dump Ustorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_XSTORM, /* dump Xstorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_YSTORM, /* dump Ystorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_PSTORM, /* dump Pstorm memories (0/1) */ - DBG_GRC_PARAM_DUMP_REGS, /* dump non-memory registers (0/1) */ - DBG_GRC_PARAM_DUMP_RAM, /* dump Storm internal RAMs (0/1) */ - DBG_GRC_PARAM_DUMP_PBUF, /* dump Storm passive buffer (0/1) */ - DBG_GRC_PARAM_DUMP_IOR, /* dump Storm IORs (0/1) */ - DBG_GRC_PARAM_DUMP_VFC, /* dump VFC memories (0/1) */ - DBG_GRC_PARAM_DUMP_CM_CTX, /* dump CM contexts (0/1) */ - DBG_GRC_PARAM_DUMP_PXP, /* dump PXP memories (0/1) */ - DBG_GRC_PARAM_DUMP_RSS, /* dump RSS memories (0/1) */ - DBG_GRC_PARAM_DUMP_CAU, /* dump CAU memories (0/1) */ - DBG_GRC_PARAM_DUMP_QM, /* dump QM memories (0/1) */ - DBG_GRC_PARAM_DUMP_MCP, /* dump MCP memories (0/1) */ - DBG_GRC_PARAM_RESERVED, /* reserved */ - DBG_GRC_PARAM_DUMP_CFC, /* dump CFC memories (0/1) */ - DBG_GRC_PARAM_DUMP_IGU, /* dump IGU memories (0/1) */ - DBG_GRC_PARAM_DUMP_BRB, /* dump BRB memories (0/1) */ - DBG_GRC_PARAM_DUMP_BTB, /* dump BTB memories (0/1) */ - DBG_GRC_PARAM_DUMP_BMB, /* dump BMB memories (0/1) */ - DBG_GRC_PARAM_DUMP_NIG, /* dump NIG memories (0/1) */ - DBG_GRC_PARAM_DUMP_MULD, /* dump MULD memories (0/1) */ - DBG_GRC_PARAM_DUMP_PRS, /* dump PRS memories (0/1) */ - DBG_GRC_PARAM_DUMP_DMAE, /* dump PRS memories (0/1) */ - DBG_GRC_PARAM_DUMP_TM, /* dump TM (timers) memories (0/1) */ - DBG_GRC_PARAM_DUMP_SDM, /* dump SDM memories (0/1) */ - DBG_GRC_PARAM_DUMP_DIF, /* dump DIF memories (0/1) */ - DBG_GRC_PARAM_DUMP_STATIC, /* dump static debug data (0/1) */ - DBG_GRC_PARAM_UNSTALL, /* un-stall Storms after dump (0/1) */ - DBG_GRC_PARAM_NUM_LCIDS, /* number of LCIDs (0..320) */ - DBG_GRC_PARAM_NUM_LTIDS, /* number of LTIDs (0..320) */ - /* preset: exclude all memories from dump (1 only) */ + DBG_GRC_PARAM_DUMP_TSTORM, + DBG_GRC_PARAM_DUMP_MSTORM, + DBG_GRC_PARAM_DUMP_USTORM, + DBG_GRC_PARAM_DUMP_XSTORM, + DBG_GRC_PARAM_DUMP_YSTORM, + DBG_GRC_PARAM_DUMP_PSTORM, + DBG_GRC_PARAM_DUMP_REGS, + DBG_GRC_PARAM_DUMP_RAM, + DBG_GRC_PARAM_DUMP_PBUF, + DBG_GRC_PARAM_DUMP_IOR, + DBG_GRC_PARAM_DUMP_VFC, + DBG_GRC_PARAM_DUMP_CM_CTX, + DBG_GRC_PARAM_DUMP_PXP, + DBG_GRC_PARAM_DUMP_RSS, + DBG_GRC_PARAM_DUMP_CAU, + DBG_GRC_PARAM_DUMP_QM, + DBG_GRC_PARAM_DUMP_MCP, + DBG_GRC_PARAM_RESERVED, + DBG_GRC_PARAM_DUMP_CFC, + DBG_GRC_PARAM_DUMP_IGU, + DBG_GRC_PARAM_DUMP_BRB, + DBG_GRC_PARAM_DUMP_BTB, + DBG_GRC_PARAM_DUMP_BMB, + DBG_GRC_PARAM_DUMP_NIG, + DBG_GRC_PARAM_DUMP_MULD, + DBG_GRC_PARAM_DUMP_PRS, + DBG_GRC_PARAM_DUMP_DMAE, + DBG_GRC_PARAM_DUMP_TM, + DBG_GRC_PARAM_DUMP_SDM, + DBG_GRC_PARAM_DUMP_DIF, + DBG_GRC_PARAM_DUMP_STATIC, + DBG_GRC_PARAM_UNSTALL, + DBG_GRC_PARAM_NUM_LCIDS, + DBG_GRC_PARAM_NUM_LTIDS, DBG_GRC_PARAM_EXCLUDE_ALL, - /* preset: include memories for crash dump (1 only) */ DBG_GRC_PARAM_CRASH, - /* perform dump only if MFW is responding (0/1) */ DBG_GRC_PARAM_PARITY_SAFE, - DBG_GRC_PARAM_DUMP_CM, /* dump CM memories (0/1) */ - DBG_GRC_PARAM_DUMP_PHY, /* dump PHY memories (0/1) */ + DBG_GRC_PARAM_DUMP_CM, + DBG_GRC_PARAM_DUMP_PHY, DBG_GRC_PARAM_NO_MCP, DBG_GRC_PARAM_NO_FW_VER, MAX_DBG_GRC_PARAMS @@ -2347,7 +2359,10 @@ enum dbg_status { DBG_STATUS_REG_FIFO_BAD_DATA, DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA, DBG_STATUS_DBG_ARRAY_NOT_SET, - DBG_STATUS_MULTI_BLOCKS_WITH_FILTER, + DBG_STATUS_FILTER_BUG, + DBG_STATUS_NON_MATCHING_LINES, + DBG_STATUS_INVALID_TRIGGER_DWORD_OFFSET, + DBG_STATUS_DBG_BUS_IN_USE, MAX_DBG_STATUS }; @@ -2364,25 +2379,22 @@ enum dbg_storms { /* Idle Check data */ struct idle_chk_data { - __le32 buf_size; /* Idle check buffer size in dwords */ - u8 buf_size_set; /* Indicates if the idle check buffer size was set - * (0/1). - */ + __le32 buf_size; + u8 buf_size_set; u8 reserved1; __le16 reserved2; }; /* Debug Tools data (per HW function) */ struct dbg_tools_data { - struct dbg_grc_data grc; /* GRC Dump data */ - struct dbg_bus_data bus; /* Debug Bus data */ - struct idle_chk_data idle_chk; /* Idle Check data */ - u8 mode_enable[40]; /* Indicates if a mode is enabled (0/1) */ - u8 block_in_reset[88]; /* Indicates if a block is in reset state (0/1). - */ - u8 chip_id; /* Chip ID (from enum chip_ids) */ - u8 platform_id; /* Platform ID (from enum platform_ids) */ - u8 initialized; /* Indicates if the data was initialized */ + struct dbg_grc_data grc; + struct dbg_bus_data bus; + struct idle_chk_data idle_chk; + u8 mode_enable[40]; + u8 block_in_reset[88]; + u8 chip_id; + u8 platform_id; + u8 initialized; u8 reserved; }; @@ -2464,6 +2476,12 @@ struct init_qm_vport_params { /* Max size in dwords of a zipped array */ #define MAX_ZIPPED_SIZE 8192 +enum chip_ids { + CHIP_BB, + CHIP_K2, + CHIP_RESERVED, + MAX_CHIP_IDS +}; struct fw_asserts_ram_section { __le16 section_ram_line_offset; @@ -2475,18 +2493,18 @@ struct fw_asserts_ram_section { }; struct fw_ver_num { - u8 major; /* Firmware major version number */ - u8 minor; /* Firmware minor version number */ - u8 rev; /* Firmware revision version number */ - u8 eng; /* Firmware engineering version number (for bootleg versions) */ + u8 major; + u8 minor; + u8 rev; + u8 eng; }; struct fw_ver_info { - __le16 tools_ver; /* Tools version number */ - u8 image_id; /* FW image ID (e.g. main) */ + __le16 tools_ver; + u8 image_id; u8 reserved1; - struct fw_ver_num num; /* FW version number */ - __le32 timestamp; /* FW Timestamp in unix time (sec. since 1970) */ + struct fw_ver_num num; + __le32 timestamp; __le32 reserved2; }; @@ -2722,7 +2740,6 @@ struct init_read_op { #define INIT_READ_OP_ADDRESS_MASK 0x7FFFFF #define INIT_READ_OP_ADDRESS_SHIFT 9 __le32 expected_val; - }; /* Init operations union */ @@ -2782,6 +2799,7 @@ struct iro { * @param bin_ptr - a pointer to the binary data with debug arrays. */ enum dbg_status qed_dbg_set_bin_ptr(const u8 * const bin_ptr); + /** * @brief qed_dbg_grc_set_params_default - Reverts all GRC parameters to their * default value. @@ -2805,6 +2823,7 @@ void qed_dbg_grc_set_params_default(struct qed_hwfn *p_hwfn); enum dbg_status qed_dbg_grc_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_grc_dump - Dumps GRC data into the specified buffer. * @@ -2824,6 +2843,7 @@ enum dbg_status qed_dbg_grc_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_idle_chk_get_dump_buf_size - Returns the required buffer size * for idle check results. @@ -2840,6 +2860,7 @@ enum dbg_status qed_dbg_grc_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_idle_chk_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_idle_chk_dump - Performs idle check and writes the results * into the specified buffer. @@ -2860,6 +2881,7 @@ enum dbg_status qed_dbg_idle_chk_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_mcp_trace_get_dump_buf_size - Returns the required buffer size * for mcp trace results. @@ -2878,6 +2900,7 @@ enum dbg_status qed_dbg_idle_chk_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_mcp_trace_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_mcp_trace_dump - Performs mcp trace and writes the results * into the specified buffer. @@ -2902,6 +2925,7 @@ enum dbg_status qed_dbg_mcp_trace_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_reg_fifo_get_dump_buf_size - Returns the required buffer size * for grc trace fifo results. @@ -2917,6 +2941,7 @@ enum dbg_status qed_dbg_mcp_trace_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_reg_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_reg_fifo_dump - Reads the reg fifo and writes the results into * the specified buffer. @@ -2938,6 +2963,7 @@ enum dbg_status qed_dbg_reg_fifo_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_igu_fifo_get_dump_buf_size - Returns the required buffer size * for the IGU fifo results. @@ -2954,6 +2980,7 @@ enum dbg_status qed_dbg_reg_fifo_dump(struct qed_hwfn *p_hwfn, enum dbg_status qed_dbg_igu_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *buf_size); + /** * @brief qed_dbg_igu_fifo_dump - Reads the IGU fifo and writes the results into * the specified buffer. @@ -2975,6 +3002,7 @@ enum dbg_status qed_dbg_igu_fifo_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + /** * @brief qed_dbg_protection_override_get_dump_buf_size - Returns the required * buffer size for protection override window results. @@ -3074,6 +3102,7 @@ enum dbg_status qed_dbg_print_attn(struct qed_hwfn *p_hwfn, * @param bin_ptr - a pointer to the binary data with debug arrays. */ enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr); + /** * @brief qed_dbg_get_status_str - Returns a string for the specified status. * @@ -3082,6 +3111,7 @@ enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr); * @return a string for the specified status */ const char *qed_dbg_get_status_str(enum dbg_status status); + /** * @brief qed_get_idle_chk_results_buf_size - Returns the required buffer size * for idle check results (in bytes). @@ -3116,6 +3146,7 @@ enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn, char *results_buf, u32 *num_errors, u32 *num_warnings); + /** * @brief qed_get_mcp_trace_results_buf_size - Returns the required buffer size * for MCP Trace results (in bytes). @@ -3132,6 +3163,7 @@ enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_mcp_trace_results - Prints MCP Trace results * @@ -3146,6 +3178,7 @@ enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + /** * @brief qed_get_reg_fifo_results_buf_size - Returns the required buffer size * for reg_fifo results (in bytes). @@ -3162,6 +3195,7 @@ enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_reg_fifo_results - Prints reg fifo results * @@ -3176,6 +3210,7 @@ enum dbg_status qed_print_reg_fifo_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + /** * @brief qed_get_igu_fifo_results_buf_size - Returns the required buffer size * for igu_fifo results (in bytes). @@ -3192,6 +3227,7 @@ enum dbg_status qed_get_igu_fifo_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_igu_fifo_results - Prints IGU fifo results * @@ -3206,6 +3242,7 @@ enum dbg_status qed_print_igu_fifo_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + /** * @brief qed_get_protection_override_results_buf_size - Returns the required * buffer size for protection override results (in bytes). @@ -3223,6 +3260,7 @@ qed_get_protection_override_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_protection_override_results - Prints protection override * results. @@ -3238,6 +3276,7 @@ enum dbg_status qed_print_protection_override_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + /** * @brief qed_get_fw_asserts_results_buf_size - Returns the required buffer size * for FW Asserts results (in bytes). @@ -3254,6 +3293,7 @@ enum dbg_status qed_get_fw_asserts_results_buf_size(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, u32 *results_buf_size); + /** * @brief qed_print_fw_asserts_results - Prints FW Asserts results * @@ -3268,6 +3308,269 @@ enum dbg_status qed_print_fw_asserts_results(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 num_dumped_dwords, char *results_buf); + +/* Debug Bus blocks */ +static const u32 dbg_bus_blocks[] = { + 0x0000000f, /* grc, bb, 15 lines */ + 0x0000000f, /* grc, k2, 15 lines */ + 0x00000000, + 0x00000000, /* miscs, bb, 0 lines */ + 0x00000000, /* miscs, k2, 0 lines */ + 0x00000000, + 0x00000000, /* misc, bb, 0 lines */ + 0x00000000, /* misc, k2, 0 lines */ + 0x00000000, + 0x00000000, /* dbu, bb, 0 lines */ + 0x00000000, /* dbu, k2, 0 lines */ + 0x00000000, + 0x000f0127, /* pglue_b, bb, 39 lines */ + 0x0036012a, /* pglue_b, k2, 42 lines */ + 0x00000000, + 0x00000000, /* cnig, bb, 0 lines */ + 0x00120102, /* cnig, k2, 2 lines */ + 0x00000000, + 0x00000000, /* cpmu, bb, 0 lines */ + 0x00000000, /* cpmu, k2, 0 lines */ + 0x00000000, + 0x00000001, /* ncsi, bb, 1 lines */ + 0x00000001, /* ncsi, k2, 1 lines */ + 0x00000000, + 0x00000000, /* opte, bb, 0 lines */ + 0x00000000, /* opte, k2, 0 lines */ + 0x00000000, + 0x00600085, /* bmb, bb, 133 lines */ + 0x00600085, /* bmb, k2, 133 lines */ + 0x00000000, + 0x00000000, /* pcie, bb, 0 lines */ + 0x00e50033, /* pcie, k2, 51 lines */ + 0x00000000, + 0x00000000, /* mcp, bb, 0 lines */ + 0x00000000, /* mcp, k2, 0 lines */ + 0x00000000, + 0x01180009, /* mcp2, bb, 9 lines */ + 0x01180009, /* mcp2, k2, 9 lines */ + 0x00000000, + 0x01210104, /* pswhst, bb, 4 lines */ + 0x01210104, /* pswhst, k2, 4 lines */ + 0x00000000, + 0x01250103, /* pswhst2, bb, 3 lines */ + 0x01250103, /* pswhst2, k2, 3 lines */ + 0x00000000, + 0x00340101, /* pswrd, bb, 1 lines */ + 0x00340101, /* pswrd, k2, 1 lines */ + 0x00000000, + 0x01280119, /* pswrd2, bb, 25 lines */ + 0x01280119, /* pswrd2, k2, 25 lines */ + 0x00000000, + 0x01410109, /* pswwr, bb, 9 lines */ + 0x01410109, /* pswwr, k2, 9 lines */ + 0x00000000, + 0x00000000, /* pswwr2, bb, 0 lines */ + 0x00000000, /* pswwr2, k2, 0 lines */ + 0x00000000, + 0x001c0001, /* pswrq, bb, 1 lines */ + 0x001c0001, /* pswrq, k2, 1 lines */ + 0x00000000, + 0x014a0015, /* pswrq2, bb, 21 lines */ + 0x014a0015, /* pswrq2, k2, 21 lines */ + 0x00000000, + 0x00000000, /* pglcs, bb, 0 lines */ + 0x00120006, /* pglcs, k2, 6 lines */ + 0x00000000, + 0x00100001, /* dmae, bb, 1 lines */ + 0x00100001, /* dmae, k2, 1 lines */ + 0x00000000, + 0x015f0105, /* ptu, bb, 5 lines */ + 0x015f0105, /* ptu, k2, 5 lines */ + 0x00000000, + 0x01640120, /* tcm, bb, 32 lines */ + 0x01640120, /* tcm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* mcm, bb, 32 lines */ + 0x01640120, /* mcm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* ucm, bb, 32 lines */ + 0x01640120, /* ucm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* xcm, bb, 32 lines */ + 0x01640120, /* xcm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* ycm, bb, 32 lines */ + 0x01640120, /* ycm, k2, 32 lines */ + 0x00000000, + 0x01640120, /* pcm, bb, 32 lines */ + 0x01640120, /* pcm, k2, 32 lines */ + 0x00000000, + 0x01840062, /* qm, bb, 98 lines */ + 0x01840062, /* qm, k2, 98 lines */ + 0x00000000, + 0x01e60021, /* tm, bb, 33 lines */ + 0x01e60021, /* tm, k2, 33 lines */ + 0x00000000, + 0x02070107, /* dorq, bb, 7 lines */ + 0x02070107, /* dorq, k2, 7 lines */ + 0x00000000, + 0x00600185, /* brb, bb, 133 lines */ + 0x00600185, /* brb, k2, 133 lines */ + 0x00000000, + 0x020e0019, /* src, bb, 25 lines */ + 0x020c001a, /* src, k2, 26 lines */ + 0x00000000, + 0x02270104, /* prs, bb, 4 lines */ + 0x02270104, /* prs, k2, 4 lines */ + 0x00000000, + 0x022b0133, /* tsdm, bb, 51 lines */ + 0x022b0133, /* tsdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* msdm, bb, 51 lines */ + 0x022b0133, /* msdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* usdm, bb, 51 lines */ + 0x022b0133, /* usdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* xsdm, bb, 51 lines */ + 0x022b0133, /* xsdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* ysdm, bb, 51 lines */ + 0x022b0133, /* ysdm, k2, 51 lines */ + 0x00000000, + 0x022b0133, /* psdm, bb, 51 lines */ + 0x022b0133, /* psdm, k2, 51 lines */ + 0x00000000, + 0x025e010c, /* tsem, bb, 12 lines */ + 0x025e010c, /* tsem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* msem, bb, 12 lines */ + 0x025e010c, /* msem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* usem, bb, 12 lines */ + 0x025e010c, /* usem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* xsem, bb, 12 lines */ + 0x025e010c, /* xsem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* ysem, bb, 12 lines */ + 0x025e010c, /* ysem, k2, 12 lines */ + 0x00000000, + 0x025e010c, /* psem, bb, 12 lines */ + 0x025e010c, /* psem, k2, 12 lines */ + 0x00000000, + 0x026a000d, /* rss, bb, 13 lines */ + 0x026a000d, /* rss, k2, 13 lines */ + 0x00000000, + 0x02770106, /* tmld, bb, 6 lines */ + 0x02770106, /* tmld, k2, 6 lines */ + 0x00000000, + 0x027d0106, /* muld, bb, 6 lines */ + 0x027d0106, /* muld, k2, 6 lines */ + 0x00000000, + 0x02770005, /* yuld, bb, 5 lines */ + 0x02770005, /* yuld, k2, 5 lines */ + 0x00000000, + 0x02830107, /* xyld, bb, 7 lines */ + 0x027d0107, /* xyld, k2, 7 lines */ + 0x00000000, + 0x00000000, /* ptld, bb, 0 lines */ + 0x00000000, /* ptld, k2, 0 lines */ + 0x00000000, + 0x00000000, /* ypld, bb, 0 lines */ + 0x00000000, /* ypld, k2, 0 lines */ + 0x00000000, + 0x028a010e, /* prm, bb, 14 lines */ + 0x02980110, /* prm, k2, 16 lines */ + 0x00000000, + 0x02a8000d, /* pbf_pb1, bb, 13 lines */ + 0x02a8000d, /* pbf_pb1, k2, 13 lines */ + 0x00000000, + 0x02a8000d, /* pbf_pb2, bb, 13 lines */ + 0x02a8000d, /* pbf_pb2, k2, 13 lines */ + 0x00000000, + 0x02a8000d, /* rpb, bb, 13 lines */ + 0x02a8000d, /* rpb, k2, 13 lines */ + 0x00000000, + 0x00600185, /* btb, bb, 133 lines */ + 0x00600185, /* btb, k2, 133 lines */ + 0x00000000, + 0x02b50117, /* pbf, bb, 23 lines */ + 0x02b50117, /* pbf, k2, 23 lines */ + 0x00000000, + 0x02cc0006, /* rdif, bb, 6 lines */ + 0x02cc0006, /* rdif, k2, 6 lines */ + 0x00000000, + 0x02d20006, /* tdif, bb, 6 lines */ + 0x02d20006, /* tdif, k2, 6 lines */ + 0x00000000, + 0x02d80003, /* cdu, bb, 3 lines */ + 0x02db000e, /* cdu, k2, 14 lines */ + 0x00000000, + 0x02e9010d, /* ccfc, bb, 13 lines */ + 0x02f60117, /* ccfc, k2, 23 lines */ + 0x00000000, + 0x02e9010d, /* tcfc, bb, 13 lines */ + 0x02f60117, /* tcfc, k2, 23 lines */ + 0x00000000, + 0x030d0133, /* igu, bb, 51 lines */ + 0x030d0133, /* igu, k2, 51 lines */ + 0x00000000, + 0x03400106, /* cau, bb, 6 lines */ + 0x03400106, /* cau, k2, 6 lines */ + 0x00000000, + 0x00000000, /* rgfs, bb, 0 lines */ + 0x00000000, /* rgfs, k2, 0 lines */ + 0x00000000, + 0x00000000, /* rgsrc, bb, 0 lines */ + 0x00000000, /* rgsrc, k2, 0 lines */ + 0x00000000, + 0x00000000, /* tgfs, bb, 0 lines */ + 0x00000000, /* tgfs, k2, 0 lines */ + 0x00000000, + 0x00000000, /* tgsrc, bb, 0 lines */ + 0x00000000, /* tgsrc, k2, 0 lines */ + 0x00000000, + 0x00000000, /* umac, bb, 0 lines */ + 0x00120006, /* umac, k2, 6 lines */ + 0x00000000, + 0x00000000, /* xmac, bb, 0 lines */ + 0x00000000, /* xmac, k2, 0 lines */ + 0x00000000, + 0x00000000, /* dbg, bb, 0 lines */ + 0x00000000, /* dbg, k2, 0 lines */ + 0x00000000, + 0x0346012b, /* nig, bb, 43 lines */ + 0x0346011d, /* nig, k2, 29 lines */ + 0x00000000, + 0x00000000, /* wol, bb, 0 lines */ + 0x001c0002, /* wol, k2, 2 lines */ + 0x00000000, + 0x00000000, /* bmbn, bb, 0 lines */ + 0x00210008, /* bmbn, k2, 8 lines */ + 0x00000000, + 0x00000000, /* ipc, bb, 0 lines */ + 0x00000000, /* ipc, k2, 0 lines */ + 0x00000000, + 0x00000000, /* nwm, bb, 0 lines */ + 0x0371000b, /* nwm, k2, 11 lines */ + 0x00000000, + 0x00000000, /* nws, bb, 0 lines */ + 0x037c0009, /* nws, k2, 9 lines */ + 0x00000000, + 0x00000000, /* ms, bb, 0 lines */ + 0x00120004, /* ms, k2, 4 lines */ + 0x00000000, + 0x00000000, /* phy_pcie, bb, 0 lines */ + 0x00e5001a, /* phy_pcie, k2, 26 lines */ + 0x00000000, + 0x00000000, /* led, bb, 0 lines */ + 0x00000000, /* led, k2, 0 lines */ + 0x00000000, + 0x00000000, /* avs_wrap, bb, 0 lines */ + 0x00000000, /* avs_wrap, k2, 0 lines */ + 0x00000000, + 0x00000000, /* bar0_map, bb, 0 lines */ + 0x00000000, /* bar0_map, k2, 0 lines */ + 0x00000000, +}; + /* Win 2 */ #define GTT_BAR0_MAP_REG_IGU_CMD 0x00f000UL @@ -3589,37 +3892,37 @@ void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, #define PSTORM_FCOE_TX_STATS_OFFSET(pf_id) \ (IRO[44].base + ((pf_id) * IRO[44].m1)) -static const struct iro iro_arr[47] = { +static const struct iro iro_arr[49] = { {0x0, 0x0, 0x0, 0x0, 0x8}, {0x4cb0, 0x80, 0x0, 0x0, 0x80}, - {0x6318, 0x20, 0x0, 0x0, 0x20}, + {0x6518, 0x20, 0x0, 0x0, 0x20}, {0xb00, 0x8, 0x0, 0x0, 0x4}, {0xa80, 0x8, 0x0, 0x0, 0x4}, {0x0, 0x8, 0x0, 0x0, 0x2}, {0x80, 0x8, 0x0, 0x0, 0x4}, {0x84, 0x8, 0x0, 0x0, 0x2}, - {0x4bc0, 0x0, 0x0, 0x0, 0x78}, + {0x4c40, 0x0, 0x0, 0x0, 0x78}, {0x3df0, 0x0, 0x0, 0x0, 0x78}, {0x29b0, 0x0, 0x0, 0x0, 0x78}, {0x4c38, 0x0, 0x0, 0x0, 0x78}, {0x4990, 0x0, 0x0, 0x0, 0x78}, - {0x7e48, 0x0, 0x0, 0x0, 0x78}, + {0x7f48, 0x0, 0x0, 0x0, 0x78}, {0xa28, 0x8, 0x0, 0x0, 0x8}, - {0x60f8, 0x10, 0x0, 0x0, 0x10}, - {0xb820, 0x30, 0x0, 0x0, 0x30}, + {0x61f8, 0x10, 0x0, 0x0, 0x10}, + {0xbd20, 0x30, 0x0, 0x0, 0x30}, {0x95b8, 0x30, 0x0, 0x0, 0x30}, {0x4b60, 0x80, 0x0, 0x0, 0x40}, {0x1f8, 0x4, 0x0, 0x0, 0x4}, {0x53a0, 0x80, 0x4, 0x0, 0x4}, - {0xc8f0, 0x0, 0x0, 0x0, 0x4}, + {0xc7c8, 0x0, 0x0, 0x0, 0x4}, {0x4ba0, 0x80, 0x0, 0x0, 0x20}, - {0x8050, 0x40, 0x0, 0x0, 0x30}, - {0xe770, 0x60, 0x0, 0x0, 0x60}, + {0x8150, 0x40, 0x0, 0x0, 0x30}, + {0xec70, 0x60, 0x0, 0x0, 0x60}, {0x2b48, 0x80, 0x0, 0x0, 0x38}, - {0xf188, 0x78, 0x0, 0x0, 0x78}, + {0xf1b0, 0x78, 0x0, 0x0, 0x78}, {0x1f8, 0x4, 0x0, 0x0, 0x4}, - {0xacf0, 0x0, 0x0, 0x0, 0xf0}, - {0xade0, 0x8, 0x0, 0x0, 0x8}, + {0xaef8, 0x0, 0x0, 0x0, 0xf0}, + {0xafe8, 0x8, 0x0, 0x0, 0x8}, {0x1f8, 0x8, 0x0, 0x0, 0x8}, {0xac0, 0x8, 0x0, 0x0, 0x8}, {0x2578, 0x8, 0x0, 0x0, 0x8}, @@ -3627,16 +3930,18 @@ static const struct iro iro_arr[47] = { {0x0, 0x8, 0x0, 0x0, 0x8}, {0x200, 0x10, 0x8, 0x0, 0x8}, {0xb78, 0x10, 0x8, 0x0, 0x2}, - {0xd888, 0x38, 0x0, 0x0, 0x24}, - {0x12c38, 0x10, 0x0, 0x0, 0x8}, - {0x11aa0, 0x38, 0x0, 0x0, 0x18}, - {0xa8c0, 0x38, 0x0, 0x0, 0x10}, + {0xd9a8, 0x38, 0x0, 0x0, 0x24}, + {0x12988, 0x10, 0x0, 0x0, 0x8}, + {0x11fa0, 0x38, 0x0, 0x0, 0x18}, + {0xa580, 0x38, 0x0, 0x0, 0x10}, {0x86f8, 0x30, 0x0, 0x0, 0x18}, {0x101f8, 0x10, 0x0, 0x0, 0x10}, - {0xdd08, 0x48, 0x0, 0x0, 0x38}, + {0xde28, 0x48, 0x0, 0x0, 0x38}, {0x10660, 0x20, 0x0, 0x0, 0x20}, {0x2b80, 0x80, 0x0, 0x0, 0x10}, {0x5020, 0x10, 0x0, 0x0, 0x10}, + {0xc9b0, 0x30, 0x0, 0x0, 0x10}, + {0xeec0, 0x10, 0x0, 0x0, 0x10}, }; /* Runtime array offsets */ @@ -3724,361 +4029,359 @@ static const struct iro iro_arr[47] = { #define PSWRQ2_REG_CDUC_BLOCKS_FACTOR_RT_OFFSET 6697 #define PSWRQ2_REG_VF_BASE_RT_OFFSET 6698 #define PSWRQ2_REG_VF_LAST_ILT_RT_OFFSET 6699 -#define PSWRQ2_REG_WR_MBS0_RT_OFFSET 6700 -#define PSWRQ2_REG_RD_MBS0_RT_OFFSET 6701 -#define PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET 6702 -#define PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET 6703 -#define PSWRQ2_REG_ILT_MEMORY_RT_OFFSET 6704 +#define PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET 6700 +#define PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET 6701 +#define PSWRQ2_REG_ILT_MEMORY_RT_OFFSET 6702 #define PSWRQ2_REG_ILT_MEMORY_RT_SIZE 22000 -#define PGLUE_REG_B_VF_BASE_RT_OFFSET 28704 -#define PGLUE_REG_B_MSDM_OFFSET_MASK_B_RT_OFFSET 28705 -#define PGLUE_REG_B_MSDM_VF_SHIFT_B_RT_OFFSET 28706 -#define PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET 28707 -#define PGLUE_REG_B_PF_BAR0_SIZE_RT_OFFSET 28708 -#define PGLUE_REG_B_PF_BAR1_SIZE_RT_OFFSET 28709 -#define PGLUE_REG_B_VF_BAR1_SIZE_RT_OFFSET 28710 -#define TM_REG_VF_ENABLE_CONN_RT_OFFSET 28711 -#define TM_REG_PF_ENABLE_CONN_RT_OFFSET 28712 -#define TM_REG_PF_ENABLE_TASK_RT_OFFSET 28713 -#define TM_REG_GROUP_SIZE_RESOLUTION_CONN_RT_OFFSET 28714 -#define TM_REG_GROUP_SIZE_RESOLUTION_TASK_RT_OFFSET 28715 -#define TM_REG_CONFIG_CONN_MEM_RT_OFFSET 28716 +#define PGLUE_REG_B_VF_BASE_RT_OFFSET 28702 +#define PGLUE_REG_B_MSDM_OFFSET_MASK_B_RT_OFFSET 28703 +#define PGLUE_REG_B_MSDM_VF_SHIFT_B_RT_OFFSET 28704 +#define PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET 28705 +#define PGLUE_REG_B_PF_BAR0_SIZE_RT_OFFSET 28706 +#define PGLUE_REG_B_PF_BAR1_SIZE_RT_OFFSET 28707 +#define PGLUE_REG_B_VF_BAR1_SIZE_RT_OFFSET 28708 +#define TM_REG_VF_ENABLE_CONN_RT_OFFSET 28709 +#define TM_REG_PF_ENABLE_CONN_RT_OFFSET 28710 +#define TM_REG_PF_ENABLE_TASK_RT_OFFSET 28711 +#define TM_REG_GROUP_SIZE_RESOLUTION_CONN_RT_OFFSET 28712 +#define TM_REG_GROUP_SIZE_RESOLUTION_TASK_RT_OFFSET 28713 +#define TM_REG_CONFIG_CONN_MEM_RT_OFFSET 28714 #define TM_REG_CONFIG_CONN_MEM_RT_SIZE 416 -#define TM_REG_CONFIG_TASK_MEM_RT_OFFSET 29132 -#define TM_REG_CONFIG_TASK_MEM_RT_SIZE 512 -#define QM_REG_MAXPQSIZE_0_RT_OFFSET 29644 -#define QM_REG_MAXPQSIZE_1_RT_OFFSET 29645 -#define QM_REG_MAXPQSIZE_2_RT_OFFSET 29646 -#define QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET 29647 -#define QM_REG_MAXPQSIZETXSEL_1_RT_OFFSET 29648 -#define QM_REG_MAXPQSIZETXSEL_2_RT_OFFSET 29649 -#define QM_REG_MAXPQSIZETXSEL_3_RT_OFFSET 29650 -#define QM_REG_MAXPQSIZETXSEL_4_RT_OFFSET 29651 -#define QM_REG_MAXPQSIZETXSEL_5_RT_OFFSET 29652 -#define QM_REG_MAXPQSIZETXSEL_6_RT_OFFSET 29653 -#define QM_REG_MAXPQSIZETXSEL_7_RT_OFFSET 29654 -#define QM_REG_MAXPQSIZETXSEL_8_RT_OFFSET 29655 -#define QM_REG_MAXPQSIZETXSEL_9_RT_OFFSET 29656 -#define QM_REG_MAXPQSIZETXSEL_10_RT_OFFSET 29657 -#define QM_REG_MAXPQSIZETXSEL_11_RT_OFFSET 29658 -#define QM_REG_MAXPQSIZETXSEL_12_RT_OFFSET 29659 -#define QM_REG_MAXPQSIZETXSEL_13_RT_OFFSET 29660 -#define QM_REG_MAXPQSIZETXSEL_14_RT_OFFSET 29661 -#define QM_REG_MAXPQSIZETXSEL_15_RT_OFFSET 29662 -#define QM_REG_MAXPQSIZETXSEL_16_RT_OFFSET 29663 -#define QM_REG_MAXPQSIZETXSEL_17_RT_OFFSET 29664 -#define QM_REG_MAXPQSIZETXSEL_18_RT_OFFSET 29665 -#define QM_REG_MAXPQSIZETXSEL_19_RT_OFFSET 29666 -#define QM_REG_MAXPQSIZETXSEL_20_RT_OFFSET 29667 -#define QM_REG_MAXPQSIZETXSEL_21_RT_OFFSET 29668 -#define QM_REG_MAXPQSIZETXSEL_22_RT_OFFSET 29669 -#define QM_REG_MAXPQSIZETXSEL_23_RT_OFFSET 29670 -#define QM_REG_MAXPQSIZETXSEL_24_RT_OFFSET 29671 -#define QM_REG_MAXPQSIZETXSEL_25_RT_OFFSET 29672 -#define QM_REG_MAXPQSIZETXSEL_26_RT_OFFSET 29673 -#define QM_REG_MAXPQSIZETXSEL_27_RT_OFFSET 29674 -#define QM_REG_MAXPQSIZETXSEL_28_RT_OFFSET 29675 -#define QM_REG_MAXPQSIZETXSEL_29_RT_OFFSET 29676 -#define QM_REG_MAXPQSIZETXSEL_30_RT_OFFSET 29677 -#define QM_REG_MAXPQSIZETXSEL_31_RT_OFFSET 29678 -#define QM_REG_MAXPQSIZETXSEL_32_RT_OFFSET 29679 -#define QM_REG_MAXPQSIZETXSEL_33_RT_OFFSET 29680 -#define QM_REG_MAXPQSIZETXSEL_34_RT_OFFSET 29681 -#define QM_REG_MAXPQSIZETXSEL_35_RT_OFFSET 29682 -#define QM_REG_MAXPQSIZETXSEL_36_RT_OFFSET 29683 -#define QM_REG_MAXPQSIZETXSEL_37_RT_OFFSET 29684 -#define QM_REG_MAXPQSIZETXSEL_38_RT_OFFSET 29685 -#define QM_REG_MAXPQSIZETXSEL_39_RT_OFFSET 29686 -#define QM_REG_MAXPQSIZETXSEL_40_RT_OFFSET 29687 -#define QM_REG_MAXPQSIZETXSEL_41_RT_OFFSET 29688 -#define QM_REG_MAXPQSIZETXSEL_42_RT_OFFSET 29689 -#define QM_REG_MAXPQSIZETXSEL_43_RT_OFFSET 29690 -#define QM_REG_MAXPQSIZETXSEL_44_RT_OFFSET 29691 -#define QM_REG_MAXPQSIZETXSEL_45_RT_OFFSET 29692 -#define QM_REG_MAXPQSIZETXSEL_46_RT_OFFSET 29693 -#define QM_REG_MAXPQSIZETXSEL_47_RT_OFFSET 29694 -#define QM_REG_MAXPQSIZETXSEL_48_RT_OFFSET 29695 -#define QM_REG_MAXPQSIZETXSEL_49_RT_OFFSET 29696 -#define QM_REG_MAXPQSIZETXSEL_50_RT_OFFSET 29697 -#define QM_REG_MAXPQSIZETXSEL_51_RT_OFFSET 29698 -#define QM_REG_MAXPQSIZETXSEL_52_RT_OFFSET 29699 -#define QM_REG_MAXPQSIZETXSEL_53_RT_OFFSET 29700 -#define QM_REG_MAXPQSIZETXSEL_54_RT_OFFSET 29701 -#define QM_REG_MAXPQSIZETXSEL_55_RT_OFFSET 29702 -#define QM_REG_MAXPQSIZETXSEL_56_RT_OFFSET 29703 -#define QM_REG_MAXPQSIZETXSEL_57_RT_OFFSET 29704 -#define QM_REG_MAXPQSIZETXSEL_58_RT_OFFSET 29705 -#define QM_REG_MAXPQSIZETXSEL_59_RT_OFFSET 29706 -#define QM_REG_MAXPQSIZETXSEL_60_RT_OFFSET 29707 -#define QM_REG_MAXPQSIZETXSEL_61_RT_OFFSET 29708 -#define QM_REG_MAXPQSIZETXSEL_62_RT_OFFSET 29709 -#define QM_REG_MAXPQSIZETXSEL_63_RT_OFFSET 29710 -#define QM_REG_BASEADDROTHERPQ_RT_OFFSET 29711 +#define TM_REG_CONFIG_TASK_MEM_RT_OFFSET 29130 +#define TM_REG_CONFIG_TASK_MEM_RT_SIZE 608 +#define QM_REG_MAXPQSIZE_0_RT_OFFSET 29738 +#define QM_REG_MAXPQSIZE_1_RT_OFFSET 29739 +#define QM_REG_MAXPQSIZE_2_RT_OFFSET 29740 +#define QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET 29741 +#define QM_REG_MAXPQSIZETXSEL_1_RT_OFFSET 29742 +#define QM_REG_MAXPQSIZETXSEL_2_RT_OFFSET 29743 +#define QM_REG_MAXPQSIZETXSEL_3_RT_OFFSET 29744 +#define QM_REG_MAXPQSIZETXSEL_4_RT_OFFSET 29745 +#define QM_REG_MAXPQSIZETXSEL_5_RT_OFFSET 29746 +#define QM_REG_MAXPQSIZETXSEL_6_RT_OFFSET 29747 +#define QM_REG_MAXPQSIZETXSEL_7_RT_OFFSET 29748 +#define QM_REG_MAXPQSIZETXSEL_8_RT_OFFSET 29749 +#define QM_REG_MAXPQSIZETXSEL_9_RT_OFFSET 29750 +#define QM_REG_MAXPQSIZETXSEL_10_RT_OFFSET 29751 +#define QM_REG_MAXPQSIZETXSEL_11_RT_OFFSET 29752 +#define QM_REG_MAXPQSIZETXSEL_12_RT_OFFSET 29753 +#define QM_REG_MAXPQSIZETXSEL_13_RT_OFFSET 29754 +#define QM_REG_MAXPQSIZETXSEL_14_RT_OFFSET 29755 +#define QM_REG_MAXPQSIZETXSEL_15_RT_OFFSET 29756 +#define QM_REG_MAXPQSIZETXSEL_16_RT_OFFSET 29757 +#define QM_REG_MAXPQSIZETXSEL_17_RT_OFFSET 29758 +#define QM_REG_MAXPQSIZETXSEL_18_RT_OFFSET 29759 +#define QM_REG_MAXPQSIZETXSEL_19_RT_OFFSET 29760 +#define QM_REG_MAXPQSIZETXSEL_20_RT_OFFSET 29761 +#define QM_REG_MAXPQSIZETXSEL_21_RT_OFFSET 29762 +#define QM_REG_MAXPQSIZETXSEL_22_RT_OFFSET 29763 +#define QM_REG_MAXPQSIZETXSEL_23_RT_OFFSET 29764 +#define QM_REG_MAXPQSIZETXSEL_24_RT_OFFSET 29765 +#define QM_REG_MAXPQSIZETXSEL_25_RT_OFFSET 29766 +#define QM_REG_MAXPQSIZETXSEL_26_RT_OFFSET 29767 +#define QM_REG_MAXPQSIZETXSEL_27_RT_OFFSET 29768 +#define QM_REG_MAXPQSIZETXSEL_28_RT_OFFSET 29769 +#define QM_REG_MAXPQSIZETXSEL_29_RT_OFFSET 29770 +#define QM_REG_MAXPQSIZETXSEL_30_RT_OFFSET 29771 +#define QM_REG_MAXPQSIZETXSEL_31_RT_OFFSET 29772 +#define QM_REG_MAXPQSIZETXSEL_32_RT_OFFSET 29773 +#define QM_REG_MAXPQSIZETXSEL_33_RT_OFFSET 29774 +#define QM_REG_MAXPQSIZETXSEL_34_RT_OFFSET 29775 +#define QM_REG_MAXPQSIZETXSEL_35_RT_OFFSET 29776 +#define QM_REG_MAXPQSIZETXSEL_36_RT_OFFSET 29777 +#define QM_REG_MAXPQSIZETXSEL_37_RT_OFFSET 29778 +#define QM_REG_MAXPQSIZETXSEL_38_RT_OFFSET 29779 +#define QM_REG_MAXPQSIZETXSEL_39_RT_OFFSET 29780 +#define QM_REG_MAXPQSIZETXSEL_40_RT_OFFSET 29781 +#define QM_REG_MAXPQSIZETXSEL_41_RT_OFFSET 29782 +#define QM_REG_MAXPQSIZETXSEL_42_RT_OFFSET 29783 +#define QM_REG_MAXPQSIZETXSEL_43_RT_OFFSET 29784 +#define QM_REG_MAXPQSIZETXSEL_44_RT_OFFSET 29785 +#define QM_REG_MAXPQSIZETXSEL_45_RT_OFFSET 29786 +#define QM_REG_MAXPQSIZETXSEL_46_RT_OFFSET 29787 +#define QM_REG_MAXPQSIZETXSEL_47_RT_OFFSET 29788 +#define QM_REG_MAXPQSIZETXSEL_48_RT_OFFSET 29789 +#define QM_REG_MAXPQSIZETXSEL_49_RT_OFFSET 29790 +#define QM_REG_MAXPQSIZETXSEL_50_RT_OFFSET 29791 +#define QM_REG_MAXPQSIZETXSEL_51_RT_OFFSET 29792 +#define QM_REG_MAXPQSIZETXSEL_52_RT_OFFSET 29793 +#define QM_REG_MAXPQSIZETXSEL_53_RT_OFFSET 29794 +#define QM_REG_MAXPQSIZETXSEL_54_RT_OFFSET 29795 +#define QM_REG_MAXPQSIZETXSEL_55_RT_OFFSET 29796 +#define QM_REG_MAXPQSIZETXSEL_56_RT_OFFSET 29797 +#define QM_REG_MAXPQSIZETXSEL_57_RT_OFFSET 29798 +#define QM_REG_MAXPQSIZETXSEL_58_RT_OFFSET 29799 +#define QM_REG_MAXPQSIZETXSEL_59_RT_OFFSET 29800 +#define QM_REG_MAXPQSIZETXSEL_60_RT_OFFSET 29801 +#define QM_REG_MAXPQSIZETXSEL_61_RT_OFFSET 29802 +#define QM_REG_MAXPQSIZETXSEL_62_RT_OFFSET 29803 +#define QM_REG_MAXPQSIZETXSEL_63_RT_OFFSET 29804 +#define QM_REG_BASEADDROTHERPQ_RT_OFFSET 29805 #define QM_REG_BASEADDROTHERPQ_RT_SIZE 128 -#define QM_REG_VOQCRDLINE_RT_OFFSET 29839 -#define QM_REG_VOQCRDLINE_RT_SIZE 20 -#define QM_REG_VOQINITCRDLINE_RT_OFFSET 29859 -#define QM_REG_VOQINITCRDLINE_RT_SIZE 20 -#define QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET 29879 -#define QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET 29880 -#define QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET 29881 -#define QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET 29882 -#define QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET 29883 -#define QM_REG_WRROTHERPQGRP_0_RT_OFFSET 29884 -#define QM_REG_WRROTHERPQGRP_1_RT_OFFSET 29885 -#define QM_REG_WRROTHERPQGRP_2_RT_OFFSET 29886 -#define QM_REG_WRROTHERPQGRP_3_RT_OFFSET 29887 -#define QM_REG_WRROTHERPQGRP_4_RT_OFFSET 29888 -#define QM_REG_WRROTHERPQGRP_5_RT_OFFSET 29889 -#define QM_REG_WRROTHERPQGRP_6_RT_OFFSET 29890 -#define QM_REG_WRROTHERPQGRP_7_RT_OFFSET 29891 -#define QM_REG_WRROTHERPQGRP_8_RT_OFFSET 29892 -#define QM_REG_WRROTHERPQGRP_9_RT_OFFSET 29893 -#define QM_REG_WRROTHERPQGRP_10_RT_OFFSET 29894 -#define QM_REG_WRROTHERPQGRP_11_RT_OFFSET 29895 -#define QM_REG_WRROTHERPQGRP_12_RT_OFFSET 29896 -#define QM_REG_WRROTHERPQGRP_13_RT_OFFSET 29897 -#define QM_REG_WRROTHERPQGRP_14_RT_OFFSET 29898 -#define QM_REG_WRROTHERPQGRP_15_RT_OFFSET 29899 -#define QM_REG_WRROTHERGRPWEIGHT_0_RT_OFFSET 29900 -#define QM_REG_WRROTHERGRPWEIGHT_1_RT_OFFSET 29901 -#define QM_REG_WRROTHERGRPWEIGHT_2_RT_OFFSET 29902 -#define QM_REG_WRROTHERGRPWEIGHT_3_RT_OFFSET 29903 -#define QM_REG_WRRTXGRPWEIGHT_0_RT_OFFSET 29904 -#define QM_REG_WRRTXGRPWEIGHT_1_RT_OFFSET 29905 -#define QM_REG_PQTX2PF_0_RT_OFFSET 29906 -#define QM_REG_PQTX2PF_1_RT_OFFSET 29907 -#define QM_REG_PQTX2PF_2_RT_OFFSET 29908 -#define QM_REG_PQTX2PF_3_RT_OFFSET 29909 -#define QM_REG_PQTX2PF_4_RT_OFFSET 29910 -#define QM_REG_PQTX2PF_5_RT_OFFSET 29911 -#define QM_REG_PQTX2PF_6_RT_OFFSET 29912 -#define QM_REG_PQTX2PF_7_RT_OFFSET 29913 -#define QM_REG_PQTX2PF_8_RT_OFFSET 29914 -#define QM_REG_PQTX2PF_9_RT_OFFSET 29915 -#define QM_REG_PQTX2PF_10_RT_OFFSET 29916 -#define QM_REG_PQTX2PF_11_RT_OFFSET 29917 -#define QM_REG_PQTX2PF_12_RT_OFFSET 29918 -#define QM_REG_PQTX2PF_13_RT_OFFSET 29919 -#define QM_REG_PQTX2PF_14_RT_OFFSET 29920 -#define QM_REG_PQTX2PF_15_RT_OFFSET 29921 -#define QM_REG_PQTX2PF_16_RT_OFFSET 29922 -#define QM_REG_PQTX2PF_17_RT_OFFSET 29923 -#define QM_REG_PQTX2PF_18_RT_OFFSET 29924 -#define QM_REG_PQTX2PF_19_RT_OFFSET 29925 -#define QM_REG_PQTX2PF_20_RT_OFFSET 29926 -#define QM_REG_PQTX2PF_21_RT_OFFSET 29927 -#define QM_REG_PQTX2PF_22_RT_OFFSET 29928 -#define QM_REG_PQTX2PF_23_RT_OFFSET 29929 -#define QM_REG_PQTX2PF_24_RT_OFFSET 29930 -#define QM_REG_PQTX2PF_25_RT_OFFSET 29931 -#define QM_REG_PQTX2PF_26_RT_OFFSET 29932 -#define QM_REG_PQTX2PF_27_RT_OFFSET 29933 -#define QM_REG_PQTX2PF_28_RT_OFFSET 29934 -#define QM_REG_PQTX2PF_29_RT_OFFSET 29935 -#define QM_REG_PQTX2PF_30_RT_OFFSET 29936 -#define QM_REG_PQTX2PF_31_RT_OFFSET 29937 -#define QM_REG_PQTX2PF_32_RT_OFFSET 29938 -#define QM_REG_PQTX2PF_33_RT_OFFSET 29939 -#define QM_REG_PQTX2PF_34_RT_OFFSET 29940 -#define QM_REG_PQTX2PF_35_RT_OFFSET 29941 -#define QM_REG_PQTX2PF_36_RT_OFFSET 29942 -#define QM_REG_PQTX2PF_37_RT_OFFSET 29943 -#define QM_REG_PQTX2PF_38_RT_OFFSET 29944 -#define QM_REG_PQTX2PF_39_RT_OFFSET 29945 -#define QM_REG_PQTX2PF_40_RT_OFFSET 29946 -#define QM_REG_PQTX2PF_41_RT_OFFSET 29947 -#define QM_REG_PQTX2PF_42_RT_OFFSET 29948 -#define QM_REG_PQTX2PF_43_RT_OFFSET 29949 -#define QM_REG_PQTX2PF_44_RT_OFFSET 29950 -#define QM_REG_PQTX2PF_45_RT_OFFSET 29951 -#define QM_REG_PQTX2PF_46_RT_OFFSET 29952 -#define QM_REG_PQTX2PF_47_RT_OFFSET 29953 -#define QM_REG_PQTX2PF_48_RT_OFFSET 29954 -#define QM_REG_PQTX2PF_49_RT_OFFSET 29955 -#define QM_REG_PQTX2PF_50_RT_OFFSET 29956 -#define QM_REG_PQTX2PF_51_RT_OFFSET 29957 -#define QM_REG_PQTX2PF_52_RT_OFFSET 29958 -#define QM_REG_PQTX2PF_53_RT_OFFSET 29959 -#define QM_REG_PQTX2PF_54_RT_OFFSET 29960 -#define QM_REG_PQTX2PF_55_RT_OFFSET 29961 -#define QM_REG_PQTX2PF_56_RT_OFFSET 29962 -#define QM_REG_PQTX2PF_57_RT_OFFSET 29963 -#define QM_REG_PQTX2PF_58_RT_OFFSET 29964 -#define QM_REG_PQTX2PF_59_RT_OFFSET 29965 -#define QM_REG_PQTX2PF_60_RT_OFFSET 29966 -#define QM_REG_PQTX2PF_61_RT_OFFSET 29967 -#define QM_REG_PQTX2PF_62_RT_OFFSET 29968 -#define QM_REG_PQTX2PF_63_RT_OFFSET 29969 -#define QM_REG_PQOTHER2PF_0_RT_OFFSET 29970 -#define QM_REG_PQOTHER2PF_1_RT_OFFSET 29971 -#define QM_REG_PQOTHER2PF_2_RT_OFFSET 29972 -#define QM_REG_PQOTHER2PF_3_RT_OFFSET 29973 -#define QM_REG_PQOTHER2PF_4_RT_OFFSET 29974 -#define QM_REG_PQOTHER2PF_5_RT_OFFSET 29975 -#define QM_REG_PQOTHER2PF_6_RT_OFFSET 29976 -#define QM_REG_PQOTHER2PF_7_RT_OFFSET 29977 -#define QM_REG_PQOTHER2PF_8_RT_OFFSET 29978 -#define QM_REG_PQOTHER2PF_9_RT_OFFSET 29979 -#define QM_REG_PQOTHER2PF_10_RT_OFFSET 29980 -#define QM_REG_PQOTHER2PF_11_RT_OFFSET 29981 -#define QM_REG_PQOTHER2PF_12_RT_OFFSET 29982 -#define QM_REG_PQOTHER2PF_13_RT_OFFSET 29983 -#define QM_REG_PQOTHER2PF_14_RT_OFFSET 29984 -#define QM_REG_PQOTHER2PF_15_RT_OFFSET 29985 -#define QM_REG_RLGLBLPERIOD_0_RT_OFFSET 29986 -#define QM_REG_RLGLBLPERIOD_1_RT_OFFSET 29987 -#define QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET 29988 -#define QM_REG_RLGLBLPERIODTIMER_1_RT_OFFSET 29989 -#define QM_REG_RLGLBLPERIODSEL_0_RT_OFFSET 29990 -#define QM_REG_RLGLBLPERIODSEL_1_RT_OFFSET 29991 -#define QM_REG_RLGLBLPERIODSEL_2_RT_OFFSET 29992 -#define QM_REG_RLGLBLPERIODSEL_3_RT_OFFSET 29993 -#define QM_REG_RLGLBLPERIODSEL_4_RT_OFFSET 29994 -#define QM_REG_RLGLBLPERIODSEL_5_RT_OFFSET 29995 -#define QM_REG_RLGLBLPERIODSEL_6_RT_OFFSET 29996 -#define QM_REG_RLGLBLPERIODSEL_7_RT_OFFSET 29997 -#define QM_REG_RLGLBLINCVAL_RT_OFFSET 29998 +#define QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET 29933 +#define QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET 29934 +#define QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET 29935 +#define QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET 29936 +#define QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET 29937 +#define QM_REG_WRROTHERPQGRP_0_RT_OFFSET 29938 +#define QM_REG_WRROTHERPQGRP_1_RT_OFFSET 29939 +#define QM_REG_WRROTHERPQGRP_2_RT_OFFSET 29940 +#define QM_REG_WRROTHERPQGRP_3_RT_OFFSET 29941 +#define QM_REG_WRROTHERPQGRP_4_RT_OFFSET 29942 +#define QM_REG_WRROTHERPQGRP_5_RT_OFFSET 29943 +#define QM_REG_WRROTHERPQGRP_6_RT_OFFSET 29944 +#define QM_REG_WRROTHERPQGRP_7_RT_OFFSET 29945 +#define QM_REG_WRROTHERPQGRP_8_RT_OFFSET 29946 +#define QM_REG_WRROTHERPQGRP_9_RT_OFFSET 29947 +#define QM_REG_WRROTHERPQGRP_10_RT_OFFSET 29948 +#define QM_REG_WRROTHERPQGRP_11_RT_OFFSET 29949 +#define QM_REG_WRROTHERPQGRP_12_RT_OFFSET 29950 +#define QM_REG_WRROTHERPQGRP_13_RT_OFFSET 29951 +#define QM_REG_WRROTHERPQGRP_14_RT_OFFSET 29952 +#define QM_REG_WRROTHERPQGRP_15_RT_OFFSET 29953 +#define QM_REG_WRROTHERGRPWEIGHT_0_RT_OFFSET 29954 +#define QM_REG_WRROTHERGRPWEIGHT_1_RT_OFFSET 29955 +#define QM_REG_WRROTHERGRPWEIGHT_2_RT_OFFSET 29956 +#define QM_REG_WRROTHERGRPWEIGHT_3_RT_OFFSET 29957 +#define QM_REG_WRRTXGRPWEIGHT_0_RT_OFFSET 29958 +#define QM_REG_WRRTXGRPWEIGHT_1_RT_OFFSET 29959 +#define QM_REG_PQTX2PF_0_RT_OFFSET 29960 +#define QM_REG_PQTX2PF_1_RT_OFFSET 29961 +#define QM_REG_PQTX2PF_2_RT_OFFSET 29962 +#define QM_REG_PQTX2PF_3_RT_OFFSET 29963 +#define QM_REG_PQTX2PF_4_RT_OFFSET 29964 +#define QM_REG_PQTX2PF_5_RT_OFFSET 29965 +#define QM_REG_PQTX2PF_6_RT_OFFSET 29966 +#define QM_REG_PQTX2PF_7_RT_OFFSET 29967 +#define QM_REG_PQTX2PF_8_RT_OFFSET 29968 +#define QM_REG_PQTX2PF_9_RT_OFFSET 29969 +#define QM_REG_PQTX2PF_10_RT_OFFSET 29970 +#define QM_REG_PQTX2PF_11_RT_OFFSET 29971 +#define QM_REG_PQTX2PF_12_RT_OFFSET 29972 +#define QM_REG_PQTX2PF_13_RT_OFFSET 29973 +#define QM_REG_PQTX2PF_14_RT_OFFSET 29974 +#define QM_REG_PQTX2PF_15_RT_OFFSET 29975 +#define QM_REG_PQTX2PF_16_RT_OFFSET 29976 +#define QM_REG_PQTX2PF_17_RT_OFFSET 29977 +#define QM_REG_PQTX2PF_18_RT_OFFSET 29978 +#define QM_REG_PQTX2PF_19_RT_OFFSET 29979 +#define QM_REG_PQTX2PF_20_RT_OFFSET 29980 +#define QM_REG_PQTX2PF_21_RT_OFFSET 29981 +#define QM_REG_PQTX2PF_22_RT_OFFSET 29982 +#define QM_REG_PQTX2PF_23_RT_OFFSET 29983 +#define QM_REG_PQTX2PF_24_RT_OFFSET 29984 +#define QM_REG_PQTX2PF_25_RT_OFFSET 29985 +#define QM_REG_PQTX2PF_26_RT_OFFSET 29986 +#define QM_REG_PQTX2PF_27_RT_OFFSET 29987 +#define QM_REG_PQTX2PF_28_RT_OFFSET 29988 +#define QM_REG_PQTX2PF_29_RT_OFFSET 29989 +#define QM_REG_PQTX2PF_30_RT_OFFSET 29990 +#define QM_REG_PQTX2PF_31_RT_OFFSET 29991 +#define QM_REG_PQTX2PF_32_RT_OFFSET 29992 +#define QM_REG_PQTX2PF_33_RT_OFFSET 29993 +#define QM_REG_PQTX2PF_34_RT_OFFSET 29994 +#define QM_REG_PQTX2PF_35_RT_OFFSET 29995 +#define QM_REG_PQTX2PF_36_RT_OFFSET 29996 +#define QM_REG_PQTX2PF_37_RT_OFFSET 29997 +#define QM_REG_PQTX2PF_38_RT_OFFSET 29998 +#define QM_REG_PQTX2PF_39_RT_OFFSET 29999 +#define QM_REG_PQTX2PF_40_RT_OFFSET 30000 +#define QM_REG_PQTX2PF_41_RT_OFFSET 30001 +#define QM_REG_PQTX2PF_42_RT_OFFSET 30002 +#define QM_REG_PQTX2PF_43_RT_OFFSET 30003 +#define QM_REG_PQTX2PF_44_RT_OFFSET 30004 +#define QM_REG_PQTX2PF_45_RT_OFFSET 30005 +#define QM_REG_PQTX2PF_46_RT_OFFSET 30006 +#define QM_REG_PQTX2PF_47_RT_OFFSET 30007 +#define QM_REG_PQTX2PF_48_RT_OFFSET 30008 +#define QM_REG_PQTX2PF_49_RT_OFFSET 30009 +#define QM_REG_PQTX2PF_50_RT_OFFSET 30010 +#define QM_REG_PQTX2PF_51_RT_OFFSET 30011 +#define QM_REG_PQTX2PF_52_RT_OFFSET 30012 +#define QM_REG_PQTX2PF_53_RT_OFFSET 30013 +#define QM_REG_PQTX2PF_54_RT_OFFSET 30014 +#define QM_REG_PQTX2PF_55_RT_OFFSET 30015 +#define QM_REG_PQTX2PF_56_RT_OFFSET 30016 +#define QM_REG_PQTX2PF_57_RT_OFFSET 30017 +#define QM_REG_PQTX2PF_58_RT_OFFSET 30018 +#define QM_REG_PQTX2PF_59_RT_OFFSET 30019 +#define QM_REG_PQTX2PF_60_RT_OFFSET 30020 +#define QM_REG_PQTX2PF_61_RT_OFFSET 30021 +#define QM_REG_PQTX2PF_62_RT_OFFSET 30022 +#define QM_REG_PQTX2PF_63_RT_OFFSET 30023 +#define QM_REG_PQOTHER2PF_0_RT_OFFSET 30024 +#define QM_REG_PQOTHER2PF_1_RT_OFFSET 30025 +#define QM_REG_PQOTHER2PF_2_RT_OFFSET 30026 +#define QM_REG_PQOTHER2PF_3_RT_OFFSET 30027 +#define QM_REG_PQOTHER2PF_4_RT_OFFSET 30028 +#define QM_REG_PQOTHER2PF_5_RT_OFFSET 30029 +#define QM_REG_PQOTHER2PF_6_RT_OFFSET 30030 +#define QM_REG_PQOTHER2PF_7_RT_OFFSET 30031 +#define QM_REG_PQOTHER2PF_8_RT_OFFSET 30032 +#define QM_REG_PQOTHER2PF_9_RT_OFFSET 30033 +#define QM_REG_PQOTHER2PF_10_RT_OFFSET 30034 +#define QM_REG_PQOTHER2PF_11_RT_OFFSET 30035 +#define QM_REG_PQOTHER2PF_12_RT_OFFSET 30036 +#define QM_REG_PQOTHER2PF_13_RT_OFFSET 30037 +#define QM_REG_PQOTHER2PF_14_RT_OFFSET 30038 +#define QM_REG_PQOTHER2PF_15_RT_OFFSET 30039 +#define QM_REG_RLGLBLPERIOD_0_RT_OFFSET 30040 +#define QM_REG_RLGLBLPERIOD_1_RT_OFFSET 30041 +#define QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET 30042 +#define QM_REG_RLGLBLPERIODTIMER_1_RT_OFFSET 30043 +#define QM_REG_RLGLBLPERIODSEL_0_RT_OFFSET 30044 +#define QM_REG_RLGLBLPERIODSEL_1_RT_OFFSET 30045 +#define QM_REG_RLGLBLPERIODSEL_2_RT_OFFSET 30046 +#define QM_REG_RLGLBLPERIODSEL_3_RT_OFFSET 30047 +#define QM_REG_RLGLBLPERIODSEL_4_RT_OFFSET 30048 +#define QM_REG_RLGLBLPERIODSEL_5_RT_OFFSET 30049 +#define QM_REG_RLGLBLPERIODSEL_6_RT_OFFSET 30050 +#define QM_REG_RLGLBLPERIODSEL_7_RT_OFFSET 30051 +#define QM_REG_RLGLBLINCVAL_RT_OFFSET 30052 #define QM_REG_RLGLBLINCVAL_RT_SIZE 256 -#define QM_REG_RLGLBLUPPERBOUND_RT_OFFSET 30254 +#define QM_REG_RLGLBLUPPERBOUND_RT_OFFSET 30308 #define QM_REG_RLGLBLUPPERBOUND_RT_SIZE 256 -#define QM_REG_RLGLBLCRD_RT_OFFSET 30510 +#define QM_REG_RLGLBLCRD_RT_OFFSET 30564 #define QM_REG_RLGLBLCRD_RT_SIZE 256 -#define QM_REG_RLGLBLENABLE_RT_OFFSET 30766 -#define QM_REG_RLPFPERIOD_RT_OFFSET 30767 -#define QM_REG_RLPFPERIODTIMER_RT_OFFSET 30768 -#define QM_REG_RLPFINCVAL_RT_OFFSET 30769 +#define QM_REG_RLGLBLENABLE_RT_OFFSET 30820 +#define QM_REG_RLPFPERIOD_RT_OFFSET 30821 +#define QM_REG_RLPFPERIODTIMER_RT_OFFSET 30822 +#define QM_REG_RLPFINCVAL_RT_OFFSET 30823 #define QM_REG_RLPFINCVAL_RT_SIZE 16 -#define QM_REG_RLPFUPPERBOUND_RT_OFFSET 30785 +#define QM_REG_RLPFUPPERBOUND_RT_OFFSET 30839 #define QM_REG_RLPFUPPERBOUND_RT_SIZE 16 -#define QM_REG_RLPFCRD_RT_OFFSET 30801 +#define QM_REG_RLPFCRD_RT_OFFSET 30855 #define QM_REG_RLPFCRD_RT_SIZE 16 -#define QM_REG_RLPFENABLE_RT_OFFSET 30817 -#define QM_REG_RLPFVOQENABLE_RT_OFFSET 30818 -#define QM_REG_WFQPFWEIGHT_RT_OFFSET 30819 +#define QM_REG_RLPFENABLE_RT_OFFSET 30871 +#define QM_REG_RLPFVOQENABLE_RT_OFFSET 30872 +#define QM_REG_WFQPFWEIGHT_RT_OFFSET 30873 #define QM_REG_WFQPFWEIGHT_RT_SIZE 16 -#define QM_REG_WFQPFUPPERBOUND_RT_OFFSET 30835 +#define QM_REG_WFQPFUPPERBOUND_RT_OFFSET 30889 #define QM_REG_WFQPFUPPERBOUND_RT_SIZE 16 -#define QM_REG_WFQPFCRD_RT_OFFSET 30851 -#define QM_REG_WFQPFCRD_RT_SIZE 160 -#define QM_REG_WFQPFENABLE_RT_OFFSET 31011 -#define QM_REG_WFQVPENABLE_RT_OFFSET 31012 -#define QM_REG_BASEADDRTXPQ_RT_OFFSET 31013 +#define QM_REG_WFQPFCRD_RT_OFFSET 30905 +#define QM_REG_WFQPFCRD_RT_SIZE 256 +#define QM_REG_WFQPFENABLE_RT_OFFSET 31161 +#define QM_REG_WFQVPENABLE_RT_OFFSET 31162 +#define QM_REG_BASEADDRTXPQ_RT_OFFSET 31163 #define QM_REG_BASEADDRTXPQ_RT_SIZE 512 -#define QM_REG_TXPQMAP_RT_OFFSET 31525 +#define QM_REG_TXPQMAP_RT_OFFSET 31675 #define QM_REG_TXPQMAP_RT_SIZE 512 -#define QM_REG_WFQVPWEIGHT_RT_OFFSET 32037 +#define QM_REG_WFQVPWEIGHT_RT_OFFSET 32187 #define QM_REG_WFQVPWEIGHT_RT_SIZE 512 -#define QM_REG_WFQVPCRD_RT_OFFSET 32549 +#define QM_REG_WFQVPCRD_RT_OFFSET 32699 #define QM_REG_WFQVPCRD_RT_SIZE 512 -#define QM_REG_WFQVPMAP_RT_OFFSET 33061 +#define QM_REG_WFQVPMAP_RT_OFFSET 33211 #define QM_REG_WFQVPMAP_RT_SIZE 512 -#define QM_REG_WFQPFCRD_MSB_RT_OFFSET 33573 -#define QM_REG_WFQPFCRD_MSB_RT_SIZE 160 -#define NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET 33733 -#define NIG_REG_OUTER_TAG_VALUE_LIST0_RT_OFFSET 33734 -#define NIG_REG_OUTER_TAG_VALUE_LIST1_RT_OFFSET 33735 -#define NIG_REG_OUTER_TAG_VALUE_LIST2_RT_OFFSET 33736 -#define NIG_REG_OUTER_TAG_VALUE_LIST3_RT_OFFSET 33737 -#define NIG_REG_OUTER_TAG_VALUE_MASK_RT_OFFSET 33738 -#define NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET 33739 -#define NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET 33740 +#define QM_REG_WFQPFCRD_MSB_RT_OFFSET 33723 +#define QM_REG_WFQPFCRD_MSB_RT_SIZE 320 +#define QM_REG_VOQCRDLINE_RT_OFFSET 34043 +#define QM_REG_VOQCRDLINE_RT_SIZE 36 +#define QM_REG_VOQINITCRDLINE_RT_OFFSET 34079 +#define QM_REG_VOQINITCRDLINE_RT_SIZE 36 +#define NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET 34115 +#define NIG_REG_OUTER_TAG_VALUE_LIST0_RT_OFFSET 34116 +#define NIG_REG_OUTER_TAG_VALUE_LIST1_RT_OFFSET 34117 +#define NIG_REG_OUTER_TAG_VALUE_LIST2_RT_OFFSET 34118 +#define NIG_REG_OUTER_TAG_VALUE_LIST3_RT_OFFSET 34119 +#define NIG_REG_OUTER_TAG_VALUE_MASK_RT_OFFSET 34120 +#define NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET 34121 +#define NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET 34122 #define NIG_REG_LLH_FUNC_TAG_EN_RT_SIZE 4 -#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_OFFSET 33744 +#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_OFFSET 34126 #define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_SIZE 4 -#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET 33748 +#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET 34130 #define NIG_REG_LLH_FUNC_TAG_VALUE_RT_SIZE 4 -#define NIG_REG_LLH_FUNC_NO_TAG_RT_OFFSET 33752 -#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_OFFSET 33753 +#define NIG_REG_LLH_FUNC_NO_TAG_RT_OFFSET 34134 +#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_OFFSET 34135 #define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_SIZE 32 -#define NIG_REG_LLH_FUNC_FILTER_EN_RT_OFFSET 33785 +#define NIG_REG_LLH_FUNC_FILTER_EN_RT_OFFSET 34167 #define NIG_REG_LLH_FUNC_FILTER_EN_RT_SIZE 16 -#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_OFFSET 33801 +#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_OFFSET 34183 #define NIG_REG_LLH_FUNC_FILTER_MODE_RT_SIZE 16 -#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_OFFSET 33817 +#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_OFFSET 34199 #define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_SIZE 16 -#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET 33833 +#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET 34215 #define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_SIZE 16 -#define NIG_REG_TX_EDPM_CTRL_RT_OFFSET 33849 -#define NIG_REG_ROCE_DUPLICATE_TO_HOST_RT_OFFSET 33850 -#define CDU_REG_CID_ADDR_PARAMS_RT_OFFSET 33851 -#define CDU_REG_SEGMENT0_PARAMS_RT_OFFSET 33852 -#define CDU_REG_SEGMENT1_PARAMS_RT_OFFSET 33853 -#define CDU_REG_PF_SEG0_TYPE_OFFSET_RT_OFFSET 33854 -#define CDU_REG_PF_SEG1_TYPE_OFFSET_RT_OFFSET 33855 -#define CDU_REG_PF_SEG2_TYPE_OFFSET_RT_OFFSET 33856 -#define CDU_REG_PF_SEG3_TYPE_OFFSET_RT_OFFSET 33857 -#define CDU_REG_PF_FL_SEG0_TYPE_OFFSET_RT_OFFSET 33858 -#define CDU_REG_PF_FL_SEG1_TYPE_OFFSET_RT_OFFSET 33859 -#define CDU_REG_PF_FL_SEG2_TYPE_OFFSET_RT_OFFSET 33860 -#define CDU_REG_PF_FL_SEG3_TYPE_OFFSET_RT_OFFSET 33861 -#define CDU_REG_VF_SEG_TYPE_OFFSET_RT_OFFSET 33862 -#define CDU_REG_VF_FL_SEG_TYPE_OFFSET_RT_OFFSET 33863 -#define PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET 33864 -#define PBF_REG_BTB_SHARED_AREA_SIZE_RT_OFFSET 33865 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET 33866 -#define PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET 33867 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ0_RT_OFFSET 33868 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET 33869 -#define PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET 33870 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ1_RT_OFFSET 33871 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ2_RT_OFFSET 33872 -#define PBF_REG_BTB_GUARANTEED_VOQ2_RT_OFFSET 33873 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ2_RT_OFFSET 33874 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ3_RT_OFFSET 33875 -#define PBF_REG_BTB_GUARANTEED_VOQ3_RT_OFFSET 33876 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ3_RT_OFFSET 33877 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ4_RT_OFFSET 33878 -#define PBF_REG_BTB_GUARANTEED_VOQ4_RT_OFFSET 33879 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ4_RT_OFFSET 33880 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ5_RT_OFFSET 33881 -#define PBF_REG_BTB_GUARANTEED_VOQ5_RT_OFFSET 33882 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ5_RT_OFFSET 33883 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ6_RT_OFFSET 33884 -#define PBF_REG_BTB_GUARANTEED_VOQ6_RT_OFFSET 33885 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ6_RT_OFFSET 33886 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ7_RT_OFFSET 33887 -#define PBF_REG_BTB_GUARANTEED_VOQ7_RT_OFFSET 33888 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ7_RT_OFFSET 33889 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ8_RT_OFFSET 33890 -#define PBF_REG_BTB_GUARANTEED_VOQ8_RT_OFFSET 33891 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ8_RT_OFFSET 33892 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ9_RT_OFFSET 33893 -#define PBF_REG_BTB_GUARANTEED_VOQ9_RT_OFFSET 33894 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ9_RT_OFFSET 33895 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ10_RT_OFFSET 33896 -#define PBF_REG_BTB_GUARANTEED_VOQ10_RT_OFFSET 33897 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ10_RT_OFFSET 33898 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ11_RT_OFFSET 33899 -#define PBF_REG_BTB_GUARANTEED_VOQ11_RT_OFFSET 33900 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ11_RT_OFFSET 33901 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ12_RT_OFFSET 33902 -#define PBF_REG_BTB_GUARANTEED_VOQ12_RT_OFFSET 33903 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ12_RT_OFFSET 33904 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ13_RT_OFFSET 33905 -#define PBF_REG_BTB_GUARANTEED_VOQ13_RT_OFFSET 33906 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ13_RT_OFFSET 33907 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ14_RT_OFFSET 33908 -#define PBF_REG_BTB_GUARANTEED_VOQ14_RT_OFFSET 33909 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ14_RT_OFFSET 33910 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ15_RT_OFFSET 33911 -#define PBF_REG_BTB_GUARANTEED_VOQ15_RT_OFFSET 33912 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ15_RT_OFFSET 33913 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ16_RT_OFFSET 33914 -#define PBF_REG_BTB_GUARANTEED_VOQ16_RT_OFFSET 33915 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ16_RT_OFFSET 33916 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ17_RT_OFFSET 33917 -#define PBF_REG_BTB_GUARANTEED_VOQ17_RT_OFFSET 33918 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ17_RT_OFFSET 33919 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ18_RT_OFFSET 33920 -#define PBF_REG_BTB_GUARANTEED_VOQ18_RT_OFFSET 33921 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ18_RT_OFFSET 33922 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ19_RT_OFFSET 33923 -#define PBF_REG_BTB_GUARANTEED_VOQ19_RT_OFFSET 33924 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ19_RT_OFFSET 33925 -#define XCM_REG_CON_PHY_Q3_RT_OFFSET 33926 - -#define RUNTIME_ARRAY_SIZE 33927 +#define NIG_REG_TX_EDPM_CTRL_RT_OFFSET 34231 +#define NIG_REG_ROCE_DUPLICATE_TO_HOST_RT_OFFSET 34232 +#define CDU_REG_CID_ADDR_PARAMS_RT_OFFSET 34233 +#define CDU_REG_SEGMENT0_PARAMS_RT_OFFSET 34234 +#define CDU_REG_SEGMENT1_PARAMS_RT_OFFSET 34235 +#define CDU_REG_PF_SEG0_TYPE_OFFSET_RT_OFFSET 34236 +#define CDU_REG_PF_SEG1_TYPE_OFFSET_RT_OFFSET 34237 +#define CDU_REG_PF_SEG2_TYPE_OFFSET_RT_OFFSET 34238 +#define CDU_REG_PF_SEG3_TYPE_OFFSET_RT_OFFSET 34239 +#define CDU_REG_PF_FL_SEG0_TYPE_OFFSET_RT_OFFSET 34240 +#define CDU_REG_PF_FL_SEG1_TYPE_OFFSET_RT_OFFSET 34241 +#define CDU_REG_PF_FL_SEG2_TYPE_OFFSET_RT_OFFSET 34242 +#define CDU_REG_PF_FL_SEG3_TYPE_OFFSET_RT_OFFSET 34243 +#define CDU_REG_VF_SEG_TYPE_OFFSET_RT_OFFSET 34244 +#define CDU_REG_VF_FL_SEG_TYPE_OFFSET_RT_OFFSET 34245 +#define PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET 34246 +#define PBF_REG_BTB_SHARED_AREA_SIZE_RT_OFFSET 34247 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET 34248 +#define PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET 34249 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ0_RT_OFFSET 34250 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET 34251 +#define PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET 34252 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ1_RT_OFFSET 34253 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ2_RT_OFFSET 34254 +#define PBF_REG_BTB_GUARANTEED_VOQ2_RT_OFFSET 34255 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ2_RT_OFFSET 34256 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ3_RT_OFFSET 34257 +#define PBF_REG_BTB_GUARANTEED_VOQ3_RT_OFFSET 34258 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ3_RT_OFFSET 34259 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ4_RT_OFFSET 34260 +#define PBF_REG_BTB_GUARANTEED_VOQ4_RT_OFFSET 34261 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ4_RT_OFFSET 34262 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ5_RT_OFFSET 34263 +#define PBF_REG_BTB_GUARANTEED_VOQ5_RT_OFFSET 34264 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ5_RT_OFFSET 34265 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ6_RT_OFFSET 34266 +#define PBF_REG_BTB_GUARANTEED_VOQ6_RT_OFFSET 34267 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ6_RT_OFFSET 34268 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ7_RT_OFFSET 34269 +#define PBF_REG_BTB_GUARANTEED_VOQ7_RT_OFFSET 34270 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ7_RT_OFFSET 34271 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ8_RT_OFFSET 34272 +#define PBF_REG_BTB_GUARANTEED_VOQ8_RT_OFFSET 34273 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ8_RT_OFFSET 34274 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ9_RT_OFFSET 34275 +#define PBF_REG_BTB_GUARANTEED_VOQ9_RT_OFFSET 34276 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ9_RT_OFFSET 34277 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ10_RT_OFFSET 34278 +#define PBF_REG_BTB_GUARANTEED_VOQ10_RT_OFFSET 34279 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ10_RT_OFFSET 34280 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ11_RT_OFFSET 34281 +#define PBF_REG_BTB_GUARANTEED_VOQ11_RT_OFFSET 34282 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ11_RT_OFFSET 34283 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ12_RT_OFFSET 34284 +#define PBF_REG_BTB_GUARANTEED_VOQ12_RT_OFFSET 34285 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ12_RT_OFFSET 34286 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ13_RT_OFFSET 34287 +#define PBF_REG_BTB_GUARANTEED_VOQ13_RT_OFFSET 34288 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ13_RT_OFFSET 34289 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ14_RT_OFFSET 34290 +#define PBF_REG_BTB_GUARANTEED_VOQ14_RT_OFFSET 34291 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ14_RT_OFFSET 34292 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ15_RT_OFFSET 34293 +#define PBF_REG_BTB_GUARANTEED_VOQ15_RT_OFFSET 34294 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ15_RT_OFFSET 34295 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ16_RT_OFFSET 34296 +#define PBF_REG_BTB_GUARANTEED_VOQ16_RT_OFFSET 34297 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ16_RT_OFFSET 34298 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ17_RT_OFFSET 34299 +#define PBF_REG_BTB_GUARANTEED_VOQ17_RT_OFFSET 34300 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ17_RT_OFFSET 34301 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ18_RT_OFFSET 34302 +#define PBF_REG_BTB_GUARANTEED_VOQ18_RT_OFFSET 34303 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ18_RT_OFFSET 34304 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ19_RT_OFFSET 34305 +#define PBF_REG_BTB_GUARANTEED_VOQ19_RT_OFFSET 34306 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ19_RT_OFFSET 34307 +#define XCM_REG_CON_PHY_Q3_RT_OFFSET 34308 + +#define RUNTIME_ARRAY_SIZE 34309 /* The eth storm context for the Tstorm */ struct tstorm_eth_conn_st_ctx { @@ -4307,7 +4610,7 @@ struct xstorm_eth_conn_ag_ctx { #define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_SHIFT 6 u8 edpm_event_id; __le16 physical_q0; - __le16 quota; + __le16 ereserved1; __le16 edpm_num_bds; __le16 tx_bd_cons; __le16 tx_bd_prod; @@ -4340,7 +4643,7 @@ struct xstorm_eth_conn_ag_ctx { u8 byte13; u8 byte14; u8 byte15; - u8 byte16; + u8 ereserved; __le16 word11; __le32 reg10; __le32 reg11; @@ -4627,6 +4930,7 @@ enum eth_error_code { ETH_FILTERS_PAIR_ADD_FAIL_ZERO_MAC, ETH_FILTERS_VNI_ADD_FAIL_FULL, ETH_FILTERS_VNI_ADD_FAIL_DUP, + ETH_FILTERS_GFT_UPDATE_FAIL, MAX_ETH_ERROR_CODE }; @@ -4879,6 +5183,39 @@ enum gft_logic_filter_type { MAX_GFT_LOGIC_FILTER_TYPE }; +struct rx_add_openflow_filter_data { + __le16 action_icid; + u8 priority; + u8 reserved0; + __le32 tenant_id; + __le16 dst_mac_hi; + __le16 dst_mac_mid; + __le16 dst_mac_lo; + __le16 src_mac_hi; + __le16 src_mac_mid; + __le16 src_mac_lo; + __le16 vlan_id; + __le16 l2_eth_type; + u8 ipv4_dscp; + u8 ipv4_frag_type; + u8 ipv4_over_ip; + u8 tenant_id_exists; + __le32 ipv4_dst_addr; + __le32 ipv4_src_addr; + __le16 l4_dst_port; + __le16 l4_src_port; +}; + +struct rx_create_gft_action_data { + u8 vport_id; + u8 reserved[7]; +}; + +struct rx_create_openflow_action_data { + u8 vport_id; + u8 reserved[7]; +}; + /* Ramrod data for rx queue start ramrod */ struct rx_queue_start_ramrod_data { __le16 rx_queue_id; @@ -4956,7 +5293,7 @@ struct rx_update_gft_filter_data { u8 vport_id; u8 filter_type; u8 filter_action; - u8 reserved; + u8 assert_on_error; }; /* Ramrod data for rx queue start ramrod */ @@ -5102,203 +5439,6 @@ struct vport_update_ramrod_data { struct eth_vport_rss_config rss_config; }; -struct gft_cam_line { - __le32 camline; -#define GFT_CAM_LINE_VALID_MASK 0x1 -#define GFT_CAM_LINE_VALID_SHIFT 0 -#define GFT_CAM_LINE_DATA_MASK 0x3FFF -#define GFT_CAM_LINE_DATA_SHIFT 1 -#define GFT_CAM_LINE_MASK_BITS_MASK 0x3FFF -#define GFT_CAM_LINE_MASK_BITS_SHIFT 15 -#define GFT_CAM_LINE_RESERVED1_MASK 0x7 -#define GFT_CAM_LINE_RESERVED1_SHIFT 29 -}; - -struct gft_cam_line_mapped { - __le32 camline; -#define GFT_CAM_LINE_MAPPED_VALID_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_VALID_SHIFT 0 -#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_IP_VERSION_SHIFT 1 -#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_SHIFT 2 -#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK 0xF -#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_SHIFT 3 -#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK 0xF -#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_SHIFT 7 -#define GFT_CAM_LINE_MAPPED_PF_ID_MASK 0xF -#define GFT_CAM_LINE_MAPPED_PF_ID_SHIFT 11 -#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_SHIFT 15 -#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_MASK 0x1 -#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_SHIFT 16 -#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_MASK 0xF -#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_SHIFT 17 -#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_MASK 0xF -#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_SHIFT 21 -#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_MASK 0xF -#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_SHIFT 25 -#define GFT_CAM_LINE_MAPPED_RESERVED1_MASK 0x7 -#define GFT_CAM_LINE_MAPPED_RESERVED1_SHIFT 29 -}; - -union gft_cam_line_union { - struct gft_cam_line cam_line; - struct gft_cam_line_mapped cam_line_mapped; -}; - -enum gft_profile_ip_version { - GFT_PROFILE_IPV4 = 0, - GFT_PROFILE_IPV6 = 1, - MAX_GFT_PROFILE_IP_VERSION -}; - -enum gft_profile_upper_protocol_type { - GFT_PROFILE_ROCE_PROTOCOL = 0, - GFT_PROFILE_RROCE_PROTOCOL = 1, - GFT_PROFILE_FCOE_PROTOCOL = 2, - GFT_PROFILE_ICMP_PROTOCOL = 3, - GFT_PROFILE_ARP_PROTOCOL = 4, - GFT_PROFILE_USER_TCP_SRC_PORT_1_INNER = 5, - GFT_PROFILE_USER_TCP_DST_PORT_1_INNER = 6, - GFT_PROFILE_TCP_PROTOCOL = 7, - GFT_PROFILE_USER_UDP_DST_PORT_1_INNER = 8, - GFT_PROFILE_USER_UDP_DST_PORT_2_OUTER = 9, - GFT_PROFILE_UDP_PROTOCOL = 10, - GFT_PROFILE_USER_IP_1_INNER = 11, - GFT_PROFILE_USER_IP_2_OUTER = 12, - GFT_PROFILE_USER_ETH_1_INNER = 13, - GFT_PROFILE_USER_ETH_2_OUTER = 14, - GFT_PROFILE_RAW = 15, - MAX_GFT_PROFILE_UPPER_PROTOCOL_TYPE -}; - -struct gft_ram_line { - __le32 low32bits; -#define GFT_RAM_LINE_VLAN_SELECT_MASK 0x3 -#define GFT_RAM_LINE_VLAN_SELECT_SHIFT 0 -#define GFT_RAM_LINE_TUNNEL_ENTROPHY_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_ENTROPHY_SHIFT 2 -#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_SHIFT 3 -#define GFT_RAM_LINE_TUNNEL_TTL_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_TTL_SHIFT 4 -#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_SHIFT 5 -#define GFT_RAM_LINE_TUNNEL_DST_PORT_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_DST_PORT_SHIFT 6 -#define GFT_RAM_LINE_TUNNEL_SRC_PORT_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_SRC_PORT_SHIFT 7 -#define GFT_RAM_LINE_TUNNEL_DSCP_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_DSCP_SHIFT 8 -#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_SHIFT 9 -#define GFT_RAM_LINE_TUNNEL_DST_IP_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_DST_IP_SHIFT 10 -#define GFT_RAM_LINE_TUNNEL_SRC_IP_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_SRC_IP_SHIFT 11 -#define GFT_RAM_LINE_TUNNEL_PRIORITY_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_PRIORITY_SHIFT 12 -#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_SHIFT 13 -#define GFT_RAM_LINE_TUNNEL_VLAN_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_VLAN_SHIFT 14 -#define GFT_RAM_LINE_TUNNEL_DST_MAC_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_DST_MAC_SHIFT 15 -#define GFT_RAM_LINE_TUNNEL_SRC_MAC_MASK 0x1 -#define GFT_RAM_LINE_TUNNEL_SRC_MAC_SHIFT 16 -#define GFT_RAM_LINE_TTL_EQUAL_ONE_MASK 0x1 -#define GFT_RAM_LINE_TTL_EQUAL_ONE_SHIFT 17 -#define GFT_RAM_LINE_TTL_MASK 0x1 -#define GFT_RAM_LINE_TTL_SHIFT 18 -#define GFT_RAM_LINE_ETHERTYPE_MASK 0x1 -#define GFT_RAM_LINE_ETHERTYPE_SHIFT 19 -#define GFT_RAM_LINE_RESERVED0_MASK 0x1 -#define GFT_RAM_LINE_RESERVED0_SHIFT 20 -#define GFT_RAM_LINE_TCP_FLAG_FIN_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_FIN_SHIFT 21 -#define GFT_RAM_LINE_TCP_FLAG_SYN_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_SYN_SHIFT 22 -#define GFT_RAM_LINE_TCP_FLAG_RST_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_RST_SHIFT 23 -#define GFT_RAM_LINE_TCP_FLAG_PSH_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_PSH_SHIFT 24 -#define GFT_RAM_LINE_TCP_FLAG_ACK_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_ACK_SHIFT 25 -#define GFT_RAM_LINE_TCP_FLAG_URG_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_URG_SHIFT 26 -#define GFT_RAM_LINE_TCP_FLAG_ECE_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_ECE_SHIFT 27 -#define GFT_RAM_LINE_TCP_FLAG_CWR_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_CWR_SHIFT 28 -#define GFT_RAM_LINE_TCP_FLAG_NS_MASK 0x1 -#define GFT_RAM_LINE_TCP_FLAG_NS_SHIFT 29 -#define GFT_RAM_LINE_DST_PORT_MASK 0x1 -#define GFT_RAM_LINE_DST_PORT_SHIFT 30 -#define GFT_RAM_LINE_SRC_PORT_MASK 0x1 -#define GFT_RAM_LINE_SRC_PORT_SHIFT 31 - __le32 high32bits; -#define GFT_RAM_LINE_DSCP_MASK 0x1 -#define GFT_RAM_LINE_DSCP_SHIFT 0 -#define GFT_RAM_LINE_OVER_IP_PROTOCOL_MASK 0x1 -#define GFT_RAM_LINE_OVER_IP_PROTOCOL_SHIFT 1 -#define GFT_RAM_LINE_DST_IP_MASK 0x1 -#define GFT_RAM_LINE_DST_IP_SHIFT 2 -#define GFT_RAM_LINE_SRC_IP_MASK 0x1 -#define GFT_RAM_LINE_SRC_IP_SHIFT 3 -#define GFT_RAM_LINE_PRIORITY_MASK 0x1 -#define GFT_RAM_LINE_PRIORITY_SHIFT 4 -#define GFT_RAM_LINE_PROVIDER_VLAN_MASK 0x1 -#define GFT_RAM_LINE_PROVIDER_VLAN_SHIFT 5 -#define GFT_RAM_LINE_VLAN_MASK 0x1 -#define GFT_RAM_LINE_VLAN_SHIFT 6 -#define GFT_RAM_LINE_DST_MAC_MASK 0x1 -#define GFT_RAM_LINE_DST_MAC_SHIFT 7 -#define GFT_RAM_LINE_SRC_MAC_MASK 0x1 -#define GFT_RAM_LINE_SRC_MAC_SHIFT 8 -#define GFT_RAM_LINE_TENANT_ID_MASK 0x1 -#define GFT_RAM_LINE_TENANT_ID_SHIFT 9 -#define GFT_RAM_LINE_RESERVED1_MASK 0x3FFFFF -#define GFT_RAM_LINE_RESERVED1_SHIFT 10 -}; - -struct mstorm_eth_conn_ag_ctx { - u8 byte0; - u8 byte1; - u8 flags0; -#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 -#define MSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 -#define MSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 -#define MSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 2 -#define MSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 -#define MSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 4 -#define MSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 -#define MSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 - u8 flags1; -#define MSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 0 -#define MSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 1 -#define MSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 -#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 3 -#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 4 -#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 5 -#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 6 -#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 7 - __le16 word0; - __le16 word1; - __le32 reg0; - __le32 reg1; -}; - struct xstorm_eth_conn_agctxdq_ext_ldpart { u8 reserved0; u8 eth_state; @@ -5511,7 +5651,7 @@ struct xstorm_eth_conn_agctxdq_ext_ldpart { #define XSTORMETHCONNAGCTXDQEXTLDPART_TPH_ENABLE_SHIFT 6 u8 edpm_event_id; __le16 physical_q0; - __le16 quota; + __le16 ereserved1; __le16 edpm_num_bds; __le16 tx_bd_cons; __le16 tx_bd_prod; @@ -5528,6 +5668,43 @@ struct xstorm_eth_conn_agctxdq_ext_ldpart { __le32 reg4; }; +struct mstorm_eth_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define MSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; +}; + struct xstorm_eth_hw_conn_ag_ctx { u8 reserved0; u8 eth_state; @@ -5740,7 +5917,7 @@ struct xstorm_eth_hw_conn_ag_ctx { #define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_SHIFT 6 u8 edpm_event_id; __le16 physical_q0; - __le16 quota; + __le16 ereserved1; __le16 edpm_num_bds; __le16 tx_bd_cons; __le16 tx_bd_prod; @@ -5748,32 +5925,226 @@ struct xstorm_eth_hw_conn_ag_ctx { __le16 conn_dpi; }; -struct mstorm_rdma_task_st_ctx { - struct regpair temp[4]; -}; - -struct rdma_close_func_ramrod_data { - u8 cnq_start_offset; - u8 num_cnqs; - u8 vf_id; - u8 vf_valid; - u8 reserved[4]; -}; - -struct rdma_cnq_params { - __le16 sb_num; - u8 sb_index; - u8 num_pbl_pages; - __le32 reserved; - struct regpair pbl_base_addr; - __le16 queue_zone_num; - u8 reserved1[6]; +struct gft_cam_line { + __le32 camline; +#define GFT_CAM_LINE_VALID_MASK 0x1 +#define GFT_CAM_LINE_VALID_SHIFT 0 +#define GFT_CAM_LINE_DATA_MASK 0x3FFF +#define GFT_CAM_LINE_DATA_SHIFT 1 +#define GFT_CAM_LINE_MASK_BITS_MASK 0x3FFF +#define GFT_CAM_LINE_MASK_BITS_SHIFT 15 +#define GFT_CAM_LINE_RESERVED1_MASK 0x7 +#define GFT_CAM_LINE_RESERVED1_SHIFT 29 }; -struct rdma_create_cq_ramrod_data { - struct regpair cq_handle; - struct regpair pbl_addr; - __le32 max_cqes; +struct gft_cam_line_mapped { + __le32 camline; +#define GFT_CAM_LINE_MAPPED_VALID_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_VALID_SHIFT 0 +#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_IP_VERSION_SHIFT 1 +#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_SHIFT 2 +#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK 0xF +#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_SHIFT 3 +#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK 0xF +#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_SHIFT 7 +#define GFT_CAM_LINE_MAPPED_PF_ID_MASK 0xF +#define GFT_CAM_LINE_MAPPED_PF_ID_SHIFT 11 +#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_IP_VERSION_MASK_SHIFT 15 +#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_MASK 0x1 +#define GFT_CAM_LINE_MAPPED_TUNNEL_IP_VERSION_MASK_SHIFT 16 +#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_MASK 0xF +#define GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_SHIFT 17 +#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_MASK 0xF +#define GFT_CAM_LINE_MAPPED_TUNNEL_TYPE_MASK_SHIFT 21 +#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_MASK 0xF +#define GFT_CAM_LINE_MAPPED_PF_ID_MASK_SHIFT 25 +#define GFT_CAM_LINE_MAPPED_RESERVED1_MASK 0x7 +#define GFT_CAM_LINE_MAPPED_RESERVED1_SHIFT 29 +}; + +union gft_cam_line_union { + struct gft_cam_line cam_line; + struct gft_cam_line_mapped cam_line_mapped; +}; + +enum gft_profile_ip_version { + GFT_PROFILE_IPV4 = 0, + GFT_PROFILE_IPV6 = 1, + MAX_GFT_PROFILE_IP_VERSION +}; + +struct gft_profile_key { + __le16 profile_key; +#define GFT_PROFILE_KEY_IP_VERSION_MASK 0x1 +#define GFT_PROFILE_KEY_IP_VERSION_SHIFT 0 +#define GFT_PROFILE_KEY_TUNNEL_IP_VERSION_MASK 0x1 +#define GFT_PROFILE_KEY_TUNNEL_IP_VERSION_SHIFT 1 +#define GFT_PROFILE_KEY_UPPER_PROTOCOL_TYPE_MASK 0xF +#define GFT_PROFILE_KEY_UPPER_PROTOCOL_TYPE_SHIFT 2 +#define GFT_PROFILE_KEY_TUNNEL_TYPE_MASK 0xF +#define GFT_PROFILE_KEY_TUNNEL_TYPE_SHIFT 6 +#define GFT_PROFILE_KEY_PF_ID_MASK 0xF +#define GFT_PROFILE_KEY_PF_ID_SHIFT 10 +#define GFT_PROFILE_KEY_RESERVED0_MASK 0x3 +#define GFT_PROFILE_KEY_RESERVED0_SHIFT 14 +}; + +enum gft_profile_tunnel_type { + GFT_PROFILE_NO_TUNNEL = 0, + GFT_PROFILE_VXLAN_TUNNEL = 1, + GFT_PROFILE_GRE_MAC_OR_NVGRE_TUNNEL = 2, + GFT_PROFILE_GRE_IP_TUNNEL = 3, + GFT_PROFILE_GENEVE_MAC_TUNNEL = 4, + GFT_PROFILE_GENEVE_IP_TUNNEL = 5, + MAX_GFT_PROFILE_TUNNEL_TYPE +}; + +enum gft_profile_upper_protocol_type { + GFT_PROFILE_ROCE_PROTOCOL = 0, + GFT_PROFILE_RROCE_PROTOCOL = 1, + GFT_PROFILE_FCOE_PROTOCOL = 2, + GFT_PROFILE_ICMP_PROTOCOL = 3, + GFT_PROFILE_ARP_PROTOCOL = 4, + GFT_PROFILE_USER_TCP_SRC_PORT_1_INNER = 5, + GFT_PROFILE_USER_TCP_DST_PORT_1_INNER = 6, + GFT_PROFILE_TCP_PROTOCOL = 7, + GFT_PROFILE_USER_UDP_DST_PORT_1_INNER = 8, + GFT_PROFILE_USER_UDP_DST_PORT_2_OUTER = 9, + GFT_PROFILE_UDP_PROTOCOL = 10, + GFT_PROFILE_USER_IP_1_INNER = 11, + GFT_PROFILE_USER_IP_2_OUTER = 12, + GFT_PROFILE_USER_ETH_1_INNER = 13, + GFT_PROFILE_USER_ETH_2_OUTER = 14, + GFT_PROFILE_RAW = 15, + MAX_GFT_PROFILE_UPPER_PROTOCOL_TYPE +}; + +struct gft_ram_line { + __le32 lo; +#define GFT_RAM_LINE_VLAN_SELECT_MASK 0x3 +#define GFT_RAM_LINE_VLAN_SELECT_SHIFT 0 +#define GFT_RAM_LINE_TUNNEL_ENTROPHY_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_ENTROPHY_SHIFT 2 +#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_TTL_EQUAL_ONE_SHIFT 3 +#define GFT_RAM_LINE_TUNNEL_TTL_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_TTL_SHIFT 4 +#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_ETHERTYPE_SHIFT 5 +#define GFT_RAM_LINE_TUNNEL_DST_PORT_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_DST_PORT_SHIFT 6 +#define GFT_RAM_LINE_TUNNEL_SRC_PORT_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_SRC_PORT_SHIFT 7 +#define GFT_RAM_LINE_TUNNEL_DSCP_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_DSCP_SHIFT 8 +#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_OVER_IP_PROTOCOL_SHIFT 9 +#define GFT_RAM_LINE_TUNNEL_DST_IP_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_DST_IP_SHIFT 10 +#define GFT_RAM_LINE_TUNNEL_SRC_IP_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_SRC_IP_SHIFT 11 +#define GFT_RAM_LINE_TUNNEL_PRIORITY_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_PRIORITY_SHIFT 12 +#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_PROVIDER_VLAN_SHIFT 13 +#define GFT_RAM_LINE_TUNNEL_VLAN_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_VLAN_SHIFT 14 +#define GFT_RAM_LINE_TUNNEL_DST_MAC_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_DST_MAC_SHIFT 15 +#define GFT_RAM_LINE_TUNNEL_SRC_MAC_MASK 0x1 +#define GFT_RAM_LINE_TUNNEL_SRC_MAC_SHIFT 16 +#define GFT_RAM_LINE_TTL_EQUAL_ONE_MASK 0x1 +#define GFT_RAM_LINE_TTL_EQUAL_ONE_SHIFT 17 +#define GFT_RAM_LINE_TTL_MASK 0x1 +#define GFT_RAM_LINE_TTL_SHIFT 18 +#define GFT_RAM_LINE_ETHERTYPE_MASK 0x1 +#define GFT_RAM_LINE_ETHERTYPE_SHIFT 19 +#define GFT_RAM_LINE_RESERVED0_MASK 0x1 +#define GFT_RAM_LINE_RESERVED0_SHIFT 20 +#define GFT_RAM_LINE_TCP_FLAG_FIN_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_FIN_SHIFT 21 +#define GFT_RAM_LINE_TCP_FLAG_SYN_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_SYN_SHIFT 22 +#define GFT_RAM_LINE_TCP_FLAG_RST_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_RST_SHIFT 23 +#define GFT_RAM_LINE_TCP_FLAG_PSH_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_PSH_SHIFT 24 +#define GFT_RAM_LINE_TCP_FLAG_ACK_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_ACK_SHIFT 25 +#define GFT_RAM_LINE_TCP_FLAG_URG_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_URG_SHIFT 26 +#define GFT_RAM_LINE_TCP_FLAG_ECE_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_ECE_SHIFT 27 +#define GFT_RAM_LINE_TCP_FLAG_CWR_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_CWR_SHIFT 28 +#define GFT_RAM_LINE_TCP_FLAG_NS_MASK 0x1 +#define GFT_RAM_LINE_TCP_FLAG_NS_SHIFT 29 +#define GFT_RAM_LINE_DST_PORT_MASK 0x1 +#define GFT_RAM_LINE_DST_PORT_SHIFT 30 +#define GFT_RAM_LINE_SRC_PORT_MASK 0x1 +#define GFT_RAM_LINE_SRC_PORT_SHIFT 31 + __le32 hi; +#define GFT_RAM_LINE_DSCP_MASK 0x1 +#define GFT_RAM_LINE_DSCP_SHIFT 0 +#define GFT_RAM_LINE_OVER_IP_PROTOCOL_MASK 0x1 +#define GFT_RAM_LINE_OVER_IP_PROTOCOL_SHIFT 1 +#define GFT_RAM_LINE_DST_IP_MASK 0x1 +#define GFT_RAM_LINE_DST_IP_SHIFT 2 +#define GFT_RAM_LINE_SRC_IP_MASK 0x1 +#define GFT_RAM_LINE_SRC_IP_SHIFT 3 +#define GFT_RAM_LINE_PRIORITY_MASK 0x1 +#define GFT_RAM_LINE_PRIORITY_SHIFT 4 +#define GFT_RAM_LINE_PROVIDER_VLAN_MASK 0x1 +#define GFT_RAM_LINE_PROVIDER_VLAN_SHIFT 5 +#define GFT_RAM_LINE_VLAN_MASK 0x1 +#define GFT_RAM_LINE_VLAN_SHIFT 6 +#define GFT_RAM_LINE_DST_MAC_MASK 0x1 +#define GFT_RAM_LINE_DST_MAC_SHIFT 7 +#define GFT_RAM_LINE_SRC_MAC_MASK 0x1 +#define GFT_RAM_LINE_SRC_MAC_SHIFT 8 +#define GFT_RAM_LINE_TENANT_ID_MASK 0x1 +#define GFT_RAM_LINE_TENANT_ID_SHIFT 9 +#define GFT_RAM_LINE_RESERVED1_MASK 0x3FFFFF +#define GFT_RAM_LINE_RESERVED1_SHIFT 10 +}; + +enum gft_vlan_select { + INNER_PROVIDER_VLAN = 0, + INNER_VLAN = 1, + OUTER_PROVIDER_VLAN = 2, + OUTER_VLAN = 3, + MAX_GFT_VLAN_SELECT +}; + +struct mstorm_rdma_task_st_ctx { + struct regpair temp[4]; +}; + +struct rdma_close_func_ramrod_data { + u8 cnq_start_offset; + u8 num_cnqs; + u8 vf_id; + u8 vf_valid; + u8 reserved[4]; +}; + +struct rdma_cnq_params { + __le16 sb_num; + u8 sb_index; + u8 num_pbl_pages; + __le32 reserved; + struct regpair pbl_base_addr; + __le16 queue_zone_num; + u8 reserved1[6]; +}; + +struct rdma_create_cq_ramrod_data { + struct regpair cq_handle; + struct regpair pbl_addr; + __le32 max_cqes; __le16 pbl_num_pages; __le16 dpi; u8 is_two_level_pbl; @@ -5827,12 +6198,9 @@ struct rdma_init_func_hdr { u8 cnq_start_offset; u8 num_cnqs; u8 cq_ring_mode; - u8 cnp_vlan_priority; - __le32 cnp_send_timeout; - u8 cnp_dscp; u8 vf_id; u8 vf_valid; - u8 reserved[5]; + u8 reserved[3]; }; struct rdma_init_func_ramrod_data { @@ -5856,54 +6224,55 @@ enum rdma_ramrod_cmd_id { }; struct rdma_register_tid_ramrod_data { - __le32 flags; -#define RDMA_REGISTER_TID_RAMROD_DATA_MAX_ID_MASK 0x3FFFF -#define RDMA_REGISTER_TID_RAMROD_DATA_MAX_ID_SHIFT 0 -#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_MASK 0x1F -#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_SHIFT 18 -#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_SHIFT 23 -#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_SHIFT 24 -#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_SHIFT 25 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_SHIFT 26 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_SHIFT 27 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_SHIFT 28 -#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_SHIFT 29 -#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_SHIFT 30 -#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_SHIFT 31 + __le16 flags; +#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_MASK 0x1F +#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_SHIFT 0 +#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_SHIFT 5 +#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_SHIFT 6 +#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_SHIFT 7 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_SHIFT 8 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_SHIFT 9 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_SHIFT 10 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_SHIFT 11 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_SHIFT 12 +#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_SHIFT 13 +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED_MASK 0x3 +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED_SHIFT 14 u8 flags1; -#define RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG_MASK 0x1F +#define RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG_MASK 0x1F #define RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG_SHIFT 0 -#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_MASK 0x7 -#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_SHIFT 5 +#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_MASK 0x7 +#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_SHIFT 5 u8 flags2; -#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_SHIFT 0 -#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_MASK 0x1 -#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_SHIFT 1 -#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_MASK 0x3F -#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_SHIFT 2 +#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_SHIFT 0 +#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_SHIFT 1 +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_MASK 0x3F +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_SHIFT 2 u8 key; u8 length_hi; u8 vf_id; u8 vf_valid; __le16 pd; + __le16 reserved2; __le32 length_lo; __le32 itid; - __le32 reserved2; + __le32 reserved3; struct regpair va; struct regpair pbl_base; struct regpair dif_error_addr; struct regpair dif_runt_addr; - __le32 reserved3[2]; + __le32 reserved4[2]; }; struct rdma_resize_cq_output_params { @@ -6149,298 +6518,9 @@ enum rdma_tid_type { MAX_RDMA_TID_TYPE }; -struct mstorm_rdma_conn_ag_ctx { - u8 byte0; - u8 byte1; - u8 flags0; -#define MSTORM_RDMA_CONN_AG_CTX_BIT0_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_BIT0_SHIFT 0 -#define MSTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 -#define MSTORM_RDMA_CONN_AG_CTX_CF0_MASK 0x3 -#define MSTORM_RDMA_CONN_AG_CTX_CF0_SHIFT 2 -#define MSTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 -#define MSTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 4 -#define MSTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 -#define MSTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 6 - u8 flags1; -#define MSTORM_RDMA_CONN_AG_CTX_CF0EN_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_CF0EN_SHIFT 0 -#define MSTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 1 -#define MSTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 2 -#define MSTORM_RDMA_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_RULE0EN_SHIFT 3 -#define MSTORM_RDMA_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_RULE1EN_SHIFT 4 -#define MSTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 5 -#define MSTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 6 -#define MSTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define MSTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 7 - __le16 word0; - __le16 word1; - __le32 reg0; - __le32 reg1; -}; - -struct tstorm_rdma_conn_ag_ctx { +struct xstorm_roce_conn_ag_ctx_dq_ext_ld_part { u8 reserved0; - u8 byte1; - u8 flags0; -#define TSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 -#define TSTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 -#define TSTORM_RDMA_CONN_AG_CTX_BIT2_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_BIT2_SHIFT 2 -#define TSTORM_RDMA_CONN_AG_CTX_BIT3_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_BIT3_SHIFT 3 -#define TSTORM_RDMA_CONN_AG_CTX_BIT4_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_BIT4_SHIFT 4 -#define TSTORM_RDMA_CONN_AG_CTX_BIT5_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_BIT5_SHIFT 5 -#define TSTORM_RDMA_CONN_AG_CTX_CF0_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_CF0_SHIFT 6 - u8 flags1; -#define TSTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 0 -#define TSTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 2 -#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_SHIFT 4 -#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 6 - u8 flags2; -#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_SHIFT 0 -#define TSTORM_RDMA_CONN_AG_CTX_CF6_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_CF6_SHIFT 2 -#define TSTORM_RDMA_CONN_AG_CTX_CF7_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_CF7_SHIFT 4 -#define TSTORM_RDMA_CONN_AG_CTX_CF8_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_CF8_SHIFT 6 - u8 flags3; -#define TSTORM_RDMA_CONN_AG_CTX_CF9_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_CF9_SHIFT 0 -#define TSTORM_RDMA_CONN_AG_CTX_CF10_MASK 0x3 -#define TSTORM_RDMA_CONN_AG_CTX_CF10_SHIFT 2 -#define TSTORM_RDMA_CONN_AG_CTX_CF0EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_CF0EN_SHIFT 4 -#define TSTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 5 -#define TSTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 6 -#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_SHIFT 7 - u8 flags4; -#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 0 -#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_SHIFT 1 -#define TSTORM_RDMA_CONN_AG_CTX_CF6EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_CF6EN_SHIFT 2 -#define TSTORM_RDMA_CONN_AG_CTX_CF7EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_CF7EN_SHIFT 3 -#define TSTORM_RDMA_CONN_AG_CTX_CF8EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_CF8EN_SHIFT 4 -#define TSTORM_RDMA_CONN_AG_CTX_CF9EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_CF9EN_SHIFT 5 -#define TSTORM_RDMA_CONN_AG_CTX_CF10EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_CF10EN_SHIFT 6 -#define TSTORM_RDMA_CONN_AG_CTX_RULE0EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE0EN_SHIFT 7 - u8 flags5; -#define TSTORM_RDMA_CONN_AG_CTX_RULE1EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE1EN_SHIFT 0 -#define TSTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 2 -#define TSTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 3 -#define TSTORM_RDMA_CONN_AG_CTX_RULE5EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE5EN_SHIFT 4 -#define TSTORM_RDMA_CONN_AG_CTX_RULE6EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE6EN_SHIFT 5 -#define TSTORM_RDMA_CONN_AG_CTX_RULE7EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE7EN_SHIFT 6 -#define TSTORM_RDMA_CONN_AG_CTX_RULE8EN_MASK 0x1 -#define TSTORM_RDMA_CONN_AG_CTX_RULE8EN_SHIFT 7 - __le32 reg0; - __le32 reg1; - __le32 reg2; - __le32 reg3; - __le32 reg4; - __le32 reg5; - __le32 reg6; - __le32 reg7; - __le32 reg8; - u8 byte2; - u8 byte3; - __le16 word0; - u8 byte4; - u8 byte5; - __le16 word1; - __le16 word2; - __le16 word3; - __le32 reg9; - __le32 reg10; -}; - -struct tstorm_rdma_task_ag_ctx { - u8 byte0; - u8 byte1; - __le16 word0; - u8 flags0; -#define TSTORM_RDMA_TASK_AG_CTX_NIBBLE0_MASK 0xF -#define TSTORM_RDMA_TASK_AG_CTX_NIBBLE0_SHIFT 0 -#define TSTORM_RDMA_TASK_AG_CTX_BIT0_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_BIT0_SHIFT 4 -#define TSTORM_RDMA_TASK_AG_CTX_BIT1_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_BIT1_SHIFT 5 -#define TSTORM_RDMA_TASK_AG_CTX_BIT2_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_BIT2_SHIFT 6 -#define TSTORM_RDMA_TASK_AG_CTX_BIT3_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_BIT3_SHIFT 7 - u8 flags1; -#define TSTORM_RDMA_TASK_AG_CTX_BIT4_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_BIT4_SHIFT 0 -#define TSTORM_RDMA_TASK_AG_CTX_BIT5_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_BIT5_SHIFT 1 -#define TSTORM_RDMA_TASK_AG_CTX_CF0_MASK 0x3 -#define TSTORM_RDMA_TASK_AG_CTX_CF0_SHIFT 2 -#define TSTORM_RDMA_TASK_AG_CTX_CF1_MASK 0x3 -#define TSTORM_RDMA_TASK_AG_CTX_CF1_SHIFT 4 -#define TSTORM_RDMA_TASK_AG_CTX_CF2_MASK 0x3 -#define TSTORM_RDMA_TASK_AG_CTX_CF2_SHIFT 6 - u8 flags2; -#define TSTORM_RDMA_TASK_AG_CTX_CF3_MASK 0x3 -#define TSTORM_RDMA_TASK_AG_CTX_CF3_SHIFT 0 -#define TSTORM_RDMA_TASK_AG_CTX_CF4_MASK 0x3 -#define TSTORM_RDMA_TASK_AG_CTX_CF4_SHIFT 2 -#define TSTORM_RDMA_TASK_AG_CTX_CF5_MASK 0x3 -#define TSTORM_RDMA_TASK_AG_CTX_CF5_SHIFT 4 -#define TSTORM_RDMA_TASK_AG_CTX_CF6_MASK 0x3 -#define TSTORM_RDMA_TASK_AG_CTX_CF6_SHIFT 6 - u8 flags3; -#define TSTORM_RDMA_TASK_AG_CTX_CF7_MASK 0x3 -#define TSTORM_RDMA_TASK_AG_CTX_CF7_SHIFT 0 -#define TSTORM_RDMA_TASK_AG_CTX_CF0EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_CF0EN_SHIFT 2 -#define TSTORM_RDMA_TASK_AG_CTX_CF1EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_CF1EN_SHIFT 3 -#define TSTORM_RDMA_TASK_AG_CTX_CF2EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_CF2EN_SHIFT 4 -#define TSTORM_RDMA_TASK_AG_CTX_CF3EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_CF3EN_SHIFT 5 -#define TSTORM_RDMA_TASK_AG_CTX_CF4EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_CF4EN_SHIFT 6 -#define TSTORM_RDMA_TASK_AG_CTX_CF5EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_CF5EN_SHIFT 7 - u8 flags4; -#define TSTORM_RDMA_TASK_AG_CTX_CF6EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_CF6EN_SHIFT 0 -#define TSTORM_RDMA_TASK_AG_CTX_CF7EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_CF7EN_SHIFT 1 -#define TSTORM_RDMA_TASK_AG_CTX_RULE0EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_RULE0EN_SHIFT 2 -#define TSTORM_RDMA_TASK_AG_CTX_RULE1EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_RULE1EN_SHIFT 3 -#define TSTORM_RDMA_TASK_AG_CTX_RULE2EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_RULE2EN_SHIFT 4 -#define TSTORM_RDMA_TASK_AG_CTX_RULE3EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_RULE3EN_SHIFT 5 -#define TSTORM_RDMA_TASK_AG_CTX_RULE4EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_RULE4EN_SHIFT 6 -#define TSTORM_RDMA_TASK_AG_CTX_RULE5EN_MASK 0x1 -#define TSTORM_RDMA_TASK_AG_CTX_RULE5EN_SHIFT 7 - u8 byte2; - __le16 word1; - __le32 reg0; - u8 byte3; - u8 byte4; - __le16 word2; - __le16 word3; - __le16 word4; - __le32 reg1; - __le32 reg2; -}; - -struct ustorm_rdma_conn_ag_ctx { - u8 reserved; - u8 byte1; - u8 flags0; -#define USTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 -#define USTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 -#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 -#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 2 -#define USTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 -#define USTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 4 -#define USTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 -#define USTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 6 - u8 flags1; -#define USTORM_RDMA_CONN_AG_CTX_CF3_MASK 0x3 -#define USTORM_RDMA_CONN_AG_CTX_CF3_SHIFT 0 -#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_MASK 0x3 -#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_SHIFT 2 -#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_MASK 0x3 -#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_SHIFT 4 -#define USTORM_RDMA_CONN_AG_CTX_CF6_MASK 0x3 -#define USTORM_RDMA_CONN_AG_CTX_CF6_SHIFT 6 - u8 flags2; -#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 0 -#define USTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 1 -#define USTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 2 -#define USTORM_RDMA_CONN_AG_CTX_CF3EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_CF3EN_SHIFT 3 -#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_EN_SHIFT 4 -#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_EN_SHIFT 5 -#define USTORM_RDMA_CONN_AG_CTX_CF6EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_CF6EN_SHIFT 6 -#define USTORM_RDMA_CONN_AG_CTX_CQ_SE_EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_CQ_SE_EN_SHIFT 7 - u8 flags3; -#define USTORM_RDMA_CONN_AG_CTX_CQ_EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_CQ_EN_SHIFT 0 -#define USTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 1 -#define USTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 2 -#define USTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 3 -#define USTORM_RDMA_CONN_AG_CTX_RULE5EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_RULE5EN_SHIFT 4 -#define USTORM_RDMA_CONN_AG_CTX_RULE6EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_RULE6EN_SHIFT 5 -#define USTORM_RDMA_CONN_AG_CTX_RULE7EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_RULE7EN_SHIFT 6 -#define USTORM_RDMA_CONN_AG_CTX_RULE8EN_MASK 0x1 -#define USTORM_RDMA_CONN_AG_CTX_RULE8EN_SHIFT 7 - u8 byte2; - u8 byte3; - __le16 conn_dpi; - __le16 word1; - __le32 cq_cons; - __le32 cq_se_prod; - __le32 cq_prod; - __le32 reg3; - __le16 int_timeout; - __le16 word3; -}; - -struct xstorm_roce_conn_ag_ctx_dq_ext_ld_part { - u8 reserved0; - u8 state; + u8 state; u8 flags0; #define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM0_MASK 0x1 #define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM0_SHIFT 0 @@ -6469,8 +6549,8 @@ struct xstorm_roce_conn_ag_ctx_dq_ext_ld_part { #define XSTORMROCECONNAGCTXDQEXTLDPART_BIT11_SHIFT 3 #define XSTORMROCECONNAGCTXDQEXTLDPART_BIT12_MASK 0x1 #define XSTORMROCECONNAGCTXDQEXTLDPART_BIT12_SHIFT 4 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT13_MASK 0x1 -#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT13_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_MSTORM_FLUSH_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_MSTORM_FLUSH_SHIFT 5 #define XSTORMROCECONNAGCTXDQEXTLDPART_BIT14_MASK 0x1 #define XSTORMROCECONNAGCTXDQEXTLDPART_BIT14_SHIFT 6 #define XSTORMROCECONNAGCTXDQEXTLDPART_YSTORM_FLUSH_MASK 0x1 @@ -6647,22 +6727,311 @@ struct xstorm_roce_conn_ag_ctx_dq_ext_ld_part { #define XSTORMROCECONNAGCTXDQEXTLDPART_CF23_MASK 0x3 #define XSTORMROCECONNAGCTXDQEXTLDPART_CF23_SHIFT 6 u8 byte2; - __le16 physical_q0; + __le16 physical_q0; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le16 word5; + __le16 conn_dpi; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 snd_nxt_psn; + __le32 reg4; +}; + +struct mstorm_rdma_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define MSTORM_RDMA_CONN_AG_CTX_BIT0_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_BIT0_SHIFT 0 +#define MSTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_RDMA_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_RDMA_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_RDMA_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_RDMA_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_RDMA_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; +}; + +struct tstorm_rdma_conn_ag_ctx { + u8 reserved0; + u8 byte1; + u8 flags0; +#define TSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_RDMA_CONN_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_BIT5_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_RDMA_CONN_AG_CTX_CF0_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF0_SHIFT 6 + u8 flags1; +#define TSTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 6 + u8 flags2; +#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_CF6_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_CF7_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_CF8_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF8_SHIFT 6 + u8 flags3; +#define TSTORM_RDMA_CONN_AG_CTX_CF9_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF9_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_CF10_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 6 +#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_SHIFT 7 + u8 flags4; +#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_SHIFT 1 +#define TSTORM_RDMA_CONN_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_RDMA_CONN_AG_CTX_CF8EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_CF9EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF9EN_SHIFT 5 +#define TSTORM_RDMA_CONN_AG_CTX_CF10EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_RDMA_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags5; +#define TSTORM_RDMA_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_RDMA_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define TSTORM_RDMA_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_RDMA_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le32 reg7; + __le32 reg8; + u8 byte2; + u8 byte3; + __le16 word0; + u8 byte4; + u8 byte5; + __le16 word1; + __le16 word2; + __le16 word3; + __le32 reg9; + __le32 reg10; +}; + +struct tstorm_rdma_task_ag_ctx { + u8 byte0; + u8 byte1; + __le16 word0; + u8 flags0; +#define TSTORM_RDMA_TASK_AG_CTX_NIBBLE0_MASK 0xF +#define TSTORM_RDMA_TASK_AG_CTX_NIBBLE0_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_BIT0_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT0_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT1_SHIFT 5 +#define TSTORM_RDMA_TASK_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT2_SHIFT 6 +#define TSTORM_RDMA_TASK_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT3_SHIFT 7 + u8 flags1; +#define TSTORM_RDMA_TASK_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT4_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_BIT5_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT5_SHIFT 1 +#define TSTORM_RDMA_TASK_AG_CTX_CF0_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF0_SHIFT 2 +#define TSTORM_RDMA_TASK_AG_CTX_CF1_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF1_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_CF2_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF2_SHIFT 6 + u8 flags2; +#define TSTORM_RDMA_TASK_AG_CTX_CF3_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF3_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_CF4_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF4_SHIFT 2 +#define TSTORM_RDMA_TASK_AG_CTX_CF5_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF5_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_CF6_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF6_SHIFT 6 + u8 flags3; +#define TSTORM_RDMA_TASK_AG_CTX_CF7_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF7_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF0EN_SHIFT 2 +#define TSTORM_RDMA_TASK_AG_CTX_CF1EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF1EN_SHIFT 3 +#define TSTORM_RDMA_TASK_AG_CTX_CF2EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF2EN_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_CF3EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF3EN_SHIFT 5 +#define TSTORM_RDMA_TASK_AG_CTX_CF4EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF4EN_SHIFT 6 +#define TSTORM_RDMA_TASK_AG_CTX_CF5EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF5EN_SHIFT 7 + u8 flags4; +#define TSTORM_RDMA_TASK_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF6EN_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF7EN_SHIFT 1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE0EN_SHIFT 2 +#define TSTORM_RDMA_TASK_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE1EN_SHIFT 3 +#define TSTORM_RDMA_TASK_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE2EN_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE3EN_SHIFT 5 +#define TSTORM_RDMA_TASK_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE4EN_SHIFT 6 +#define TSTORM_RDMA_TASK_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE5EN_SHIFT 7 + u8 byte2; + __le16 word1; + __le32 reg0; + u8 byte3; + u8 byte4; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg1; + __le32 reg2; +}; + +struct ustorm_rdma_conn_ag_ctx { + u8 reserved; + u8 byte1; + u8 flags0; +#define USTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define USTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 2 +#define USTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define USTORM_RDMA_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_SHIFT 2 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_SHIFT 4 +#define USTORM_RDMA_CONN_AG_CTX_CF6_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CF6_SHIFT 6 + u8 flags2; +#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 0 +#define USTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_RDMA_CONN_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_EN_SHIFT 4 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_EN_SHIFT 5 +#define USTORM_RDMA_CONN_AG_CTX_CF6EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CF6EN_SHIFT 6 +#define USTORM_RDMA_CONN_AG_CTX_CQ_SE_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CQ_SE_EN_SHIFT 7 + u8 flags3; +#define USTORM_RDMA_CONN_AG_CTX_CQ_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CQ_EN_SHIFT 0 +#define USTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_RDMA_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_RDMA_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_RDMA_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_RDMA_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 conn_dpi; __le16 word1; - __le16 word2; + __le32 cq_cons; + __le32 cq_se_prod; + __le32 cq_prod; + __le32 reg3; + __le16 int_timeout; __le16 word3; - __le16 word4; - __le16 word5; - __le16 conn_dpi; - u8 byte3; - u8 byte4; - u8 byte5; - u8 byte6; - __le32 reg0; - __le32 reg1; - __le32 reg2; - __le32 snd_nxt_psn; - __le32 reg4; }; struct xstorm_rdma_conn_ag_ctx { @@ -6696,8 +7065,8 @@ struct xstorm_rdma_conn_ag_ctx { #define XSTORM_RDMA_CONN_AG_CTX_BIT11_SHIFT 3 #define XSTORM_RDMA_CONN_AG_CTX_BIT12_MASK 0x1 #define XSTORM_RDMA_CONN_AG_CTX_BIT12_SHIFT 4 -#define XSTORM_RDMA_CONN_AG_CTX_BIT13_MASK 0x1 -#define XSTORM_RDMA_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_SHIFT 5 #define XSTORM_RDMA_CONN_AG_CTX_BIT14_MASK 0x1 #define XSTORM_RDMA_CONN_AG_CTX_BIT14_SHIFT 6 #define XSTORM_RDMA_CONN_AG_CTX_YSTORM_FLUSH_MASK 0x1 @@ -7093,16 +7462,35 @@ struct roce_destroy_qp_resp_ramrod_data { struct regpair output_params_addr; }; +struct roce_events_stats { + __le16 silent_drops; + __le16 rnr_naks_sent; + __le32 retransmit_count; + __le32 icrc_error_count; + __le32 reserved; +}; + enum roce_event_opcode { ROCE_EVENT_CREATE_QP = 11, ROCE_EVENT_MODIFY_QP, ROCE_EVENT_QUERY_QP, ROCE_EVENT_DESTROY_QP, + ROCE_EVENT_CREATE_UD_QP, + ROCE_EVENT_DESTROY_UD_QP, MAX_ROCE_EVENT_OPCODE }; +struct roce_init_func_params { + u8 ll2_queue_id; + u8 cnp_vlan_priority; + u8 cnp_dscp; + u8 reserved; + __le32 cnp_send_timeout; +}; + struct roce_init_func_ramrod_data { struct rdma_init_func_ramrod_data rdma; + struct roce_init_func_params roce; }; struct roce_modify_qp_req_ramrod_data { @@ -7222,6 +7610,8 @@ enum roce_ramrod_cmd_id { ROCE_RAMROD_MODIFY_QP, ROCE_RAMROD_QUERY_QP, ROCE_RAMROD_DESTROY_QP, + ROCE_RAMROD_CREATE_UD_QP, + ROCE_RAMROD_DESTROY_UD_QP, MAX_ROCE_RAMROD_CMD_ID }; @@ -7299,13 +7689,6 @@ struct mstorm_roce_resp_conn_ag_ctx { __le32 reg1; }; -enum roce_flavor { - PLAIN_ROCE /* RoCE v1 */ , - RROCE_IPV4 /* RoCE v2 (Routable RoCE) over ipv4 */ , - RROCE_IPV6 /* RoCE v2 (Routable RoCE) over ipv6 */ , - MAX_ROCE_FLAVOR -}; - struct tstorm_roce_req_conn_ag_ctx { u8 reserved0; u8 state; @@ -7416,8 +7799,8 @@ struct tstorm_roce_resp_conn_ag_ctx { u8 flags0; #define TSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 #define TSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 -#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_MASK 0x1 -#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_NOTIFY_REQUESTER_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_NOTIFY_REQUESTER_SHIFT 1 #define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT2_MASK 0x1 #define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT2_SHIFT 2 #define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT3_MASK 0x1 @@ -8097,7 +8480,7 @@ struct xstorm_roce_resp_conn_ag_ctx { __le16 irq_prod; __le16 word3; __le16 word4; - __le16 word5; + __le16 ereserved1; __le16 irq_cons; u8 rxmit_opcode; u8 byte4; @@ -8200,6 +8583,812 @@ struct ystorm_roce_resp_conn_ag_ctx { __le32 reg3; }; +enum roce_flavor { + PLAIN_ROCE, + RROCE_IPV4, + RROCE_IPV6, + MAX_ROCE_FLAVOR +}; + +struct ystorm_iwarp_conn_st_ctx { + __le32 reserved[4]; +}; + +struct pstorm_iwarp_conn_st_ctx { + __le32 reserved[36]; +}; + +struct xstorm_iwarp_conn_st_ctx { + __le32 reserved[44]; +}; + +struct xstorm_iwarp_conn_ag_ctx { + u8 reserved0; + u8 state; + u8 flags0; +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM1_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM1_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM2_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM2_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_BIT4_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT4_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RESERVED2_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_BIT6_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT6_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_BIT7_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT7_SHIFT 7 + u8 flags1; +#define XSTORM_IWARP_CONN_AG_CTX_BIT8_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT8_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_BIT9_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT9_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT10_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT10_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_BIT11_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_BIT12_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_BIT13_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_BIT14_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT14_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_YSTORM_FLUSH_OR_REWIND_SND_MAX_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_YSTORM_FLUSH_OR_REWIND_SND_MAX_SHIFT 7 + u8 flags2; +#define XSTORM_IWARP_CONN_AG_CTX_CF0_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF1_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF2_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_SHIFT 6 + u8 flags3; +#define XSTORM_IWARP_CONN_AG_CTX_CF4_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF4_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF5_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF5_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF6_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF6_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF7_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF7_SHIFT 6 + u8 flags4; +#define XSTORM_IWARP_CONN_AG_CTX_CF8_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF9_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF10_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF11_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF11_SHIFT 6 + u8 flags5; +#define XSTORM_IWARP_CONN_AG_CTX_CF12_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF13_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FLUSH_CF_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FLUSH_CF_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF15_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF15_SHIFT 6 + u8 flags6; +#define XSTORM_IWARP_CONN_AG_CTX_MPA_OR_ERROR_WAKEUP_TRIGGER_CF_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_MPA_OR_ERROR_WAKEUP_TRIGGER_CF_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF17_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF17_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF18_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF18_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_DQ_FLUSH_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_DQ_FLUSH_SHIFT 6 + u8 flags7; +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q1_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q1_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_SLOW_PATH_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORM_IWARP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_CF4EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF4EN_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF5EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF5EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_CF6EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF6EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF7EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF7EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_CF8EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_CF9EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORM_IWARP_CONN_AG_CTX_CF10EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_CF11EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_CF12EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_CF13EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FLUSH_CF_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FLUSH_CF_EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF15EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_MPA_OR_ERROR_WAKEUP_TRIGGER_CF_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_MPA_OR_ERROR_WAKEUP_TRIGGER_CF_EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_CF17EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF17EN_SHIFT 7 + u8 flags10; +#define XSTORM_IWARP_CONN_AG_CTX_CF18EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF18EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_DQ_FLUSH_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_DQ_FLUSH_EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q1_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_FLUSH_Q1_EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_CF23EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_CF23EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE0EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_MORE_TO_SEND_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_MORE_TO_SEND_RULE_EN_SHIFT 7 + u8 flags11; +#define XSTORM_IWARP_CONN_AG_CTX_TX_BLOCKED_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_TX_BLOCKED_EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE3EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_RESERVED3_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RESERVED3_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_RULE9EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORM_IWARP_CONN_AG_CTX_SQ_NOT_EMPTY_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_NOT_EMPTY_RULE_EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_RULE11EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FENCE_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_SQ_FENCE_RULE_EN_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_RULE15EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_RULE16EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_RULE17EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORM_IWARP_CONN_AG_CTX_IRQ_NOT_EMPTY_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_IRQ_NOT_EMPTY_RULE_EN_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_HQ_NOT_FULL_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_HQ_NOT_FULL_RULE_EN_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_ORQ_RD_FENCE_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_ORQ_RD_FENCE_RULE_EN_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_RULE21EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_RULE21EN_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_ORQ_NOT_FULL_RULE_EN_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_ORQ_NOT_FULL_RULE_EN_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORM_IWARP_CONN_AG_CTX_BIT16_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT16_SHIFT 0 +#define XSTORM_IWARP_CONN_AG_CTX_BIT17_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT17_SHIFT 1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT18_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_BIT18_SHIFT 2 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED1_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED1_SHIFT 3 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED2_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED2_SHIFT 4 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED3_MASK 0x1 +#define XSTORM_IWARP_CONN_AG_CTX_E5_RESERVED3_SHIFT 5 +#define XSTORM_IWARP_CONN_AG_CTX_CF23_MASK 0x3 +#define XSTORM_IWARP_CONN_AG_CTX_CF23_SHIFT 6 + u8 byte2; + __le16 physical_q0; + __le16 physical_q1; + __le16 sq_comp_cons; + __le16 sq_tx_cons; + __le16 sq_prod; + __le16 word5; + __le16 conn_dpi; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 more_to_send_seq; + __le32 reg4; + __le32 rewinded_snd_max; + __le32 rd_msn; + __le16 irq_prod_via_msdm; + __le16 irq_cons; + __le16 hq_cons_th_or_mpa_data; + __le16 hq_cons; + __le32 atom_msn; + __le32 orq_cons; + __le32 orq_cons_th; + u8 byte7; + u8 max_ord; + u8 wqe_data_pad_bytes; + u8 former_hq_prod; + u8 irq_prod_via_msem; + u8 byte12; + u8 max_pkt_pdu_size_lo; + u8 max_pkt_pdu_size_hi; + u8 byte15; + u8 e5_reserved; + __le16 e5_reserved4; + __le32 reg10; + __le32 reg11; + __le32 shared_queue_page_addr_lo; + __le32 shared_queue_page_addr_hi; + __le32 reg14; + __le32 reg15; + __le32 reg16; + __le32 reg17; +}; + +struct tstorm_iwarp_conn_ag_ctx { + u8 reserved0; + u8 state; + u8 flags0; +#define TSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_IWARP_CONN_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_MSTORM_FLUSH_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_MSTORM_FLUSH_SHIFT 3 +#define TSTORM_IWARP_CONN_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_CACHED_ORQ_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CACHED_ORQ_SHIFT 5 +#define TSTORM_IWARP_CONN_AG_CTX_CF0_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF0_SHIFT 6 + u8 flags1; +#define TSTORM_IWARP_CONN_AG_CTX_RQ_POST_CF_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_RQ_POST_CF_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_MPA_TIMEOUT_CF_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_MPA_TIMEOUT_CF_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_CF4_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF4_SHIFT 6 + u8 flags2; +#define TSTORM_IWARP_CONN_AG_CTX_CF5_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF5_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_CF6_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_CF7_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_CF8_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_CF8_SHIFT 6 + u8 flags3; +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_OR_ERROR_DETECTED_MASK 0x3 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_OR_ERROR_DETECTED_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_RQ_POST_CF_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RQ_POST_CF_EN_SHIFT 5 +#define TSTORM_IWARP_CONN_AG_CTX_MPA_TIMEOUT_CF_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_MPA_TIMEOUT_CF_EN_SHIFT 6 +#define TSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_TIMER_STOP_ALL_EN_SHIFT 7 + u8 flags4; +#define TSTORM_IWARP_CONN_AG_CTX_CF4EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF4EN_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_CF5EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF5EN_SHIFT 1 +#define TSTORM_IWARP_CONN_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_IWARP_CONN_AG_CTX_CF8EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 5 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_OR_ERROR_DETECTED_EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_FLUSH_OR_ERROR_DETECTED_EN_SHIFT 6 +#define TSTORM_IWARP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags5; +#define TSTORM_IWARP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_IWARP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_IWARP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_IWARP_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_IWARP_CONN_AG_CTX_SND_SQ_CONS_RULE_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_SND_SQ_CONS_RULE_SHIFT 5 +#define TSTORM_IWARP_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_IWARP_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define TSTORM_IWARP_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0; + __le32 reg1; + __le32 unaligned_nxt_seq; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le32 reg7; + __le32 reg8; + u8 orq_cache_idx; + u8 hq_prod; + __le16 sq_tx_cons_th; + u8 orq_prod; + u8 irq_cons; + __le16 sq_tx_cons; + __le16 conn_dpi; + __le16 rq_prod; + __le32 snd_seq; + __le32 last_hq_sequence; +}; + +struct tstorm_iwarp_conn_st_ctx { + __le32 reserved[60]; +}; + +struct mstorm_iwarp_conn_st_ctx { + __le32 reserved[32]; +}; + +struct ustorm_iwarp_conn_st_ctx { + __le32 reserved[24]; +}; + +struct iwarp_conn_context { + struct ystorm_iwarp_conn_st_ctx ystorm_st_context; + struct regpair ystorm_st_padding[2]; + struct pstorm_iwarp_conn_st_ctx pstorm_st_context; + struct regpair pstorm_st_padding[2]; + struct xstorm_iwarp_conn_st_ctx xstorm_st_context; + struct regpair xstorm_st_padding[2]; + struct xstorm_iwarp_conn_ag_ctx xstorm_ag_context; + struct tstorm_iwarp_conn_ag_ctx tstorm_ag_context; + struct timers_context timer_context; + struct ustorm_rdma_conn_ag_ctx ustorm_ag_context; + struct tstorm_iwarp_conn_st_ctx tstorm_st_context; + struct regpair tstorm_st_padding[2]; + struct mstorm_iwarp_conn_st_ctx mstorm_st_context; + struct ustorm_iwarp_conn_st_ctx ustorm_st_context; +}; + +struct iwarp_create_qp_ramrod_data { + u8 flags; +#define IWARP_CREATE_QP_RAMROD_DATA_FMR_AND_RESERVED_EN_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_FMR_AND_RESERVED_EN_SHIFT 0 +#define IWARP_CREATE_QP_RAMROD_DATA_SIGNALED_COMP_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_SIGNALED_COMP_SHIFT 1 +#define IWARP_CREATE_QP_RAMROD_DATA_RDMA_RD_EN_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_RDMA_RD_EN_SHIFT 2 +#define IWARP_CREATE_QP_RAMROD_DATA_RDMA_WR_EN_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_RDMA_WR_EN_SHIFT 3 +#define IWARP_CREATE_QP_RAMROD_DATA_ATOMIC_EN_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_ATOMIC_EN_SHIFT 4 +#define IWARP_CREATE_QP_RAMROD_DATA_SRQ_FLG_MASK 0x1 +#define IWARP_CREATE_QP_RAMROD_DATA_SRQ_FLG_SHIFT 5 +#define IWARP_CREATE_QP_RAMROD_DATA_RESERVED0_MASK 0x3 +#define IWARP_CREATE_QP_RAMROD_DATA_RESERVED0_SHIFT 6 + u8 reserved1; + __le16 pd; + __le16 sq_num_pages; + __le16 rq_num_pages; + __le32 reserved3[2]; + struct regpair qp_handle_for_cqe; + struct rdma_srq_id srq_id; + __le32 cq_cid_for_sq; + __le32 cq_cid_for_rq; + __le16 dpi; + __le16 physical_q0; + __le16 physical_q1; + u8 reserved2[6]; +}; + +enum iwarp_eqe_async_opcode { + IWARP_EVENT_TYPE_ASYNC_CONNECT_COMPLETE, + IWARP_EVENT_TYPE_ASYNC_ENHANCED_MPA_REPLY_ARRIVED, + IWARP_EVENT_TYPE_ASYNC_MPA_HANDSHAKE_COMPLETE, + IWARP_EVENT_TYPE_ASYNC_CID_CLEANED, + IWARP_EVENT_TYPE_ASYNC_EXCEPTION_DETECTED, + IWARP_EVENT_TYPE_ASYNC_QP_IN_ERROR_STATE, + IWARP_EVENT_TYPE_ASYNC_CQ_OVERFLOW, + MAX_IWARP_EQE_ASYNC_OPCODE +}; + +struct iwarp_eqe_data_mpa_async_completion { + __le16 ulp_data_len; + u8 reserved[6]; +}; + +struct iwarp_eqe_data_tcp_async_completion { + __le16 ulp_data_len; + u8 mpa_handshake_mode; + u8 reserved[5]; +}; + +enum iwarp_eqe_sync_opcode { + IWARP_EVENT_TYPE_TCP_OFFLOAD = + 11, + IWARP_EVENT_TYPE_MPA_OFFLOAD, + IWARP_EVENT_TYPE_MPA_OFFLOAD_SEND_RTR, + IWARP_EVENT_TYPE_CREATE_QP, + IWARP_EVENT_TYPE_QUERY_QP, + IWARP_EVENT_TYPE_MODIFY_QP, + IWARP_EVENT_TYPE_DESTROY_QP, + MAX_IWARP_EQE_SYNC_OPCODE +}; + +enum iwarp_fw_return_code { + IWARP_CONN_ERROR_TCP_CONNECT_INVALID_PACKET = 5, + IWARP_CONN_ERROR_TCP_CONNECTION_RST, + IWARP_CONN_ERROR_TCP_CONNECT_TIMEOUT, + IWARP_CONN_ERROR_MPA_ERROR_REJECT, + IWARP_CONN_ERROR_MPA_NOT_SUPPORTED_VER, + IWARP_CONN_ERROR_MPA_RST, + IWARP_CONN_ERROR_MPA_FIN, + IWARP_CONN_ERROR_MPA_RTR_MISMATCH, + IWARP_CONN_ERROR_MPA_INSUF_IRD, + IWARP_CONN_ERROR_MPA_INVALID_PACKET, + IWARP_CONN_ERROR_MPA_LOCAL_ERROR, + IWARP_CONN_ERROR_MPA_TIMEOUT, + IWARP_CONN_ERROR_MPA_TERMINATE, + IWARP_QP_IN_ERROR_GOOD_CLOSE, + IWARP_QP_IN_ERROR_BAD_CLOSE, + IWARP_EXCEPTION_DETECTED_LLP_CLOSED, + IWARP_EXCEPTION_DETECTED_LLP_RESET, + IWARP_EXCEPTION_DETECTED_IRQ_FULL, + IWARP_EXCEPTION_DETECTED_RQ_EMPTY, + IWARP_EXCEPTION_DETECTED_LLP_TIMEOUT, + IWARP_EXCEPTION_DETECTED_REMOTE_PROTECTION_ERROR, + IWARP_EXCEPTION_DETECTED_CQ_OVERFLOW, + IWARP_EXCEPTION_DETECTED_LOCAL_CATASTROPHIC, + IWARP_EXCEPTION_DETECTED_LOCAL_ACCESS_ERROR, + IWARP_EXCEPTION_DETECTED_REMOTE_OPERATION_ERROR, + IWARP_EXCEPTION_DETECTED_TERMINATE_RECEIVED, + MAX_IWARP_FW_RETURN_CODE +}; + +struct iwarp_init_func_params { + u8 ll2_ooo_q_index; + u8 reserved1[7]; +}; + +struct iwarp_init_func_ramrod_data { + struct rdma_init_func_ramrod_data rdma; + struct tcp_init_params tcp; + struct iwarp_init_func_params iwarp; +}; + +enum iwarp_modify_qp_new_state_type { + IWARP_MODIFY_QP_STATE_CLOSING = 1, + IWARP_MODIFY_QP_STATE_ERROR = + 2, + MAX_IWARP_MODIFY_QP_NEW_STATE_TYPE +}; + +struct iwarp_modify_qp_ramrod_data { + __le16 transition_to_state; + __le16 flags; +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_RD_EN_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_RD_EN_SHIFT 0 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_WR_EN_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_WR_EN_SHIFT 1 +#define IWARP_MODIFY_QP_RAMROD_DATA_ATOMIC_EN_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_ATOMIC_EN_SHIFT 2 +#define IWARP_MODIFY_QP_RAMROD_DATA_STATE_TRANS_EN_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_STATE_TRANS_EN_SHIFT 3 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_OPS_EN_FLG_MASK 0x1 +#define IWARP_MODIFY_QP_RAMROD_DATA_RDMA_OPS_EN_FLG_SHIFT 4 +#define IWARP_MODIFY_QP_RAMROD_DATA_RESERVED_MASK 0x7FF +#define IWARP_MODIFY_QP_RAMROD_DATA_RESERVED_SHIFT 5 + __le32 reserved3[3]; + __le32 reserved4[8]; +}; + +struct mpa_rq_params { + __le32 ird; + __le32 ord; +}; + +struct mpa_ulp_buffer { + struct regpair addr; + __le16 len; + __le16 reserved[3]; +}; + +struct mpa_outgoing_params { + u8 crc_needed; + u8 reject; + u8 reserved[6]; + struct mpa_rq_params out_rq; + struct mpa_ulp_buffer outgoing_ulp_buffer; +}; + +struct iwarp_mpa_offload_ramrod_data { + struct mpa_outgoing_params common; + __le32 tcp_cid; + u8 mode; + u8 tcp_connect_side; + u8 rtr_pref; +#define IWARP_MPA_OFFLOAD_RAMROD_DATA_RTR_SUPPORTED_MASK 0x7 +#define IWARP_MPA_OFFLOAD_RAMROD_DATA_RTR_SUPPORTED_SHIFT 0 +#define IWARP_MPA_OFFLOAD_RAMROD_DATA_RESERVED1_MASK 0x1F +#define IWARP_MPA_OFFLOAD_RAMROD_DATA_RESERVED1_SHIFT 3 + u8 reserved2; + struct mpa_ulp_buffer incoming_ulp_buffer; + struct regpair async_eqe_output_buf; + struct regpair handle_for_async; + struct regpair shared_queue_addr; + u8 stats_counter_id; + u8 reserved3[15]; +}; + +struct iwarp_offload_params { + struct mpa_ulp_buffer incoming_ulp_buffer; + struct regpair async_eqe_output_buf; + struct regpair handle_for_async; + __le16 physical_q0; + __le16 physical_q1; + u8 stats_counter_id; + u8 mpa_mode; + u8 reserved[10]; +}; + +struct iwarp_query_qp_output_params { + __le32 flags; +#define IWARP_QUERY_QP_OUTPUT_PARAMS_ERROR_FLG_MASK 0x1 +#define IWARP_QUERY_QP_OUTPUT_PARAMS_ERROR_FLG_SHIFT 0 +#define IWARP_QUERY_QP_OUTPUT_PARAMS_RESERVED0_MASK 0x7FFFFFFF +#define IWARP_QUERY_QP_OUTPUT_PARAMS_RESERVED0_SHIFT 1 + u8 reserved1[4]; +}; + +struct iwarp_query_qp_ramrod_data { + struct regpair output_params_addr; +}; + +enum iwarp_ramrod_cmd_id { + IWARP_RAMROD_CMD_ID_TCP_OFFLOAD = + 11, + IWARP_RAMROD_CMD_ID_MPA_OFFLOAD, + IWARP_RAMROD_CMD_ID_MPA_OFFLOAD_SEND_RTR, + IWARP_RAMROD_CMD_ID_CREATE_QP, + IWARP_RAMROD_CMD_ID_QUERY_QP, + IWARP_RAMROD_CMD_ID_MODIFY_QP, + IWARP_RAMROD_CMD_ID_DESTROY_QP, + MAX_IWARP_RAMROD_CMD_ID +}; + +struct iwarp_rxmit_stats_drv { + struct regpair tx_go_to_slow_start_event_cnt; + struct regpair tx_fast_retransmit_event_cnt; +}; + +struct iwarp_tcp_offload_ramrod_data { + struct iwarp_offload_params iwarp; + struct tcp_offload_params_opt2 tcp; +}; + +enum mpa_negotiation_mode { + MPA_NEGOTIATION_TYPE_BASIC = 1, + MPA_NEGOTIATION_TYPE_ENHANCED = 2, + MAX_MPA_NEGOTIATION_MODE +}; + +enum mpa_rtr_type { + MPA_RTR_TYPE_NONE = 0, + MPA_RTR_TYPE_ZERO_SEND = 1, + MPA_RTR_TYPE_ZERO_WRITE = 2, + MPA_RTR_TYPE_ZERO_SEND_AND_WRITE = 3, + MPA_RTR_TYPE_ZERO_READ = 4, + MPA_RTR_TYPE_ZERO_SEND_AND_READ = 5, + MPA_RTR_TYPE_ZERO_WRITE_AND_READ = 6, + MPA_RTR_TYPE_ZERO_SEND_AND_WRITE_AND_READ = 7, + MAX_MPA_RTR_TYPE +}; + +struct unaligned_opaque_data { + __le16 first_mpa_offset; + u8 tcp_payload_offset; + u8 flags; +#define UNALIGNED_OPAQUE_DATA_PKT_REACHED_WIN_RIGHT_EDGE_MASK 0x1 +#define UNALIGNED_OPAQUE_DATA_PKT_REACHED_WIN_RIGHT_EDGE_SHIFT 0 +#define UNALIGNED_OPAQUE_DATA_CONNECTION_CLOSED_MASK 0x1 +#define UNALIGNED_OPAQUE_DATA_CONNECTION_CLOSED_SHIFT 1 +#define UNALIGNED_OPAQUE_DATA_RESERVED_MASK 0x3F +#define UNALIGNED_OPAQUE_DATA_RESERVED_SHIFT 2 + __le32 cid; +}; + +struct mstorm_iwarp_conn_ag_ctx { + u8 reserved; + u8 state; + u8 flags0; +#define MSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define MSTORM_IWARP_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_IWARP_CONN_AG_CTX_INV_STAG_DONE_CF_MASK 0x3 +#define MSTORM_IWARP_CONN_AG_CTX_INV_STAG_DONE_CF_SHIFT 2 +#define MSTORM_IWARP_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_IWARP_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_IWARP_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_IWARP_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_IWARP_CONN_AG_CTX_INV_STAG_DONE_CF_EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_INV_STAG_DONE_CF_EN_SHIFT 0 +#define MSTORM_IWARP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_IWARP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_IWARP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_IWARP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_IWARP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_IWARP_CONN_AG_CTX_RCQ_CONS_EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RCQ_CONS_EN_SHIFT 6 +#define MSTORM_IWARP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_IWARP_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 rcq_cons; + __le16 rcq_cons_th; + __le32 reg0; + __le32 reg1; +}; + +struct ustorm_iwarp_conn_ag_ctx { + u8 reserved; + u8 byte1; + u8 flags0; +#define USTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define USTORM_IWARP_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_IWARP_CONN_AG_CTX_CF0_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF0_SHIFT 2 +#define USTORM_IWARP_CONN_AG_CTX_CF1_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_IWARP_CONN_AG_CTX_CF2_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define USTORM_IWARP_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_SE_CF_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_SE_CF_SHIFT 2 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_CF_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_CF_SHIFT 4 +#define USTORM_IWARP_CONN_AG_CTX_CF6_MASK 0x3 +#define USTORM_IWARP_CONN_AG_CTX_CF6_SHIFT 6 + u8 flags2; +#define USTORM_IWARP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF0EN_SHIFT 0 +#define USTORM_IWARP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_IWARP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_IWARP_CONN_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_SE_CF_EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_SE_CF_EN_SHIFT 4 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_CF_EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CQ_ARM_CF_EN_SHIFT 5 +#define USTORM_IWARP_CONN_AG_CTX_CF6EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CF6EN_SHIFT 6 +#define USTORM_IWARP_CONN_AG_CTX_CQ_SE_EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CQ_SE_EN_SHIFT 7 + u8 flags3; +#define USTORM_IWARP_CONN_AG_CTX_CQ_EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_CQ_EN_SHIFT 0 +#define USTORM_IWARP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_IWARP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_IWARP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_IWARP_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_IWARP_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_IWARP_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_IWARP_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define USTORM_IWARP_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le16 word1; + __le32 cq_cons; + __le32 cq_se_prod; + __le32 cq_prod; + __le32 reg3; + __le16 word2; + __le16 word3; +}; + +struct ystorm_iwarp_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define YSTORM_IWARP_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_IWARP_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_IWARP_CONN_AG_CTX_CF0_MASK 0x3 +#define YSTORM_IWARP_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_IWARP_CONN_AG_CTX_CF1_MASK 0x3 +#define YSTORM_IWARP_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_IWARP_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_IWARP_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_IWARP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_IWARP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_IWARP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_IWARP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_IWARP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_IWARP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_IWARP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_IWARP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_IWARP_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le32 reg0; + __le32 reg1; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; +}; + struct ystorm_fcoe_conn_st_ctx { u8 func_mode; u8 cos; @@ -9222,7 +10411,7 @@ struct xstorm_iscsi_conn_ag_ctx { u8 byte13; u8 byte14; u8 byte15; - u8 byte16; + u8 ereserved; __le16 word11; __le32 reg10; __le32 reg11; @@ -10758,6 +11947,8 @@ struct static_init { u32 rsrv_persist[5]; /* Persist reserved for MFW upgrades */ }; +#define NVM_MAGIC_VALUE 0x669955aa + enum nvm_image_type { NVM_TYPE_TIM1 = 0x01, NVM_TYPE_TIM2 = 0x02, diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c index 0a8fde629991..b069ad088269 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c @@ -40,31 +40,17 @@ #include "qed_init_ops.h" #include "qed_reg_addr.h" -enum cminterface { - MCM_SEC, - MCM_PRI, - UCM_SEC, - UCM_PRI, - TCM_SEC, - TCM_PRI, - YCM_SEC, - YCM_PRI, - XCM_SEC, - XCM_PRI, - NUM_OF_CM_INTERFACES -}; - -/* general constants */ +/* General constants */ #define QM_PQ_MEM_4KB(pq_size) (pq_size ? DIV_ROUND_UP((pq_size + 1) * \ QM_PQ_ELEMENT_SIZE, \ 0x1000) : 0) #define QM_PQ_SIZE_256B(pq_size) (pq_size ? DIV_ROUND_UP(pq_size, \ 0x100) - 1 : 0) #define QM_INVALID_PQ_ID 0xffff -/* feature enable */ +/* Feature enable */ #define QM_BYPASS_EN 1 #define QM_BYTE_CRD_EN 1 -/* other PQ constants */ +/* Other PQ constants */ #define QM_OTHER_PQS_PER_PF 4 /* WFQ constants */ #define QM_WFQ_UPPER_BOUND 62500000 @@ -106,20 +92,21 @@ enum cminterface { #define BTB_PURE_LB_FACTOR 10 #define BTB_PURE_LB_RATIO 7 /* QM stop command constants */ -#define QM_STOP_PQ_MASK_WIDTH 32 -#define QM_STOP_CMD_ADDR 0x2 -#define QM_STOP_CMD_STRUCT_SIZE 2 +#define QM_STOP_PQ_MASK_WIDTH 32 +#define QM_STOP_CMD_ADDR 2 +#define QM_STOP_CMD_STRUCT_SIZE 2 #define QM_STOP_CMD_PAUSE_MASK_OFFSET 0 #define QM_STOP_CMD_PAUSE_MASK_SHIFT 0 -#define QM_STOP_CMD_PAUSE_MASK_MASK -1 -#define QM_STOP_CMD_GROUP_ID_OFFSET 1 -#define QM_STOP_CMD_GROUP_ID_SHIFT 16 -#define QM_STOP_CMD_GROUP_ID_MASK 15 -#define QM_STOP_CMD_PQ_TYPE_OFFSET 1 -#define QM_STOP_CMD_PQ_TYPE_SHIFT 24 -#define QM_STOP_CMD_PQ_TYPE_MASK 1 -#define QM_STOP_CMD_MAX_POLL_COUNT 100 -#define QM_STOP_CMD_POLL_PERIOD_US 500 +#define QM_STOP_CMD_PAUSE_MASK_MASK -1 +#define QM_STOP_CMD_GROUP_ID_OFFSET 1 +#define QM_STOP_CMD_GROUP_ID_SHIFT 16 +#define QM_STOP_CMD_GROUP_ID_MASK 15 +#define QM_STOP_CMD_PQ_TYPE_OFFSET 1 +#define QM_STOP_CMD_PQ_TYPE_SHIFT 24 +#define QM_STOP_CMD_PQ_TYPE_MASK 1 +#define QM_STOP_CMD_MAX_POLL_COUNT 100 +#define QM_STOP_CMD_POLL_PERIOD_US 500 + /* QM command macros */ #define QM_CMD_STRUCT_SIZE(cmd) cmd ## \ _STRUCT_SIZE @@ -146,16 +133,17 @@ static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, bool pf_rl_en) { STORE_RT_REG(p_hwfn, QM_REG_RLPFENABLE_RT_OFFSET, pf_rl_en ? 1 : 0); if (pf_rl_en) { - /* enable RLs for all VOQs */ + /* Enable RLs for all VOQs */ STORE_RT_REG(p_hwfn, QM_REG_RLPFVOQENABLE_RT_OFFSET, (1 << MAX_NUM_VOQS) - 1); - /* write RL period */ + /* Write RL period */ STORE_RT_REG(p_hwfn, QM_REG_RLPFPERIOD_RT_OFFSET, QM_RL_PERIOD_CLK_25M); STORE_RT_REG(p_hwfn, QM_REG_RLPFPERIODTIMER_RT_OFFSET, QM_RL_PERIOD_CLK_25M); - /* set credit threshold for QM bypass flow */ + + /* Set credit threshold for QM bypass flow */ if (QM_BYPASS_EN) STORE_RT_REG(p_hwfn, QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET, @@ -167,7 +155,8 @@ static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, bool pf_rl_en) static void qed_enable_pf_wfq(struct qed_hwfn *p_hwfn, bool pf_wfq_en) { STORE_RT_REG(p_hwfn, QM_REG_WFQPFENABLE_RT_OFFSET, pf_wfq_en ? 1 : 0); - /* set credit threshold for QM bypass flow */ + + /* Set credit threshold for QM bypass flow */ if (pf_wfq_en && QM_BYPASS_EN) STORE_RT_REG(p_hwfn, QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET, @@ -180,14 +169,15 @@ static void qed_enable_vport_rl(struct qed_hwfn *p_hwfn, bool vport_rl_en) STORE_RT_REG(p_hwfn, QM_REG_RLGLBLENABLE_RT_OFFSET, vport_rl_en ? 1 : 0); if (vport_rl_en) { - /* write RL period (use timer 0 only) */ + /* Write RL period (use timer 0 only) */ STORE_RT_REG(p_hwfn, QM_REG_RLGLBLPERIOD_0_RT_OFFSET, QM_RL_PERIOD_CLK_25M); STORE_RT_REG(p_hwfn, QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET, QM_RL_PERIOD_CLK_25M); - /* set credit threshold for QM bypass flow */ + + /* Set credit threshold for QM bypass flow */ if (QM_BYPASS_EN) STORE_RT_REG(p_hwfn, QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET, @@ -200,7 +190,8 @@ static void qed_enable_vport_wfq(struct qed_hwfn *p_hwfn, bool vport_wfq_en) { STORE_RT_REG(p_hwfn, QM_REG_WFQVPENABLE_RT_OFFSET, vport_wfq_en ? 1 : 0); - /* set credit threshold for QM bypass flow */ + + /* Set credit threshold for QM bypass flow */ if (vport_wfq_en && QM_BYPASS_EN) STORE_RT_REG(p_hwfn, QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET, @@ -208,7 +199,7 @@ static void qed_enable_vport_wfq(struct qed_hwfn *p_hwfn, bool vport_wfq_en) } /* Prepare runtime init values to allocate PBF command queue lines for - * the specified VOQ + * the specified VOQ. */ static void qed_cmdq_lines_voq_rt_init(struct qed_hwfn *p_hwfn, u8 voq, u16 cmdq_lines) @@ -232,7 +223,7 @@ static void qed_cmdq_lines_rt_init( { u8 tc, voq, port_id, num_tcs_in_port; - /* clear PBF lines for all VOQs */ + /* Clear PBF lines for all VOQs */ for (voq = 0; voq < MAX_NUM_VOQS; voq++) STORE_RT_REG(p_hwfn, PBF_CMDQ_LINES_RT_OFFSET(voq), 0); for (port_id = 0; port_id < max_ports_per_engine; port_id++) { @@ -285,7 +276,7 @@ static void qed_btb_blocks_rt_init( if (!port_params[port_id].active) continue; - /* subtract headroom blocks */ + /* Subtract headroom blocks */ usable_blocks = port_params[port_id].num_btb_blocks - BTB_HEADROOM_BLOCKS; @@ -305,7 +296,7 @@ static void qed_btb_blocks_rt_init( phys_blocks = (usable_blocks - pure_lb_blocks) / num_tcs_in_port; - /* init physical TCs */ + /* Init physical TCs */ for (tc = 0; tc < NUM_OF_PHYS_TCS; tc++) { if (((port_params[port_id].active_phys_tcs >> tc) & 0x1) != 1) @@ -317,7 +308,7 @@ static void qed_btb_blocks_rt_init( phys_blocks); } - /* init pure LB TC */ + /* Init pure LB TC */ temp = LB_VOQ(port_id); STORE_RT_REG(p_hwfn, PBF_BTB_GUARANTEED_RT_OFFSET(temp), pure_lb_blocks); @@ -338,24 +329,24 @@ static void qed_tx_pq_map_rt_init( QM_PF_QUEUE_GROUP_SIZE; u16 i, pq_id, pq_group; - /* a bit per Tx PQ indicating if the PQ is associated with a VF */ + /* A bit per Tx PQ indicating if the PQ is associated with a VF */ u32 tx_pq_vf_mask[MAX_QM_TX_QUEUES / QM_PF_QUEUE_GROUP_SIZE] = { 0 }; u32 num_tx_pq_vf_masks = MAX_QM_TX_QUEUES / QM_PF_QUEUE_GROUP_SIZE; u32 pq_mem_4kb = QM_PQ_MEM_4KB(p_params->num_pf_cids); u32 vport_pq_mem_4kb = QM_PQ_MEM_4KB(p_params->num_vf_cids); u32 mem_addr_4kb = base_mem_addr_4kb; - /* set mapping from PQ group to PF */ + /* Set mapping from PQ group to PF */ for (pq_group = first_pq_group; pq_group <= last_pq_group; pq_group++) STORE_RT_REG(p_hwfn, QM_REG_PQTX2PF_0_RT_OFFSET + pq_group, (u32)(p_params->pf_id)); - /* set PQ sizes */ + /* Set PQ sizes */ STORE_RT_REG(p_hwfn, QM_REG_MAXPQSIZE_0_RT_OFFSET, QM_PQ_SIZE_256B(p_params->num_pf_cids)); STORE_RT_REG(p_hwfn, QM_REG_MAXPQSIZE_1_RT_OFFSET, QM_PQ_SIZE_256B(p_params->num_vf_cids)); - /* go over all Tx PQs */ + /* Go over all Tx PQs */ for (i = 0, pq_id = p_params->start_pq; i < num_pqs; i++, pq_id++) { u8 voq = VOQ(p_params->port_id, p_params->pq_params[i].tc_id, p_params->max_phys_tcs_per_port); @@ -366,17 +357,18 @@ static void qed_tx_pq_map_rt_init( (p_params->pq_params[i].vport_id < MAX_QM_GLOBAL_RLS); - /* update first Tx PQ of VPORT/TC */ + /* Update first Tx PQ of VPORT/TC */ u8 vport_id_in_pf = p_params->pq_params[i].vport_id - p_params->start_vport; u16 *pq_ids = &vport_params[vport_id_in_pf].first_tx_pq_id[0]; u16 first_tx_pq_id = pq_ids[p_params->pq_params[i].tc_id]; if (first_tx_pq_id == QM_INVALID_PQ_ID) { - /* create new VP PQ */ + /* Create new VP PQ */ pq_ids[p_params->pq_params[i].tc_id] = pq_id; first_tx_pq_id = pq_id; - /* map VP PQ to VOQ and PF */ + + /* Map VP PQ to VOQ and PF */ STORE_RT_REG(p_hwfn, QM_REG_WFQVPMAP_RT_OFFSET + first_tx_pq_id, @@ -388,7 +380,7 @@ static void qed_tx_pq_map_rt_init( if (p_params->pq_params[i].rl_valid && !rl_valid) DP_NOTICE(p_hwfn, "Invalid VPORT ID for rate limiter configuration"); - /* fill PQ map entry */ + /* Fill PQ map entry */ memset(&tx_pq_map, 0, sizeof(tx_pq_map)); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_PQ_VALID, 1); SET_FIELD(tx_pq_map.reg, @@ -400,18 +392,16 @@ static void qed_tx_pq_map_rt_init( SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_VOQ, voq); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_WRR_WEIGHT_GROUP, p_params->pq_params[i].wrr_group); - /* write PQ map entry to CAM */ + /* Write PQ map entry to CAM */ STORE_RT_REG(p_hwfn, QM_REG_TXPQMAP_RT_OFFSET + pq_id, *((u32 *)&tx_pq_map)); - /* set base address */ + /* Set base address */ STORE_RT_REG(p_hwfn, QM_REG_BASEADDRTXPQ_RT_OFFSET + pq_id, mem_addr_4kb); - /* check if VF PQ */ + + /* If VF PQ, add indication to PQ VF mask */ if (is_vf_pq) { - /* if PQ is associated with a VF, add indication - * to PQ VF mask - */ tx_pq_vf_mask[pq_id / QM_PF_QUEUE_GROUP_SIZE] |= BIT((pq_id % QM_PF_QUEUE_GROUP_SIZE)); @@ -421,16 +411,12 @@ static void qed_tx_pq_map_rt_init( } } - /* store Tx PQ VF mask to size select register */ - for (i = 0; i < num_tx_pq_vf_masks; i++) { - if (tx_pq_vf_mask[i]) { - u32 addr; - - addr = QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET + i; - STORE_RT_REG(p_hwfn, addr, + /* Store Tx PQ VF mask to size select register */ + for (i = 0; i < num_tx_pq_vf_masks; i++) + if (tx_pq_vf_mask[i]) + STORE_RT_REG(p_hwfn, + QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET + i, tx_pq_vf_mask[i]); - } - } } /* Prepare Other PQ mapping runtime init values for the specified PF */ @@ -440,23 +426,25 @@ static void qed_other_pq_map_rt_init(struct qed_hwfn *p_hwfn, u32 num_pf_cids, u32 num_tids, u32 base_mem_addr_4kb) { - u16 i, pq_id; + u32 pq_size, pq_mem_4kb, mem_addr_4kb; + u16 i, pq_id, pq_group; /* a single other PQ group is used in each PF, * where PQ group i is used in PF i. */ - u16 pq_group = pf_id; - u32 pq_size = num_pf_cids + num_tids; - u32 pq_mem_4kb = QM_PQ_MEM_4KB(pq_size); - u32 mem_addr_4kb = base_mem_addr_4kb; + pq_group = pf_id; + pq_size = num_pf_cids + num_tids; + pq_mem_4kb = QM_PQ_MEM_4KB(pq_size); + mem_addr_4kb = base_mem_addr_4kb; - /* map PQ group to PF */ + /* Map PQ group to PF */ STORE_RT_REG(p_hwfn, QM_REG_PQOTHER2PF_0_RT_OFFSET + pq_group, (u32)(pf_id)); - /* set PQ sizes */ + /* Set PQ sizes */ STORE_RT_REG(p_hwfn, QM_REG_MAXPQSIZE_2_RT_OFFSET, QM_PQ_SIZE_256B(pq_size)); - /* set base address */ + + /* Set base address */ for (i = 0, pq_id = pf_id * QM_PF_QUEUE_GROUP_SIZE; i < QM_OTHER_PQS_PER_PF; i++, pq_id++) { STORE_RT_REG(p_hwfn, @@ -485,7 +473,7 @@ static int qed_pf_wfq_rt_init(struct qed_hwfn *p_hwfn, inc_val = QM_WFQ_INC_VAL(p_params->pf_wfq); if (!inc_val || inc_val > QM_WFQ_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration"); + DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration\n"); return -1; } @@ -514,7 +502,7 @@ static int qed_pf_rl_rt_init(struct qed_hwfn *p_hwfn, u8 pf_id, u32 pf_rl) u32 inc_val = QM_RL_INC_VAL(pf_rl); if (inc_val > QM_RL_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration"); + DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration\n"); return -1; } STORE_RT_REG(p_hwfn, QM_REG_RLPFCRD_RT_OFFSET + pf_id, @@ -535,7 +523,7 @@ static int qed_vp_wfq_rt_init(struct qed_hwfn *p_hwfn, u32 inc_val; u8 tc, i; - /* go over all PF VPORTs */ + /* Go over all PF VPORTs */ for (i = 0; i < num_vports; i++) { if (!vport_params[i].vport_wfq) @@ -544,7 +532,7 @@ static int qed_vp_wfq_rt_init(struct qed_hwfn *p_hwfn, inc_val = QM_WFQ_INC_VAL(vport_params[i].vport_wfq); if (inc_val > QM_WFQ_MAX_INC_VAL) { DP_NOTICE(p_hwfn, - "Invalid VPORT WFQ weight configuration"); + "Invalid VPORT WFQ weight configuration\n"); return -1; } @@ -578,17 +566,17 @@ static int qed_vport_rl_rt_init(struct qed_hwfn *p_hwfn, if (start_vport + num_vports >= MAX_QM_GLOBAL_RLS) { DP_NOTICE(p_hwfn, - "Invalid VPORT ID for rate limiter configuration"); + "Invalid VPORT ID for rate limiter configuration\n"); return -1; } - /* go over all PF VPORTs */ + /* Go over all PF VPORTs */ for (i = 0, vport_id = start_vport; i < num_vports; i++, vport_id++) { u32 inc_val = QM_RL_INC_VAL(vport_params[i].vport_rl); if (inc_val > QM_RL_MAX_INC_VAL) { DP_NOTICE(p_hwfn, - "Invalid VPORT rate-limit configuration"); + "Invalid VPORT rate-limit configuration\n"); return -1; } @@ -617,7 +605,7 @@ static bool qed_poll_on_qm_cmd_ready(struct qed_hwfn *p_hwfn, reg_val = qed_rd(p_hwfn, p_ptt, QM_REG_SDMCMDREADY); } - /* check if timeout while waiting for SDM command ready */ + /* Check if timeout while waiting for SDM command ready */ if (i == QM_STOP_CMD_MAX_POLL_COUNT) { DP_VERBOSE(p_hwfn, NETIF_MSG_HW, "Timeout when waiting for QM SDM command ready signal\n"); @@ -701,16 +689,16 @@ int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn, QM_OTHER_PQS_PER_PF; u8 tc, i; - /* clear first Tx PQ ID array for each VPORT */ + /* Clear first Tx PQ ID array for each VPORT */ for (i = 0; i < p_params->num_vports; i++) for (tc = 0; tc < NUM_OF_TCS; tc++) vport_params[i].first_tx_pq_id[tc] = QM_INVALID_PQ_ID; - /* map Other PQs (if any) */ + /* Map Other PQs (if any) */ qed_other_pq_map_rt_init(p_hwfn, p_params->port_id, p_params->pf_id, p_params->num_pf_cids, p_params->num_tids, 0); - /* map Tx PQs */ + /* Map Tx PQs */ qed_tx_pq_map_rt_init(p_hwfn, p_ptt, p_params, other_mem_size_4kb); if (p_params->pf_wfq) @@ -736,7 +724,7 @@ int qed_init_pf_wfq(struct qed_hwfn *p_hwfn, u32 inc_val = QM_WFQ_INC_VAL(pf_wfq); if (!inc_val || inc_val > QM_WFQ_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration"); + DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration\n"); return -1; } @@ -750,7 +738,7 @@ int qed_init_pf_rl(struct qed_hwfn *p_hwfn, u32 inc_val = QM_RL_INC_VAL(pf_rl); if (inc_val > QM_RL_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration"); + DP_NOTICE(p_hwfn, "Invalid PF rate limit configuration\n"); return -1; } @@ -766,17 +754,18 @@ int qed_init_vport_wfq(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 first_tx_pq_id[NUM_OF_TCS], u16 vport_wfq) { - u32 inc_val = QM_WFQ_INC_VAL(vport_wfq); + u16 vport_pq_id; + u32 inc_val; u8 tc; + inc_val = QM_WFQ_INC_VAL(vport_wfq); if (!inc_val || inc_val > QM_WFQ_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid VPORT WFQ weight configuration"); + DP_NOTICE(p_hwfn, "Invalid VPORT WFQ weight configuration\n"); return -1; } for (tc = 0; tc < NUM_OF_TCS; tc++) { - u16 vport_pq_id = first_tx_pq_id[tc]; - + vport_pq_id = first_tx_pq_id[tc]; if (vport_pq_id != QM_INVALID_PQ_ID) qed_wr(p_hwfn, p_ptt, QM_REG_WFQVPWEIGHT + vport_pq_id * 4, @@ -793,12 +782,12 @@ int qed_init_vport_rl(struct qed_hwfn *p_hwfn, if (vport_id >= MAX_QM_GLOBAL_RLS) { DP_NOTICE(p_hwfn, - "Invalid VPORT ID for rate limiter configuration"); + "Invalid VPORT ID for rate limiter configuration\n"); return -1; } if (inc_val > QM_RL_MAX_INC_VAL) { - DP_NOTICE(p_hwfn, "Invalid VPORT rate-limit configuration"); + DP_NOTICE(p_hwfn, "Invalid VPORT rate-limit configuration\n"); return -1; } @@ -818,15 +807,15 @@ bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, u32 cmd_arr[QM_CMD_STRUCT_SIZE(QM_STOP_CMD)] = { 0 }; u32 pq_mask = 0, last_pq = start_pq + num_pqs - 1, pq_id; - /* set command's PQ type */ + /* Set command's PQ type */ QM_CMD_SET_FIELD(cmd_arr, QM_STOP_CMD, PQ_TYPE, is_tx_pq ? 0 : 1); for (pq_id = start_pq; pq_id <= last_pq; pq_id++) { - /* set PQ bit in mask (stop command only) */ + /* Set PQ bit in mask (stop command only) */ if (!is_release_cmd) pq_mask |= (1 << (pq_id % QM_STOP_PQ_MASK_WIDTH)); - /* if last PQ or end of PQ mask, write command */ + /* If last PQ or end of PQ mask, write command */ if ((pq_id == last_pq) || (pq_id % QM_STOP_PQ_MASK_WIDTH == (QM_STOP_PQ_MASK_WIDTH - 1))) { @@ -962,8 +951,10 @@ void qed_set_geneve_enable(struct qed_hwfn *p_hwfn, ip_geneve_enable ? 1 : 0); } +#define T_ETH_PACKET_ACTION_GFT_EVENTID 23 +#define PARSER_ETH_CONN_GFT_ACTION_CM_HDR 272 #define T_ETH_PACKET_MATCH_RFS_EVENTID 25 -#define PARSER_ETH_CONN_CM_HDR (0x0) +#define PARSER_ETH_CONN_CM_HDR 0 #define CAM_LINE_SIZE sizeof(u32) #define RAM_LINE_SIZE sizeof(u64) #define REG_SIZE sizeof(u32) @@ -971,40 +962,26 @@ void qed_set_geneve_enable(struct qed_hwfn *p_hwfn, void qed_set_rfs_mode_disable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 pf_id) { - union gft_cam_line_union camline; - struct gft_ram_line ramline; - u32 *p_ramline, i; - - p_ramline = (u32 *)&ramline; + u32 hw_addr = PRS_REG_GFT_PROFILE_MASK_RAM + + pf_id * RAM_LINE_SIZE; /*stop using gft logic */ qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_GFT, 0); qed_wr(p_hwfn, p_ptt, PRS_REG_CM_HDR_GFT, 0x0); - memset(&camline, 0, sizeof(union gft_cam_line_union)); - qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id, - camline.cam_line_mapped.camline); - memset(&ramline, 0, sizeof(ramline)); - - for (i = 0; i < RAM_LINE_SIZE / REG_SIZE; i++) { - u32 hw_addr = PRS_REG_GFT_PROFILE_MASK_RAM; - - hw_addr += (RAM_LINE_SIZE * pf_id + i * REG_SIZE); - - qed_wr(p_hwfn, p_ptt, hw_addr, *(p_ramline + i)); - } + qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id, 0); + qed_wr(p_hwfn, p_ptt, hw_addr, 0); + qed_wr(p_hwfn, p_ptt, hw_addr + 4, 0); } void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 pf_id, bool tcp, bool udp, bool ipv4, bool ipv6) { - u32 rfs_cm_hdr_event_id, *p_ramline; union gft_cam_line_union camline; struct gft_ram_line ramline; - int i; + u32 rfs_cm_hdr_event_id; rfs_cm_hdr_event_id = qed_rd(p_hwfn, p_ptt, PRS_REG_CM_HDR_GFT); - p_ramline = (u32 *)&ramline; if (!ipv6 && !ipv4) DP_NOTICE(p_hwfn, @@ -1024,18 +1001,20 @@ void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, qed_wr(p_hwfn, p_ptt, PRS_REG_LOAD_L2_FILTER, 0); camline.cam_line_mapped.camline = 0; - /* cam line is now valid!! */ + /* Cam line is now valid!! */ SET_FIELD(camline.cam_line_mapped.camline, GFT_CAM_LINE_MAPPED_VALID, 1); /* filters are per PF!! */ SET_FIELD(camline.cam_line_mapped.camline, - GFT_CAM_LINE_MAPPED_PF_ID_MASK, 1); + GFT_CAM_LINE_MAPPED_PF_ID_MASK, + GFT_CAM_LINE_MAPPED_PF_ID_MASK_MASK); SET_FIELD(camline.cam_line_mapped.camline, GFT_CAM_LINE_MAPPED_PF_ID, pf_id); if (!(tcp && udp)) { SET_FIELD(camline.cam_line_mapped.camline, - GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK, 1); + GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK, + GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE_MASK_MASK); if (tcp) SET_FIELD(camline.cam_line_mapped.camline, GFT_CAM_LINE_MAPPED_UPPER_PROTOCOL_TYPE, @@ -1059,34 +1038,38 @@ void qed_set_rfs_mode_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, GFT_PROFILE_IPV6); } - /* write characteristics to cam */ + /* Write characteristics to cam */ qed_wr(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id, camline.cam_line_mapped.camline); camline.cam_line_mapped.camline = qed_rd(p_hwfn, p_ptt, PRS_REG_GFT_CAM + CAM_LINE_SIZE * pf_id); - /* write line to RAM - compare to filter 4 tuple */ - ramline.low32bits = 0; - ramline.high32bits = 0; - SET_FIELD(ramline.high32bits, GFT_RAM_LINE_DST_IP, 1); - SET_FIELD(ramline.high32bits, GFT_RAM_LINE_SRC_IP, 1); - SET_FIELD(ramline.low32bits, GFT_RAM_LINE_SRC_PORT, 1); - SET_FIELD(ramline.low32bits, GFT_RAM_LINE_DST_PORT, 1); - - /* each iteration write to reg */ - for (i = 0; i < RAM_LINE_SIZE / REG_SIZE; i++) - qed_wr(p_hwfn, p_ptt, - PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id + - i * REG_SIZE, *(p_ramline + i)); - - /* set default profile so that no filter match will happen */ - ramline.low32bits = 0xffff; - ramline.high32bits = 0xffff; - - for (i = 0; i < RAM_LINE_SIZE / REG_SIZE; i++) - qed_wr(p_hwfn, p_ptt, - PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * - PRS_GFT_CAM_LINES_NO_MATCH + i * REG_SIZE, - *(p_ramline + i)); + /* Write line to RAM - compare to filter 4 tuple */ + ramline.lo = 0; + ramline.hi = 0; + SET_FIELD(ramline.hi, GFT_RAM_LINE_DST_IP, 1); + SET_FIELD(ramline.hi, GFT_RAM_LINE_SRC_IP, 1); + SET_FIELD(ramline.hi, GFT_RAM_LINE_OVER_IP_PROTOCOL, 1); + SET_FIELD(ramline.lo, GFT_RAM_LINE_ETHERTYPE, 1); + SET_FIELD(ramline.lo, GFT_RAM_LINE_SRC_PORT, 1); + SET_FIELD(ramline.lo, GFT_RAM_LINE_DST_PORT, 1); + + /* Each iteration write to reg */ + qed_wr(p_hwfn, p_ptt, + PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id, + ramline.lo); + qed_wr(p_hwfn, p_ptt, + PRS_REG_GFT_PROFILE_MASK_RAM + RAM_LINE_SIZE * pf_id + 4, + ramline.hi); + + /* Set default profile so that no filter match will happen */ + qed_wr(p_hwfn, p_ptt, + PRS_REG_GFT_PROFILE_MASK_RAM + + RAM_LINE_SIZE * PRS_GFT_CAM_LINES_NO_MATCH, + ramline.lo); + qed_wr(p_hwfn, p_ptt, + PRS_REG_GFT_PROFILE_MASK_RAM + + RAM_LINE_SIZE * PRS_GFT_CAM_LINES_NO_MATCH + 4, + ramline.hi); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index 339c91dfa658..3897ac0ae835 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -375,7 +375,6 @@ static int qed_sp_iscsi_conn_offload(struct qed_hwfn *p_hwfn, p_tcp->ss_thresh = cpu_to_le32(p_conn->ss_thresh); p_tcp->srtt = cpu_to_le16(p_conn->srtt); p_tcp->rtt_var = cpu_to_le16(p_conn->rtt_var); - p_tcp->ts_time = cpu_to_le32(p_conn->ts_time); p_tcp->ts_recent = cpu_to_le32(p_conn->ts_recent); p_tcp->ts_recent_age = cpu_to_le32(p_conn->ts_recent_age); p_tcp->total_rt = cpu_to_le32(p_conn->total_rt); @@ -400,8 +399,6 @@ static int qed_sp_iscsi_conn_offload(struct qed_hwfn *p_hwfn, p_tcp->mss = cpu_to_le16(p_conn->mss); p_tcp->snd_wnd_scale = p_conn->snd_wnd_scale; p_tcp->rcv_wnd_scale = p_conn->rcv_wnd_scale; - dval = p_conn->ts_ticks_per_second; - p_tcp->ts_ticks_per_second = cpu_to_le32(dval); wval = p_conn->da_timeout_value; p_tcp->da_timeout_value = cpu_to_le16(wval); p_tcp->ack_frequency = p_conn->ack_frequency; diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 1ae73b2d6d1e..f14772b9cda3 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -592,15 +592,15 @@ #define QM_REG_WFQPFWEIGHT 0x2f4e80UL #define QM_REG_WFQVPWEIGHT 0x2fa000UL -#define PGLCS_REG_DBG_SELECT \ +#define PGLCS_REG_DBG_SELECT_K2 \ 0x001d14UL -#define PGLCS_REG_DBG_DWORD_ENABLE \ +#define PGLCS_REG_DBG_DWORD_ENABLE_K2 \ 0x001d18UL -#define PGLCS_REG_DBG_SHIFT \ +#define PGLCS_REG_DBG_SHIFT_K2 \ 0x001d1cUL -#define PGLCS_REG_DBG_FORCE_VALID \ +#define PGLCS_REG_DBG_FORCE_VALID_K2 \ 0x001d20UL -#define PGLCS_REG_DBG_FORCE_FRAME \ +#define PGLCS_REG_DBG_FORCE_FRAME_K2 \ 0x001d24UL #define MISC_REG_RESET_PL_PDA_VMAIN_1 \ 0x008070UL @@ -612,7 +612,7 @@ 0x009050UL #define MISCS_REG_RESET_PL_HV \ 0x009060UL -#define MISCS_REG_RESET_PL_HV_2 \ +#define MISCS_REG_RESET_PL_HV_2_K2 \ 0x009150UL #define DMAE_REG_DBG_SELECT \ 0x00c510UL @@ -644,15 +644,15 @@ 0x0500b0UL #define GRC_REG_DBG_FORCE_FRAME \ 0x0500b4UL -#define UMAC_REG_DBG_SELECT \ +#define UMAC_REG_DBG_SELECT_K2 \ 0x051094UL -#define UMAC_REG_DBG_DWORD_ENABLE \ +#define UMAC_REG_DBG_DWORD_ENABLE_K2 \ 0x051098UL -#define UMAC_REG_DBG_SHIFT \ +#define UMAC_REG_DBG_SHIFT_K2 \ 0x05109cUL -#define UMAC_REG_DBG_FORCE_VALID \ +#define UMAC_REG_DBG_FORCE_VALID_K2 \ 0x0510a0UL -#define UMAC_REG_DBG_FORCE_FRAME \ +#define UMAC_REG_DBG_FORCE_FRAME_K2 \ 0x0510a4UL #define MCP2_REG_DBG_SELECT \ 0x052400UL @@ -924,15 +924,15 @@ 0x4c160cUL #define XYLD_REG_DBG_FORCE_FRAME \ 0x4c1610UL -#define YULD_REG_DBG_SELECT \ +#define YULD_REG_DBG_SELECT_BB_K2 \ 0x4c9600UL -#define YULD_REG_DBG_DWORD_ENABLE \ +#define YULD_REG_DBG_DWORD_ENABLE_BB_K2 \ 0x4c9604UL -#define YULD_REG_DBG_SHIFT \ +#define YULD_REG_DBG_SHIFT_BB_K2 \ 0x4c9608UL -#define YULD_REG_DBG_FORCE_VALID \ +#define YULD_REG_DBG_FORCE_VALID_BB_K2 \ 0x4c960cUL -#define YULD_REG_DBG_FORCE_FRAME \ +#define YULD_REG_DBG_FORCE_FRAME_BB_K2 \ 0x4c9610UL #define TMLD_REG_DBG_SELECT \ 0x4d1600UL @@ -994,35 +994,35 @@ 0x580710UL #define CDU_REG_DBG_FORCE_FRAME \ 0x580714UL -#define WOL_REG_DBG_SELECT \ +#define WOL_REG_DBG_SELECT_K2 \ 0x600140UL -#define WOL_REG_DBG_DWORD_ENABLE \ +#define WOL_REG_DBG_DWORD_ENABLE_K2 \ 0x600144UL -#define WOL_REG_DBG_SHIFT \ +#define WOL_REG_DBG_SHIFT_K2 \ 0x600148UL -#define WOL_REG_DBG_FORCE_VALID \ +#define WOL_REG_DBG_FORCE_VALID_K2 \ 0x60014cUL -#define WOL_REG_DBG_FORCE_FRAME \ +#define WOL_REG_DBG_FORCE_FRAME_K2 \ 0x600150UL -#define BMBN_REG_DBG_SELECT \ +#define BMBN_REG_DBG_SELECT_K2 \ 0x610140UL -#define BMBN_REG_DBG_DWORD_ENABLE \ +#define BMBN_REG_DBG_DWORD_ENABLE_K2 \ 0x610144UL -#define BMBN_REG_DBG_SHIFT \ +#define BMBN_REG_DBG_SHIFT_K2 \ 0x610148UL -#define BMBN_REG_DBG_FORCE_VALID \ +#define BMBN_REG_DBG_FORCE_VALID_K2 \ 0x61014cUL -#define BMBN_REG_DBG_FORCE_FRAME \ +#define BMBN_REG_DBG_FORCE_FRAME_K2 \ 0x610150UL -#define NWM_REG_DBG_SELECT \ +#define NWM_REG_DBG_SELECT_K2 \ 0x8000ecUL -#define NWM_REG_DBG_DWORD_ENABLE \ +#define NWM_REG_DBG_DWORD_ENABLE_K2 \ 0x8000f0UL -#define NWM_REG_DBG_SHIFT \ +#define NWM_REG_DBG_SHIFT_K2 \ 0x8000f4UL -#define NWM_REG_DBG_FORCE_VALID \ +#define NWM_REG_DBG_FORCE_VALID_K2 \ 0x8000f8UL -#define NWM_REG_DBG_FORCE_FRAME \ +#define NWM_REG_DBG_FORCE_FRAME_K2\ 0x8000fcUL #define PBF_REG_DBG_SELECT \ 0xd80060UL @@ -1244,35 +1244,35 @@ 0x1901534UL #define USEM_REG_DBG_FORCE_FRAME \ 0x1901538UL -#define NWS_REG_DBG_SELECT \ +#define NWS_REG_DBG_SELECT_K2 \ 0x700128UL -#define NWS_REG_DBG_DWORD_ENABLE \ +#define NWS_REG_DBG_DWORD_ENABLE_K2 \ 0x70012cUL -#define NWS_REG_DBG_SHIFT \ +#define NWS_REG_DBG_SHIFT_K2 \ 0x700130UL -#define NWS_REG_DBG_FORCE_VALID \ +#define NWS_REG_DBG_FORCE_VALID_K2 \ 0x700134UL -#define NWS_REG_DBG_FORCE_FRAME \ +#define NWS_REG_DBG_FORCE_FRAME_K2 \ 0x700138UL -#define MS_REG_DBG_SELECT \ +#define MS_REG_DBG_SELECT_K2 \ 0x6a0228UL -#define MS_REG_DBG_DWORD_ENABLE \ +#define MS_REG_DBG_DWORD_ENABLE_K2 \ 0x6a022cUL -#define MS_REG_DBG_SHIFT \ +#define MS_REG_DBG_SHIFT_K2 \ 0x6a0230UL -#define MS_REG_DBG_FORCE_VALID \ +#define MS_REG_DBG_FORCE_VALID_K2 \ 0x6a0234UL -#define MS_REG_DBG_FORCE_FRAME \ +#define MS_REG_DBG_FORCE_FRAME_K2 \ 0x6a0238UL -#define PCIE_REG_DBG_COMMON_SELECT \ +#define PCIE_REG_DBG_COMMON_SELECT_K2 \ 0x054398UL -#define PCIE_REG_DBG_COMMON_DWORD_ENABLE \ +#define PCIE_REG_DBG_COMMON_DWORD_ENABLE_K2 \ 0x05439cUL -#define PCIE_REG_DBG_COMMON_SHIFT \ +#define PCIE_REG_DBG_COMMON_SHIFT_K2 \ 0x0543a0UL -#define PCIE_REG_DBG_COMMON_FORCE_VALID \ +#define PCIE_REG_DBG_COMMON_FORCE_VALID_K2 \ 0x0543a4UL -#define PCIE_REG_DBG_COMMON_FORCE_FRAME \ +#define PCIE_REG_DBG_COMMON_FORCE_FRAME_K2 \ 0x0543a8UL #define MISC_REG_RESET_PL_UA \ 0x008050UL @@ -1328,85 +1328,85 @@ 0x128170cUL #define UCM_REG_SM_TASK_CTX \ 0x1281710UL -#define XSEM_REG_SLOW_DBG_EMPTY \ +#define XSEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1401140UL #define XSEM_REG_SYNC_DBG_EMPTY \ 0x1401160UL -#define XSEM_REG_SLOW_DBG_ACTIVE \ +#define XSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1401400UL -#define XSEM_REG_SLOW_DBG_MODE \ +#define XSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1401404UL -#define XSEM_REG_DBG_FRAME_MODE \ +#define XSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1401408UL -#define XSEM_REG_DBG_MODE1_CFG \ +#define XSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1401420UL #define XSEM_REG_FAST_MEMORY \ 0x1440000UL #define YSEM_REG_SYNC_DBG_EMPTY \ 0x1501160UL -#define YSEM_REG_SLOW_DBG_ACTIVE \ +#define YSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1501400UL -#define YSEM_REG_SLOW_DBG_MODE \ +#define YSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1501404UL -#define YSEM_REG_DBG_FRAME_MODE \ +#define YSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1501408UL -#define YSEM_REG_DBG_MODE1_CFG \ +#define YSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1501420UL #define YSEM_REG_FAST_MEMORY \ 0x1540000UL -#define PSEM_REG_SLOW_DBG_EMPTY \ +#define PSEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1601140UL #define PSEM_REG_SYNC_DBG_EMPTY \ 0x1601160UL -#define PSEM_REG_SLOW_DBG_ACTIVE \ +#define PSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1601400UL -#define PSEM_REG_SLOW_DBG_MODE \ +#define PSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1601404UL -#define PSEM_REG_DBG_FRAME_MODE \ +#define PSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1601408UL -#define PSEM_REG_DBG_MODE1_CFG \ +#define PSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1601420UL #define PSEM_REG_FAST_MEMORY \ 0x1640000UL -#define TSEM_REG_SLOW_DBG_EMPTY \ +#define TSEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1701140UL #define TSEM_REG_SYNC_DBG_EMPTY \ 0x1701160UL -#define TSEM_REG_SLOW_DBG_ACTIVE \ +#define TSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1701400UL -#define TSEM_REG_SLOW_DBG_MODE \ +#define TSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1701404UL -#define TSEM_REG_DBG_FRAME_MODE \ +#define TSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1701408UL -#define TSEM_REG_DBG_MODE1_CFG \ +#define TSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1701420UL #define TSEM_REG_FAST_MEMORY \ 0x1740000UL -#define MSEM_REG_SLOW_DBG_EMPTY \ +#define MSEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1801140UL #define MSEM_REG_SYNC_DBG_EMPTY \ 0x1801160UL -#define MSEM_REG_SLOW_DBG_ACTIVE \ +#define MSEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1801400UL -#define MSEM_REG_SLOW_DBG_MODE \ +#define MSEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1801404UL -#define MSEM_REG_DBG_FRAME_MODE \ +#define MSEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1801408UL -#define MSEM_REG_DBG_MODE1_CFG \ +#define MSEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1801420UL #define MSEM_REG_FAST_MEMORY \ 0x1840000UL -#define USEM_REG_SLOW_DBG_EMPTY \ +#define USEM_REG_SLOW_DBG_EMPTY_BB_K2 \ 0x1901140UL #define USEM_REG_SYNC_DBG_EMPTY \ 0x1901160UL -#define USEM_REG_SLOW_DBG_ACTIVE \ +#define USEM_REG_SLOW_DBG_ACTIVE_BB_K2 \ 0x1901400UL -#define USEM_REG_SLOW_DBG_MODE \ +#define USEM_REG_SLOW_DBG_MODE_BB_K2 \ 0x1901404UL -#define USEM_REG_DBG_FRAME_MODE \ +#define USEM_REG_DBG_FRAME_MODE_BB_K2 \ 0x1901408UL -#define USEM_REG_DBG_MODE1_CFG \ +#define USEM_REG_DBG_MODE1_CFG_BB_K2 \ 0x1901420UL #define USEM_REG_FAST_MEMORY \ 0x1940000UL @@ -1430,7 +1430,7 @@ 0x340800UL #define BRB_REG_BIG_RAM_DATA \ 0x341500UL -#define SEM_FAST_REG_STALL_0 \ +#define SEM_FAST_REG_STALL_0_BB_K2 \ 0x000488UL #define SEM_FAST_REG_STALLED \ 0x000494UL @@ -1480,37 +1480,37 @@ 4 #define MISC_REG_BLOCK_256B_EN \ 0x008c14UL -#define NWS_REG_NWS_CMU \ +#define NWS_REG_NWS_CMU_K2 \ 0x720000UL -#define PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_7_0 \ +#define PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_7_0_K2 \ 0x000680UL -#define PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_15_8 \ +#define PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_15_8_K2 \ 0x000684UL -#define PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_7_0 \ +#define PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_7_0_K2 \ 0x0006c0UL -#define PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_11_8 \ +#define PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_11_8_K2 \ 0x0006c4UL -#define MS_REG_MS_CMU \ +#define MS_REG_MS_CMU_K2 \ 0x6a4000UL -#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X130 \ +#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X130_K2 \ 0x000208UL -#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X132 \ - 0x000210UL -#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X131 \ +#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X131_K2 \ 0x00020cUL -#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X133 \ +#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X132_K2 \ + 0x000210UL +#define PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X133_K2 \ 0x000214UL -#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130 \ +#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130_K2 \ 0x000208UL -#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131 \ +#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131_K2 \ 0x00020cUL -#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132 \ +#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132_K2 \ 0x000210UL -#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133 \ +#define PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133_K2 \ 0x000214UL -#define PHY_PCIE_REG_PHY0 \ +#define PHY_PCIE_REG_PHY0_K2 \ 0x620000UL -#define PHY_PCIE_REG_PHY1 \ +#define PHY_PCIE_REG_PHY1_K2 \ 0x624000UL #define NIG_REG_ROCE_DUPLICATE_TO_HOST 0x5088f0UL #define PRS_REG_LIGHT_L2_ETHERTYPE_EN 0x1f0968UL diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 56289d7cd306..eb1a5cfc49c0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -2431,10 +2431,6 @@ qed_rdma_register_tid(void *rdma_cxt, RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG, params->page_size_log - 12); - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_MAX_ID, - p_hwfn->p_rdma_info->last_tid); - SET_FIELD(p_ramrod->flags, RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ, params->remote_read); diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c index bc3694e91b85..5abcac64d969 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c @@ -185,22 +185,20 @@ static void qed_set_tunn_ports(struct qed_tunnel_info *p_tun, } static void -__qed_set_ramrod_tunnel_param(u8 *p_tunn_cls, u8 *p_enable_tx_clas, +__qed_set_ramrod_tunnel_param(u8 *p_tunn_cls, struct qed_tunn_update_type *tun_type) { *p_tunn_cls = tun_type->tun_cls; - - if (tun_type->b_mode_enabled) - *p_enable_tx_clas = 1; } static void -qed_set_ramrod_tunnel_param(u8 *p_tunn_cls, u8 *p_enable_tx_clas, +qed_set_ramrod_tunnel_param(u8 *p_tunn_cls, struct qed_tunn_update_type *tun_type, - u8 *p_update_port, __le16 *p_port, + u8 *p_update_port, + __le16 *p_port, struct qed_tunn_update_udp_port *p_udp_port) { - __qed_set_ramrod_tunnel_param(p_tunn_cls, p_enable_tx_clas, tun_type); + __qed_set_ramrod_tunnel_param(p_tunn_cls, tun_type); if (p_udp_port->b_update_port) { *p_update_port = 1; *p_port = cpu_to_le16(p_udp_port->port); @@ -219,33 +217,27 @@ qed_tunn_set_pf_update_params(struct qed_hwfn *p_hwfn, qed_set_tunn_ports(p_tun, p_src); qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_vxlan, - &p_tunn_cfg->tx_enable_vxlan, &p_tun->vxlan, &p_tunn_cfg->set_vxlan_udp_port_flg, &p_tunn_cfg->vxlan_udp_port, &p_tun->vxlan_port); qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_l2geneve, - &p_tunn_cfg->tx_enable_l2geneve, &p_tun->l2_geneve, &p_tunn_cfg->set_geneve_udp_port_flg, &p_tunn_cfg->geneve_udp_port, &p_tun->geneve_port); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_ipgeneve, - &p_tunn_cfg->tx_enable_ipgeneve, &p_tun->ip_geneve); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_l2gre, - &p_tunn_cfg->tx_enable_l2gre, &p_tun->l2_gre); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_ipgre, - &p_tunn_cfg->tx_enable_ipgre, &p_tun->ip_gre); p_tunn_cfg->update_rx_pf_clss = p_tun->b_update_rx_cls; - p_tunn_cfg->update_tx_pf_clss = p_tun->b_update_tx_cls; } static void qed_set_hw_tunn_mode(struct qed_hwfn *p_hwfn, @@ -289,29 +281,24 @@ qed_tunn_set_pf_start_params(struct qed_hwfn *p_hwfn, qed_set_tunn_ports(p_tun, p_src); qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_vxlan, - &p_tunn_cfg->tx_enable_vxlan, &p_tun->vxlan, &p_tunn_cfg->set_vxlan_udp_port_flg, &p_tunn_cfg->vxlan_udp_port, &p_tun->vxlan_port); qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_l2geneve, - &p_tunn_cfg->tx_enable_l2geneve, &p_tun->l2_geneve, &p_tunn_cfg->set_geneve_udp_port_flg, &p_tunn_cfg->geneve_udp_port, &p_tun->geneve_port); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_ipgeneve, - &p_tunn_cfg->tx_enable_ipgeneve, &p_tun->ip_geneve); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_l2gre, - &p_tunn_cfg->tx_enable_l2gre, &p_tun->l2_gre); __qed_set_ramrod_tunnel_param(&p_tunn_cfg->tunnel_clss_ipgre, - &p_tunn_cfg->tx_enable_ipgre, &p_tun->ip_gre); } diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c index d6978cbc56f0..7658138f2283 100644 --- a/drivers/scsi/qedi/qedi_fw.c +++ b/drivers/scsi/qedi/qedi_fw.c @@ -2099,14 +2099,16 @@ int qedi_iscsi_send_ioreq(struct iscsi_task *task) /* Update header info */ SET_FIELD(cmd_pdu_header.flags_attr, ISCSI_CMD_HDR_ATTR, ISCSI_ATTR_SIMPLE); - if (sc->sc_data_direction == DMA_TO_DEVICE) { - SET_FIELD(cmd_pdu_header.flags_attr, - ISCSI_CMD_HDR_WRITE, 1); - task_type = ISCSI_TASK_TYPE_INITIATOR_WRITE; - } else { - SET_FIELD(cmd_pdu_header.flags_attr, - ISCSI_CMD_HDR_READ, 1); - task_type = ISCSI_TASK_TYPE_INITIATOR_READ; + if (hdr->cdb[0] != TEST_UNIT_READY) { + if (sc->sc_data_direction == DMA_TO_DEVICE) { + SET_FIELD(cmd_pdu_header.flags_attr, + ISCSI_CMD_HDR_WRITE, 1); + task_type = ISCSI_TASK_TYPE_INITIATOR_WRITE; + } else { + SET_FIELD(cmd_pdu_header.flags_attr, + ISCSI_CMD_HDR_READ, 1); + task_type = ISCSI_TASK_TYPE_INITIATOR_READ; + } } cmd_pdu_header.lun.lo = be32_to_cpu(scsi_lun[0]); @@ -2117,7 +2119,7 @@ int qedi_iscsi_send_ioreq(struct iscsi_task *task) cmd_pdu_header.expected_transfer_length = cpu_to_be32(hdr->data_length); cmd_pdu_header.hdr_second_dword = ntoh24(hdr->dlength); cmd_pdu_header.cmd_sn = be32_to_cpu(hdr->cmdsn); - cmd_pdu_header.opcode = hdr->opcode; + cmd_pdu_header.hdr_first_byte = hdr->opcode; qedi_cpy_scsi_cdb(sc, (u32 *)cmd_pdu_header.cdb); /* Fill tx AHS and rx buffer */ diff --git a/drivers/scsi/qedi/qedi_fw_api.c b/drivers/scsi/qedi/qedi_fw_api.c index fd354d4e03eb..7df32a68bd54 100644 --- a/drivers/scsi/qedi/qedi_fw_api.c +++ b/drivers/scsi/qedi/qedi_fw_api.c @@ -578,7 +578,8 @@ int init_initiator_rw_iscsi_task(struct iscsi_task_params *task_params, (struct iscsi_common_hdr *)cmd_header, tx_sgl_params, cmd_params, dif_task_params); - else if (GET_FIELD(cmd_header->flags_attr, ISCSI_CMD_HDR_READ)) + else if (GET_FIELD(cmd_header->flags_attr, ISCSI_CMD_HDR_READ) || + (task_params->rx_io_size == 0 && task_params->tx_io_size == 0)) return init_rw_iscsi_task(task_params, ISCSI_TASK_TYPE_INITIATOR_READ, conn_params, diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index 3548d46f9b27..0c8ccffa4c38 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -1461,9 +1461,6 @@ static const struct { { ISCSI_CONN_ERROR_OUT_OF_SGES_ERROR, "out of sge error" }, - { ISCSI_CONN_ERROR_TCP_SEG_PROC_IP_OPTIONS_ERROR, - "tcp seg ip options error" - }, { ISCSI_CONN_ERROR_TCP_IP_FRAGMENT_ERROR, "tcp ip fragment error" }, -- cgit v1.2.3 From db646cc0aefbc5da0b9699ed40d4402e01245f57 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 18 May 2017 10:45:33 -0700 Subject: r8152: Remove unused function usb_ocp_read() The function is not used, removing it fixes the following warning when building with clang: drivers/net/usb/r8152.c:825:5: error: unused function 'usb_ocp_read' [-Werror,-Wunused-function] Signed-off-by: Matthias Kaehlcke Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ddc62cb69be8..e902df9595b9 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -840,12 +840,6 @@ int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA); } -static inline -int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data) -{ - return generic_ocp_read(tp, index, size, data, MCU_TYPE_USB); -} - static inline int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) { -- cgit v1.2.3 From ce064e68a7e1ae525cd525fac3a6901591ddae3c Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 18 May 2017 10:57:19 -0700 Subject: net1080: Remove unused function nc_dump_ttl() The function is not used, removing it fixes the following warning when building with clang: drivers/net/usb/net1080.c:271:20: error: unused function 'nc_dump_ttl' [-Werror,-Wunused-function] Also remove the definition of TTL_THIS, which is only used in nc_dump_ttl() Signed-off-by: Matthias Kaehlcke Signed-off-by: David S. Miller --- drivers/net/usb/net1080.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index 4cbdb1307f3e..3202c19df83d 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -264,17 +264,9 @@ static inline void nc_dump_status(struct usbnet *dev, u16 status) * TTL register */ -#define TTL_THIS(ttl) (0x00ff & ttl) #define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) #define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) -static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl) -{ - netif_dbg(dev, link, dev->net, "net1080 %s-%s ttl 0x%x this = %d, other = %d\n", - dev->udev->bus->bus_name, dev->udev->devpath, - ttl, TTL_THIS(ttl), TTL_OTHER(ttl)); -} - /*-------------------------------------------------------------------------*/ static int net1080_reset(struct usbnet *dev) @@ -308,7 +300,6 @@ static int net1080_reset(struct usbnet *dev) goto done; } ttl = vp; - // nc_dump_ttl(dev, ttl); nc_register_write(dev, REG_TTL, MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) ); -- cgit v1.2.3 From 6d0af07d5f4579ed8d43eb2de91c84c79c780755 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 18 May 2017 15:24:52 +0000 Subject: ibmvnic: fix missing unlock on error in __ibmvnic_reset() Add the missing unlock before return from function __ibmvnic_reset() in the error handling case. Fixes: ed651a10875f ("ibmvnic: Updated reset handling") Signed-off-by: Wei Yongjun Reviewed-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 4f2d329dba99..27f79339e9a8 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1313,6 +1313,7 @@ static void __ibmvnic_reset(struct work_struct *work) if (rc) { free_all_rwi(adapter); + mutex_unlock(&adapter->reset_lock); return; } -- cgit v1.2.3 From 74ed053d1c43f1476da82670f27536ddfcb75fdd Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 18 May 2017 15:26:29 +0000 Subject: qed: Remove unused including Remove including that is not needed. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_fcoe.c | 1 - drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 1 - drivers/net/ethernet/qlogic/qed/qed_l2.c | 1 - drivers/net/ethernet/qlogic/qed/qed_ll2.c | 1 - drivers/net/ethernet/qlogic/qed/qed_main.c | 1 - 5 files changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c index 21a58fffd02b..690dd2b903d4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index 3897ac0ae835..fba55662ea8b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 746fed4099c8..fab6e697c3ab 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 09c86411918c..b04dfc41fc9c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 537d1236a4fe..f286daa59bbc 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 27902f08065ba61514c331b7d6e85635c1655d82 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 18 May 2017 15:34:41 +0000 Subject: net/mlx5e: Fix possible memory leak 'encap_header' is malloced and should be freed before leaving from the error handling cases, otherwise it will cause memory leak. Fixes: 232c001398ae ("net/mlx5e: Add support to neighbour update flow") Signed-off-by: Wei Yongjun Reviewed-by: Yuval Shaia Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 11c27e4fadf6..a72ecbc27f85 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1404,8 +1404,8 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, if (!(nud_state & NUD_VALID)) { neigh_event_send(n, NULL); - neigh_release(n); - return -EAGAIN; + err = -EAGAIN; + goto out; } err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, @@ -1510,8 +1510,8 @@ static int mlx5e_create_encap_header_ipv6(struct mlx5e_priv *priv, if (!(nud_state & NUD_VALID)) { neigh_event_send(n, NULL); - neigh_release(n); - return -EAGAIN; + err = -EAGAIN; + goto out; } err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, -- cgit v1.2.3 From d41bf5c1c0ed980366dc0d5174a3706309652c20 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 18 May 2017 09:34:47 -0700 Subject: mwifiex: pcie: de-duplicate buffer allocation code This code was duplicated as part of the PCIe FLR code added to this driver. Let's de-duplicate it to: * make things easier to read (mwifiex_pcie_free_buffers() now has a corresponding mwifiex_pcie_alloc_buffers()) * reduce likelihood of bugs * make error logging equally verbose * save lines of code! Also drop some of the commentary that isn't really needed. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 157 ++++++++++++---------------- 1 file changed, 66 insertions(+), 91 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 78688ff6ecd0..8729809aa248 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2860,6 +2860,61 @@ static void mwifiex_pcie_card_reset(struct mwifiex_adapter *adapter) schedule_work(&card->work); } +static int mwifiex_pcie_alloc_buffers(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int ret; + + card->cmdrsp_buf = NULL; + ret = mwifiex_pcie_create_txbd_ring(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to create txbd ring\n"); + goto err_cre_txbd; + } + + ret = mwifiex_pcie_create_rxbd_ring(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to create rxbd ring\n"); + goto err_cre_rxbd; + } + + ret = mwifiex_pcie_create_evtbd_ring(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to create evtbd ring\n"); + goto err_cre_evtbd; + } + + ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to allocate cmdbuf buffer\n"); + goto err_alloc_cmdbuf; + } + + if (reg->sleep_cookie) { + ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); + if (ret) { + mwifiex_dbg(adapter, ERROR, "Failed to allocate sleep_cookie buffer\n"); + goto err_alloc_cookie; + } + } else { + card->sleep_cookie_vbase = NULL; + } + + return 0; + +err_alloc_cookie: + mwifiex_pcie_delete_cmdrsp_buf(adapter); +err_alloc_cmdbuf: + mwifiex_pcie_delete_evtbd_ring(adapter); +err_cre_evtbd: + mwifiex_pcie_delete_rxbd_ring(adapter); +err_cre_rxbd: + mwifiex_pcie_delete_txbd_ring(adapter); +err_cre_txbd: + return ret; +} + static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; @@ -2877,20 +2932,12 @@ static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter) /* * This function initializes the PCI-E host memory space, WCB rings, etc. - * - * The following initializations steps are followed - - * - Allocate TXBD ring buffers - * - Allocate RXBD ring buffers - * - Allocate event BD ring buffers - * - Allocate command response ring buffer - * - Allocate sleep cookie buffer */ static int mwifiex_init_pcie(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; int ret; struct pci_dev *pdev = card->dev; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; pci_set_drvdata(pdev, card); @@ -2939,37 +2986,13 @@ static int mwifiex_init_pcie(struct mwifiex_adapter *adapter) pr_notice("PCI memory map Virt0: %p PCI memory map Virt2: %p\n", card->pci_mmap, card->pci_mmap1); - card->cmdrsp_buf = NULL; - ret = mwifiex_pcie_create_txbd_ring(adapter); + ret = mwifiex_pcie_alloc_buffers(adapter); if (ret) - goto err_cre_txbd; - ret = mwifiex_pcie_create_rxbd_ring(adapter); - if (ret) - goto err_cre_rxbd; - ret = mwifiex_pcie_create_evtbd_ring(adapter); - if (ret) - goto err_cre_evtbd; - ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); - if (ret) - goto err_alloc_cmdbuf; - if (reg->sleep_cookie) { - ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); - if (ret) - goto err_alloc_cookie; - } else { - card->sleep_cookie_vbase = NULL; - } - return ret; + goto err_alloc_buffers; -err_alloc_cookie: - mwifiex_pcie_delete_cmdrsp_buf(adapter); -err_alloc_cmdbuf: - mwifiex_pcie_delete_evtbd_ring(adapter); -err_cre_evtbd: - mwifiex_pcie_delete_rxbd_ring(adapter); -err_cre_rxbd: - mwifiex_pcie_delete_txbd_ring(adapter); -err_cre_txbd: + return 0; + +err_alloc_buffers: pci_iounmap(pdev, card->pci_mmap1); err_iomap2: pci_release_region(pdev, 2); @@ -3183,73 +3206,25 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) card->adapter = NULL; } -/* This function initializes the PCI-E host memory space, WCB rings, etc. - * - * The following initializations steps are followed - - * - Allocate TXBD ring buffers - * - Allocate RXBD ring buffers - * - Allocate event BD ring buffers - * - Allocate command response ring buffer - * - Allocate sleep cookie buffer - * Part of mwifiex_init_pcie(), not reset the PCIE registers +/* + * This function initializes the PCI-E host memory space, WCB rings, etc., + * similar to mwifiex_init_pcie(), but without resetting PCI-E state. */ static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; int ret; struct pci_dev *pdev = card->dev; - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; /* tx_buf_size might be changed to 3584 by firmware during * data transfer, we should reset it to default size. */ adapter->tx_buf_size = card->pcie.tx_buf_size; - card->cmdrsp_buf = NULL; - ret = mwifiex_pcie_create_txbd_ring(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to create txbd ring\n"); - goto err_cre_txbd; - } - - ret = mwifiex_pcie_create_rxbd_ring(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to create rxbd ring\n"); - goto err_cre_rxbd; - } - - ret = mwifiex_pcie_create_evtbd_ring(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to create evtbd ring\n"); - goto err_cre_evtbd; - } - - ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to allocate cmdbuf buffer\n"); - goto err_alloc_cmdbuf; - } - - if (reg->sleep_cookie) { - ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); - if (ret) { - mwifiex_dbg(adapter, ERROR, "Failed to allocate sleep_cookie buffer\n"); - goto err_alloc_cookie; - } - } else { - card->sleep_cookie_vbase = NULL; - } - return; + ret = mwifiex_pcie_alloc_buffers(adapter); + if (!ret) + return; -err_alloc_cookie: - mwifiex_pcie_delete_cmdrsp_buf(adapter); -err_alloc_cmdbuf: - mwifiex_pcie_delete_evtbd_ring(adapter); -err_cre_evtbd: - mwifiex_pcie_delete_rxbd_ring(adapter); -err_cre_rxbd: - mwifiex_pcie_delete_txbd_ring(adapter); -err_cre_txbd: pci_iounmap(pdev, card->pci_mmap1); } -- cgit v1.2.3 From 8535107aa4ef92520cbb9a4739563b389c5f8e2c Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 12 May 2017 09:41:58 -0700 Subject: mwifiex: fixup error cases in mwifiex_add_virtual_intf() If we fail to add an interface in mwifiex_add_virtual_intf(), we might hit a BUG_ON() in the networking code, because we didn't tear things down properly. Among the problems: (a) when failing to allocate workqueues, we fail to unregister the netdev before calling free_netdev() (b) even if we do try to unregister the netdev, we're still holding the rtnl lock, so the device never properly unregistered; we'll be at state NETREG_UNREGISTERING, and then hit free_netdev()'s: BUG_ON(dev->reg_state != NETREG_UNREGISTERED); (c) we're allocating some dependent resources (e.g., DFS workqueues) after we've registered the interface; this may or may not cause problems, but it's good practice to allocate these before registering (d) we're not even trying to unwind anything when mwifiex_send_cmd() or mwifiex_sta_init_cmd() fail To fix these issues, let's: * add a stacked set of error handling labels, to keep error handling consistent and properly ordered (resolving (a) and (d)) * move the workqueue allocations before the registration (to resolve (c); also resolves (b) by avoiding error cases where we have to unregister) [Incidentally, it's pretty easy to interrupt the alloc_workqueue() in, e.g., the following: iw phy phy0 interface add mlan0 type station by sending it SIGTERM.] This bugfix covers commits like commit 7d652034d1a0 ("mwifiex: channel switch support for mwifiex"), but parts of this bug exist all the way back to the introduction of dynamic interface handling in commit 93a1df48d224 ("mwifiex: add cfg80211 handlers add/del_virtual_intf"). Cc: Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 71 ++++++++++++------------- 1 file changed, 35 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 7ec06bf13413..025bc06a19d6 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -2964,10 +2964,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, if (!dev) { mwifiex_dbg(adapter, ERROR, "no memory available for netdevice\n"); - memset(&priv->wdev, 0, sizeof(priv->wdev)); - priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - return ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto err_alloc_netdev; } mwifiex_init_priv_params(priv, dev); @@ -2976,11 +2974,11 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, HostCmd_ACT_GEN_SET, 0, NULL, true); if (ret) - return ERR_PTR(ret); + goto err_set_bss_mode; ret = mwifiex_sta_init_cmd(priv, false, false); if (ret) - return ERR_PTR(ret); + goto err_sta_init; mwifiex_setup_ht_caps(&wiphy->bands[NL80211_BAND_2GHZ]->ht_cap, priv); if (adapter->is_hw_11ac_capable) @@ -3011,31 +3009,14 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, SET_NETDEV_DEV(dev, adapter->dev); - /* Register network device */ - if (register_netdevice(dev)) { - mwifiex_dbg(adapter, ERROR, - "cannot register virtual network device\n"); - free_netdev(dev); - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - priv->netdev = NULL; - memset(&priv->wdev, 0, sizeof(priv->wdev)); - priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - return ERR_PTR(-EFAULT); - } - priv->dfs_cac_workqueue = alloc_workqueue("MWIFIEX_DFS_CAC%s", WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1, name); if (!priv->dfs_cac_workqueue) { - mwifiex_dbg(adapter, ERROR, - "cannot register virtual network device\n"); - free_netdev(dev); - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - priv->netdev = NULL; - memset(&priv->wdev, 0, sizeof(priv->wdev)); - priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - return ERR_PTR(-ENOMEM); + mwifiex_dbg(adapter, ERROR, "cannot alloc DFS CAC queue\n"); + ret = -ENOMEM; + goto err_alloc_cac; } INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue); @@ -3044,16 +3025,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, WQ_HIGHPRI | WQ_UNBOUND | WQ_MEM_RECLAIM, 1, name); if (!priv->dfs_chan_sw_workqueue) { - mwifiex_dbg(adapter, ERROR, - "cannot register virtual network device\n"); - free_netdev(dev); - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - priv->netdev = NULL; - memset(&priv->wdev, 0, sizeof(priv->wdev)); - priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - destroy_workqueue(priv->dfs_cac_workqueue); - priv->dfs_cac_workqueue = NULL; - return ERR_PTR(-ENOMEM); + mwifiex_dbg(adapter, ERROR, "cannot alloc DFS channel sw queue\n"); + ret = -ENOMEM; + goto err_alloc_chsw; } INIT_DELAYED_WORK(&priv->dfs_chan_sw_work, @@ -3061,6 +3035,13 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, sema_init(&priv->async_sem, 1); + /* Register network device */ + if (register_netdevice(dev)) { + mwifiex_dbg(adapter, ERROR, "cannot register network device\n"); + ret = -EFAULT; + goto err_reg_netdev; + } + mwifiex_dbg(adapter, INFO, "info: %s: Marvell 802.11 Adapter\n", dev->name); @@ -3081,11 +3062,29 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, adapter->curr_iface_comb.p2p_intf++; break; default: + /* This should be dead code; checked above */ mwifiex_dbg(adapter, ERROR, "type not supported\n"); return ERR_PTR(-EINVAL); } return &priv->wdev; + +err_reg_netdev: + destroy_workqueue(priv->dfs_chan_sw_workqueue); + priv->dfs_chan_sw_workqueue = NULL; +err_alloc_chsw: + destroy_workqueue(priv->dfs_cac_workqueue); + priv->dfs_cac_workqueue = NULL; +err_alloc_cac: + free_netdev(dev); + priv->netdev = NULL; +err_sta_init: +err_set_bss_mode: +err_alloc_netdev: + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); -- cgit v1.2.3 From e0b636e5ee15558c6240fa8738f2b608c07ea17a Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 12 May 2017 09:41:59 -0700 Subject: mwifiex: Don't release tx_ba_stream_tbl_lock while iterating Despite the macro list_for_each_entry_safe() having the word "safe" in the name, it's still not actually safe to release the list spinlock while iterating over the list. The "safe" in the macro name actually only means that it's safe to delete the current entry while iterating over the list. Releasing the spinlock while iterating over the list means that someone else could come in and adjust the list while we don't have the spinlock. If they do that it can totally mix up our iteration and fully corrupt the list. Later iterating over a corrupted list while holding a spinlock and having IRQs off can cause all sorts of hard to debug problems. As evidenced by the other call to mwifiex_11n_delete_tx_ba_stream_tbl_entry() in mwifiex_11n_delete_all_tx_ba_stream_tbl(), it's actually safe to skip the spinlock release. Let's do that. No known problems are fixed by this patch, but it could fix all sorts of weird problems and it should be very safe. Signed-off-by: Douglas Anderson Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/11n.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c index c174e79e6df2..c75b6abf16a0 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -764,14 +764,9 @@ void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra) return; spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); - list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) { - if (!memcmp(tbl->ra, ra, ETH_ALEN)) { - spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, - flags); + list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) + if (!memcmp(tbl->ra, ra, ETH_ALEN)) mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl); - spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); - } - } spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); return; -- cgit v1.2.3 From 90ad0be83676c82d9f1bfc1c1c3b3f61f3291017 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 12 May 2017 09:42:00 -0700 Subject: mwifiex: Don't release cmd_pending_q_lock while iterating Just like in the previous patch ("mwifiex: Don't release tx_ba_stream_tbl_lock while iterating"), in mwifiex_cancel_all_pending_cmd() we were itearting over a list protected by a spinlock. Again, it is not safe to release the spinlock while iterating. Don't do it. Luckily in this case there should be no need to release the spinlock. This is evidenced by: 1. The only function called while the spinlock was released was mwifiex_recycle_cmd_node() 2. Aside from atomic functions (which are safe to call), the only function called by mwifiex_recycle_cmd_node() was mwifiex_insert_cmd_to_free_q(). 3. It can be seen in mwifiex_cancel_pending_scan_cmd() that it's OK to call mwifiex_insert_cmd_to_free_q() while holding a different spinlock (scan_pending_q_lock), so in general holding a spinlock should be OK. 4. It doesn't appear that mwifiex_insert_cmd_to_free_q() has any interaction with the cmd_pending_q_lock No known bugs are fixed with this change, but as with other similar changes this could fix random list corruption. Signed-off-by: Douglas Anderson Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cmdevt.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 0c3b217247b1..5fd6c53d7b06 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -1056,12 +1056,10 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) list_for_each_entry_safe(cmd_node, tmp_node, &adapter->cmd_pending_q, list) { list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); if (cmd_node->wait_q_enabled) adapter->cmd_wait_q.status = -1; mwifiex_recycle_cmd_node(adapter, cmd_node); - spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); } spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); -- cgit v1.2.3 From 09bdb65005515c97b29e0792bc6e5598d9e4035f Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 12 May 2017 09:42:01 -0700 Subject: mwifiex: Add locking to mwifiex_11n_delba The mwifiex_11n_delba() function walked the rx_reorder_tbl_ptr without holding the lock, which was an obvious violation. Grab the lock. NOTE: we hold the lock while calling mwifiex_send_delba(). There's also several callers in 11n_rxreorder.c that hold the lock and the comments in the struct sound just like very other list/lock pair -- as if the lock should definitely be help for all operations like this. Signed-off-by: Douglas Anderson Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/11n.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c index c75b6abf16a0..16c77c27f1b6 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -653,11 +653,13 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, void mwifiex_11n_delba(struct mwifiex_private *priv, int tid) { struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + unsigned long flags; + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); if (list_empty(&priv->rx_reorder_tbl_ptr)) { dev_dbg(priv->adapter->dev, "mwifiex_11n_delba: rx_reorder_tbl_ptr empty\n"); - return; + goto exit; } list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { @@ -666,9 +668,11 @@ void mwifiex_11n_delba(struct mwifiex_private *priv, int tid) "Send delba to tid=%d, %pM\n", tid, rx_reor_tbl_ptr->ta); mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0); - return; + goto exit; } } +exit: + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); } /* -- cgit v1.2.3 From 0f13acf0c61234b22e2c1478a932a7610b7ad7ca Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 12 May 2017 09:42:02 -0700 Subject: mwifiex: don't drop lock between list-retrieval / list-deletion mwifiex_exec_next_cmd() seems to have a classic TOCTOU race, where we drop the list lock in between retrieving the next command and deleting it from the list. This potentially leaves room for someone else to also retrieve / steal this node from the list (e.g., mwifiex_cancel_all_pending_cmd()). Let's keep holding the lock while we do our 'ps_state' sanity checks. There should be no harm in continuing to hold this lock for a bit more. Noticed only by code inspection. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cmdevt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 5fd6c53d7b06..95221306a4e5 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -761,8 +761,6 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) } cmd_node = list_first_entry(&adapter->cmd_pending_q, struct cmd_ctrl_node, list); - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); priv = cmd_node->priv; @@ -771,11 +769,12 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) mwifiex_dbg(adapter, ERROR, "%s: cannot send cmd in sleep state,\t" "this should not happen\n", __func__); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); return ret; } - spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); -- cgit v1.2.3 From 6eb2d002d4ea3157c7dee90dcaf6ca13cd729169 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 12 May 2017 09:42:03 -0700 Subject: mwifiex: don't leak stashed beacon buffer on reset When removing or resetting an mwifiex device, we don't remember to free the saved beacon buffer. Use the (somewhat misleadingly-named) mwifiex_free_priv() helper to handle this. Noticed by kmemleak during tests: echo 1 > /sys/bus/pci/devices/.../reset unreferenced object 0xffffffc09d034a00 (size 256): ... backtrace: [] create_object+0x228/0x3c4 [] kmemleak_alloc+0x54/0x88 [] __kmalloc+0x1cc/0x2dc [] mwifiex_save_curr_bcn+0x80/0x308 [mwifiex] [] mwifiex_ret_802_11_associate+0x4ec/0x5fc [mwifiex] [] mwifiex_process_sta_cmdresp+0xaf8/0x1fa4 [mwifiex] [] mwifiex_process_cmdresp+0x40c/0x510 [mwifiex] [] mwifiex_main_process+0x4a4/0xb00 [mwifiex] [] mwifiex_main_work_queue+0x34/0x40 [mwifiex] Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 756948385b60..2ada202c72ec 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -670,8 +670,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) mwifiex_clean_auto_tdls(priv); mwifiex_abort_cac(priv); - mwifiex_clean_txrx(priv); - mwifiex_delete_bss_prio_tbl(priv); + mwifiex_free_priv(priv); } } -- cgit v1.2.3 From bc69ca391eff0de1fb57066a5407d59723ed2da5 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 12 May 2017 09:42:04 -0700 Subject: mwifiex: remove useless 'mwifiex_lock' If mwifiex_shutdown_drv() is racing with another mwifiex_shutdown_drv(), we *really* have problems. Kill the lock. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/init.c | 4 ---- drivers/net/wireless/marvell/mwifiex/main.h | 2 -- 2 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 2ada202c72ec..2bff87bd76a6 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -439,7 +439,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) struct mwifiex_private *priv; s32 i, j; - spin_lock_init(&adapter->mwifiex_lock); spin_lock_init(&adapter->int_lock); spin_lock_init(&adapter->main_proc_lock); spin_lock_init(&adapter->mwifiex_cmd_lock); @@ -693,11 +692,8 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); - spin_lock(&adapter->mwifiex_lock); - mwifiex_adapter_cleanup(adapter); - spin_unlock(&adapter->mwifiex_lock); adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY; } diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 6e76b302739b..c1d96c64af74 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -870,8 +870,6 @@ struct mwifiex_adapter { bool rx_locked; bool main_locked; struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; - /* spin lock for init/shutdown */ - spinlock_t mwifiex_lock; /* spin lock for main process */ spinlock_t main_proc_lock; u32 mwifiex_processing; -- cgit v1.2.3 From 7170862738dc129d98f8ea99f28b2d0d133365eb Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 12 May 2017 09:42:05 -0700 Subject: mwifiex: remove redundant 'adapter' check in mwifiex_adapter_cleanup We're using 'adapter' right before calling this. Stop being unnecessarily paranoid. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/init.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 2bff87bd76a6..80bdf1c5f77f 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -409,11 +409,6 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) static void mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) { - if (!adapter) { - pr_err("%s: adapter is NULL\n", __func__); - return; - } - del_timer(&adapter->wakeup_timer); mwifiex_cancel_all_pending_cmd(adapter); wake_up_interruptible(&adapter->cmd_wait_q.wait); -- cgit v1.2.3 From 7ade530e7384d3ee7b3919c1e7cf436c25631238 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 12 May 2017 09:42:06 -0700 Subject: mwifiex: 11h: drop unnecessary check for '!priv' These pointers are retrieved via container_of(). There's no way they are NULL. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/11h.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index 366eb4991a7d..238accfe4f41 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -128,9 +128,6 @@ void mwifiex_dfs_cac_work_queue(struct work_struct *work) container_of(delayed_work, struct mwifiex_private, dfs_cac_work); - if (WARN_ON(!priv)) - return; - chandef = priv->dfs_chandef; if (priv->wdev.cac_started) { mwifiex_dbg(priv->adapter, MSG, @@ -289,9 +286,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) container_of(delayed_work, struct mwifiex_private, dfs_chan_sw_work); - if (WARN_ON(!priv)) - return; - bss_cfg = &priv->bss_cfg; if (!bss_cfg->beacon_period) { mwifiex_dbg(priv->adapter, ERROR, -- cgit v1.2.3 From fa4651e12ae8ac1b691cee9d0cd6554a934428b7 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 12 May 2017 09:42:07 -0700 Subject: mwifiex: pcie: remove useless pdev check Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 8729809aa248..be5050a536e1 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2380,11 +2380,6 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) struct pcie_service_card *card; struct mwifiex_adapter *adapter; - if (!pdev) { - pr_err("info: %s: pdev is NULL\n", __func__); - goto exit; - } - card = pci_get_drvdata(pdev); if (!card->adapter) { -- cgit v1.2.3 From 68efd038698871ec86855642fdb83353902a258c Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 12 May 2017 09:42:08 -0700 Subject: mwifiex: pcie: stop setting/clearing 'surprise_removed' These are already handled by mwifiex_shutdown_sw() and mwifiex_reinit_sw(). Ideally, we'll kill the flag entirely eventually, as I suspect it breeds race conditions. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index be5050a536e1..394224d6c219 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -370,7 +370,6 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) * PCIe and HW. */ mwifiex_shutdown_sw(adapter); - adapter->surprise_removed = true; clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); } else { @@ -378,7 +377,6 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) * after performing FLR respectively. Reconfigure the software * and firmware including firmware redownload */ - adapter->surprise_removed = false; ret = mwifiex_reinit_sw(adapter); if (ret) { dev_err(&pdev->dev, "reinit failed: %d\n", ret); -- cgit v1.2.3 From a1ad7198202ff9a2436bd24437730e78d90c5271 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 12 May 2017 12:15:55 +0200 Subject: mwifiex: add missing USB-descriptor endianness conversion Add the missing endianness conversions to a debug statement printing the USB device-descriptor bcdUSB field during probe. Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 2f7705c50161..debd6216366a 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -424,7 +424,8 @@ static int mwifiex_usb_probe(struct usb_interface *intf, card->intf = intf; pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x\n", - udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass, + le16_to_cpu(udev->descriptor.bcdUSB), + udev->descriptor.bDeviceClass, udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceProtocol); -- cgit v1.2.3 From 1ed760c9aca0b69c5b24c6fd454bcc573a01df99 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Tue, 25 Apr 2017 10:10:08 +0100 Subject: ath6kl: assure headroom of skbuff is writable in .start_xmit() An issue was found brcmfmac driver in which a skbuff in .start_xmit() callback was actually cloned. So instead of checking for sufficient headroom it should also be writable. Hence use skb_cow_head() to check and expand the headroom appropriately. Signed-off-by: Arend van Spriel Tested-by: Steve deRosier Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/txrx.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index a531e0c5c1e2..e6b2517e6334 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -399,15 +399,10 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) csum_dest = skb->csum_offset + csum_start; } - if (skb_headroom(skb) < dev->needed_headroom) { - struct sk_buff *tmp_skb = skb; - - skb = skb_realloc_headroom(skb, dev->needed_headroom); - kfree_skb(tmp_skb); - if (skb == NULL) { - dev->stats.tx_dropped++; - return 0; - } + if (skb_cow_head(skb, dev->needed_headroom)) { + dev->stats.tx_dropped++; + kfree_skb(skb); + return 0; } if (ath6kl_wmi_dix_2_dot3(ar->wmi, skb)) { -- cgit v1.2.3 From c46e2a848f29ce592f5f0db81757d17bbdbe45e4 Mon Sep 17 00:00:00 2001 From: Ammly Fredrick Date: Thu, 27 Apr 2017 19:31:37 +0300 Subject: ath9k: fix spelling in ath9k_tx99_init() It's spelled hardware, not harware. Signed-off-by: Ammly Fredrick [kvalo@qca.qualcomm.com: improve commit log] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/tx99.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 16aca9e28b77..a866cbda0799 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -153,7 +153,7 @@ static int ath9k_tx99_init(struct ath_softc *sc) sc->tx99_power, sc->tx99_power / 2); - /* We leave the harware awake as it will be chugging on */ + /* We leave the hardware awake as it will be chugging on */ return 0; } -- cgit v1.2.3 From 8fed6823e06e43ee9cf7c0ffecec2f9111ce6201 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 3 May 2017 15:26:00 +0100 Subject: ath5k: fix memory leak on buf on failed eeprom read The AR5K_EEPROM_READ macro returns with -EIO if a read error occurs causing a memory leak on the allocated buffer buf. Fix this by explicitly calling ath5k_hw_nvram_read and exiting on the via the freebuf label that performs the necessary free'ing of buf when a read error occurs. Detected by CoverityScan, CID#1248782 ("Resource Leak") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath5k/debug.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index d068df520e7a..bd7f6d7b199e 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -938,7 +938,10 @@ static int open_file_eeprom(struct inode *inode, struct file *file) } for (i = 0; i < eesize; ++i) { - AR5K_EEPROM_READ(i, val); + if (!ath5k_hw_nvram_read(ah, i, &val)) { + ret = -EIO; + goto freebuf; + } buf[i] = val; } -- cgit v1.2.3 From 9a49290919e1787ced66dcca055712338a9ee888 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sat, 6 May 2017 23:42:19 +0800 Subject: wil6210: use memdup_user Use memdup_user() helper instead of open-coding to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 5648ebbd0e16..5b0f9fc66bb6 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -795,15 +795,11 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, struct wireless_dev *wdev = wil_to_wdev(wil); struct cfg80211_mgmt_tx_params params; int rc; - void *frame = kmalloc(len, GFP_KERNEL); + void *frame; - if (!frame) - return -ENOMEM; - - if (copy_from_user(frame, buf, len)) { - kfree(frame); - return -EIO; - } + frame = memdup_user(buf, len); + if (IS_ERR(frame)) + return PTR_ERR(frame); params.buf = frame; params.len = len; -- cgit v1.2.3 From 641c1f4ab7f62278a3a08c0861725ba21a53e5d5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 9 May 2017 08:04:30 -0500 Subject: ath9k: remove unnecessary code The array field eeprom_data in struct th9k_platform_data is a fixed size array so it can never be NULL. Addresses-Coverity-ID: 1364903 Cc: Arend Van Spriel Cc: Kalle Valo Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 6ccf24814514..6fbd5559c0c0 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -143,7 +143,7 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) if (ah->eeprom_blob) ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data); - else if (pdata && !pdata->use_eeprom && pdata->eeprom_data) + else if (pdata && !pdata->use_eeprom) ret = ath9k_hw_nvram_read_pdata(pdata, off, data); else ret = common->bus_ops->eeprom_read(common, off, data); -- cgit v1.2.3 From b01c9e327249e4995e5b5b6cebec14166db9c1e7 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 10 May 2017 10:54:54 +0200 Subject: ath9k: check ah->curchan when updating tx power When driver fail to reset card ah->curchan value stay NULL. When later driver try to update tx power it oops by using ah->curchan (calltrace is shown below). This problem were reported at various places and for some it was fixed by making ath9k_hw_chip_reset() do not fail. I have this bug report on some oldish RHEL kernel with AR9285, however it's hard to debug where reset fail when kernel OOPS, so I think this patch should be applied. Hopefully ah->curchan is not used unconditionally on other places until is initialized on ath9k_config(). ath: phy0: Chip reset failed ath: phy0: Unable to reset hardware; reset status -22 (freq 2412 MHz) BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] ath9k_hw_set_txpowerlimit+0x25/0x80 [ath9k_hw] Oops: 0000 [#1] SMP Call Trace: [] ? ath9k_cmn_update_txpow+0x1a/0x30 [ath9k_common] [] ? ath_complete_reset+0x4e/0x130 [ath9k] [] ? ath9k_start+0x127/0x1e0 [ath9k] [] ? ieee80211_do_open+0x30f/0x910 [mac80211] [] ? dev_open+0x8d/0xf0 Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index b80e08b13b74..eea2f7f23a2a 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -368,7 +368,7 @@ void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, { struct ath_regulatory *reg = ath9k_hw_regulatory(ah); - if (reg->power_limit != new_txpow) + if (ah->curchan && reg->power_limit != new_txpow) ath9k_hw_set_txpowerlimit(ah, new_txpow, false); /* read back in case value is clamped */ -- cgit v1.2.3 From 219f1d79871257e9603f504dce0fe8ebf47aad08 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 18 May 2017 15:44:39 +0200 Subject: sk_buff: remove support for csum_bad in sk_buff This bit was introduced with commit 5a21232983aa ("net: Support for csum_bad in skbuff") to reduce the stack workload when processing RX packets carrying a wrong Internet Checksum. Up to now, only one driver and GRO core are setting it. Suggested-by: Tom Herbert Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 3a8a4aa13687..9a0817938eca 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -223,7 +223,7 @@ int aq_ring_rx_clean(struct aq_ring_s *self, int *work_done, int budget) skb->protocol = eth_type_trans(skb, ndev); if (unlikely(buff->is_cso_err)) { ++self->stats.rx.errors; - __skb_mark_checksum_bad(skb); + skb->ip_summed = CHECKSUM_NONE; } else { if (buff->is_ip_cso) { __skb_incr_checksum_unnecessary(skb); -- cgit v1.2.3 From 326dde3e3b2ed05e5882e4401368d0f5d8861da7 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Thu, 18 May 2017 15:13:44 -0700 Subject: xgene: Check all RGMII phy mode variants This patch addresses the review comment from the previous patch set, by using phy_interface_mode_is_rgmii() helper function to address all RGMII phy mode variants. Signed-off-by: Iyappan Subramanian Signed-off-by: Quan Nguyen Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c | 6 +++--- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 12 ++++++------ drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 15 +++++++++------ 3 files changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 0fdec78c5399..559963b1aa32 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -127,7 +127,7 @@ static int xgene_get_link_ksettings(struct net_device *ndev, struct phy_device *phydev = ndev->phydev; u32 supported; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + if (phy_interface_mode_is_rgmii(pdata->phy_mode)) { if (phydev == NULL) return -ENODEV; @@ -177,7 +177,7 @@ static int xgene_set_link_ksettings(struct net_device *ndev, struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct phy_device *phydev = ndev->phydev; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + if (phy_interface_mode_is_rgmii(pdata->phy_mode)) { if (!phydev) return -ENODEV; @@ -304,7 +304,7 @@ static int xgene_set_pauseparam(struct net_device *ndev, struct phy_device *phydev = ndev->phydev; u32 oldadv, newadv; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII || + if (phy_interface_mode_is_rgmii(pdata->phy_mode) || pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { if (!phydev) return -EINVAL; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 6ac27c7522a7..e45b587c2994 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -272,7 +272,7 @@ void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr, u32 wr_data) u32 done; if (pdata->mdio_driver && ndev->phydev && - pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { + phy_interface_mode_is_rgmii(pdata->phy_mode)) { struct mii_bus *bus = ndev->phydev->mdio.bus; return xgene_mdio_wr_mac(bus->priv, wr_addr, wr_data); @@ -326,12 +326,13 @@ static void xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *pdata, u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr) { void __iomem *addr, *rd, *cmd, *cmd_done; + struct net_device *ndev = pdata->ndev; u32 done, rd_data; u8 wait = 10; - if (pdata->mdio_driver && pdata->ndev->phydev && - pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { - struct mii_bus *bus = pdata->ndev->phydev->mdio.bus; + if (pdata->mdio_driver && ndev->phydev && + phy_interface_mode_is_rgmii(pdata->phy_mode)) { + struct mii_bus *bus = ndev->phydev->mdio.bus; return xgene_mdio_rd_mac(bus->priv, rd_addr); } @@ -349,8 +350,7 @@ u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr) udelay(1); if (!done) - netdev_err(pdata->ndev, "mac read failed, addr: %04x\n", - rd_addr); + netdev_err(ndev, "mac read failed, addr: %04x\n", rd_addr); rd_data = ioread32(rd); iowrite32(0, cmd); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 21cd4ef3e5eb..d3906f6b01bd 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -1634,7 +1634,7 @@ static int xgene_enet_get_irqs(struct xgene_enet_pdata *pdata) struct device *dev = &pdev->dev; int i, ret, max_irqs; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + if (phy_interface_mode_is_rgmii(pdata->phy_mode)) max_irqs = 1; else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) max_irqs = 2; @@ -1760,7 +1760,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) dev_err(dev, "Unable to get phy-connection-type\n"); return pdata->phy_mode; } - if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII && + if (!phy_interface_mode_is_rgmii(pdata->phy_mode) && pdata->phy_mode != PHY_INTERFACE_MODE_SGMII && pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { dev_err(dev, "Incorrect phy-connection-type specified\n"); @@ -1805,7 +1805,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) pdata->cle.base = base_addr + BLOCK_ETH_CLE_CSR_OFFSET; pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET; pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET; - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII || + if (phy_interface_mode_is_rgmii(pdata->phy_mode) || pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { pdata->mcx_mac_addr = pdata->base_addr + BLOCK_ETH_MAC_OFFSET; pdata->mcx_stats_addr = @@ -1904,6 +1904,9 @@ static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) { switch (pdata->phy_mode) { case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: pdata->mac_ops = &xgene_gmac_ops; pdata->port_ops = &xgene_gport_ops; pdata->rm = RM3; @@ -2100,7 +2103,7 @@ static int xgene_enet_probe(struct platform_device *pdev) if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { INIT_DELAYED_WORK(&pdata->link_work, link_state); } else if (!pdata->mdio_driver) { - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + if (phy_interface_mode_is_rgmii(pdata->phy_mode)) ret = xgene_enet_mdio_config(pdata); else INIT_DELAYED_WORK(&pdata->link_work, link_state); @@ -2131,7 +2134,7 @@ err2: if (pdata->mdio_driver) xgene_enet_phy_disconnect(pdata); - else if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + else if (phy_interface_mode_is_rgmii(pdata->phy_mode)) xgene_enet_mdio_remove(pdata); err1: xgene_enet_delete_desc_rings(pdata); @@ -2155,7 +2158,7 @@ static int xgene_enet_remove(struct platform_device *pdev) if (pdata->mdio_driver) xgene_enet_phy_disconnect(pdata); - else if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + else if (phy_interface_mode_is_rgmii(pdata->phy_mode)) xgene_enet_mdio_remove(pdata); unregister_netdev(ndev); -- cgit v1.2.3 From ba798b5b6d067baa7ca7be3cdfd1f37a89da873f Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 21 May 2017 12:10:52 +0300 Subject: qede: Allow WoL to activate by default When management firmware declares that the device is WoL-capable, the default driver behavior would be to allow the management firmware to take the decision of whether it's actually needed or not. Problem is ethtool interface doesn't have a 'default' kind of option, and user would see the interface WoL as disabled, which doesn't accurately reflect the actual configuration. More-so, if the user actually wants to explicitly disable WoL he'd have to first enable it [otherwise ethtool would block the command]. Instead of allowing management to make the decision, enable WoL by default on all devices capable of it. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 38b77bbfe4ee..4a460525b1e5 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -618,6 +618,12 @@ static struct qede_dev *qede_alloc_etherdev(struct qed_dev *cdev, memset(&edev->stats, 0, sizeof(edev->stats)); memcpy(&edev->dev_info, info, sizeof(*info)); + /* As ethtool doesn't have the ability to show WoL behavior as + * 'default', if device supports it declare it's enabled. + */ + if (edev->dev_info.common.wol_support) + edev->wol_enabled = true; + INIT_LIST_HEAD(&edev->vlan_list); return edev; -- cgit v1.2.3 From 5a052d62ab01cc95446f47cb1f41c3bd99546051 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Sun, 21 May 2017 12:10:53 +0300 Subject: qede: Honor user request for Tx buffers Driver always allocates the maximal number of tx-buffers irrespective of actual Tx ring config. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 6 +++--- drivers/net/ethernet/qlogic/qede/qede_fp.c | 18 +++++++++--------- drivers/net/ethernet/qlogic/qede/qede_main.c | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 172b292241a5..47ec4f3cfe79 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -1297,7 +1297,7 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, } /* Fill the entry in the SW ring and the BDs in the FW ring */ - idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; + idx = txq->sw_tx_prod; txq->sw_tx_ring.skbs[idx].skb = skb; first_bd = qed_chain_produce(&txq->tx_pbl); memset(first_bd, 0, sizeof(*first_bd)); @@ -1317,7 +1317,7 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, /* update the first BD with the actual num BDs */ first_bd->data.nbds = 1; - txq->sw_tx_prod++; + txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers; /* 'next page' entries are counted in the producer value */ val = cpu_to_le16(qed_chain_get_prod_idx(&txq->tx_pbl)); txq->tx_db.data.bd_prod = val; @@ -1351,7 +1351,7 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, first_bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl); dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE); - txq->sw_tx_cons++; + txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers; txq->sw_tx_ring.skbs[idx].skb = NULL; return 0; diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index 7b6f41d06245..38c82658e5bd 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -99,7 +99,7 @@ int qede_alloc_rx_buffer(struct qede_rx_queue *rxq, bool allow_lazy) /* Unmap the data and free skb */ int qede_free_tx_pkt(struct qede_dev *edev, struct qede_tx_queue *txq, int *len) { - u16 idx = txq->sw_tx_cons & NUM_TX_BDS_MAX; + u16 idx = txq->sw_tx_cons; struct sk_buff *skb = txq->sw_tx_ring.skbs[idx].skb; struct eth_tx_1st_bd *first_bd; struct eth_tx_bd *tx_data_bd; @@ -156,7 +156,7 @@ static void qede_free_failed_tx_pkt(struct qede_tx_queue *txq, struct eth_tx_1st_bd *first_bd, int nbd, bool data_split) { - u16 idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; + u16 idx = txq->sw_tx_prod; struct sk_buff *skb = txq->sw_tx_ring.skbs[idx].skb; struct eth_tx_bd *tx_data_bd; int i, split_bd_len = 0; @@ -333,8 +333,8 @@ static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp, struct sw_rx_data *metadata, u16 padding, u16 length) { struct qede_tx_queue *txq = fp->xdp_tx; - u16 idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; struct eth_tx_1st_bd *first_bd; + u16 idx = txq->sw_tx_prod; if (!qed_chain_get_elem_left(&txq->tx_pbl)) { txq->stopped_cnt++; @@ -363,7 +363,7 @@ static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp, txq->sw_tx_ring.xdp[idx].page = metadata->data; txq->sw_tx_ring.xdp[idx].mapping = metadata->mapping; - txq->sw_tx_prod++; + txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers; /* Mark the fastpath for future XDP doorbell */ fp->xdp_xmit = 1; @@ -393,14 +393,14 @@ static void qede_xdp_tx_int(struct qede_dev *edev, struct qede_tx_queue *txq) while (hw_bd_cons != qed_chain_get_cons_idx(&txq->tx_pbl)) { qed_chain_consume(&txq->tx_pbl); - idx = txq->sw_tx_cons & NUM_TX_BDS_MAX; + idx = txq->sw_tx_cons; dma_unmap_page(&edev->pdev->dev, txq->sw_tx_ring.xdp[idx].mapping, PAGE_SIZE, DMA_BIDIRECTIONAL); __free_page(txq->sw_tx_ring.xdp[idx].page); - txq->sw_tx_cons++; + txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers; txq->xmit_pkts++; } } @@ -430,7 +430,7 @@ static int qede_tx_int(struct qede_dev *edev, struct qede_tx_queue *txq) bytes_compl += len; pkts_compl++; - txq->sw_tx_cons++; + txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers; txq->xmit_pkts++; } @@ -1455,7 +1455,7 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) #endif /* Fill the entry in the SW ring and the BDs in the FW ring */ - idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; + idx = txq->sw_tx_prod; txq->sw_tx_ring.skbs[idx].skb = skb; first_bd = (struct eth_tx_1st_bd *) qed_chain_produce(&txq->tx_pbl); @@ -1639,7 +1639,7 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Advance packet producer only before sending the packet since mapping * of pages may fail. */ - txq->sw_tx_prod++; + txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers; /* 'next page' entries are counted in the producer value */ txq->tx_db.data.bd_prod = diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 4a460525b1e5..766bd373fa99 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1304,12 +1304,12 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) /* Allocate the parallel driver ring for Tx buffers */ if (txq->is_xdp) { - size = sizeof(*txq->sw_tx_ring.xdp) * TX_RING_SIZE; + size = sizeof(*txq->sw_tx_ring.xdp) * txq->num_tx_buffers; txq->sw_tx_ring.xdp = kzalloc(size, GFP_KERNEL); if (!txq->sw_tx_ring.xdp) goto err; } else { - size = sizeof(*txq->sw_tx_ring.skbs) * TX_RING_SIZE; + size = sizeof(*txq->sw_tx_ring.skbs) * txq->num_tx_buffers; txq->sw_tx_ring.skbs = kzalloc(size, GFP_KERNEL); if (!txq->sw_tx_ring.skbs) goto err; @@ -1319,7 +1319,7 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) QED_CHAIN_USE_TO_CONSUME_PRODUCE, QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, - TX_RING_SIZE, + txq->num_tx_buffers, sizeof(*p_virt), &txq->tx_pbl); if (rc) goto err; -- cgit v1.2.3 From 71851ea5fae7e01fe66f4f820bea2ef6c6534a37 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Sun, 21 May 2017 12:10:54 +0300 Subject: qede: Add missing Status-block free When destroying the datapath channels, qede doesn't notify qed of the released status blocks which were acquired during the initialization. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 766bd373fa99..aea9dcfae62a 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1072,12 +1072,15 @@ static int qede_set_num_queues(struct qede_dev *edev) return rc; } -static void qede_free_mem_sb(struct qede_dev *edev, - struct qed_sb_info *sb_info) +static void qede_free_mem_sb(struct qede_dev *edev, struct qed_sb_info *sb_info, + u16 sb_id) { - if (sb_info->sb_virt) + if (sb_info->sb_virt) { + edev->ops->common->sb_release(edev->cdev, sb_info, sb_id); dma_free_coherent(&edev->pdev->dev, sizeof(*sb_info->sb_virt), (void *)sb_info->sb_virt, sb_info->sb_phys); + memset(sb_info, 0, sizeof(*sb_info)); + } } /* This function allocates fast-path status block memory */ @@ -1334,7 +1337,7 @@ err: /* This function frees all memory of a single fp */ static void qede_free_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) { - qede_free_mem_sb(edev, fp->sb_info); + qede_free_mem_sb(edev, fp->sb_info, fp->id); if (fp->type & QEDE_FASTPATH_RX) qede_free_mem_rxq(edev, fp->rxq); -- cgit v1.2.3 From 492a1d9811cbd17c833bd0af18bfaff00cd3ac85 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 21 May 2017 12:10:55 +0300 Subject: qede: Don't use an internal MAC field Driver maintains its primary MAC in a private field which gets updated when ndo_dev_set_mac() gets called. However, there are flows where the primary MAC of the device can change without said NDO being called [bond device in TLB mode configuring slaves' addresses], resulting in a configuration where there's a mismatch between what's apparent to user [the netdevice's value] and what's configured in the HW [the private value]. As we don't have any real motivation of maintaining this private field, simply remove it and start using the netdevice's field instead. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede.h | 1 - drivers/net/ethernet/qlogic/qede/qede_filter.c | 62 ++++++++++++++++---------- drivers/net/ethernet/qlogic/qede/qede_main.c | 3 -- 3 files changed, 38 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 9b4f08b6f9b9..694c09b8997e 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -197,7 +197,6 @@ struct qede_dev { #define QEDE_TSS_COUNT(edev) ((edev)->num_queues - (edev)->fp_num_rx) struct qed_int_info int_info; - unsigned char primary_mac[ETH_ALEN]; /* Smaller private varaiant of the RTNL lock */ struct mutex qede_lock; diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c index 333876c19d7d..13955a3bd3b3 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_filter.c +++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c @@ -495,12 +495,16 @@ void qede_force_mac(void *dev, u8 *mac, bool forced) { struct qede_dev *edev = dev; + __qede_lock(edev); + /* MAC hints take effect only if we haven't set one already */ - if (is_valid_ether_addr(edev->ndev->dev_addr) && !forced) + if (is_valid_ether_addr(edev->ndev->dev_addr) && !forced) { + __qede_unlock(edev); return; + } ether_addr_copy(edev->ndev->dev_addr, mac); - ether_addr_copy(edev->primary_mac, mac); + __qede_unlock(edev); } void qede_fill_rss_params(struct qede_dev *edev, @@ -1061,41 +1065,51 @@ int qede_set_mac_addr(struct net_device *ndev, void *p) { struct qede_dev *edev = netdev_priv(ndev); struct sockaddr *addr = p; - int rc; - - ASSERT_RTNL(); /* @@@TBD To be removed */ + int rc = 0; - DP_INFO(edev, "Set_mac_addr called\n"); + /* Make sure the state doesn't transition while changing the MAC. + * Also, all flows accessing the dev_addr field are doing that under + * this lock. + */ + __qede_lock(edev); if (!is_valid_ether_addr(addr->sa_data)) { DP_NOTICE(edev, "The MAC address is not valid\n"); - return -EFAULT; + rc = -EFAULT; + goto out; } if (!edev->ops->check_mac(edev->cdev, addr->sa_data)) { - DP_NOTICE(edev, "qed prevents setting MAC\n"); - return -EINVAL; + DP_NOTICE(edev, "qed prevents setting MAC %pM\n", + addr->sa_data); + rc = -EINVAL; + goto out; + } + + if (edev->state == QEDE_STATE_OPEN) { + /* Remove the previous primary mac */ + rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_DEL, + ndev->dev_addr); + if (rc) + goto out; } ether_addr_copy(ndev->dev_addr, addr->sa_data); + DP_INFO(edev, "Setting device MAC to %pM\n", addr->sa_data); - if (!netif_running(ndev)) { - DP_NOTICE(edev, "The device is currently down\n"); - return 0; + if (edev->state != QEDE_STATE_OPEN) { + DP_VERBOSE(edev, NETIF_MSG_IFDOWN, + "The device is currently down\n"); + goto out; } - /* Remove the previous primary mac */ - rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_DEL, - edev->primary_mac); - if (rc) - return rc; - - edev->ops->common->update_mac(edev->cdev, addr->sa_data); + edev->ops->common->update_mac(edev->cdev, ndev->dev_addr); - /* Add MAC filter according to the new unicast HW MAC address */ - ether_addr_copy(edev->primary_mac, ndev->dev_addr); - return qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_ADD, - edev->primary_mac); + rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_ADD, + ndev->dev_addr); +out: + __qede_unlock(edev); + return rc; } static int @@ -1200,7 +1214,7 @@ void qede_config_rx_mode(struct net_device *ndev) * (configrue / leave the primary mac) */ rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_REPLACE, - edev->primary_mac); + edev->ndev->dev_addr); if (rc) goto out; diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index aea9dcfae62a..a66bdfe40e5b 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1997,9 +1997,6 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, goto err4; DP_INFO(edev, "Start VPORT, RXQ and TXQ succeeded\n"); - /* Add primary mac and set Rx filters */ - ether_addr_copy(edev->primary_mac, edev->ndev->dev_addr); - /* Program un-configured VLANs */ qede_configure_vlan_filters(edev); -- cgit v1.2.3 From 3587cb87cc44ce16581dd7908d74ea91984f93b6 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Sun, 21 May 2017 12:10:56 +0300 Subject: qed: Revise alloc/setup/free flow Re-organize the logic that allocates and frees memory of various sub-components of the hw-function - a. No need to pass pointers to said structure as parameters; The internal logic knows exactly where to find/set the data. b. Nullify pointers after cleanup to prevent possible errors to re-entrant code. Signed-off-by: Tomer Tayar Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 1 + drivers/net/ethernet/qlogic/qed/qed_dev.c | 79 +++++++++++--------------- drivers/net/ethernet/qlogic/qed/qed_fcoe.c | 23 ++++---- drivers/net/ethernet/qlogic/qed/qed_fcoe.h | 22 +++---- drivers/net/ethernet/qlogic/qed/qed_init_ops.c | 4 ++ drivers/net/ethernet/qlogic/qed/qed_int.c | 3 + drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 22 ++++--- drivers/net/ethernet/qlogic/qed/qed_iscsi.h | 23 ++++---- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 21 ++++--- drivers/net/ethernet/qlogic/qed/qed_ll2.h | 13 ++--- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 1 + drivers/net/ethernet/qlogic/qed/qed_ooo.c | 30 ++++++---- drivers/net/ethernet/qlogic/qed/qed_ooo.h | 26 ++++----- drivers/net/ethernet/qlogic/qed/qed_sp.h | 32 ++++------- drivers/net/ethernet/qlogic/qed/qed_spq.c | 54 ++++++++++-------- 15 files changed, 177 insertions(+), 177 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index b7ca0e2181c4..b83fe1d9e988 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -923,6 +923,7 @@ int qed_dcbx_info_alloc(struct qed_hwfn *p_hwfn) void qed_dcbx_info_free(struct qed_hwfn *p_hwfn) { kfree(p_hwfn->p_dcbx_info); + p_hwfn->p_dcbx_info = NULL; } static void qed_dcbx_update_protocol_data(struct protocol_dcb_data *p_data, diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 463927f17032..3fc3b2e03ef0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -161,6 +161,7 @@ void qed_resc_free(struct qed_dev *cdev) cdev->fw_data = NULL; kfree(cdev->reset_stats); + cdev->reset_stats = NULL; for_each_hwfn(cdev, i) { struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; @@ -168,18 +169,18 @@ void qed_resc_free(struct qed_dev *cdev) qed_cxt_mngr_free(p_hwfn); qed_qm_info_free(p_hwfn); qed_spq_free(p_hwfn); - qed_eq_free(p_hwfn, p_hwfn->p_eq); - qed_consq_free(p_hwfn, p_hwfn->p_consq); + qed_eq_free(p_hwfn); + qed_consq_free(p_hwfn); qed_int_free(p_hwfn); #ifdef CONFIG_QED_LL2 - qed_ll2_free(p_hwfn, p_hwfn->p_ll2_info); + qed_ll2_free(p_hwfn); #endif if (p_hwfn->hw_info.personality == QED_PCI_FCOE) - qed_fcoe_free(p_hwfn, p_hwfn->p_fcoe_info); + qed_fcoe_free(p_hwfn); if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { - qed_iscsi_free(p_hwfn, p_hwfn->p_iscsi_info); - qed_ooo_free(p_hwfn, p_hwfn->p_ooo_info); + qed_iscsi_free(p_hwfn); + qed_ooo_free(p_hwfn); } qed_iov_free(p_hwfn); qed_dmae_info_free(p_hwfn); @@ -843,15 +844,7 @@ alloc_err: int qed_resc_alloc(struct qed_dev *cdev) { - struct qed_iscsi_info *p_iscsi_info; - struct qed_fcoe_info *p_fcoe_info; - struct qed_ooo_info *p_ooo_info; -#ifdef CONFIG_QED_LL2 - struct qed_ll2_info *p_ll2_info; -#endif u32 rdma_tasks, excess_tasks; - struct qed_consq *p_consq; - struct qed_eq *p_eq; u32 line_count; int i, rc = 0; @@ -956,45 +949,38 @@ int qed_resc_alloc(struct qed_dev *cdev) DP_ERR(p_hwfn, "Cannot allocate 0x%x EQ elements. The maximum of a u16 chain is 0x%x\n", n_eqes, 0xFFFF); - rc = -EINVAL; - goto alloc_err; + goto alloc_no_mem; } - p_eq = qed_eq_alloc(p_hwfn, (u16) n_eqes); - if (!p_eq) - goto alloc_no_mem; - p_hwfn->p_eq = p_eq; + rc = qed_eq_alloc(p_hwfn, (u16) n_eqes); + if (rc) + goto alloc_err; - p_consq = qed_consq_alloc(p_hwfn); - if (!p_consq) - goto alloc_no_mem; - p_hwfn->p_consq = p_consq; + rc = qed_consq_alloc(p_hwfn); + if (rc) + goto alloc_err; #ifdef CONFIG_QED_LL2 if (p_hwfn->using_ll2) { - p_ll2_info = qed_ll2_alloc(p_hwfn); - if (!p_ll2_info) - goto alloc_no_mem; - p_hwfn->p_ll2_info = p_ll2_info; + rc = qed_ll2_alloc(p_hwfn); + if (rc) + goto alloc_err; } #endif if (p_hwfn->hw_info.personality == QED_PCI_FCOE) { - p_fcoe_info = qed_fcoe_alloc(p_hwfn); - if (!p_fcoe_info) - goto alloc_no_mem; - p_hwfn->p_fcoe_info = p_fcoe_info; + rc = qed_fcoe_alloc(p_hwfn); + if (rc) + goto alloc_err; } if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { - p_iscsi_info = qed_iscsi_alloc(p_hwfn); - if (!p_iscsi_info) - goto alloc_no_mem; - p_hwfn->p_iscsi_info = p_iscsi_info; - p_ooo_info = qed_ooo_alloc(p_hwfn); - if (!p_ooo_info) - goto alloc_no_mem; - p_hwfn->p_ooo_info = p_ooo_info; + rc = qed_iscsi_alloc(p_hwfn); + if (rc) + goto alloc_err; + rc = qed_ooo_alloc(p_hwfn); + if (rc) + goto alloc_err; } /* DMA info initialization */ @@ -1033,8 +1019,8 @@ void qed_resc_setup(struct qed_dev *cdev) qed_cxt_mngr_setup(p_hwfn); qed_spq_setup(p_hwfn); - qed_eq_setup(p_hwfn, p_hwfn->p_eq); - qed_consq_setup(p_hwfn, p_hwfn->p_consq); + qed_eq_setup(p_hwfn); + qed_consq_setup(p_hwfn); /* Read shadow of current MFW mailbox */ qed_mcp_read_mb(p_hwfn, p_hwfn->p_main_ptt); @@ -1047,14 +1033,14 @@ void qed_resc_setup(struct qed_dev *cdev) qed_iov_setup(p_hwfn, p_hwfn->p_main_ptt); #ifdef CONFIG_QED_LL2 if (p_hwfn->using_ll2) - qed_ll2_setup(p_hwfn, p_hwfn->p_ll2_info); + qed_ll2_setup(p_hwfn); #endif if (p_hwfn->hw_info.personality == QED_PCI_FCOE) - qed_fcoe_setup(p_hwfn, p_hwfn->p_fcoe_info); + qed_fcoe_setup(p_hwfn); if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { - qed_iscsi_setup(p_hwfn, p_hwfn->p_iscsi_info); - qed_ooo_setup(p_hwfn, p_hwfn->p_ooo_info); + qed_iscsi_setup(p_hwfn); + qed_ooo_setup(p_hwfn); } } } @@ -1968,6 +1954,7 @@ static void qed_hw_hwfn_free(struct qed_hwfn *p_hwfn) { qed_ptt_pool_free(p_hwfn); kfree(p_hwfn->hw_info.p_igu_info); + p_hwfn->hw_info.p_igu_info = NULL; } /* Setup bar access */ diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c index 690dd2b903d4..cb342f16c137 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c @@ -538,7 +538,7 @@ static void __iomem *qed_fcoe_get_secondary_bdq_prod(struct qed_hwfn *p_hwfn, } } -struct qed_fcoe_info *qed_fcoe_alloc(struct qed_hwfn *p_hwfn) +int qed_fcoe_alloc(struct qed_hwfn *p_hwfn) { struct qed_fcoe_info *p_fcoe_info; @@ -546,19 +546,21 @@ struct qed_fcoe_info *qed_fcoe_alloc(struct qed_hwfn *p_hwfn) p_fcoe_info = kzalloc(sizeof(*p_fcoe_info), GFP_KERNEL); if (!p_fcoe_info) { DP_NOTICE(p_hwfn, "Failed to allocate qed_fcoe_info'\n"); - return NULL; + return -ENOMEM; } INIT_LIST_HEAD(&p_fcoe_info->free_list); - return p_fcoe_info; + + p_hwfn->p_fcoe_info = p_fcoe_info; + return 0; } -void qed_fcoe_setup(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) +void qed_fcoe_setup(struct qed_hwfn *p_hwfn) { struct fcoe_task_context *p_task_ctx = NULL; int rc; u32 i; - spin_lock_init(&p_fcoe_info->lock); + spin_lock_init(&p_hwfn->p_fcoe_info->lock); for (i = 0; i < p_hwfn->pf_params.fcoe_pf_params.num_tasks; i++) { rc = qed_cxt_get_task_ctx(p_hwfn, i, QED_CTX_WORKING_MEM, @@ -576,15 +578,15 @@ void qed_fcoe_setup(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) } } -void qed_fcoe_free(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) +void qed_fcoe_free(struct qed_hwfn *p_hwfn) { struct qed_fcoe_conn *p_conn = NULL; - if (!p_fcoe_info) + if (!p_hwfn->p_fcoe_info) return; - while (!list_empty(&p_fcoe_info->free_list)) { - p_conn = list_first_entry(&p_fcoe_info->free_list, + while (!list_empty(&p_hwfn->p_fcoe_info->free_list)) { + p_conn = list_first_entry(&p_hwfn->p_fcoe_info->free_list, struct qed_fcoe_conn, list_entry); if (!p_conn) break; @@ -592,7 +594,8 @@ void qed_fcoe_free(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) qed_fcoe_free_connection(p_hwfn, p_conn); } - kfree(p_fcoe_info); + kfree(p_hwfn->p_fcoe_info); + p_hwfn->p_fcoe_info = NULL; } static int diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.h b/drivers/net/ethernet/qlogic/qed/qed_fcoe.h index 472af34a171d..027a76ac839a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.h +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.h @@ -49,29 +49,21 @@ struct qed_fcoe_info { }; #if IS_ENABLED(CONFIG_QED_FCOE) -struct qed_fcoe_info *qed_fcoe_alloc(struct qed_hwfn *p_hwfn); +int qed_fcoe_alloc(struct qed_hwfn *p_hwfn); -void qed_fcoe_setup(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info); +void qed_fcoe_setup(struct qed_hwfn *p_hwfn); -void qed_fcoe_free(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info); +void qed_fcoe_free(struct qed_hwfn *p_hwfn); void qed_get_protocol_stats_fcoe(struct qed_dev *cdev, struct qed_mcp_fcoe_stats *stats); #else /* CONFIG_QED_FCOE */ -static inline struct qed_fcoe_info * -qed_fcoe_alloc(struct qed_hwfn *p_hwfn) +static inline int qed_fcoe_alloc(struct qed_hwfn *p_hwfn) { - return NULL; + return -EINVAL; } -static inline void qed_fcoe_setup(struct qed_hwfn *p_hwfn, - struct qed_fcoe_info *p_fcoe_info) -{ -} - -static inline void qed_fcoe_free(struct qed_hwfn *p_hwfn, - struct qed_fcoe_info *p_fcoe_info) -{ -} +static inline void qed_fcoe_setup(struct qed_hwfn *p_hwfn) {} +static inline void qed_fcoe_free(struct qed_hwfn *p_hwfn) {} static inline void qed_get_protocol_stats_fcoe(struct qed_dev *cdev, struct qed_mcp_fcoe_stats *stats) diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c index 4a2e7be5bf72..e3f368882f46 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c @@ -158,6 +158,7 @@ int qed_init_alloc(struct qed_hwfn *p_hwfn) GFP_KERNEL); if (!rt_data->init_val) { kfree(rt_data->b_valid); + rt_data->b_valid = NULL; return -ENOMEM; } @@ -167,7 +168,9 @@ int qed_init_alloc(struct qed_hwfn *p_hwfn) void qed_init_free(struct qed_hwfn *p_hwfn) { kfree(p_hwfn->rt_data.init_val); + p_hwfn->rt_data.init_val = NULL; kfree(p_hwfn->rt_data.b_valid); + p_hwfn->rt_data.b_valid = NULL; } static int qed_init_array_dmae(struct qed_hwfn *p_hwfn, @@ -525,6 +528,7 @@ int qed_init_run(struct qed_hwfn *p_hwfn, } kfree(p_hwfn->unzip_buf); + p_hwfn->unzip_buf = NULL; return rc; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 40f057edeafc..661412c275f7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -2328,6 +2328,7 @@ static void qed_int_sb_attn_free(struct qed_hwfn *p_hwfn) SB_ATTN_ALIGNED_SIZE(p_hwfn), p_sb->sb_attn, p_sb->sb_phys); kfree(p_sb); + p_hwfn->p_sb_attn = NULL; } static void qed_int_sb_attn_setup(struct qed_hwfn *p_hwfn, @@ -2679,6 +2680,7 @@ static void qed_int_sp_sb_free(struct qed_hwfn *p_hwfn) p_sb->sb_info.sb_virt, p_sb->sb_info.sb_phys); kfree(p_sb); + p_hwfn->p_sp_sb = NULL; } static int qed_int_sp_sb_alloc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) @@ -3157,6 +3159,7 @@ static int qed_int_sp_dpc_alloc(struct qed_hwfn *p_hwfn) static void qed_int_sp_dpc_free(struct qed_hwfn *p_hwfn) { kfree(p_hwfn->sp_dpc); + p_hwfn->sp_dpc = NULL; } int qed_int_alloc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index fba55662ea8b..6ab563e1999e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -818,29 +818,32 @@ void qed_iscsi_free_connection(struct qed_hwfn *p_hwfn, kfree(p_conn); } -struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn) +int qed_iscsi_alloc(struct qed_hwfn *p_hwfn) { struct qed_iscsi_info *p_iscsi_info; p_iscsi_info = kzalloc(sizeof(*p_iscsi_info), GFP_KERNEL); if (!p_iscsi_info) - return NULL; + return -ENOMEM; INIT_LIST_HEAD(&p_iscsi_info->free_list); - return p_iscsi_info; + + p_hwfn->p_iscsi_info = p_iscsi_info; + return 0; } -void qed_iscsi_setup(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info) +void qed_iscsi_setup(struct qed_hwfn *p_hwfn) { - spin_lock_init(&p_iscsi_info->lock); + spin_lock_init(&p_hwfn->p_iscsi_info->lock); } -void qed_iscsi_free(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info) +void qed_iscsi_free(struct qed_hwfn *p_hwfn) { struct qed_iscsi_conn *p_conn = NULL; + if (!p_hwfn->p_iscsi_info) + return; + while (!list_empty(&p_hwfn->p_iscsi_info->free_list)) { p_conn = list_first_entry(&p_hwfn->p_iscsi_info->free_list, struct qed_iscsi_conn, list_entry); @@ -850,7 +853,8 @@ void qed_iscsi_free(struct qed_hwfn *p_hwfn, } } - kfree(p_iscsi_info); + kfree(p_hwfn->p_iscsi_info); + p_hwfn->p_iscsi_info = NULL; } static void _qed_iscsi_get_tstats(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h index ae98f772cbc0..225c75b02a06 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h @@ -57,13 +57,11 @@ extern const struct qed_ll2_ops qed_ll2_ops_pass; #endif #if IS_ENABLED(CONFIG_QED_ISCSI) -struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn); +int qed_iscsi_alloc(struct qed_hwfn *p_hwfn); -void qed_iscsi_setup(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info); +void qed_iscsi_setup(struct qed_hwfn *p_hwfn); -void qed_iscsi_free(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info); +void qed_iscsi_free(struct qed_hwfn *p_hwfn); /** * @brief - Fills provided statistics struct with statistics. @@ -74,12 +72,15 @@ void qed_iscsi_free(struct qed_hwfn *p_hwfn, void qed_get_protocol_stats_iscsi(struct qed_dev *cdev, struct qed_mcp_iscsi_stats *stats); #else /* IS_ENABLED(CONFIG_QED_ISCSI) */ -static inline struct qed_iscsi_info *qed_iscsi_alloc( - struct qed_hwfn *p_hwfn) { return NULL; } -static inline void qed_iscsi_setup(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info) {} -static inline void qed_iscsi_free(struct qed_hwfn *p_hwfn, - struct qed_iscsi_info *p_iscsi_info) {} +static inline int qed_iscsi_alloc(struct qed_hwfn *p_hwfn) +{ + return -EINVAL; +} + +static inline void qed_iscsi_setup(struct qed_hwfn *p_hwfn) {} + +static inline void qed_iscsi_free(struct qed_hwfn *p_hwfn) {} + static inline void qed_get_protocol_stats_iscsi(struct qed_dev *cdev, struct qed_mcp_iscsi_stats *stats) {} diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index b04dfc41fc9c..f67ed6d39dfd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -1920,7 +1920,7 @@ void qed_ll2_release_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) mutex_unlock(&p_ll2_conn->mutex); } -struct qed_ll2_info *qed_ll2_alloc(struct qed_hwfn *p_hwfn) +int qed_ll2_alloc(struct qed_hwfn *p_hwfn) { struct qed_ll2_info *p_ll2_connections; u8 i; @@ -1930,28 +1930,31 @@ struct qed_ll2_info *qed_ll2_alloc(struct qed_hwfn *p_hwfn) sizeof(struct qed_ll2_info), GFP_KERNEL); if (!p_ll2_connections) { DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_ll2'\n"); - return NULL; + return -ENOMEM; } for (i = 0; i < QED_MAX_NUM_OF_LL2_CONNECTIONS; i++) p_ll2_connections[i].my_id = i; - return p_ll2_connections; + p_hwfn->p_ll2_info = p_ll2_connections; + return 0; } -void qed_ll2_setup(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_connections) +void qed_ll2_setup(struct qed_hwfn *p_hwfn) { int i; for (i = 0; i < QED_MAX_NUM_OF_LL2_CONNECTIONS; i++) - mutex_init(&p_ll2_connections[i].mutex); + mutex_init(&p_hwfn->p_ll2_info[i].mutex); } -void qed_ll2_free(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_connections) +void qed_ll2_free(struct qed_hwfn *p_hwfn) { - kfree(p_ll2_connections); + if (!p_hwfn->p_ll2_info) + return; + + kfree(p_hwfn->p_ll2_info); + p_hwfn->p_ll2_info = NULL; } static void _qed_ll2_get_tstats(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h index 31a409033c41..2c07d0ed971a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h @@ -306,27 +306,24 @@ int qed_ll2_get_stats(struct qed_hwfn *p_hwfn, * * @param p_hwfn * - * @return pointer to alocated qed_ll2_info or NULL + * @return int */ -struct qed_ll2_info *qed_ll2_alloc(struct qed_hwfn *p_hwfn); +int qed_ll2_alloc(struct qed_hwfn *p_hwfn); /** * @brief qed_ll2_setup - Inits LL2 connections set * * @param p_hwfn - * @param p_ll2_connections * */ -void qed_ll2_setup(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_connections); +void qed_ll2_setup(struct qed_hwfn *p_hwfn); /** * @brief qed_ll2_free - Releases LL2 connections set * * @param p_hwfn - * @param p_ll2_connections * */ -void qed_ll2_free(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_connections); +void qed_ll2_free(struct qed_hwfn *p_hwfn); + #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 7266b36a2655..b32e8190f3fb 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -177,6 +177,7 @@ int qed_mcp_free(struct qed_hwfn *p_hwfn) } kfree(p_hwfn->mcp_info); + p_hwfn->mcp_info = NULL; return 0; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.c b/drivers/net/ethernet/qlogic/qed/qed_ooo.c index db96670192c7..000636530111 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ooo.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ooo.c @@ -99,7 +99,7 @@ void qed_ooo_save_history_entry(struct qed_hwfn *p_hwfn, p_history->head_idx++; } -struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn) +int qed_ooo_alloc(struct qed_hwfn *p_hwfn) { u16 max_num_archipelagos = 0, cid_base; struct qed_ooo_info *p_ooo_info; @@ -109,7 +109,7 @@ struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn) if (p_hwfn->hw_info.personality != QED_PCI_ISCSI) { DP_NOTICE(p_hwfn, "Failed to allocate qed_ooo_info: unknown personality\n"); - return NULL; + return -EINVAL; } max_num_archipelagos = p_hwfn->pf_params.iscsi_pf_params.num_cons; @@ -119,12 +119,12 @@ struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn) if (!max_num_archipelagos) { DP_NOTICE(p_hwfn, "Failed to allocate qed_ooo_info: unknown amount of connections\n"); - return NULL; + return -EINVAL; } p_ooo_info = kzalloc(sizeof(*p_ooo_info), GFP_KERNEL); if (!p_ooo_info) - return NULL; + return -ENOMEM; p_ooo_info->cid_base = cid_base; p_ooo_info->max_num_archipelagos = max_num_archipelagos; @@ -164,7 +164,8 @@ struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn) p_ooo_info->ooo_history.num_of_cqes = QED_MAX_NUM_OOO_HISTORY_ENTRIES; - return p_ooo_info; + p_hwfn->p_ooo_info = p_ooo_info; + return 0; no_history_mem: kfree(p_ooo_info->p_archipelagos_mem); @@ -172,7 +173,7 @@ no_archipelagos_mem: kfree(p_ooo_info->p_isles_mem); no_isles_mem: kfree(p_ooo_info); - return NULL; + return -ENOMEM; } void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn, @@ -249,19 +250,23 @@ void qed_ooo_release_all_isles(struct qed_hwfn *p_hwfn, &p_ooo_info->free_buffers_list); } -void qed_ooo_setup(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info) +void qed_ooo_setup(struct qed_hwfn *p_hwfn) { - qed_ooo_release_all_isles(p_hwfn, p_ooo_info); - memset(p_ooo_info->ooo_history.p_cqes, 0, - p_ooo_info->ooo_history.num_of_cqes * + qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); + memset(p_hwfn->p_ooo_info->ooo_history.p_cqes, 0, + p_hwfn->p_ooo_info->ooo_history.num_of_cqes * sizeof(struct ooo_opaque)); - p_ooo_info->ooo_history.head_idx = 0; + p_hwfn->p_ooo_info->ooo_history.head_idx = 0; } -void qed_ooo_free(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info) +void qed_ooo_free(struct qed_hwfn *p_hwfn) { + struct qed_ooo_info *p_ooo_info = p_hwfn->p_ooo_info; struct qed_ooo_buffer *p_buffer; + if (!p_ooo_info) + return; + qed_ooo_release_all_isles(p_hwfn, p_ooo_info); while (!list_empty(&p_ooo_info->free_buffers_list)) { p_buffer = list_first_entry(&p_ooo_info->free_buffers_list, @@ -282,6 +287,7 @@ void qed_ooo_free(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info) kfree(p_ooo_info->p_archipelagos_mem); kfree(p_ooo_info->ooo_history.p_cqes); kfree(p_ooo_info); + p_hwfn->p_ooo_info = NULL; } void qed_ooo_put_free_buffer(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.h b/drivers/net/ethernet/qlogic/qed/qed_ooo.h index 791ad0f8b759..e8ed40b848f5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ooo.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ooo.h @@ -88,7 +88,11 @@ void qed_ooo_save_history_entry(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, struct ooo_opaque *p_cqe); -struct qed_ooo_info *qed_ooo_alloc(struct qed_hwfn *p_hwfn); +int qed_ooo_alloc(struct qed_hwfn *p_hwfn); + +void qed_ooo_setup(struct qed_hwfn *p_hwfn); + +void qed_ooo_free(struct qed_hwfn *p_hwfn); void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, @@ -97,10 +101,6 @@ void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn, void qed_ooo_release_all_isles(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info); -void qed_ooo_setup(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info); - -void qed_ooo_free(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info); - void qed_ooo_put_free_buffer(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, struct qed_ooo_buffer *p_buffer); @@ -140,8 +140,14 @@ static inline void qed_ooo_save_history_entry(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, struct ooo_opaque *p_cqe) {} -static inline struct qed_ooo_info *qed_ooo_alloc( - struct qed_hwfn *p_hwfn) { return NULL; } +static inline int qed_ooo_alloc(struct qed_hwfn *p_hwfn) +{ + return -EINVAL; +} + +static inline void qed_ooo_setup(struct qed_hwfn *p_hwfn) {} + +static inline void qed_ooo_free(struct qed_hwfn *p_hwfn) {} static inline void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn, @@ -152,12 +158,6 @@ static inline void qed_ooo_release_all_isles(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info) {} -static inline void qed_ooo_setup(struct qed_hwfn *p_hwfn, - struct qed_ooo_info *p_ooo_info) {} - -static inline void qed_ooo_free(struct qed_hwfn *p_hwfn, - struct qed_ooo_info *p_ooo_info) {} - static inline void qed_ooo_put_free_buffer(struct qed_hwfn *p_hwfn, struct qed_ooo_info *p_ooo_info, struct qed_ooo_buffer *p_buffer) {} diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index 3357bbefa445..c0b56b98d2ea 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -270,28 +270,23 @@ void qed_spq_return_entry(struct qed_hwfn *p_hwfn, * @param p_hwfn * @param num_elem number of elements in the eq * - * @return struct qed_eq* - a newly allocated structure; NULL upon error. + * @return int */ -struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn, - u16 num_elem); +int qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem); /** - * @brief qed_eq_setup - Reset the SPQ to its start state. + * @brief qed_eq_setup - Reset the EQ to its start state. * * @param p_hwfn - * @param p_eq */ -void qed_eq_setup(struct qed_hwfn *p_hwfn, - struct qed_eq *p_eq); +void qed_eq_setup(struct qed_hwfn *p_hwfn); /** - * @brief qed_eq_deallocate - deallocates the given EQ struct. + * @brief qed_eq_free - deallocates the given EQ struct. * * @param p_hwfn - * @param p_eq */ -void qed_eq_free(struct qed_hwfn *p_hwfn, - struct qed_eq *p_eq); +void qed_eq_free(struct qed_hwfn *p_hwfn); /** * @brief qed_eq_prod_update - update the FW with default EQ producer @@ -342,28 +337,23 @@ u32 qed_spq_get_cid(struct qed_hwfn *p_hwfn); * * @param p_hwfn * - * @return struct qed_eq* - a newly allocated structure; NULL upon error. + * @return int */ -struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn); +int qed_consq_alloc(struct qed_hwfn *p_hwfn); /** - * @brief qed_consq_setup - Reset the ConsQ to its start - * state. + * @brief qed_consq_setup - Reset the ConsQ to its start state. * * @param p_hwfn - * @param p_eq */ -void qed_consq_setup(struct qed_hwfn *p_hwfn, - struct qed_consq *p_consq); +void qed_consq_setup(struct qed_hwfn *p_hwfn); /** * @brief qed_consq_free - deallocates the given ConsQ struct. * * @param p_hwfn - * @param p_eq */ -void qed_consq_free(struct qed_hwfn *p_hwfn, - struct qed_consq *p_consq); +void qed_consq_free(struct qed_hwfn *p_hwfn); /** * @file diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index f6423a139ca0..dede73f41e61 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -403,14 +403,14 @@ int qed_eq_completion(struct qed_hwfn *p_hwfn, void *cookie) return rc; } -struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem) +int qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem) { struct qed_eq *p_eq; /* Allocate EQ struct */ p_eq = kzalloc(sizeof(*p_eq), GFP_KERNEL); if (!p_eq) - return NULL; + return -ENOMEM; /* Allocate and initialize EQ chain*/ if (qed_chain_alloc(p_hwfn->cdev, @@ -426,24 +426,28 @@ struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem) qed_int_register_cb(p_hwfn, qed_eq_completion, p_eq, &p_eq->eq_sb_index, &p_eq->p_fw_cons); - return p_eq; + p_hwfn->p_eq = p_eq; + return 0; eq_allocate_fail: - qed_eq_free(p_hwfn, p_eq); - return NULL; + kfree(p_eq); + return -ENOMEM; } -void qed_eq_setup(struct qed_hwfn *p_hwfn, struct qed_eq *p_eq) +void qed_eq_setup(struct qed_hwfn *p_hwfn) { - qed_chain_reset(&p_eq->chain); + qed_chain_reset(&p_hwfn->p_eq->chain); } -void qed_eq_free(struct qed_hwfn *p_hwfn, struct qed_eq *p_eq) +void qed_eq_free(struct qed_hwfn *p_hwfn) { - if (!p_eq) + if (!p_hwfn->p_eq) return; - qed_chain_free(p_hwfn->cdev, &p_eq->chain); - kfree(p_eq); + + qed_chain_free(p_hwfn->cdev, &p_hwfn->p_eq->chain); + + kfree(p_hwfn->p_eq); + p_hwfn->p_eq = NULL; } /*************************************************************************** @@ -583,8 +587,8 @@ void qed_spq_free(struct qed_hwfn *p_hwfn) } qed_chain_free(p_hwfn->cdev, &p_spq->chain); - ; kfree(p_spq); + p_hwfn->p_spq = NULL; } int qed_spq_get_entry(struct qed_hwfn *p_hwfn, struct qed_spq_entry **pp_ent) @@ -934,14 +938,14 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn, return rc; } -struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn) +int qed_consq_alloc(struct qed_hwfn *p_hwfn) { struct qed_consq *p_consq; /* Allocate ConsQ struct */ p_consq = kzalloc(sizeof(*p_consq), GFP_KERNEL); if (!p_consq) - return NULL; + return -ENOMEM; /* Allocate and initialize EQ chain*/ if (qed_chain_alloc(p_hwfn->cdev, @@ -952,22 +956,26 @@ struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn) 0x80, &p_consq->chain)) goto consq_allocate_fail; - return p_consq; + p_hwfn->p_consq = p_consq; + return 0; consq_allocate_fail: - qed_consq_free(p_hwfn, p_consq); - return NULL; + kfree(p_consq); + return -ENOMEM; } -void qed_consq_setup(struct qed_hwfn *p_hwfn, struct qed_consq *p_consq) +void qed_consq_setup(struct qed_hwfn *p_hwfn) { - qed_chain_reset(&p_consq->chain); + qed_chain_reset(&p_hwfn->p_consq->chain); } -void qed_consq_free(struct qed_hwfn *p_hwfn, struct qed_consq *p_consq) +void qed_consq_free(struct qed_hwfn *p_hwfn) { - if (!p_consq) + if (!p_hwfn->p_consq) return; - qed_chain_free(p_hwfn->cdev, &p_consq->chain); - kfree(p_consq); + + qed_chain_free(p_hwfn->cdev, &p_hwfn->p_consq->chain); + + kfree(p_hwfn->p_consq); + p_hwfn->p_consq = NULL; } -- cgit v1.2.3 From 88fa95278503523df5fbb18b4e98526e61e13218 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 21 May 2017 12:10:57 +0300 Subject: qed: Correct print in iscsi error-flow If too many CQs are requested, qed would print the available number as if it's a resource and not a feature leading to the wrong print. Fixes: 08737a3fa30a ("qed: Inform qedi the number of possible CQs") Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index 6ab563e1999e..43a20a6fd1b6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -185,7 +185,7 @@ qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn, DP_ERR(p_hwfn, "Cannot satisfy CQ amount. Queues requested %d, CQs available %d. Aborting function start\n", p_params->num_queues, - p_hwfn->hw_info.resc_num[QED_ISCSI_CQ]); + p_hwfn->hw_info.feat_num[QED_ISCSI_CQ]); return -EINVAL; } -- cgit v1.2.3 From 2e7022d64e77dae5972f125f9ce95c012dfe7b3a Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 21 May 2017 12:10:58 +0300 Subject: qede: qedr closure after setting state This is benign, but it makes more sense to start the close sequence only after changing the internal state [in case it would once care]. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index a66bdfe40e5b..f0871e179e99 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1899,9 +1899,10 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, if (!is_locked) __qede_lock(edev); - qede_roce_dev_event_close(edev); edev->state = QEDE_STATE_CLOSED; + qede_roce_dev_event_close(edev); + /* Close OS Tx */ netif_tx_disable(edev->ndev); netif_carrier_off(edev->ndev); -- cgit v1.2.3 From b19601bbf1a1a230beb35ea77acbbfb5bbf542fa Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Sun, 21 May 2017 12:10:59 +0300 Subject: qed: Fix setting of Management bitfields The management firmware HSI contains masks which are already shifted to their right place, so QED_MFW_SET_FIELD() is clearing incorrect fields by shifting the mask by the offset. Luckily, today we set the fields in an incrementing order [so we're not erasing any previously set fields], but this still needs fixing. Signed-off-by: Tomer Tayar Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 162cd7ff9a69..fd8cf31cce05 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -92,7 +92,7 @@ enum qed_mcp_protocol_type; #define QED_MFW_SET_FIELD(name, field, value) \ do { \ - (name) &= ~((field ## _MASK) << (field ## _SHIFT)); \ + (name) &= ~(field ## _MASK); \ (name) |= (((value) << (field ## _SHIFT)) & (field ## _MASK));\ } while (0) -- cgit v1.2.3 From 9ac4c546ef109ff633c3d56acdc3c501a6e0f7a1 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Sun, 21 May 2017 12:11:00 +0300 Subject: qede: Support 1G advertisment. Some variants of adapters support the 1G speed capability. Need to allow the configuration of 1G speed if adapter supports it. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 47ec4f3cfe79..6c76a12c4e0d 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -506,6 +506,14 @@ static int qede_set_link_ksettings(struct net_device *dev, params.autoneg = false; params.forced_speed = base->speed; switch (base->speed) { + case SPEED_1000: + if (!(current_link.supported_caps & + QED_LM_1000baseT_Full_BIT)) { + DP_INFO(edev, "1G speed not supported\n"); + return -EINVAL; + } + params.adv_speeds = QED_LM_1000baseT_Full_BIT; + break; case SPEED_10000: if (!(current_link.supported_caps & QED_LM_10000baseKR_Full_BIT)) { -- cgit v1.2.3 From 66aa0678efc29abd2ab02a09b23f9a8bc9f12a6c Mon Sep 17 00:00:00 2001 From: Sivakumar Krishnasamy Date: Fri, 19 May 2017 05:30:38 -0400 Subject: ibmveth: Support to enable LSO/CSO for Trunk VEA. Current largesend and checksum offload feature in ibmveth driver, - Source VM sends the TCP packets with ip_summed field set as CHECKSUM_PARTIAL and TCP pseudo header checksum is placed in checksum field - CHECKSUM_PARTIAL flag in SKB will enable ibmveth driver to mark "no checksum" and "checksum good" bits in transmit buffer descriptor before the packet is delivered to pseries PowerVM Hypervisor - If ibmveth has largesend capability enabled, transmit buffer descriptors are market accordingly before packet is delivered to Hypervisor (along with mss value for packets with length > MSS) - Destination VM's ibmveth driver receives the packet with "checksum good" bit set and so, SKB's ip_summed field is set with CHECKSUM_UNNECESSARY - If "largesend" bit was on, mss value is copied from receive descriptor into SKB's gso_size and other flags are appropriately set for packets > MSS size - The packet is now successfully delivered up the stack in destination VM The offloads described above works fine for TCP communication among VMs in the same pseries server ( VM A <=> PowerVM Hypervisor <=> VM B ) We are now enabling support for OVS in pseries PowerVM environment. One of our requirements is to have ibmveth driver configured in "Trunk" mode, when they are used with OVS. This is because, PowerVM Hypervisor will no more bridge the packets between VMs, instead the packets are delivered to IO Server which hosts OVS to bridge them between VMs or to external networks (flow shown below), VM A <=> PowerVM Hypervisor <=> IO Server(OVS) <=> PowerVM Hypervisor <=> VM B In "IO server" the packet is received by inbound Trunk ibmveth and then delivered to OVS, which is then bridged to outbound Trunk ibmveth (shown below), Inbound Trunk ibmveth <=> OVS <=> Outbound Trunk ibmveth In this model, we hit the following issues which impacted the VM communication performance, - Issue 1: ibmveth doesn't support largesend and checksum offload features when configured as "Trunk". Driver has explicit checks to prevent enabling these offloads. - Issue 2: SYN packet drops seen at destination VM. When the packet originates, it has CHECKSUM_PARTIAL flag set and as it gets delivered to IO server's inbound Trunk ibmveth, on validating "checksum good" bits in ibmveth receive routine, SKB's ip_summed field is set with CHECKSUM_UNNECESSARY flag. This packet is then bridged by OVS (or Linux Bridge) and delivered to outbound Trunk ibmveth. At this point the outbound ibmveth transmit routine will not set "no checksum" and "checksum good" bits in transmit buffer descriptor, as it does so only when the ip_summed field is CHECKSUM_PARTIAL. When this packet gets delivered to destination VM, TCP layer receives the packet with checksum value of 0 and with no checksum related flags in ip_summed field. This leads to packet drops. So, TCP connections never goes through fine. - Issue 3: First packet of a TCP connection will be dropped, if there is no OVS flow cached in datapath. OVS while trying to identify the flow, computes the checksum. The computed checksum will be invalid at the receiving end, as ibmveth transmit routine zeroes out the pseudo checksum value in the packet. This leads to packet drop. - Issue 4: ibmveth driver doesn't have support for SKB's with frag_list. When Physical NIC has GRO enabled and when OVS bridges these packets, OVS vport send code will end up calling dev_queue_xmit, which in turn calls validate_xmit_skb. In validate_xmit_skb routine, the larger packets will get segmented into MSS sized segments, if SKB has a frag_list and if the driver to which they are delivered to doesn't support NETIF_F_FRAGLIST feature. This patch addresses the above four issues, thereby enabling end to end largesend and checksum offload support for better performance. - Fix for Issue 1 : Remove checks which prevent enabling TCP largesend and checksum offloads. - Fix for Issue 2 : When ibmveth receives a packet with "checksum good" bit set and if its configured in Trunk mode, set appropriate SKB fields using skb_partial_csum_set (ip_summed field is set with CHECKSUM_PARTIAL) - Fix for Issue 3: Recompute the pseudo header checksum before sending the SKB up the stack. - Fix for Issue 4: Linearize the SKBs with frag_list. Though we end up allocating buffers and copying data, this fix gives upto 4X throughput increase. Note: All these fixes need to be dropped together as fixing just one of them will lead to other issues immediately (especially for Issues 1,2 & 3). Signed-off-by: Sivakumar Krishnasamy Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmveth.c | 107 ++++++++++++++++++++++++++++++------- drivers/net/ethernet/ibm/ibmveth.h | 1 + 2 files changed, 90 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 72ab7b6bf20b..9a74c4e2e193 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include "ibmveth.h" @@ -808,8 +810,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); - if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) && - !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) && + if (ret == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) { ret4 = h_illan_attributes(adapter->vdev->unit_address, clr_attr, set_attr, &ret_attr); @@ -1040,6 +1041,15 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, dma_addr_t dma_addr; unsigned long mss = 0; + /* veth doesn't handle frag_list, so linearize the skb. + * When GRO is enabled SKB's can have frag_list. + */ + if (adapter->is_active_trunk && + skb_has_frag_list(skb) && __skb_linearize(skb)) { + netdev->stats.tx_dropped++; + goto out; + } + /* * veth handles a maximum of 6 segments including the header, so * we have to linearize the skb if there are more than this. @@ -1064,9 +1074,6 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, desc_flags = IBMVETH_BUF_VALID; - if (skb_is_gso(skb) && adapter->fw_large_send_support) - desc_flags |= IBMVETH_BUF_LRG_SND; - if (skb->ip_summed == CHECKSUM_PARTIAL) { unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; @@ -1076,6 +1083,9 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, /* Need to zero out the checksum */ buf[0] = 0; buf[1] = 0; + + if (skb_is_gso(skb) && adapter->fw_large_send_support) + desc_flags |= IBMVETH_BUF_LRG_SND; } retry_bounce: @@ -1128,7 +1138,7 @@ retry_bounce: descs[i+1].fields.address = dma_addr; } - if (skb_is_gso(skb)) { + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_is_gso(skb)) { if (adapter->fw_large_send_support) { mss = (unsigned long)skb_shinfo(skb)->gso_size; adapter->tx_large_packets++; @@ -1232,6 +1242,71 @@ static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt) } } +static void ibmveth_rx_csum_helper(struct sk_buff *skb, + struct ibmveth_adapter *adapter) +{ + struct iphdr *iph = NULL; + struct ipv6hdr *iph6 = NULL; + __be16 skb_proto = 0; + u16 iphlen = 0; + u16 iph_proto = 0; + u16 tcphdrlen = 0; + + skb_proto = be16_to_cpu(skb->protocol); + + if (skb_proto == ETH_P_IP) { + iph = (struct iphdr *)skb->data; + + /* If the IP checksum is not offloaded and if the packet + * is large send, the checksum must be rebuilt. + */ + if (iph->check == 0xffff) { + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, + iph->ihl); + } + + iphlen = iph->ihl * 4; + iph_proto = iph->protocol; + } else if (skb_proto == ETH_P_IPV6) { + iph6 = (struct ipv6hdr *)skb->data; + iphlen = sizeof(struct ipv6hdr); + iph_proto = iph6->nexthdr; + } + + /* In OVS environment, when a flow is not cached, specifically for a + * new TCP connection, the first packet information is passed up + * the user space for finding a flow. During this process, OVS computes + * checksum on the first packet when CHECKSUM_PARTIAL flag is set. + * + * Given that we zeroed out TCP checksum field in transmit path + * (refer ibmveth_start_xmit routine) as we set "no checksum bit", + * OVS computed checksum will be incorrect w/o TCP pseudo checksum + * in the packet. This leads to OVS dropping the packet and hence + * TCP retransmissions are seen. + * + * So, re-compute TCP pseudo header checksum. + */ + if (iph_proto == IPPROTO_TCP && adapter->is_active_trunk) { + struct tcphdr *tcph = (struct tcphdr *)(skb->data + iphlen); + + tcphdrlen = skb->len - iphlen; + + /* Recompute TCP pseudo header checksum */ + if (skb_proto == ETH_P_IP) + tcph->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, tcphdrlen, iph_proto, 0); + else if (skb_proto == ETH_P_IPV6) + tcph->check = ~csum_ipv6_magic(&iph6->saddr, + &iph6->daddr, tcphdrlen, iph_proto, 0); + + /* Setup SKB fields for checksum offload */ + skb_partial_csum_set(skb, iphlen, + offsetof(struct tcphdr, check)); + skb_reset_network_header(skb); + } +} + static int ibmveth_poll(struct napi_struct *napi, int budget) { struct ibmveth_adapter *adapter = @@ -1239,7 +1314,6 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) struct net_device *netdev = adapter->netdev; int frames_processed = 0; unsigned long lpar_rc; - struct iphdr *iph; u16 mss = 0; restart_poll: @@ -1297,17 +1371,7 @@ restart_poll: if (csum_good) { skb->ip_summed = CHECKSUM_UNNECESSARY; - if (be16_to_cpu(skb->protocol) == ETH_P_IP) { - iph = (struct iphdr *)skb->data; - - /* If the IP checksum is not offloaded and if the packet - * is large send, the checksum must be rebuilt. - */ - if (iph->check == 0xffff) { - iph->check = 0; - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); - } - } + ibmveth_rx_csum_helper(skb, adapter); } if (length > netdev->mtu + ETH_HLEN) { @@ -1626,6 +1690,13 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) netdev->hw_features |= NETIF_F_TSO; } + adapter->is_active_trunk = false; + if (ret == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK)) { + adapter->is_active_trunk = true; + netdev->hw_features |= NETIF_F_FRAGLIST; + netdev->features |= NETIF_F_FRAGLIST; + } + netdev->min_mtu = IBMVETH_MIN_MTU; netdev->max_mtu = ETH_MAX_MTU; diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index ed8780cca982..01c587fc02c7 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -156,6 +156,7 @@ struct ibmveth_adapter { int pool_config; int rx_csum; int large_send; + bool is_active_trunk; void *bounce_buffer; dma_addr_t bounce_buffer_dma; -- cgit v1.2.3 From 2061ec3f1370d5491e801a693618af2b933781fe Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Fri, 19 May 2017 17:50:15 +0530 Subject: cxgb4 : retrieve port information from firmware issue get port information command to firmware to retrieve port information and update if it is different from what was last recorded and also add indication for supported link modes for firmware port types FW_PORT_TYPE_SFP28, FW_PORT_TYPE_KR_SFP28, FW_PORT_TYPE_CR4_QSFP. Based on the original work by Casey Leedom Signed-off-by: Casey Leedom Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 34 ++++++++++++++++++++-- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 7 +++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 30 +++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 1 + 5 files changed, 70 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index e88c1808e46f..1cf3e2f89fc1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1551,6 +1551,7 @@ int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int eqid); int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox); void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl); +int t4_update_port_info(struct port_info *pi); int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl); void t4_db_full(struct adapter *adapter); void t4_db_dropped(struct adapter *adapter); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c index 0ba7866c8259..e9bab72253bb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -500,7 +500,11 @@ static int from_fw_port_mod_type(enum fw_port_type port_type, } else if (port_type == FW_PORT_TYPE_SFP || port_type == FW_PORT_TYPE_QSFP_10G || port_type == FW_PORT_TYPE_QSA || - port_type == FW_PORT_TYPE_QSFP) { + port_type == FW_PORT_TYPE_QSFP || + port_type == FW_PORT_TYPE_CR4_QSFP || + port_type == FW_PORT_TYPE_CR_QSFP || + port_type == FW_PORT_TYPE_CR2_QSFP || + port_type == FW_PORT_TYPE_SFP28) { if (mod_type == FW_PORT_MOD_TYPE_LR || mod_type == FW_PORT_MOD_TYPE_SR || mod_type == FW_PORT_MOD_TYPE_ER || @@ -511,6 +515,9 @@ static int from_fw_port_mod_type(enum fw_port_type port_type, return PORT_DA; else return PORT_OTHER; + } else if (port_type == FW_PORT_TYPE_KR4_100G || + port_type == FW_PORT_TYPE_KR_SFP28) { + return PORT_NONE; } return PORT_OTHER; @@ -618,7 +625,21 @@ static void fw_caps_to_lmm(enum fw_port_type port_type, case FW_PORT_TYPE_CR_QSFP: case FW_PORT_TYPE_SFP28: SET_LMM(FIBRE); - SET_LMM(25000baseCR_Full); + FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); + FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); + FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full); + break; + + case FW_PORT_TYPE_KR_SFP28: + SET_LMM(Backplane); + FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); + FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); + FW_CAPS_TO_LMM(SPEED_25G, 25000baseKR_Full); + break; + + case FW_PORT_TYPE_CR2_QSFP: + SET_LMM(FIBRE); + SET_LMM(50000baseSR2_Full); break; case FW_PORT_TYPE_KR4_100G: @@ -674,13 +695,20 @@ static unsigned int lmm_to_fw_caps(const unsigned long *link_mode_mask) static int get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *link_ksettings) { - const struct port_info *pi = netdev_priv(dev); + struct port_info *pi = netdev_priv(dev); struct ethtool_link_settings *base = &link_ksettings->base; ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising); + /* For the nonce, the Firmware doesn't send up Port State changes + * when the Virtual Interface attached to the Port is down. So + * if it's down, let's grab any changes. + */ + if (!netif_running(dev)) + (void)t4_update_port_info(pi); + base->port = from_fw_port_mod_type(pi->port_type, pi->mod_type); if (pi->mdio_addr >= 0) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 4249ffbc0427..2ae54d54aea8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2245,6 +2245,13 @@ static int cxgb_open(struct net_device *dev) return err; } + /* It's possible that the basic port information could have + * changed since we first read it. + */ + err = t4_update_port_info(pi); + if (err < 0) + return err; + err = link_start(dev); if (!err) netif_tx_start_all_queues(dev); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index aded42b96f6d..b97ce4a15ae0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -7355,10 +7355,40 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) lc->fc = fc; lc->supported = be16_to_cpu(p->u.info.pcap); lc->lp_advertising = be16_to_cpu(p->u.info.lpacap); + t4_os_link_changed(adap, pi->port_id, link_ok); } } +/** + * t4_update_port_info - retrieve and update port information if changed + * @pi: the port_info + * + * We issue a Get Port Information Command to the Firmware and, if + * successful, we check to see if anything is different from what we + * last recorded and update things accordingly. + */ +int t4_update_port_info(struct port_info *pi) +{ + struct fw_port_cmd port_cmd; + int ret; + + memset(&port_cmd, 0, sizeof(port_cmd)); + port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | + FW_CMD_REQUEST_F | FW_CMD_READ_F | + FW_PORT_CMD_PORTID_V(pi->port_id)); + port_cmd.action_to_len16 = cpu_to_be32( + FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) | + FW_LEN16(port_cmd)); + ret = t4_wr_mbox(pi->adapter, pi->adapter->mbox, + &port_cmd, sizeof(port_cmd), &port_cmd); + if (ret) + return ret; + + t4_handle_get_port_info(pi, (__be64 *)&port_cmd); + return 0; +} + /** * t4_handle_fw_rpl - process a FW reply message * @adap: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 251a35e9795c..c65c33c03bcb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -2572,6 +2572,7 @@ enum fw_port_type { FW_PORT_TYPE_CR_QSFP, FW_PORT_TYPE_CR2_QSFP, FW_PORT_TYPE_SFP28, + FW_PORT_TYPE_KR_SFP28, FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_M }; -- cgit v1.2.3 From e3412575488ac2408f737a14296cce34c9d8b4f8 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 19 May 2017 17:52:36 +0200 Subject: net: ethernet: update drivers to handle HWTSTAMP_FILTER_NTP_ALL Include HWTSTAMP_FILTER_NTP_ALL in net_hwtstamp_validate() as a valid filter and update drivers which can timestamp all packets, or which explicitly list unsupported filters instead of using a default case, to handle the filter. CC: Richard Cochran CC: Willem de Bruijn Signed-off-by: Miroslav Lichvar Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 1 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 1 + drivers/net/ethernet/cavium/liquidio/lio_main.c | 1 + drivers/net/ethernet/cavium/liquidio/lio_vf_main.c | 1 + drivers/net/ethernet/cavium/octeon/octeon_mgmt.c | 1 + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + drivers/net/ethernet/intel/i40e/i40e_ptp.c | 1 + drivers/net/ethernet/intel/igb/igb_ptp.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 1 + drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 1 + drivers/net/ethernet/mellanox/mlx5/core/en_clock.c | 1 + drivers/net/ethernet/neterion/vxge/vxge-main.c | 1 + drivers/net/ethernet/qlogic/qede/qede_ptp.c | 1 + drivers/net/ethernet/sfc/ef10.c | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1 + drivers/net/ethernet/ti/cpsw.c | 1 + drivers/net/ethernet/tile/tilegx.c | 1 + 17 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index c772420fa41c..89b21d7c537b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1268,6 +1268,7 @@ static int xgbe_set_hwtstamp_settings(struct xgbe_prv_data *pdata, case HWTSTAMP_FILTER_NONE: break; + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENALL, 1); XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 7414ffd70c90..14c236e5bdb1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -15351,6 +15351,7 @@ int bnx2x_configure_ptp_filters(struct bnx2x *bp) break; case HWTSTAMP_FILTER_ALL: case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_NTP_ALL: bp->rx_filter = HWTSTAMP_FILTER_NONE; break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 649f2aaf0afb..ba012427edd6 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -3024,6 +3024,7 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: conf.rx_filter = HWTSTAMP_FILTER_ALL; break; default: diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index d51c8d8d9a35..31d737c22648 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -2085,6 +2085,7 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: conf.rx_filter = HWTSTAMP_FILTER_ALL; break; default: diff --git a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c index a2138686c605..2887bcaf6af5 100644 --- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c @@ -755,6 +755,7 @@ static int octeon_mgmt_ioctl_hwtstamp(struct net_device *netdev, case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: p->has_rx_tstamp = have_hw_timestamps; config.rx_filter = HWTSTAMP_FILTER_ALL; if (p->has_rx_tstamp) { diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b3679728caac..0ff9295ed449 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3680,6 +3680,7 @@ static int e1000e_config_hwtstamp(struct e1000_adapter *adapter, * Delay Request messages but not both so fall-through to * time stamp all packets. */ + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: is_l2 = true; is_l4 = true; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 18c1cc08da97..0efff18ee336 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -562,6 +562,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; } break; + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: default: return -ERANGE; diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 7a3fd4d74592..d333d6d80194 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -941,6 +941,7 @@ static int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter, is_l4 = true; break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: /* 82576 cannot timestamp all packets, which it needs to do to * support both V1 Sync and Delay_Req messages diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index ef0635e0918c..d44c728fdc0b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -883,6 +883,7 @@ static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: /* The X550 controller is capable of timestamping all packets, * which allows it to accept any filter. diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 94fab20ef146..82436742ad75 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2375,6 +2375,7 @@ static int mlx4_en_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: config.rx_filter = HWTSTAMP_FILTER_ALL; break; default: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c index e706a87fc8b2..e29494464cae 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c @@ -128,6 +128,7 @@ int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: /* Disable CQE compression */ netdev_warn(dev, "Disabling cqe compression"); err = mlx5e_modify_rx_cqe_compression_locked(priv, false); diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index 6a4310af5d97..50ea69d88480 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -3218,6 +3218,7 @@ static int vxge_hwtstamp_set(struct vxgedev *vdev, void __user *data) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: if (vdev->devh->config.hwts_en != VXGE_HW_HWTS_ENABLE) return -EFAULT; diff --git a/drivers/net/ethernet/qlogic/qede/qede_ptp.c b/drivers/net/ethernet/qlogic/qede/qede_ptp.c index 24f06e2ef43e..9b2280badaf7 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ptp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ptp.c @@ -244,6 +244,7 @@ static int qede_ptp_cfg_filters(struct qede_dev *edev) break; case HWTSTAMP_FILTER_ALL: case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_NTP_ALL: ptp->rx_filter = HWTSTAMP_FILTER_NONE; rx_filter = QED_PTP_FILTER_ALL; break; diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 78efb2822b86..ad9c4ded2b90 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -6068,6 +6068,7 @@ static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx, case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: init->rx_filter = HWTSTAMP_FILTER_ALL; rc = efx_ptp_change_mode(efx, true, 0); if (!rc) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index a74c481401c4..cce862b81f3e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -644,6 +644,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ptp_over_ethernet = PTP_TCR_TSIPENA; break; + case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: /* time stamp any incoming packet */ config.rx_filter = HWTSTAMP_FILTER_ALL; diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index f4d7aec50479..37fc16521143 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1734,6 +1734,7 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: return -ERANGE; case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 7c634bc75615..aec95382ea5c 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -512,6 +512,7 @@ static int tile_hwtstamp_set(struct net_device *dev, struct ifreq *rq) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_NTP_ALL: config.rx_filter = HWTSTAMP_FILTER_ALL; break; default: -- cgit v1.2.3 From 74abc9b18f446d1a9e0602a71a22e5ffe8a2cd23 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 19 May 2017 17:52:41 +0200 Subject: net: ethernet: update drivers to make both SW and HW TX timestamps Some drivers were calling the skb_tx_timestamp() function only when a hardware timestamp was not requested. Now that applications can use the SOF_TIMESTAMPING_OPT_TX_SWHW option to request both software and hardware timestamps, the drivers need to be modified to unconditionally call skb_tx_timestamp(). CC: Richard Cochran CC: Willem de Bruijn Signed-off-by: Miroslav Lichvar Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 3 +-- drivers/net/ethernet/intel/e1000e/netdev.c | 4 ++-- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 3 +-- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ++---- 4 files changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 89b21d7c537b..5a2ad9c5faab 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1391,8 +1391,7 @@ static void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata, spin_unlock_irqrestore(&pdata->tstamp_lock, flags); } - if (!XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP)) - skb_tx_timestamp(skb); + skb_tx_timestamp(skb); } static void xgbe_prep_vlan(struct sk_buff *skb, struct xgbe_packet_data *packet) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 0ff9295ed449..6ed3bc419b96 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5868,10 +5868,10 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, adapter->tx_hwtstamp_skb = skb_get(skb); adapter->tx_hwtstamp_start = jiffies; schedule_work(&adapter->tx_hwtstamp_work); - } else { - skb_tx_timestamp(skb); } + skb_tx_timestamp(skb); + netdev_sent_queue(netdev, skb->len); e1000_tx_queue(tx_ring, tx_flags, count); /* Make sure there is space in the ring for the next send. */ diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 1e594351a60f..89831adb8eb7 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -1418,8 +1418,7 @@ static netdev_tx_t sxgbe_xmit(struct sk_buff *skb, struct net_device *dev) priv->hw->desc->tx_enable_tstamp(first_desc); } - if (!tqueue->hwts_tx_en) - skb_tx_timestamp(skb); + skb_tx_timestamp(skb); priv->hw->dma->enable_dma_transmission(priv->ioaddr, txq_index); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index cce862b81f3e..27c12e732a8a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2880,8 +2880,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) priv->xstats.tx_set_ic_bit++; } - if (!priv->hwts_tx_en) - skb_tx_timestamp(skb); + skb_tx_timestamp(skb); if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en)) { @@ -3084,8 +3083,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) priv->xstats.tx_set_ic_bit++; } - if (!priv->hwts_tx_en) - skb_tx_timestamp(skb); + skb_tx_timestamp(skb); /* Ready to fill the first descriptor and set the OWN bit w/o any * problems because all the descriptors are actually ready to be -- cgit v1.2.3 From 8ec4a1e950edd29075c5316dc68e83faf69904d6 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 22 May 2017 07:32:46 +0200 Subject: ieee802154: ca8210: Delete an error message for a failed memory allocation in ca8210_probe() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/ca8210.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index 25fd3b04b3c0..25ed11bb5ed3 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -3143,10 +3143,6 @@ static int ca8210_probe(struct spi_device *spi_device) pdata = kmalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) { - dev_crit( - &spi_device->dev, - "Could not allocate platform data\n" - ); ret = -ENOMEM; goto error; } -- cgit v1.2.3 From 3a21bf586dd012e82abbd4dcedafdfa991f02fa3 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 22 May 2017 08:03:17 +0200 Subject: ieee802154: ca8210: Delete an error message for a failed memory allocation in ca8210_skb_rx() Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/ca8210.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index 25ed11bb5ed3..f6df75e80a60 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -1808,10 +1808,9 @@ static int ca8210_skb_rx( /* Allocate mtu size buffer for every rx packet */ skb = dev_alloc_skb(IEEE802154_MTU + sizeof(hdr)); - if (!skb) { - dev_crit(&priv->spi->dev, "dev_alloc_skb failed\n"); + if (!skb) return -ENOMEM; - } + skb_reserve(skb, sizeof(hdr)); msdulen = data_ind[22]; /* msdu_length */ -- cgit v1.2.3 From 3c89a72ad80c64bdbd5ff851ee9c328a191f7e01 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 May 2017 11:27:52 +0200 Subject: b43: Add missing MODULE_FIRMWARE() Some firmware entries were forgotten to be added via MODULE_FIRMWARE(), which may result in the non-functional state when the driver is loaded in initrd. Link: http://bugzilla.opensuse.org/show_bug.cgi?id=1037344 Fixes: 15be8e89cdd9 ("b43: add more bcma cores") Signed-off-by: Takashi Iwai Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/b43/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index d23aac7503d3..b37e7391f55d 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -71,8 +71,18 @@ MODULE_FIRMWARE("b43/ucode11.fw"); MODULE_FIRMWARE("b43/ucode13.fw"); MODULE_FIRMWARE("b43/ucode14.fw"); MODULE_FIRMWARE("b43/ucode15.fw"); +MODULE_FIRMWARE("b43/ucode16_lp.fw"); MODULE_FIRMWARE("b43/ucode16_mimo.fw"); +MODULE_FIRMWARE("b43/ucode24_lcn.fw"); +MODULE_FIRMWARE("b43/ucode25_lcn.fw"); +MODULE_FIRMWARE("b43/ucode25_mimo.fw"); +MODULE_FIRMWARE("b43/ucode26_mimo.fw"); +MODULE_FIRMWARE("b43/ucode29_mimo.fw"); +MODULE_FIRMWARE("b43/ucode33_lcn40.fw"); +MODULE_FIRMWARE("b43/ucode30_mimo.fw"); MODULE_FIRMWARE("b43/ucode5.fw"); +MODULE_FIRMWARE("b43/ucode40.fw"); +MODULE_FIRMWARE("b43/ucode42.fw"); MODULE_FIRMWARE("b43/ucode9.fw"); static int modparam_bad_frames_preempt; -- cgit v1.2.3 From 6572e5f72d01121f21734a1309dac2ecd7bbff95 Mon Sep 17 00:00:00 2001 From: Xie Qirong Date: Fri, 12 May 2017 17:32:59 +0800 Subject: brcmfmac: btcoex: replace init_timer with setup_timer setup_timer.cocci suggested the following improvement: drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c:383:1-11: Use setup_timer function for function on line 384. The combination of init_timer and setting up the data and function field manually is equivalent to calling setup_timer(). This is an api consolidation only and improves readability. Acked-by: Arend van Spriel Signed-off-by: Xie Qirong Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c index 14a70d4b4e86..3559fb5b8fb0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c @@ -380,9 +380,7 @@ int brcmf_btcoex_attach(struct brcmf_cfg80211_info *cfg) /* Set up timer for BT */ btci->timer_on = false; btci->timeout = BRCMF_BTCOEX_OPPR_WIN_TIME; - init_timer(&btci->timer); - btci->timer.data = (ulong)btci; - btci->timer.function = brcmf_btcoex_timerfunc; + setup_timer(&btci->timer, brcmf_btcoex_timerfunc, (ulong)btci); btci->cfg = cfg; btci->saved_regs_part1 = false; btci->saved_regs_part2 = false; -- cgit v1.2.3 From 9029679f66d976f8c720eb03c4898274803c9923 Mon Sep 17 00:00:00 2001 From: Chi-hsien Lin Date: Thu, 18 May 2017 17:22:19 +0800 Subject: brcmfmac: remove setting IBSS mode when stopping AP Upon stopping an AP interface the driver disable INFRA mode effectively setting the interface in IBSS mode. However, this may affect other interfaces running in INFRA mode. For instance, if user creates and stops hostap daemon on virtual interface, then association cannot work on primary interface because default BSS has been set to IBSS mode in firmware side. The IBSS mode should be set when cfg80211 changes the interface. Reviewed-by: Wright Feng Signed-off-by: Chi-hsien Lin [kvalo@codeaurora.org: rephased commit log based on discussion] Signed-off-by: Wright Feng Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 2bf76bd765bd..a2bf11fc8ecc 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -4674,9 +4674,6 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0); if (err < 0) brcmf_err("setting AP mode failed %d\n", err); - err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0); - if (err < 0) - brcmf_err("setting INFRA mode failed %d\n", err); if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) brcmf_fil_iovar_int_set(ifp, "mbss", 0); brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, -- cgit v1.2.3 From 552aa585faff19ceead7aa840d4ce11830ce34a9 Mon Sep 17 00:00:00 2001 From: Elena Reshetova Date: Tue, 28 Mar 2017 11:56:42 +0300 Subject: hostap: convert hostap_cmd_queue.usecnt from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Signed-off-by: Kalle Valo --- drivers/net/wireless/intersil/hostap/hostap_hw.c | 12 ++++++------ drivers/net/wireless/intersil/hostap/hostap_wlan.h | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index 04dfd040a650..d4f0b730796e 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -190,7 +190,7 @@ static inline void __hostap_cmd_queue_free(local_info_t *local, } } - if (atomic_dec_and_test(&entry->usecnt) && entry->del_req) + if (refcount_dec_and_test(&entry->usecnt) && entry->del_req) kfree(entry); } @@ -228,7 +228,7 @@ static void prism2_clear_cmd_queue(local_info_t *local) spin_lock_irqsave(&local->cmdlock, flags); list_for_each_safe(ptr, n, &local->cmd_queue) { entry = list_entry(ptr, struct hostap_cmd_queue, list); - atomic_inc(&entry->usecnt); + refcount_inc(&entry->usecnt); printk(KERN_DEBUG "%s: removed pending cmd_queue entry " "(type=%d, cmd=0x%04x, param0=0x%04x)\n", local->dev->name, entry->type, entry->cmd, @@ -350,7 +350,7 @@ static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, if (entry == NULL) return -ENOMEM; - atomic_set(&entry->usecnt, 1); + refcount_set(&entry->usecnt, 1); entry->type = CMD_SLEEP; entry->cmd = cmd; entry->param0 = param0; @@ -516,7 +516,7 @@ static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, if (entry == NULL) return -ENOMEM; - atomic_set(&entry->usecnt, 1); + refcount_set(&entry->usecnt, 1); entry->type = CMD_CALLBACK; entry->cmd = cmd; entry->param0 = param0; @@ -666,7 +666,7 @@ static void prism2_cmd_ev(struct net_device *dev) if (!list_empty(&local->cmd_queue)) { entry = list_entry(local->cmd_queue.next, struct hostap_cmd_queue, list); - atomic_inc(&entry->usecnt); + refcount_inc(&entry->usecnt); list_del_init(&entry->list); local->cmd_queue_len--; @@ -718,7 +718,7 @@ static void prism2_cmd_ev(struct net_device *dev) entry = NULL; } if (entry) - atomic_inc(&entry->usecnt); + refcount_inc(&entry->usecnt); } spin_unlock(&local->cmdlock); diff --git a/drivers/net/wireless/intersil/hostap/hostap_wlan.h b/drivers/net/wireless/intersil/hostap/hostap_wlan.h index ca25283e1c92..5352adb94d50 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_wlan.h +++ b/drivers/net/wireless/intersil/hostap/hostap_wlan.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -557,7 +558,7 @@ struct hostap_cmd_queue { u16 resp0, res; volatile int issued, issuing; - atomic_t usecnt; + refcount_t usecnt; int del_req; }; -- cgit v1.2.3 From 0aeffa7041d84976432e903cb04e8d7b0edf31ed Mon Sep 17 00:00:00 2001 From: Elena Reshetova Date: Tue, 28 Mar 2017 11:56:43 +0300 Subject: orinoco_usb: convert request_context.refcount from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Signed-off-by: Kalle Valo --- drivers/net/wireless/intersil/orinoco/orinoco_usb.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index 132f5fbda58b..c84fd8490601 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -64,6 +64,7 @@ #include #include #include +#include #include "mic.h" #include "orinoco.h" @@ -268,7 +269,7 @@ enum ezusb_state { struct request_context { struct list_head list; - atomic_t refcount; + refcount_t refcount; struct completion done; /* Signals that CTX is dead */ int killed; struct urb *outurb; /* OUT for req pkt */ @@ -298,7 +299,7 @@ static inline u8 ezusb_reply_inc(u8 count) static void ezusb_request_context_put(struct request_context *ctx) { - if (!atomic_dec_and_test(&ctx->refcount)) + if (!refcount_dec_and_test(&ctx->refcount)) return; WARN_ON(!ctx->done.done); @@ -328,7 +329,7 @@ static void ezusb_request_timerfn(u_long _ctx) } else { ctx->state = EZUSB_CTX_RESP_TIMEOUT; dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n"); - atomic_inc(&ctx->refcount); + refcount_inc(&ctx->refcount); ctx->killed = 1; ezusb_ctx_complete(ctx); ezusb_request_context_put(ctx); @@ -361,7 +362,7 @@ static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv, ctx->out_rid = out_rid; ctx->in_rid = in_rid; - atomic_set(&ctx->refcount, 1); + refcount_set(&ctx->refcount, 1); init_completion(&ctx->done); setup_timer(&ctx->timer, ezusb_request_timerfn, (u_long)ctx); @@ -469,7 +470,7 @@ static void ezusb_req_queue_run(struct ezusb_priv *upriv) list_move_tail(&ctx->list, &upriv->req_active); if (ctx->state == EZUSB_CTX_QUEUED) { - atomic_inc(&ctx->refcount); + refcount_inc(&ctx->refcount); result = usb_submit_urb(ctx->outurb, GFP_ATOMIC); if (result) { ctx->state = EZUSB_CTX_REQSUBMIT_FAIL; @@ -507,7 +508,7 @@ static void ezusb_req_enqueue_run(struct ezusb_priv *upriv, spin_unlock_irqrestore(&upriv->req_lock, flags); goto done; } - atomic_inc(&ctx->refcount); + refcount_inc(&ctx->refcount); list_add_tail(&ctx->list, &upriv->req_pending); spin_unlock_irqrestore(&upriv->req_lock, flags); @@ -1477,7 +1478,7 @@ static inline void ezusb_delete(struct ezusb_priv *upriv) int err; ctx = list_entry(item, struct request_context, list); - atomic_inc(&ctx->refcount); + refcount_inc(&ctx->refcount); ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK; err = usb_unlink_urb(ctx->outurb); -- cgit v1.2.3 From e48d661eb13f2f83861428f001c567fdb3f317e8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 5 May 2017 15:38:41 -0700 Subject: ray_cs: Avoid reading past end of buffer Using memcpy() from a buffer that is shorter than the length copied means the destination buffer is being filled with arbitrary data from the kernel rodata segment. In this case, the source was made longer, since it did not match the destination structure size. Additionally removes a needless cast. This was found with the future CONFIG_FORTIFY_SOURCE feature. Cc: Daniel Micay Signed-off-by: Kees Cook Signed-off-by: Kalle Valo --- drivers/net/wireless/ray_cs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index b94479441b0c..170cd504e8ff 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -247,7 +247,10 @@ static const UCHAR b4_default_startup_parms[] = { 0x04, 0x08, /* Noise gain, limit offset */ 0x28, 0x28, /* det rssi, med busy offsets */ 7, /* det sync thresh */ - 0, 2, 2 /* test mode, min, max */ + 0, 2, 2, /* test mode, min, max */ + 0, /* rx/tx delay */ + 0, 0, 0, 0, 0, 0, /* current BSS id */ + 0 /* hop set */ }; /*===========================================================================*/ @@ -597,7 +600,7 @@ static void init_startup_params(ray_dev_t *local) * a_beacon_period = hops a_beacon_period = KuS *//* 64ms = 010000 */ if (local->fw_ver == 0x55) { - memcpy((UCHAR *) &local->sparm.b4, b4_default_startup_parms, + memcpy(&local->sparm.b4, b4_default_startup_parms, sizeof(struct b4_startup_params)); /* Translate sane kus input values to old build 4/5 format */ /* i = hop time in uS truncated to 3 bytes */ -- cgit v1.2.3 From c239838fbd6d5aadac193e02d0cf1866238da97b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 6 May 2017 03:48:35 +0300 Subject: p54: allocate enough space for ->used_rxkeys We have the number of longs, but we should be calculating the number of bytes needed. Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/intersil/p54/fwio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c index 4ac6764f4897..3076f646c829 100644 --- a/drivers/net/wireless/intersil/p54/fwio.c +++ b/drivers/net/wireless/intersil/p54/fwio.c @@ -176,8 +176,9 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) * keeping a extra list for uploaded keys. */ - priv->used_rxkeys = kzalloc(BITS_TO_LONGS( - priv->rx_keycache_size), GFP_KERNEL); + priv->used_rxkeys = kcalloc(BITS_TO_LONGS(priv->rx_keycache_size), + sizeof(long), + GFP_KERNEL); if (!priv->used_rxkeys) return -ENOMEM; -- cgit v1.2.3 From 863483c970e968efd6a119a2118f57977d04cefe Mon Sep 17 00:00:00 2001 From: Girish Moodalbail Date: Fri, 19 May 2017 15:25:44 -0700 Subject: macsec: double accounting of dropped rx/tx packets The macsec implementation shouldn't account for rx/tx packets that are dropped in the netdev framework. The netdev framework itself accounts for such packets by atomically updating struct net_device`rx_dropped and struct net_device`tx_dropped fields. Later on when the stats for macsec link is retrieved, the packets dropped in netdev framework will be included in dev_get_stats() after calling macsec.c`macsec_get_stats64() Signed-off-by: Girish Moodalbail Signed-off-by: David S. Miller --- drivers/net/macsec.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index cdc347be68f2..91642fd87cd1 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -588,8 +588,6 @@ static void count_tx(struct net_device *dev, int ret, int len) stats->tx_packets++; stats->tx_bytes += len; u64_stats_update_end(&stats->syncp); - } else { - dev->stats.tx_dropped++; } } @@ -883,7 +881,7 @@ static void macsec_decrypt_done(struct crypto_async_request *base, int err) struct macsec_dev *macsec = macsec_priv(dev); struct macsec_rx_sa *rx_sa = macsec_skb_cb(skb)->rx_sa; struct macsec_rx_sc *rx_sc = rx_sa->sc; - int len, ret; + int len; u32 pn; aead_request_free(macsec_skb_cb(skb)->req); @@ -904,11 +902,8 @@ static void macsec_decrypt_done(struct crypto_async_request *base, int err) macsec_reset_skb(skb, macsec->secy.netdev); len = skb->len; - ret = gro_cells_receive(&macsec->gro_cells, skb); - if (ret == NET_RX_SUCCESS) + if (gro_cells_receive(&macsec->gro_cells, skb) == NET_RX_SUCCESS) count_rx(dev, len); - else - macsec->secy.netdev->stats.rx_dropped++; rcu_read_unlock_bh(); @@ -1037,7 +1032,6 @@ static void handle_not_macsec(struct sk_buff *skb) */ list_for_each_entry_rcu(macsec, &rxd->secys, secys) { struct sk_buff *nskb; - int ret; struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats); if (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) { @@ -1054,13 +1048,10 @@ static void handle_not_macsec(struct sk_buff *skb) nskb->dev = macsec->secy.netdev; - ret = netif_rx(nskb); - if (ret == NET_RX_SUCCESS) { + if (netif_rx(nskb) == NET_RX_SUCCESS) { u64_stats_update_begin(&secy_stats->syncp); secy_stats->stats.InPktsUntagged++; u64_stats_update_end(&secy_stats->syncp); - } else { - macsec->secy.netdev->stats.rx_dropped++; } } -- cgit v1.2.3 From 85deed56032b6c98b541895bfda9bdd74f6ed987 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Mon, 22 May 2017 09:31:15 +0200 Subject: net/wan/fsl_ucc_hdlc: fix muram allocation error sizeof(priv->ucc_pram) is 4 as it is the size of a pointer, but we want to reserve space for the struct ucc_hdlc_param. Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index e9b2d687f150..33df76405b86 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -189,7 +189,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) } /* Alloc parameter ram for ucc hdlc */ - priv->ucc_pram_offset = qe_muram_alloc(sizeof(priv->ucc_pram), + priv->ucc_pram_offset = qe_muram_alloc(sizeof(struct ucc_hdlc_param), ALIGNMENT_OF_UCC_HDLC_PRAM); if (priv->ucc_pram_offset < 0) { -- cgit v1.2.3 From cd6f8db9aebeb7f234b38756ba8ee77230058846 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 22 May 2017 10:59:22 -0700 Subject: nfp: add nfp_cppcore_pcie_unit() helper Add nfp_cppcore_pcie_unit() helper to retrieve the PCIE unit of a CPP handle and use the new helper as appropriate. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 16 ++++------------ drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 11 +++++++++++ 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 8cb87cbe1120..16115973112c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -190,15 +190,11 @@ nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id) static unsigned int nfp_net_pf_get_num_ports(struct nfp_pf *pf) { char name[256]; - u16 interface; - int pcie_pf; int err = 0; u64 val; - interface = nfp_cpp_interface(pf->cpp); - pcie_pf = NFP_CPP_INTERFACE_UNIT_of(interface); - - snprintf(name, sizeof(name), "nfd_cfg_pf%d_num_ports", pcie_pf); + snprintf(name, sizeof(name), "nfd_cfg_pf%u_num_ports", + nfp_cppcore_pcie_unit(pf->cpp)); val = nfp_rtsym_read_le(pf->cpp, name, &err); /* Default to one port */ @@ -241,13 +237,9 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) const struct nfp_rtsym *ctrl_sym; u8 __iomem *ctrl_bar; char pf_symbol[256]; - u16 interface; - int pcie_pf; - - interface = nfp_cpp_interface(pf->cpp); - pcie_pf = NFP_CPP_INTERFACE_UNIT_of(interface); - snprintf(pf_symbol, sizeof(pf_symbol), "_pf%d_net_bar0", pcie_pf); + snprintf(pf_symbol, sizeof(pf_symbol), "_pf%u_net_bar0", + nfp_cppcore_pcie_unit(pf->cpp)); ctrl_sym = nfp_rtsym_lookup(pf->cpp, pf_symbol); if (!ctrl_sym) { diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index edecc0a27485..154b0b594184 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -289,6 +289,17 @@ int nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex); int nfp_cpp_mutex_unlock(struct nfp_cpp_mutex *mutex); int nfp_cpp_mutex_trylock(struct nfp_cpp_mutex *mutex); +/** + * nfp_cppcore_pcie_unit() - Get PCI Unit of a CPP handle + * @cpp: CPP handle + * + * Return: PCI unit for the NFP CPP handle + */ +static inline u8 nfp_cppcore_pcie_unit(struct nfp_cpp *cpp) +{ + return NFP_CPP_INTERFACE_UNIT_of(nfp_cpp_interface(cpp)); +} + struct nfp_cpp_explicit; struct nfp_cpp_explicit_command { -- cgit v1.2.3 From beba69ca755542c2581bbb64b2fa79b11047ed8f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:23 -0700 Subject: nfp: make nfp_net alloc/init/cleanup/free not depend on netdevs struct nfp_net represents a vNIC, we will be moving away from the requirement for every vNIC to have a netdev associated with it. Remove "netdev" from some function names and prefer passing struct nfp_net pointer as argument instead of struct net_device *. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 12 ++++---- .../net/ethernet/netronome/nfp/nfp_net_common.c | 35 ++++++++++------------ drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 14 ++++----- .../net/ethernet/netronome/nfp/nfp_netvf_main.c | 10 +++---- 4 files changed, 35 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 7b9518cbe965..04609191ca88 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -807,11 +807,13 @@ void nfp_net_get_fw_version(struct nfp_net_fw_version *fw_ver, void __iomem *ctrl_bar); struct nfp_net * -nfp_net_netdev_alloc(struct pci_dev *pdev, - unsigned int max_tx_rings, unsigned int max_rx_rings); -void nfp_net_netdev_free(struct nfp_net *nn); -int nfp_net_netdev_init(struct net_device *netdev); -void nfp_net_netdev_clean(struct net_device *netdev); +nfp_net_alloc(struct pci_dev *pdev, + unsigned int max_tx_rings, unsigned int max_rx_rings); +void nfp_net_free(struct nfp_net *nn); + +int nfp_net_init(struct nfp_net *nn); +void nfp_net_clean(struct nfp_net *nn); + void nfp_net_set_ethtool_ops(struct net_device *netdev); void nfp_net_info(struct nfp_net *nn); int nfp_net_reconfig(struct nfp_net *nn, u32 update); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index da83e17b8b20..b427c95c5acd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -516,11 +516,10 @@ nfp_net_rx_ring_init(struct nfp_net_rx_ring *rx_ring, /** * nfp_net_vecs_init() - Assign IRQs and setup rvecs. - * @netdev: netdev structure + * @nn: NFP Network structure */ -static void nfp_net_vecs_init(struct net_device *netdev) +static void nfp_net_vecs_init(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); struct nfp_net_r_vector *r_vec; int r; @@ -3087,7 +3086,7 @@ void nfp_net_info(struct nfp_net *nn) } /** - * nfp_net_netdev_alloc() - Allocate netdev and related structure + * nfp_net_alloc() - Allocate netdev and related structure * @pdev: PCI device * @max_tx_rings: Maximum number of TX rings supported by device * @max_rx_rings: Maximum number of RX rings supported by device @@ -3097,9 +3096,9 @@ void nfp_net_info(struct nfp_net *nn) * * Return: NFP Net device structure, or ERR_PTR on error. */ -struct nfp_net *nfp_net_netdev_alloc(struct pci_dev *pdev, - unsigned int max_tx_rings, - unsigned int max_rx_rings) +struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, + unsigned int max_tx_rings, + unsigned int max_rx_rings) { struct net_device *netdev; struct nfp_net *nn; @@ -3144,10 +3143,10 @@ struct nfp_net *nfp_net_netdev_alloc(struct pci_dev *pdev, } /** - * nfp_net_netdev_free() - Undo what @nfp_net_netdev_alloc() did + * nfp_net_free() - Undo what @nfp_net_alloc() did * @nn: NFP Net device to reconfigure */ -void nfp_net_netdev_free(struct nfp_net *nn) +void nfp_net_free(struct nfp_net *nn) { free_netdev(nn->dp.netdev); } @@ -3221,14 +3220,14 @@ static void nfp_net_irqmod_init(struct nfp_net *nn) } /** - * nfp_net_netdev_init() - Initialise/finalise the netdev structure - * @netdev: netdev structure + * nfp_net_init() - Initialise/finalise the nfp_net structure + * @nn: NFP Net device structure * * Return: 0 on success or negative errno on error. */ -int nfp_net_netdev_init(struct net_device *netdev) +int nfp_net_init(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); + struct net_device *netdev = nn->dp.netdev; int err; nn->dp.rx_dma_dir = DMA_FROM_DEVICE; @@ -3367,19 +3366,17 @@ int nfp_net_netdev_init(struct net_device *netdev) netif_carrier_off(netdev); nfp_net_set_ethtool_ops(netdev); - nfp_net_vecs_init(netdev); + nfp_net_vecs_init(nn); return register_netdev(netdev); } /** - * nfp_net_netdev_clean() - Undo what nfp_net_netdev_init() did. - * @netdev: netdev structure + * nfp_net_clean() - Undo what nfp_net_init() did. + * @nn: NFP Net device structure */ -void nfp_net_netdev_clean(struct net_device *netdev) +void nfp_net_clean(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); - unregister_netdev(nn->dp.netdev); if (nn->dp.xdp_prog) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 16115973112c..55d916cb04fe 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -277,7 +277,7 @@ static void nfp_net_pf_free_netdevs(struct nfp_pf *pf) list_del(&nn->port_list); pf->num_netdevs--; - nfp_net_netdev_free(nn); + nfp_net_free(nn); } } @@ -294,7 +294,7 @@ nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar, n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS); /* Allocate and initialise the netdev */ - nn = nfp_net_netdev_alloc(pf->pdev, n_tx_rings, n_rx_rings); + nn = nfp_net_alloc(pf->pdev, n_tx_rings, n_rx_rings); if (IS_ERR(nn)) return nn; @@ -326,7 +326,7 @@ nfp_net_pf_init_port_netdev(struct nfp_pf *pf, struct nfp_net *nn, */ nn->me_freq_mhz = 1200; - err = nfp_net_netdev_init(nn->dp.netdev); + err = nfp_net_init(nn); if (err) return err; @@ -451,7 +451,7 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, err_prev_deinit: list_for_each_entry_continue_reverse(nn, &pf->ports, port_list) { nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_netdev_clean(nn->dp.netdev); + nfp_net_clean(nn); } nfp_net_irqs_disable(pf->pdev); err_vec_free: @@ -518,11 +518,11 @@ static void nfp_net_refresh_netdevs(struct work_struct *work) nn_warn(nn, "Port config changed, unregistering. Reboot required before port will be operational again.\n"); nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_netdev_clean(nn->dp.netdev); + nfp_net_clean(nn); list_del(&nn->port_list); pf->num_netdevs--; - nfp_net_netdev_free(nn); + nfp_net_free(nn); } if (list_empty(&pf->ports)) @@ -693,7 +693,7 @@ void nfp_net_pci_remove(struct nfp_pf *pf) list_for_each_entry(nn, &pf->ports, port_list) { nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_netdev_clean(nn->dp.netdev); + nfp_net_clean(nn); } nfp_net_pf_free_netdevs(pf); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c index 86e61be6f35c..856a76bdfc24 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c @@ -202,7 +202,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, rx_bar_off = NFP_PCIE_QUEUE(startq); /* Allocate and initialise the netdev */ - nn = nfp_net_netdev_alloc(pdev, max_tx_rings, max_rx_rings); + nn = nfp_net_alloc(pdev, max_tx_rings, max_rx_rings); if (IS_ERR(nn)) { err = PTR_ERR(nn); goto err_ctrl_unmap; @@ -283,7 +283,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, */ nn->me_freq_mhz = 1200; - err = nfp_net_netdev_init(nn->dp.netdev); + err = nfp_net_init(nn); if (err) goto err_irqs_disable; @@ -304,7 +304,7 @@ err_unmap_tx: else iounmap(vf->q_bar); err_netdev_free: - nfp_net_netdev_free(nn); + nfp_net_free(nn); err_ctrl_unmap: iounmap(ctrl_bar); err_pci_regions: @@ -328,7 +328,7 @@ static void nfp_netvf_pci_remove(struct pci_dev *pdev) nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_debugfs_dir_clean(&vf->ddir); - nfp_net_netdev_clean(nn->dp.netdev); + nfp_net_clean(nn); nfp_net_irqs_disable(pdev); @@ -340,7 +340,7 @@ static void nfp_netvf_pci_remove(struct pci_dev *pdev) } iounmap(nn->dp.ctrl_bar); - nfp_net_netdev_free(nn); + nfp_net_free(nn); pci_release_regions(pdev); pci_disable_device(pdev); -- cgit v1.2.3 From d4e7f0928593ac7df9b78410beb90178326a22c0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:24 -0700 Subject: nfp: rename netdev/port to vNIC vNIC is a PCIe-side abstraction NFP firmwares supported by this driver use. It was initially meant to represent a device port and therefore a netdev but today should be thought of as a way of grouping descriptor rings and associated state. Advanced apps will have vNICs without netdevs and ports without a vNIC (using representors instead). Make sure code refers to vNICs as vNICs and not ports or netdevs. No functional changes. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 2 +- drivers/net/ethernet/netronome/nfp/nfp_main.h | 22 +-- drivers/net/ethernet/netronome/nfp/nfp_net.h | 10 +- .../net/ethernet/netronome/nfp/nfp_net_debugfs.c | 4 +- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 150 ++++++++++----------- .../net/ethernet/netronome/nfp/nfp_netvf_main.c | 4 +- 6 files changed, 95 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index dde35dae35c5..9fbc7eedc017 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -340,7 +340,7 @@ static int nfp_pci_probe(struct pci_dev *pdev, err = -ENOMEM; goto err_rel_regions; } - INIT_LIST_HEAD(&pf->ports); + INIT_LIST_HEAD(&pf->vnics); pci_set_drvdata(pdev, pf); pf->pdev = pdev; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index b57de047b002..1ca1c61450c1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -57,27 +57,27 @@ struct nfp_eth_table; * struct nfp_pf - NFP PF-specific device structure * @pdev: Backpointer to PCI device * @cpp: Pointer to the CPP handle - * @ctrl_area: Pointer to the CPP area for the control BAR + * @data_vnic_bar: Pointer to the CPP area for the data vNICs' BARs * @tx_area: Pointer to the CPP area for the TX queues * @rx_area: Pointer to the CPP area for the FL/RX queues - * @irq_entries: Array of MSI-X entries for all ports + * @irq_entries: Array of MSI-X entries for all vNICs * @limit_vfs: Number of VFs supported by firmware (~0 for PCI limit) * @num_vfs: Number of SR-IOV VFs enabled * @fw_loaded: Is the firmware loaded? * @eth_tbl: NSP ETH table * @ddir: Per-device debugfs directory - * @num_ports: Number of adapter ports app firmware supports - * @num_netdevs: Number of netdevs spawned - * @ports: Linked list of port structures (struct nfp_net) - * @port_lock: Protects @ports, @num_ports, @num_netdevs + * @max_data_vnics: Number of data vNICs app firmware supports + * @num_vnics: Number of vNICs spawned + * @vnics: Linked list of vNIC structures (struct nfp_net) * @port_refresh_work: Work entry for taking netdevs out + * @lock: Protects all fields which may change after probe */ struct nfp_pf { struct pci_dev *pdev; struct nfp_cpp *cpp; - struct nfp_cpp_area *ctrl_area; + struct nfp_cpp_area *data_vnic_bar; struct nfp_cpp_area *tx_area; struct nfp_cpp_area *rx_area; @@ -92,12 +92,12 @@ struct nfp_pf { struct dentry *ddir; - unsigned int num_ports; - unsigned int num_netdevs; + unsigned int max_data_vnics; + unsigned int num_vnics; - struct list_head ports; + struct list_head vnics; struct work_struct port_refresh_work; - struct mutex port_lock; + struct mutex lock; }; extern struct pci_driver nfp_netvf_pci_driver; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 04609191ca88..1d41be9b2309 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -84,7 +84,7 @@ #define NFP_NET_NON_Q_VECTORS 2 #define NFP_NET_IRQ_LSC_IDX 0 #define NFP_NET_IRQ_EXN_IDX 1 -#define NFP_NET_MIN_PORT_IRQS (NFP_NET_NON_Q_VECTORS + 1) +#define NFP_NET_MIN_VNIC_IRQS (NFP_NET_NON_Q_VECTORS + 1) /* Queue/Ring definitions */ #define NFP_NET_MAX_TX_RINGS 64 /* Max. # of Tx rings per device */ @@ -555,7 +555,7 @@ struct nfp_net_dp { * @rx_bar: Pointer to mapped FL/RX queues * @debugfs_dir: Device directory in debugfs * @ethtool_dump_flag: Ethtool dump flag - * @port_list: Entry on device port list + * @vnic_list: Entry on device vNIC list * @pdev: Backpointer to PCI device * @cpp: CPP device handle if available * @eth_port: Translated ETH Table port entry @@ -625,7 +625,7 @@ struct nfp_net { struct dentry *debugfs_dir; u32 ethtool_dump_flag; - struct list_head port_list; + struct list_head vnic_list; struct pci_dev *pdev; struct nfp_cpp *cpp; @@ -842,7 +842,7 @@ void nfp_net_refresh_port_table(struct nfp_net *nn); void nfp_net_debugfs_create(void); void nfp_net_debugfs_destroy(void); struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev); -void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id); +void nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id); void nfp_net_debugfs_dir_clean(struct dentry **dir); #else static inline void nfp_net_debugfs_create(void) @@ -859,7 +859,7 @@ static inline struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev) } static inline void -nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id) +nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id) { } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c index 4077c59bf782..6cf1b234eecd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c @@ -200,7 +200,7 @@ static const struct file_operations nfp_xdp_q_fops = { .llseek = seq_lseek }; -void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id) +void nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id) { struct dentry *queues, *tx, *rx, *xdp; char name[20]; @@ -209,7 +209,7 @@ void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id) if (IS_ERR_OR_NULL(nfp_dir)) return; - sprintf(name, "port%d", id); + sprintf(name, "vnic%d", id); nn->debugfs_dir = debugfs_create_dir(name, ddir); if (IS_ERR_OR_NULL(nn->debugfs_dir)) return; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 55d916cb04fe..532371940fd6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -197,10 +197,10 @@ static unsigned int nfp_net_pf_get_num_ports(struct nfp_pf *pf) nfp_cppcore_pcie_unit(pf->cpp)); val = nfp_rtsym_read_le(pf->cpp, name, &err); - /* Default to one port */ + /* Default to one port/vNIC */ if (err) { if (err != -ENOENT) - nfp_err(pf->cpp, "Unable to read adapter port count\n"); + nfp_err(pf->cpp, "Unable to read adapter vNIC count\n"); val = 1; } @@ -216,7 +216,7 @@ nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar, min_qc = readl(ctrl_bar + start_off); max_qc = min_qc; - for (i = 0; i < pf->num_ports; i++) { + for (i = 0; i < pf->max_data_vnics; i++) { /* To make our lives simpler only accept configuration where * queues are allocated to PFs in order (queues of PFn all have * indexes lower than PFn+1). @@ -248,17 +248,17 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) return NULL; } - if (ctrl_sym->size < pf->num_ports * NFP_PF_CSR_SLICE_SIZE) { + if (ctrl_sym->size < pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE) { dev_err(&pf->pdev->dev, - "PF BAR0 too small to contain %d ports\n", - pf->num_ports); + "PF BAR0 too small to contain %d vNICs\n", + pf->max_data_vnics); return NULL; } ctrl_bar = nfp_net_map_area(pf->cpp, "net.ctrl", ctrl_sym->domain, ctrl_sym->target, ctrl_sym->addr, ctrl_sym->size, - &pf->ctrl_area); + &pf->data_vnic_bar); if (IS_ERR(ctrl_bar)) { dev_err(&pf->pdev->dev, "Failed to map PF BAR0: %ld\n", PTR_ERR(ctrl_bar)); @@ -268,24 +268,24 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) return ctrl_bar; } -static void nfp_net_pf_free_netdevs(struct nfp_pf *pf) +static void nfp_net_pf_free_vnics(struct nfp_pf *pf) { struct nfp_net *nn; - while (!list_empty(&pf->ports)) { - nn = list_first_entry(&pf->ports, struct nfp_net, port_list); - list_del(&nn->port_list); - pf->num_netdevs--; + while (!list_empty(&pf->vnics)) { + nn = list_first_entry(&pf->vnics, struct nfp_net, vnic_list); + list_del(&nn->vnic_list); + pf->num_vnics--; nfp_net_free(nn); } } static struct nfp_net * -nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar, - void __iomem *tx_bar, void __iomem *rx_bar, - int stride, struct nfp_net_fw_version *fw_ver, - struct nfp_eth_table_port *eth_port) +nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, + void __iomem *tx_bar, void __iomem *rx_bar, + int stride, struct nfp_net_fw_version *fw_ver, + struct nfp_eth_table_port *eth_port) { u32 n_tx_rings, n_rx_rings; struct nfp_net *nn; @@ -293,7 +293,7 @@ nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar, n_tx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_TXRINGS); n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS); - /* Allocate and initialise the netdev */ + /* Allocate and initialise the vNIC */ nn = nfp_net_alloc(pf->pdev, n_tx_rings, n_rx_rings); if (IS_ERR(nn)) return nn; @@ -312,8 +312,7 @@ nfp_net_pf_alloc_port_netdev(struct nfp_pf *pf, void __iomem *ctrl_bar, } static int -nfp_net_pf_init_port_netdev(struct nfp_pf *pf, struct nfp_net *nn, - unsigned int id) +nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id) { int err; @@ -330,7 +329,7 @@ nfp_net_pf_init_port_netdev(struct nfp_pf *pf, struct nfp_net *nn, if (err) return err; - nfp_net_debugfs_port_add(nn, pf->ddir, id); + nfp_net_debugfs_vnic_add(nn, pf->ddir, id); nfp_net_info(nn); @@ -338,9 +337,9 @@ nfp_net_pf_init_port_netdev(struct nfp_pf *pf, struct nfp_net *nn, } static int -nfp_net_pf_alloc_netdevs(struct nfp_pf *pf, void __iomem *ctrl_bar, - void __iomem *tx_bar, void __iomem *rx_bar, - int stride, struct nfp_net_fw_version *fw_ver) +nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, + void __iomem *tx_bar, void __iomem *rx_bar, + int stride, struct nfp_net_fw_version *fw_ver) { u32 prev_tx_base, prev_rx_base, tgt_tx_base, tgt_rx_base; struct nfp_eth_table_port *eth_port; @@ -351,7 +350,7 @@ nfp_net_pf_alloc_netdevs(struct nfp_pf *pf, void __iomem *ctrl_bar, prev_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); prev_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); - for (i = 0; i < pf->num_ports; i++) { + for (i = 0; i < pf->max_data_vnics; i++) { tgt_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); tgt_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); tx_bar += (tgt_tx_base - prev_tx_base) * NFP_QCP_QUEUE_ADDR_SZ; @@ -363,49 +362,48 @@ nfp_net_pf_alloc_netdevs(struct nfp_pf *pf, void __iomem *ctrl_bar, if (eth_port && eth_port->override_changed) { nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i); } else { - nn = nfp_net_pf_alloc_port_netdev(pf, ctrl_bar, tx_bar, - rx_bar, stride, - fw_ver, eth_port); + nn = nfp_net_pf_alloc_vnic(pf, ctrl_bar, tx_bar, rx_bar, + stride, fw_ver, eth_port); if (IS_ERR(nn)) { err = PTR_ERR(nn); goto err_free_prev; } - list_add_tail(&nn->port_list, &pf->ports); - pf->num_netdevs++; + list_add_tail(&nn->vnic_list, &pf->vnics); + pf->num_vnics++; } ctrl_bar += NFP_PF_CSR_SLICE_SIZE; } - if (list_empty(&pf->ports)) + if (list_empty(&pf->vnics)) return -ENODEV; return 0; err_free_prev: - nfp_net_pf_free_netdevs(pf); + nfp_net_pf_free_vnics(pf); return err; } static int -nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, - void __iomem *ctrl_bar, void __iomem *tx_bar, - void __iomem *rx_bar, int stride, - struct nfp_net_fw_version *fw_ver) +nfp_net_pf_spawn_vnics(struct nfp_pf *pf, + void __iomem *ctrl_bar, void __iomem *tx_bar, + void __iomem *rx_bar, int stride, + struct nfp_net_fw_version *fw_ver) { - unsigned int id, wanted_irqs, num_irqs, ports_left, irqs_left; + unsigned int id, wanted_irqs, num_irqs, vnics_left, irqs_left; struct nfp_net *nn; int err; - /* Allocate the netdevs and do basic init */ - err = nfp_net_pf_alloc_netdevs(pf, ctrl_bar, tx_bar, rx_bar, - stride, fw_ver); + /* Allocate the vnics and do basic init */ + err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, tx_bar, rx_bar, + stride, fw_ver); if (err) return err; /* Get MSI-X vectors */ wanted_irqs = 0; - list_for_each_entry(nn, &pf->ports, port_list) + list_for_each_entry(nn, &pf->vnics, vnic_list) wanted_irqs += NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs; pf->irq_entries = kcalloc(wanted_irqs, sizeof(*pf->irq_entries), GFP_KERNEL); @@ -415,7 +413,7 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, } num_irqs = nfp_net_irqs_alloc(pf->pdev, pf->irq_entries, - NFP_NET_MIN_PORT_IRQS * pf->num_netdevs, + NFP_NET_MIN_VNIC_IRQS * pf->num_vnics, wanted_irqs); if (!num_irqs) { nn_warn(nn, "Unable to allocate MSI-X Vectors. Exiting\n"); @@ -423,23 +421,23 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, goto err_vec_free; } - /* Distribute IRQs to ports */ + /* Distribute IRQs to vNICs */ irqs_left = num_irqs; - ports_left = pf->num_netdevs; - list_for_each_entry(nn, &pf->ports, port_list) { + vnics_left = pf->num_vnics; + list_for_each_entry(nn, &pf->vnics, vnic_list) { unsigned int n; - n = DIV_ROUND_UP(irqs_left, ports_left); + n = DIV_ROUND_UP(irqs_left, vnics_left); nfp_net_irqs_assign(nn, &pf->irq_entries[num_irqs - irqs_left], n); irqs_left -= n; - ports_left--; + vnics_left--; } - /* Finish netdev init and register */ + /* Finish vNIC init and register */ id = 0; - list_for_each_entry(nn, &pf->ports, port_list) { - err = nfp_net_pf_init_port_netdev(pf, nn, id); + list_for_each_entry(nn, &pf->vnics, vnic_list) { + err = nfp_net_pf_init_vnic(pf, nn, id); if (err) goto err_prev_deinit; @@ -449,7 +447,7 @@ nfp_net_pf_spawn_netdevs(struct nfp_pf *pf, return 0; err_prev_deinit: - list_for_each_entry_continue_reverse(nn, &pf->ports, port_list) { + list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list) { nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_clean(nn); } @@ -457,7 +455,7 @@ err_prev_deinit: err_vec_free: kfree(pf->irq_entries); err_nn_free: - nfp_net_pf_free_netdevs(pf); + nfp_net_pf_free_vnics(pf); return err; } @@ -470,23 +468,23 @@ static void nfp_net_pci_remove_finish(struct nfp_pf *pf) nfp_cpp_area_release_free(pf->rx_area); nfp_cpp_area_release_free(pf->tx_area); - nfp_cpp_area_release_free(pf->ctrl_area); + nfp_cpp_area_release_free(pf->data_vnic_bar); } -static void nfp_net_refresh_netdevs(struct work_struct *work) +static void nfp_net_refresh_vnics(struct work_struct *work) { struct nfp_pf *pf = container_of(work, struct nfp_pf, port_refresh_work); struct nfp_eth_table *eth_table; struct nfp_net *nn, *next; - mutex_lock(&pf->port_lock); + mutex_lock(&pf->lock); /* Check for nfp_net_pci_remove() racing against us */ - if (list_empty(&pf->ports)) + if (list_empty(&pf->vnics)) goto out; - list_for_each_entry(nn, &pf->ports, port_list) + list_for_each_entry(nn, &pf->vnics, vnic_list) nfp_net_link_changed_read_clear(nn); eth_table = nfp_eth_read_ports(pf->cpp); @@ -496,7 +494,7 @@ static void nfp_net_refresh_netdevs(struct work_struct *work) } rtnl_lock(); - list_for_each_entry(nn, &pf->ports, port_list) { + list_for_each_entry(nn, &pf->vnics, vnic_list) { if (!nn->eth_port) continue; nn->eth_port = nfp_net_find_port(eth_table, @@ -507,7 +505,7 @@ static void nfp_net_refresh_netdevs(struct work_struct *work) kfree(pf->eth_tbl); pf->eth_tbl = eth_table; - list_for_each_entry_safe(nn, next, &pf->ports, port_list) { + list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) { if (!nn->eth_port) { nfp_warn(pf->cpp, "Warning: port not present after reconfig\n"); continue; @@ -520,15 +518,15 @@ static void nfp_net_refresh_netdevs(struct work_struct *work) nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_clean(nn); - list_del(&nn->port_list); - pf->num_netdevs--; + list_del(&nn->vnic_list); + pf->num_vnics--; nfp_net_free(nn); } - if (list_empty(&pf->ports)) + if (list_empty(&pf->vnics)) nfp_net_pci_remove_finish(pf); out: - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); } void nfp_net_refresh_port_table(struct nfp_net *nn) @@ -576,8 +574,8 @@ int nfp_net_pci_probe(struct nfp_pf *pf) int stride; int err; - INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_netdevs); - mutex_init(&pf->port_lock); + INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_vnics); + mutex_init(&pf->lock); /* Verify that the board has completed initialization */ if (!nfp_is_ready(pf->cpp)) { @@ -585,8 +583,8 @@ int nfp_net_pci_probe(struct nfp_pf *pf) return -EINVAL; } - mutex_lock(&pf->port_lock); - pf->num_ports = nfp_net_pf_get_num_ports(pf); + mutex_lock(&pf->lock); + pf->max_data_vnics = nfp_net_pf_get_num_ports(pf); ctrl_bar = nfp_net_pf_map_ctrl_bar(pf); if (!ctrl_bar) { @@ -661,12 +659,12 @@ int nfp_net_pci_probe(struct nfp_pf *pf) pf->ddir = nfp_net_debugfs_device_add(pf->pdev); - err = nfp_net_pf_spawn_netdevs(pf, ctrl_bar, tx_bar, rx_bar, - stride, &fw_ver); + err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, tx_bar, rx_bar, + stride, &fw_ver); if (err) goto err_clean_ddir; - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); return 0; @@ -676,9 +674,9 @@ err_clean_ddir: err_unmap_tx: nfp_cpp_area_release_free(pf->tx_area); err_ctrl_unmap: - nfp_cpp_area_release_free(pf->ctrl_area); + nfp_cpp_area_release_free(pf->data_vnic_bar); err_unlock: - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); return err; } @@ -686,21 +684,21 @@ void nfp_net_pci_remove(struct nfp_pf *pf) { struct nfp_net *nn; - mutex_lock(&pf->port_lock); - if (list_empty(&pf->ports)) + mutex_lock(&pf->lock); + if (list_empty(&pf->vnics)) goto out; - list_for_each_entry(nn, &pf->ports, port_list) { + list_for_each_entry(nn, &pf->vnics, vnic_list) { nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_clean(nn); } - nfp_net_pf_free_netdevs(pf); + nfp_net_pf_free_vnics(pf); nfp_net_pci_remove_finish(pf); out: - mutex_unlock(&pf->port_lock); + mutex_unlock(&pf->lock); cancel_work_sync(&pf->port_refresh_work); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c index 856a76bdfc24..3f1c7f0f392e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c @@ -267,7 +267,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, nfp_netvf_get_mac_addr(nn); num_irqs = nfp_net_irqs_alloc(pdev, vf->irq_entries, - NFP_NET_MIN_PORT_IRQS, + NFP_NET_MIN_VNIC_IRQS, NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs); if (!num_irqs) { @@ -289,7 +289,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, nfp_net_info(nn); vf->ddir = nfp_net_debugfs_device_add(pdev); - nfp_net_debugfs_port_add(nn, vf->ddir, 0); + nfp_net_debugfs_vnic_add(nn, vf->ddir, 0); return 0; -- cgit v1.2.3 From 9140b30d318520e6d7dfe3b48aa62e6a7336b510 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:25 -0700 Subject: nfp: add nfp_net_pf_free_vnic() function Soon a third place will need to free a struct nfp_net. Add a free counterpart to nfp_net_pf_alloc_vnic(). Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 532371940fd6..5f0c58a56182 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -268,16 +268,20 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) return ctrl_bar; } +static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn) +{ + list_del(&nn->vnic_list); + pf->num_vnics--; + nfp_net_free(nn); +} + static void nfp_net_pf_free_vnics(struct nfp_pf *pf) { struct nfp_net *nn; while (!list_empty(&pf->vnics)) { nn = list_first_entry(&pf->vnics, struct nfp_net, vnic_list); - list_del(&nn->vnic_list); - pf->num_vnics--; - - nfp_net_free(nn); + nfp_net_pf_free_vnic(pf, nn); } } @@ -518,9 +522,7 @@ static void nfp_net_refresh_vnics(struct work_struct *work) nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_clean(nn); - list_del(&nn->vnic_list); - pf->num_vnics--; - nfp_net_free(nn); + nfp_net_pf_free_vnic(pf, nn); } if (list_empty(&pf->vnics)) -- cgit v1.2.3 From 7ac9ebd567252d1799002b9282c658f7229ba21c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:26 -0700 Subject: nfp: introduce very minimal nfp_app Introduce a concept of an application. For now it's just grouping pointers and serving as a layer of indirection. It will help us weaken the dependency on nfp_net in ethtool code. Later series will flesh out support for different apps in the driver. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 1 + drivers/net/ethernet/netronome/nfp/nfp_app.c | 57 ++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_app.h | 56 +++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_main.h | 3 ++ drivers/net/ethernet/netronome/nfp/nfp_net.h | 4 +- .../net/ethernet/netronome/nfp/nfp_net_ethtool.c | 19 ++++---- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 26 ++++++++-- 7 files changed, 152 insertions(+), 14 deletions(-) create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_app.c create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_app.h (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 4b15f0f496aa..a6b9c4dcbe12 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -14,6 +14,7 @@ nfp-objs := \ nfpcore/nfp_resource.o \ nfpcore/nfp_rtsym.o \ nfpcore/nfp_target.o \ + nfp_app.o \ nfp_main.o \ nfp_net_common.o \ nfp_net_ethtool.o \ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c new file mode 100644 index 000000000000..59be638bb60e --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "nfp_app.h" +#include "nfp_main.h" + +struct nfp_app *nfp_app_alloc(struct nfp_pf *pf) +{ + struct nfp_app *app; + + app = kzalloc(sizeof(*app), GFP_KERNEL); + if (!app) + return ERR_PTR(-ENOMEM); + + app->pf = pf; + app->cpp = pf->cpp; + app->pdev = pf->pdev; + + return app; +} + +void nfp_app_free(struct nfp_app *app) +{ + kfree(app); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h new file mode 100644 index 000000000000..e63425c02c8d --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _NFP_APP_H +#define _NFP_APP_H 1 + +struct pci_dev; +struct nfp_cpp; +struct nfp_pf; + +/** + * struct nfp_app - NFP application container + * @pdev: backpointer to PCI device + * @pf: backpointer to NFP PF structure + * @cpp: pointer to the CPP handle + */ +struct nfp_app { + struct pci_dev *pdev; + struct nfp_pf *pf; + struct nfp_cpp *cpp; +}; + +struct nfp_app *nfp_app_alloc(struct nfp_pf *pf); +void nfp_app_free(struct nfp_app *app); + +#endif diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 1ca1c61450c1..3716ef6b8599 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -57,6 +57,7 @@ struct nfp_eth_table; * struct nfp_pf - NFP PF-specific device structure * @pdev: Backpointer to PCI device * @cpp: Pointer to the CPP handle + * @app: Pointer to the APP handle * @data_vnic_bar: Pointer to the CPP area for the data vNICs' BARs * @tx_area: Pointer to the CPP area for the TX queues * @rx_area: Pointer to the CPP area for the FL/RX queues @@ -77,6 +78,8 @@ struct nfp_pf { struct nfp_cpp *cpp; + struct nfp_app *app; + struct nfp_cpp_area *data_vnic_bar; struct nfp_cpp_area *tx_area; struct nfp_cpp_area *rx_area; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 1d41be9b2309..d8edd61a5ad1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -557,7 +557,7 @@ struct nfp_net_dp { * @ethtool_dump_flag: Ethtool dump flag * @vnic_list: Entry on device vNIC list * @pdev: Backpointer to PCI device - * @cpp: CPP device handle if available + * @app: APP handle if available * @eth_port: Translated ETH Table port entry */ struct nfp_net { @@ -628,7 +628,7 @@ struct nfp_net { struct list_head vnic_list; struct pci_dev *pdev; - struct nfp_cpp *cpp; + struct nfp_app *app; struct nfp_eth_table_port *eth_port; }; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 70bb0a0152b9..b9a70659530d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -50,6 +50,7 @@ #include "nfpcore/nfp.h" #include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" @@ -134,14 +135,14 @@ static const struct _nfp_net_et_stats nfp_net_et_stats[] = { #define NN_ET_STATS_LEN (NN_ET_GLOBAL_STATS_LEN + NN_ET_RVEC_GATHER_STATS + \ NN_ET_RVEC_STATS_LEN + NN_ET_QUEUE_STATS_LEN) -static void nfp_net_get_nspinfo(struct nfp_net *nn, char *version) +static void nfp_net_get_nspinfo(struct nfp_app *app, char *version) { struct nfp_nsp *nsp; - if (!nn->cpp) + if (!app) return; - nsp = nfp_nsp_open(nn->cpp); + nsp = nfp_nsp_open(app->cpp); if (IS_ERR(nsp)) return; @@ -162,7 +163,7 @@ static void nfp_net_get_drvinfo(struct net_device *netdev, sizeof(drvinfo->driver)); strlcpy(drvinfo->version, nfp_driver_version, sizeof(drvinfo->version)); - nfp_net_get_nspinfo(nn, nsp_version); + nfp_net_get_nspinfo(nn->app, nsp_version); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%d.%d %s", nn->fw_ver.resv, nn->fw_ver.class, @@ -258,7 +259,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev, return -EBUSY; } - nsp = nfp_eth_config_start(nn->cpp, nn->eth_port->index); + nsp = nfp_eth_config_start(nn->app->cpp, nn->eth_port->index); if (IS_ERR(nsp)) return PTR_ERR(nsp); @@ -706,13 +707,13 @@ nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer) struct nfp_resource *res; int ret; - if (!nn->cpp) + if (!nn->app) return -EOPNOTSUPP; dump->version = 1; dump->flag = NFP_DUMP_NSP_DIAG; - res = nfp_resource_acquire(nn->cpp, NFP_RESOURCE_NSP_DIAG); + res = nfp_resource_acquire(nn->app->cpp, NFP_RESOURCE_NSP_DIAG); if (IS_ERR(res)) return PTR_ERR(res); @@ -722,7 +723,7 @@ nfp_dump_nsp_diag(struct nfp_net *nn, struct ethtool_dump *dump, void *buffer) goto exit_release; } - ret = nfp_cpp_read(nn->cpp, nfp_resource_cpp_id(res), + ret = nfp_cpp_read(nn->app->cpp, nfp_resource_cpp_id(res), nfp_resource_address(res), buffer, dump->len); if (ret != dump->len) @@ -743,7 +744,7 @@ static int nfp_net_set_dump(struct net_device *netdev, struct ethtool_dump *val) { struct nfp_net *nn = netdev_priv(netdev); - if (!nn->cpp) + if (!nn->app) return -EOPNOTSUPP; if (val->flag != NFP_DUMP_NSP_DIAG) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 5f0c58a56182..1281e9019e92 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -54,7 +54,7 @@ #include "nfpcore/nfp_nffw.h" #include "nfpcore/nfp_nsp.h" #include "nfpcore/nfp6000_pcie.h" - +#include "nfp_app.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" #include "nfp_main.h" @@ -302,7 +302,7 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, if (IS_ERR(nn)) return nn; - nn->cpp = pf->cpp; + nn->app = pf->app; nn->fw_ver = *fw_ver; nn->dp.ctrl_bar = ctrl_bar; nn->tx_bar = tx_bar; @@ -463,6 +463,18 @@ err_nn_free: return err; } +static int nfp_net_pf_app_init(struct nfp_pf *pf) +{ + pf->app = nfp_app_alloc(pf); + + return PTR_ERR_OR_ZERO(pf->app); +} + +static void nfp_net_pf_app_clean(struct nfp_pf *pf) +{ + nfp_app_free(pf->app); +} + static void nfp_net_pci_remove_finish(struct nfp_pf *pf) { nfp_net_debugfs_dir_clean(&pf->ddir); @@ -470,6 +482,8 @@ static void nfp_net_pci_remove_finish(struct nfp_pf *pf) nfp_net_irqs_disable(pf->pdev); kfree(pf->irq_entries); + nfp_net_pf_app_clean(pf); + nfp_cpp_area_release_free(pf->rx_area); nfp_cpp_area_release_free(pf->tx_area); nfp_cpp_area_release_free(pf->data_vnic_bar); @@ -543,7 +557,7 @@ int nfp_net_refresh_eth_port(struct nfp_net *nn) struct nfp_eth_table_port *eth_port; struct nfp_eth_table *eth_table; - eth_table = nfp_eth_read_ports(nn->cpp); + eth_table = nfp_eth_read_ports(nn->app->cpp); if (!eth_table) { nn_err(nn, "Error refreshing port state table!\n"); return -EIO; @@ -659,6 +673,10 @@ int nfp_net_pci_probe(struct nfp_pf *pf) goto err_unmap_tx; } + err = nfp_net_pf_app_init(pf); + if (err) + goto err_unmap_rx; + pf->ddir = nfp_net_debugfs_device_add(pf->pdev); err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, tx_bar, rx_bar, @@ -672,6 +690,8 @@ int nfp_net_pci_probe(struct nfp_pf *pf) err_clean_ddir: nfp_net_debugfs_dir_clean(&pf->ddir); + nfp_net_pf_app_clean(pf); +err_unmap_rx: nfp_cpp_area_release_free(pf->rx_area); err_unmap_tx: nfp_cpp_area_release_free(pf->tx_area); -- cgit v1.2.3 From d88b0a233fafa4abda3b3aa5a69d46574e4c793e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:27 -0700 Subject: nfp: disallow mixing vNICs with and without NSP port entry We only support core NIC apps which have vNICs for each physical port/ split and no representors right now. Enforce that either each vNIC has a NSP eth_table entry or if NSP port table is not available none do. One scenario this will prevent from happening is user force-loading wrong firmware file if FW app requires different firmwares per media config. While at it move some code to nfp_net_pf_alloc_vnic() to make it counter-match nfp_net_pf_free_vnic() better. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 52 ++++++++++++++--------- 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 1281e9019e92..8f267b1534e2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -289,7 +289,7 @@ static struct nfp_net * nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, void __iomem *tx_bar, void __iomem *rx_bar, int stride, struct nfp_net_fw_version *fw_ver, - struct nfp_eth_table_port *eth_port) + unsigned int eth_id) { u32 n_tx_rings, n_rx_rings; struct nfp_net *nn; @@ -310,7 +310,10 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, nn->dp.is_vf = 0; nn->stride_rx = stride; nn->stride_tx = stride; - nn->eth_port = eth_port; + nn->eth_port = nfp_net_find_port(pf->eth_tbl, eth_id); + + pf->num_vnics++; + list_add_tail(&nn->vnic_list, &pf->vnics); return nn; } @@ -346,11 +349,16 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, int stride, struct nfp_net_fw_version *fw_ver) { u32 prev_tx_base, prev_rx_base, tgt_tx_base, tgt_rx_base; - struct nfp_eth_table_port *eth_port; struct nfp_net *nn; unsigned int i; int err; + if (pf->eth_tbl && pf->max_data_vnics != pf->eth_tbl->count) { + nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n", + pf->max_data_vnics, pf->eth_tbl->count); + return -EINVAL; + } + prev_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); prev_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); @@ -362,21 +370,26 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, prev_tx_base = tgt_tx_base; prev_rx_base = tgt_rx_base; - eth_port = nfp_net_find_port(pf->eth_tbl, i); - if (eth_port && eth_port->override_changed) { - nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i); - } else { - nn = nfp_net_pf_alloc_vnic(pf, ctrl_bar, tx_bar, rx_bar, - stride, fw_ver, eth_port); - if (IS_ERR(nn)) { - err = PTR_ERR(nn); - goto err_free_prev; - } - list_add_tail(&nn->vnic_list, &pf->vnics); - pf->num_vnics++; + nn = nfp_net_pf_alloc_vnic(pf, ctrl_bar, tx_bar, rx_bar, + stride, fw_ver, i); + if (IS_ERR(nn)) { + err = PTR_ERR(nn); + goto err_free_prev; } ctrl_bar += NFP_PF_CSR_SLICE_SIZE; + + /* Check if vNIC has external port associated and cfg is OK */ + if (pf->eth_tbl && !nn->eth_port) { + nfp_err(pf->cpp, "NSP port entries don't match vNICs (no entry for port #%d)\n", i); + err = -EINVAL; + goto err_free_prev; + } + if (nn->eth_port && nn->eth_port->override_changed) { + nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i); + nfp_net_pf_free_vnic(pf, nn); + continue; + } } if (list_empty(&pf->vnics)) @@ -517,6 +530,9 @@ static void nfp_net_refresh_vnics(struct work_struct *work) continue; nn->eth_port = nfp_net_find_port(eth_table, nn->eth_port->eth_index); + if (!nn->eth_port) + nfp_err(pf->cpp, + "Warning: port disappeared after reconfig\n"); } rtnl_unlock(); @@ -524,11 +540,7 @@ static void nfp_net_refresh_vnics(struct work_struct *work) pf->eth_tbl = eth_table; list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) { - if (!nn->eth_port) { - nfp_warn(pf->cpp, "Warning: port not present after reconfig\n"); - continue; - } - if (!nn->eth_port->override_changed) + if (nn->eth_port && !nn->eth_port->override_changed) continue; nn_warn(nn, "Port config changed, unregistering. Reboot required before port will be operational again.\n"); -- cgit v1.2.3 From eb488c26d713b2a9ebba6c12bbefd04e01197693 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:28 -0700 Subject: nfp: introduce nfp_port Encapsulate port information into struct nfp_port. nfp_port will soon be extended to contain devlink_port information. It also makes it easier to reuse port-related code between vNICs and representors. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 3 +- drivers/net/ethernet/netronome/nfp/nfp_net.h | 14 ++- .../net/ethernet/netronome/nfp/nfp_net_common.c | 25 +---- .../net/ethernet/netronome/nfp/nfp_net_ethtool.c | 39 +++++--- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 68 +++++++++----- drivers/net/ethernet/netronome/nfp/nfp_port.c | 104 +++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_port.h | 85 +++++++++++++++++ 7 files changed, 275 insertions(+), 63 deletions(-) create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_port.c create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_port.h (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index a6b9c4dcbe12..e8333283ada6 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -20,7 +20,8 @@ nfp-objs := \ nfp_net_ethtool.o \ nfp_net_offload.o \ nfp_net_main.o \ - nfp_netvf_main.o + nfp_netvf_main.o \ + nfp_port.o ifeq ($(CONFIG_BPF_SYSCALL),y) nfp-objs += \ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index d8edd61a5ad1..8132dd31a6dd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -116,6 +116,7 @@ struct nfp_cpp; struct nfp_eth_table_port; struct nfp_net; struct nfp_net_r_vector; +struct nfp_port; /* Convenience macro for wrapping descriptor index on ring size */ #define D_IDX(ring, idx) ((idx) & ((ring)->cnt - 1)) @@ -558,7 +559,7 @@ struct nfp_net_dp { * @vnic_list: Entry on device vNIC list * @pdev: Backpointer to PCI device * @app: APP handle if available - * @eth_port: Translated ETH Table port entry + * @port: Pointer to nfp_port structure if vNIC is a port */ struct nfp_net { struct nfp_net_dp dp; @@ -630,7 +631,7 @@ struct nfp_net { struct pci_dev *pdev; struct nfp_app *app; - struct nfp_eth_table_port *eth_port; + struct nfp_port *port; }; /* Functions to read/write from/to a BAR @@ -802,6 +803,13 @@ static inline u32 nfp_qcp_wr_ptr_read(u8 __iomem *q) /* Globals */ extern const char nfp_driver_version[]; +extern const struct net_device_ops nfp_net_netdev_ops; + +static inline bool nfp_netdev_is_nfp_net(struct net_device *netdev) +{ + return netdev->netdev_ops == &nfp_net_netdev_ops; +} + /* Prototypes */ void nfp_net_get_fw_version(struct nfp_net_fw_version *fw_ver, void __iomem *ctrl_bar); @@ -835,8 +843,6 @@ int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new, struct netlink_ext_ack *extack); bool nfp_net_link_changed_read_clear(struct nfp_net *nn); -int nfp_net_refresh_eth_port(struct nfp_net *nn); -void nfp_net_refresh_port_table(struct nfp_net *nn); #ifdef CONFIG_NFP_DEBUG void nfp_net_debugfs_create(void); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index b427c95c5acd..15ef45a05c1e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -70,6 +70,7 @@ #include "nfpcore/nfp_nsp.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" +#include "nfp_port.h" /** * nfp_net_get_fw_version() - Read and parse the FW version @@ -2846,26 +2847,6 @@ nfp_net_features_check(struct sk_buff *skb, struct net_device *dev, return features; } -static int -nfp_net_get_phys_port_name(struct net_device *netdev, char *name, size_t len) -{ - struct nfp_net *nn = netdev_priv(netdev); - int err; - - if (!nn->eth_port) - return -EOPNOTSUPP; - - if (!nn->eth_port->is_split) - err = snprintf(name, len, "p%d", nn->eth_port->label_port); - else - err = snprintf(name, len, "p%ds%d", nn->eth_port->label_port, - nn->eth_port->label_subport); - if (err >= len) - return -EINVAL; - - return 0; -} - /** * nfp_net_set_vxlan_port() - set vxlan port in SW and reconfigure HW * @nn: NFP Net device to reconfigure @@ -3028,7 +3009,7 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) } } -static const struct net_device_ops nfp_net_netdev_ops = { +const struct net_device_ops nfp_net_netdev_ops = { .ndo_open = nfp_net_netdev_open, .ndo_stop = nfp_net_netdev_close, .ndo_start_xmit = nfp_net_tx, @@ -3040,7 +3021,7 @@ static const struct net_device_ops nfp_net_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, .ndo_set_features = nfp_net_set_features, .ndo_features_check = nfp_net_features_check, - .ndo_get_phys_port_name = nfp_net_get_phys_port_name, + .ndo_get_phys_port_name = nfp_port_get_phys_port_name, .ndo_udp_tunnel_add = nfp_net_add_vxlan_port, .ndo_udp_tunnel_del = nfp_net_del_vxlan_port, .ndo_xdp = nfp_net_xdp, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index b9a70659530d..334020347ff2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -53,6 +53,7 @@ #include "nfp_app.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" +#include "nfp_port.h" enum nfp_dump_diag { NFP_DUMP_NSP_DIAG = 0, @@ -196,33 +197,42 @@ nfp_net_get_link_ksettings(struct net_device *netdev, [NFP_NET_CFG_STS_LINK_RATE_50G] = SPEED_50000, [NFP_NET_CFG_STS_LINK_RATE_100G] = SPEED_100000, }; - struct nfp_net *nn = netdev_priv(netdev); + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + struct nfp_net *nn; u32 sts, ls; + /* Init to unknowns */ ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); cmd->base.port = PORT_OTHER; cmd->base.speed = SPEED_UNKNOWN; cmd->base.duplex = DUPLEX_UNKNOWN; - if (nn->eth_port) - cmd->base.autoneg = nn->eth_port->aneg != NFP_ANEG_DISABLED ? + port = nfp_port_from_netdev(netdev); + eth_port = __nfp_port_get_eth_port(port); + if (eth_port) + cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ? AUTONEG_ENABLE : AUTONEG_DISABLE; if (!netif_carrier_ok(netdev)) return 0; + if (!nfp_netdev_is_nfp_net(netdev)) + return -EOPNOTSUPP; + nn = netdev_priv(netdev); + /* Use link speed from ETH table if available, otherwise try the BAR */ - if (nn->eth_port) { + if (eth_port) { int err; if (nfp_net_link_changed_read_clear(nn)) { - err = nfp_net_refresh_eth_port(nn); + err = nfp_net_refresh_eth_port(port); if (err) return err; } - cmd->base.port = nn->eth_port->port_type; - cmd->base.speed = nn->eth_port->speed; + cmd->base.port = eth_port->port_type; + cmd->base.speed = eth_port->speed; cmd->base.duplex = DUPLEX_FULL; return 0; } @@ -247,19 +257,22 @@ static int nfp_net_set_link_ksettings(struct net_device *netdev, const struct ethtool_link_ksettings *cmd) { - struct nfp_net *nn = netdev_priv(netdev); + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; struct nfp_nsp *nsp; int err; - if (!nn->eth_port) + port = nfp_port_from_netdev(netdev); + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) return -EOPNOTSUPP; if (netif_running(netdev)) { - nn_warn(nn, "Changing settings not allowed on an active interface. It may cause the port to be disabled until reboot.\n"); + netdev_warn(netdev, "Changing settings not allowed on an active interface. It may cause the port to be disabled until reboot.\n"); return -EBUSY; } - nsp = nfp_eth_config_start(nn->app->cpp, nn->eth_port->index); + nsp = nfp_eth_config_start(port->app->cpp, eth_port->index); if (IS_ERR(nsp)) return PTR_ERR(nsp); @@ -268,7 +281,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev, if (err) goto err_bad_set; if (cmd->base.speed != SPEED_UNKNOWN) { - u32 speed = cmd->base.speed / nn->eth_port->lanes; + u32 speed = cmd->base.speed / eth_port->lanes; err = __nfp_eth_set_speed(nsp, speed); if (err) @@ -279,7 +292,7 @@ nfp_net_set_link_ksettings(struct net_device *netdev, if (err > 0) return 0; /* no change */ - nfp_net_refresh_port_table(nn); + nfp_net_refresh_port_table(port); return err; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 8f267b1534e2..8e1e55187262 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -58,6 +58,7 @@ #include "nfp_net_ctrl.h" #include "nfp_net.h" #include "nfp_main.h" +#include "nfp_port.h" #define NFP_PF_CSR_SLICE_SIZE (32 * 1024) @@ -142,14 +143,16 @@ err_area: static void nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id) { + struct nfp_eth_table_port *eth_port; struct nfp_net_dp *dp = &nn->dp; u8 mac_addr[ETH_ALEN]; const char *mac_str; char name[32]; - if (nn->eth_port) { - ether_addr_copy(dp->netdev->dev_addr, nn->eth_port->mac_addr); - ether_addr_copy(dp->netdev->perm_addr, nn->eth_port->mac_addr); + eth_port = __nfp_port_get_eth_port(nn->port); + if (eth_port) { + ether_addr_copy(dp->netdev->dev_addr, eth_port->mac_addr); + ether_addr_copy(dp->netdev->perm_addr, eth_port->mac_addr); return; } @@ -270,6 +273,7 @@ static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn) { + nfp_port_free(nn->port); list_del(&nn->vnic_list); pf->num_vnics--; nfp_net_free(nn); @@ -291,6 +295,7 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, int stride, struct nfp_net_fw_version *fw_ver, unsigned int eth_id) { + struct nfp_eth_table_port *eth_port; u32 n_tx_rings, n_rx_rings; struct nfp_net *nn; @@ -310,7 +315,18 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, nn->dp.is_vf = 0; nn->stride_rx = stride; nn->stride_tx = stride; - nn->eth_port = nfp_net_find_port(pf->eth_tbl, eth_id); + + eth_port = nfp_net_find_port(pf->eth_tbl, eth_id); + if (eth_port) { + nn->port = nfp_port_alloc(pf->app, NFP_PORT_PHYS_PORT, + nn->dp.netdev); + if (IS_ERR(nn->port)) { + nfp_net_free(nn); + return ERR_CAST(nn->port); + } + nn->port->eth_id = eth_id; + nn->port->eth_port = eth_port; + } pf->num_vnics++; list_add_tail(&nn->vnic_list, &pf->vnics); @@ -380,12 +396,12 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, ctrl_bar += NFP_PF_CSR_SLICE_SIZE; /* Check if vNIC has external port associated and cfg is OK */ - if (pf->eth_tbl && !nn->eth_port) { + if (pf->eth_tbl && !nn->port) { nfp_err(pf->cpp, "NSP port entries don't match vNICs (no entry for port #%d)\n", i); err = -EINVAL; goto err_free_prev; } - if (nn->eth_port && nn->eth_port->override_changed) { + if (nn->port && nn->port->eth_port->override_changed) { nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i); nfp_net_pf_free_vnic(pf, nn); continue; @@ -526,13 +542,20 @@ static void nfp_net_refresh_vnics(struct work_struct *work) rtnl_lock(); list_for_each_entry(nn, &pf->vnics, vnic_list) { - if (!nn->eth_port) + if (!__nfp_port_get_eth_port(nn->port)) continue; - nn->eth_port = nfp_net_find_port(eth_table, - nn->eth_port->eth_index); - if (!nn->eth_port) - nfp_err(pf->cpp, - "Warning: port disappeared after reconfig\n"); + nn->port->eth_port = nfp_net_find_port(eth_table, + nn->port->eth_id); + if (!nn->port->eth_port) { + nfp_warn(pf->cpp, "Warning: port #%d not present after reconfig\n", + nn->port->eth_id); + continue; + } + if (nn->port->eth_port->override_changed) { + nfp_warn(pf->cpp, "Port config changed, unregistering. Reboot required before port will be operational again.\n"); + nn->port->type = NFP_PORT_INVALID; + continue; + } } rtnl_unlock(); @@ -540,11 +563,9 @@ static void nfp_net_refresh_vnics(struct work_struct *work) pf->eth_tbl = eth_table; list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) { - if (nn->eth_port && !nn->eth_port->override_changed) + if (!nn->port || nn->port->type != NFP_PORT_INVALID) continue; - nn_warn(nn, "Port config changed, unregistering. Reboot required before port will be operational again.\n"); - nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_clean(nn); @@ -557,32 +578,33 @@ out: mutex_unlock(&pf->lock); } -void nfp_net_refresh_port_table(struct nfp_net *nn) +void nfp_net_refresh_port_table(struct nfp_port *port) { - struct nfp_pf *pf = pci_get_drvdata(nn->pdev); + struct nfp_pf *pf = port->app->pf; schedule_work(&pf->port_refresh_work); } -int nfp_net_refresh_eth_port(struct nfp_net *nn) +int nfp_net_refresh_eth_port(struct nfp_port *port) { + struct nfp_cpp *cpp = port->app->cpp; struct nfp_eth_table_port *eth_port; struct nfp_eth_table *eth_table; - eth_table = nfp_eth_read_ports(nn->app->cpp); + eth_table = nfp_eth_read_ports(cpp); if (!eth_table) { - nn_err(nn, "Error refreshing port state table!\n"); + nfp_err(cpp, "Error refreshing port state table!\n"); return -EIO; } - eth_port = nfp_net_find_port(eth_table, nn->eth_port->eth_index); + eth_port = nfp_net_find_port(eth_table, port->eth_id); if (!eth_port) { - nn_err(nn, "Error finding state of the port!\n"); + nfp_err(cpp, "Error finding state of the port!\n"); kfree(eth_table); return -EIO; } - memcpy(nn->eth_port, eth_port, sizeof(*eth_port)); + memcpy(port->eth_port, eth_port, sizeof(*eth_port)); kfree(eth_table); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c new file mode 100644 index 000000000000..95726e01592d --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" +#include "nfp_main.h" +#include "nfp_net.h" +#include "nfp_port.h" + +struct nfp_port *nfp_port_from_netdev(struct net_device *netdev) +{ + struct nfp_net *nn; + + if (WARN_ON(!nfp_netdev_is_nfp_net(netdev))) + return NULL; + nn = netdev_priv(netdev); + + return nn->port; +} + +struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port) +{ + if (!port) + return NULL; + if (port->type != NFP_PORT_PHYS_PORT) + return NULL; + + return port->eth_port; +} + +int +nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len) +{ + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + int n; + + port = nfp_port_from_netdev(netdev); + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) + return -EOPNOTSUPP; + + if (!eth_port->is_split) + n = snprintf(name, len, "p%d", eth_port->label_port); + else + n = snprintf(name, len, "p%ds%d", eth_port->label_port, + eth_port->label_subport); + if (n >= len) + return -EINVAL; + + return 0; +} + +struct nfp_port * +nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, + struct net_device *netdev) +{ + struct nfp_port *port; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return ERR_PTR(-ENOMEM); + + port->netdev = netdev; + port->type = type; + port->app = app; + + return port; +} + +void nfp_port_free(struct nfp_port *port) +{ + kfree(port); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h new file mode 100644 index 000000000000..341e7e128233 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _NFP_PORT_H_ +#define _NFP_PORT_H_ + +struct net_device; +struct nfp_app; +struct nfp_port; + +/** + * enum nfp_port_type - type of port NFP can switch traffic to + * @NFP_PORT_INVALID: port is invalid, %NFP_PORT_PHYS_PORT transitions to this + * state when port disappears because of FW fault or config + * change + * @NFP_PORT_PHYS_PORT: external NIC port + */ +enum nfp_port_type { + NFP_PORT_INVALID, + NFP_PORT_PHYS_PORT, +}; + +/** + * struct nfp_port - structure representing NFP port + * @netdev: backpointer to associated netdev + * @type: what port type does the entity represent + * @app: backpointer to the app structure + * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme + * @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry + */ +struct nfp_port { + struct net_device *netdev; + enum nfp_port_type type; + + struct nfp_app *app; + + unsigned int eth_id; + struct nfp_eth_table_port *eth_port; +}; + +struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); +struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port); + +int +nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len); + +struct nfp_port * +nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, + struct net_device *netdev); +void nfp_port_free(struct nfp_port *port); + +int nfp_net_refresh_eth_port(struct nfp_port *port); +void nfp_net_refresh_port_table(struct nfp_port *port); + +#endif -- cgit v1.2.3 From 3d4ed1e70185936ea7cfeec18dd25963c2908871 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:29 -0700 Subject: nfp: update port state in place Always updating port state in place by overriding values in exiting pf->eth_tbl makes things easier to manage and allows us to have a common helper for both full and per-port refresh. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 54 +++++++++++++---------- 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 8e1e55187262..92037e3624ad 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -518,6 +518,30 @@ static void nfp_net_pci_remove_finish(struct nfp_pf *pf) nfp_cpp_area_release_free(pf->data_vnic_bar); } +static int +nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port, + struct nfp_eth_table *eth_table) +{ + struct nfp_eth_table_port *eth_port; + + ASSERT_RTNL(); + + eth_port = nfp_net_find_port(eth_table, port->eth_id); + if (!eth_port) { + nfp_warn(cpp, "Warning: port #%d not present after reconfig\n", + port->eth_id); + return -EIO; + } + if (eth_port->override_changed) { + nfp_warn(cpp, "Port #%d config changed, unregistering. Reboot required before port will be operational again.\n", port->eth_id); + port->type = NFP_PORT_INVALID; + } + + memcpy(port->eth_port, eth_port, sizeof(*eth_port)); + + return 0; +} + static void nfp_net_refresh_vnics(struct work_struct *work) { struct nfp_pf *pf = container_of(work, struct nfp_pf, @@ -544,23 +568,12 @@ static void nfp_net_refresh_vnics(struct work_struct *work) list_for_each_entry(nn, &pf->vnics, vnic_list) { if (!__nfp_port_get_eth_port(nn->port)) continue; - nn->port->eth_port = nfp_net_find_port(eth_table, - nn->port->eth_id); - if (!nn->port->eth_port) { - nfp_warn(pf->cpp, "Warning: port #%d not present after reconfig\n", - nn->port->eth_id); - continue; - } - if (nn->port->eth_port->override_changed) { - nfp_warn(pf->cpp, "Port config changed, unregistering. Reboot required before port will be operational again.\n"); - nn->port->type = NFP_PORT_INVALID; - continue; - } + + nfp_net_eth_port_update(pf->cpp, nn->port, eth_table); } rtnl_unlock(); - kfree(pf->eth_tbl); - pf->eth_tbl = eth_table; + kfree(eth_table); list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) { if (!nn->port || nn->port->type != NFP_PORT_INVALID) @@ -588,8 +601,8 @@ void nfp_net_refresh_port_table(struct nfp_port *port) int nfp_net_refresh_eth_port(struct nfp_port *port) { struct nfp_cpp *cpp = port->app->cpp; - struct nfp_eth_table_port *eth_port; struct nfp_eth_table *eth_table; + int ret; eth_table = nfp_eth_read_ports(cpp); if (!eth_table) { @@ -597,18 +610,11 @@ int nfp_net_refresh_eth_port(struct nfp_port *port) return -EIO; } - eth_port = nfp_net_find_port(eth_table, port->eth_id); - if (!eth_port) { - nfp_err(cpp, "Error finding state of the port!\n"); - kfree(eth_table); - return -EIO; - } - - memcpy(port->eth_port, eth_port, sizeof(*eth_port)); + ret = nfp_net_eth_port_update(cpp, port, eth_table); kfree(eth_table); - return 0; + return ret; } /* -- cgit v1.2.3 From 6d4f8cba5fbbc83e74ee8a49e5234e446306bac6 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:30 -0700 Subject: nfp: move refresh tracking into the port structure Track whether physical port's state have changed since last refresh inside the nfp_port structure instead of the vNIC structure. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 4 ---- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 16 ++-------------- drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 10 +++++----- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 10 ++++++++-- drivers/net/ethernet/netronome/nfp/nfp_port.h | 13 +++++++++++++ 5 files changed, 28 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 8132dd31a6dd..7882d2604835 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -543,7 +543,6 @@ struct nfp_net_dp { * @reconfig_sync_present: Some thread is performing synchronous reconfig * @reconfig_timer: Timer for async reading of reconfig results * @link_up: Is the link up? - * @link_changed: Has link state changes since last port refresh? * @link_status_lock: Protects @link_* and ensures atomicity with BAR reading * @rx_coalesce_usecs: RX interrupt moderation usecs delay parameter * @rx_coalesce_max_frames: RX interrupt moderation frame count parameter @@ -601,7 +600,6 @@ struct nfp_net { u32 me_freq_mhz; bool link_up; - bool link_changed; spinlock_t link_status_lock; spinlock_t reconfig_lock; @@ -842,8 +840,6 @@ struct nfp_net_dp *nfp_net_clone_dp(struct nfp_net *nn); int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new, struct netlink_ext_ack *extack); -bool nfp_net_link_changed_read_clear(struct nfp_net *nn); - #ifdef CONFIG_NFP_DEBUG void nfp_net_debugfs_create(void); void nfp_net_debugfs_destroy(void); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 15ef45a05c1e..b3f5c8af6789 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -392,19 +392,6 @@ static irqreturn_t nfp_net_irq_rxtx(int irq, void *data) return IRQ_HANDLED; } -bool nfp_net_link_changed_read_clear(struct nfp_net *nn) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&nn->link_status_lock, flags); - ret = nn->link_changed; - nn->link_changed = false; - spin_unlock_irqrestore(&nn->link_status_lock, flags); - - return ret; -} - /** * nfp_net_read_link_status() - Reread link status from control BAR * @nn: NFP Network structure @@ -424,7 +411,8 @@ static void nfp_net_read_link_status(struct nfp_net *nn) goto out; nn->link_up = link_up; - nn->link_changed = true; + if (nn->port) + set_bit(NFP_PORT_CHANGED, &nn->port->flags); if (nn->link_up) { netif_carrier_on(nn->dp.netdev); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 334020347ff2..23f9ea0f8982 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -217,15 +217,11 @@ nfp_net_get_link_ksettings(struct net_device *netdev, if (!netif_carrier_ok(netdev)) return 0; - if (!nfp_netdev_is_nfp_net(netdev)) - return -EOPNOTSUPP; - nn = netdev_priv(netdev); - /* Use link speed from ETH table if available, otherwise try the BAR */ if (eth_port) { int err; - if (nfp_net_link_changed_read_clear(nn)) { + if (test_bit(NFP_PORT_CHANGED, &port->flags)) { err = nfp_net_refresh_eth_port(port); if (err) return err; @@ -237,6 +233,10 @@ nfp_net_get_link_ksettings(struct net_device *netdev, return 0; } + if (!nfp_netdev_is_nfp_net(netdev)) + return -EOPNOTSUPP; + nn = netdev_priv(netdev); + sts = nn_readl(nn, NFP_NET_CFG_STS); ls = FIELD_GET(NFP_NET_CFG_STS_LINK_RATE, sts); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 92037e3624ad..e8d54b9b9b97 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -555,16 +555,19 @@ static void nfp_net_refresh_vnics(struct work_struct *work) if (list_empty(&pf->vnics)) goto out; + /* Update state of all ports */ + rtnl_lock(); list_for_each_entry(nn, &pf->vnics, vnic_list) - nfp_net_link_changed_read_clear(nn); + if (nn->port) + clear_bit(NFP_PORT_CHANGED, &nn->port->flags); eth_table = nfp_eth_read_ports(pf->cpp); if (!eth_table) { + rtnl_unlock(); nfp_err(pf->cpp, "Error refreshing port config!\n"); goto out; } - rtnl_lock(); list_for_each_entry(nn, &pf->vnics, vnic_list) { if (!__nfp_port_get_eth_port(nn->port)) continue; @@ -575,6 +578,7 @@ static void nfp_net_refresh_vnics(struct work_struct *work) kfree(eth_table); + /* Shoot off the ports which became invalid */ list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) { if (!nn->port || nn->port->type != NFP_PORT_INVALID) continue; @@ -604,6 +608,8 @@ int nfp_net_refresh_eth_port(struct nfp_port *port) struct nfp_eth_table *eth_table; int ret; + clear_bit(NFP_PORT_CHANGED, &port->flags); + eth_table = nfp_eth_read_ports(cpp); if (!eth_table) { nfp_err(cpp, "Error refreshing port state table!\n"); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 341e7e128233..47adacf88557 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -50,10 +50,21 @@ enum nfp_port_type { NFP_PORT_PHYS_PORT, }; +/** + * enum nfp_port_flags - port flags (can be type-specific) + * @NFP_PORT_CHANGED: port state has changed since last eth table refresh; + * for NFP_PORT_PHYS_PORT, never set otherwise; must hold + * rtnl_lock to clear + */ +enum nfp_port_flags { + NFP_PORT_CHANGED = 0, +}; + /** * struct nfp_port - structure representing NFP port * @netdev: backpointer to associated netdev * @type: what port type does the entity represent + * @flags: port flags * @app: backpointer to the app structure * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme * @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry @@ -62,6 +73,8 @@ struct nfp_port { struct net_device *netdev; enum nfp_port_type type; + unsigned long flags; + struct nfp_app *app; unsigned int eth_id; -- cgit v1.2.3 From 3eb3b74adb701d575d718df1bbffefa2543a302d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:31 -0700 Subject: nfp: provide linking on port structures Add link to nfp_ports to make it possible to iterate over all ports. This will come in handy when some ports may be representors. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 1 + drivers/net/ethernet/netronome/nfp/nfp_main.h | 2 ++ drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 15 ++++++--------- drivers/net/ethernet/netronome/nfp/nfp_port.c | 5 +++++ drivers/net/ethernet/netronome/nfp/nfp_port.h | 3 +++ 5 files changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 9fbc7eedc017..bb586ce1ea06 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -341,6 +341,7 @@ static int nfp_pci_probe(struct pci_dev *pdev, goto err_rel_regions; } INIT_LIST_HEAD(&pf->vnics); + INIT_LIST_HEAD(&pf->ports); pci_set_drvdata(pdev, pf); pf->pdev = pdev; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 3716ef6b8599..991c4cba0bbf 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -70,6 +70,7 @@ struct nfp_eth_table; * @max_data_vnics: Number of data vNICs app firmware supports * @num_vnics: Number of vNICs spawned * @vnics: Linked list of vNIC structures (struct nfp_net) + * @ports: Linked list of port structures (struct nfp_port) * @port_refresh_work: Work entry for taking netdevs out * @lock: Protects all fields which may change after probe */ @@ -99,6 +100,7 @@ struct nfp_pf { unsigned int num_vnics; struct list_head vnics; + struct list_head ports; struct work_struct port_refresh_work; struct mutex lock; }; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index e8d54b9b9b97..40ba5775ff79 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -548,6 +548,7 @@ static void nfp_net_refresh_vnics(struct work_struct *work) port_refresh_work); struct nfp_eth_table *eth_table; struct nfp_net *nn, *next; + struct nfp_port *port; mutex_lock(&pf->lock); @@ -557,9 +558,8 @@ static void nfp_net_refresh_vnics(struct work_struct *work) /* Update state of all ports */ rtnl_lock(); - list_for_each_entry(nn, &pf->vnics, vnic_list) - if (nn->port) - clear_bit(NFP_PORT_CHANGED, &nn->port->flags); + list_for_each_entry(port, &pf->ports, port_list) + clear_bit(NFP_PORT_CHANGED, &port->flags); eth_table = nfp_eth_read_ports(pf->cpp); if (!eth_table) { @@ -568,12 +568,9 @@ static void nfp_net_refresh_vnics(struct work_struct *work) goto out; } - list_for_each_entry(nn, &pf->vnics, vnic_list) { - if (!__nfp_port_get_eth_port(nn->port)) - continue; - - nfp_net_eth_port_update(pf->cpp, nn->port, eth_table); - } + list_for_each_entry(port, &pf->ports, port_list) + if (__nfp_port_get_eth_port(port)) + nfp_net_eth_port_update(pf->cpp, port, eth_table); rtnl_unlock(); kfree(eth_table); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 95726e01592d..295db04ccb05 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -95,10 +95,15 @@ nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, port->type = type; port->app = app; + list_add_tail(&port->port_list, &app->pf->ports); + return port; } void nfp_port_free(struct nfp_port *port) { + if (!port) + return; + list_del(&port->port_list); kfree(port); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 47adacf88557..471fff1fc58f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -68,6 +68,7 @@ enum nfp_port_flags { * @app: backpointer to the app structure * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme * @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry + * @port_list: entry on pf's list of ports */ struct nfp_port { struct net_device *netdev; @@ -79,6 +80,8 @@ struct nfp_port { unsigned int eth_id; struct nfp_eth_table_port *eth_port; + + struct list_head port_list; }; struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); -- cgit v1.2.3 From 1f60a5815bade268696d57452dfbfcbf0c655a23 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:32 -0700 Subject: nfp: mark port state as stale after reconfig After port configuration is performed mark it as changed. This will close a window of time between configuration and async state refresh which runs from a workqueue where old port state would be reported. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 40ba5775ff79..12cbf21df3b9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -596,6 +596,8 @@ void nfp_net_refresh_port_table(struct nfp_port *port) { struct nfp_pf *pf = port->app->pf; + set_bit(NFP_PORT_CHANGED, &port->flags); + schedule_work(&pf->port_refresh_work); } -- cgit v1.2.3 From 46b250311dac828bcb79f0807c16d4157059ce7e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:33 -0700 Subject: nfp: mark port state as stale if update failed If reading new state of the port failed, mark the port back as CHANGED. This way next user state request will trigger refresh, which will hopefully succeed. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 12cbf21df3b9..dd1118c7e1a4 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -528,6 +528,7 @@ nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port, eth_port = nfp_net_find_port(eth_table, port->eth_id); if (!eth_port) { + set_bit(NFP_PORT_CHANGED, &port->flags); nfp_warn(cpp, "Warning: port #%d not present after reconfig\n", port->eth_id); return -EIO; @@ -563,6 +564,9 @@ static void nfp_net_refresh_vnics(struct work_struct *work) eth_table = nfp_eth_read_ports(pf->cpp); if (!eth_table) { + list_for_each_entry(port, &pf->ports, port_list) + if (__nfp_port_get_eth_port(port)) + set_bit(NFP_PORT_CHANGED, &port->flags); rtnl_unlock(); nfp_err(pf->cpp, "Error refreshing port config!\n"); goto out; @@ -611,6 +615,7 @@ int nfp_net_refresh_eth_port(struct nfp_port *port) eth_table = nfp_eth_read_ports(cpp); if (!eth_table) { + set_bit(NFP_PORT_CHANGED, &port->flags); nfp_err(cpp, "Error refreshing port state table!\n"); return -EIO; } -- cgit v1.2.3 From 1876749da87500c7228f91398e04291389a18634 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 22 May 2017 10:59:34 -0700 Subject: nfp: refresh port state before reporting autonegotiation State of autonegotiation may have changed but is not yet refreshed. Make sure ethtool respects the NFP_PORT_CHANGED flag when looking at autoneg. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 10 +--------- drivers/net/ethernet/netronome/nfp/nfp_port.c | 12 ++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_port.h | 1 + 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 23f9ea0f8982..84fdbc4b835b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -209,7 +209,7 @@ nfp_net_get_link_ksettings(struct net_device *netdev, cmd->base.duplex = DUPLEX_UNKNOWN; port = nfp_port_from_netdev(netdev); - eth_port = __nfp_port_get_eth_port(port); + eth_port = nfp_port_get_eth_port(port); if (eth_port) cmd->base.autoneg = eth_port->aneg != NFP_ANEG_DISABLED ? AUTONEG_ENABLE : AUTONEG_DISABLE; @@ -219,14 +219,6 @@ nfp_net_get_link_ksettings(struct net_device *netdev, /* Use link speed from ETH table if available, otherwise try the BAR */ if (eth_port) { - int err; - - if (test_bit(NFP_PORT_CHANGED, &port->flags)) { - err = nfp_net_refresh_eth_port(port); - if (err) - return err; - } - cmd->base.port = eth_port->port_type; cmd->base.speed = eth_port->speed; cmd->base.duplex = DUPLEX_FULL; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 295db04ccb05..3beed4167e2f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -58,6 +58,18 @@ struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port) return port->eth_port; } +struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port) +{ + if (!__nfp_port_get_eth_port(port)) + return NULL; + + if (test_bit(NFP_PORT_CHANGED, &port->flags)) + if (nfp_net_refresh_eth_port(port)) + return NULL; + + return __nfp_port_get_eth_port(port); +} + int nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 471fff1fc58f..641617de41cc 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -86,6 +86,7 @@ struct nfp_port { struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port); +struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port); int nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len); -- cgit v1.2.3 From 823b84201f4a719414d61b105fd23706c5668ab5 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Mon, 22 May 2017 21:50:42 +0800 Subject: Bluetooth: hci_ll: Fix download_firmware() return when __hci_cmd_sync fails When __hci_cmd_sync() fails, download_firmware() should also fail, and the same error value should be returned as PTR_ERR(skb). Without this fix, download_firmware() will return a success when it actually failed in __hci_cmd_sync(). Fixes: 371805522f87 ("bluetooth: hci_uart: add LL protocol serdev driver support") Signed-off-by: Guodong Xu Acked-by: Rob Herring Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_ll.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index adc444f309a3..200288c87fc4 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -624,6 +624,7 @@ static int download_firmware(struct ll_device *lldev) skb = __hci_cmd_sync(lldev->hu.hdev, cmd->opcode, cmd->plen, &cmd->speed, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(lldev->hu.hdev, "send command failed\n"); + err = PTR_ERR(skb); goto out_rel_fw; } kfree_skb(skb); -- cgit v1.2.3 From a6187ffdfcc854ce4d97f307e12508a4bde8bcf3 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 23 May 2017 11:51:00 +0200 Subject: Bluetooth: btwilink: Fix unexpected skb free The caller (hci_core) still owns the skb in case of error, releasing it inside the send function can lead to use-after-free errors. Reported-by: Dan Carpenter Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btwilink.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index b6bb58c41df5..85a3978b064f 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -262,7 +262,6 @@ static int ti_st_send_frame(struct hci_dev *hdev, struct sk_buff *skb) pkt_type = hci_skb_pkt_type(skb); len = hst->st_write(skb); if (len < 0) { - kfree_skb(skb); BT_ERR("ST write failed (%ld)", len); /* Try Again, would only fail if UART has gone bad */ return -EAGAIN; -- cgit v1.2.3 From 9acfd1c02993b4fb11f08104e7166249925f25d5 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan Date: Mon, 22 May 2017 12:19:48 -0700 Subject: enic: unmask intr only when napi is complete In case of busy poll, napi_complete_done returns false and does not dequeue napi. In this case do not unmask the intr. We are guaranteed napi is called again. This reduces unnecessary iowrites. Signed-off-by: Govindarajulu Varadarajan Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 4b87beeabce1..6a9c8878aca0 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1537,13 +1537,12 @@ static int enic_poll(struct napi_struct *napi, int budget) */ enic_calc_int_moderation(enic, &enic->rq[0]); - if (rq_work_done < rq_work_to_do) { + if ((rq_work_done < budget) && napi_complete_done(napi, rq_work_done)) { /* Some work done, but not enough to stay in polling, * exit polling */ - napi_complete_done(napi, rq_work_done); if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) enic_set_int_moderation(enic, &enic->rq[0]); vnic_intr_unmask(&enic->intr[intr]); @@ -1663,13 +1662,12 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget) */ enic_calc_int_moderation(enic, &enic->rq[rq]); - if (work_done < work_to_do) { + if ((work_done < budget) && napi_complete_done(napi, work_done)) { /* Some work done, but not enough to stay in polling, * exit polling */ - napi_complete_done(napi, work_done); if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) enic_set_int_moderation(enic, &enic->rq[rq]); vnic_intr_unmask(&enic->intr[intr]); -- cgit v1.2.3 From 8c1f20815231edf1ed2b7133ea07ea94ca31db05 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 19 May 2017 11:54:00 +0300 Subject: ath10k: remove unnecessary code The array fields in struct wmi_start_scan_arg that are checked here are fixed size arrays so they can never be NULL. Addresses-Coverity-ID: 1260031 Cc: Arend Van Spriel Cc: Kalle Valo Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6afc8d27f0d5..0dbcc79d718e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5948,15 +5948,6 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) { - if (arg->ie_len && !arg->ie) - return -EINVAL; - if (arg->n_channels && !arg->channels) - return -EINVAL; - if (arg->n_ssids && !arg->ssids) - return -EINVAL; - if (arg->n_bssids && !arg->bssids) - return -EINVAL; - if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN) return -EINVAL; if (arg->n_channels > ARRAY_SIZE(arg->channels)) -- cgit v1.2.3 From c1dd8016ae02557e4f3fcf7339865924d9357f76 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 19 May 2017 11:54:02 +0300 Subject: ath10k: fix reported HT MCS rates with NSS > 1 The QCA4019 firmware 10.4-3.2.1-00050 reports only HT MCS rates between 0-9. But 802.11n MCS rates can be larger than that. For example a 2x2 device can send with up to MCS 15. The firmware encodes the higher MCS rates using the NSS field. The actual calculation is not documented by QCA but it seems like the NSS field can be mapped for HT rates to following MCS offsets: * NSS 1: 0 * NSS 2: 8 * NSS 3: 16 * NSS 4: 24 This offset therefore has to be added for HT rates before they are stored in the rate_info struct. Fixes: cec17c382140 ("ath10k: add per peer htt tx stats support for 10.4") Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 84b6067ff6e7..6c0a821fe79d 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2229,9 +2229,15 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, txrate.mcs = ATH10K_HW_MCS_RATE(peer_stats->ratecode); sgi = ATH10K_HW_GI(peer_stats->flags); - if (((txrate.flags == WMI_RATE_PREAMBLE_HT) || - (txrate.flags == WMI_RATE_PREAMBLE_VHT)) && txrate.mcs > 9) { - ath10k_warn(ar, "Invalid mcs %hhd peer stats", txrate.mcs); + if (txrate.flags == WMI_RATE_PREAMBLE_VHT && txrate.mcs > 9) { + ath10k_warn(ar, "Invalid VHT mcs %hhd peer stats", txrate.mcs); + return; + } + + if (txrate.flags == WMI_RATE_PREAMBLE_HT && + (txrate.mcs > 7 || txrate.nss < 1)) { + ath10k_warn(ar, "Invalid HT mcs %hhd nss %hhd peer stats", + txrate.mcs, txrate.nss); return; } @@ -2254,7 +2260,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, arsta->txrate.legacy = rate; } else if (txrate.flags == WMI_RATE_PREAMBLE_HT) { arsta->txrate.flags = RATE_INFO_FLAGS_MCS; - arsta->txrate.mcs = txrate.mcs; + arsta->txrate.mcs = txrate.mcs + 8 * (txrate.nss - 1); } else { arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; arsta->txrate.mcs = txrate.mcs; -- cgit v1.2.3 From 0216a895946fa683ea51b842501e66106c0f1017 Mon Sep 17 00:00:00 2001 From: Lior David Date: Fri, 19 May 2017 11:54:06 +0300 Subject: wil6210: low level RF sector API Added vendor commands for low level control over RF sectors. It allows user space a fine-grained control over RF characteristics for TX and RX, such as direction and gain of TX/RX. Main usages are debugging and diagnostics, but also operational use cases. API includes getting/setting a specific RF sector configuration, as well as getting/setting the selected sector which is used to communicate with a station. Signed-off-by: Lior David Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 573 ++++++++++++++++++++++++++++ 1 file changed, 573 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index fdaa99c541ac..aa9ce3014fa8 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -16,6 +16,7 @@ #include #include +#include #include "wil6210.h" #include "wmi.h" @@ -41,6 +42,126 @@ static struct ieee80211_channel wil_60ghz_channels[] = { /* channel 4 not supported yet */ }; +/* Vendor id to be used in vendor specific command and events + * to user space. + * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID, + * vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and + * qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in + * git://w1.fi/srv/git/hostap.git; the values here are just a copy of that + */ + +#define QCA_NL80211_VENDOR_ID 0x001374 + +#define WIL_MAX_RF_SECTORS (128) +#define WIL_CID_ALL (0xff) + +enum qca_wlan_vendor_attr_rf_sector { + QCA_ATTR_MAC_ADDR = 6, + QCA_ATTR_PAD = 13, + QCA_ATTR_TSF = 29, + QCA_ATTR_DMG_RF_SECTOR_INDEX = 30, + QCA_ATTR_DMG_RF_SECTOR_TYPE = 31, + QCA_ATTR_DMG_RF_MODULE_MASK = 32, + QCA_ATTR_DMG_RF_SECTOR_CFG = 33, + QCA_ATTR_DMG_RF_SECTOR_MAX, +}; + +enum qca_wlan_vendor_attr_dmg_rf_sector_type { + QCA_ATTR_DMG_RF_SECTOR_TYPE_RX, + QCA_ATTR_DMG_RF_SECTOR_TYPE_TX, + QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX +}; + +enum qca_wlan_vendor_attr_dmg_rf_sector_cfg { + QCA_ATTR_DMG_RF_SECTOR_CFG_INVALID = 0, + QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX, + QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0, + QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1, + QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2, + QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI, + QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO, + QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16, + + /* keep last */ + QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST, + QCA_ATTR_DMG_RF_SECTOR_CFG_MAX = + QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST - 1 +}; + +static const struct +nla_policy wil_rf_sector_policy[QCA_ATTR_DMG_RF_SECTOR_MAX + 1] = { + [QCA_ATTR_MAC_ADDR] = { .len = ETH_ALEN }, + [QCA_ATTR_DMG_RF_SECTOR_INDEX] = { .type = NLA_U16 }, + [QCA_ATTR_DMG_RF_SECTOR_TYPE] = { .type = NLA_U8 }, + [QCA_ATTR_DMG_RF_MODULE_MASK] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG] = { .type = NLA_NESTED }, +}; + +static const struct +nla_policy wil_rf_sector_cfg_policy[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1] = { + [QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX] = { .type = NLA_U8 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO] = { .type = NLA_U32 }, + [QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16] = { .type = NLA_U32 }, +}; + +enum qca_nl80211_vendor_subcmds { + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG = 139, + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG = 140, + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141, + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142, +}; + +static int wil_rf_sector_get_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +static int wil_rf_sector_set_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +static int wil_rf_sector_get_selected(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +static int wil_rf_sector_set_selected(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +/* vendor specific commands */ +static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = { + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wil_rf_sector_get_cfg + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wil_rf_sector_set_cfg + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wil_rf_sector_get_selected + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wil_rf_sector_set_selected + }, +}; + static struct ieee80211_supported_band wil_band_60ghz = { .channels = wil_60ghz_channels, .n_channels = ARRAY_SIZE(wil_60ghz_channels), @@ -1637,6 +1758,9 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); wiphy->mgmt_stypes = wil_mgmt_stypes; wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; + + wiphy->n_vendor_commands = ARRAY_SIZE(wil_nl80211_vendor_commands); + wiphy->vendor_commands = wil_nl80211_vendor_commands; } struct wireless_dev *wil_cfg80211_init(struct device *dev) @@ -1695,3 +1819,452 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil) kfree(p2p_wdev); } } + +static int wil_rf_sector_status_to_rc(u8 status) +{ + switch (status) { + case WMI_RF_SECTOR_STATUS_SUCCESS: + return 0; + case WMI_RF_SECTOR_STATUS_BAD_PARAMETERS_ERROR: + return -EINVAL; + case WMI_RF_SECTOR_STATUS_BUSY_ERROR: + return -EAGAIN; + case WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR: + return -EOPNOTSUPP; + default: + return -EINVAL; + } +} + +static int wil_rf_sector_get_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct wil6210_priv *wil = wdev_to_wil(wdev); + int rc; + struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; + u16 sector_index; + u8 sector_type; + u32 rf_modules_vec; + struct wmi_get_rf_sector_params_cmd cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_get_rf_sector_params_done_event evt; + } __packed reply; + struct sk_buff *msg; + struct nlattr *nl_cfgs, *nl_cfg; + u32 i; + struct wmi_rf_sector_info *si; + + if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities)) + return -EOPNOTSUPP; + + rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, + wil_rf_sector_policy, NULL); + if (rc) { + wil_err(wil, "Invalid rf sector ATTR\n"); + return rc; + } + + if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] || + !tb[QCA_ATTR_DMG_RF_SECTOR_TYPE] || + !tb[QCA_ATTR_DMG_RF_MODULE_MASK]) { + wil_err(wil, "Invalid rf sector spec\n"); + return -EINVAL; + } + + sector_index = nla_get_u16( + tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]); + if (sector_index >= WIL_MAX_RF_SECTORS) { + wil_err(wil, "Invalid sector index %d\n", sector_index); + return -EINVAL; + } + + sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]); + if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) { + wil_err(wil, "Invalid sector type %d\n", sector_type); + return -EINVAL; + } + + rf_modules_vec = nla_get_u32( + tb[QCA_ATTR_DMG_RF_MODULE_MASK]); + if (rf_modules_vec >= BIT(WMI_MAX_RF_MODULES_NUM)) { + wil_err(wil, "Invalid rf module mask 0x%x\n", rf_modules_vec); + return -EINVAL; + } + + cmd.sector_idx = cpu_to_le16(sector_index); + cmd.sector_type = sector_type; + cmd.rf_modules_vec = rf_modules_vec & 0xFF; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_GET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd), + WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID, + &reply, sizeof(reply), + 500); + if (rc) + return rc; + if (reply.evt.status) { + wil_err(wil, "get rf sector cfg failed with status %d\n", + reply.evt.status); + return wil_rf_sector_status_to_rc(reply.evt.status); + } + + msg = cfg80211_vendor_cmd_alloc_reply_skb( + wiphy, 64 * WMI_MAX_RF_MODULES_NUM); + if (!msg) + return -ENOMEM; + + if (nla_put_u64_64bit(msg, QCA_ATTR_TSF, + le64_to_cpu(reply.evt.tsf), + QCA_ATTR_PAD)) + goto nla_put_failure; + + nl_cfgs = nla_nest_start(msg, QCA_ATTR_DMG_RF_SECTOR_CFG); + if (!nl_cfgs) + goto nla_put_failure; + for (i = 0; i < WMI_MAX_RF_MODULES_NUM; i++) { + if (!(rf_modules_vec & BIT(i))) + continue; + nl_cfg = nla_nest_start(msg, i); + if (!nl_cfg) + goto nla_put_failure; + si = &reply.evt.sectors_info[i]; + if (nla_put_u8(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX, + i) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0, + le32_to_cpu(si->etype0)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1, + le32_to_cpu(si->etype1)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2, + le32_to_cpu(si->etype2)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI, + le32_to_cpu(si->psh_hi)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO, + le32_to_cpu(si->psh_lo)) || + nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16, + le32_to_cpu(si->dtype_swch_off))) + goto nla_put_failure; + nla_nest_end(msg, nl_cfg); + } + + nla_nest_end(msg, nl_cfgs); + rc = cfg80211_vendor_cmd_reply(msg); + return rc; +nla_put_failure: + kfree_skb(msg); + return -ENOBUFS; +} + +static int wil_rf_sector_set_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct wil6210_priv *wil = wdev_to_wil(wdev); + int rc, tmp; + struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; + struct nlattr *tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1]; + u16 sector_index, rf_module_index; + u8 sector_type; + u32 rf_modules_vec = 0; + struct wmi_set_rf_sector_params_cmd cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_set_rf_sector_params_done_event evt; + } __packed reply; + struct nlattr *nl_cfg; + struct wmi_rf_sector_info *si; + + if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities)) + return -EOPNOTSUPP; + + rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, + wil_rf_sector_policy, NULL); + if (rc) { + wil_err(wil, "Invalid rf sector ATTR\n"); + return rc; + } + + if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] || + !tb[QCA_ATTR_DMG_RF_SECTOR_TYPE] || + !tb[QCA_ATTR_DMG_RF_SECTOR_CFG]) { + wil_err(wil, "Invalid rf sector spec\n"); + return -EINVAL; + } + + sector_index = nla_get_u16( + tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]); + if (sector_index >= WIL_MAX_RF_SECTORS) { + wil_err(wil, "Invalid sector index %d\n", sector_index); + return -EINVAL; + } + + sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]); + if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) { + wil_err(wil, "Invalid sector type %d\n", sector_type); + return -EINVAL; + } + + memset(&cmd, 0, sizeof(cmd)); + + cmd.sector_idx = cpu_to_le16(sector_index); + cmd.sector_type = sector_type; + nla_for_each_nested(nl_cfg, tb[QCA_ATTR_DMG_RF_SECTOR_CFG], + tmp) { + rc = nla_parse_nested(tb2, QCA_ATTR_DMG_RF_SECTOR_CFG_MAX, + nl_cfg, wil_rf_sector_cfg_policy, + NULL); + if (rc) { + wil_err(wil, "invalid sector cfg\n"); + return -EINVAL; + } + + if (!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO] || + !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16]) { + wil_err(wil, "missing cfg params\n"); + return -EINVAL; + } + + rf_module_index = nla_get_u8( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX]); + if (rf_module_index >= WMI_MAX_RF_MODULES_NUM) { + wil_err(wil, "invalid RF module index %d\n", + rf_module_index); + return -EINVAL; + } + rf_modules_vec |= BIT(rf_module_index); + si = &cmd.sectors_info[rf_module_index]; + si->etype0 = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0])); + si->etype1 = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1])); + si->etype2 = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2])); + si->psh_hi = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI])); + si->psh_lo = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO])); + si->dtype_swch_off = cpu_to_le32(nla_get_u32( + tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16])); + } + + cmd.rf_modules_vec = rf_modules_vec & 0xFF; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_SET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd), + WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID, + &reply, sizeof(reply), + 500); + if (rc) + return rc; + return wil_rf_sector_status_to_rc(reply.evt.status); +} + +static int wil_rf_sector_get_selected(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct wil6210_priv *wil = wdev_to_wil(wdev); + int rc; + struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; + u8 sector_type, mac_addr[ETH_ALEN]; + int cid = 0; + struct wmi_get_selected_rf_sector_index_cmd cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_get_selected_rf_sector_index_done_event evt; + } __packed reply; + struct sk_buff *msg; + + if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities)) + return -EOPNOTSUPP; + + rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, + wil_rf_sector_policy, NULL); + if (rc) { + wil_err(wil, "Invalid rf sector ATTR\n"); + return rc; + } + + if (!tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]) { + wil_err(wil, "Invalid rf sector spec\n"); + return -EINVAL; + } + sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]); + if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) { + wil_err(wil, "Invalid sector type %d\n", sector_type); + return -EINVAL; + } + + if (tb[QCA_ATTR_MAC_ADDR]) { + ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR])); + cid = wil_find_cid(wil, mac_addr); + if (cid < 0) { + wil_err(wil, "invalid MAC address %pM\n", mac_addr); + return -ENOENT; + } + } else { + if (test_bit(wil_status_fwconnected, wil->status)) { + wil_err(wil, "must specify MAC address when connected\n"); + return -EINVAL; + } + } + + memset(&cmd, 0, sizeof(cmd)); + cmd.cid = (u8)cid; + cmd.sector_type = sector_type; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID, + &cmd, sizeof(cmd), + WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID, + &reply, sizeof(reply), + 500); + if (rc) + return rc; + if (reply.evt.status) { + wil_err(wil, "get rf selected sector cfg failed with status %d\n", + reply.evt.status); + return wil_rf_sector_status_to_rc(reply.evt.status); + } + + msg = cfg80211_vendor_cmd_alloc_reply_skb( + wiphy, 64 * WMI_MAX_RF_MODULES_NUM); + if (!msg) + return -ENOMEM; + + if (nla_put_u64_64bit(msg, QCA_ATTR_TSF, + le64_to_cpu(reply.evt.tsf), + QCA_ATTR_PAD) || + nla_put_u16(msg, QCA_ATTR_DMG_RF_SECTOR_INDEX, + le16_to_cpu(reply.evt.sector_idx))) + goto nla_put_failure; + + rc = cfg80211_vendor_cmd_reply(msg); + return rc; +nla_put_failure: + kfree_skb(msg); + return -ENOBUFS; +} + +static int wil_rf_sector_wmi_set_selected(struct wil6210_priv *wil, + u16 sector_index, + u8 sector_type, u8 cid) +{ + struct wmi_set_selected_rf_sector_index_cmd cmd; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_set_selected_rf_sector_index_done_event evt; + } __packed reply; + int rc; + + memset(&cmd, 0, sizeof(cmd)); + cmd.sector_idx = cpu_to_le16(sector_index); + cmd.sector_type = sector_type; + cmd.cid = (u8)cid; + memset(&reply, 0, sizeof(reply)); + rc = wmi_call(wil, WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID, + &cmd, sizeof(cmd), + WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID, + &reply, sizeof(reply), + 500); + if (rc) + return rc; + return wil_rf_sector_status_to_rc(reply.evt.status); +} + +static int wil_rf_sector_set_selected(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct wil6210_priv *wil = wdev_to_wil(wdev); + int rc; + struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; + u16 sector_index; + u8 sector_type, mac_addr[ETH_ALEN], i; + int cid = 0; + + if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities)) + return -EOPNOTSUPP; + + rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, + wil_rf_sector_policy, NULL); + if (rc) { + wil_err(wil, "Invalid rf sector ATTR\n"); + return rc; + } + + if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] || + !tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]) { + wil_err(wil, "Invalid rf sector spec\n"); + return -EINVAL; + } + + sector_index = nla_get_u16( + tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]); + if (sector_index >= WIL_MAX_RF_SECTORS && + sector_index != WMI_INVALID_RF_SECTOR_INDEX) { + wil_err(wil, "Invalid sector index %d\n", sector_index); + return -EINVAL; + } + + sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]); + if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) { + wil_err(wil, "Invalid sector type %d\n", sector_type); + return -EINVAL; + } + + if (tb[QCA_ATTR_MAC_ADDR]) { + ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR])); + if (!is_broadcast_ether_addr(mac_addr)) { + cid = wil_find_cid(wil, mac_addr); + if (cid < 0) { + wil_err(wil, "invalid MAC address %pM\n", + mac_addr); + return -ENOENT; + } + } else { + if (sector_index != WMI_INVALID_RF_SECTOR_INDEX) { + wil_err(wil, "broadcast MAC valid only with unlocking\n"); + return -EINVAL; + } + cid = -1; + } + } else { + if (test_bit(wil_status_fwconnected, wil->status)) { + wil_err(wil, "must specify MAC address when connected\n"); + return -EINVAL; + } + /* otherwise, using cid=0 for unassociated station */ + } + + if (cid >= 0) { + rc = wil_rf_sector_wmi_set_selected(wil, sector_index, + sector_type, cid); + } else { + /* unlock all cids */ + rc = wil_rf_sector_wmi_set_selected( + wil, WMI_INVALID_RF_SECTOR_INDEX, sector_type, + WIL_CID_ALL); + if (rc == -EINVAL) { + for (i = 0; i < WIL6210_MAX_CID; i++) { + rc = wil_rf_sector_wmi_set_selected( + wil, WMI_INVALID_RF_SECTOR_INDEX, + sector_type, i); + /* the FW will silently ignore and return + * success for unused cid, so abort the loop + * on any other error + */ + if (rc) { + wil_err(wil, "unlock cid %d failed with status %d\n", + i, rc); + break; + } + } + } + } + + return rc; +} -- cgit v1.2.3 From 1c3964540425f1c12b652a2f2e45d73ffc16c37e Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Fri, 19 May 2017 11:54:07 +0300 Subject: wil6210: add option to load FTM FW Module parameter allows to load specific FW used for FTM testing. Signed-off-by: Hamad Kadmany Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 18 +++++++++++++----- drivers/net/wireless/ath/wil6210/wil6210.h | 9 +++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index b38515fc7ce7..33bd85cea05e 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,6 +26,10 @@ static bool use_msi = true; module_param(use_msi, bool, 0444); MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true"); +static bool ftm_mode; +module_param(ftm_mode, bool, 0444); +MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false"); + #ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP static int wil6210_pm_notify(struct notifier_block *notify_block, @@ -36,13 +40,15 @@ static int wil6210_pm_notify(struct notifier_block *notify_block, static void wil_set_capabilities(struct wil6210_priv *wil) { + const char *wil_fw_name; u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) & RGF_USER_REVISION_ID_MASK); bitmap_zero(wil->hw_capabilities, hw_capability_last); bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX); - wil->wil_fw_name = WIL_FW_NAME_DEFAULT; + wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT : + WIL_FW_NAME_DEFAULT; wil->chip_revision = chip_revision; switch (jtag_id) { @@ -51,9 +57,11 @@ void wil_set_capabilities(struct wil6210_priv *wil) case REVISION_ID_SPARROW_D0: wil->hw_name = "Sparrow D0"; wil->hw_version = HW_VER_SPARROW_D0; - if (wil_fw_verify_file_exists(wil, - WIL_FW_NAME_SPARROW_PLUS)) - wil->wil_fw_name = WIL_FW_NAME_SPARROW_PLUS; + wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_SPARROW_PLUS : + WIL_FW_NAME_SPARROW_PLUS; + + if (wil_fw_verify_file_exists(wil, wil_fw_name)) + wil->wil_fw_name = wil_fw_name; break; case REVISION_ID_SPARROW_B0: wil->hw_name = "Sparrow B0"; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b00c803a1e83..fe942bae2978 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -37,8 +37,13 @@ extern bool debug_fw; extern bool disable_ap_sme; #define WIL_NAME "wil6210" -#define WIL_FW_NAME_DEFAULT "wil6210.fw" /* code Sparrow B0 */ -#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" /* code Sparrow D0 */ + +#define WIL_FW_NAME_DEFAULT "wil6210.fw" +#define WIL_FW_NAME_FTM_DEFAULT "wil6210_ftm.fw" + +#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" +#define WIL_FW_NAME_FTM_SPARROW_PLUS "wil6210_sparrow_plus_ftm.fw" + #define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */ #define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */ -- cgit v1.2.3 From 646d402d9f8f5669b3ddc6fbec5f55288777704b Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Fri, 19 May 2017 11:54:08 +0300 Subject: wil6210: Improve AP stop handling Set resetting flag early when stopping AP to avoid disconnect events as a result of disconnect command sent during AP stop procedure. Signed-off-by: Hamad Kadmany Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index aa9ce3014fa8..567fe43b5cf8 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1446,6 +1446,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); wil_set_recovery_state(wil, fw_recovery_idle); + set_bit(wil_status_resetting, wil->status); + mutex_lock(&wil->mutex); wmi_pcp_stop(wil); -- cgit v1.2.3 From d86d47164b227f01c3ec34c3f5a1613977d563eb Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Fri, 19 May 2017 11:54:10 +0300 Subject: wil6210: support devices with different PCIe bar size wil6210 devices can have different PCIe bar size, hence get the bar size from PCIe device instead of using a constant bar size. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/ioctl.c | 4 ++-- drivers/net/wireless/ath/wil6210/pcie_bus.c | 17 ++++++++++------- drivers/net/wireless/ath/wil6210/wil6210.h | 4 +++- drivers/net/wireless/ath/wil6210/wmi.c | 4 ++-- 4 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c index 630380078236..1c49ad8f9478 100644 --- a/drivers/net/wireless/ath/wil6210/ioctl.c +++ b/drivers/net/wireless/ath/wil6210/ioctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -46,7 +46,7 @@ static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr, } off = a - wil->csr; - if (size >= WIL6210_MEM_SIZE - off) { + if (size >= wil->bar_size - off) { wil_err(wil, "Requested block does not fit into memory: " "off = 0x%08x size = 0x%08x\n", off, size); return NULL; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 33bd85cea05e..bf9f26563c48 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -200,16 +200,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) .ramdump = wil_platform_rop_ramdump, .fw_recovery = wil_platform_rop_fw_recovery, }; + u32 bar_size = pci_resource_len(pdev, 0); /* check HW */ dev_info(&pdev->dev, WIL_NAME - " device found [%04x:%04x] (rev %x)\n", - (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); - - if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { - dev_err(&pdev->dev, "Not " WIL_NAME "? " - "BAR0 size is %lu while expecting %lu\n", - (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE); + " device found [%04x:%04x] (rev %x) bar size 0x%x\n", + (int)pdev->vendor, (int)pdev->device, (int)pdev->revision, + bar_size); + + if ((bar_size < WIL6210_MIN_MEM_SIZE) || + (bar_size > WIL6210_MAX_MEM_SIZE)) { + dev_err(&pdev->dev, "Unexpected BAR0 size 0x%x\n", + bar_size); return -ENODEV; } @@ -222,6 +224,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil->pdev = pdev; pci_set_drvdata(pdev, wil); + wil->bar_size = bar_size; /* rollback to if_free */ wil->platform_handle = diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index fe942bae2978..ca532c777b56 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -58,7 +58,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1); } -#define WIL6210_MEM_SIZE (2*1024*1024UL) +#define WIL6210_MIN_MEM_SIZE (2 * 1024 * 1024UL) +#define WIL6210_MAX_MEM_SIZE (4 * 1024 * 1024UL) #define WIL_TX_Q_LEN_DEFAULT (4000) #define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) @@ -599,6 +600,7 @@ extern u8 led_polarity; struct wil6210_priv { struct pci_dev *pdev; + u32 bar_size; struct wireless_dev *wdev; void __iomem *csr; DECLARE_BITMAP(status, wil_status_last); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 814c35645b73..93902cb2e8cf 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -157,7 +157,7 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) return NULL; off = HOSTADDR(ptr); - if (off > WIL6210_MEM_SIZE - 4) + if (off > wil->bar_size - 4) return NULL; return wil->csr + off; @@ -177,7 +177,7 @@ void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr) return NULL; off = HOSTADDR(ptr); - if (off > WIL6210_MEM_SIZE - 4) + if (off > wil->bar_size - 4) return NULL; return wil->csr + off; -- cgit v1.2.3 From d1b7abae666cc4630daa3db4e839626bc179f6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Billeter?= Date: Tue, 23 May 2017 18:46:25 +0200 Subject: Bluetooth: btintel: Add MODULE_FIRMWARE entries for iBT 3.5 controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The iBT 3.5 controllers (Intel 8265, Windstorm Peak) need intel/ibt-12-16.sfi and intel/ibt-12-16.ddc firmware files from linux-firmware repository. Signed-off-by: Jürg Billeter Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btintel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index fce154855718..d32e109bd5cb 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -575,3 +575,5 @@ MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("intel/ibt-11-5.sfi"); MODULE_FIRMWARE("intel/ibt-11-5.ddc"); +MODULE_FIRMWARE("intel/ibt-12-16.sfi"); +MODULE_FIRMWARE("intel/ibt-12-16.ddc"); -- cgit v1.2.3 From 7dab5467647be42736dcabcd5d035c7b571f4653 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 23 May 2017 13:11:47 -0500 Subject: net: ieee802154: fix potential null pointer dereference Null check at line 918: if (!spi) {, implies spi might be NULL. Function spi_get_drvdata() dereference pointer spi. Move pointer priv assignment after the null check. Addresses-Coverity-ID: 1408888 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/ca8210.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index f6df75e80a60..7a218549c80a 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -912,7 +912,7 @@ static int ca8210_spi_transfer( ) { int i, status = 0; - struct ca8210_priv *priv = spi_get_drvdata(spi); + struct ca8210_priv *priv; struct cas_control *cas_ctl; if (!spi) { @@ -923,6 +923,7 @@ static int ca8210_spi_transfer( return -ENODEV; } + priv = spi_get_drvdata(spi); reinit_completion(&priv->spi_transfer_complete); dev_dbg(&spi->dev, "ca8210_spi_transfer called\n"); -- cgit v1.2.3 From d7af6bb7e527e700dac04f8e0e791baf716a3988 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:07 +0530 Subject: rsi: Rename file rsi_91x_pkt.c to rsi_91x_hal.c The file rsi_91x_hal.c is going to contain device specific code i.e new firmware loading method for RS9113 chipset. As the file rsi_91x_pkt.c contains code to prepare device specific descriptors for transmit packet, this file is renamed to rsi_91x_hal.c which is more relevant as per it's functionality. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/Makefile | 2 +- drivers/net/wireless/rsi/rsi_91x_hal.c | 215 +++++++++++++++++++++++++++++++++ drivers/net/wireless/rsi/rsi_91x_pkt.c | 215 --------------------------------- 3 files changed, 216 insertions(+), 216 deletions(-) create mode 100644 drivers/net/wireless/rsi/rsi_91x_hal.c delete mode 100644 drivers/net/wireless/rsi/rsi_91x_pkt.c (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile index 25828b692756..a475c813674a 100644 --- a/drivers/net/wireless/rsi/Makefile +++ b/drivers/net/wireless/rsi/Makefile @@ -2,7 +2,7 @@ rsi_91x-y += rsi_91x_main.o rsi_91x-y += rsi_91x_core.o rsi_91x-y += rsi_91x_mac80211.o rsi_91x-y += rsi_91x_mgmt.o -rsi_91x-y += rsi_91x_pkt.o +rsi_91x-y += rsi_91x_hal.o rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c new file mode 100644 index 000000000000..02920c93e82d --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -0,0 +1,215 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "rsi_mgmt.h" + +/** + * rsi_send_data_pkt() - This function sends the recieved data packet from + * driver to device. + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: status: 0 on success, -1 on failure. + */ +int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_hdr *tmp_hdr; + struct ieee80211_tx_info *info; + struct skb_info *tx_params; + struct ieee80211_bss_conf *bss; + int status; + u8 ieee80211_size = MIN_802_11_HDR_LEN; + u8 extnd_size; + __le16 *frame_desc; + u16 seq_num; + + info = IEEE80211_SKB_CB(skb); + bss = &info->control.vif->bss_conf; + tx_params = (struct skb_info *)info->driver_data; + + if (!bss->assoc) { + status = -EINVAL; + goto err; + } + + tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; + seq_num = (le16_to_cpu(tmp_hdr->seq_ctrl) >> 4); + + extnd_size = ((uintptr_t)skb->data & 0x3); + + if ((FRAME_DESC_SZ + extnd_size) > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); + status = -ENOSPC; + goto err; + } + + skb_push(skb, (FRAME_DESC_SZ + extnd_size)); + frame_desc = (__le16 *)&skb->data[0]; + memset((u8 *)frame_desc, 0, FRAME_DESC_SZ); + + if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { + ieee80211_size += 2; + frame_desc[6] |= cpu_to_le16(BIT(12)); + } + + if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) && + (common->secinfo.security_enable)) { + if (rsi_is_cipher_wep(common)) + ieee80211_size += 4; + else + ieee80211_size += 8; + frame_desc[6] |= cpu_to_le16(BIT(15)); + } + + frame_desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | + (RSI_WIFI_DATA_Q << 12)); + frame_desc[2] = cpu_to_le16((extnd_size) | (ieee80211_size) << 8); + + if (common->min_rate != 0xffff) { + /* Send fixed rate */ + frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE); + frame_desc[4] = cpu_to_le16(common->min_rate); + + if (conf_is_ht40(&common->priv->hw->conf)) + frame_desc[5] = cpu_to_le16(FULL40M_ENABLE); + + if (common->vif_info[0].sgi) { + if (common->min_rate & 0x100) /* Only MCS rates */ + frame_desc[4] |= + cpu_to_le16(ENABLE_SHORTGI_RATE); + } + + } + + frame_desc[6] |= cpu_to_le16(seq_num & 0xfff); + frame_desc[7] = cpu_to_le16(((tx_params->tid & 0xf) << 4) | + (skb->priority & 0xf) | + (tx_params->sta_id << 8)); + + status = adapter->host_intf_write_pkt(common->priv, + skb->data, + skb->len); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", + __func__); + +err: + ++common->tx_stats.total_tx_pkt_freed[skb->priority]; + rsi_indicate_tx_status(common->priv, skb, status); + return status; +} + +/** + * rsi_send_mgmt_pkt() - This functions sends the received management packet + * from driver to device. + * @common: Pointer to the driver private structure. + * @skb: Pointer to the socket buffer structure. + * + * Return: status: 0 on success, -1 on failure. + */ +int rsi_send_mgmt_pkt(struct rsi_common *common, + struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_hdr *wh; + struct ieee80211_tx_info *info; + struct ieee80211_bss_conf *bss; + struct ieee80211_hw *hw = adapter->hw; + struct ieee80211_conf *conf = &hw->conf; + struct skb_info *tx_params; + int status = -E2BIG; + __le16 *msg; + u8 extnd_size; + u8 vap_id = 0; + + info = IEEE80211_SKB_CB(skb); + tx_params = (struct skb_info *)info->driver_data; + extnd_size = ((uintptr_t)skb->data & 0x3); + + if (tx_params->flags & INTERNAL_MGMT_PKT) { + if ((extnd_size) > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); + dev_kfree_skb(skb); + return -ENOSPC; + } + skb_push(skb, extnd_size); + skb->data[extnd_size + 4] = extnd_size; + status = adapter->host_intf_write_pkt(common->priv, + (u8 *)skb->data, + skb->len); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write the packet\n", __func__); + } + dev_kfree_skb(skb); + return status; + } + + bss = &info->control.vif->bss_conf; + wh = (struct ieee80211_hdr *)&skb->data[0]; + + if (FRAME_DESC_SZ > skb_headroom(skb)) + goto err; + + skb_push(skb, FRAME_DESC_SZ); + memset(skb->data, 0, FRAME_DESC_SZ); + msg = (__le16 *)skb->data; + + if (skb->len > MAX_MGMT_PKT_SIZE) { + rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); + goto err; + } + + msg[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | + (RSI_WIFI_MGMT_Q << 12)); + msg[1] = cpu_to_le16(TX_DOT11_MGMT); + msg[2] = cpu_to_le16(MIN_802_11_HDR_LEN << 8); + msg[3] = cpu_to_le16(RATE_INFO_ENABLE); + msg[6] = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4); + + if (wh->addr1[0] & BIT(0)) + msg[3] |= cpu_to_le16(RSI_BROADCAST_PKT); + + if (common->band == NL80211_BAND_2GHZ) + msg[4] = cpu_to_le16(RSI_11B_MODE); + else + msg[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE); + + if (conf_is_ht40(conf)) { + msg[4] = cpu_to_le16(0xB | RSI_11G_MODE); + msg[5] = cpu_to_le16(0x6); + } + + /* Indicate to firmware to give cfm */ + if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) { + msg[1] |= cpu_to_le16(BIT(10)); + msg[7] = cpu_to_le16(PROBEREQ_CONFIRM); + common->mgmt_q_block = true; + } + + msg[7] |= cpu_to_le16(vap_id << 8); + + status = adapter->host_intf_write_pkt(common->priv, + (u8 *)msg, + skb->len); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); + +err: + rsi_indicate_tx_status(common->priv, skb, status); + return status; +} diff --git a/drivers/net/wireless/rsi/rsi_91x_pkt.c b/drivers/net/wireless/rsi/rsi_91x_pkt.c deleted file mode 100644 index 02920c93e82d..000000000000 --- a/drivers/net/wireless/rsi/rsi_91x_pkt.c +++ /dev/null @@ -1,215 +0,0 @@ -/** - * Copyright (c) 2014 Redpine Signals Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "rsi_mgmt.h" - -/** - * rsi_send_data_pkt() - This function sends the recieved data packet from - * driver to device. - * @common: Pointer to the driver private structure. - * @skb: Pointer to the socket buffer structure. - * - * Return: status: 0 on success, -1 on failure. - */ -int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) -{ - struct rsi_hw *adapter = common->priv; - struct ieee80211_hdr *tmp_hdr; - struct ieee80211_tx_info *info; - struct skb_info *tx_params; - struct ieee80211_bss_conf *bss; - int status; - u8 ieee80211_size = MIN_802_11_HDR_LEN; - u8 extnd_size; - __le16 *frame_desc; - u16 seq_num; - - info = IEEE80211_SKB_CB(skb); - bss = &info->control.vif->bss_conf; - tx_params = (struct skb_info *)info->driver_data; - - if (!bss->assoc) { - status = -EINVAL; - goto err; - } - - tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; - seq_num = (le16_to_cpu(tmp_hdr->seq_ctrl) >> 4); - - extnd_size = ((uintptr_t)skb->data & 0x3); - - if ((FRAME_DESC_SZ + extnd_size) > skb_headroom(skb)) { - rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); - status = -ENOSPC; - goto err; - } - - skb_push(skb, (FRAME_DESC_SZ + extnd_size)); - frame_desc = (__le16 *)&skb->data[0]; - memset((u8 *)frame_desc, 0, FRAME_DESC_SZ); - - if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { - ieee80211_size += 2; - frame_desc[6] |= cpu_to_le16(BIT(12)); - } - - if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) && - (common->secinfo.security_enable)) { - if (rsi_is_cipher_wep(common)) - ieee80211_size += 4; - else - ieee80211_size += 8; - frame_desc[6] |= cpu_to_le16(BIT(15)); - } - - frame_desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | - (RSI_WIFI_DATA_Q << 12)); - frame_desc[2] = cpu_to_le16((extnd_size) | (ieee80211_size) << 8); - - if (common->min_rate != 0xffff) { - /* Send fixed rate */ - frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE); - frame_desc[4] = cpu_to_le16(common->min_rate); - - if (conf_is_ht40(&common->priv->hw->conf)) - frame_desc[5] = cpu_to_le16(FULL40M_ENABLE); - - if (common->vif_info[0].sgi) { - if (common->min_rate & 0x100) /* Only MCS rates */ - frame_desc[4] |= - cpu_to_le16(ENABLE_SHORTGI_RATE); - } - - } - - frame_desc[6] |= cpu_to_le16(seq_num & 0xfff); - frame_desc[7] = cpu_to_le16(((tx_params->tid & 0xf) << 4) | - (skb->priority & 0xf) | - (tx_params->sta_id << 8)); - - status = adapter->host_intf_write_pkt(common->priv, - skb->data, - skb->len); - if (status) - rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", - __func__); - -err: - ++common->tx_stats.total_tx_pkt_freed[skb->priority]; - rsi_indicate_tx_status(common->priv, skb, status); - return status; -} - -/** - * rsi_send_mgmt_pkt() - This functions sends the received management packet - * from driver to device. - * @common: Pointer to the driver private structure. - * @skb: Pointer to the socket buffer structure. - * - * Return: status: 0 on success, -1 on failure. - */ -int rsi_send_mgmt_pkt(struct rsi_common *common, - struct sk_buff *skb) -{ - struct rsi_hw *adapter = common->priv; - struct ieee80211_hdr *wh; - struct ieee80211_tx_info *info; - struct ieee80211_bss_conf *bss; - struct ieee80211_hw *hw = adapter->hw; - struct ieee80211_conf *conf = &hw->conf; - struct skb_info *tx_params; - int status = -E2BIG; - __le16 *msg; - u8 extnd_size; - u8 vap_id = 0; - - info = IEEE80211_SKB_CB(skb); - tx_params = (struct skb_info *)info->driver_data; - extnd_size = ((uintptr_t)skb->data & 0x3); - - if (tx_params->flags & INTERNAL_MGMT_PKT) { - if ((extnd_size) > skb_headroom(skb)) { - rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); - dev_kfree_skb(skb); - return -ENOSPC; - } - skb_push(skb, extnd_size); - skb->data[extnd_size + 4] = extnd_size; - status = adapter->host_intf_write_pkt(common->priv, - (u8 *)skb->data, - skb->len); - if (status) { - rsi_dbg(ERR_ZONE, - "%s: Failed to write the packet\n", __func__); - } - dev_kfree_skb(skb); - return status; - } - - bss = &info->control.vif->bss_conf; - wh = (struct ieee80211_hdr *)&skb->data[0]; - - if (FRAME_DESC_SZ > skb_headroom(skb)) - goto err; - - skb_push(skb, FRAME_DESC_SZ); - memset(skb->data, 0, FRAME_DESC_SZ); - msg = (__le16 *)skb->data; - - if (skb->len > MAX_MGMT_PKT_SIZE) { - rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); - goto err; - } - - msg[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); - msg[1] = cpu_to_le16(TX_DOT11_MGMT); - msg[2] = cpu_to_le16(MIN_802_11_HDR_LEN << 8); - msg[3] = cpu_to_le16(RATE_INFO_ENABLE); - msg[6] = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4); - - if (wh->addr1[0] & BIT(0)) - msg[3] |= cpu_to_le16(RSI_BROADCAST_PKT); - - if (common->band == NL80211_BAND_2GHZ) - msg[4] = cpu_to_le16(RSI_11B_MODE); - else - msg[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE); - - if (conf_is_ht40(conf)) { - msg[4] = cpu_to_le16(0xB | RSI_11G_MODE); - msg[5] = cpu_to_le16(0x6); - } - - /* Indicate to firmware to give cfm */ - if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) { - msg[1] |= cpu_to_le16(BIT(10)); - msg[7] = cpu_to_le16(PROBEREQ_CONFIRM); - common->mgmt_q_block = true; - } - - msg[7] |= cpu_to_le16(vap_id << 8); - - status = adapter->host_intf_write_pkt(common->priv, - (u8 *)msg, - skb->len); - if (status) - rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); - -err: - rsi_indicate_tx_status(common->priv, skb, status); - return status; -} -- cgit v1.2.3 From 897d341dee4f44659ed4b705ae59500fa6b74b28 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:08 +0530 Subject: rsi: Changes to sdio reads and writes SDIO read or write maximum size is limited to 2^16. This is done to make the host interface operations common for SDIO and USB. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 10 +++++----- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 8 ++++---- drivers/net/wireless/rsi/rsi_sdio.h | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 8428858204a6..39d94b38f0a0 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -487,8 +487,8 @@ void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit) */ static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter, u32 addr, - u32 count, - u8 *data) + u8 *data, + u16 count) { struct rsi_91x_sdiodev *dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; @@ -518,7 +518,7 @@ static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter, int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr, u8 *data, - u32 count) + u16 count) { struct rsi_91x_sdiodev *dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; @@ -614,8 +614,8 @@ int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, status = rsi_sdio_read_register_multiple(adapter, length, - length, /*num of bytes*/ - (u8 *)pkt); + (u8 *)pkt, + length); /*num of bytes*/ if (status) rsi_dbg(ERR_ZONE, "%s: Failed to read frame: %d\n", __func__, diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 40d72312f3df..7c9cf016188c 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -75,13 +75,13 @@ static int rsi_sdio_master_access_msword(struct rsi_hw *adapter, static int rsi_copy_to_card(struct rsi_common *common, const u8 *fw, u32 len, - u32 num_blocks) + u16 num_blocks) { struct rsi_hw *adapter = common->priv; struct rsi_91x_sdiodev *dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; u32 indx, ii; - u32 block_size = dev->tx_blk_size; + u16 block_size = dev->tx_blk_size; u32 lsb_address; __le32 data[] = { TA_HOLD_THREAD_VALUE, TA_SOFT_RST_CLR, TA_PC_ZERO, TA_RELEASE_THREAD_VALUE }; @@ -171,10 +171,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) struct rsi_91x_sdiodev *dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; u32 len; - u32 num_blocks; + u16 num_blocks; const u8 *fw; const struct firmware *fw_entry = NULL; - u32 block_size = dev->tx_blk_size; + u16 block_size = dev->tx_blk_size; int status = 0; u32 base_address; u16 msb_address; diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index c7e8f2be7901..a82bc4c73f66 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -110,7 +110,7 @@ struct rsi_91x_sdiodev { u8 sdio_clock_speed; u32 cardcapability; u8 prev_desc[16]; - u32 tx_blk_size; + u16 tx_blk_size; u8 write_fail; }; @@ -122,7 +122,7 @@ int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, u8 *pkt, u32 length); int rsi_sdio_write_register(struct rsi_hw *adapter, u8 function, u32 addr, u8 *data); int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr, - u8 *data, u32 count); + u8 *data, u16 count); void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit); int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter); int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num); -- cgit v1.2.3 From 7bdead7ae944c06ef5916e22254929f583684b4a Mon Sep 17 00:00:00 2001 From: amit karwar Date: Tue, 16 May 2017 15:31:09 +0530 Subject: rsi: define RSI_USB_BUF_SIZE macro RSI_USB_BUF_SIZE macro is used instead of hardcoding a buffer size to 4096. Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 4 ++-- drivers/net/wireless/rsi/rsi_usb.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index cc8deecea8cb..be8487c56945 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -293,12 +293,12 @@ int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u8 transfer; int status = 0; - buf = kzalloc(4096, GFP_KERNEL); + buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; while (count) { - transfer = (u8)(min_t(u32, count, 4096)); + transfer = (u8)(min_t(u32, count, RSI_USB_BUF_SIZE)); memcpy(buf, data, transfer); status = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h index ebea0c411ead..48c9211fac09 100644 --- a/drivers/net/wireless/rsi/rsi_usb.h +++ b/drivers/net/wireless/rsi/rsi_usb.h @@ -35,6 +35,8 @@ #define MGMT_EP 1 #define DATA_EP 2 +#define RSI_USB_BUF_SIZE 4096 + struct rsi_91x_usbdev { struct rsi_thread rx_thread; u8 endpoint; -- cgit v1.2.3 From 2fbbe5179ebe8d7f307c8f9fc9fbd75254fdf4be Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:10 +0530 Subject: rsi: Changes in USB read and write operations USB read and write registers maximum size is limited 2^16. More than this size is not used in the driver. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 6 +++--- drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 9 +++++---- drivers/net/wireless/rsi/rsi_usb.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index be8487c56945..5f6c7000bc51 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -286,11 +286,11 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter) int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, u8 *data, - u32 count) + u16 count) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; u8 *buf; - u8 transfer; + u16 transfer; int status = 0; buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); @@ -298,7 +298,7 @@ int rsi_usb_write_register_multiple(struct rsi_hw *adapter, return -ENOMEM; while (count) { - transfer = (u8)(min_t(u32, count, RSI_USB_BUF_SIZE)); + transfer = min_t(u16, count, RSI_USB_BUF_SIZE); memcpy(buf, data, transfer); status = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index de4900862836..1c3e65433ceb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -33,12 +33,12 @@ static int rsi_copy_to_card(struct rsi_common *common, const u8 *fw, u32 len, - u32 num_blocks) + u16 num_blocks) { struct rsi_hw *adapter = common->priv; struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; u32 indx, ii; - u32 block_size = dev->tx_blk_size; + u16 block_size = dev->tx_blk_size; u32 lsb_address; u32 base_address; @@ -134,9 +134,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) struct rsi_hw *adapter = common->priv; struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; const struct firmware *fw_entry = NULL; - u32 block_size = dev->tx_blk_size; + u16 block_size = dev->tx_blk_size; const u8 *fw; - u32 num_blocks, len; + u16 num_blocks; + u32 len; int status = 0; status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device); diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h index 48c9211fac09..d1e01bcf772b 100644 --- a/drivers/net/wireless/rsi/rsi_usb.h +++ b/drivers/net/wireless/rsi/rsi_usb.h @@ -65,6 +65,6 @@ static inline int rsi_usb_event_timeout(struct rsi_hw *adapter) int rsi_usb_device_init(struct rsi_common *common); int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, - u8 *data, u32 count); + u8 *data, u16 count); void rsi_usb_rx_thread(struct rsi_common *common); #endif -- cgit v1.2.3 From 4b1fc881173e7c67468c78d7a7b215d527d14042 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:11 +0530 Subject: rsi: use macros in USB specific code For USB vendor read and write operations new macros added to avoid redundant usage of long or'ed macros. Also for timeouts standard USB macros are used. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 5f6c7000bc51..9e1359a204fc 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -141,6 +141,9 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface, return 0; } +#define RSI_USB_REQ_OUT (USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE) +#define RSI_USB_REQ_IN (USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE) + /* rsi_usb_reg_read() - This function reads data from given register address. * @usbdev: Pointer to the usb_device structure. * @reg: Address of the register to be read. @@ -164,11 +167,11 @@ static int rsi_usb_reg_read(struct usb_device *usbdev, status = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_READ, - USB_TYPE_VENDOR, + RSI_USB_REQ_IN, ((reg & 0xffff0000) >> 16), (reg & 0xffff), (void *)buf, len, - HZ * 5); + USB_CTRL_GET_TIMEOUT); *value = (buf[0] | (buf[1] << 8)); if (status < 0) { @@ -211,12 +214,12 @@ static int rsi_usb_reg_write(struct usb_device *usbdev, status = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_WRITE, - USB_TYPE_VENDOR, + RSI_USB_REQ_OUT, ((reg & 0xffff0000) >> 16), (reg & 0xffff), (void *)usb_reg_buf, len, - HZ * 5); + USB_CTRL_SET_TIMEOUT); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Reg write failed with error code :%d\n", @@ -303,12 +306,12 @@ int rsi_usb_write_register_multiple(struct rsi_hw *adapter, status = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), USB_VENDOR_REGISTER_WRITE, - USB_TYPE_VENDOR, + RSI_USB_REQ_OUT, ((addr & 0xffff0000) >> 16), (addr & 0xffff), (void *)buf, transfer, - HZ * 5); + USB_CTRL_SET_TIMEOUT); if (status < 0) { rsi_dbg(ERR_ZONE, "Reg write failed with error code :%d\n", -- cgit v1.2.3 From ea3336ac0094b9d461fdde22127087ee293e609a Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:12 +0530 Subject: rsi: Handle usb multi-byte write failure case properly In function usb_write_register_multiple, if any intermediate block transfer is failed, further operations should be terminated. 'else' is removed, as there is no significance for it after return. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 9e1359a204fc..a900a7288acb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -316,11 +316,12 @@ int rsi_usb_write_register_multiple(struct rsi_hw *adapter, rsi_dbg(ERR_ZONE, "Reg write failed with error code :%d\n", status); - } else { - count -= transfer; - data += transfer; - addr += transfer; + kfree(buf); + return status; } + count -= transfer; + data += transfer; + addr += transfer; } kfree(buf); -- cgit v1.2.3 From 88fa51e1b33c27bba6080f04f218e9d17632aec7 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:13 +0530 Subject: rsi: Add usb multi-byte read operation USB multibyte read will be used in the new firmware loading method for RS9113 chipset. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index a900a7288acb..31f96f0f6e30 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -276,6 +276,46 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter) return status; } +static int rsi_usb_read_register_multiple(struct rsi_hw *adapter, u32 addr, + u8 *data, u16 count) +{ + struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; + u8 *buf; + u16 transfer; + int status; + + if (!addr) + return -EINVAL; + + buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + while (count) { + transfer = min_t(u16, count, RSI_USB_BUF_SIZE); + status = usb_control_msg(dev->usbdev, + usb_rcvctrlpipe(dev->usbdev, 0), + USB_VENDOR_REGISTER_READ, + RSI_USB_REQ_IN, + ((addr & 0xffff0000) >> 16), + (addr & 0xffff), (void *)buf, + transfer, USB_CTRL_GET_TIMEOUT); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "Reg read failed with error code :%d\n", + status); + kfree(buf); + return status; + } + memcpy(data, buf, transfer); + count -= transfer; + data += transfer; + addr += transfer; + } + kfree(buf); + return 0; +} + /** * rsi_usb_write_register_multiple() - This function writes multiple bytes of * information to multiple registers. -- cgit v1.2.3 From a2ce952c8e09eb36e3f1da0c2dbe8b41c7b8297c Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:14 +0530 Subject: rsi: Add host interface operations as separate structure. Host interface operations are currently function pointers in rsi_hw structure. As more host interface operations are going to be introduced, separate structure is added for these for convenience. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 16 +++++++--------- drivers/net/wireless/rsi/rsi_91x_sdio.c | 11 +++++++++-- drivers/net/wireless/rsi/rsi_91x_usb.c | 9 ++++++++- drivers/net/wireless/rsi/rsi_main.h | 18 ++++++++++++++++-- 4 files changed, 40 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 02920c93e82d..8fbf90498d65 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -100,9 +100,8 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) (skb->priority & 0xf) | (tx_params->sta_id << 8)); - status = adapter->host_intf_write_pkt(common->priv, - skb->data, - skb->len); + status = adapter->host_intf_ops->write_pkt(common->priv, skb->data, + skb->len); if (status) rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__); @@ -148,9 +147,9 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, } skb_push(skb, extnd_size); skb->data[extnd_size + 4] = extnd_size; - status = adapter->host_intf_write_pkt(common->priv, - (u8 *)skb->data, - skb->len); + status = adapter->host_intf_ops->write_pkt(common->priv, + (u8 *)skb->data, + skb->len); if (status) { rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); @@ -203,9 +202,8 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, msg[7] |= cpu_to_le16(vap_id << 8); - status = adapter->host_intf_write_pkt(common->priv, - (u8 *)msg, - skb->len); + status = adapter->host_intf_ops->write_pkt(common->priv, (u8 *)msg, + skb->len); if (status) rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 39d94b38f0a0..bdbec8b27071 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -676,8 +676,6 @@ static int rsi_init_sdio_interface(struct rsi_hw *adapter, } sdio_release_host(pfunction); - adapter->host_intf_write_pkt = rsi_sdio_host_intf_write_pkt; - adapter->host_intf_read_pkt = rsi_sdio_host_intf_read_pkt; adapter->determine_event_timeout = rsi_sdio_determine_event_timeout; adapter->check_hw_queue_status = rsi_sdio_read_buffer_status_register; @@ -691,6 +689,13 @@ fail: return status; } +static struct rsi_host_intf_ops sdio_host_intf_ops = { + .write_pkt = rsi_sdio_host_intf_write_pkt, + .read_pkt = rsi_sdio_host_intf_read_pkt, + .read_reg_multiple = rsi_sdio_read_register_multiple, + .write_reg_multiple = rsi_sdio_write_register_multiple, +}; + /** * rsi_probe() - This function is called by kernel when the driver provided * Vendor and device IDs are matched. All the initialization @@ -713,6 +718,8 @@ static int rsi_probe(struct sdio_func *pfunction, __func__); return 1; } + adapter->rsi_host_intf = RSI_HOST_INTF_SDIO; + adapter->host_intf_ops = &sdio_host_intf_ops; if (rsi_init_sdio_interface(adapter, pfunction)) { rsi_dbg(ERR_ZONE, "%s: Failed to init sdio interface\n", diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 31f96f0f6e30..9000e09a4d7d 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -392,6 +392,12 @@ static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter, len); } +static struct rsi_host_intf_ops usb_host_intf_ops = { + .write_pkt = rsi_usb_host_intf_write_pkt, + .read_reg_multiple = rsi_usb_read_register_multiple, + .write_reg_multiple = rsi_usb_write_register_multiple, +}; + /** * rsi_deinit_usb_interface() - This function deinitializes the usb interface. * @adapter: Pointer to the adapter structure. @@ -457,9 +463,10 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, /* Initializing function callbacks */ adapter->rx_urb_submit = rsi_rx_urb_submit; - adapter->host_intf_write_pkt = rsi_usb_host_intf_write_pkt; adapter->check_hw_queue_status = rsi_usb_check_queue_status; adapter->determine_event_timeout = rsi_usb_event_timeout; + adapter->rsi_host_intf = RSI_HOST_INTF_USB; + adapter->host_intf_ops = &usb_host_intf_ops; rsi_init_event(&rsi_dev->rx_thread.event); status = rsi_create_kthread(common, &rsi_dev->rx_thread, diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 1d5904bc2c74..7fdeda7ae07c 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -209,6 +209,11 @@ struct rsi_common { u8 ant_in_use; }; +enum host_intf { + RSI_HOST_INTF_SDIO = 0, + RSI_HOST_INTF_USB +}; + struct rsi_hw { struct rsi_common *priv; struct ieee80211_hw *hw; @@ -219,16 +224,25 @@ struct rsi_hw { struct device *device; u8 sc_nvifs; + enum host_intf rsi_host_intf; #ifdef CONFIG_RSI_DEBUGFS struct rsi_debugfs *dfsentry; u8 num_debugfs_entries; #endif u8 dfs_region; void *rsi_dev; - int (*host_intf_read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); - int (*host_intf_write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); + struct rsi_host_intf_ops *host_intf_ops; int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num); int (*rx_urb_submit)(struct rsi_hw *adapter); int (*determine_event_timeout)(struct rsi_hw *adapter); }; + +struct rsi_host_intf_ops { + int (*read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); + int (*write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); + int (*read_reg_multiple)(struct rsi_hw *adapter, u32 addr, + u8 *data, u16 count); + int (*write_reg_multiple)(struct rsi_hw *adapter, u32 addr, + u8 *data, u16 count); +}; #endif -- cgit v1.2.3 From b97e9b94ad75caf8d9fcb6a20cd1e3d7f1e67ae8 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:15 +0530 Subject: rsi: Add new host interface operations Host interface opearation master_reg_read, master_reg_write and load_data_master_write are added. These functions are needed for the new firmware loading method. As part of this, the function master_access_msword is moved from rsi_91x_sdio_ops.c to rsi_91x_sdio.c. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 179 ++++++++++++++++++++++++++++ drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 3 +- drivers/net/wireless/rsi/rsi_91x_usb.c | 65 ++++++++++ drivers/net/wireless/rsi/rsi_main.h | 8 ++ drivers/net/wireless/rsi/rsi_sdio.h | 1 + 5 files changed, 254 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index bdbec8b27071..b397e2c2059d 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -552,6 +552,182 @@ int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, return status; } +static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, + u32 base_address, + u32 instructions_sz, + u16 block_size, + u8 *ta_firmware) +{ + u32 num_blocks, offset, i; + u16 msb_address, lsb_address; + u8 temp_buf[block_size]; + int status; + + num_blocks = instructions_sz / block_size; + msb_address = base_address >> 16; + + rsi_dbg(INFO_ZONE, "ins_size: %d, num_blocks: %d\n", + instructions_sz, num_blocks); + + /* Loading DM ms word in the sdio slave */ + status = rsi_sdio_master_access_msword(adapter, msb_address); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); + return status; + } + + for (offset = 0, i = 0; i < num_blocks; i++, offset += block_size) { + memset(temp_buf, 0, block_size); + memcpy(temp_buf, ta_firmware + offset, block_size); + lsb_address = (u16)base_address; + status = rsi_sdio_write_register_multiple + (adapter, + lsb_address | RSI_SD_REQUEST_MASTER, + temp_buf, block_size); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: failed to write\n", __func__); + return status; + } + rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i); + base_address += block_size; + + if ((base_address >> 16) != msb_address) { + msb_address += 1; + + /* Loading DM ms word in the sdio slave */ + status = rsi_sdio_master_access_msword(adapter, + msb_address); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word reg\n", + __func__); + return status; + } + } + } + + if (instructions_sz % block_size) { + memset(temp_buf, 0, block_size); + memcpy(temp_buf, ta_firmware + offset, + instructions_sz % block_size); + lsb_address = (u16)base_address; + status = rsi_sdio_write_register_multiple + (adapter, + lsb_address | RSI_SD_REQUEST_MASTER, + temp_buf, + instructions_sz % block_size); + if (status < 0) + return status; + rsi_dbg(INFO_ZONE, + "Written Last Block in Address 0x%x Successfully\n", + offset | RSI_SD_REQUEST_MASTER); + } + return 0; +} + +#define FLASH_SIZE_ADDR 0x04000016 +static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, + u32 *read_buf, u16 size) +{ + u32 addr_on_bus, *data; + u32 align[2] = {}; + u16 ms_addr; + int status; + + data = PTR_ALIGN(&align[0], 8); + + ms_addr = (addr >> 16); + status = rsi_sdio_master_access_msword(adapter, ms_addr); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word to common reg\n", + __func__); + return status; + } + addr &= 0xFFFF; + + addr_on_bus = (addr & 0xFF000000); + if ((addr_on_bus == (FLASH_SIZE_ADDR & 0xFF000000)) || + (addr_on_bus == 0x0)) + addr_on_bus = (addr & ~(0x3)); + else + addr_on_bus = addr; + + /* Bring TA out of reset */ + status = rsi_sdio_read_register_multiple + (adapter, + (addr_on_bus | RSI_SD_REQUEST_MASTER), + (u8 *)data, 4); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__); + return status; + } + if (size == 2) { + if ((addr & 0x3) == 0) + *read_buf = *data; + else + *read_buf = (*data >> 16); + *read_buf = (*read_buf & 0xFFFF); + } else if (size == 1) { + if ((addr & 0x3) == 0) + *read_buf = *data; + else if ((addr & 0x3) == 1) + *read_buf = (*data >> 8); + else if ((addr & 0x3) == 2) + *read_buf = (*data >> 16); + else + *read_buf = (*data >> 24); + *read_buf = (*read_buf & 0xFF); + } else { + *read_buf = *data; + } + + return 0; +} + +static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, + unsigned long addr, + unsigned long data, u16 size) +{ + unsigned long data1[2], *data_aligned; + int status; + + data_aligned = PTR_ALIGN(&data1[0], 8); + + if (size == 2) { + *data_aligned = ((data << 16) | (data & 0xFFFF)); + } else if (size == 1) { + u32 temp_data = data & 0xFF; + + *data_aligned = ((temp_data << 24) | (temp_data << 16) | + (temp_data << 8) | temp_data); + } else { + *data_aligned = data; + } + size = 4; + + status = rsi_sdio_master_access_msword(adapter, (addr >> 16)); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word to common reg\n", + __func__); + return -EIO; + } + addr = addr & 0xFFFF; + + /* Bring TA out of reset */ + status = rsi_sdio_write_register_multiple + (adapter, + (addr | RSI_SD_REQUEST_MASTER), + (u8 *)data_aligned, size); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to do AHB reg write\n", __func__); + return status; + } + return 0; +} + /** * rsi_sdio_host_intf_write_pkt() - This function writes the packet to device. * @adapter: Pointer to the adapter structure. @@ -694,6 +870,9 @@ static struct rsi_host_intf_ops sdio_host_intf_ops = { .read_pkt = rsi_sdio_host_intf_read_pkt, .read_reg_multiple = rsi_sdio_read_register_multiple, .write_reg_multiple = rsi_sdio_write_register_multiple, + .master_reg_read = rsi_sdio_master_reg_read, + .master_reg_write = rsi_sdio_master_reg_write, + .load_data_master_write = rsi_sdio_load_data_master_write, }; /** diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 7c9cf016188c..225042f675ca 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -27,8 +27,7 @@ * * Return: status: 0 on success, -1 on failure. */ -static int rsi_sdio_master_access_msword(struct rsi_hw *adapter, - u16 ms_word) +int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word) { u8 byte; u8 function = 0; diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 9000e09a4d7d..b10b145f8a2e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -392,10 +392,75 @@ static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter, len); } +static int rsi_usb_master_reg_read(struct rsi_hw *adapter, u32 reg, + u32 *value, u16 len) +{ + struct usb_device *usbdev = + ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev; + + return rsi_usb_reg_read(usbdev, reg, (u16 *)value, len); +} + +static int rsi_usb_master_reg_write(struct rsi_hw *adapter, + unsigned long reg, + unsigned long value, u16 len) +{ + struct usb_device *usbdev = + ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev; + + return rsi_usb_reg_write(usbdev, reg, value, len); +} + +static int rsi_usb_load_data_master_write(struct rsi_hw *adapter, + u32 base_address, + u32 instructions_sz, u16 block_size, + u8 *ta_firmware) +{ + u16 num_blocks; + u32 cur_indx, i; + u8 temp_buf[256]; + int status; + + num_blocks = instructions_sz / block_size; + rsi_dbg(INFO_ZONE, "num_blocks: %d\n", num_blocks); + + for (cur_indx = 0, i = 0; i < num_blocks; i++, cur_indx += block_size) { + memset(temp_buf, 0, block_size); + memcpy(temp_buf, ta_firmware + cur_indx, block_size); + status = rsi_usb_write_register_multiple(adapter, base_address, + (u8 *)(temp_buf), + block_size); + if (status < 0) + return status; + + rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i); + base_address += block_size; + } + + if (instructions_sz % block_size) { + memset(temp_buf, 0, block_size); + memcpy(temp_buf, ta_firmware + cur_indx, + instructions_sz % block_size); + status = rsi_usb_write_register_multiple + (adapter, base_address, + (u8 *)temp_buf, + instructions_sz % block_size); + if (status < 0) + return status; + rsi_dbg(INFO_ZONE, + "Written Last Block in Address 0x%x Successfully\n", + cur_indx); + } + return 0; +} + static struct rsi_host_intf_ops usb_host_intf_ops = { .write_pkt = rsi_usb_host_intf_write_pkt, .read_reg_multiple = rsi_usb_read_register_multiple, .write_reg_multiple = rsi_usb_write_register_multiple, + .master_reg_read = rsi_usb_master_reg_read, + .master_reg_write = rsi_usb_master_reg_write, + .load_data_master_write = rsi_usb_load_data_master_write, }; /** diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 7fdeda7ae07c..2ac5bcf87622 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -244,5 +244,13 @@ struct rsi_host_intf_ops { u8 *data, u16 count); int (*write_reg_multiple)(struct rsi_hw *adapter, u32 addr, u8 *data, u16 count); + int (*master_reg_read)(struct rsi_hw *adapter, u32 addr, + u32 *read_buf, u16 size); + int (*master_reg_write)(struct rsi_hw *adapter, + unsigned long addr, unsigned long data, + u16 size); + int (*load_data_master_write)(struct rsi_hw *adapter, u32 addr, + u32 instructions_size, u16 block_size, + u8 *fw); }; #endif diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index a82bc4c73f66..7ae6d516c99c 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -123,6 +123,7 @@ int rsi_sdio_write_register(struct rsi_hw *adapter, u8 function, u32 addr, u8 *data); int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr, u8 *data, u16 count); +int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word); void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit); int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter); int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num); -- cgit v1.2.3 From b78e91bcfb3347f4bc977b7b2799544f908d55d4 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:16 +0530 Subject: rsi: Add new firmware loading method The older firmware loading method has been deprecated and not in use for any chipets. New method is introduced which works based on soft boot loader. In this method, complete RAM image and FLASH image are present in the flash. Before loading the functional firmware, host issues boot loader commands to verify whether firmware to load is different from the current functional firmware. If not, firmware upgrade progresses and boot loader will switch to the new functional firmware. "rs9113_wlan_qspi.rps" is the firmware filename used in this patch. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 527 ++++++++++++++++++++++++++++++++ drivers/net/wireless/rsi/rsi_91x_sdio.c | 11 +- drivers/net/wireless/rsi/rsi_91x_usb.c | 16 +- drivers/net/wireless/rsi/rsi_hal.h | 81 +++++ drivers/net/wireless/rsi/rsi_main.h | 10 + 5 files changed, 635 insertions(+), 10 deletions(-) create mode 100644 drivers/net/wireless/rsi/rsi_hal.h (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 8fbf90498d65..d49dbaa14079 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -14,7 +14,16 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include "rsi_mgmt.h" +#include "rsi_hal.h" +#include "rsi_sdio.h" + +/* FLASH Firmware */ +static struct ta_metadata metadata_flash_content[] = { + {"flash_content", 0x00010000}, + {"rs9113_wlan_qspi.rps", 0x00010000}, +}; /** * rsi_send_data_pkt() - This function sends the recieved data packet from @@ -211,3 +220,521 @@ err: rsi_indicate_tx_status(common->priv, skb, status); return status; } + +static void bl_cmd_timeout(unsigned long priv) +{ + struct rsi_hw *adapter = (struct rsi_hw *)priv; + + adapter->blcmd_timer_expired = true; + del_timer(&adapter->bl_cmd_timer); +} + +static int bl_start_cmd_timer(struct rsi_hw *adapter, u32 timeout) +{ + init_timer(&adapter->bl_cmd_timer); + adapter->bl_cmd_timer.data = (unsigned long)adapter; + adapter->bl_cmd_timer.function = (void *)&bl_cmd_timeout; + adapter->bl_cmd_timer.expires = (msecs_to_jiffies(timeout) + jiffies); + + adapter->blcmd_timer_expired = false; + add_timer(&adapter->bl_cmd_timer); + + return 0; +} + +static int bl_stop_cmd_timer(struct rsi_hw *adapter) +{ + adapter->blcmd_timer_expired = false; + if (timer_pending(&adapter->bl_cmd_timer)) + del_timer(&adapter->bl_cmd_timer); + + return 0; +} + +static int bl_write_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, + u16 *cmd_resp) +{ + struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; + u32 regin_val = 0, regout_val = 0; + u32 regin_input = 0; + u8 output = 0; + int status; + + regin_input = (REGIN_INPUT | adapter->priv->coex_mode); + + while (!adapter->blcmd_timer_expired) { + regin_val = 0; + status = hif_ops->master_reg_read(adapter, SWBL_REGIN, + ®in_val, 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGIN reading failed..\n", + __func__, cmd); + return status; + } + mdelay(1); + if ((regin_val >> 12) != REGIN_VALID) + break; + } + if (adapter->blcmd_timer_expired) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGIN reading timed out..\n", + __func__, cmd); + return -ETIMEDOUT; + } + + rsi_dbg(INFO_ZONE, + "Issuing write to Regin val:%0x sending cmd:%0x\n", + regin_val, (cmd | regin_input << 8)); + status = hif_ops->master_reg_write(adapter, SWBL_REGIN, + (cmd | regin_input << 8), 2); + if (status < 0) + return status; + mdelay(1); + + if (cmd == LOAD_HOSTED_FW || cmd == JUMP_TO_ZERO_PC) { + /* JUMP_TO_ZERO_PC doesn't expect + * any response. So return from here + */ + return 0; + } + + while (!adapter->blcmd_timer_expired) { + regout_val = 0; + status = hif_ops->master_reg_read(adapter, SWBL_REGOUT, + ®out_val, 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGOUT reading failed..\n", + __func__, cmd); + return status; + } + mdelay(1); + if ((regout_val >> 8) == REGOUT_VALID) + break; + } + if (adapter->blcmd_timer_expired) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGOUT reading timed out..\n", + __func__, cmd); + return status; + } + + *cmd_resp = ((u16 *)®out_val)[0] & 0xffff; + + output = ((u8 *)®out_val)[0] & 0xff; + + status = hif_ops->master_reg_write(adapter, SWBL_REGOUT, + (cmd | REGOUT_INVALID << 8), 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Command %0x REGOUT writing failed..\n", + __func__, cmd); + return status; + } + mdelay(1); + + if (output != exp_resp) { + rsi_dbg(ERR_ZONE, + "%s: Recvd resp %x for cmd %0x\n", + __func__, output, cmd); + return -EINVAL; + } + rsi_dbg(INFO_ZONE, + "%s: Recvd Expected resp %x for cmd %0x\n", + __func__, output, cmd); + + return 0; +} + +static int bl_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, char *str) +{ + u16 regout_val = 0; + u32 timeout; + int status; + + if ((cmd == EOF_REACHED) || (cmd == PING_VALID) || (cmd == PONG_VALID)) + timeout = BL_BURN_TIMEOUT; + else + timeout = BL_CMD_TIMEOUT; + + bl_start_cmd_timer(adapter, timeout); + status = bl_write_cmd(adapter, cmd, exp_resp, ®out_val); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Command %s (%0x) writing failed..\n", + __func__, str, cmd); + return status; + } + bl_stop_cmd_timer(adapter); + return 0; +} + +#define CHECK_SUM_OFFSET 20 +#define LEN_OFFSET 8 +#define ADDR_OFFSET 16 +static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, + u32 content_size) +{ + struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; + struct bl_header bl_hdr; + u32 write_addr, write_len; + int status; + + bl_hdr.flags = 0; + bl_hdr.image_no = cpu_to_le32(adapter->priv->coex_mode); + bl_hdr.check_sum = cpu_to_le32( + *(u32 *)&flash_content[CHECK_SUM_OFFSET]); + bl_hdr.flash_start_address = cpu_to_le32( + *(u32 *)&flash_content[ADDR_OFFSET]); + bl_hdr.flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); + write_len = sizeof(struct bl_header); + + if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) { + write_addr = PING_BUFFER_ADDRESS; + status = hif_ops->write_reg_multiple(adapter, write_addr, + (u8 *)&bl_hdr, write_len); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to load Version/CRC structure\n", + __func__); + return status; + } + } else { + write_addr = PING_BUFFER_ADDRESS >> 16; + status = hif_ops->master_access_msword(adapter, write_addr); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word to common reg\n", + __func__); + return status; + } + write_addr = RSI_SD_REQUEST_MASTER | + (PING_BUFFER_ADDRESS & 0xFFFF); + status = hif_ops->write_reg_multiple(adapter, write_addr, + (u8 *)&bl_hdr, write_len); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to load Version/CRC structure\n", + __func__); + return status; + } + } + return 0; +} + +static u32 read_flash_capacity(struct rsi_hw *adapter) +{ + u32 flash_sz = 0; + + if ((adapter->host_intf_ops->master_reg_read(adapter, FLASH_SIZE_ADDR, + &flash_sz, 2)) < 0) { + rsi_dbg(ERR_ZONE, + "%s: Flash size reading failed..\n", + __func__); + return 0; + } + rsi_dbg(INIT_ZONE, "Flash capacity: %d KiloBytes\n", flash_sz); + + return (flash_sz * 1024); /* Return size in kbytes */ +} + +static int ping_pong_write(struct rsi_hw *adapter, u8 cmd, u8 *addr, u32 size) +{ + struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; + u32 block_size = adapter->block_size; + u32 cmd_addr; + u16 cmd_resp, cmd_req; + u8 *str; + int status; + + if (cmd == PING_WRITE) { + cmd_addr = PING_BUFFER_ADDRESS; + cmd_resp = PONG_AVAIL; + cmd_req = PING_VALID; + str = "PING_VALID"; + } else { + cmd_addr = PONG_BUFFER_ADDRESS; + cmd_resp = PING_AVAIL; + cmd_req = PONG_VALID; + str = "PONG_VALID"; + } + + status = hif_ops->load_data_master_write(adapter, cmd_addr, size, + block_size, addr); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Unable to write blk at addr %0x\n", + __func__, *addr); + return status; + } + + status = bl_cmd(adapter, cmd_req, cmd_resp, str); + if (status) { + bl_stop_cmd_timer(adapter); + return status; + } + return 0; +} + +static int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content, + u32 content_size) +{ + u8 cmd, *temp_flash_content; + u32 temp_content_size, num_flash, index; + u32 flash_start_address; + int status; + + temp_flash_content = flash_content; + + if (content_size > MAX_FLASH_FILE_SIZE) { + rsi_dbg(ERR_ZONE, + "%s: Flash Content size is more than 400K %u\n", + __func__, MAX_FLASH_FILE_SIZE); + return -EINVAL; + } + + flash_start_address = *(u32 *)&flash_content[FLASH_START_ADDRESS]; + rsi_dbg(INFO_ZONE, "flash start address: %08x\n", flash_start_address); + + if (flash_start_address < FW_IMAGE_MIN_ADDRESS) { + rsi_dbg(ERR_ZONE, + "%s: Fw image Flash Start Address is less than 64K\n", + __func__); + return -EINVAL; + } + + if (flash_start_address % FLASH_SECTOR_SIZE) { + rsi_dbg(ERR_ZONE, + "%s: Flash Start Address is not multiple of 4K\n", + __func__); + return -EINVAL; + } + + if ((flash_start_address + content_size) > adapter->flash_capacity) { + rsi_dbg(ERR_ZONE, + "%s: Flash Content will cross max flash size\n", + __func__); + return -EINVAL; + } + + temp_content_size = content_size; + num_flash = content_size / FLASH_WRITE_CHUNK_SIZE; + + rsi_dbg(INFO_ZONE, "content_size: %d, num_flash: %d\n", + content_size, num_flash); + + for (index = 0; index <= num_flash; index++) { + rsi_dbg(INFO_ZONE, "flash index: %d\n", index); + if (index != num_flash) { + content_size = FLASH_WRITE_CHUNK_SIZE; + rsi_dbg(INFO_ZONE, "QSPI content_size:%d\n", + content_size); + } else { + content_size = + temp_content_size % FLASH_WRITE_CHUNK_SIZE; + rsi_dbg(INFO_ZONE, + "Writing last sector content_size:%d\n", + content_size); + if (!content_size) { + rsi_dbg(INFO_ZONE, "instruction size zero\n"); + break; + } + } + + if (index % 2) + cmd = PING_WRITE; + else + cmd = PONG_WRITE; + + status = ping_pong_write(adapter, cmd, flash_content, + content_size); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Unable to load %d block\n", + __func__, index); + return status; + } + + rsi_dbg(INFO_ZONE, + "%s: Successfully loaded %d instructions\n", + __func__, index); + flash_content += content_size; + } + + status = bl_cmd(adapter, EOF_REACHED, FW_LOADING_SUCCESSFUL, + "EOF_REACHED"); + if (status) { + bl_stop_cmd_timer(adapter); + return status; + } + rsi_dbg(INFO_ZONE, "FW loading is done and FW is running..\n"); + return 0; +} + +static int rsi_load_firmware(struct rsi_hw *adapter) +{ + struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; + const struct firmware *fw_entry = NULL; + u32 regout_val = 0, content_size; + u16 tmp_regout_val = 0; + u8 *flash_content = NULL; + struct ta_metadata *metadata_p; + int status; + + bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT); + + while (!adapter->blcmd_timer_expired) { + status = hif_ops->master_reg_read(adapter, SWBL_REGOUT, + ®out_val, 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, + "%s: REGOUT read failed\n", __func__); + return status; + } + mdelay(1); + if ((regout_val >> 8) == REGOUT_VALID) + break; + } + if (adapter->blcmd_timer_expired) { + rsi_dbg(ERR_ZONE, "%s: REGOUT read timedout\n", __func__); + rsi_dbg(ERR_ZONE, + "%s: Soft boot loader not present\n", __func__); + return -ETIMEDOUT; + } + bl_stop_cmd_timer(adapter); + + rsi_dbg(INFO_ZONE, "Received Board Version Number: %x\n", + (regout_val & 0xff)); + + status = hif_ops->master_reg_write(adapter, SWBL_REGOUT, + (REGOUT_INVALID | REGOUT_INVALID << 8), + 2); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: REGOUT writing failed..\n", __func__); + return status; + } + mdelay(1); + + status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS, + "AUTO_READ_CMD"); + if (status < 0) + return status; + + adapter->flash_capacity = read_flash_capacity(adapter); + if (adapter->flash_capacity <= 0) { + rsi_dbg(ERR_ZONE, + "%s: Unable to read flash size from EEPROM\n", + __func__); + return -EINVAL; + } + + metadata_p = &metadata_flash_content[adapter->priv->coex_mode]; + + rsi_dbg(INIT_ZONE, "%s: Loading file %s\n", __func__, metadata_p->name); + adapter->fw_file_name = metadata_p->name; + + status = request_firmware(&fw_entry, metadata_p->name, adapter->device); + if (status < 0) { + rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n", + __func__, metadata_p->name); + return status; + } + flash_content = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + if (!flash_content) { + rsi_dbg(ERR_ZONE, "%s: Failed to copy firmware\n", __func__); + status = -EIO; + goto fail; + } + content_size = fw_entry->size; + rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", content_size); + + status = bl_write_header(adapter, flash_content, content_size); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: RPS Image header loading failed\n", + __func__); + goto fail; + } + + bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT); + status = bl_write_cmd(adapter, CHECK_CRC, CMD_PASS, &tmp_regout_val); + if (status) { + bl_stop_cmd_timer(adapter); + rsi_dbg(ERR_ZONE, + "%s: CHECK_CRC Command writing failed..\n", + __func__); + if ((tmp_regout_val & 0xff) == CMD_FAIL) { + rsi_dbg(ERR_ZONE, + "CRC Fail.. Proceeding to Upgrade mode\n"); + goto fw_upgrade; + } + } + bl_stop_cmd_timer(adapter); + + status = bl_cmd(adapter, POLLING_MODE, CMD_PASS, "POLLING_MODE"); + if (status) + goto fail; + +load_image_cmd: + status = bl_cmd(adapter, LOAD_HOSTED_FW, LOADING_INITIATED, + "LOAD_HOSTED_FW"); + if (status) + goto fail; + rsi_dbg(INFO_ZONE, "Load Image command passed..\n"); + goto success; + +fw_upgrade: + status = bl_cmd(adapter, BURN_HOSTED_FW, SEND_RPS_FILE, "FW_UPGRADE"); + if (status) + goto fail; + + rsi_dbg(INFO_ZONE, "Burn Command Pass.. Upgrading the firmware\n"); + + status = auto_fw_upgrade(adapter, flash_content, content_size); + if (status == 0) { + rsi_dbg(ERR_ZONE, "Firmware upgradation Done\n"); + goto load_image_cmd; + } + rsi_dbg(ERR_ZONE, "Firmware upgrade failed\n"); + + status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS, + "AUTO_READ_MODE"); + if (status) + goto fail; + +success: + rsi_dbg(ERR_ZONE, "***** Firmware Loading successful *****\n"); + kfree(flash_content); + release_firmware(fw_entry); + return 0; + +fail: + rsi_dbg(ERR_ZONE, "##### Firmware loading failed #####\n"); + kfree(flash_content); + release_firmware(fw_entry); + return status; +} + +int rsi_hal_device_init(struct rsi_hw *adapter) +{ + struct rsi_common *common = adapter->priv; + + common->coex_mode = 1; + adapter->device_model = RSI_DEV_9113; + + switch (adapter->device_model) { + case RSI_DEV_9113: + if (rsi_load_firmware(adapter)) { + rsi_dbg(ERR_ZONE, + "%s: Failed to load TA instructions\n", + __func__); + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rsi_hal_device_init); + diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index b397e2c2059d..2ef844adacf3 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -18,6 +18,7 @@ #include #include "rsi_sdio.h" #include "rsi_common.h" +#include "rsi_hal.h" /** * rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg. @@ -365,6 +366,7 @@ static int rsi_setblocklength(struct rsi_hw *adapter, u32 length) status = sdio_set_block_size(dev->pfunction, length); dev->pfunction->max_blksize = 256; + adapter->block_size = dev->pfunction->max_blksize; rsi_dbg(INFO_ZONE, "%s: Operational blk length is %d\n", __func__, length); @@ -868,6 +870,7 @@ fail: static struct rsi_host_intf_ops sdio_host_intf_ops = { .write_pkt = rsi_sdio_host_intf_write_pkt, .read_pkt = rsi_sdio_host_intf_read_pkt, + .master_access_msword = rsi_sdio_master_access_msword, .read_reg_multiple = rsi_sdio_read_register_multiple, .write_reg_multiple = rsi_sdio_write_register_multiple, .master_reg_read = rsi_sdio_master_reg_read, @@ -906,13 +909,19 @@ static int rsi_probe(struct sdio_func *pfunction, goto fail; } - if (rsi_sdio_device_init(adapter->priv)) { + if (rsi_hal_device_init(adapter)) { rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); sdio_claim_host(pfunction); sdio_disable_func(pfunction); sdio_release_host(pfunction); goto fail; } + rsi_dbg(INFO_ZONE, "===> RSI Device Init Done <===\n"); + + if (rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR)) { + rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); + return -EIO; + } sdio_claim_host(pfunction); if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index b10b145f8a2e..72c7f3a2fbf2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -17,6 +17,7 @@ #include #include "rsi_usb.h" +#include "rsi_hal.h" /** * rsi_usb_card_write() - This function writes to the USB Card. @@ -525,6 +526,7 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter, } rsi_dev->rx_usb_urb[0]->transfer_buffer = adapter->priv->rx_data_pkt; rsi_dev->tx_blk_size = 252; + adapter->block_size = rsi_dev->tx_blk_size; /* Initializing function callbacks */ adapter->rx_urb_submit = rsi_rx_urb_submit; @@ -583,6 +585,7 @@ static int rsi_probe(struct usb_interface *pfunction, __func__); return -ENOMEM; } + adapter->rsi_host_intf = RSI_HOST_INTF_USB; status = rsi_init_usb_interface(adapter, pfunction); if (status) { @@ -596,25 +599,20 @@ static int rsi_probe(struct usb_interface *pfunction, dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; status = rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2); - if (status) + if (status < 0) goto err1; else fw_status &= 1; if (!fw_status) { - status = rsi_usb_device_init(adapter->priv); + rsi_dbg(INIT_ZONE, "Loading firmware...\n"); + status = rsi_hal_device_init(adapter); if (status) { rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); goto err1; } - - status = rsi_usb_reg_write(dev->usbdev, - USB_INTERNAL_REG_1, - RSI_USB_READY_MAGIC_NUM, 1); - if (status) - goto err1; - rsi_dbg(INIT_ZONE, "%s: Performed device init\n", __func__); + rsi_dbg(INIT_ZONE, "%s: Device Init Done\n", __func__); } status = rsi_rx_urb_submit(adapter); diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h new file mode 100644 index 000000000000..b95200df5b0f --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2017 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __RSI_HAL_H__ +#define __RSI_HAL_H__ + +#define FLASH_WRITE_CHUNK_SIZE (4 * 1024) +#define FLASH_SECTOR_SIZE (4 * 1024) + +#define FLASH_SIZE_ADDR 0x04000016 +#define PING_BUFFER_ADDRESS 0x19000 +#define PONG_BUFFER_ADDRESS 0x1a000 +#define SWBL_REGIN 0x41050034 +#define SWBL_REGOUT 0x4105003c +#define PING_WRITE 0x1 +#define PONG_WRITE 0x2 + +#define BL_CMD_TIMEOUT 2000 +#define BL_BURN_TIMEOUT (50 * 1000) + +#define REGIN_VALID 0xA +#define REGIN_INPUT 0xA0 +#define REGOUT_VALID 0xAB +#define REGOUT_INVALID (~0xAB) +#define CMD_PASS 0xAA +#define CMD_FAIL 0xCC + +#define LOAD_HOSTED_FW 'A' +#define BURN_HOSTED_FW 'B' +#define PING_VALID 'I' +#define PONG_VALID 'O' +#define PING_AVAIL 'I' +#define PONG_AVAIL 'O' +#define EOF_REACHED 'E' +#define CHECK_CRC 'K' +#define POLLING_MODE 'P' +#define CONFIG_AUTO_READ_MODE 'R' +#define JUMP_TO_ZERO_PC 'J' +#define FW_LOADING_SUCCESSFUL 'S' +#define LOADING_INITIATED '1' + +/* Boot loader commands */ +#define SEND_RPS_FILE '2' + +#define FW_IMAGE_MIN_ADDRESS (68 * 1024) +#define MAX_FLASH_FILE_SIZE (400 * 1024) //400K +#define FLASH_START_ADDRESS 16 + +#define COMMON_HAL_CARD_READY_IND 0x0 + +#define COMMAN_HAL_WAIT_FOR_CARD_READY 1 + +struct bl_header { + __le32 flags; + __le32 image_no; + __le32 check_sum; + __le32 flash_start_address; + __le32 flash_len; +} __packed; + +struct ta_metadata { + char *name; + unsigned int address; +}; + +int rsi_hal_device_init(struct rsi_hw *adapter); + +#endif diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 2ac5bcf87622..ea4fc223cea7 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -82,6 +82,8 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); ((_q) == VI_Q) ? IEEE80211_AC_VI : \ IEEE80211_AC_VO) +#define RSI_DEV_9113 1 + struct version_info { u16 major; u16 minor; @@ -204,6 +206,7 @@ struct rsi_common { struct cqm_info cqm_info; bool hw_data_qs_blocked; + u8 coex_mode; int tx_power; u8 ant_in_use; @@ -216,6 +219,7 @@ enum host_intf { struct rsi_hw { struct rsi_common *priv; + u8 device_model; struct ieee80211_hw *hw; struct ieee80211_vif *vifs[RSI_MAX_VIFS]; struct ieee80211_tx_queue_params edca_params[NUM_EDCA_QUEUES]; @@ -225,10 +229,15 @@ struct rsi_hw { u8 sc_nvifs; enum host_intf rsi_host_intf; + u16 block_size; #ifdef CONFIG_RSI_DEBUGFS struct rsi_debugfs *dfsentry; u8 num_debugfs_entries; #endif + char *fw_file_name; + struct timer_list bl_cmd_timer; + bool blcmd_timer_expired; + u32 flash_capacity; u8 dfs_region; void *rsi_dev; struct rsi_host_intf_ops *host_intf_ops; @@ -240,6 +249,7 @@ struct rsi_hw { struct rsi_host_intf_ops { int (*read_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); int (*write_pkt)(struct rsi_hw *adapter, u8 *pkt, u32 len); + int (*master_access_msword)(struct rsi_hw *adapter, u16 ms_word); int (*read_reg_multiple)(struct rsi_hw *adapter, u32 addr, u8 *data, u16 count); int (*write_reg_multiple)(struct rsi_hw *adapter, u32 addr, -- cgit v1.2.3 From 5578b1ffdc3091dd0ae164b056fd1224fb00f1e9 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Tue, 16 May 2017 15:31:17 +0530 Subject: rsi: Remove old firmware loading method The older firmware loading method is not usable by any Redpine chipset. Hence removing that part of the code. Older firmware image with rsi_91x.fw name is deprecated Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 187 ---------------------------- drivers/net/wireless/rsi/rsi_91x_usb.c | 6 +- drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 126 ------------------- drivers/net/wireless/rsi/rsi_common.h | 3 +- drivers/net/wireless/rsi/rsi_sdio.h | 1 - drivers/net/wireless/rsi/rsi_usb.h | 3 - 6 files changed, 3 insertions(+), 323 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 225042f675ca..df2a63b1f15c 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -59,171 +59,6 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word) return status; } -/** - * rsi_copy_to_card() - This function includes the actual funtionality of - * copying the TA firmware to the card.Basically this - * function includes opening the TA file,reading the - * TA file and writing their values in blocks of data. - * @common: Pointer to the driver private structure. - * @fw: Pointer to the firmware value to be written. - * @len: length of firmware file. - * @num_blocks: Number of blocks to be written to the card. - * - * Return: 0 on success and -1 on failure. - */ -static int rsi_copy_to_card(struct rsi_common *common, - const u8 *fw, - u32 len, - u16 num_blocks) -{ - struct rsi_hw *adapter = common->priv; - struct rsi_91x_sdiodev *dev = - (struct rsi_91x_sdiodev *)adapter->rsi_dev; - u32 indx, ii; - u16 block_size = dev->tx_blk_size; - u32 lsb_address; - __le32 data[] = { TA_HOLD_THREAD_VALUE, TA_SOFT_RST_CLR, - TA_PC_ZERO, TA_RELEASE_THREAD_VALUE }; - u32 address[] = { TA_HOLD_THREAD_REG, TA_SOFT_RESET_REG, - TA_TH0_PC_REG, TA_RELEASE_THREAD_REG }; - u32 base_address; - u16 msb_address; - - base_address = TA_LOAD_ADDRESS; - msb_address = base_address >> 16; - - for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) { - lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER); - if (rsi_sdio_write_register_multiple(adapter, - lsb_address, - (u8 *)(fw + indx), - block_size)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to load %s blk\n", __func__, - FIRMWARE_RSI9113); - return -1; - } - rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii); - base_address += block_size; - if ((base_address >> 16) != msb_address) { - msb_address += 1; - if (rsi_sdio_master_access_msword(adapter, - msb_address)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to set ms word reg\n", - __func__); - return -1; - } - } - } - - if (len % block_size) { - lsb_address = ((u16) base_address | RSI_SD_REQUEST_MASTER); - if (rsi_sdio_write_register_multiple(adapter, - lsb_address, - (u8 *)(fw + indx), - len % block_size)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to load f/w\n", __func__); - return -1; - } - } - rsi_dbg(INIT_ZONE, - "%s: Succesfully loaded TA instructions\n", __func__); - - if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to set ms word to common reg\n", - __func__); - return -1; - } - - for (ii = 0; ii < ARRAY_SIZE(data); ii++) { - /* Bringing TA out of reset */ - if (rsi_sdio_write_register_multiple(adapter, - (address[ii] | - RSI_SD_REQUEST_MASTER), - (u8 *)&data[ii], - 4)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to hold TA threads\n", __func__); - return -1; - } - } - - rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__); - return 0; -} - -/** - * rsi_load_ta_instructions() - This function includes the actual funtionality - * of loading the TA firmware.This function also - * includes opening the TA file,reading the TA - * file and writing their value in blocks of data. - * @common: Pointer to the driver private structure. - * - * Return: status: 0 on success, -1 on failure. - */ -static int rsi_load_ta_instructions(struct rsi_common *common) -{ - struct rsi_hw *adapter = common->priv; - struct rsi_91x_sdiodev *dev = - (struct rsi_91x_sdiodev *)adapter->rsi_dev; - u32 len; - u16 num_blocks; - const u8 *fw; - const struct firmware *fw_entry = NULL; - u16 block_size = dev->tx_blk_size; - int status = 0; - u32 base_address; - u16 msb_address; - - if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to set ms word to common reg\n", - __func__); - return -1; - } - base_address = TA_LOAD_ADDRESS; - msb_address = (base_address >> 16); - - if (rsi_sdio_master_access_msword(adapter, msb_address)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to set ms word reg\n", __func__); - return -1; - } - - status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device); - if (status < 0) { - rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n", - __func__, FIRMWARE_RSI9113); - return status; - } - - /* Copy firmware into DMA-accessible memory */ - fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); - if (!fw) { - status = -ENOMEM; - goto out; - } - len = fw_entry->size; - - if (len % 4) - len += (4 - (len % 4)); - - num_blocks = (len / block_size); - - rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); - rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); - - status = rsi_copy_to_card(common, fw, len, num_blocks); - kfree(fw); - -out: - release_firmware(fw_entry); - return status; -} - /** * rsi_process_pkt() - This Function reads rx_blocks register and figures out * the size of the rx pkt. @@ -470,28 +305,6 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) } while (1); } -/** - * rsi_device_init() - This Function Initializes The HAL. - * @common: Pointer to the driver private structure. - * - * Return: 0 on success, -1 on failure. - */ -int rsi_sdio_device_init(struct rsi_common *common) -{ - if (rsi_load_ta_instructions(common)) - return -1; - - if (rsi_sdio_master_access_msword(common->priv, MISC_CFG_BASE_ADDR)) { - rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", - __func__); - return -1; - } - rsi_dbg(INIT_ZONE, - "%s: Setting ms word to 0x41050000\n", __func__); - - return 0; -} - /** * rsi_sdio_read_buffer_status_register() - This function is used to the read * buffer status register and set diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 72c7f3a2fbf2..f5de6934f7ec 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -327,10 +327,8 @@ static int rsi_usb_read_register_multiple(struct rsi_hw *adapter, u32 addr, * * Return: status: 0 on success, a negative error code on failure. */ -int rsi_usb_write_register_multiple(struct rsi_hw *adapter, - u32 addr, - u8 *data, - u16 count) +static int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, + u8 *data, u16 count) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; u8 *buf; diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index 1c3e65433ceb..d3e0a07604a6 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -18,67 +18,6 @@ #include #include "rsi_usb.h" -/** - * rsi_copy_to_card() - This function includes the actual funtionality of - * copying the TA firmware to the card.Basically this - * function includes opening the TA file,reading the TA - * file and writing their values in blocks of data. - * @common: Pointer to the driver private structure. - * @fw: Pointer to the firmware value to be written. - * @len: length of firmware file. - * @num_blocks: Number of blocks to be written to the card. - * - * Return: 0 on success and -1 on failure. - */ -static int rsi_copy_to_card(struct rsi_common *common, - const u8 *fw, - u32 len, - u16 num_blocks) -{ - struct rsi_hw *adapter = common->priv; - struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; - u32 indx, ii; - u16 block_size = dev->tx_blk_size; - u32 lsb_address; - u32 base_address; - - base_address = TA_LOAD_ADDRESS; - - for (indx = 0, ii = 0; ii < num_blocks; ii++, indx += block_size) { - lsb_address = base_address; - if (rsi_usb_write_register_multiple(adapter, - lsb_address, - (u8 *)(fw + indx), - block_size)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to load %s blk\n", __func__, - FIRMWARE_RSI9113); - return -EIO; - } - rsi_dbg(INIT_ZONE, "%s: loading block: %d\n", __func__, ii); - base_address += block_size; - } - - if (len % block_size) { - lsb_address = base_address; - if (rsi_usb_write_register_multiple(adapter, - lsb_address, - (u8 *)(fw + indx), - len % block_size)) { - rsi_dbg(ERR_ZONE, - "%s: Unable to load %s blk\n", __func__, - FIRMWARE_RSI9113); - return -EIO; - } - } - rsi_dbg(INIT_ZONE, - "%s: Succesfully loaded %s instructions\n", __func__, - FIRMWARE_RSI9113); - - rsi_dbg(INIT_ZONE, "%s: loaded firmware\n", __func__); - return 0; -} - /** * rsi_usb_rx_thread() - This is a kernel thread to receive the packets from * the USB device. @@ -119,68 +58,3 @@ out: complete_and_exit(&dev->rx_thread.completion, 0); } - -/** - * rsi_load_ta_instructions() - This function includes the actual funtionality - * of loading the TA firmware.This function also - * includes opening the TA file,reading the TA - * file and writing their value in blocks of data. - * @common: Pointer to the driver private structure. - * - * Return: status: 0 on success, -1 on failure. - */ -static int rsi_load_ta_instructions(struct rsi_common *common) -{ - struct rsi_hw *adapter = common->priv; - struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; - const struct firmware *fw_entry = NULL; - u16 block_size = dev->tx_blk_size; - const u8 *fw; - u16 num_blocks; - u32 len; - int status = 0; - - status = request_firmware(&fw_entry, FIRMWARE_RSI9113, adapter->device); - if (status < 0) { - rsi_dbg(ERR_ZONE, "%s Firmware file %s not found\n", - __func__, FIRMWARE_RSI9113); - return status; - } - - /* Copy firmware into DMA-accessible memory */ - fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); - if (!fw) { - status = -ENOMEM; - goto out; - } - len = fw_entry->size; - - if (len % 4) - len += (4 - (len % 4)); - - num_blocks = (len / block_size); - - rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); - rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); - - status = rsi_copy_to_card(common, fw, len, num_blocks); - kfree(fw); - -out: - release_firmware(fw_entry); - return status; -} - -/** - * rsi_device_init() - This Function Initializes The HAL. - * @common: Pointer to the driver private structure. - * - * Return: 0 on success, -1 on failure. - */ -int rsi_usb_device_init(struct rsi_common *common) -{ - if (rsi_load_ta_instructions(common)) - return -EIO; - - return 0; - } diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index d3fbe33d2324..44349696f5de 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -20,8 +20,7 @@ #include #define EVENT_WAIT_FOREVER 0 -#define TA_LOAD_ADDRESS 0x00 -#define FIRMWARE_RSI9113 "rsi_91x.fw" +#define FIRMWARE_RSI9113 "rs9113_wlan_qspi.rps" #define QUEUE_NOT_FULL 1 #define QUEUE_FULL 0 diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index 7ae6d516c99c..9fb73f68282a 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -116,7 +116,6 @@ struct rsi_91x_sdiodev { void rsi_interrupt_handler(struct rsi_hw *adapter); int rsi_init_sdio_slave_regs(struct rsi_hw *adapter); -int rsi_sdio_device_init(struct rsi_common *common); int rsi_sdio_read_register(struct rsi_hw *adapter, u32 addr, u8 *data); int rsi_sdio_host_intf_read_pkt(struct rsi_hw *adapter, u8 *pkt, u32 length); int rsi_sdio_write_register(struct rsi_hw *adapter, u8 function, diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h index d1e01bcf772b..59513ac61fb3 100644 --- a/drivers/net/wireless/rsi/rsi_usb.h +++ b/drivers/net/wireless/rsi/rsi_usb.h @@ -63,8 +63,5 @@ static inline int rsi_usb_event_timeout(struct rsi_hw *adapter) return EVENT_WAIT_FOREVER; } -int rsi_usb_device_init(struct rsi_common *common); -int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, - u8 *data, u16 count); void rsi_usb_rx_thread(struct rsi_common *common); #endif -- cgit v1.2.3 From c07036f18d93a0703a18a9a9a658d830110a10d8 Mon Sep 17 00:00:00 2001 From: Karim Eshapa Date: Tue, 9 May 2017 00:34:10 +0200 Subject: rsi: rsi_91x_core: Use time_after time comparison Use time_after kernel macro for time comparison. Signed-off-by: Karim Eshapa Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index f3d3995d8f6b..68f04a76769e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -306,7 +306,7 @@ void rsi_core_qos_processor(struct rsi_common *common) tstamp_2 = jiffies; mutex_unlock(&common->tx_rxlock); - if (tstamp_2 > tstamp_1 + (300 * HZ / 1000)) + if (time_after(tstamp_2, tstamp_1 + (300 * HZ) / 1000)) schedule(); } } -- cgit v1.2.3 From 4a4274bf2dbbd1c7a45be0c89a1687c9d2eef4a0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 11 May 2017 13:52:09 +0200 Subject: wlcore: fix 64K page support In the stable linux-3.16 branch, I ran into a warning in the wlcore driver: drivers/net/wireless/ti/wlcore/spi.c: In function 'wl12xx_spi_raw_write': drivers/net/wireless/ti/wlcore/spi.c:315:1: error: the frame size of 12848 bytes is larger than 2048 bytes [-Werror=frame-larger-than=] Newer kernels no longer show the warning, but the bug is still there, as the allocation is based on the CPU page size rather than the actual capabilities of the hardware. This replaces the PAGE_SIZE macro with the SZ_4K macro, i.e. 4096 bytes per buffer. Cc: stable@vger.kernel.org Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index f949ad2bd898..fa3547e06424 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -70,10 +70,10 @@ #define WSPI_MAX_CHUNK_SIZE 4092 /* - * wl18xx driver aggregation buffer size is (13 * PAGE_SIZE) compared to - * (4 * PAGE_SIZE) for wl12xx, so use the larger buffer needed for wl18xx + * wl18xx driver aggregation buffer size is (13 * 4K) compared to + * (4 * 4K) for wl12xx, so use the larger buffer needed for wl18xx */ -#define SPI_AGGR_BUFFER_SIZE (13 * PAGE_SIZE) +#define SPI_AGGR_BUFFER_SIZE (13 * SZ_4K) /* Maximum number of SPI write chunks */ #define WSPI_MAX_NUM_OF_CHUNKS \ -- cgit v1.2.3 From 438f3d13da5e0714f1add1652865b864a2c36eb7 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 15 May 2017 11:28:26 +0200 Subject: iwlegacy: warn when enabling power save iwlegacy firmware can crash when power save is configured. PS was allowed in "dbdac2b iwlegacy: properly enable power saving" with belive that user who enable PS is aware of that and can relate firmware crahes with PS. However some distributions seems to enable PS without user intervention, so warn about that. Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlegacy/common.c | 2 ++ drivers/net/wireless/intel/iwlegacy/common.h | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 140b6ea8f7cc..8d5acda92a9b 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5147,6 +5147,8 @@ set_ch_out: if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) { il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS); + if (!il->power_data.ps_disabled) + IL_WARN_ONCE("Enabling power save might cause firmware crashes\n"); ret = il_power_update_mode(il, false); if (ret) D_MAC80211("Error setting sleep level\n"); diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h index 3bba521d2cd9..18c60c92e3a3 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.h +++ b/drivers/net/wireless/intel/iwlegacy/common.h @@ -45,6 +45,7 @@ struct il_tx_queue; #define IL_ERR(f, a...) dev_err(&il->pci_dev->dev, f, ## a) #define IL_WARN(f, a...) dev_warn(&il->pci_dev->dev, f, ## a) +#define IL_WARN_ONCE(f, a...) dev_warn_once(&il->pci_dev->dev, f, ## a) #define IL_INFO(f, a...) dev_info(&il->pci_dev->dev, f, ## a) #define RX_QUEUE_SIZE 256 -- cgit v1.2.3 From 12e3c0433e8a3b817fbb978a1be973a04cd5d6f3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 15 May 2017 14:26:40 -0700 Subject: libertas: Avoid reading past end of buffer Using memcpy() from a string that is shorter than the length copied means the destination buffer is being filled with arbitrary data from the kernel rodata segment. Instead, redefine the stat strings to be ETH_GSTRING_LEN sizes, like other drivers. This lets us use a single memcpy that does not leak rodata contents. Additionally adjust indentation to keep checkpatch.pl happy. This was found with the future CONFIG_FORTIFY_SOURCE feature. Cc: Daniel Micay Signed-off-by: Kees Cook Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/mesh.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c index d0c881dd5846..2229fb448189 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.c +++ b/drivers/net/wireless/marvell/libertas/mesh.c @@ -1108,15 +1108,15 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, * Ethtool related */ -static const char * const mesh_stat_strings[] = { - "drop_duplicate_bcast", - "drop_ttl_zero", - "drop_no_fwd_route", - "drop_no_buffers", - "fwded_unicast_cnt", - "fwded_bcast_cnt", - "drop_blind_table", - "tx_failed_cnt" +static const char mesh_stat_strings[MESH_STATS_NUM][ETH_GSTRING_LEN] = { + "drop_duplicate_bcast", + "drop_ttl_zero", + "drop_no_fwd_route", + "drop_no_buffers", + "fwded_unicast_cnt", + "fwded_bcast_cnt", + "drop_blind_table", + "tx_failed_cnt" }; void lbs_mesh_ethtool_get_stats(struct net_device *dev, @@ -1170,17 +1170,11 @@ int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset) void lbs_mesh_ethtool_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *s) { - int i; - lbs_deb_enter(LBS_DEB_ETHTOOL); switch (stringset) { case ETH_SS_STATS: - for (i = 0; i < MESH_STATS_NUM; i++) { - memcpy(s + i * ETH_GSTRING_LEN, - mesh_stat_strings[i], - ETH_GSTRING_LEN); - } + memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings)); break; } lbs_deb_enter(LBS_DEB_ETHTOOL); -- cgit v1.2.3 From 4bc606af9fab7d5e3c6f2a333b290f9dce89c19a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 15 May 2017 14:33:17 -0700 Subject: libertas: Remove function entry/exit debugging In at least one place, the enter/exit debugging was not being correctly matched. Based on mailing list feedback, it was desired to drop all of these in favor of using ftrace instead. Suggested-by: Joe Perches Suggested-by: Kalle Valo Signed-off-by: Kees Cook Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/cfg.c | 104 +-------------------- drivers/net/wireless/marvell/libertas/cmd.c | 116 ++---------------------- drivers/net/wireless/marvell/libertas/cmdresp.c | 9 -- drivers/net/wireless/marvell/libertas/defs.h | 9 -- drivers/net/wireless/marvell/libertas/ethtool.c | 3 - drivers/net/wireless/marvell/libertas/if_cs.c | 36 -------- drivers/net/wireless/marvell/libertas/if_sdio.c | 66 +------------- drivers/net/wireless/marvell/libertas/if_spi.c | 38 ++------ drivers/net/wireless/marvell/libertas/if_usb.c | 27 +----- drivers/net/wireless/marvell/libertas/main.c | 81 +---------------- drivers/net/wireless/marvell/libertas/mesh.c | 28 ------ drivers/net/wireless/marvell/libertas/rx.c | 6 -- drivers/net/wireless/marvell/libertas/tx.c | 3 - 13 files changed, 24 insertions(+), 502 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index a0463fef79b0..71ba2c8d09b5 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -443,17 +443,12 @@ static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy, struct lbs_private *priv = wiphy_priv(wiphy); int ret = -ENOTSUPP; - lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", - chandef->chan->center_freq, - cfg80211_get_chandef_type(chandef)); - if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT) goto out; ret = lbs_set_channel(priv, chandef->chan->hw_value); out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -464,16 +459,12 @@ static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy, struct lbs_private *priv = wiphy_priv(wiphy); int ret = -ENOTSUPP; - lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d", - netdev_name(netdev), channel->center_freq); - if (netdev != priv->mesh_dev) goto out; ret = lbs_mesh_set_channel(priv, channel->hw_value); out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -512,8 +503,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, int i; int ret = -EILSEQ; - lbs_deb_enter(LBS_DEB_CFG80211); - bsssize = get_unaligned_le16(&scanresp->bssdescriptsize); lbs_deb_scan("scan response: %d BSSs (%d bytes); resp size %d bytes\n", @@ -665,7 +654,6 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, ret = 0; done: - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } @@ -693,11 +681,9 @@ static void lbs_scan_worker(struct work_struct *work) int last_channel; int running, carrier; - lbs_deb_enter(LBS_DEB_SCAN); - scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL); if (scan_cmd == NULL) - goto out_no_scan_cmd; + return; /* prepare fixed part of scan command */ scan_cmd->bsstype = CMD_BSS_TYPE_ANY; @@ -766,16 +752,11 @@ static void lbs_scan_worker(struct work_struct *work) lbs_deb_scan("scan: waking up waiters\n"); wake_up_all(&priv->scan_q); } - - out_no_scan_cmd: - lbs_deb_leave(LBS_DEB_SCAN); } static void _internal_start_scan(struct lbs_private *priv, bool internal, struct cfg80211_scan_request *request) { - lbs_deb_enter(LBS_DEB_CFG80211); - lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n", request->n_ssids, request->n_channels, request->ie_len); @@ -785,8 +766,6 @@ static void _internal_start_scan(struct lbs_private *priv, bool internal, queue_delayed_work(priv->work_thread, &priv->scan_work, msecs_to_jiffies(50)); - - lbs_deb_leave(LBS_DEB_CFG80211); } /* @@ -815,8 +794,6 @@ static int lbs_cfg_scan(struct wiphy *wiphy, struct lbs_private *priv = wiphy_priv(wiphy); int ret = 0; - lbs_deb_enter(LBS_DEB_CFG80211); - if (priv->scan_req || delayed_work_pending(&priv->scan_work)) { /* old scan request not yet processed */ ret = -EAGAIN; @@ -829,7 +806,6 @@ static int lbs_cfg_scan(struct wiphy *wiphy, ret = -EIO; out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -843,18 +819,12 @@ static int lbs_cfg_scan(struct wiphy *wiphy, void lbs_send_disconnect_notification(struct lbs_private *priv, bool locally_generated) { - lbs_deb_enter(LBS_DEB_CFG80211); - cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated, GFP_KERNEL); - - lbs_deb_leave(LBS_DEB_CFG80211); } void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) { - lbs_deb_enter(LBS_DEB_CFG80211); - cfg80211_michael_mic_failure(priv->dev, priv->assoc_bss, event == MACREG_INT_CODE_MIC_ERR_MULTICAST ? @@ -863,8 +833,6 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) -1, NULL, GFP_KERNEL); - - lbs_deb_leave(LBS_DEB_CFG80211); } @@ -883,8 +851,6 @@ static int lbs_remove_wep_keys(struct lbs_private *priv) struct cmd_ds_802_11_set_wep cmd; int ret; - lbs_deb_enter(LBS_DEB_CFG80211); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.keyindex = cpu_to_le16(priv->wep_tx_key); @@ -892,7 +858,6 @@ static int lbs_remove_wep_keys(struct lbs_private *priv) ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); - lbs_deb_leave(LBS_DEB_CFG80211); return ret; } @@ -905,8 +870,6 @@ static int lbs_set_wep_keys(struct lbs_private *priv) int i; int ret; - lbs_deb_enter(LBS_DEB_CFG80211); - /* * command 13 00 * size 50 00 @@ -956,7 +919,6 @@ static int lbs_set_wep_keys(struct lbs_private *priv) ret = lbs_remove_wep_keys(priv); } - lbs_deb_leave(LBS_DEB_CFG80211); return ret; } @@ -969,8 +931,6 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable) struct cmd_ds_802_11_enable_rsn cmd; int ret; - lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable); - /* * cmd 2f 00 * size 0c 00 @@ -986,7 +946,6 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable) ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd); - lbs_deb_leave(LBS_DEB_CFG80211); return ret; } @@ -1014,8 +973,6 @@ static int lbs_set_key_material(struct lbs_private *priv, struct cmd_key_material cmd; int ret; - lbs_deb_enter(LBS_DEB_CFG80211); - /* * Example for WPA (TKIP): * @@ -1044,7 +1001,6 @@ static int lbs_set_key_material(struct lbs_private *priv, ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); - lbs_deb_leave(LBS_DEB_CFG80211); return ret; } @@ -1061,8 +1017,6 @@ static int lbs_set_authtype(struct lbs_private *priv, struct cmd_ds_802_11_authenticate cmd; int ret; - lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type); - /* * cmd 11 00 * size 19 00 @@ -1085,7 +1039,6 @@ static int lbs_set_authtype(struct lbs_private *priv, ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); done: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1116,8 +1069,6 @@ static int lbs_associate(struct lbs_private *priv, u8 *pos; u8 *tmp; - lbs_deb_enter(LBS_DEB_CFG80211); - if (!cmd) { ret = -ENOMEM; goto done; @@ -1262,7 +1213,6 @@ static int lbs_associate(struct lbs_private *priv, kfree(cmd); done: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1329,8 +1279,6 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, if (dev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - if (!sme->bssid) { struct cfg80211_scan_request *creq; @@ -1442,7 +1390,6 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, done: if (bss) cfg80211_put_bss(wiphy, bss); - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1478,8 +1425,6 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, if (dev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code); - /* store for lbs_cfg_ret_disconnect() */ priv->disassoc_reason = reason_code; @@ -1496,8 +1441,6 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy, if (netdev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - if (key_index != priv->wep_tx_key) { lbs_deb_assoc("set_default_key: to %d\n", key_index); priv->wep_tx_key = key_index; @@ -1520,8 +1463,6 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, if (netdev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n", params->cipher, mac_addr); lbs_deb_assoc("add_key: key index %d, key len %d\n", @@ -1575,8 +1516,6 @@ static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr) { - lbs_deb_enter(LBS_DEB_CFG80211); - lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n", key_index, mac_addr); @@ -1619,8 +1558,6 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, int ret; size_t i; - lbs_deb_enter(LBS_DEB_CFG80211); - sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) | BIT(NL80211_STA_INFO_TX_PACKETS) | BIT(NL80211_STA_INFO_RX_BYTES) | @@ -1675,15 +1612,12 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, return -EOPNOTSUPP; } - lbs_deb_enter(LBS_DEB_CFG80211); - if (priv->iface_running) ret = lbs_set_iface_type(priv, type); if (!ret) priv->wdev->iftype = type; - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1713,8 +1647,6 @@ static void lbs_join_post(struct lbs_private *priv, u8 *fake = fake_ie; struct cfg80211_bss *bss; - lbs_deb_enter(LBS_DEB_CFG80211); - /* * For cfg80211_inform_bss, we'll need a fake IE, as we can't get * the real IE from the firmware. So we fabricate a fake IE based on @@ -1777,8 +1709,6 @@ static void lbs_join_post(struct lbs_private *priv, netif_carrier_on(priv->dev); if (!priv->tx_pending_len) netif_wake_queue(priv->dev); - - lbs_deb_leave(LBS_DEB_CFG80211); } static int lbs_ibss_join_existing(struct lbs_private *priv, @@ -1790,8 +1720,6 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, u8 preamble = RADIO_PREAMBLE_SHORT; int ret = 0; - lbs_deb_enter(LBS_DEB_CFG80211); - /* TODO: set preamble based on scan result */ ret = lbs_set_radio(priv, preamble, 1); if (ret) @@ -1888,7 +1816,6 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, lbs_join_post(priv, params, bss->bssid, bss->capability); out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1904,8 +1831,6 @@ static int lbs_ibss_start_new(struct lbs_private *priv, int ret = 0; u16 capability; - lbs_deb_enter(LBS_DEB_CFG80211); - ret = lbs_set_radio(priv, preamble, 1); if (ret) goto out; @@ -1975,7 +1900,6 @@ static int lbs_ibss_start_new(struct lbs_private *priv, lbs_join_post(priv, params, resp->bssid, capability); out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -1990,8 +1914,6 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, if (dev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - if (!params->chandef.chan) { ret = -ENOTSUPP; goto out; @@ -2015,7 +1937,6 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, out: - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -2029,8 +1950,6 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) if (dev == priv->mesh_dev) return -EOPNOTSUPP; - lbs_deb_enter(LBS_DEB_CFG80211); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); @@ -2038,7 +1957,6 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */ lbs_mac_event_disconnected(priv, true); - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } @@ -2114,8 +2032,6 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev) int ret = 0; struct wireless_dev *wdev; - lbs_deb_enter(LBS_DEB_CFG80211); - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (!wdev) return ERR_PTR(-ENOMEM); @@ -2127,12 +2043,10 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev) goto err_wiphy_new; } - lbs_deb_leave(LBS_DEB_CFG80211); return wdev; err_wiphy_new: kfree(wdev); - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ERR_PTR(ret); } @@ -2155,15 +2069,11 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv) }; size_t i; - lbs_deb_enter(LBS_DEB_CFG80211); - for (i = 0; i < ARRAY_SIZE(regmap); i++) if (regmap[i].code == priv->regioncode) { regulatory_hint(priv->wdev->wiphy, regmap[i].cn); break; } - - lbs_deb_leave(LBS_DEB_CFG80211); } static void lbs_reg_notifier(struct wiphy *wiphy, @@ -2171,15 +2081,9 @@ static void lbs_reg_notifier(struct wiphy *wiphy, { struct lbs_private *priv = wiphy_priv(wiphy); - lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain " - "callback for domain %c%c\n", request->alpha2[0], - request->alpha2[1]); - memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); if (lbs_iface_active(priv)) lbs_set_11d_domain_info(priv); - - lbs_deb_leave(LBS_DEB_CFG80211); } /* @@ -2192,8 +2096,6 @@ int lbs_cfg_register(struct lbs_private *priv) struct wireless_dev *wdev = priv->wdev; int ret; - lbs_deb_enter(LBS_DEB_CFG80211); - wdev->wiphy->max_scan_ssids = 1; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; @@ -2229,13 +2131,11 @@ int lbs_cfg_register(struct lbs_private *priv) lbs_cfg_set_regulatory_hint(priv); - lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); return ret; } void lbs_scan_deinit(struct lbs_private *priv) { - lbs_deb_enter(LBS_DEB_CFG80211); cancel_delayed_work_sync(&priv->scan_work); } @@ -2244,8 +2144,6 @@ void lbs_cfg_free(struct lbs_private *priv) { struct wireless_dev *wdev = priv->wdev; - lbs_deb_enter(LBS_DEB_CFG80211); - if (!wdev) return; diff --git a/drivers/net/wireless/marvell/libertas/cmd.c b/drivers/net/wireless/marvell/libertas/cmd.c index 033ff881c751..c1f422918737 100644 --- a/drivers/net/wireless/marvell/libertas/cmd.c +++ b/drivers/net/wireless/marvell/libertas/cmd.c @@ -91,8 +91,6 @@ int lbs_update_hw_spec(struct lbs_private *priv) int ret = -1; u32 i; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN); @@ -159,14 +157,12 @@ int lbs_update_hw_spec(struct lbs_private *priv) } out: - lbs_deb_leave(LBS_DEB_CMD); return ret; } static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy, struct cmd_header *resp) { - lbs_deb_enter(LBS_DEB_CMD); if (priv->is_host_sleep_activated) { priv->is_host_sleep_configured = 0; if (priv->psstate == PS_STATE_FULL_POWER) { @@ -176,7 +172,7 @@ static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy, } else { priv->is_host_sleep_configured = 1; } - lbs_deb_leave(LBS_DEB_CMD); + return 0; } @@ -236,8 +232,6 @@ int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block) struct cmd_ds_802_11_ps_mode cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(cmd_action); @@ -262,7 +256,6 @@ int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block) lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd)); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -272,8 +265,6 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, struct cmd_ds_802_11_sleep_params cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - if (cmd_action == CMD_ACT_GET) { memset(&cmd, 0, sizeof(cmd)); } else { @@ -304,7 +295,6 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, sp->sp_reserved = le16_to_cpu(cmd.reserved); } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -312,8 +302,6 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv) { int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - if (priv->is_deep_sleep) { if (!wait_event_interruptible_timeout(priv->ds_awake_q, !priv->is_deep_sleep, (10 * HZ))) { @@ -322,7 +310,6 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv) } } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -330,8 +317,6 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) { int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - if (deep_sleep) { if (priv->is_deep_sleep != 1) { lbs_deb_cmd("deep sleep: sleep\n"); @@ -358,7 +343,6 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) } } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -366,10 +350,9 @@ static int lbs_ret_host_sleep_activate(struct lbs_private *priv, unsigned long dummy, struct cmd_header *cmd) { - lbs_deb_enter(LBS_DEB_FW); priv->is_host_sleep_activated = 1; wake_up_interruptible(&priv->host_sleep_q); - lbs_deb_leave(LBS_DEB_FW); + return 0; } @@ -379,8 +362,6 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) int ret = 0; uint32_t criteria = EHS_REMOVE_WAKEUP; - lbs_deb_enter(LBS_DEB_CMD); - if (host_sleep) { if (priv->is_host_sleep_activated != 1) { memset(&cmd, 0, sizeof(cmd)); @@ -438,8 +419,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) struct cmd_ds_802_11_snmp_mib cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof (cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); @@ -470,7 +449,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -488,8 +466,6 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) struct cmd_ds_802_11_snmp_mib cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof (cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_GET); @@ -513,7 +489,6 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) } out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -533,8 +508,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, struct cmd_ds_802_11_rf_tx_power cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_GET); @@ -548,7 +521,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, *maxlevel = cmd.maxlevel; } - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -565,8 +537,6 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) struct cmd_ds_802_11_rf_tx_power cmd; int ret; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); @@ -576,7 +546,6 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -608,7 +577,6 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable) ARPHRD_ETHER; } - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -624,8 +592,6 @@ static int lbs_get_channel(struct lbs_private *priv) struct cmd_ds_802_11_rf_channel cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET); @@ -638,7 +604,6 @@ static int lbs_get_channel(struct lbs_private *priv) lbs_deb_cmd("current radio channel is %d\n", ret); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -647,14 +612,12 @@ int lbs_update_channel(struct lbs_private *priv) int ret; /* the channel in f/w could be out of sync; get the current channel */ - lbs_deb_enter(LBS_DEB_ASSOC); - ret = lbs_get_channel(priv); if (ret > 0) { priv->channel = ret; ret = 0; } - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; } @@ -674,8 +637,6 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel) #endif int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET); @@ -690,7 +651,6 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel) priv->channel); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -708,8 +668,6 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) struct cmd_ds_802_11_rssi cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - BUG_ON(rssi == NULL); BUG_ON(nf == NULL); @@ -724,7 +682,6 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) *rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf)); } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -752,7 +709,6 @@ int lbs_set_11d_domain_info(struct lbs_private *priv) size_t triplet_size; int ret = 0; - lbs_deb_enter(LBS_DEB_11D); if (!priv->country_code[0]) goto out; @@ -849,7 +805,6 @@ int lbs_set_11d_domain_info(struct lbs_private *priv) ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd); out: - lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret); return ret; } @@ -869,8 +824,6 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) struct cmd_ds_reg_access cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - BUG_ON(value == NULL); memset(&cmd, 0, sizeof(cmd)); @@ -894,7 +847,6 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) } out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -914,8 +866,6 @@ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value) struct cmd_ds_reg_access cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); @@ -933,7 +883,6 @@ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value) ret = lbs_cmd_with_response(priv, reg, &cmd); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -943,15 +892,13 @@ static void lbs_queue_cmd(struct lbs_private *priv, unsigned long flags; int addtail = 1; - lbs_deb_enter(LBS_DEB_HOST); - if (!cmdnode) { lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n"); - goto done; + return; } if (!cmdnode->cmdbuf->size) { lbs_deb_host("DNLD_CMD: cmd size is zero\n"); - goto done; + return; } cmdnode->result = 0; @@ -979,9 +926,6 @@ static void lbs_queue_cmd(struct lbs_private *priv, lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n", le16_to_cpu(cmdnode->cmdbuf->command)); - -done: - lbs_deb_leave(LBS_DEB_HOST); } static void lbs_submit_command(struct lbs_private *priv, @@ -994,8 +938,6 @@ static void lbs_submit_command(struct lbs_private *priv, int timeo = 3 * HZ; int ret; - lbs_deb_enter(LBS_DEB_HOST); - cmd = cmdnode->cmdbuf; spin_lock_irqsave(&priv->driver_lock, flags); @@ -1036,8 +978,6 @@ static void lbs_submit_command(struct lbs_private *priv, /* Setup the timer after transmit command */ mod_timer(&priv->command_timer, jiffies + timeo); } - - lbs_deb_leave(LBS_DEB_HOST); } /* @@ -1047,10 +987,8 @@ static void lbs_submit_command(struct lbs_private *priv, static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv, struct cmd_ctrl_node *cmdnode) { - lbs_deb_enter(LBS_DEB_HOST); - if (!cmdnode) - goto out; + return; cmdnode->callback = NULL; cmdnode->callback_arg = 0; @@ -1058,8 +996,6 @@ static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv, memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE); list_add_tail(&cmdnode->list, &priv->cmdfreeq); - out: - lbs_deb_leave(LBS_DEB_HOST); } static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv, @@ -1107,8 +1043,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) struct cmd_ds_802_11_radio_control cmd; int ret = -EINVAL; - lbs_deb_enter(LBS_DEB_CMD); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); cmd.control = 0; @@ -1141,7 +1075,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } @@ -1149,15 +1082,11 @@ void lbs_set_mac_control(struct lbs_private *priv) { struct cmd_ds_mac_control cmd; - lbs_deb_enter(LBS_DEB_CMD); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(priv->mac_control); cmd.reserved = 0; lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd)); - - lbs_deb_leave(LBS_DEB_CMD); } int lbs_set_mac_control_sync(struct lbs_private *priv) @@ -1165,14 +1094,11 @@ int lbs_set_mac_control_sync(struct lbs_private *priv) struct cmd_ds_mac_control cmd; int ret = 0; - lbs_deb_enter(LBS_DEB_CMD); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(priv->mac_control); cmd.reserved = 0; ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd); - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -1191,8 +1117,6 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) u32 i; struct cmd_ctrl_node *cmdarray; - lbs_deb_enter(LBS_DEB_HOST); - /* Allocate and initialize the command array */ bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS; if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) { @@ -1219,7 +1143,6 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) ret = 0; done: - lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -1235,8 +1158,6 @@ int lbs_free_cmd_buffer(struct lbs_private *priv) struct cmd_ctrl_node *cmdarray; unsigned int i; - lbs_deb_enter(LBS_DEB_HOST); - /* need to check if cmd array is allocated or not */ if (priv->cmd_array == NULL) { lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n"); @@ -1260,7 +1181,6 @@ int lbs_free_cmd_buffer(struct lbs_private *priv) } done: - lbs_deb_leave(LBS_DEB_HOST); return 0; } @@ -1278,8 +1198,6 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) struct cmd_ctrl_node *tempnode; unsigned long flags; - lbs_deb_enter(LBS_DEB_HOST); - if (!priv) return NULL; @@ -1296,7 +1214,6 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_HOST); return tempnode; } @@ -1318,8 +1235,6 @@ int lbs_execute_next_command(struct lbs_private *priv) /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the * only caller to us is lbs_thread() and we get even when a * data packet is received */ - lbs_deb_enter(LBS_DEB_THREAD); - spin_lock_irqsave(&priv->driver_lock, flags); if (priv->cur_cmd) { @@ -1440,7 +1355,6 @@ int lbs_execute_next_command(struct lbs_private *priv) ret = 0; done: - lbs_deb_leave(LBS_DEB_THREAD); return ret; } @@ -1449,7 +1363,6 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) unsigned long flags; int ret; - lbs_deb_enter(LBS_DEB_HOST); lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep, sizeof(confirm_sleep)); @@ -1457,7 +1370,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) sizeof(confirm_sleep)); if (ret) { netdev_alert(priv->dev, "confirm_sleep failed\n"); - goto out; + return; } spin_lock_irqsave(&priv->driver_lock, flags); @@ -1475,9 +1388,6 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) priv->psstate = PS_STATE_SLEEP; spin_unlock_irqrestore(&priv->driver_lock, flags); - -out: - lbs_deb_leave(LBS_DEB_HOST); } /** @@ -1493,8 +1403,6 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) unsigned long flags =0; int allowed = 1; - lbs_deb_enter(LBS_DEB_HOST); - spin_lock_irqsave(&priv->driver_lock, flags); if (priv->dnld_sent) { allowed = 0; @@ -1520,8 +1428,6 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) } else { lbs_deb_host("sleep confirm has been delayed\n"); } - - lbs_deb_leave(LBS_DEB_HOST); } @@ -1596,8 +1502,6 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, { struct cmd_ctrl_node *cmdnode; - lbs_deb_enter(LBS_DEB_HOST); - if (priv->surpriseremoved) { lbs_deb_host("PREP_CMD: card removed\n"); cmdnode = ERR_PTR(-ENOENT); @@ -1643,17 +1547,14 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, wake_up(&priv->waitq); done: - lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode); return cmdnode; } void lbs_cmd_async(struct lbs_private *priv, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size) { - lbs_deb_enter(LBS_DEB_CMD); __lbs_cmd_async(priv, command, in_cmd, in_cmd_size, lbs_cmd_async_callback, 0); - lbs_deb_leave(LBS_DEB_CMD); } int __lbs_cmd(struct lbs_private *priv, uint16_t command, @@ -1665,8 +1566,6 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, unsigned long flags; int ret = 0; - lbs_deb_enter(LBS_DEB_HOST); - cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size, callback, callback_arg); if (IS_ERR(cmdnode)) { @@ -1693,7 +1592,6 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, spin_unlock_irqrestore(&priv->driver_lock, flags); done: - lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(__lbs_cmd); diff --git a/drivers/net/wireless/marvell/libertas/cmdresp.c b/drivers/net/wireless/marvell/libertas/cmdresp.c index c753e36c2c0e..aaf01619de59 100644 --- a/drivers/net/wireless/marvell/libertas/cmdresp.c +++ b/drivers/net/wireless/marvell/libertas/cmdresp.c @@ -32,8 +32,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv, if (priv->connect_status != LBS_CONNECTED) return; - lbs_deb_enter(LBS_DEB_ASSOC); - /* * Cisco AP sends EAP failure and de-auth in less than 0.5 ms. * It causes problem in the Supplicant @@ -61,7 +59,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv, lbs_deb_cmd("disconnected, so exit PS mode\n"); lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false); } - lbs_deb_leave(LBS_DEB_ASSOC); } int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) @@ -72,8 +69,6 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) unsigned long flags; uint16_t result; - lbs_deb_enter(LBS_DEB_HOST); - mutex_lock(&priv->lock); spin_lock_irqsave(&priv->driver_lock, flags); @@ -221,7 +216,6 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) done: mutex_unlock(&priv->lock); - lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } @@ -230,8 +224,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event) int ret = 0; struct cmd_header cmd; - lbs_deb_enter(LBS_DEB_CMD); - switch (event) { case MACREG_INT_CODE_LINK_SENSED: lbs_deb_cmd("EVENT: link sensed\n"); @@ -359,6 +351,5 @@ int lbs_process_event(struct lbs_private *priv, u32 event) break; } - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/marvell/libertas/defs.h b/drivers/net/wireless/marvell/libertas/defs.h index 407784aca627..d3221444e51c 100644 --- a/drivers/net/wireless/marvell/libertas/defs.h +++ b/drivers/net/wireless/marvell/libertas/defs.h @@ -55,15 +55,6 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0) #endif -#define lbs_deb_enter(grp) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s()\n", __func__); -#define lbs_deb_enter_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args); -#define lbs_deb_leave(grp) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s()\n", __func__); -#define lbs_deb_leave_args(grp, fmt, args...) \ - LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s(), " fmt "\n", \ - __func__, ##args); #define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args) #define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args) #define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args) diff --git a/drivers/net/wireless/marvell/libertas/ethtool.c b/drivers/net/wireless/marvell/libertas/ethtool.c index f955b2d66ed6..693868f16921 100644 --- a/drivers/net/wireless/marvell/libertas/ethtool.c +++ b/drivers/net/wireless/marvell/libertas/ethtool.c @@ -41,8 +41,6 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev, struct cmd_ds_802_11_eeprom_access cmd; int ret; - lbs_deb_enter(LBS_DEB_ETHTOOL); - if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN || eeprom->len > LBS_EEPROM_READ_LEN) { ret = -EINVAL; @@ -59,7 +57,6 @@ static int lbs_ethtool_get_eeprom(struct net_device *dev, memcpy(bytes, cmd.value, eeprom->len); out: - lbs_deb_leave_args(LBS_DEB_ETHTOOL, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c index f499efc6abcf..7d88223f890b 100644 --- a/drivers/net/wireless/marvell/libertas/if_cs.c +++ b/drivers/net/wireless/marvell/libertas/if_cs.c @@ -336,13 +336,11 @@ static inline u32 get_model(u16 manf_id, u16 card_id) static inline void if_cs_enable_ints(struct if_cs_card *card) { - lbs_deb_enter(LBS_DEB_CS); if_cs_write16(card, IF_CS_HOST_INT_MASK, 0); } static inline void if_cs_disable_ints(struct if_cs_card *card) { - lbs_deb_enter(LBS_DEB_CS); if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK); } @@ -355,7 +353,6 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) int ret = -1; int loops = 0; - lbs_deb_enter(LBS_DEB_CS); if_cs_disable_ints(card); /* Is hardware ready? */ @@ -388,7 +385,6 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) done: if_cs_enable_ints(card); - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -400,7 +396,6 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) struct if_cs_card *card = (struct if_cs_card *)priv->card; u16 status; - lbs_deb_enter(LBS_DEB_CS); if_cs_disable_ints(card); status = if_cs_read16(card, IF_CS_CARD_STATUS); @@ -416,8 +411,6 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX); if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX); if_cs_enable_ints(card); - - lbs_deb_leave(LBS_DEB_CS); } /* @@ -429,8 +422,6 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) int ret = -1; u16 status; - lbs_deb_enter(LBS_DEB_CS); - /* is hardware ready? */ status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); if ((status & IF_CS_BIT_RESP) == 0) { @@ -463,7 +454,6 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) spin_unlock_irqrestore(&priv->driver_lock, flags); out: - lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len); return ret; } @@ -473,8 +463,6 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) u16 len; u8 *data; - lbs_deb_enter(LBS_DEB_CS); - len = if_cs_read16(priv->card, IF_CS_READ_LEN); if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { netdev_err(priv->dev, @@ -501,7 +489,6 @@ dat_err: if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX); out: - lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb); return skb; } @@ -511,8 +498,6 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) struct lbs_private *priv = card->priv; u16 cause; - lbs_deb_enter(LBS_DEB_CS); - /* Ask card interrupt cause register if there is something for us */ cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE); lbs_deb_cs("cause 0x%04x\n", cause); @@ -569,7 +554,6 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) /* Clear interrupt cause */ if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK); - lbs_deb_leave(LBS_DEB_CS); return IRQ_HANDLED; } @@ -591,8 +575,6 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) int sent = 0; u8 scratch; - lbs_deb_enter(LBS_DEB_CS); - /* * This is the only place where an unaligned register access happens on * the CF8305 card, therefore for the sake of speed of the driver, we do @@ -671,7 +653,6 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) } done: - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -683,8 +664,6 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) int len = 0; int sent; - lbs_deb_enter(LBS_DEB_CS); - lbs_deb_cs("fw size %td\n", fw->size); ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, @@ -734,7 +713,6 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) pr_err("firmware download failed\n"); done: - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -792,8 +770,6 @@ static int if_cs_host_to_card(struct lbs_private *priv, { int ret = -1; - lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb); - switch (type) { case MVMS_DAT: priv->dnld_sent = DNLD_DATA_SENT; @@ -809,7 +785,6 @@ static int if_cs_host_to_card(struct lbs_private *priv, __func__, type); } - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -818,14 +793,10 @@ static void if_cs_release(struct pcmcia_device *p_dev) { struct if_cs_card *card = p_dev->priv; - lbs_deb_enter(LBS_DEB_CS); - free_irq(p_dev->irq, card); pcmcia_disable_device(p_dev); if (card->iobase) ioport_unmap(card->iobase); - - lbs_deb_leave(LBS_DEB_CS); } @@ -850,8 +821,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) struct lbs_private *priv; struct if_cs_card *card; - lbs_deb_enter(LBS_DEB_CS); - card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); if (!card) goto out; @@ -961,7 +930,6 @@ out2: out1: pcmcia_disable_device(p_dev); out: - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } @@ -970,15 +938,11 @@ static void if_cs_detach(struct pcmcia_device *p_dev) { struct if_cs_card *card = p_dev->priv; - lbs_deb_enter(LBS_DEB_CS); - lbs_stop_card(card->priv); lbs_remove_card(card->priv); if_cs_disable_ints(card); if_cs_release(p_dev); kfree(card); - - lbs_deb_leave(LBS_DEB_CS); } diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 47f4a14c84fe..e0196208ab0d 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -211,8 +211,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card, unsigned long flags; u8 i; - lbs_deb_enter(LBS_DEB_SDIO); - if (size > LBS_CMD_BUFFER_SIZE) { lbs_deb_sdio("response packet too large (%d bytes)\n", (int)size); @@ -233,7 +231,6 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card, ret = 0; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; } @@ -244,8 +241,6 @@ static int if_sdio_handle_data(struct if_sdio_card *card, struct sk_buff *skb; char *data; - lbs_deb_enter(LBS_DEB_SDIO); - if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_deb_sdio("response packet too large (%d bytes)\n", (int)size); @@ -270,8 +265,6 @@ static int if_sdio_handle_data(struct if_sdio_card *card, ret = 0; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } @@ -281,8 +274,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card, int ret; u32 event; - lbs_deb_enter(LBS_DEB_SDIO); - if (card->model == MODEL_8385) { event = sdio_readb(card->func, IF_SDIO_EVENT, &ret); if (ret) @@ -307,8 +298,6 @@ static int if_sdio_handle_event(struct if_sdio_card *card, ret = 0; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } @@ -337,8 +326,6 @@ static int if_sdio_card_to_host(struct if_sdio_card *card) int ret; u16 size, type, chunk; - lbs_deb_enter(LBS_DEB_SDIO); - size = if_sdio_read_rx_len(card, &ret); if (ret) goto out; @@ -410,8 +397,6 @@ out: if (ret) pr_err("problem fetching packet from firmware\n"); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } @@ -422,8 +407,6 @@ static void if_sdio_host_to_card_worker(struct work_struct *work) int ret; unsigned long flags; - lbs_deb_enter(LBS_DEB_SDIO); - card = container_of(work, struct if_sdio_card, packet_worker); while (1) { @@ -451,8 +434,6 @@ static void if_sdio_host_to_card_worker(struct work_struct *work) kfree(packet); } - - lbs_deb_leave(LBS_DEB_SDIO); } /********************************************************************/ @@ -471,8 +452,6 @@ static int if_sdio_prog_helper(struct if_sdio_card *card, const u8 *firmware; size_t size; - lbs_deb_enter(LBS_DEB_SDIO); - chunk_buffer = kzalloc(64, GFP_KERNEL); if (!chunk_buffer) { ret = -ENOMEM; @@ -556,7 +535,6 @@ out: if (ret) pr_err("failed to load helper firmware\n"); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; } @@ -570,8 +548,6 @@ static int if_sdio_prog_real(struct if_sdio_card *card, const u8 *firmware; size_t size, req_size; - lbs_deb_enter(LBS_DEB_SDIO); - chunk_buffer = kzalloc(512, GFP_KERNEL); if (!chunk_buffer) { ret = -ENOMEM; @@ -691,7 +667,6 @@ out: if (ret) pr_err("failed to load firmware\n"); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; } @@ -725,8 +700,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) int ret; u16 scratch; - lbs_deb_enter(LBS_DEB_SDIO); - /* * Disable interrupts */ @@ -769,7 +742,6 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) fw_table, if_sdio_do_prog_firmware); out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; } @@ -948,8 +920,6 @@ static int if_sdio_host_to_card(struct lbs_private *priv, u16 size; unsigned long flags; - lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb); - card = priv->card; if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) { @@ -1013,8 +983,6 @@ static int if_sdio_host_to_card(struct lbs_private *priv, ret = 0; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } @@ -1040,7 +1008,6 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv) struct if_sdio_card *card = priv->card; int ret = -1; - lbs_deb_enter(LBS_DEB_SDIO); sdio_claim_host(card->func); sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret); @@ -1048,7 +1015,7 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv) netdev_err(priv->dev, "sdio_writeb failed!\n"); sdio_release_host(card->func); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); + return ret; } @@ -1057,7 +1024,6 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv) struct if_sdio_card *card = priv->card; int ret = -1; - lbs_deb_enter(LBS_DEB_SDIO); sdio_claim_host(card->func); sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret); @@ -1065,7 +1031,7 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv) netdev_err(priv->dev, "sdio_writeb failed!\n"); sdio_release_host(card->func); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); + return ret; } @@ -1143,19 +1109,17 @@ static void if_sdio_interrupt(struct sdio_func *func) struct if_sdio_card *card; u8 cause; - lbs_deb_enter(LBS_DEB_SDIO); - card = sdio_get_drvdata(func); cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret); if (ret || !cause) - goto out; + return; lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause); sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret); if (ret) - goto out; + return; /* * Ignore the define name, this really means the card has @@ -1169,13 +1133,8 @@ static void if_sdio_interrupt(struct sdio_func *func) if (cause & IF_SDIO_H_INT_UPLD) { ret = if_sdio_card_to_host(card); if (ret) - goto out; + return; } - - ret = 0; - -out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); } static int if_sdio_probe(struct sdio_func *func, @@ -1187,8 +1146,6 @@ static int if_sdio_probe(struct sdio_func *func, unsigned int model; struct if_sdio_packet *packet; - lbs_deb_enter(LBS_DEB_SDIO); - for (i = 0;i < func->card->num_info;i++) { if (sscanf(func->card->info[i], "802.11 SDIO ID: %x", &model) == 1) @@ -1273,8 +1230,6 @@ static int if_sdio_probe(struct sdio_func *func, goto err_activate_card; out: - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; err_activate_card: @@ -1298,8 +1253,6 @@ static void if_sdio_remove(struct sdio_func *func) struct if_sdio_card *card; struct if_sdio_packet *packet; - lbs_deb_enter(LBS_DEB_SDIO); - card = sdio_get_drvdata(func); /* Undo decrement done above in if_sdio_probe */ @@ -1335,7 +1288,6 @@ static void if_sdio_remove(struct sdio_func *func) } kfree(card); - lbs_deb_leave(LBS_DEB_SDIO); } static int if_sdio_suspend(struct device *dev) @@ -1415,8 +1367,6 @@ static int __init if_sdio_init_module(void) { int ret = 0; - lbs_deb_enter(LBS_DEB_SDIO); - printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n"); printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n"); @@ -1425,23 +1375,17 @@ static int __init if_sdio_init_module(void) /* Clear the flag in case user removes the card. */ user_rmmod = 0; - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); - return ret; } static void __exit if_sdio_exit_module(void) { - lbs_deb_enter(LBS_DEB_SDIO); - /* Set the flag as user is removing this module. */ user_rmmod = 1; cancel_work_sync(&card_reset_work); sdio_unregister_driver(&if_sdio_driver); - - lbs_deb_leave(LBS_DEB_SDIO); } module_init(if_sdio_init_module); diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index 7b4955cc38db..e9aec6cb1105 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -466,8 +466,6 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, const u8 *fw; u8 temp[HELPER_FW_LOAD_CHUNK_SZ]; - lbs_deb_enter(LBS_DEB_SPI); - err = spu_set_interrupt_mode(card, 1, 0); if (err) goto out; @@ -533,7 +531,7 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, out: if (err) pr_err("failed to load helper firmware (err=%d)\n", err); - lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err); + return err; } @@ -588,8 +586,6 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, const u8 *fw; u16 num_crc_errs; - lbs_deb_enter(LBS_DEB_SPI); - err = spu_set_interrupt_mode(card, 1, 0); if (err) goto out; @@ -666,7 +662,7 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, out: if (err) pr_err("failed to load firmware (err=%d)\n", err); - lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err); + return err; } @@ -699,8 +695,6 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) */ BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0); - lbs_deb_enter(LBS_DEB_SPI); - /* How many bytes are there to read? */ err = spu_read_u16(card, IF_SPI_SCRATCH_2_REG, &len); if (err) @@ -735,7 +729,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) out: if (err) netdev_err(priv->dev, "%s: err=%d\n", __func__, err); - lbs_deb_leave(LBS_DEB_SPI); + return err; } @@ -748,8 +742,6 @@ static int if_spi_c2h_data(struct if_spi_card *card) u16 len; int err = 0; - lbs_deb_enter(LBS_DEB_SPI); - /* How many bytes are there to read? */ err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len); if (err) @@ -794,7 +786,7 @@ free_skb: out: if (err) netdev_err(priv->dev, "%s: err=%d\n", __func__, err); - lbs_deb_leave(LBS_DEB_SPI); + return err; } @@ -870,8 +862,6 @@ static void if_spi_host_to_card_worker(struct work_struct *work) card = container_of(work, struct if_spi_card, packet_work); priv = card->priv; - lbs_deb_enter(LBS_DEB_SPI); - /* * Read the host interrupt status register to see what we * can do. @@ -943,8 +933,6 @@ static void if_spi_host_to_card_worker(struct work_struct *work) err: if (err) netdev_err(priv->dev, "%s: got error %d\n", __func__, err); - - lbs_deb_leave(LBS_DEB_SPI); } /* @@ -962,8 +950,6 @@ static int if_spi_host_to_card(struct lbs_private *priv, struct if_spi_packet *packet; u16 blen; - lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb); - if (nb == 0) { netdev_err(priv->dev, "%s: invalid size requested: %d\n", __func__, nb); @@ -1004,7 +990,6 @@ static int if_spi_host_to_card(struct lbs_private *priv, /* Queue spi xfer work */ queue_work(card->workqueue, &card->packet_work); out: - lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err); return err; } @@ -1035,8 +1020,6 @@ static int if_spi_init_card(struct if_spi_card *card) const struct firmware *helper = NULL; const struct firmware *mainfw = NULL; - lbs_deb_enter(LBS_DEB_SPI); - err = spu_init(card, card->pdata->use_dummy_writes); if (err) goto out; @@ -1093,7 +1076,6 @@ static int if_spi_init_card(struct if_spi_card *card) goto out; out: - lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); return err; } @@ -1126,8 +1108,6 @@ static int if_spi_probe(struct spi_device *spi) struct libertas_spi_platform_data *pdata = dev_get_platdata(&spi->dev); int err = 0; - lbs_deb_enter(LBS_DEB_SPI); - if (!pdata) { err = -EINVAL; goto out; @@ -1221,7 +1201,6 @@ teardown: if (pdata->teardown) pdata->teardown(spi); out: - lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); return err; } @@ -1231,7 +1210,6 @@ static int libertas_spi_remove(struct spi_device *spi) struct lbs_private *priv = card->priv; lbs_deb_spi("libertas_spi_remove\n"); - lbs_deb_enter(LBS_DEB_SPI); cancel_work_sync(&card->resume_work); @@ -1243,7 +1221,7 @@ static int libertas_spi_remove(struct spi_device *spi) if (card->pdata->teardown) card->pdata->teardown(spi); free_if_spi_card(card); - lbs_deb_leave(LBS_DEB_SPI); + return 0; } @@ -1297,18 +1275,16 @@ static struct spi_driver libertas_spi_driver = { static int __init if_spi_init_module(void) { int ret = 0; - lbs_deb_enter(LBS_DEB_SPI); + printk(KERN_INFO "libertas_spi: Libertas SPI driver\n"); ret = spi_register_driver(&libertas_spi_driver); - lbs_deb_leave(LBS_DEB_SPI); + return ret; } static void __exit if_spi_exit_module(void) { - lbs_deb_enter(LBS_DEB_SPI); spi_unregister_driver(&libertas_spi_driver); - lbs_deb_leave(LBS_DEB_SPI); } module_init(if_spi_init_module); diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c index aba0c9995b14..e53025ea6689 100644 --- a/drivers/net/wireless/marvell/libertas/if_usb.c +++ b/drivers/net/wireless/marvell/libertas/if_usb.c @@ -111,8 +111,6 @@ static void if_usb_write_bulk_callback(struct urb *urb) */ static void if_usb_free(struct if_usb_card *cardp) { - lbs_deb_enter(LBS_DEB_USB); - /* Unlink tx & rx urb */ usb_kill_urb(cardp->tx_urb); usb_kill_urb(cardp->rx_urb); @@ -125,8 +123,6 @@ static void if_usb_free(struct if_usb_card *cardp) kfree(cardp->ep_out_buf); cardp->ep_out_buf = NULL; - - lbs_deb_leave(LBS_DEB_USB); } static void if_usb_setup_firmware(struct lbs_private *priv) @@ -306,8 +302,6 @@ static void if_usb_disconnect(struct usb_interface *intf) struct if_usb_card *cardp = usb_get_intfdata(intf); struct lbs_private *priv = cardp->priv; - lbs_deb_enter(LBS_DEB_MAIN); - cardp->surprise_removed = 1; if (priv) { @@ -320,8 +314,6 @@ static void if_usb_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); - - lbs_deb_leave(LBS_DEB_MAIN); } /** @@ -388,8 +380,6 @@ static int if_usb_reset_device(struct if_usb_card *cardp) struct cmd_header *cmd = cardp->ep_out_buf + 4; int ret; - lbs_deb_enter(LBS_DEB_USB); - *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); cmd->command = cpu_to_le16(CMD_802_11_RESET); @@ -407,8 +397,6 @@ static int if_usb_reset_device(struct if_usb_card *cardp) if_usb_reset_olpc_card(NULL); #endif - lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); - return ret; } @@ -671,8 +659,6 @@ static void if_usb_receive(struct urb *urb) __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET); uint32_t event; - lbs_deb_enter(LBS_DEB_USB); - if (recvlength) { if (urb->status) { lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n", @@ -688,7 +674,7 @@ static void if_usb_receive(struct urb *urb) recvlength, recvtype); } else if (urb->status) { kfree_skb(skb); - goto rx_exit; + return; } switch (recvtype) { @@ -724,8 +710,6 @@ static void if_usb_receive(struct urb *urb) setup_for_next: if_usb_submit_rx_urb(cardp); -rx_exit: - lbs_deb_leave(LBS_DEB_USB); } /** @@ -835,8 +819,6 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret, int i = 0; static int reset_count = 10; - lbs_deb_enter(LBS_DEB_USB); - if (ret) { pr_err("failed to find firmware (%d)\n", ret); goto done; @@ -942,7 +924,6 @@ restart: done: cardp->fw = NULL; - lbs_deb_leave(LBS_DEB_USB); } @@ -953,8 +934,6 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) struct lbs_private *priv = cardp->priv; int ret; - lbs_deb_enter(LBS_DEB_USB); - if (priv->psstate != PS_STATE_FULL_POWER) { ret = -1; goto out; @@ -978,7 +957,6 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) usb_kill_urb(cardp->rx_urb); out: - lbs_deb_leave(LBS_DEB_USB); return ret; } @@ -987,13 +965,10 @@ static int if_usb_resume(struct usb_interface *intf) struct if_usb_card *cardp = usb_get_intfdata(intf); struct lbs_private *priv = cardp->priv; - lbs_deb_enter(LBS_DEB_USB); - if_usb_submit_rx_urb(cardp); lbs_resume(priv); - lbs_deb_leave(LBS_DEB_USB); return 0; } #else diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c index e3500203715c..55f8c997e5cb 100644 --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c @@ -180,7 +180,6 @@ static int lbs_dev_open(struct net_device *dev) struct lbs_private *priv = dev->ml_priv; int ret = 0; - lbs_deb_enter(LBS_DEB_NET); if (!priv->iface_running) { ret = lbs_start_iface(priv); if (ret) @@ -197,7 +196,6 @@ static int lbs_dev_open(struct net_device *dev) spin_unlock_irq(&priv->driver_lock); out: - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } @@ -216,8 +214,6 @@ int lbs_stop_iface(struct lbs_private *priv) unsigned long flags; int ret = 0; - lbs_deb_enter(LBS_DEB_MAIN); - spin_lock_irqsave(&priv->driver_lock, flags); priv->iface_running = false; kfree_skb(priv->currenttxskb); @@ -236,7 +232,6 @@ int lbs_stop_iface(struct lbs_private *priv) if (priv->power_save) ret = priv->power_save(priv); - lbs_deb_leave(LBS_DEB_MAIN); return ret; } @@ -250,8 +245,6 @@ static int lbs_eth_stop(struct net_device *dev) { struct lbs_private *priv = dev->ml_priv; - lbs_deb_enter(LBS_DEB_NET); - if (priv->connect_status == LBS_CONNECTED) lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING); @@ -269,7 +262,6 @@ static int lbs_eth_stop(struct net_device *dev) if (!lbs_iface_active(priv)) lbs_stop_iface(priv); - lbs_deb_leave(LBS_DEB_NET); return 0; } @@ -277,8 +269,6 @@ void lbs_host_to_card_done(struct lbs_private *priv) { unsigned long flags; - lbs_deb_enter(LBS_DEB_THREAD); - spin_lock_irqsave(&priv->driver_lock, flags); del_timer(&priv->tx_lockup_timer); @@ -291,7 +281,6 @@ void lbs_host_to_card_done(struct lbs_private *priv) } spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_THREAD); } EXPORT_SYMBOL_GPL(lbs_host_to_card_done); @@ -301,8 +290,6 @@ int lbs_set_mac_address(struct net_device *dev, void *addr) struct lbs_private *priv = dev->ml_priv; struct sockaddr *phwaddr = addr; - lbs_deb_enter(LBS_DEB_NET); - /* * Can only set MAC address when all interfaces are down, to be written * to the hardware when one of them is brought up. @@ -318,7 +305,6 @@ int lbs_set_mac_address(struct net_device *dev, void *addr) if (priv->mesh_dev) memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN); - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } @@ -378,8 +364,6 @@ void lbs_update_mcast(struct lbs_private *priv) int nr_addrs; int old_mac_control = priv->mac_control; - lbs_deb_enter(LBS_DEB_NET); - if (netif_running(priv->dev)) dev_flags |= priv->dev->flags; if (priv->mesh_dev && netif_running(priv->mesh_dev)) @@ -424,8 +408,6 @@ void lbs_update_mcast(struct lbs_private *priv) out_set_mac_control: if (priv->mac_control != old_mac_control) lbs_set_mac_control(priv); - - lbs_deb_leave(LBS_DEB_NET); } static void lbs_set_mcast_worker(struct work_struct *work) @@ -455,8 +437,6 @@ static int lbs_thread(void *data) struct lbs_private *priv = dev->ml_priv; wait_queue_t wait; - lbs_deb_enter(LBS_DEB_THREAD); - init_waitqueue_entry(&wait, current); for (;;) { @@ -648,7 +628,6 @@ static int lbs_thread(void *data) del_timer(&priv->tx_lockup_timer); del_timer(&priv->auto_deepsleep_timer); - lbs_deb_leave(LBS_DEB_THREAD); return 0; } @@ -664,8 +643,6 @@ static int lbs_setup_firmware(struct lbs_private *priv) int ret = -1; s16 curlevel = 0, minlevel = 0, maxlevel = 0; - lbs_deb_enter(LBS_DEB_FW); - /* Read MAC address from firmware */ eth_broadcast_addr(priv->current_addr); ret = lbs_update_hw_spec(priv); @@ -687,7 +664,6 @@ static int lbs_setup_firmware(struct lbs_private *priv) ret = lbs_set_mac_control_sync(priv); done: - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; } @@ -695,8 +671,6 @@ int lbs_suspend(struct lbs_private *priv) { int ret; - lbs_deb_enter(LBS_DEB_FW); - if (priv->is_deep_sleep) { ret = lbs_set_deep_sleep(priv, 0); if (ret) { @@ -713,7 +687,6 @@ int lbs_suspend(struct lbs_private *priv) if (priv->mesh_dev) netif_device_detach(priv->mesh_dev); - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(lbs_suspend); @@ -722,8 +695,6 @@ int lbs_resume(struct lbs_private *priv) { int ret; - lbs_deb_enter(LBS_DEB_FW); - ret = lbs_set_host_sleep(priv, 0); netif_device_attach(priv->dev); @@ -741,7 +712,6 @@ int lbs_resume(struct lbs_private *priv) if (priv->setup_fw_on_resume) ret = lbs_setup_firmware(priv); - lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(lbs_resume); @@ -757,7 +727,6 @@ static void lbs_cmd_timeout_handler(unsigned long data) struct lbs_private *priv = (struct lbs_private *)data; unsigned long flags; - lbs_deb_enter(LBS_DEB_CMD); spin_lock_irqsave(&priv->driver_lock, flags); if (!priv->cur_cmd) @@ -778,7 +747,6 @@ static void lbs_cmd_timeout_handler(unsigned long data) wake_up(&priv->waitq); out: spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_CMD); } /** @@ -793,7 +761,6 @@ static void lbs_tx_lockup_handler(unsigned long data) struct lbs_private *priv = (struct lbs_private *)data; unsigned long flags; - lbs_deb_enter(LBS_DEB_TX); spin_lock_irqsave(&priv->driver_lock, flags); netdev_info(priv->dev, "TX lockup detected\n"); @@ -804,7 +771,6 @@ static void lbs_tx_lockup_handler(unsigned long data) wake_up_interruptible(&priv->waitq); spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_TX); } /** @@ -817,8 +783,6 @@ static void auto_deepsleep_timer_fn(unsigned long data) { struct lbs_private *priv = (struct lbs_private *)data; - lbs_deb_enter(LBS_DEB_CMD); - if (priv->is_activity_detected) { priv->is_activity_detected = 0; } else { @@ -836,32 +800,25 @@ static void auto_deepsleep_timer_fn(unsigned long data) } mod_timer(&priv->auto_deepsleep_timer , jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000); - lbs_deb_leave(LBS_DEB_CMD); } int lbs_enter_auto_deep_sleep(struct lbs_private *priv) { - lbs_deb_enter(LBS_DEB_SDIO); - priv->is_auto_deep_sleep_enabled = 1; if (priv->is_deep_sleep) priv->wakeup_dev_required = 1; mod_timer(&priv->auto_deepsleep_timer , jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000); - lbs_deb_leave(LBS_DEB_SDIO); return 0; } int lbs_exit_auto_deep_sleep(struct lbs_private *priv) { - lbs_deb_enter(LBS_DEB_SDIO); - priv->is_auto_deep_sleep_enabled = 0; priv->auto_deep_sleep_timeout = 0; del_timer(&priv->auto_deepsleep_timer); - lbs_deb_leave(LBS_DEB_SDIO); return 0; } @@ -869,8 +826,6 @@ static int lbs_init_adapter(struct lbs_private *priv) { int ret; - lbs_deb_enter(LBS_DEB_MAIN); - eth_broadcast_addr(priv->current_addr); priv->connect_status = LBS_DISCONNECTED; @@ -921,22 +876,16 @@ static int lbs_init_adapter(struct lbs_private *priv) } out: - lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); - return ret; } static void lbs_free_adapter(struct lbs_private *priv) { - lbs_deb_enter(LBS_DEB_MAIN); - lbs_free_cmd_buffer(priv); kfifo_free(&priv->event_fifo); del_timer(&priv->command_timer); del_timer(&priv->tx_lockup_timer); del_timer(&priv->auto_deepsleep_timer); - - lbs_deb_leave(LBS_DEB_MAIN); } static const struct net_device_ops lbs_netdev_ops = { @@ -962,8 +911,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) struct wireless_dev *wdev; struct lbs_private *priv = NULL; - lbs_deb_enter(LBS_DEB_MAIN); - /* Allocate an Ethernet device and register it */ wdev = lbs_cfg_alloc(dmdev); if (IS_ERR(wdev)) { @@ -1031,7 +978,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv = NULL; done: - lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv); return priv; } EXPORT_SYMBOL_GPL(lbs_add_card); @@ -1041,8 +987,6 @@ void lbs_remove_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; - lbs_deb_enter(LBS_DEB_MAIN); - lbs_remove_mesh(priv); if (priv->wiphy_registered) @@ -1083,8 +1027,6 @@ void lbs_remove_card(struct lbs_private *priv) lbs_free_adapter(priv); lbs_cfg_free(priv); free_netdev(dev); - - lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(lbs_remove_card); @@ -1105,8 +1047,6 @@ int lbs_start_card(struct lbs_private *priv) struct net_device *dev = priv->dev; int ret = -1; - lbs_deb_enter(LBS_DEB_MAIN); - /* poke the firmware */ ret = lbs_setup_firmware(priv); if (ret) @@ -1133,7 +1073,6 @@ int lbs_start_card(struct lbs_private *priv) ret = 0; done: - lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(lbs_start_card); @@ -1143,16 +1082,14 @@ void lbs_stop_card(struct lbs_private *priv) { struct net_device *dev; - lbs_deb_enter(LBS_DEB_MAIN); - if (!priv) - goto out; + return; dev = priv->dev; /* If the netdev isn't registered, it means that lbs_start_card() was * never called so we have nothing to do here. */ if (dev->reg_state != NETREG_REGISTERED) - goto out; + return; netif_stop_queue(dev); netif_carrier_off(dev); @@ -1160,9 +1097,6 @@ void lbs_stop_card(struct lbs_private *priv) lbs_debugfs_remove_one(priv); lbs_deinit_mesh(priv); unregister_netdev(dev); - -out: - lbs_deb_leave(LBS_DEB_MAIN); } EXPORT_SYMBOL_GPL(lbs_stop_card); @@ -1171,7 +1105,6 @@ void lbs_queue_event(struct lbs_private *priv, u32 event) { unsigned long flags; - lbs_deb_enter(LBS_DEB_THREAD); spin_lock_irqsave(&priv->driver_lock, flags); if (priv->psstate == PS_STATE_SLEEP) @@ -1182,14 +1115,11 @@ void lbs_queue_event(struct lbs_private *priv, u32 event) wake_up(&priv->waitq); spin_unlock_irqrestore(&priv->driver_lock, flags); - lbs_deb_leave(LBS_DEB_THREAD); } EXPORT_SYMBOL_GPL(lbs_queue_event); void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) { - lbs_deb_enter(LBS_DEB_THREAD); - if (priv->psstate == PS_STATE_SLEEP) priv->psstate = PS_STATE_AWAKE; @@ -1198,28 +1128,23 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) priv->resp_idx = resp_idx; wake_up(&priv->waitq); - - lbs_deb_leave(LBS_DEB_THREAD); } EXPORT_SYMBOL_GPL(lbs_notify_command_response); static int __init lbs_init_module(void) { - lbs_deb_enter(LBS_DEB_MAIN); memset(&confirm_sleep, 0, sizeof(confirm_sleep)); confirm_sleep.hdr.command = cpu_to_le16(CMD_802_11_PS_MODE); confirm_sleep.hdr.size = cpu_to_le16(sizeof(confirm_sleep)); confirm_sleep.action = cpu_to_le16(PS_MODE_ACTION_SLEEP_CONFIRMED); lbs_debugfs_init(); - lbs_deb_leave(LBS_DEB_MAIN); + return 0; } static void __exit lbs_exit_module(void) { - lbs_deb_enter(LBS_DEB_MAIN); lbs_debugfs_remove(); - lbs_deb_leave(LBS_DEB_MAIN); } module_init(lbs_init_module); diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c index 2229fb448189..eeeb892219aa 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.c +++ b/drivers/net/wireless/marvell/libertas/mesh.c @@ -26,8 +26,6 @@ static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, { int ret; - lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); - cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS); cmd->hdr.size = cpu_to_le16(sizeof(*cmd)); cmd->hdr.result = 0; @@ -36,7 +34,6 @@ static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd); - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -47,8 +44,6 @@ static int __lbs_mesh_config_send(struct lbs_private *priv, int ret; u16 command = CMD_MESH_CONFIG_OLD; - lbs_deb_enter(LBS_DEB_CMD); - /* * Command id is 0xac for v10 FW along with mesh interface * id in bits 14-13-12. @@ -66,7 +61,6 @@ static int __lbs_mesh_config_send(struct lbs_private *priv, ret = lbs_cmd_with_response(priv, command, cmd); - lbs_deb_leave(LBS_DEB_CMD); return ret; } @@ -823,8 +817,6 @@ int lbs_init_mesh(struct lbs_private *priv) { int ret = 0; - lbs_deb_enter(LBS_DEB_MESH); - /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ /* 5.110.22 have mesh command with 0xa3 command id */ @@ -870,7 +862,6 @@ int lbs_init_mesh(struct lbs_private *priv) ret = 1; } - lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; } @@ -887,14 +878,11 @@ int lbs_deinit_mesh(struct lbs_private *priv) struct net_device *dev = priv->dev; int ret = 0; - lbs_deb_enter(LBS_DEB_MESH); - if (priv->mesh_tlv) { device_remove_file(&dev->dev, &dev_attr_lbs_mesh); ret = 1; } - lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; } @@ -909,7 +897,6 @@ static int lbs_mesh_stop(struct net_device *dev) { struct lbs_private *priv = dev->ml_priv; - lbs_deb_enter(LBS_DEB_MESH); lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, lbs_mesh_get_channel(priv)); @@ -924,7 +911,6 @@ static int lbs_mesh_stop(struct net_device *dev) if (!lbs_iface_active(priv)) lbs_stop_iface(priv); - lbs_deb_leave(LBS_DEB_MESH); return 0; } @@ -939,7 +925,6 @@ static int lbs_mesh_dev_open(struct net_device *dev) struct lbs_private *priv = dev->ml_priv; int ret = 0; - lbs_deb_enter(LBS_DEB_NET); if (!priv->iface_running) { ret = lbs_start_iface(priv); if (ret) @@ -965,7 +950,6 @@ static int lbs_mesh_dev_open(struct net_device *dev) lbs_mesh_get_channel(priv)); out: - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } @@ -989,8 +973,6 @@ static int lbs_add_mesh(struct lbs_private *priv) struct wireless_dev *mesh_wdev; int ret = 0; - lbs_deb_enter(LBS_DEB_MESH); - /* Allocate a virtual mesh device */ mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (!mesh_wdev) { @@ -1048,7 +1030,6 @@ err_free_wdev: kfree(mesh_wdev); done: - lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; } @@ -1060,7 +1041,6 @@ void lbs_remove_mesh(struct lbs_private *priv) if (!mesh_dev) return; - lbs_deb_enter(LBS_DEB_MESH); netif_stop_queue(mesh_dev); netif_carrier_off(mesh_dev); sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); @@ -1069,7 +1049,6 @@ void lbs_remove_mesh(struct lbs_private *priv) priv->mesh_dev = NULL; kfree(mesh_dev->ieee80211_ptr); free_netdev(mesh_dev); - lbs_deb_leave(LBS_DEB_MESH); } @@ -1126,8 +1105,6 @@ void lbs_mesh_ethtool_get_stats(struct net_device *dev, struct cmd_ds_mesh_access mesh_access; int ret; - lbs_deb_enter(LBS_DEB_ETHTOOL); - /* Get Mesh Statistics */ ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access); @@ -1153,8 +1130,6 @@ void lbs_mesh_ethtool_get_stats(struct net_device *dev, data[5] = priv->mstats.fwd_bcast_cnt; data[6] = priv->mstats.drop_blind; data[7] = priv->mstats.tx_failed_cnt; - - lbs_deb_enter(LBS_DEB_ETHTOOL); } int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset) @@ -1170,12 +1145,9 @@ int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset) void lbs_mesh_ethtool_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *s) { - lbs_deb_enter(LBS_DEB_ETHTOOL); - switch (stringset) { case ETH_SS_STATS: memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings)); break; } - lbs_deb_enter(LBS_DEB_ETHTOOL); } diff --git a/drivers/net/wireless/marvell/libertas/rx.c b/drivers/net/wireless/marvell/libertas/rx.c index e446fed7b345..a18bb7a9889c 100644 --- a/drivers/net/wireless/marvell/libertas/rx.c +++ b/drivers/net/wireless/marvell/libertas/rx.c @@ -65,8 +65,6 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - lbs_deb_enter(LBS_DEB_RX); - BUG_ON(!skb); skb->ip_summed = CHECKSUM_NONE; @@ -158,7 +156,6 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) ret = 0; done: - lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; } EXPORT_SYMBOL_GPL(lbs_process_rxed_packet); @@ -221,8 +218,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, struct rx_radiotap_hdr radiotap_hdr; struct rx_radiotap_hdr *pradiotap_hdr; - lbs_deb_enter(LBS_DEB_RX); - p_rx_pkt = (struct rx80211packethdr *) skb->data; prxpd = &p_rx_pkt->rx_pd; @@ -281,6 +276,5 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, ret = 0; done: - lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/marvell/libertas/tx.c b/drivers/net/wireless/marvell/libertas/tx.c index c025f9c18282..723ba5fd0bfe 100644 --- a/drivers/net/wireless/marvell/libertas/tx.c +++ b/drivers/net/wireless/marvell/libertas/tx.c @@ -70,8 +70,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) uint16_t pkt_len; netdev_tx_t ret = NETDEV_TX_OK; - lbs_deb_enter(LBS_DEB_TX); - /* We need to protect against the queues being restarted before we get round to stopping them */ spin_lock_irqsave(&priv->driver_lock, flags); @@ -166,7 +164,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->driver_lock, flags); wake_up(&priv->waitq); - lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret); return ret; } -- cgit v1.2.3 From 6b81745e36e346e8aa936219d0311b384313bee3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:46:53 +0200 Subject: rt2x00: change function pointers for register accessors This prepares the driver for changing all the 'read' register accessors to return the value instead of passing it by reference. Since a lot of them are used in callbacks, this takes care of the callbacks first, adding a couple of helpers that will be removed again one at a time. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 18 +++++++++++---- drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 18 +++++++++++---- drivers/net/wireless/ralink/rt2x00/rt2500usb.c | 24 ++++++++++++++------ drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 28 +++++++++++++++++++----- drivers/net/wireless/ralink/rt2x00/rt2800lib.h | 20 ++++++++++++----- drivers/net/wireless/ralink/rt2x00/rt2800pci.c | 4 ++-- drivers/net/wireless/ralink/rt2x00/rt2800soc.c | 4 ++-- drivers/net/wireless/ralink/rt2x00/rt2800usb.c | 4 ++-- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 13 +++++++++++ drivers/net/wireless/ralink/rt2x00/rt2x00debug.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00debug.h | 4 ++-- drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h | 6 +++++ drivers/net/wireless/ralink/rt2x00/rt2x00usb.h | 22 ++++++++++++++++++- drivers/net/wireless/ralink/rt2x00/rt61pci.c | 17 ++++++++++---- drivers/net/wireless/ralink/rt2x00/rt73usb.c | 17 ++++++++++---- 15 files changed, 157 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 19874439ac40..3ba9a1674e1d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -164,10 +164,20 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS +static u8 _rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) +{ + u8 value; + + rt2400pci_bbp_read(rt2x00dev, word, &value); + + return value; +} + static const struct rt2x00debug rt2400pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2x00mmio_register_read, + .read = _rt2x00mmio_register_read, .write = rt2x00mmio_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -175,21 +185,21 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { - .read = rt2x00_eeprom_read, + .read = _rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = rt2400pci_bbp_read, + .read = _rt2400pci_bbp_read, .write = rt2400pci_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = rt2x00_rf_read, + .read = _rt2x00_rf_read, .write = rt2400pci_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index 791434de8052..d9b061b73e83 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -164,10 +164,20 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS +static u8 _rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) +{ + u8 value; + + rt2500pci_bbp_read(rt2x00dev, word, &value); + + return value; +} + static const struct rt2x00debug rt2500pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2x00mmio_register_read, + .read = _rt2x00mmio_register_read, .write = rt2x00mmio_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -175,21 +185,21 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { - .read = rt2x00_eeprom_read, + .read = _rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = rt2500pci_bbp_read, + .read = _rt2500pci_bbp_read, .write = rt2500pci_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = rt2x00_rf_read, + .read = _rt2x00_rf_read, .write = rt2500pci_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index 0d2670a56c4c..5bd160f732de 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -216,14 +216,14 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -static void _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) +static u32 _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { u16 tmp; rt2500usb_register_read(rt2x00dev, offset, &tmp); - *value = tmp; + + return tmp; } static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, @@ -233,6 +233,16 @@ static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write(rt2x00dev, offset, value); } +static u8 _rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) +{ + u8 value; + + rt2500usb_bbp_read(rt2x00dev, word, &value); + + return value; +} + static const struct rt2x00debug rt2500usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { @@ -244,21 +254,21 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u16), }, .eeprom = { - .read = rt2x00_eeprom_read, + .read = _rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = rt2500usb_bbp_read, + .read = _rt2500usb_bbp_read, .write = rt2500usb_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = rt2x00_rf_read, + .read = _rt2x00_rf_read, .write = rt2500usb_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index d11c7b210e81..87cfc135e564 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1225,10 +1225,28 @@ void rt2800_clear_beacon(struct queue_entry *entry) EXPORT_SYMBOL_GPL(rt2800_clear_beacon); #ifdef CONFIG_RT2X00_LIB_DEBUGFS +static u8 _rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) +{ + u8 value; + + rt2800_bbp_read(rt2x00dev, word, &value); + + return value; +} + +static u8 _rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) +{ + u8 value; + + rt2800_rfcsr_read(rt2x00dev, word, &value); + + return value; +} + const struct rt2x00debug rt2800_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2800_register_read, + .read = _rt2800_register_read, .write = rt2800_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -1239,28 +1257,28 @@ const struct rt2x00debug rt2800_rt2x00debug = { /* NOTE: The local EEPROM access functions can't * be used here, use the generic versions instead. */ - .read = rt2x00_eeprom_read, + .read = _rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = rt2800_bbp_read, + .read = _rt2800_bbp_read, .write = rt2800_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = rt2x00_rf_read, + .read = _rt2x00_rf_read, .write = rt2800_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, .rfcsr = { - .read = rt2800_rfcsr_read, + .read = _rt2800_rfcsr_read, .write = rt2800_rfcsr_write, .word_base = RFCSR_BASE, .word_size = sizeof(u8), diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h index f357531d9488..6bed0d5e930e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -49,10 +49,10 @@ struct rt2800_drv_data { }; struct rt2800_ops { - void (*register_read)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value); - void (*register_read_lock)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value); + u32 (*register_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset); + u32 (*register_read_lock)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset); void (*register_write)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 value); void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, @@ -84,7 +84,7 @@ static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, { const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; - rt2800ops->register_read(rt2x00dev, offset, value); + *value = rt2800ops->register_read(rt2x00dev, offset); } static inline void rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev, @@ -93,7 +93,15 @@ static inline void rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev, { const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; - rt2800ops->register_read_lock(rt2x00dev, offset, value); + *value = rt2800ops->register_read_lock(rt2x00dev, offset); +} + +static inline u32 _rt2800_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) +{ + const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; + + return rt2800ops->register_read(rt2x00dev, offset); } static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c index 0af22573a2eb..98f16312e3f1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c @@ -325,8 +325,8 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = { }; static const struct rt2800_ops rt2800pci_rt2800_ops = { - .register_read = rt2x00mmio_register_read, - .register_read_lock = rt2x00mmio_register_read, /* same for PCI */ + .register_read = _rt2x00mmio_register_read, + .register_read_lock = _rt2x00mmio_register_read, /* same for PCI */ .register_write = rt2x00mmio_register_write, .register_write_lock = rt2x00mmio_register_write, /* same for PCI */ .register_multiread = rt2x00mmio_register_multiread, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index a985a5a7945e..c1eda3798b9b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -164,8 +164,8 @@ static const struct ieee80211_ops rt2800soc_mac80211_ops = { }; static const struct rt2800_ops rt2800soc_rt2800_ops = { - .register_read = rt2x00mmio_register_read, - .register_read_lock = rt2x00mmio_register_read, /* same for SoCs */ + .register_read = _rt2x00mmio_register_read, + .register_read_lock = _rt2x00mmio_register_read, /* same for SoCs */ .register_write = rt2x00mmio_register_write, .register_write_lock = rt2x00mmio_register_write, /* same for SoCs */ .register_multiread = rt2x00mmio_register_multiread, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index f11e3f532a84..7fd7e6114c0c 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -802,8 +802,8 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { }; static const struct rt2800_ops rt2800usb_rt2800_ops = { - .register_read = rt2x00usb_register_read, - .register_read_lock = rt2x00usb_register_read_lock, + .register_read = _rt2x00usb_register_read, + .register_read_lock = _rt2x00usb_register_read_lock, .register_write = rt2x00usb_register_write, .register_write_lock = rt2x00usb_register_write_lock, .register_multiread = rt2x00usb_register_multiread, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 1bc353eafe37..f2ae33bf2ef2 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1056,6 +1056,13 @@ static inline void rt2x00_rf_read(struct rt2x00_dev *rt2x00dev, *data = rt2x00dev->rf[word - 1]; } +static inline u32 _rt2x00_rf_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) +{ + BUG_ON(word < 1 || word > rt2x00dev->ops->rf_size / sizeof(u32)); + return rt2x00dev->rf[word - 1]; +} + static inline void rt2x00_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 data) { @@ -1078,6 +1085,12 @@ static inline void rt2x00_eeprom_read(struct rt2x00_dev *rt2x00dev, *data = le16_to_cpu(rt2x00dev->eeprom[word]); } +static inline u16 _rt2x00_eeprom_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) +{ + return le16_to_cpu(rt2x00dev->eeprom[word]); +} + static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, u16 data) { diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index 964aefdc11f0..4a1bca1b1e26 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -460,7 +460,7 @@ static ssize_t rt2x00debug_read_##__name(struct file *file, \ if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ index *= debug->__name.word_size; \ \ - debug->__name.read(intf->rt2x00dev, index, &value); \ + value = debug->__name.read(intf->rt2x00dev, index); \ \ size = sprintf(line, __format, value); \ \ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.h b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.h index e65712c235bd..a357a0727a0b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.h @@ -38,8 +38,8 @@ enum rt2x00debugfs_entry_flags { #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \ struct reg##__name { \ - void (*read)(struct rt2x00_dev *rt2x00dev, \ - const unsigned int word, __type *data); \ + __type (*read)(struct rt2x00_dev *rt2x00dev, \ + const unsigned int word); \ void (*write)(struct rt2x00_dev *rt2x00dev, \ const unsigned int word, __type data); \ \ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h index 701c3127efb9..6d7a27ee6444 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h @@ -36,6 +36,12 @@ static inline void rt2x00mmio_register_read(struct rt2x00_dev *rt2x00dev, *value = readl(rt2x00dev->csr.base + offset); } +static inline u32 _rt2x00mmio_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) +{ + return readl(rt2x00dev->csr.base + offset); +} + static inline void rt2x00mmio_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u32 length) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h index 569363da00a2..4cad1beec791 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h @@ -206,6 +206,16 @@ static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, *value = le32_to_cpu(reg); } +static inline u32 _rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) +{ + __le32 reg = 0; + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(reg)); + return le32_to_cpu(reg); +} + /** * rt2x00usb_register_read_lock - Read 32bit register word * @rt2x00dev: Device pointer, see &struct rt2x00_dev. @@ -216,7 +226,7 @@ static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, * through rt2x00usb_vendor_req_buff_lock(). */ static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, + const unsigned int offset, u32 *value) { __le32 reg = 0; @@ -226,6 +236,16 @@ static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, *value = le32_to_cpu(reg); } +static inline u32 _rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) +{ + __le32 reg = 0; + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); + return le32_to_cpu(reg); +} + /** * rt2x00usb_register_multiread - Read 32bit register words * @rt2x00dev: Device pointer, see &struct rt2x00_dev. diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index 973d418b8113..efe8a766b251 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -202,10 +202,19 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS +static u8 _rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) +{ + u8 value; + + rt61pci_bbp_read(rt2x00dev, word, &value); + + return value; +} + static const struct rt2x00debug rt61pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2x00mmio_register_read, + .read = _rt2x00mmio_register_read, .write = rt2x00mmio_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -213,21 +222,21 @@ static const struct rt2x00debug rt61pci_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { - .read = rt2x00_eeprom_read, + .read = _rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = rt61pci_bbp_read, + .read = _rt61pci_bbp_read, .write = rt61pci_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = rt2x00_rf_read, + .read = _rt2x00_rf_read, .write = rt61pci_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index bb8d307a789f..5db174922120 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -147,10 +147,19 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, } #ifdef CONFIG_RT2X00_LIB_DEBUGFS +static u8 _rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) +{ + u8 value; + + rt73usb_bbp_read(rt2x00dev, word, &value); + + return value; +} + static const struct rt2x00debug rt73usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2x00usb_register_read, + .read = _rt2x00usb_register_read, .write = rt2x00usb_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -158,21 +167,21 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { - .read = rt2x00_eeprom_read, + .read = _rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = rt73usb_bbp_read, + .read = _rt73usb_bbp_read, .write = rt73usb_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = rt2x00_rf_read, + .read = _rt2x00_rf_read, .write = rt73usb_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), -- cgit v1.2.3 From 16d571bb0fe6aa7fed82e19166ca1542026c9c06 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:46:54 +0200 Subject: rt2x00: convert rt2800_rfcsr_read return type With CONFIG_KASAN enabled and gcc-7, we get a warning about rather high stack usage (with a private patch set I have to turn on this warning, which I intend to get into the next kernel release): wireless/ralink/rt2x00/rt2800lib.c: In function 'rt2800_bw_filter_calibration': wireless/ralink/rt2x00/rt2800lib.c:7990:1: error: the frame size of 2144 bytes is larger than 1536 bytes [-Werror=frame-larger-than=] The problem is that KASAN inserts a redzone around each local variable that gets passed by reference, and the newly added function has a lot of them. This is a semi-automated conversion to change rt2800_rfcsr_read to return the register contents instead of passing them by value, resulting in much better object code. The majority of the patch was done using: sed -i 's:\(rt2800_rfcsr_read(.*, .*\), &\(.*\));:\2 = \1);:' \ -i 's:\(rt2800_rfcsr_read_bank(.*, .*\), &\(.*\));:\2 = \1);:' \ drivers/net/wireless/ralink/rt2x00/rt2800lib.c Fixes: 41977e86c984 ("rt2x00: add support for MT7620") Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 322 ++++++++++++------------- 1 file changed, 158 insertions(+), 164 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 87cfc135e564..9b8c19dcdb2c 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -203,10 +203,11 @@ static void rt2800_rfcsr_write_dccal(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write_bank(rt2x00dev, 7, reg, value); } -static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -232,7 +233,7 @@ static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_RFCSR_MT7620(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA_MT7620); + value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA_MT7620); break; default: @@ -247,17 +248,19 @@ static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_RFCSR(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); + value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); break; } mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } -static void rt2800_rfcsr_read_bank(struct rt2x00_dev *rt2x00dev, const u8 bank, - const unsigned int reg, u8 *value) +static u8 rt2800_rfcsr_read_bank(struct rt2x00_dev *rt2x00dev, const u8 bank, + const unsigned int reg) { - rt2800_rfcsr_read(rt2x00dev, (reg | (bank << 6)), value); + return rt2800_rfcsr_read(rt2x00dev, (reg | (bank << 6))); } static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, @@ -1234,15 +1237,6 @@ static u8 _rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word return value; } -static u8 _rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) -{ - u8 value; - - rt2800_rfcsr_read(rt2x00dev, word, &value); - - return value; -} - const struct rt2x00debug rt2800_rt2x00debug = { .owner = THIS_MODULE, .csr = { @@ -1278,7 +1272,7 @@ const struct rt2x00debug rt2800_rt2x00debug = { .word_count = RF_SIZE / sizeof(u32), }, .rfcsr = { - .read = _rt2800_rfcsr_read, + .read = rt2800_rfcsr_read, .write = rt2800_rfcsr_write, .word_base = RFCSR_BASE, .word_size = sizeof(u8), @@ -2090,7 +2084,7 @@ static void rt2800_freq_cal_mode1(struct rt2x00_dev *rt2x00dev) freq_offset = rt2x00_get_field8(rt2x00dev->freq_offset, RFCSR17_CODE); freq_offset = min_t(u8, freq_offset, FREQ_OFFSET_BOUND); - rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 17); prev_rfcsr = rfcsr; rt2x00_set_field8(&rfcsr, RFCSR17_CODE, freq_offset); @@ -2192,23 +2186,23 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); rt2x00_set_field8(&rfcsr, RFCSR3_K, rf->rf3); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 12); rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1); rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 13); rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2); rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, rt2x00dev->default_ant.rx_chain_num <= 1); @@ -2221,7 +2215,7 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, rt2x00dev->default_ant.tx_chain_num <= 2); rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 23); rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); @@ -2238,19 +2232,19 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, } } - rt2800_rfcsr_read(rt2x00dev, 24, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 24); rt2x00_set_field8(&rfcsr, RFCSR24_TX_CALIB, calib_tx); rt2800_rfcsr_write(rt2x00dev, 24, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 31, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 31); rt2x00_set_field8(&rfcsr, RFCSR31_RX_CALIB, calib_rx); rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 7); rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); @@ -2280,7 +2274,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 2); @@ -2288,14 +2282,14 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 5, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 5); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR5_R1, 1); else rt2x00_set_field8(&rfcsr, RFCSR5_R1, 2); rt2800_rfcsr_write(rt2x00dev, 5, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 12); if (rf->channel <= 14) { rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 3); rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, @@ -2308,7 +2302,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 13); if (rf->channel <= 14) { rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 3); rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, @@ -2321,7 +2315,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); @@ -2354,7 +2348,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 23); rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); @@ -2384,7 +2378,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 27, 0x00); rt2800_rfcsr_write(rt2x00dev, 29, 0x9b); } else { - rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 7); rt2x00_set_field8(&rfcsr, RFCSR7_BIT2, 1); rt2x00_set_field8(&rfcsr, RFCSR7_BIT3, 0); rt2x00_set_field8(&rfcsr, RFCSR7_BIT4, 1); @@ -2425,7 +2419,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, GPIO_CTRL_VAL7, 0); rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); - rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 7); rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); } @@ -2468,11 +2462,11 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3 & 0xf); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_R, (rf->rf2 & 0x3)); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_PLL_IDOH, 1); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 1); @@ -2480,7 +2474,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 2); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 53, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 53); if (rf->channel <= 14) { rfcsr = 0; rt2x00_set_field8(&rfcsr, RFCSR53_TX_POWER, @@ -2495,7 +2489,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 53, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 55, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 55); if (rf->channel <= 14) { rfcsr = 0; rt2x00_set_field8(&rfcsr, RFCSR55_TX_POWER, @@ -2510,7 +2504,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 55, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 54, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 54); if (rf->channel <= 14) { rfcsr = 0; rt2x00_set_field8(&rfcsr, RFCSR54_TX_POWER, @@ -2525,7 +2519,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 54, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0); @@ -2577,7 +2571,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, /* NOTE: the reference driver does not writes the new value * back to RFCSR 32 */ - rt2800_rfcsr_read(rt2x00dev, 32, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 32); rt2x00_set_field8(&rfcsr, RFCSR32_TX_AGC_FC, txrx_agc_fc); if (rf->channel <= 14) @@ -2586,34 +2580,34 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rfcsr = 0x80; rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, txrx_h20m); rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, txrx_h20m); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); /* Band selection */ - rt2800_rfcsr_read(rt2x00dev, 36, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 36); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 1); else rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 0); rt2800_rfcsr_write(rt2x00dev, 36, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 34, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 34); if (rf->channel <= 14) rfcsr = 0x3c; else rfcsr = 0x20; rt2800_rfcsr_write(rt2x00dev, 34, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 12); if (rf->channel <= 14) rfcsr = 0x1a; else rfcsr = 0x12; rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); if (rf->channel >= 1 && rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1); else if (rf->channel >= 36 && rf->channel <= 64) @@ -2624,7 +2618,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); @@ -2638,11 +2632,11 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 13, 0x23); } - rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 51); rt2x00_set_field8(&rfcsr, RFCSR51_BITS01, 1); rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 51); if (rf->channel <= 14) { rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, 5); rt2x00_set_field8(&rfcsr, RFCSR51_BITS57, 3); @@ -2652,7 +2646,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 49); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR49_TX_LO1_IC, 3); else @@ -2663,11 +2657,11 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 50); rt2x00_set_field8(&rfcsr, RFCSR50_TX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 57, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 57); if (rf->channel <= 14) rt2x00_set_field8(&rfcsr, RFCSR57_DRV_CC, 0x1b); else @@ -2683,7 +2677,7 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, } /* Initiate VCO calibration */ - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); if (rf->channel <= 14) { rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); } else { @@ -2739,11 +2733,11 @@ static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 49); if (info->default_power1 > POWER_BOUND) rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); else @@ -2793,7 +2787,7 @@ static void rt2800_config_channel_rf3322(struct rt2x00_dev *rt2x00dev, rt2800_freq_cal_mode1(rt2x00dev); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1); rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1); @@ -2824,11 +2818,11 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 49); if (info->default_power1 > POWER_BOUND) rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); else @@ -2836,7 +2830,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); if (rt2x00_rt(rt2x00dev, RT5392)) { - rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 50); if (info->default_power2 > POWER_BOUND) rt2x00_set_field8(&rfcsr, RFCSR50_TX, POWER_BOUND); else @@ -2845,7 +2839,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); } - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); if (rt2x00_rt(rt2x00dev, RT5392)) { rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1); rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); @@ -2937,13 +2931,13 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, /* Order of values on rf_channel entry: N, K, mod, R */ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1 & 0xff); - rt2800_rfcsr_read(rt2x00dev, 9, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 9); rt2x00_set_field8(&rfcsr, RFCSR9_K, rf->rf2 & 0xf); rt2x00_set_field8(&rfcsr, RFCSR9_N, (rf->rf1 & 0x100) >> 8); rt2x00_set_field8(&rfcsr, RFCSR9_MOD, ((rf->rf3 - 8) & 0x4) >> 2); rt2800_rfcsr_write(rt2x00dev, 9, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 11); rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf4 - 1); rt2x00_set_field8(&rfcsr, RFCSR11_MOD, (rf->rf3 - 8) & 0x3); rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); @@ -3111,7 +3105,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, ep_reg = 0x3; } - rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 49); if (info->default_power1 > power_bound) rt2x00_set_field8(&rfcsr, RFCSR49_TX, power_bound); else @@ -3120,7 +3114,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR49_EP, ep_reg); rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 50); if (info->default_power2 > power_bound) rt2x00_set_field8(&rfcsr, RFCSR50_TX, power_bound); else @@ -3129,7 +3123,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR50_EP, ep_reg); rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1); @@ -3162,7 +3156,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, rt2800_freq_cal_mode1(rt2x00dev); /* TODO merge with others */ - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); @@ -3204,7 +3198,7 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, /* Rdiv setting (set 0x03 if Xtal==20) * R13[1:0] */ - rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 13); rt2x00_set_field8(&rfcsr, RFCSR13_RDIV_MT7620, rt2800_clk_is_20mhz(rt2x00dev) ? 3 : 0); rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); @@ -3213,25 +3207,25 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, * R20[7:0] in rf->rf1 * R21[0] always 0 */ - rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 20); rfcsr = (rf->rf1 & 0x00ff); rt2800_rfcsr_write(rt2x00dev, 20, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); rt2x00_set_field8(&rfcsr, RFCSR21_BIT1, 0); rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); /* K setting (always 0) * R16[3:0] (RF PLL freq selection) */ - rt2800_rfcsr_read(rt2x00dev, 16, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 16); rt2x00_set_field8(&rfcsr, RFCSR16_RF_PLL_FREQ_SEL_MT7620, 0); rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); /* D setting (always 0) * R22[2:0] (D=15, R22[2:0]=<111>) */ - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 22); rt2x00_set_field8(&rfcsr, RFCSR22_FREQPLAN_D_MT7620, 0); rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); @@ -3240,40 +3234,40 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, * R18<7:0> in rf->rf3 * R19<1:0> in rf->rf4 */ - rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 17); rfcsr = rf->rf2; rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 18, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 18); rfcsr = rf->rf3; rt2800_rfcsr_write(rt2x00dev, 18, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 19, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 19); rt2x00_set_field8(&rfcsr, RFCSR19_K, rf->rf4); rt2800_rfcsr_write(rt2x00dev, 19, rfcsr); /* Default: XO=20MHz , SDM mode */ - rt2800_rfcsr_read(rt2x00dev, 16, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 16); rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 0x80); rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1); rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_TX2_EN_MT7620, rt2x00dev->default_ant.tx_chain_num != 1); rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 2); rt2x00_set_field8(&rfcsr, RFCSR2_TX2_EN_MT7620, rt2x00dev->default_ant.tx_chain_num != 1); rt2x00_set_field8(&rfcsr, RFCSR2_RX2_EN_MT7620, rt2x00dev->default_ant.rx_chain_num != 1); rt2800_rfcsr_write(rt2x00dev, 2, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 42, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 42); rt2x00_set_field8(&rfcsr, RFCSR42_TX2_EN_MT7620, rt2x00dev->default_ant.tx_chain_num != 1); rt2800_rfcsr_write(rt2x00dev, 42, rfcsr); @@ -3301,7 +3295,7 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28); } - rt2800_rfcsr_read(rt2x00dev, 28, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 28); rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40, conf_is_ht40(conf) && (rf->channel == 11)); rt2800_rfcsr_write(rt2x00dev, 28, rfcsr); @@ -3314,36 +3308,36 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, rx_agc_fc = drv_data->rx_calibration_bw20; tx_agc_fc = drv_data->tx_calibration_bw20; } - rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 5, 6); rfcsr &= (~0x3F); rfcsr |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 6, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 5, 7); rfcsr &= (~0x3F); rfcsr |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 7, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 7, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 7, 6); rfcsr &= (~0x3F); rfcsr |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 7, 6, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 7, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 7, 7); rfcsr &= (~0x3F); rfcsr |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 7, 7, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 58, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 5, 58); rfcsr &= (~0x3F); rfcsr |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 58, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 59, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 5, 59); rfcsr &= (~0x3F); rfcsr |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 59, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 7, 58, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 7, 58); rfcsr &= (~0x3F); rfcsr |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 7, 58, rfcsr); - rt2800_rfcsr_read_bank(rt2x00dev, 7, 59, &rfcsr); + rfcsr = rt2800_rfcsr_read_bank(rt2x00dev, 7, 59); rfcsr &= (~0x3F); rfcsr |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 7, 59, rfcsr); @@ -3615,7 +3609,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_rf(rt2x00dev, RF5372) || rt2x00_rf(rt2x00dev, RF5390) || rt2x00_rf(rt2x00dev, RF5392)) { - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); if (rt2x00_rf(rt2x00dev, RF3322)) { rt2x00_set_field8(&rfcsr, RF3322_RFCSR30_TX_H20M, conf_is_ht40(conf)); @@ -3629,7 +3623,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, } rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); } @@ -4882,7 +4876,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) case RF3022: case RF3320: case RF3052: - rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 7); rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); break; @@ -4897,7 +4891,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) case RF5390: case RF5392: case RF5592: - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 3); rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); min_sleep = 1000; @@ -4905,7 +4899,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) case RF7620: rt2800_rfcsr_write(rt2x00dev, 5, 0x40); rt2800_rfcsr_write(rt2x00dev, 4, 0x0C); - rt2800_rfcsr_read(rt2x00dev, 4, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 4); rt2x00_set_field8(&rfcsr, RFCSR4_VCOCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 4, rfcsr); min_sleep = 2000; @@ -6633,11 +6627,11 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40, rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); rt2800_bbp_write(rt2x00dev, 4, bbp); - rt2800_rfcsr_read(rt2x00dev, 31, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 31); rt2x00_set_field8(&rfcsr, RFCSR31_RX_H20M, bw40); rt2800_rfcsr_write(rt2x00dev, 31, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 22); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); @@ -6686,7 +6680,7 @@ static void rt2800_rf_init_calibration(struct rt2x00_dev *rt2x00dev, { u8 rfcsr; - rt2800_rfcsr_read(rt2x00dev, rf_reg, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, rf_reg); rt2x00_set_field8(&rfcsr, FIELD8(0x80), 1); rt2800_rfcsr_write(rt2x00dev, rf_reg, rfcsr); msleep(1); @@ -6728,7 +6722,7 @@ static void rt2800_rx_filter_calibration(struct rt2x00_dev *rt2x00dev) */ rt2800_bbp_write(rt2x00dev, 24, 0); - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 22); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); @@ -6746,7 +6740,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) u8 min_gain, rfcsr, bbp; u16 eeprom; - rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 17); rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0); if (rt2x00_rt(rt2x00dev, RT3070) || @@ -6777,7 +6771,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) } if (rt2x00_rt(rt2x00dev, RT3070)) { - rt2800_rfcsr_read(rt2x00dev, 27, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 27); if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) rt2x00_set_field8(&rfcsr, RFCSR27_R1, 3); else @@ -6789,7 +6783,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) } else if (rt2x00_rt(rt2x00dev, RT3071) || rt2x00_rt(rt2x00dev, RT3090) || rt2x00_rt(rt2x00dev, RT3390)) { - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0); rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0); @@ -6797,15 +6791,15 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1); rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 15, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 15); rt2x00_set_field8(&rfcsr, RFCSR15_TX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 15, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 20); rt2x00_set_field8(&rfcsr, RFCSR20_RX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 20, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); rt2x00_set_field8(&rfcsr, RFCSR21_RX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); } @@ -6817,30 +6811,30 @@ static void rt2800_normal_mode_setup_3593(struct rt2x00_dev *rt2x00dev) u8 rfcsr; u8 tx_gain; - rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 50); rt2x00_set_field8(&rfcsr, RFCSR50_TX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 51); tx_gain = rt2x00_get_field8(drv_data->txmixer_gain_24g, RFCSR17_TXMIXER_GAIN); rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, tx_gain); rt2800_rfcsr_write(rt2x00dev, 51, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 38); rt2x00_set_field8(&rfcsr, RFCSR38_RX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 38, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 39, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 39); rt2x00_set_field8(&rfcsr, RFCSR39_RX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 39, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1); rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1); rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); @@ -6861,17 +6855,17 @@ static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(®, BBP138_TX_DAC1, 1); rt2800_bbp_write(rt2x00dev, 138, reg); - rt2800_rfcsr_read(rt2x00dev, 38, ®); + reg = rt2800_rfcsr_read(rt2x00dev, 38); rt2x00_set_field8(®, RFCSR38_RX_LO1_EN, 0); rt2800_rfcsr_write(rt2x00dev, 38, reg); - rt2800_rfcsr_read(rt2x00dev, 39, ®); + reg = rt2800_rfcsr_read(rt2x00dev, 39); rt2x00_set_field8(®, RFCSR39_RX_LO2_EN, 0); rt2800_rfcsr_write(rt2x00dev, 39, reg); rt2800_bbp4_mac_if_ctrl(rt2x00dev); - rt2800_rfcsr_read(rt2x00dev, 30, ®); + reg = rt2800_rfcsr_read(rt2x00dev, 30); rt2x00_set_field8(®, RFCSR30_RX_VCM, 2); rt2800_rfcsr_write(rt2x00dev, 30, reg); } @@ -6952,7 +6946,7 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) rt2x00_rt(rt2x00dev, RT3090)) { rt2800_rfcsr_write(rt2x00dev, 31, 0x14); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); @@ -7038,7 +7032,7 @@ static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 60, 0x45); rt2800_rfcsr_write(rt2x00dev, 61, 0xc1); - rt2800_rfcsr_read(rt2x00dev, 29, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 29); rt2x00_set_field8(&rfcsr, RFCSR29_RSSI_GAIN, 3); rt2800_rfcsr_write(rt2x00dev, 29, rfcsr); @@ -7236,7 +7230,7 @@ static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 30, 0x09); rt2800_rfcsr_write(rt2x00dev, 31, 0x10); - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 6); rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); @@ -7350,13 +7344,13 @@ static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) /* Initiate calibration */ /* TODO: use rt2800_rf_init_calibration ? */ - rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 2); rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 2, rfcsr); rt2800_freq_cal_mode1(rt2x00dev); - rt2800_rfcsr_read(rt2x00dev, 18, &rfcsr); + rfcsr = rt2800_rfcsr_read(rt2x00dev, 18); rt2x00_set_field8(&rfcsr, RFCSR18_XO_TUNE_BYPASS, 1); rt2800_rfcsr_write(rt2x00dev, 18, rfcsr); @@ -7698,7 +7692,7 @@ static int rt2800_rf_lp_config(struct rt2x00_dev *rt2x00dev, bool btxcal) rt2800_register_write(rt2x00dev, RF_BYPASS0, 0x06); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 17, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17); rf_val |= 0x80; rt2800_rfcsr_write_bank(rt2x00dev, 5, 17, rf_val); @@ -7706,11 +7700,11 @@ static int rt2800_rf_lp_config(struct rt2x00_dev *rt2x00dev, bool btxcal) rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, 0xC1); rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, 0x20); rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, 0x02); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 3, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3); rf_val &= (~0x3F); rf_val |= 0x3F; rt2800_rfcsr_write_bank(rt2x00dev, 5, 3, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 4, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4); rf_val &= (~0x3F); rf_val |= 0x3F; rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, rf_val); @@ -7719,11 +7713,11 @@ static int rt2800_rf_lp_config(struct rt2x00_dev *rt2x00dev, bool btxcal) rt2800_rfcsr_write_bank(rt2x00dev, 5, 18, 0xF1); rt2800_rfcsr_write_bank(rt2x00dev, 5, 19, 0x18); rt2800_rfcsr_write_bank(rt2x00dev, 5, 20, 0x02); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 3, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3); rf_val &= (~0x3F); rf_val |= 0x34; rt2800_rfcsr_write_bank(rt2x00dev, 5, 3, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 4, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4); rf_val &= (~0x3F); rf_val |= 0x34; rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, rf_val); @@ -7789,51 +7783,51 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, rt2800_bbp_dcoc_read(rt2x00dev, 2, &savebbp159r2); /* Save RF registers */ - rt2800_rfcsr_read_bank(rt2x00dev, 5, 0, &saverfb5r00); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 1, &saverfb5r01); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 3, &saverfb5r03); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 4, &saverfb5r04); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 5, &saverfb5r05); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &saverfb5r06); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 7, &saverfb5r07); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 8, &saverfb5r08); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 17, &saverfb5r17); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 18, &saverfb5r18); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 19, &saverfb5r19); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 20, &saverfb5r20); - - rt2800_rfcsr_read_bank(rt2x00dev, 5, 37, &saverfb5r37); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 38, &saverfb5r38); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 39, &saverfb5r39); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 40, &saverfb5r40); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 41, &saverfb5r41); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 42, &saverfb5r42); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 43, &saverfb5r43); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 44, &saverfb5r44); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 45, &saverfb5r45); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 46, &saverfb5r46); - - rt2800_rfcsr_read_bank(rt2x00dev, 5, 58, &saverfb5r58); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 59, &saverfb5r59); - - rt2800_rfcsr_read_bank(rt2x00dev, 5, 0, &rf_val); + saverfb5r00 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0); + saverfb5r01 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1); + saverfb5r03 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 3); + saverfb5r04 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4); + saverfb5r05 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 5); + saverfb5r06 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 6); + saverfb5r07 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 7); + saverfb5r08 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 8); + saverfb5r17 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 17); + saverfb5r18 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 18); + saverfb5r19 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 19); + saverfb5r20 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 20); + + saverfb5r37 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 37); + saverfb5r38 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 38); + saverfb5r39 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 39); + saverfb5r40 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 40); + saverfb5r41 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 41); + saverfb5r42 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 42); + saverfb5r43 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 43); + saverfb5r44 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 44); + saverfb5r45 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 45); + saverfb5r46 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 46); + + saverfb5r58 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 58); + saverfb5r59 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 59); + + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0); rf_val |= 0x3; rt2800_rfcsr_write_bank(rt2x00dev, 5, 0, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 1, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1); rf_val |= 0x1; rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, rf_val); cnt = 0; do { usleep_range(500, 2000); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 1, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1); if (((rf_val & 0x1) == 0x00) || (cnt == 40)) break; cnt++; } while (cnt < 40); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 0, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0); rf_val &= (~0x3); rf_val |= 0x1; rt2800_rfcsr_write_bank(rt2x00dev, 5, 0, rf_val); @@ -7862,7 +7856,7 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, filter_target = rx_filter_target_40m; } - rt2800_rfcsr_read_bank(rt2x00dev, 5, 8, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 8); rf_val &= (~0x04); if (loop == 1) rf_val |= 0x4; @@ -7874,18 +7868,18 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, rt2800_rf_lp_config(rt2x00dev, btxcal); if (btxcal) { tx_agc_fc = 0; - rt2800_rfcsr_read_bank(rt2x00dev, 5, 58, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 58); rf_val &= (~0x7F); rt2800_rfcsr_write_bank(rt2x00dev, 5, 58, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 59, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 59); rf_val &= (~0x7F); rt2800_rfcsr_write_bank(rt2x00dev, 5, 59, rf_val); } else { rx_agc_fc = 0; - rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 6); rf_val &= (~0x7F); rt2800_rfcsr_write_bank(rt2x00dev, 5, 6, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 7, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 7); rf_val &= (~0x7F); rt2800_rfcsr_write_bank(rt2x00dev, 5, 7, rf_val); } @@ -7905,20 +7899,20 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, rt2800_bbp_dcoc_write(rt2x00dev, 2, bbp_val); do_cal: if (btxcal) { - rt2800_rfcsr_read_bank(rt2x00dev, 5, 58, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 58); rf_val &= (~0x7F); rf_val |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 58, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 59, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 59); rf_val &= (~0x7F); rf_val |= tx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 59, rf_val); } else { - rt2800_rfcsr_read_bank(rt2x00dev, 5, 6, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 6); rf_val &= (~0x7F); rf_val |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 6, rf_val); - rt2800_rfcsr_read_bank(rt2x00dev, 5, 7, &rf_val); + rf_val = rt2800_rfcsr_read_bank(rt2x00dev, 5, 7); rf_val &= (~0x7F); rf_val |= rx_agc_fc; rt2800_rfcsr_write_bank(rt2x00dev, 5, 7, rf_val); -- cgit v1.2.3 From aea8baa10ac5e9acddf80e48593fe85c22d19286 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:46:55 +0200 Subject: rt2x00: convert rt2x00_rf_read return type This is a semi-automated conversion to change rt2x00_rf_read() to return the register contents instead of passing them by value, resulting in much better object code. The majority of the patch was done using: sed -i 's:\(\(.*, .*\), &\(.*\));:\2 = \1);:' \ drivers/net/wireless/ralink/rt2x00/rt* Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 4 ++-- drivers/net/wireless/ralink/rt2x00/rt2500usb.c | 4 ++-- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 11 ++--------- drivers/net/wireless/ralink/rt2x00/rt61pci.c | 10 +++++----- drivers/net/wireless/ralink/rt2x00/rt73usb.c | 10 +++++----- 7 files changed, 18 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 3ba9a1674e1d..d41832292db2 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -199,7 +199,7 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = { .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = _rt2x00_rf_read, + .read = rt2x00_rf_read, .write = rt2400pci_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index d9b061b73e83..232feba0773f 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -199,7 +199,7 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = { .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = _rt2x00_rf_read, + .read = rt2x00_rf_read, .write = rt2500pci_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), @@ -556,7 +556,7 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, { u32 rf3; - rt2x00_rf_read(rt2x00dev, 3, &rf3); + rf3 = rt2x00_rf_read(rt2x00dev, 3); rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); rt2500pci_rf_write(rt2x00dev, 3, rf3); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index 5bd160f732de..9cff9ddafb72 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -268,7 +268,7 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = _rt2x00_rf_read, + .read = rt2x00_rf_read, .write = rt2500usb_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), @@ -639,7 +639,7 @@ static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, { u32 rf3; - rt2x00_rf_read(rt2x00dev, 3, &rf3); + rf3 = rt2x00_rf_read(rt2x00dev, 3); rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); rt2500usb_rf_write(rt2x00dev, 3, rf3); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 9b8c19dcdb2c..fef53d6a888a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1265,7 +1265,7 @@ const struct rt2x00debug rt2800_rt2x00debug = { .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = _rt2x00_rf_read, + .read = rt2x00_rf_read, .write = rt2800_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index f2ae33bf2ef2..36791f7ae2ce 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1049,15 +1049,8 @@ struct rt2x00_bar_list_entry { * Generic RF access. * The RF is being accessed by word index. */ -static inline void rt2x00_rf_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - BUG_ON(word < 1 || word > rt2x00dev->ops->rf_size / sizeof(u32)); - *data = rt2x00dev->rf[word - 1]; -} - -static inline u32 _rt2x00_rf_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word) +static inline u32 rt2x00_rf_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { BUG_ON(word < 1 || word > rt2x00dev->ops->rf_size / sizeof(u32)); return rt2x00dev->rf[word - 1]; diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index efe8a766b251..147d1d2cc0a6 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -236,7 +236,7 @@ static const struct rt2x00debug rt61pci_rt2x00debug = { .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = _rt2x00_rf_read, + .read = rt2x00_rf_read, .write = rt61pci_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), @@ -922,10 +922,10 @@ static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, { struct rf_channel rf; - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + rf.rf1 = rt2x00_rf_read(rt2x00dev, 1); + rf.rf2 = rt2x00_rf_read(rt2x00dev, 2); + rf.rf3 = rt2x00_rf_read(rt2x00dev, 3); + rf.rf4 = rt2x00_rf_read(rt2x00dev, 4); rt61pci_config_channel(rt2x00dev, &rf, txpower); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index 5db174922120..a36dee1a4f20 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -181,7 +181,7 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { .word_count = BBP_SIZE / sizeof(u8), }, .rf = { - .read = _rt2x00_rf_read, + .read = rt2x00_rf_read, .write = rt73usb_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), @@ -805,10 +805,10 @@ static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, { struct rf_channel rf; - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + rf.rf1 = rt2x00_rf_read(rt2x00dev, 1); + rf.rf2 = rt2x00_rf_read(rt2x00dev, 2); + rf.rf3 = rt2x00_rf_read(rt2x00dev, 3); + rf.rf4 = rt2x00_rf_read(rt2x00dev, 4); rt73usb_config_channel(rt2x00dev, &rf, txpower); } -- cgit v1.2.3 From 3954b4e30609ffade5eca3c13eab2fd70c76b44e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:46:56 +0200 Subject: rt2x00: convert rt2x00mmio_register_read return type This is a semi-automated conversion to change rt2x00mmio_register_read to return the register contents instead of passing them by value, resulting in much better object code. The majority of the patch was done using: sed -i 's:\(rt2x00mmio_register_read(.*, .*\), &\(.*\));:\2 = \1);:' \ -i 's:_rt2x00mmio_register_read:rt2x00mmio_register_read:' \ drivers/net/wireless/ralink/rt2x00/*.c The function itself was modified manually along with the one remaining caller that was not covered automatically. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 128 ++++++++-------- drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 140 +++++++++--------- drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 30 ++-- drivers/net/wireless/ralink/rt2x00/rt2800pci.c | 10 +- drivers/net/wireless/ralink/rt2x00/rt2800soc.c | 4 +- drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h | 9 +- drivers/net/wireless/ralink/rt2x00/rt61pci.c | 188 ++++++++++++------------ 8 files changed, 252 insertions(+), 259 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index d41832292db2..3607261df199 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -138,7 +138,7 @@ static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR21, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR21); eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT); @@ -177,7 +177,7 @@ static u8 _rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, static const struct rt2x00debug rt2400pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = _rt2x00mmio_register_read, + .read = rt2x00mmio_register_read, .write = rt2x00mmio_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -212,7 +212,7 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00mmio_register_read(rt2x00dev, GPIOCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); return rt2x00_get_field32(reg, GPIOCSR_VAL0); } @@ -225,7 +225,7 @@ static void rt2400pci_brightness_set(struct led_classdev *led_cdev, unsigned int enabled = brightness != LED_OFF; u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) rt2x00_set_field32(®, LEDCSR_LINK, enabled); @@ -243,7 +243,7 @@ static int rt2400pci_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); rt2x00_set_field32(®, LEDCSR_ON_PERIOD, *delay_on); rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, *delay_off); rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg); @@ -276,7 +276,7 @@ static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev, * Note that the version error will always be dropped * since there is no filter for it at this time. */ - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, @@ -305,14 +305,14 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, * Enable beacon config */ bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); - rt2x00mmio_register_read(rt2x00dev, BCNCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCNCSR1); rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); rt2x00mmio_register_write(rt2x00dev, BCNCSR1, reg); /* * Enable synchronisation. */ - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); rt2x00mmio_register_write(rt2x00dev, CSR14, reg); } @@ -340,35 +340,35 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, if (changed & BSS_CHANGED_ERP_PREAMBLE) { preamble_mask = erp->short_preamble << 3; - rt2x00mmio_register_read(rt2x00dev, TXCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR1); rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x1ff); rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0x13a); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR1, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR2); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00mmio_register_write(rt2x00dev, ARCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR3); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00mmio_register_write(rt2x00dev, ARCSR3, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR4); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00mmio_register_write(rt2x00dev, ARCSR4, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR5); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, @@ -380,23 +380,23 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00mmio_register_write(rt2x00dev, ARCSR1, erp->basic_rates); if (changed & BSS_CHANGED_ERP_SLOT) { - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); rt2x00mmio_register_write(rt2x00dev, CSR11, reg); - rt2x00mmio_register_read(rt2x00dev, CSR18, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR18); rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); rt2x00mmio_register_write(rt2x00dev, CSR18, reg); - rt2x00mmio_register_read(rt2x00dev, CSR19, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR19); rt2x00_set_field32(®, CSR19_DIFS, erp->difs); rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); rt2x00mmio_register_write(rt2x00dev, CSR19, reg); } if (changed & BSS_CHANGED_BEACON_INT) { - rt2x00mmio_register_read(rt2x00dev, CSR12, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR12); rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, @@ -505,7 +505,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, /* * Clear false CRC during channel switch. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, &rf->rf1); + rf->rf1 = rt2x00mmio_register_read(rt2x00dev, CNT0); } static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) @@ -518,7 +518,7 @@ static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_LONG_RETRY, libconf->conf->long_frame_max_tx_count); rt2x00_set_field32(®, CSR11_SHORT_RETRY, @@ -535,7 +535,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00mmio_register_read(rt2x00dev, CSR20, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR20); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, @@ -548,7 +548,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR20_AUTOWAKE, 1); rt2x00mmio_register_write(rt2x00dev, CSR20, reg); } else { - rt2x00mmio_register_read(rt2x00dev, CSR20, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR20); rt2x00_set_field32(®, CSR20_AUTOWAKE, 0); rt2x00mmio_register_write(rt2x00dev, CSR20, reg); } @@ -576,7 +576,7 @@ static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_CWMIN, cw_min); rt2x00_set_field32(®, CSR11_CWMAX, cw_max); rt2x00mmio_register_write(rt2x00dev, CSR11, reg); @@ -594,7 +594,7 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT0); qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); /* @@ -649,12 +649,12 @@ static void rt2400pci_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 0); rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); @@ -672,17 +672,17 @@ static void rt2400pci_kick_queue(struct data_queue *queue) switch (queue->qid) { case QID_AC_VO: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_AC_VI: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_ATIM: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; @@ -700,17 +700,17 @@ static void rt2400pci_stop_queue(struct data_queue *queue) case QID_AC_VO: case QID_AC_VI: case QID_ATIM: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_ABORT, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_RX: - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 1); rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); @@ -780,7 +780,7 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) /* * Initialize registers. */ - rt2x00mmio_register_read(rt2x00dev, TXCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR2); rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size); rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit); rt2x00_set_field32(®, TXCSR2_NUM_ATIM, rt2x00dev->atim->limit); @@ -788,36 +788,36 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, TXCSR2, reg); entry_priv = rt2x00dev->tx[1].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR3); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR3, reg); entry_priv = rt2x00dev->tx[0].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR5); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR5, reg); entry_priv = rt2x00dev->atim->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR4); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR4, reg); entry_priv = rt2x00dev->bcn->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR6, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR6); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR6, reg); - rt2x00mmio_register_read(rt2x00dev, RXCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR1); rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00mmio_register_write(rt2x00dev, RXCSR1, reg); entry_priv = rt2x00dev->rx->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, RXCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR2); rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, RXCSR2, reg); @@ -834,18 +834,18 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, PSCSR2, 0x00023f20); rt2x00mmio_register_write(rt2x00dev, PSCSR3, 0x00000002); - rt2x00mmio_register_read(rt2x00dev, TIMECSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TIMECSR); rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); rt2x00mmio_register_write(rt2x00dev, TIMECSR, reg); - rt2x00mmio_register_read(rt2x00dev, CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR9); rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, (rt2x00dev->rx->data_size / 128)); rt2x00mmio_register_write(rt2x00dev, CSR9, reg); - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); rt2x00_set_field32(®, CSR14_TBCN, 0); @@ -858,14 +858,14 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, CNT3, 0x3f080000); - rt2x00mmio_register_read(rt2x00dev, ARCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR0); rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA0, 133); rt2x00_set_field32(®, ARCSR0_AR_BBP_ID0, 134); rt2x00_set_field32(®, ARCSR0_AR_BBP_DATA1, 136); rt2x00_set_field32(®, ARCSR0_AR_BBP_ID1, 135); rt2x00mmio_register_write(rt2x00dev, ARCSR0, reg); - rt2x00mmio_register_read(rt2x00dev, RXCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR3); rt2x00_set_field32(®, RXCSR3_BBP_ID0, 3); /* Tx power.*/ rt2x00_set_field32(®, RXCSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, RXCSR3_BBP_ID1, 32); /* Signal */ @@ -882,24 +882,24 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, MACCSR0, 0x00217223); rt2x00mmio_register_write(rt2x00dev, MACCSR1, 0x00235518); - rt2x00mmio_register_read(rt2x00dev, MACCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MACCSR2); rt2x00_set_field32(®, MACCSR2_DELAY, 64); rt2x00mmio_register_write(rt2x00dev, MACCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, RALINKCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RALINKCSR); rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA0, 17); rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID0, 154); rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA1, 0); rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID1, 154); rt2x00mmio_register_write(rt2x00dev, RALINKCSR, reg); - rt2x00mmio_register_read(rt2x00dev, CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR1); rt2x00_set_field32(®, CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, CSR1_BBP_RESET, 0); rt2x00_set_field32(®, CSR1_HOST_READY, 0); rt2x00mmio_register_write(rt2x00dev, CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR1); rt2x00_set_field32(®, CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, CSR1_HOST_READY, 1); rt2x00mmio_register_write(rt2x00dev, CSR1, reg); @@ -909,8 +909,8 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, ®); - rt2x00mmio_register_read(rt2x00dev, CNT4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT0); + reg = rt2x00mmio_register_read(rt2x00dev, CNT4); return 0; } @@ -984,7 +984,7 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2x00mmio_register_read(rt2x00dev, CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR7); rt2x00mmio_register_write(rt2x00dev, CSR7, reg); } @@ -994,7 +994,7 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, */ spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, mask); @@ -1047,7 +1047,7 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, put_to_sleep = (state != STATE_AWAKE); - rt2x00mmio_register_read(rt2x00dev, PWRCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, state); rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, state); @@ -1060,7 +1060,7 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00mmio_register_read(rt2x00dev, PWRCSR1, ®2); + reg2 = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); if (bbp_state == state && rf_state == state) @@ -1190,7 +1190,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, CSR14, reg); @@ -1330,7 +1330,7 @@ static inline void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, irq_field, 0); rt2x00mmio_register_write(rt2x00dev, CSR8, reg); @@ -1355,7 +1355,7 @@ static void rt2400pci_txstatus_tasklet(unsigned long data) if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); @@ -1391,7 +1391,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) * Get the interrupt sources & saved to local variable. * Write register value back to clear pending interrupts. */ - rt2x00mmio_register_read(rt2x00dev, CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR7); rt2x00mmio_register_write(rt2x00dev, CSR7, reg); if (!reg) @@ -1429,7 +1429,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) */ spin_lock(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); reg |= mask; rt2x00mmio_register_write(rt2x00dev, CSR8, reg); @@ -1450,7 +1450,7 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) u16 word; u8 *mac; - rt2x00mmio_register_read(rt2x00dev, CSR21, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR21); eeprom.data = rt2x00dev; eeprom.register_read = rt2400pci_eepromregister_read; @@ -1495,7 +1495,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00mmio_register_read(rt2x00dev, CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR0); rt2x00_set_chip(rt2x00dev, RT2460, value, rt2x00_get_field32(reg, CSR0_REVISION)); @@ -1640,7 +1640,7 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2x00mmio_register_read(rt2x00dev, GPIOCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); rt2x00_set_field32(®, GPIOCSR_DIR0, 1); rt2x00mmio_register_write(rt2x00dev, GPIOCSR, reg); @@ -1702,9 +1702,9 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw, u64 tsf; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR17, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR17); tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32; - rt2x00mmio_register_read(rt2x00dev, CSR16, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR16); tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER); return tsf; @@ -1715,7 +1715,7 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) struct rt2x00_dev *rt2x00dev = hw->priv; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR15, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR15); return rt2x00_get_field32(reg, CSR15_BEACON_SENT); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index 232feba0773f..dc622d60f79d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -138,7 +138,7 @@ static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR21, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR21); eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT); @@ -177,7 +177,7 @@ static u8 _rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, static const struct rt2x00debug rt2500pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = _rt2x00mmio_register_read, + .read = rt2x00mmio_register_read, .write = rt2x00mmio_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -212,7 +212,7 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00mmio_register_read(rt2x00dev, GPIOCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); return rt2x00_get_field32(reg, GPIOCSR_VAL0); } @@ -225,7 +225,7 @@ static void rt2500pci_brightness_set(struct led_classdev *led_cdev, unsigned int enabled = brightness != LED_OFF; u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) rt2x00_set_field32(®, LEDCSR_LINK, enabled); @@ -243,7 +243,7 @@ static int rt2500pci_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, LEDCSR); rt2x00_set_field32(®, LEDCSR_ON_PERIOD, *delay_on); rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, *delay_off); rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg); @@ -277,7 +277,7 @@ static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, @@ -310,7 +310,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, * Enable beacon config */ bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); - rt2x00mmio_register_read(rt2x00dev, BCNCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCNCSR1); rt2x00_set_field32(®, BCNCSR1_PRELOAD, bcn_preload); rt2x00_set_field32(®, BCNCSR1_BEACON_CWMIN, queue->cw_min); rt2x00mmio_register_write(rt2x00dev, BCNCSR1, reg); @@ -318,7 +318,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable synchronisation. */ - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); rt2x00mmio_register_write(rt2x00dev, CSR14, reg); } @@ -345,35 +345,35 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, if (changed & BSS_CHANGED_ERP_PREAMBLE) { preamble_mask = erp->short_preamble << 3; - rt2x00mmio_register_read(rt2x00dev, TXCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR1); rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, 0x162); rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, 0xa2); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR1, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR2); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00mmio_register_write(rt2x00dev, ARCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR3); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00mmio_register_write(rt2x00dev, ARCSR3, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR4); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00mmio_register_write(rt2x00dev, ARCSR4, reg); - rt2x00mmio_register_read(rt2x00dev, ARCSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARCSR5); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); rt2x00_set_field32(®, ARCSR2_LENGTH, @@ -385,23 +385,23 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00mmio_register_write(rt2x00dev, ARCSR1, erp->basic_rates); if (changed & BSS_CHANGED_ERP_SLOT) { - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); rt2x00mmio_register_write(rt2x00dev, CSR11, reg); - rt2x00mmio_register_read(rt2x00dev, CSR18, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR18); rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); rt2x00mmio_register_write(rt2x00dev, CSR18, reg); - rt2x00mmio_register_read(rt2x00dev, CSR19, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR19); rt2x00_set_field32(®, CSR19_DIFS, erp->difs); rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); rt2x00mmio_register_write(rt2x00dev, CSR19, reg); } if (changed & BSS_CHANGED_BEACON_INT) { - rt2x00mmio_register_read(rt2x00dev, CSR12, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR12); rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, @@ -425,7 +425,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || ant->tx == ANTENNA_SW_DIVERSITY); - rt2x00mmio_register_read(rt2x00dev, BBPCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BBPCSR1); rt2500pci_bbp_read(rt2x00dev, 14, &r14); rt2500pci_bbp_read(rt2x00dev, 2, &r2); @@ -548,7 +548,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, /* * Clear false CRC during channel switch. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, &rf->rf1); + rf->rf1 = rt2x00mmio_register_read(rt2x00dev, CNT0); } static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, @@ -566,7 +566,7 @@ static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_LONG_RETRY, libconf->conf->long_frame_max_tx_count); rt2x00_set_field32(®, CSR11_SHORT_RETRY, @@ -583,7 +583,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00mmio_register_read(rt2x00dev, CSR20, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR20); rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN, (rt2x00dev->beacon_int - 20) * 16); rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP, @@ -596,7 +596,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, CSR20_AUTOWAKE, 1); rt2x00mmio_register_write(rt2x00dev, CSR20, reg); } else { - rt2x00mmio_register_read(rt2x00dev, CSR20, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR20); rt2x00_set_field32(®, CSR20_AUTOWAKE, 0); rt2x00mmio_register_write(rt2x00dev, CSR20, reg); } @@ -632,13 +632,13 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT0); qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); /* * Update False CCA count from register. */ - rt2x00mmio_register_read(rt2x00dev, CNT3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT3); qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA); } @@ -738,12 +738,12 @@ static void rt2500pci_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 0); rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); @@ -761,17 +761,17 @@ static void rt2500pci_kick_queue(struct data_queue *queue) switch (queue->qid) { case QID_AC_VO: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_AC_VI: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_ATIM: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; @@ -789,17 +789,17 @@ static void rt2500pci_stop_queue(struct data_queue *queue) case QID_AC_VO: case QID_AC_VI: case QID_ATIM: - rt2x00mmio_register_read(rt2x00dev, TXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR0); rt2x00_set_field32(®, TXCSR0_ABORT, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg); break; case QID_RX: - rt2x00mmio_register_read(rt2x00dev, RXCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR0); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 1); rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); rt2x00_set_field32(®, CSR14_TBCN, 0); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); @@ -865,7 +865,7 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) /* * Initialize registers. */ - rt2x00mmio_register_read(rt2x00dev, TXCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR2); rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size); rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit); rt2x00_set_field32(®, TXCSR2_NUM_ATIM, rt2x00dev->atim->limit); @@ -873,36 +873,36 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, TXCSR2, reg); entry_priv = rt2x00dev->tx[1].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR3); rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR3, reg); entry_priv = rt2x00dev->tx[0].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR5); rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR5, reg); entry_priv = rt2x00dev->atim->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR4); rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR4, reg); entry_priv = rt2x00dev->bcn->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, TXCSR6, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR6); rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, TXCSR6, reg); - rt2x00mmio_register_read(rt2x00dev, RXCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR1); rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size); rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00mmio_register_write(rt2x00dev, RXCSR1, reg); entry_priv = rt2x00dev->rx->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, RXCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR2); rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, RXCSR2, reg); @@ -919,13 +919,13 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, PSCSR2, 0x00020002); rt2x00mmio_register_write(rt2x00dev, PSCSR3, 0x00000002); - rt2x00mmio_register_read(rt2x00dev, TIMECSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TIMECSR); rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); rt2x00mmio_register_write(rt2x00dev, TIMECSR, reg); - rt2x00mmio_register_read(rt2x00dev, CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR9); rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, rt2x00dev->rx->data_size / 128); rt2x00mmio_register_write(rt2x00dev, CSR9, reg); @@ -933,11 +933,11 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) /* * Always use CWmin and CWmax set in descriptor. */ - rt2x00mmio_register_read(rt2x00dev, CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR11); rt2x00_set_field32(®, CSR11_CW_SELECT, 0); rt2x00mmio_register_write(rt2x00dev, CSR11, reg); - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_TSF_COUNT, 0); rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); rt2x00_set_field32(®, CSR14_TBCN, 0); @@ -950,7 +950,7 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, CNT3, 0); - rt2x00mmio_register_read(rt2x00dev, TXCSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXCSR8); rt2x00_set_field32(®, TXCSR8_BBP_ID0, 10); rt2x00_set_field32(®, TXCSR8_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXCSR8_BBP_ID1, 11); @@ -961,28 +961,28 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXCSR8_BBP_ID3_VALID, 1); rt2x00mmio_register_write(rt2x00dev, TXCSR8, reg); - rt2x00mmio_register_read(rt2x00dev, ARTCSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARTCSR0); rt2x00_set_field32(®, ARTCSR0_ACK_CTS_1MBS, 112); rt2x00_set_field32(®, ARTCSR0_ACK_CTS_2MBS, 56); rt2x00_set_field32(®, ARTCSR0_ACK_CTS_5_5MBS, 20); rt2x00_set_field32(®, ARTCSR0_ACK_CTS_11MBS, 10); rt2x00mmio_register_write(rt2x00dev, ARTCSR0, reg); - rt2x00mmio_register_read(rt2x00dev, ARTCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARTCSR1); rt2x00_set_field32(®, ARTCSR1_ACK_CTS_6MBS, 45); rt2x00_set_field32(®, ARTCSR1_ACK_CTS_9MBS, 37); rt2x00_set_field32(®, ARTCSR1_ACK_CTS_12MBS, 33); rt2x00_set_field32(®, ARTCSR1_ACK_CTS_18MBS, 29); rt2x00mmio_register_write(rt2x00dev, ARTCSR1, reg); - rt2x00mmio_register_read(rt2x00dev, ARTCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, ARTCSR2); rt2x00_set_field32(®, ARTCSR2_ACK_CTS_24MBS, 29); rt2x00_set_field32(®, ARTCSR2_ACK_CTS_36MBS, 25); rt2x00_set_field32(®, ARTCSR2_ACK_CTS_48MBS, 25); rt2x00_set_field32(®, ARTCSR2_ACK_CTS_54MBS, 25); rt2x00mmio_register_write(rt2x00dev, ARTCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, RXCSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RXCSR3); rt2x00_set_field32(®, RXCSR3_BBP_ID0, 47); /* CCK Signal */ rt2x00_set_field32(®, RXCSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, RXCSR3_BBP_ID1, 51); /* Rssi */ @@ -993,7 +993,7 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, RXCSR3_BBP_ID3_VALID, 1); rt2x00mmio_register_write(rt2x00dev, RXCSR3, reg); - rt2x00mmio_register_read(rt2x00dev, PCICSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, PCICSR); rt2x00_set_field32(®, PCICSR_BIG_ENDIAN, 0); rt2x00_set_field32(®, PCICSR_RX_TRESHOLD, 0); rt2x00_set_field32(®, PCICSR_TX_TRESHOLD, 3); @@ -1014,11 +1014,11 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, MACCSR0, 0x00213223); rt2x00mmio_register_write(rt2x00dev, MACCSR1, 0x00235518); - rt2x00mmio_register_read(rt2x00dev, MACCSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MACCSR2); rt2x00_set_field32(®, MACCSR2_DELAY, 64); rt2x00mmio_register_write(rt2x00dev, MACCSR2, reg); - rt2x00mmio_register_read(rt2x00dev, RALINKCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RALINKCSR); rt2x00_set_field32(®, RALINKCSR_AR_BBP_DATA0, 17); rt2x00_set_field32(®, RALINKCSR_AR_BBP_ID0, 26); rt2x00_set_field32(®, RALINKCSR_AR_BBP_VALID0, 1); @@ -1031,13 +1031,13 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, TXACKCSR0, 0x00000020); - rt2x00mmio_register_read(rt2x00dev, CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR1); rt2x00_set_field32(®, CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, CSR1_BBP_RESET, 0); rt2x00_set_field32(®, CSR1_HOST_READY, 0); rt2x00mmio_register_write(rt2x00dev, CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR1); rt2x00_set_field32(®, CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, CSR1_HOST_READY, 1); rt2x00mmio_register_write(rt2x00dev, CSR1, reg); @@ -1047,8 +1047,8 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00mmio_register_read(rt2x00dev, CNT0, ®); - rt2x00mmio_register_read(rt2x00dev, CNT4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CNT0); + reg = rt2x00mmio_register_read(rt2x00dev, CNT4); return 0; } @@ -1138,7 +1138,7 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2x00mmio_register_read(rt2x00dev, CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR7); rt2x00mmio_register_write(rt2x00dev, CSR7, reg); } @@ -1148,7 +1148,7 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, */ spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, mask); @@ -1200,7 +1200,7 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, put_to_sleep = (state != STATE_AWAKE); - rt2x00mmio_register_read(rt2x00dev, PWRCSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); rt2x00_set_field32(®, PWRCSR1_SET_STATE, 1); rt2x00_set_field32(®, PWRCSR1_BBP_DESIRE_STATE, state); rt2x00_set_field32(®, PWRCSR1_RF_DESIRE_STATE, state); @@ -1213,7 +1213,7 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00mmio_register_read(rt2x00dev, PWRCSR1, ®2); + reg2 = rt2x00mmio_register_read(rt2x00dev, PWRCSR1); bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); if (bbp_state == state && rf_state == state) @@ -1342,7 +1342,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00mmio_register_read(rt2x00dev, CSR14, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR14); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, CSR14, reg); @@ -1458,7 +1458,7 @@ static inline void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, irq_field, 0); rt2x00mmio_register_write(rt2x00dev, CSR8, reg); @@ -1483,7 +1483,7 @@ static void rt2500pci_txstatus_tasklet(unsigned long data) if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); @@ -1519,7 +1519,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) * Get the interrupt sources & saved to local variable. * Write register value back to clear pending interrupts. */ - rt2x00mmio_register_read(rt2x00dev, CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR7); rt2x00mmio_register_write(rt2x00dev, CSR7, reg); if (!reg) @@ -1557,7 +1557,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) */ spin_lock(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR8); reg |= mask; rt2x00mmio_register_write(rt2x00dev, CSR8, reg); @@ -1576,7 +1576,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) u16 word; u8 *mac; - rt2x00mmio_register_read(rt2x00dev, CSR21, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR21); eeprom.data = rt2x00dev; eeprom.register_read = rt2500pci_eepromregister_read; @@ -1649,7 +1649,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00mmio_register_read(rt2x00dev, CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR0); rt2x00_set_chip(rt2x00dev, RT2560, value, rt2x00_get_field32(reg, CSR0_REVISION)); @@ -1965,7 +1965,7 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2x00mmio_register_read(rt2x00dev, GPIOCSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, GPIOCSR); rt2x00_set_field32(®, GPIOCSR_DIR0, 1); rt2x00mmio_register_write(rt2x00dev, GPIOCSR, reg); @@ -2001,9 +2001,9 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw, u64 tsf; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR17, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR17); tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32; - rt2x00mmio_register_read(rt2x00dev, CSR16, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR16); tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER); return tsf; @@ -2014,7 +2014,7 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) struct rt2x00_dev *rt2x00dev = hw->priv; u32 reg; - rt2x00mmio_register_read(rt2x00dev, CSR15, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CSR15); return rt2x00_get_field32(reg, CSR15_BEACON_SENT); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c index 3ab3b5323897..70ad20691bff 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c @@ -331,7 +331,7 @@ static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev, * access needs locking. */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); rt2x00_set_field32(®, irq_field, 1); rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock_irq(&rt2x00dev->irqmask_lock); @@ -376,12 +376,12 @@ void rt2800mmio_tbtt_tasklet(unsigned long data) * interval every 64 beacons by 64us to mitigate this effect. */ if (drv_data->tbtt_tick == (BCN_TBTT_OFFSET - 2)) { - rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, (rt2x00dev->beacon_int * 16) - 1); rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg); } else if (drv_data->tbtt_tick == (BCN_TBTT_OFFSET - 1)) { - rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, (rt2x00dev->beacon_int * 16)); rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -439,7 +439,7 @@ static void rt2800mmio_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) * need to lock the kfifo. */ for (i = 0; i < rt2x00dev->tx->limit; i++) { - rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status); + status = rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO); if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) break; @@ -460,7 +460,7 @@ irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance) u32 reg, mask; /* Read status and ACK all interrupts */ - rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); if (!reg) @@ -501,7 +501,7 @@ irqreturn_t rt2800mmio_interrupt(int irq, void *dev_instance) * the tasklet will reenable the appropriate interrupts. */ spin_lock(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); reg &= mask; rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock(&rt2x00dev->irqmask_lock); @@ -521,7 +521,7 @@ void rt2800mmio_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); } @@ -560,18 +560,18 @@ void rt2800mmio_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg); - rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN); rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 1); rt2x00mmio_register_write(rt2x00dev, INT_TIMER_EN, reg); break; @@ -613,18 +613,18 @@ void rt2800mmio_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg); - rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN); rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 0); rt2x00mmio_register_write(rt2x00dev, INT_TIMER_EN, reg); @@ -810,7 +810,7 @@ int rt2800mmio_init_registers(struct rt2x00_dev *rt2x00dev) /* * Reset DMA indexes */ - rt2x00mmio_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + reg = rt2x00mmio_register_read(rt2x00dev, WPDMA_RST_IDX); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); @@ -831,7 +831,7 @@ int rt2800mmio_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392) || rt2x00_rt(rt2x00dev, RT5592))) { - rt2x00mmio_register_read(rt2x00dev, AUX_CTRL, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AUX_CTRL); rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); rt2x00mmio_register_write(rt2x00dev, AUX_CTRL, reg); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c index 98f16312e3f1..5cf655ff1430 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c @@ -69,7 +69,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) return; for (i = 0; i < 200; i++) { - rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); + reg = rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID); if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) || (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) || @@ -92,7 +92,7 @@ static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); @@ -122,7 +122,7 @@ static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) struct eeprom_93cx6 eeprom; u32 reg; - rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); eeprom.data = rt2x00dev; eeprom.register_read = rt2800pci_eepromregister_read; @@ -325,8 +325,8 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = { }; static const struct rt2800_ops rt2800pci_rt2800_ops = { - .register_read = _rt2x00mmio_register_read, - .register_read_lock = _rt2x00mmio_register_read, /* same for PCI */ + .register_read = rt2x00mmio_register_read, + .register_read_lock = rt2x00mmio_register_read, /* same for PCI */ .register_write = rt2x00mmio_register_write, .register_write_lock = rt2x00mmio_register_write, /* same for PCI */ .register_multiread = rt2x00mmio_register_multiread, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index c1eda3798b9b..a985a5a7945e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -164,8 +164,8 @@ static const struct ieee80211_ops rt2800soc_mac80211_ops = { }; static const struct rt2800_ops rt2800soc_rt2800_ops = { - .register_read = _rt2x00mmio_register_read, - .register_read_lock = _rt2x00mmio_register_read, /* same for SoCs */ + .register_read = rt2x00mmio_register_read, + .register_read_lock = rt2x00mmio_register_read, /* same for SoCs */ .register_write = rt2x00mmio_register_write, .register_write_lock = rt2x00mmio_register_write, /* same for SoCs */ .register_multiread = rt2x00mmio_register_multiread, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c index da38d254c26f..528cb0401df1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c @@ -43,7 +43,7 @@ int rt2x00mmio_regbusy_read(struct rt2x00_dev *rt2x00dev, return 0; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00mmio_register_read(rt2x00dev, offset, reg); + *reg = rt2x00mmio_register_read(rt2x00dev, offset); if (!rt2x00_get_field32(*reg, field)) return 1; udelay(REGISTER_BUSY_DELAY); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h index 6d7a27ee6444..184a4148b2f8 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.h @@ -29,14 +29,7 @@ /* * Register access. */ -static inline void rt2x00mmio_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) -{ - *value = readl(rt2x00dev->csr.base + offset); -} - -static inline u32 _rt2x00mmio_register_read(struct rt2x00_dev *rt2x00dev, +static inline u32 rt2x00mmio_register_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset) { return readl(rt2x00dev->csr.base + offset); diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index 147d1d2cc0a6..f2864407eb6c 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -161,7 +161,7 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, HOST_CMD_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, HOST_CMD_CSR); rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, reg); @@ -176,7 +176,7 @@ static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); @@ -214,7 +214,7 @@ static u8 _rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int wor static const struct rt2x00debug rt61pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = _rt2x00mmio_register_read, + .read = rt2x00mmio_register_read, .write = rt2x00mmio_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -249,7 +249,7 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00mmio_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); return rt2x00_get_field32(reg, MAC_CSR13_VAL5); } @@ -300,7 +300,7 @@ static int rt61pci_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00mmio_register_read(led->rt2x00dev, MAC_CSR14, ®); + reg = rt2x00mmio_register_read(led->rt2x00dev, MAC_CSR14); rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); rt2x00mmio_register_write(led->rt2x00dev, MAC_CSR14, reg); @@ -345,7 +345,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = (0xf << crypto->bssidx); - rt2x00mmio_register_read(rt2x00dev, SEC_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR0); reg &= mask; if (reg && reg == mask) @@ -378,14 +378,14 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, field.bit_offset = (3 * key->hw_key_idx); field.bit_mask = 0x7 << field.bit_offset; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR1); rt2x00_set_field32(®, field, crypto->cipher); rt2x00mmio_register_write(rt2x00dev, SEC_CSR1, reg); } else { field.bit_offset = (3 * (key->hw_key_idx - 8)); field.bit_mask = 0x7 << field.bit_offset; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR5, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR5); rt2x00_set_field32(®, field, crypto->cipher); rt2x00mmio_register_write(rt2x00dev, SEC_CSR5, reg); } @@ -410,7 +410,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = 1 << key->hw_key_idx; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR0); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -439,10 +439,10 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * When both registers are full, we drop the key. * Otherwise, we use the first invalid entry. */ - rt2x00mmio_register_read(rt2x00dev, SEC_CSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2); if (reg && reg == ~0) { key->hw_key_idx = 32; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3); if (reg && reg == ~0) return -ENOSPC; } @@ -476,7 +476,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * Without this, received frames will not be decrypted * by the hardware. */ - rt2x00mmio_register_read(rt2x00dev, SEC_CSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR4); reg |= (1 << crypto->bssidx); rt2x00mmio_register_write(rt2x00dev, SEC_CSR4, reg); @@ -501,7 +501,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, if (key->hw_key_idx < 32) { mask = 1 << key->hw_key_idx; - rt2x00mmio_register_read(rt2x00dev, SEC_CSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR2); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -510,7 +510,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, } else { mask = 1 << (key->hw_key_idx - 32); - rt2x00mmio_register_read(rt2x00dev, SEC_CSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, SEC_CSR3); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -532,7 +532,7 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, @@ -564,7 +564,7 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable synchronisation. */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -595,13 +595,13 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); @@ -613,18 +613,18 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, erp->basic_rates); if (changed & BSS_CHANGED_BEACON_INT) { - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, erp->beacon_int * 16); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); } if (changed & BSS_CHANGED_ERP_SLOT) { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9); rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR8); rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); @@ -721,7 +721,7 @@ static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); rt2x00_set_field32(®, MAC_CSR13_DIR4, 0); rt2x00_set_field32(®, MAC_CSR13_VAL4, p1); @@ -828,7 +828,7 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); - rt2x00mmio_register_read(rt2x00dev, PHY_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, PHY_CSR0); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, rt2x00dev->curr_band == NL80211_BAND_2GHZ); @@ -935,7 +935,7 @@ static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_STEP, 0); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0); @@ -955,7 +955,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, @@ -976,7 +976,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, rt61pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 0); } else { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR11, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR11); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, 0); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0); rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 0); @@ -1022,13 +1022,13 @@ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00mmio_register_read(rt2x00dev, STA_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0); qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ - rt2x00mmio_register_read(rt2x00dev, STA_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1); qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); } @@ -1147,12 +1147,12 @@ static void rt61pci_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); @@ -1170,22 +1170,22 @@ static void rt61pci_kick_queue(struct data_queue *queue) switch (queue->qid) { case QID_AC_VO: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_VI: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_BE: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_BK: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; @@ -1201,32 +1201,32 @@ static void rt61pci_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_AC_VO: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_VI: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_BE: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_AC_BK: - rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR); rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, 1); rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg); break; case QID_RX: - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); @@ -1308,7 +1308,7 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, * Wait for stable hardware. */ for (i = 0; i < 100; i++) { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0); if (reg) break; msleep(1); @@ -1347,7 +1347,7 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg); for (i = 0; i < 100; i++) { - rt2x00mmio_register_read(rt2x00dev, MCU_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_CNTL_CSR); if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY)) break; msleep(1); @@ -1371,12 +1371,12 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); @@ -1434,7 +1434,7 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) /* * Initialize registers. */ - rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR0); rt2x00_set_field32(®, TX_RING_CSR0_AC0_RING_SIZE, rt2x00dev->tx[0].limit); rt2x00_set_field32(®, TX_RING_CSR0_AC1_RING_SIZE, @@ -1445,36 +1445,36 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00dev->tx[3].limit); rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR0, reg); - rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR1); rt2x00_set_field32(®, TX_RING_CSR1_TXD_SIZE, rt2x00dev->tx[0].desc_size / 4); rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR1, reg); entry_priv = rt2x00dev->tx[0].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, AC0_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AC0_BASE_CSR); rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, AC0_BASE_CSR, reg); entry_priv = rt2x00dev->tx[1].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, AC1_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AC1_BASE_CSR); rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, AC1_BASE_CSR, reg); entry_priv = rt2x00dev->tx[2].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, AC2_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AC2_BASE_CSR); rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, AC2_BASE_CSR, reg); entry_priv = rt2x00dev->tx[3].entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, AC3_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AC3_BASE_CSR); rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, AC3_BASE_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, RX_RING_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RX_RING_CSR); rt2x00_set_field32(®, RX_RING_CSR_RING_SIZE, rt2x00dev->rx->limit); rt2x00_set_field32(®, RX_RING_CSR_RXD_SIZE, rt2x00dev->rx->desc_size / 4); @@ -1482,26 +1482,26 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, RX_RING_CSR, reg); entry_priv = rt2x00dev->rx->entries[0].priv_data; - rt2x00mmio_register_read(rt2x00dev, RX_BASE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RX_BASE_CSR); rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER, entry_priv->desc_dma); rt2x00mmio_register_write(rt2x00dev, RX_BASE_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, TX_DMA_DST_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TX_DMA_DST_CSR); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC0, 2); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC1, 2); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC2, 2); rt2x00_set_field32(®, TX_DMA_DST_CSR_DEST_AC3, 2); rt2x00mmio_register_write(rt2x00dev, TX_DMA_DST_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, LOAD_TX_RING_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, LOAD_TX_RING_CSR); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1); rt2x00_set_field32(®, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1); rt2x00mmio_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR); rt2x00_set_field32(®, RX_CNTL_CSR_LOAD_RXD, 1); rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg); @@ -1512,13 +1512,13 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg); - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ @@ -1532,7 +1532,7 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) /* * CCK TXD BBP registers */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); @@ -1546,7 +1546,7 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) /* * OFDM TXD BBP registers */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR3, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR3); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); @@ -1555,21 +1555,21 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR3, reg); - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR7, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR7); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR7, reg); - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR8, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR8); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR8, reg); - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); @@ -1582,7 +1582,7 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00mmio_register_write(rt2x00dev, MAC_CSR6, 0x00000fff); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR9); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg); @@ -1628,24 +1628,24 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00mmio_register_read(rt2x00dev, STA_CSR0, ®); - rt2x00mmio_register_read(rt2x00dev, STA_CSR1, ®); - rt2x00mmio_register_read(rt2x00dev, STA_CSR2, ®); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR0); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR1); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR2); /* * Reset MAC and BBP registers. */ - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg); @@ -1731,10 +1731,10 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); } @@ -1744,7 +1744,7 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, */ spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, mask); rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, mask); rt2x00_set_field32(®, INT_MASK_CSR_BEACON_DONE, mask); @@ -1752,7 +1752,7 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, INT_MASK_CSR_MITIGATION_PERIOD, 0xff); rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); rt2x00_set_field32(®, MCU_INT_MASK_CSR_0, mask); rt2x00_set_field32(®, MCU_INT_MASK_CSR_1, mask); rt2x00_set_field32(®, MCU_INT_MASK_CSR_2, mask); @@ -1792,7 +1792,7 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Enable RX. */ - rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR); rt2x00_set_field32(®, RX_CNTL_CSR_ENABLE_RX_DMA, 1); rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg); @@ -1815,7 +1815,7 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) put_to_sleep = (state != STATE_AWAKE); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR12, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12); rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg); @@ -1826,7 +1826,7 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00mmio_register_read(rt2x00dev, MAC_CSR12, ®2); + reg2 = rt2x00mmio_register_read(rt2x00dev, MAC_CSR12); state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); if (state == !put_to_sleep) return 0; @@ -1984,7 +1984,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); orig_reg = reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -2045,7 +2045,7 @@ static void rt61pci_clear_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &orig_reg); + orig_reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9); reg = orig_reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -2181,7 +2181,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) * tx ring size for now. */ for (i = 0; i < rt2x00dev->tx->limit; i++) { - rt2x00mmio_register_read(rt2x00dev, STA_CSR4, ®); + reg = rt2x00mmio_register_read(rt2x00dev, STA_CSR4); if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) break; @@ -2267,7 +2267,7 @@ static inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); rt2x00_set_field32(®, irq_field, 0); rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); @@ -2285,7 +2285,7 @@ static void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev, */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); rt2x00_set_field32(®, irq_field, 0); rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); @@ -2337,10 +2337,10 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) * Get the interrupt sources & saved to local variable. * Write register value back to clear pending interrupts. */ - rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®_mcu); + reg_mcu = rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu); - rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR); rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg); if (!reg && !reg_mcu) @@ -2378,11 +2378,11 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) */ spin_lock(&rt2x00dev->irqmask_lock); - rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR); reg |= mask; rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR); reg |= mask_mcu; rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); @@ -2402,7 +2402,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) u8 *mac; s8 value; - rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR); eeprom.data = rt2x00dev; eeprom.register_read = rt61pci_eepromregister_read; @@ -2517,7 +2517,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00mmio_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR0); rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); @@ -2859,7 +2859,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2x00mmio_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00mmio_register_read(rt2x00dev, MAC_CSR13); rt2x00_set_field32(®, MAC_CSR13_DIR5, 1); rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg); @@ -2931,7 +2931,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, field.bit_offset = (queue_idx & 1) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt2x00mmio_register_read(rt2x00dev, offset, ®); + reg = rt2x00mmio_register_read(rt2x00dev, offset); rt2x00_set_field32(®, field, queue->txop); rt2x00mmio_register_write(rt2x00dev, offset, reg); @@ -2939,15 +2939,15 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt2x00mmio_register_read(rt2x00dev, AIFSN_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, AIFSN_CSR); rt2x00_set_field32(®, field, queue->aifs); rt2x00mmio_register_write(rt2x00dev, AIFSN_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, CWMIN_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CWMIN_CSR); rt2x00_set_field32(®, field, queue->cw_min); rt2x00mmio_register_write(rt2x00dev, CWMIN_CSR, reg); - rt2x00mmio_register_read(rt2x00dev, CWMAX_CSR, ®); + reg = rt2x00mmio_register_read(rt2x00dev, CWMAX_CSR); rt2x00_set_field32(®, field, queue->cw_max); rt2x00mmio_register_write(rt2x00dev, CWMAX_CSR, reg); @@ -2960,9 +2960,9 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) u64 tsf; u32 reg; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR13, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR13); tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; - rt2x00mmio_register_read(rt2x00dev, TXRX_CSR12, ®); + reg = rt2x00mmio_register_read(rt2x00dev, TXRX_CSR12); tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); return tsf; -- cgit v1.2.3 From 48bde9c969724f42af7bc8482c0165292e629f5b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:46:57 +0200 Subject: rt2x00: convert rt2x00usb_register_read return type This is a semi-automated conversion to change rt2x00usb_register_read to return the register contents instead of passing them by value, resulting in much better object code. The majority of the patch was done using: sed -i 's:\(\(.*, .*\), &\(.*\));:\2 = \1);:' \ -i 's:\(\(.*, .*\), &\(.*\));:\2 = \1);:' \ -i 's:\(\(.*, .*\), &\(.*\));:\2 = \1);:' \ drivers/net/wireless/ralink/rt2x00/* Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2500usb.c | 104 +++++++++++----------- drivers/net/wireless/ralink/rt2x00/rt2800usb.c | 14 +-- drivers/net/wireless/ralink/rt2x00/rt2x00usb.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00usb.h | 32 +------ drivers/net/wireless/ralink/rt2x00/rt73usb.c | 114 ++++++++++++------------- 5 files changed, 118 insertions(+), 148 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index 9cff9ddafb72..70204cecc985 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -55,26 +55,24 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * If the csr_mutex is already held then the _lock variants must * be used instead. */ -static void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u16 *value) +static u16 rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { __le16 reg; rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, ®, sizeof(reg)); - *value = le16_to_cpu(reg); + return le16_to_cpu(reg); } -static void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u16 *value) +static u16 rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { __le16 reg; rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, ®, sizeof(reg), REGISTER_TIMEOUT); - *value = le16_to_cpu(reg); + return le16_to_cpu(reg); } static void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, @@ -114,7 +112,7 @@ static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev, unsigned int i; for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt2500usb_register_read_lock(rt2x00dev, offset, reg); + *reg = rt2500usb_register_read_lock(rt2x00dev, offset); if (!rt2x00_get_field16(*reg, field)) return 1; udelay(REGISTER_BUSY_DELAY); @@ -178,7 +176,7 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); if (WAIT_FOR_BBP(rt2x00dev, ®)) - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); + reg = rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7); } *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); @@ -219,11 +217,7 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, static u32 _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset) { - u16 tmp; - - rt2500usb_register_read(rt2x00dev, offset, &tmp); - - return tmp; + return rt2500usb_register_read(rt2x00dev, offset); } static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, @@ -281,7 +275,7 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u16 reg; - rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR19); return rt2x00_get_field16(reg, MAC_CSR19_VAL7); } @@ -294,7 +288,7 @@ static void rt2500usb_brightness_set(struct led_classdev *led_cdev, unsigned int enabled = brightness != LED_OFF; u16 reg; - rt2500usb_register_read(led->rt2x00dev, MAC_CSR20, ®); + reg = rt2500usb_register_read(led->rt2x00dev, MAC_CSR20); if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) rt2x00_set_field16(®, MAC_CSR20_LINK, enabled); @@ -312,7 +306,7 @@ static int rt2500usb_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u16 reg; - rt2500usb_register_read(led->rt2x00dev, MAC_CSR21, ®); + reg = rt2500usb_register_read(led->rt2x00dev, MAC_CSR21); rt2x00_set_field16(®, MAC_CSR21_ON_PERIOD, *delay_on); rt2x00_set_field16(®, MAC_CSR21_OFF_PERIOD, *delay_off); rt2500usb_register_write(led->rt2x00dev, MAC_CSR21, reg); @@ -366,7 +360,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, */ mask = TXRX_CSR0_KEY_ID.bit_mask; - rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR0); curr_cipher = rt2x00_get_field16(reg, TXRX_CSR0_ALGORITHM); reg &= mask; @@ -405,7 +399,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, * TXRX_CSR0_KEY_ID contains only single-bit fields to indicate * a particular key is valid. */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field16(®, TXRX_CSR0_ALGORITHM, crypto->cipher); rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); @@ -431,7 +425,7 @@ static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, @@ -463,7 +457,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, * Enable beacon config */ bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20); - rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR20); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, bcn_preload >> 6); rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2 * (conf->type != NL80211_IFTYPE_STATION)); @@ -472,11 +466,11 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable synchronisation. */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR18); rt2x00_set_field16(®, TXRX_CSR18_OFFSET, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, conf->sync); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } @@ -497,7 +491,7 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, u16 reg; if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR10); rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); @@ -508,7 +502,7 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, erp->basic_rates); if (changed & BSS_CHANGED_BEACON_INT) { - rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR18); rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, erp->beacon_int * 4); rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); @@ -538,8 +532,8 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, rt2500usb_bbp_read(rt2x00dev, 2, &r2); rt2500usb_bbp_read(rt2x00dev, 14, &r14); - rt2500usb_register_read(rt2x00dev, PHY_CSR5, &csr5); - rt2500usb_register_read(rt2x00dev, PHY_CSR6, &csr6); + csr5 = rt2500usb_register_read(rt2x00dev, PHY_CSR5); + csr6 = rt2500usb_register_read(rt2x00dev, PHY_CSR6); /* * Configure the TX antenna. @@ -653,7 +647,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, u16 reg; if (state == STATE_SLEEP) { - rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR18); rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, rt2x00dev->beacon_int - 20); rt2x00_set_field16(®, MAC_CSR18_BEACONS_BEFORE_WAKEUP, @@ -666,7 +660,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(®, MAC_CSR18_AUTO_WAKE, 1); rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); } else { - rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR18); rt2x00_set_field16(®, MAC_CSR18_AUTO_WAKE, 0); rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); } @@ -700,13 +694,13 @@ static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2500usb_register_read(rt2x00dev, STA_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, STA_CSR0); qual->rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ - rt2500usb_register_read(rt2x00dev, STA_CSR3, ®); + reg = rt2500usb_register_read(rt2x00dev, STA_CSR3); qual->false_cca = rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR); } @@ -745,12 +739,12 @@ static void rt2500usb_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); break; case QID_BEACON: - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 1); @@ -768,12 +762,12 @@ static void rt2500usb_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); break; case QID_BEACON: - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); @@ -796,54 +790,54 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_vendor_request_sw(rt2x00dev, USB_SINGLE_WRITE, 0x0308, 0x00f0, REGISTER_TIMEOUT); - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111); rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11); - rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 1); rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 1); rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 0); rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 0); rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 0); rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR5, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR5); rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0, 13); rt2x00_set_field16(®, TXRX_CSR5_BBP_ID0_VALID, 1); rt2x00_set_field16(®, TXRX_CSR5_BBP_ID1, 12); rt2x00_set_field16(®, TXRX_CSR5_BBP_ID1_VALID, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR5, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR6, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR6); rt2x00_set_field16(®, TXRX_CSR6_BBP_ID0, 10); rt2x00_set_field16(®, TXRX_CSR6_BBP_ID0_VALID, 1); rt2x00_set_field16(®, TXRX_CSR6_BBP_ID1, 11); rt2x00_set_field16(®, TXRX_CSR6_BBP_ID1_VALID, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR6, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR7, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR7); rt2x00_set_field16(®, TXRX_CSR7_BBP_ID0, 7); rt2x00_set_field16(®, TXRX_CSR7_BBP_ID0_VALID, 1); rt2x00_set_field16(®, TXRX_CSR7_BBP_ID1, 6); rt2x00_set_field16(®, TXRX_CSR7_BBP_ID1_VALID, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR7, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR8, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR8); rt2x00_set_field16(®, TXRX_CSR8_BBP_ID0, 5); rt2x00_set_field16(®, TXRX_CSR8_BBP_ID0_VALID, 1); rt2x00_set_field16(®, TXRX_CSR8_BBP_ID1, 0); rt2x00_set_field16(®, TXRX_CSR8_BBP_ID1_VALID, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0); rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0); rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0); @@ -856,14 +850,14 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) return -EBUSY; - rt2500usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field16(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field16(®, MAC_CSR1_BBP_RESET, 0); rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 1); rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); if (rt2x00_rev(rt2x00dev) >= RT2570_VERSION_C) { - rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); + reg = rt2500usb_register_read(rt2x00dev, PHY_CSR2); rt2x00_set_field16(®, PHY_CSR2_LNA, 0); } else { reg = 0; @@ -877,26 +871,26 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2500usb_register_write(rt2x00dev, MAC_CSR15, 0x01ee); rt2500usb_register_write(rt2x00dev, MAC_CSR16, 0x0000); - rt2500usb_register_read(rt2x00dev, MAC_CSR8, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR8); rt2x00_set_field16(®, MAC_CSR8_MAX_FRAME_UNIT, rt2x00dev->rx->data_size); rt2500usb_register_write(rt2x00dev, MAC_CSR8, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field16(®, TXRX_CSR0_ALGORITHM, CIPHER_NONE); rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR18); rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON, 90); rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg); - rt2500usb_register_read(rt2x00dev, PHY_CSR4, ®); + reg = rt2500usb_register_read(rt2x00dev, PHY_CSR4); rt2x00_set_field16(®, PHY_CSR4_LOW_RF_LE, 1); rt2500usb_register_write(rt2x00dev, PHY_CSR4, reg); - rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR1); rt2x00_set_field16(®, TXRX_CSR1_AUTO_SEQUENCE, 1); rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg); @@ -1028,7 +1022,7 @@ static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev, * device has entered the correct state. */ for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt2500usb_register_read(rt2x00dev, MAC_CSR17, ®2); + reg2 = rt2500usb_register_read(rt2x00dev, MAC_CSR17); bbp_state = rt2x00_get_field16(reg2, MAC_CSR17_BBP_CURR_STATE); rf_state = rt2x00_get_field16(reg2, MAC_CSR17_RF_CURR_STATE); if (bbp_state == state && rf_state == state) @@ -1153,7 +1147,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, TXRX_CSR19); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); @@ -1461,7 +1455,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR0); rt2x00_set_chip(rt2x00dev, RT2570, value, reg); if (((reg & 0xfff0) != 0) || ((reg & 0x0000000f) == 0)) { @@ -1786,7 +1780,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®); + reg = rt2500usb_register_read(rt2x00dev, MAC_CSR19); rt2x00_set_field16(®, MAC_CSR19_DIR0, 0); rt2500usb_register_write(rt2x00dev, MAC_CSR19, reg); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index 7fd7e6114c0c..75555f806905 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -61,12 +61,12 @@ static void rt2800usb_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); @@ -84,12 +84,12 @@ static void rt2800usb_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); @@ -333,7 +333,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2800_wait_csr_ready(rt2x00dev)) return -EBUSY; - rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + reg = rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL); rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); reg = 0; @@ -802,8 +802,8 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { }; static const struct rt2800_ops rt2800usb_rt2800_ops = { - .register_read = _rt2x00usb_register_read, - .register_read_lock = _rt2x00usb_register_read_lock, + .register_read = rt2x00usb_register_read, + .register_read_lock = rt2x00usb_register_read_lock, .register_write = rt2x00usb_register_write, .register_write_lock = rt2x00usb_register_write_lock, .register_multiread = rt2x00usb_register_multiread, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c index c696f0ad6a68..e2f4f5778267 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c @@ -145,7 +145,7 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, return -ENODEV; for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt2x00usb_register_read_lock(rt2x00dev, offset, reg); + *reg = rt2x00usb_register_read_lock(rt2x00dev, offset); if (!rt2x00_get_field32(*reg, field)) return 1; udelay(REGISTER_BUSY_DELAY); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h index 4cad1beec791..ff94c6944cfc 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.h @@ -190,24 +190,12 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, * rt2x00usb_register_read - Read 32bit register word * @rt2x00dev: Device pointer, see &struct rt2x00_dev. * @offset: Register offset - * @value: Pointer to where register contents should be stored * * This function is a simple wrapper for 32bit register access * through rt2x00usb_vendor_request_buff(). */ -static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) -{ - __le32 reg = 0; - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(reg)); - *value = le32_to_cpu(reg); -} - -static inline u32 _rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset) +static inline u32 rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { __le32 reg = 0; rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, @@ -220,24 +208,12 @@ static inline u32 _rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, * rt2x00usb_register_read_lock - Read 32bit register word * @rt2x00dev: Device pointer, see &struct rt2x00_dev. * @offset: Register offset - * @value: Pointer to where register contents should be stored * * This function is a simple wrapper for 32bit register access * through rt2x00usb_vendor_req_buff_lock(). */ -static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) -{ - __le32 reg = 0; - rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(reg), REGISTER_TIMEOUT); - *value = le32_to_cpu(reg); -} - -static inline u32 _rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset) +static inline u32 rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { __le32 reg = 0; rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index a36dee1a4f20..5a64de7304f1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -159,7 +159,7 @@ static u8 _rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int wor static const struct rt2x00debug rt73usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = _rt2x00usb_register_read, + .read = rt2x00usb_register_read, .write = rt2x00usb_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -194,7 +194,7 @@ static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00usb_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR13); return rt2x00_get_field32(reg, MAC_CSR13_VAL7); } @@ -247,7 +247,7 @@ static int rt73usb_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14, ®); + reg = rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14); rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); rt2x00usb_register_write(led->rt2x00dev, MAC_CSR14, reg); @@ -292,7 +292,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = (0xf << crypto->bssidx); - rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR0); reg &= mask; if (reg && reg == mask) @@ -325,14 +325,14 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, field.bit_offset = (3 * key->hw_key_idx); field.bit_mask = 0x7 << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, SEC_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR1); rt2x00_set_field32(®, field, crypto->cipher); rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg); } else { field.bit_offset = (3 * (key->hw_key_idx - 8)); field.bit_mask = 0x7 << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, SEC_CSR5, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR5); rt2x00_set_field32(®, field, crypto->cipher); rt2x00usb_register_write(rt2x00dev, SEC_CSR5, reg); } @@ -357,7 +357,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = 1 << key->hw_key_idx; - rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR0); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -386,10 +386,10 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * When both registers are full, we drop the key, * otherwise we use the first invalid entry. */ - rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR2); if (reg && reg == ~0) { key->hw_key_idx = 32; - rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR3); if (reg && reg == ~0) return -ENOSPC; } @@ -426,7 +426,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * without this received frames will not be decrypted * by the hardware. */ - rt2x00usb_register_read(rt2x00dev, SEC_CSR4, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR4); reg |= (1 << crypto->bssidx); rt2x00usb_register_write(rt2x00dev, SEC_CSR4, reg); @@ -451,7 +451,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, if (key->hw_key_idx < 32) { mask = 1 << key->hw_key_idx; - rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR2); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -460,7 +460,7 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, } else { mask = 1 << (key->hw_key_idx - 32); - rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); + reg = rt2x00usb_register_read(rt2x00dev, SEC_CSR3); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) @@ -482,7 +482,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, @@ -514,7 +514,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable synchronisation. */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -544,13 +544,13 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR4); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); @@ -562,18 +562,18 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, erp->basic_rates); if (changed & BSS_CHANGED_BEACON_INT) { - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, erp->beacon_int * 16); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } if (changed & BSS_CHANGED_ERP_SLOT) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR9); rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); - rt2x00usb_register_read(rt2x00dev, MAC_CSR8, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR8); rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); @@ -724,7 +724,7 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); - rt2x00usb_register_read(rt2x00dev, PHY_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, PHY_CSR0); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, (rt2x00dev->curr_band == NL80211_BAND_2GHZ)); @@ -818,7 +818,7 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR4); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_RATE_STEP, 0); rt2x00_set_field32(®, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0); @@ -838,7 +838,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR11); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, rt2x00dev->beacon_int - 10); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, @@ -855,7 +855,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, USB_MODE_SLEEP, REGISTER_TIMEOUT); } else { - rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR11); rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN, 0); rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0); rt2x00_set_field32(®, MAC_CSR11_AUTOWAKE, 0); @@ -897,13 +897,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR0); qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ - rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR1); qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); } @@ -1034,12 +1034,12 @@ static void rt73usb_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); @@ -1057,12 +1057,12 @@ static void rt73usb_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 1); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); @@ -1121,7 +1121,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, * Wait for stable hardware. */ for (i = 0; i < 100; i++) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR0); if (reg) break; msleep(1); @@ -1159,13 +1159,13 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR0); rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt2x00usb_register_read(rt2x00dev, TXRX_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ @@ -1179,7 +1179,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) /* * CCK TXD BBP registers */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR2, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR2); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); @@ -1193,7 +1193,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) /* * OFDM TXD BBP registers */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR3, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR3); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); @@ -1202,21 +1202,21 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); rt2x00usb_register_write(rt2x00dev, TXRX_CSR3, reg); - rt2x00usb_register_read(rt2x00dev, TXRX_CSR7, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR7); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); rt2x00usb_register_write(rt2x00dev, TXRX_CSR7, reg); - rt2x00usb_register_read(rt2x00dev, TXRX_CSR8, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR8); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); rt2x00usb_register_write(rt2x00dev, TXRX_CSR8, reg); - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); @@ -1227,7 +1227,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); - rt2x00usb_register_read(rt2x00dev, MAC_CSR6, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR6); rt2x00_set_field32(®, MAC_CSR6_MAX_FRAME_UNIT, 0xfff); rt2x00usb_register_write(rt2x00dev, MAC_CSR6, reg); @@ -1255,7 +1255,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); rt2x00usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); - rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR9); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); @@ -1275,24 +1275,24 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); - rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); - rt2x00usb_register_read(rt2x00dev, STA_CSR2, ®); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR0); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR1); + reg = rt2x00usb_register_read(rt2x00dev, STA_CSR2); /* * Reset MAC and BBP registers. */ - rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR1); rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); @@ -1399,7 +1399,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) put_to_sleep = (state != STATE_AWAKE); - rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR12); rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg); @@ -1410,7 +1410,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®2); + reg2 = rt2x00usb_register_read(rt2x00dev, MAC_CSR12); state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); if (state == !put_to_sleep) return 0; @@ -1547,7 +1547,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry, * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); orig_reg = reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -1612,7 +1612,7 @@ static void rt73usb_clear_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &orig_reg); + orig_reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR9); reg = orig_reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -1873,7 +1873,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR0); rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET), value, rt2x00_get_field32(reg, MAC_CSR0_REVISION)); @@ -2197,7 +2197,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2x00usb_register_read(rt2x00dev, MAC_CSR13, ®); + reg = rt2x00usb_register_read(rt2x00dev, MAC_CSR13); rt2x00_set_field32(®, MAC_CSR13_DIR7, 0); rt2x00usb_register_write(rt2x00dev, MAC_CSR13, reg); @@ -2269,7 +2269,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, field.bit_offset = (queue_idx & 1) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, offset, ®); + reg = rt2x00usb_register_read(rt2x00dev, offset); rt2x00_set_field32(®, field, queue->txop); rt2x00usb_register_write(rt2x00dev, offset, reg); @@ -2277,15 +2277,15 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, AIFSN_CSR, ®); + reg = rt2x00usb_register_read(rt2x00dev, AIFSN_CSR); rt2x00_set_field32(®, field, queue->aifs); rt2x00usb_register_write(rt2x00dev, AIFSN_CSR, reg); - rt2x00usb_register_read(rt2x00dev, CWMIN_CSR, ®); + reg = rt2x00usb_register_read(rt2x00dev, CWMIN_CSR); rt2x00_set_field32(®, field, queue->cw_min); rt2x00usb_register_write(rt2x00dev, CWMIN_CSR, reg); - rt2x00usb_register_read(rt2x00dev, CWMAX_CSR, ®); + reg = rt2x00usb_register_read(rt2x00dev, CWMAX_CSR); rt2x00_set_field32(®, field, queue->cw_max); rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg); @@ -2298,9 +2298,9 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) u64 tsf; u32 reg; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR13, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR13); tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; - rt2x00usb_register_read(rt2x00dev, TXRX_CSR12, ®); + reg = rt2x00usb_register_read(rt2x00dev, TXRX_CSR12); tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); return tsf; -- cgit v1.2.3 From eebd68e7824bae9c6ee637f43d3048f8d459dc1e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:46:58 +0200 Subject: rt2x00: convert rt2800_register_read return type This is a semi-automated conversion to change rt2800_register_read to return the register contents instead of passing them by value, resulting in much better object code. The majority of the patch was done using: sed -i 's:\(rt2800_register_read(.*, .*\), &\(.*\));:\2 = \1);:' \ 's:\(rt2800_register_read_lock(.*, .*\), &\(.*\));:\2 = \1);:' \ drivers/net/wireless/ralink/rt2x00/rt2800lib.c The function itself was modified manually along with the one remaining multi-line caller that was not covered automatically and the indirect reference. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 291 ++++++++++++------------- drivers/net/wireless/ralink/rt2x00/rt2800lib.h | 22 +- 2 files changed, 151 insertions(+), 162 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index fef53d6a888a..541e2692766a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -442,7 +442,7 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) u32 reg; int i, count; - rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL); rt2x00_set_field32(®, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff); rt2x00_set_field32(®, FRC_WL_ANT_SET, 1); rt2x00_set_field32(®, WLAN_CLK_EN, 0); @@ -457,7 +457,7 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) * Check PLL_LD & XTAL_RDY. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, CMB_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, CMB_CTRL); if (rt2x00_get_field32(reg, PLL_LD) && rt2x00_get_field32(reg, XTAL_RDY)) break; @@ -480,7 +480,7 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) count = 0; } - rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL); rt2x00_set_field32(®, PCIE_APP0_CLK_REQ, 0); rt2x00_set_field32(®, WLAN_CLK_EN, 1); rt2x00_set_field32(®, WLAN_RESET, 1); @@ -535,7 +535,7 @@ int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev) u32 reg; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2800_register_read(rt2x00dev, MAC_CSR0); if (reg && reg != ~0) return 0; msleep(1); @@ -556,7 +556,7 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) * before timing out. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) return 0; @@ -573,7 +573,7 @@ void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); @@ -723,7 +723,7 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) { - rt2800_register_read(rt2x00dev, AUX_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, AUX_CTRL); rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); rt2800_register_write(rt2x00dev, AUX_CTRL, reg); @@ -742,7 +742,7 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, * Wait for device to stabilize. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, PBF_SYS_CTRL); if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY)) break; msleep(1); @@ -1096,7 +1096,7 @@ static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev) /* * H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons. */ - rt2800_register_read(rt2x00dev, MAC_BSSID_DW1, &bssid_dw1); + bssid_dw1 = rt2800_register_read(rt2x00dev, MAC_BSSID_DW1); rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM, bcn_num > 0 ? bcn_num - 1 : 0); rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1); @@ -1115,7 +1115,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); orig_reg = reg; rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -1205,7 +1205,7 @@ void rt2800_clear_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &orig_reg); + orig_reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); reg = orig_reg; rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -1240,7 +1240,7 @@ static u8 _rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word const struct rt2x00debug rt2800_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = _rt2800_register_read, + .read = rt2800_register_read, .write = rt2800_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, @@ -1287,10 +1287,10 @@ int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev) u32 reg; if (rt2x00_rt(rt2x00dev, RT3290)) { - rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL); return rt2x00_get_field32(reg, WLAN_GPIO_IN_BIT0); } else { - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); return rt2x00_get_field32(reg, GPIO_CTRL_VAL2); } } @@ -1315,7 +1315,7 @@ static void rt2800_brightness_set(struct led_classdev *led_cdev, /* Check for SoC (SOC devices don't support MCU requests) */ if (rt2x00_is_soc(led->rt2x00dev)) { - rt2800_register_read(led->rt2x00dev, LED_CFG, ®); + reg = rt2800_register_read(led->rt2x00dev, LED_CFG); /* Set LED Polarity */ rt2x00_set_field32(®, LED_CFG_LED_POLAR, polarity); @@ -1404,7 +1404,7 @@ static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev, * The BSS Idx numbers is split in a main value of 3 bits, * and a extended field for adding one additional bit to the value. */ - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7)); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT, (bssidx & 0x8) >> 3); @@ -1422,7 +1422,7 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev, offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); if (crypto->cmd == SET_KEY) { - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); /* @@ -1438,7 +1438,7 @@ static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, offset, reg); } else { /* Delete the cipher without touching the bssidx */ - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, 0); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, 0); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER_EXT, 0); @@ -1494,7 +1494,7 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, field, (crypto->cmd == SET_KEY) * crypto->cipher); rt2800_register_write(rt2x00dev, offset, reg); @@ -1560,7 +1560,7 @@ static void rt2800_set_max_psdu_len(struct rt2x00_dev *rt2x00dev) max_psdu = min(drv_data->max_psdu, i); - rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MAX_LEN_CFG); rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, max_psdu); rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); } @@ -1652,7 +1652,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2800_register_read(rt2x00dev, RX_FILTER_CFG, ®); + reg = rt2800_register_read(rt2x00dev, RX_FILTER_CFG); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, @@ -1696,7 +1696,7 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, /* * Enable synchronisation. */ - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -1704,14 +1704,14 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, /* * Tune beacon queue transmit parameters for AP mode */ - rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 0); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 1); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 0); rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); } else { - rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 4); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 2); rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); @@ -1830,22 +1830,22 @@ static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev, gf20_mode = gf40_mode = 1; /* Update HT protection config */ - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, mm20_rate); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, mm20_mode); rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM40_PROT_CFG); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, mm40_rate); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, mm40_mode); rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF20_PROT_CFG); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, gf20_rate); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, gf20_mode); rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF40_PROT_CFG); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, gf40_rate); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, gf40_mode); rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); @@ -1857,14 +1857,14 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, u32 reg; if (changed & BSS_CHANGED_ERP_PREAMBLE) { - rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + reg = rt2800_register_read(rt2x00dev, AUTO_RSP_CFG); rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, !!erp->short_preamble); rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); } if (changed & BSS_CHANGED_ERP_CTS_PROT) { - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, erp->cts_protection ? 2 : 0); rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); @@ -1877,18 +1877,18 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp, } if (changed & BSS_CHANGED_ERP_SLOT) { - rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG); rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); - rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, XIFS_TIME_CFG); rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); } if (changed & BSS_CHANGED_BEACON_INT) { - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, erp->beacon_int * 16); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -1905,7 +1905,7 @@ static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev) u16 eeprom; u8 led_ctrl, led_g_mode, led_r_mode; - rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_SWITCH); if (rt2x00dev->curr_band == NL80211_BAND_5GHZ) { rt2x00_set_field32(®, GPIO_SWITCH_0, 1); rt2x00_set_field32(®, GPIO_SWITCH_1, 1); @@ -1915,7 +1915,7 @@ static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev) } rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); - rt2800_register_read(rt2x00dev, LED_CFG, ®); + reg = rt2800_register_read(rt2x00dev, LED_CFG); led_g_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 3 : 0; led_r_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 0 : 3; if (led_g_mode != rt2x00_get_field32(reg, LED_CFG_G_LED_MODE) || @@ -1941,14 +1941,14 @@ static void rt2800_set_ant_diversity(struct rt2x00_dev *rt2x00dev, u8 gpio_bit3 = (ant == ANTENNA_A) ? 0 : 1; if (rt2x00_is_pci(rt2x00dev)) { - rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); + reg = rt2800_register_read(rt2x00dev, E2PROM_CSR); rt2x00_set_field32(®, E2PROM_CSR_DATA_CLOCK, eesk_pin); rt2800_register_write(rt2x00dev, E2PROM_CSR, reg); } else if (rt2x00_is_usb(rt2x00dev)) rt2800_mcu_request(rt2x00dev, MCU_ANT_SELECT, 0xff, eesk_pin, 0); - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); rt2x00_set_field32(®, GPIO_CTRL_DIR3, 0); rt2x00_set_field32(®, GPIO_CTRL_VAL3, gpio_bit3); rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); @@ -2411,7 +2411,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 29, 0x9f); } - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); rt2x00_set_field32(®, GPIO_CTRL_DIR7, 0); if (rf->channel <= 14) rt2x00_set_field32(®, GPIO_CTRL_VAL7, 1); @@ -2923,7 +2923,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, const bool is_11b = false; const bool is_type_ep = false; - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, (rf->channel > 14 || conf_is_ht40(conf)) ? 5 : 0); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); @@ -3362,7 +3362,7 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, if (max_power > 0x2f) max_power = 0x2f; - rt2800_register_read(rt2x00dev, TX_ALC_CFG_0, ®); + reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_0); rt2x00_set_field32(®, TX_ALC_CFG_0_CH_INIT_0, power_level); rt2x00_set_field32(®, TX_ALC_CFG_0_CH_INIT_1, power_level); rt2x00_set_field32(®, TX_ALC_CFG_0_LIMIT_0, max_power); @@ -3378,18 +3378,17 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, } rt2800_register_write(rt2x00dev, TX_ALC_CFG_0, reg); - rt2800_register_read(rt2x00dev, TX_ALC_CFG_1, ®); + reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1); rt2x00_set_field32(®, TX_ALC_CFG_1_TX_TEMP_COMP, 0); rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg); /* Save MAC SYS CTRL registers */ - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &mac_sys_ctrl); + mac_sys_ctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); /* Disable Tx/Rx */ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0); /* Check MAC Tx/Rx idle */ for (i = 0; i < 10000; i++) { - rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, - &mac_status); + mac_status = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); if (mac_status & 0x3) usleep_range(50, 200); else @@ -3702,7 +3701,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_bbp_write(rt2x00dev, 75, 0x50); } - rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_BAND_CFG); rt2x00_set_field32(®, TX_BAND_CFG_HT40_MINUS, conf_is_ht40_minus(conf)); rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); @@ -3711,7 +3710,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, if (rt2x00_rt(rt2x00dev, RT3572)) rt2800_rfcsr_write(rt2x00dev, 8, 0); - rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin); + tx_pin = rt2800_register_read(rt2x00dev, TX_PIN_CFG); switch (rt2x00dev->default_ant.tx_chain_num) { case 3: @@ -3777,7 +3776,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, } if (rt2x00_rt(rt2x00dev, RT3593)) { - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); /* Band selection */ if (rt2x00_is_usb(rt2x00dev) || @@ -3869,9 +3868,9 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, /* * Clear channel statistic counters */ - rt2800_register_read(rt2x00dev, CH_IDLE_STA, ®); - rt2800_register_read(rt2x00dev, CH_BUSY_STA, ®); - rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, ®); + reg = rt2800_register_read(rt2x00dev, CH_IDLE_STA); + reg = rt2800_register_read(rt2x00dev, CH_BUSY_STA); + reg = rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC); /* * Clear update flag @@ -4613,26 +4612,26 @@ static void rt2800_config_txpower_rt6352(struct rt2x00_dev *rt2x00dev, /* For OFDM 54MBS use value from OFDM 48MBS */ pwreg = 0; - rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, ®); + reg = rt2800_register_read(rt2x00dev, TX_PWR_CFG_1); t = rt2x00_get_field32(reg, TX_PWR_CFG_1B_48MBS); rt2x00_set_field32(&pwreg, TX_PWR_CFG_7B_54MBS, t); /* For MCS 7 use value from MCS 6 */ - rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, ®); + reg = rt2800_register_read(rt2x00dev, TX_PWR_CFG_2); t = rt2x00_get_field32(reg, TX_PWR_CFG_2B_MCS6_MCS7); rt2x00_set_field32(&pwreg, TX_PWR_CFG_7B_MCS7, t); rt2800_register_write(rt2x00dev, TX_PWR_CFG_7, pwreg); /* For MCS 15 use value from MCS 14 */ pwreg = 0; - rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, ®); + reg = rt2800_register_read(rt2x00dev, TX_PWR_CFG_3); t = rt2x00_get_field32(reg, TX_PWR_CFG_3B_MCS14); rt2x00_set_field32(&pwreg, TX_PWR_CFG_8B_MCS15, t); rt2800_register_write(rt2x00dev, TX_PWR_CFG_8, pwreg); /* For STBC MCS 7 use value from STBC MCS 6 */ pwreg = 0; - rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, ®); + reg = rt2800_register_read(rt2x00dev, TX_PWR_CFG_4); t = rt2x00_get_field32(reg, TX_PWR_CFG_4B_STBC_MCS6); rt2x00_set_field32(&pwreg, TX_PWR_CFG_9B_STBC_MCS7, t); rt2800_register_write(rt2x00dev, TX_PWR_CFG_9, pwreg); @@ -4725,7 +4724,7 @@ static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, if (offset > TX_PWR_CFG_4) break; - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); /* read the next four txpower values */ rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, @@ -4865,7 +4864,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) * periodically to adjust the frequency to be precision. */ - rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin); + tx_pin = rt2800_register_read(rt2x00dev, TX_PIN_CFG); tx_pin &= TX_PIN_CFG_PA_PE_DISABLE; rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); @@ -4913,7 +4912,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) if (min_sleep > 0) usleep_range(min_sleep, min_sleep * 2); - rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin); + tx_pin = rt2800_register_read(rt2x00dev, TX_PIN_CFG); if (rt2x00dev->rf_channel <= 14) { switch (rt2x00dev->default_ant.tx_chain_num) { case 3: @@ -4987,7 +4986,7 @@ static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_RTY_CFG); rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, libconf->conf->short_frame_max_tx_count); rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, @@ -5006,7 +5005,7 @@ static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev, if (state == STATE_SLEEP) { rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); - rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + reg = rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, libconf->conf->listen_interval - 1); @@ -5015,7 +5014,7 @@ static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev, rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); } else { - rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + reg = rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); @@ -5058,7 +5057,7 @@ void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual) /* * Update FCS error count from register. */ - rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); + reg = rt2800_register_read(rt2x00dev, RX_STA_CNT0); qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); } EXPORT_SYMBOL_GPL(rt2800_link_stats); @@ -5187,7 +5186,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BCN_TIME_CFG); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 1600); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); @@ -5198,43 +5197,43 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_config_filter(rt2x00dev, FIF_ALLMULTI); - rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG); rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, 9); rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); if (rt2x00_rt(rt2x00dev, RT3290)) { - rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL); if (rt2x00_get_field32(reg, WLAN_EN) == 1) { rt2x00_set_field32(®, PCIE_APP0_CLK_REQ, 1); rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg); } - rt2800_register_read(rt2x00dev, CMB_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, CMB_CTRL); if (!(rt2x00_get_field32(reg, LDO0_EN) == 1)) { rt2x00_set_field32(®, LDO0_EN, 1); rt2x00_set_field32(®, LDO_BGSEL, 3); rt2800_register_write(rt2x00dev, CMB_CTRL, reg); } - rt2800_register_read(rt2x00dev, OSC_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, OSC_CTRL); rt2x00_set_field32(®, OSC_ROSC_EN, 1); rt2x00_set_field32(®, OSC_CAL_REQ, 1); rt2x00_set_field32(®, OSC_REF_CYCLE, 0x27); rt2800_register_write(rt2x00dev, OSC_CTRL, reg); - rt2800_register_read(rt2x00dev, COEX_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, COEX_CFG0); rt2x00_set_field32(®, COEX_CFG_ANT, 0x5e); rt2800_register_write(rt2x00dev, COEX_CFG0, reg); - rt2800_register_read(rt2x00dev, COEX_CFG2, ®); + reg = rt2800_register_read(rt2x00dev, COEX_CFG2); rt2x00_set_field32(®, BT_COEX_CFG1, 0x00); rt2x00_set_field32(®, BT_COEX_CFG0, 0x17); rt2x00_set_field32(®, WL_COEX_CFG1, 0x93); rt2x00_set_field32(®, WL_COEX_CFG0, 0x7f); rt2800_register_write(rt2x00dev, COEX_CFG2, reg); - rt2800_register_read(rt2x00dev, PLL_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, PLL_CTRL); rt2x00_set_field32(®, PLL_CONTROL, 1); rt2800_register_write(rt2x00dev, PLL_CTRL, reg); } @@ -5331,7 +5330,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) 0x3630363A); rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT, 0x3630363A); - rt2800_register_read(rt2x00dev, TX_ALC_CFG_1, ®); + reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1); rt2x00_set_field32(®, TX_ALC_CFG_1_ROS_BUSY_EN, 0); rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg); } else { @@ -5339,7 +5338,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); } - rt2800_register_read(rt2x00dev, TX_LINK_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_LINK_CFG); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); @@ -5350,13 +5349,13 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); rt2800_register_write(rt2x00dev, TX_LINK_CFG, reg); - rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG); rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 32); rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MAX_LEN_CFG); rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); if (rt2x00_is_usb(rt2x00dev)) { drv_data->max_psdu = 3; @@ -5372,7 +5371,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 10); rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); - rt2800_register_read(rt2x00dev, LED_CFG, ®); + reg = rt2800_register_read(rt2x00dev, LED_CFG); rt2x00_set_field32(®, LED_CFG_ON_PERIOD, 70); rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, 30); rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); @@ -5384,7 +5383,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); - rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_RTY_CFG); rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, 2); rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, 2); rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_THRE, 2000); @@ -5393,7 +5392,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg); - rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + reg = rt2800_register_read(rt2x00dev, AUTO_RSP_CFG); rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, 1); rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 1); @@ -5403,7 +5402,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, CCK_PROT_CFG); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 3); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5416,7 +5415,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 1); rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 3); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5429,7 +5428,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 1); rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 1); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5442,7 +5441,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM40_PROT_CFG); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 1); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5455,7 +5454,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF20_PROT_CFG); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 1); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5468,7 +5467,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, 0); rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF40_PROT_CFG); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 1); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV_SHORT, 1); @@ -5484,7 +5483,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00_is_usb(rt2x00dev)) { rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); @@ -5501,7 +5500,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) * The legacy driver also sets TXOP_CTRL_CFG_RESERVED_TRUN_EN to 1 * although it is reserved. */ - rt2800_register_read(rt2x00dev, TXOP_CTRL_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TXOP_CTRL_CFG); rt2x00_set_field32(®, TXOP_CTRL_CFG_TIMEOUT_TRUN_EN, 1); rt2x00_set_field32(®, TXOP_CTRL_CFG_AC_TRUN_EN, 1); rt2x00_set_field32(®, TXOP_CTRL_CFG_TXRATEGRP_TRUN_EN, 1); @@ -5517,7 +5516,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) reg = rt2x00_rt(rt2x00dev, RT5592) ? 0x00000082 : 0x00000002; rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, reg); - rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_RTS_CFG); rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 7); rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, IEEE80211_MAX_RTS_THRESHOLD); @@ -5533,7 +5532,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) * connection problems with 11g + CTS protection. Hence, use the same * defaults as the Ralink driver: 16 for both, CCK and OFDM SIFS. */ - rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, XIFS_TIME_CFG); rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, 16); rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, 16); rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); @@ -5563,16 +5562,16 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_clear_beacon_register(rt2x00dev, i); if (rt2x00_is_usb(rt2x00dev)) { - rt2800_register_read(rt2x00dev, US_CYC_CNT, ®); + reg = rt2800_register_read(rt2x00dev, US_CYC_CNT); rt2x00_set_field32(®, US_CYC_CNT_CLOCK_CYCLE, 30); rt2800_register_write(rt2x00dev, US_CYC_CNT, reg); } else if (rt2x00_is_pcie(rt2x00dev)) { - rt2800_register_read(rt2x00dev, US_CYC_CNT, ®); + reg = rt2800_register_read(rt2x00dev, US_CYC_CNT); rt2x00_set_field32(®, US_CYC_CNT_CLOCK_CYCLE, 125); rt2800_register_write(rt2x00dev, US_CYC_CNT, reg); } - rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, HT_FBK_CFG0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); @@ -5583,7 +5582,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); rt2800_register_write(rt2x00dev, HT_FBK_CFG0, reg); - rt2800_register_read(rt2x00dev, HT_FBK_CFG1, ®); + reg = rt2800_register_read(rt2x00dev, HT_FBK_CFG1); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); @@ -5594,7 +5593,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); rt2800_register_write(rt2x00dev, HT_FBK_CFG1, reg); - rt2800_register_read(rt2x00dev, LG_FBK_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LG_FBK_CFG0); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); @@ -5605,7 +5604,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); rt2800_register_write(rt2x00dev, LG_FBK_CFG0, reg); - rt2800_register_read(rt2x00dev, LG_FBK_CFG1, ®); + reg = rt2800_register_read(rt2x00dev, LG_FBK_CFG1); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); @@ -5615,7 +5614,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) /* * Do not force the BA window size, we use the TXWI to set it */ - rt2800_register_read(rt2x00dev, AMPDU_BA_WINSIZE, ®); + reg = rt2800_register_read(rt2x00dev, AMPDU_BA_WINSIZE); rt2x00_set_field32(®, AMPDU_BA_WINSIZE_FORCE_WINSIZE_ENABLE, 0); rt2x00_set_field32(®, AMPDU_BA_WINSIZE_FORCE_WINSIZE, 0); rt2800_register_write(rt2x00dev, AMPDU_BA_WINSIZE, reg); @@ -5625,24 +5624,24 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); - rt2800_register_read(rt2x00dev, RX_STA_CNT1, ®); - rt2800_register_read(rt2x00dev, RX_STA_CNT2, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT0, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT1, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT2, ®); + reg = rt2800_register_read(rt2x00dev, RX_STA_CNT0); + reg = rt2800_register_read(rt2x00dev, RX_STA_CNT1); + reg = rt2800_register_read(rt2x00dev, RX_STA_CNT2); + reg = rt2800_register_read(rt2x00dev, TX_STA_CNT0); + reg = rt2800_register_read(rt2x00dev, TX_STA_CNT1); + reg = rt2800_register_read(rt2x00dev, TX_STA_CNT2); /* * Setup leadtime for pre tbtt interrupt to 6ms */ - rt2800_register_read(rt2x00dev, INT_TIMER_CFG, ®); + reg = rt2800_register_read(rt2x00dev, INT_TIMER_CFG); rt2x00_set_field32(®, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4); rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg); /* * Set up channel statistics timer */ - rt2800_register_read(rt2x00dev, CH_TIME_CFG, ®); + reg = rt2800_register_read(rt2x00dev, CH_TIME_CFG); rt2x00_set_field32(®, CH_TIME_CFG_EIFS_BUSY, 1); rt2x00_set_field32(®, CH_TIME_CFG_NAV_BUSY, 1); rt2x00_set_field32(®, CH_TIME_CFG_RX_BUSY, 1); @@ -5659,7 +5658,7 @@ static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) u32 reg; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG); if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) return 0; @@ -6212,7 +6211,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) if (rt2x00_has_cap_bt_coexist(rt2x00dev)) { u32 reg; - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); rt2x00_set_field32(®, GPIO_CTRL_DIR3, 0); rt2x00_set_field32(®, GPIO_CTRL_DIR6, 0); rt2x00_set_field32(®, GPIO_CTRL_VAL3, 0); @@ -6605,7 +6604,7 @@ static void rt2800_led_open_drain_enable(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2800_register_read(rt2x00dev, OPT_14_CSR, ®); + reg = rt2800_register_read(rt2x00dev, OPT_14_CSR); rt2x00_set_field32(®, OPT_14_CSR_BIT0, 1); rt2800_register_write(rt2x00dev, OPT_14_CSR, reg); } @@ -6938,7 +6937,7 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) { - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); @@ -6950,7 +6949,7 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) { @@ -6963,7 +6962,7 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) } rt2800_register_write(rt2x00dev, LDO_CFG0, reg); - rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_SWITCH); rt2x00_set_field32(®, GPIO_SWITCH_5, 0); rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); } @@ -7178,7 +7177,7 @@ static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 30, 0x20); rt2800_rfcsr_write(rt2x00dev, 31, 0x0f); - rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_SWITCH); rt2x00_set_field32(®, GPIO_SWITCH_5, 0); rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); @@ -7234,12 +7233,12 @@ static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1); rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); msleep(1); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 0); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); @@ -7303,7 +7302,7 @@ static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) u8 rfcsr; /* Disable GPIO #4 and #7 function for LAN PE control */ - rt2800_register_read(rt2x00dev, GPIO_SWITCH, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_SWITCH); rt2x00_set_field32(®, GPIO_SWITCH_4, 0); rt2x00_set_field32(®, GPIO_SWITCH_7, 0); rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg); @@ -7354,12 +7353,12 @@ static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR18_XO_TUNE_BYPASS, 1); rt2800_rfcsr_write(rt2x00dev, 18, rfcsr); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); usleep_range(1000, 1500); - rt2800_register_read(rt2x00dev, LDO_CFG0, ®); + reg = rt2800_register_read(rt2x00dev, LDO_CFG0); rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 0); rt2800_register_write(rt2x00dev, LDO_CFG0, reg); @@ -7773,8 +7772,8 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, u32 MAC_RF_CONTROL0, MAC_RF_BYPASS0; /* Save MAC registers */ - rt2800_register_read(rt2x00dev, RF_CONTROL0, &MAC_RF_CONTROL0); - rt2800_register_read(rt2x00dev, RF_BYPASS0, &MAC_RF_BYPASS0); + MAC_RF_CONTROL0 = rt2800_register_read(rt2x00dev, RF_CONTROL0); + MAC_RF_BYPASS0 = rt2800_register_read(rt2x00dev, RF_BYPASS0); /* save BBP registers */ rt2800_bbp_read(rt2x00dev, 23, &savebbpr23); @@ -8367,20 +8366,20 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Enable RX. */ - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); udelay(50); - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); @@ -8413,7 +8412,7 @@ void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev) /* Wait for DMA, ignore error */ rt2800_wait_wpdma_ready(rt2x00dev); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 0); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); @@ -8430,7 +8429,7 @@ int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev) else efuse_ctrl_reg = EFUSE_CTRL; - rt2800_register_read(rt2x00dev, efuse_ctrl_reg, ®); + reg = rt2800_register_read(rt2x00dev, efuse_ctrl_reg); return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT); } EXPORT_SYMBOL_GPL(rt2800_efuse_detect); @@ -8459,7 +8458,7 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) } mutex_lock(&rt2x00dev->csr_mutex); - rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg); rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); @@ -8468,14 +8467,14 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) /* Wait until the EEPROM has been loaded */ rt2800_regbusy_read(rt2x00dev, efuse_ctrl_reg, EFUSE_CTRL_KICK, ®); /* Apparently the data is read from end to start */ - rt2800_register_read_lock(rt2x00dev, efuse_data3_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_data3_reg); /* The returned value is in CPU order, but eeprom is le */ *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg); - rt2800_register_read_lock(rt2x00dev, efuse_data2_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_data2_reg); *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); - rt2800_register_read_lock(rt2x00dev, efuse_data1_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_data1_reg); *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg); - rt2800_register_read_lock(rt2x00dev, efuse_data0_reg, ®); + reg = rt2800_register_read_lock(rt2x00dev, efuse_data0_reg); *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg); mutex_unlock(&rt2x00dev->csr_mutex); @@ -9251,7 +9250,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) break; case RF5592: - rt2800_register_read(rt2x00dev, MAC_DEBUG_INDEX, ®); + reg = rt2800_register_read(rt2x00dev, MAC_DEBUG_INDEX); if (rt2x00_get_field32(reg, MAC_DEBUG_INDEX_XTAL)) { spec->num_channels = ARRAY_SIZE(rf_vals_5592_xtal40); spec->channels = rf_vals_5592_xtal40; @@ -9390,9 +9389,9 @@ static int rt2800_probe_rt(struct rt2x00_dev *rt2x00dev) u32 rev; if (rt2x00_rt(rt2x00dev, RT3290)) - rt2800_register_read(rt2x00dev, MAC_CSR0_3290, ®); + reg = rt2800_register_read(rt2x00dev, MAC_CSR0_3290); else - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + reg = rt2800_register_read(rt2x00dev, MAC_CSR0); rt = rt2x00_get_field32(reg, MAC_CSR0_CHIPSET); rev = rt2x00_get_field32(reg, MAC_CSR0_REVISION); @@ -9452,7 +9451,7 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev) * Enable rfkill polling by setting GPIO direction of the * rfkill switch GPIO pin correctly. */ - rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); + reg = rt2800_register_read(rt2x00dev, GPIO_CTRL); rt2x00_set_field32(®, GPIO_CTRL_DIR2, 1); rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); @@ -9527,31 +9526,31 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) u32 reg; bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); - rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); + reg = rt2800_register_read(rt2x00dev, TX_RTS_CFG); rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, CCK_PROT_CFG); rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG); rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG); rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, MM40_PROT_CFG); rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF20_PROT_CFG); rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); + reg = rt2800_register_read(rt2x00dev, GF40_PROT_CFG); rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); @@ -9594,7 +9593,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, field.bit_offset = (queue_idx & 1) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, field, queue->txop); rt2800_register_write(rt2x00dev, offset, reg); @@ -9602,22 +9601,22 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG); rt2x00_set_field32(®, field, queue->aifs); rt2800_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); - rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG); rt2x00_set_field32(®, field, queue->cw_min); rt2800_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); - rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); + reg = rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG); rt2x00_set_field32(®, field, queue->cw_max); rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); /* Update EDCA registers */ offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); - rt2800_register_read(rt2x00dev, offset, ®); + reg = rt2800_register_read(rt2x00dev, offset); rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); @@ -9634,9 +9633,9 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) u64 tsf; u32 reg; - rt2800_register_read(rt2x00dev, TSF_TIMER_DW1, ®); + reg = rt2800_register_read(rt2x00dev, TSF_TIMER_DW1); tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; - rt2800_register_read(rt2x00dev, TSF_TIMER_DW0, ®); + reg = rt2800_register_read(rt2x00dev, TSF_TIMER_DW0); tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); return tsf; @@ -9703,9 +9702,9 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx, survey->channel = conf->chandef.chan; - rt2800_register_read(rt2x00dev, CH_IDLE_STA, &idle); - rt2800_register_read(rt2x00dev, CH_BUSY_STA, &busy); - rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext); + idle = rt2800_register_read(rt2x00dev, CH_IDLE_STA); + busy = rt2800_register_read(rt2x00dev, CH_BUSY_STA); + busy_ext = rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC); if (idle || busy) { survey->filled = SURVEY_INFO_TIME | diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h index 6bed0d5e930e..275e3969abdd 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -78,30 +78,20 @@ struct rt2800_ops { __le32 *(*drv_get_txwi)(struct queue_entry *entry); }; -static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) +static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; - *value = rt2800ops->register_read(rt2x00dev, offset); -} - -static inline void rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; - - *value = rt2800ops->register_read_lock(rt2x00dev, offset); + return rt2800ops->register_read(rt2x00dev, offset); } -static inline u32 _rt2800_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset) +static inline u32 rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset) { const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; - return rt2800ops->register_read(rt2x00dev, offset); + return rt2800ops->register_read_lock(rt2x00dev, offset); } static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, -- cgit v1.2.3 From 5fbbe378890fd543a9374ec0f86c9cba6d700712 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:46:59 +0200 Subject: rt2x00: convert rt2*_bbp_read return type This is a semi-automated conversion to change *_bbp_read() to return the register contents instead of passing them by value, resulting in much better object code. The majority of the patch was done using: sed -i 's:\(\(.*, .*\), &\(.*\));:\2 = \1);:' \ -i 's:\(\(.*, .*\), &\(.*\));:\2 = \1);:' \ -i 's:= _\(rt.*_bbp_read\):\1:' drivers/net/wireless/ralink/rt2x00/* Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 29 +++---- drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 27 +++--- drivers/net/wireless/ralink/rt2x00/rt2500usb.c | 29 +++---- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 116 ++++++++++++------------- drivers/net/wireless/ralink/rt2x00/rt61pci.c | 42 ++++----- drivers/net/wireless/ralink/rt2x00/rt73usb.c | 36 ++++---- 6 files changed, 119 insertions(+), 160 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 3607261df199..0ab3d571aba4 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -77,10 +77,11 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -103,9 +104,11 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + value = rt2x00_get_field32(reg, BBPCSR_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, @@ -164,16 +167,6 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -static u8 _rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word) -{ - u8 value; - - rt2400pci_bbp_read(rt2x00dev, word, &value); - - return value; -} - static const struct rt2x00debug rt2400pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { @@ -192,7 +185,7 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = { .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = _rt2400pci_bbp_read, + .read = rt2400pci_bbp_read, .write = rt2400pci_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), @@ -418,8 +411,8 @@ static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev, BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || ant->tx == ANTENNA_SW_DIVERSITY); - rt2400pci_bbp_read(rt2x00dev, 4, &r4); - rt2400pci_bbp_read(rt2x00dev, 1, &r1); + r4 = rt2400pci_bbp_read(rt2x00dev, 4); + r1 = rt2400pci_bbp_read(rt2x00dev, 1); /* * Configure the TX antenna. @@ -600,7 +593,7 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update False CCA count from register. */ - rt2400pci_bbp_read(rt2x00dev, 39, &bbp); + bbp = rt2400pci_bbp_read(rt2x00dev, 39); qual->false_cca = bbp; } @@ -921,7 +914,7 @@ static int rt2400pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2400pci_bbp_read(rt2x00dev, 0, &value); + value = rt2400pci_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index dc622d60f79d..a4e2f7b8adf1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -77,10 +77,11 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -103,9 +104,11 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + value = rt2x00_get_field32(reg, BBPCSR_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, @@ -164,16 +167,6 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -static u8 _rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word) -{ - u8 value; - - rt2500pci_bbp_read(rt2x00dev, word, &value); - - return value; -} - static const struct rt2x00debug rt2500pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { @@ -192,7 +185,7 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = { .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = _rt2500pci_bbp_read, + .read = rt2500pci_bbp_read, .write = rt2500pci_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), @@ -426,8 +419,8 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, ant->tx == ANTENNA_SW_DIVERSITY); reg = rt2x00mmio_register_read(rt2x00dev, BBPCSR1); - rt2500pci_bbp_read(rt2x00dev, 14, &r14); - rt2500pci_bbp_read(rt2x00dev, 2, &r2); + r14 = rt2500pci_bbp_read(rt2x00dev, 14); + r2 = rt2500pci_bbp_read(rt2x00dev, 2); /* * Configure the TX antenna. @@ -1059,7 +1052,7 @@ static int rt2500pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500pci_bbp_read(rt2x00dev, 0, &value); + value = rt2500pci_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index 70204cecc985..37c6684db4de 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -153,10 +153,11 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u16 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -179,9 +180,11 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, reg = rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7); } - *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); + value = rt2x00_get_field16(reg, PHY_CSR7_DATA); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, @@ -227,16 +230,6 @@ static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write(rt2x00dev, offset, value); } -static u8 _rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word) -{ - u8 value; - - rt2500usb_bbp_read(rt2x00dev, word, &value); - - return value; -} - static const struct rt2x00debug rt2500usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { @@ -255,7 +248,7 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = _rt2500usb_bbp_read, + .read = rt2500usb_bbp_read, .write = rt2500usb_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), @@ -530,8 +523,8 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || ant->tx == ANTENNA_SW_DIVERSITY); - rt2500usb_bbp_read(rt2x00dev, 2, &r2); - rt2500usb_bbp_read(rt2x00dev, 14, &r14); + r2 = rt2500usb_bbp_read(rt2x00dev, 2); + r14 = rt2500usb_bbp_read(rt2x00dev, 14); csr5 = rt2500usb_register_read(rt2x00dev, PHY_CSR5); csr6 = rt2500usb_register_read(rt2x00dev, PHY_CSR6); @@ -903,7 +896,7 @@ static int rt2500usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt2500usb_bbp_read(rt2x00dev, 0, &value); + value = rt2500usb_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -1391,7 +1384,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) * Switch lower vgc bound to current BBP R17 value, * lower the value a bit for better quality. */ - rt2500usb_bbp_read(rt2x00dev, 17, &bbp); + bbp = rt2500usb_bbp_read(rt2x00dev, 17); bbp -= 6; rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 541e2692766a..35c1206ed6ac 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -110,10 +110,10 @@ static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -137,9 +137,11 @@ static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); + value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, @@ -1228,15 +1230,6 @@ void rt2800_clear_beacon(struct queue_entry *entry) EXPORT_SYMBOL_GPL(rt2800_clear_beacon); #ifdef CONFIG_RT2X00_LIB_DEBUGFS -static u8 _rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) -{ - u8 value; - - rt2800_bbp_read(rt2x00dev, word, &value); - - return value; -} - const struct rt2x00debug rt2800_rt2x00debug = { .owner = THIS_MODULE, .csr = { @@ -1258,7 +1251,7 @@ const struct rt2x00debug rt2800_rt2x00debug = { .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = _rt2800_bbp_read, + .read = rt2800_bbp_read, .write = rt2800_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), @@ -1960,8 +1953,8 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) u8 r3; u16 eeprom; - rt2800_bbp_read(rt2x00dev, 1, &r1); - rt2800_bbp_read(rt2x00dev, 3, &r3); + r1 = rt2800_bbp_read(rt2x00dev, 1); + r3 = rt2800_bbp_read(rt2x00dev, 3); if (rt2x00_rt(rt2x00dev, RT3572) && rt2x00_has_cap_bt_coexist(rt2x00dev)) @@ -2437,12 +2430,12 @@ static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev, const bool txbf_enabled = false; /* TODO */ /* TODO: use TX{0,1,2}FinePowerControl values from EEPROM */ - rt2800_bbp_read(rt2x00dev, 109, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 109); rt2x00_set_field8(&bbp, BBP109_TX0_POWER, 0); rt2x00_set_field8(&bbp, BBP109_TX1_POWER, 0); rt2800_bbp_write(rt2x00dev, 109, bbp); - rt2800_bbp_read(rt2x00dev, 110, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 110); rt2x00_set_field8(&bbp, BBP110_TX2_POWER, 0); rt2800_bbp_write(rt2x00dev, 110, bbp); @@ -3399,7 +3392,7 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n"); if (chan->center_freq > 2457) { - rt2800_bbp_read(rt2x00dev, 30, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 30); bbp = 0x40; rt2800_bbp_write(rt2x00dev, 30, bbp); rt2800_rfcsr_write(rt2x00dev, 39, 0); @@ -3408,7 +3401,7 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, else rt2800_rfcsr_write(rt2x00dev, 42, 0x7b); } else { - rt2800_bbp_read(rt2x00dev, 30, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 30); bbp = 0x1f; rt2800_bbp_write(rt2x00dev, 30, bbp); rt2800_rfcsr_write(rt2x00dev, 39, 0x80); @@ -3429,7 +3422,7 @@ static void rt2800_bbp_write_with_rx_chain(struct rt2x00_dev *rt2x00dev, u8 chain, reg; for (chain = 0; chain < rt2x00dev->default_ant.rx_chain_num; chain++) { - rt2800_bbp_read(rt2x00dev, 27, ®); + reg = rt2800_bbp_read(rt2x00dev, 27); rt2x00_set_field8(®, BBP27_RX_CHAIN_SEL, chain); rt2800_bbp_write(rt2x00dev, 27, reg); @@ -3843,11 +3836,11 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_iq_calibrate(rt2x00dev, rf->channel); } - rt2800_bbp_read(rt2x00dev, 4, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); rt2800_bbp_write(rt2x00dev, 4, bbp); - rt2800_bbp_read(rt2x00dev, 3, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 3); rt2x00_set_field8(&bbp, BBP3_HT40_MINUS, conf_is_ht40_minus(conf)); rt2800_bbp_write(rt2x00dev, 3, bbp); @@ -3877,7 +3870,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, */ if (rt2x00_rt(rt2x00dev, RT3352) || rt2x00_rt(rt2x00dev, RT5350)) { - rt2800_bbp_read(rt2x00dev, 49, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 49); rt2x00_set_field8(&bbp, BBP49_UPDATE_FLAG, 0); rt2800_bbp_write(rt2x00dev, 49, bbp); } @@ -3979,7 +3972,7 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) /* * Read current TSSI (BBP 49). */ - rt2800_bbp_read(rt2x00dev, 49, ¤t_tssi); + current_tssi = rt2800_bbp_read(rt2x00dev, 49); /* * Compare TSSI value (BBP49) with the compensation boundaries @@ -4713,7 +4706,7 @@ static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, } else { power_ctrl = 0; } - rt2800_bbp_read(rt2x00dev, 1, &r1); + r1 = rt2800_bbp_read(rt2x00dev, 1); rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl); rt2800_bbp_write(rt2x00dev, 1, r1); @@ -5683,7 +5676,7 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) msleep(1); for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_bbp_read(rt2x00dev, 0, &value); + value = rt2800_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -5697,7 +5690,7 @@ static void rt2800_bbp4_mac_if_ctrl(struct rt2x00_dev *rt2x00dev) { u8 value; - rt2800_bbp_read(rt2x00dev, 4, &value); + value = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1); rt2800_bbp_write(rt2x00dev, 4, value); } @@ -5754,7 +5747,7 @@ static void rt2800_disable_unused_dac_adc(struct rt2x00_dev *rt2x00dev) u16 eeprom; u8 value; - rt2800_bbp_read(rt2x00dev, 138, &value); + value = rt2800_bbp_read(rt2x00dev, 138); rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) value |= 0x20; @@ -5938,12 +5931,12 @@ static void rt2800_init_bbp_3290(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 155, 0x3b); rt2800_bbp_write(rt2x00dev, 253, 0x04); - rt2800_bbp_read(rt2x00dev, 47, &value); + value = rt2800_bbp_read(rt2x00dev, 47); rt2x00_set_field8(&value, BBP47_TSSI_ADC6, 1); rt2800_bbp_write(rt2x00dev, 47, value); /* Use 5-bit ADC for Acquisition and 8-bit ADC for data */ - rt2800_bbp_read(rt2x00dev, 3, &value); + value = rt2800_bbp_read(rt2x00dev, 3); rt2x00_set_field8(&value, BBP3_ADC_MODE_SWITCH, 1); rt2x00_set_field8(&value, BBP3_ADC_INIT_MODE, 1); rt2800_bbp_write(rt2x00dev, 3, value); @@ -6230,7 +6223,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */ } - rt2800_bbp_read(rt2x00dev, 152, &value); + value = rt2800_bbp_read(rt2x00dev, 152); if (ant == 0) rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1); else @@ -6248,7 +6241,7 @@ static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) rt2800_init_bbp_early(rt2x00dev); - rt2800_bbp_read(rt2x00dev, 105, &value); + value = rt2800_bbp_read(rt2x00dev, 105); rt2x00_set_field8(&value, BBP105_MLD, rt2x00dev->default_ant.rx_chain_num == 2); rt2800_bbp_write(rt2x00dev, 105, value); @@ -6291,7 +6284,7 @@ static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY); ant = (div_mode == 3) ? 1 : 0; - rt2800_bbp_read(rt2x00dev, 152, &value); + value = rt2800_bbp_read(rt2x00dev, 152); if (ant == 0) { /* Main antenna */ rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1); @@ -6302,7 +6295,7 @@ static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 152, value); if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C)) { - rt2800_bbp_read(rt2x00dev, 254, &value); + value = rt2800_bbp_read(rt2x00dev, 254); rt2x00_set_field8(&value, BBP254_BIT7, 1); rt2800_bbp_write(rt2x00dev, 254, value); } @@ -6328,11 +6321,10 @@ static void rt2800_bbp_dcoc_write(struct rt2x00_dev *rt2x00dev, rt2800_bbp_write(rt2x00dev, 159, value); } -static void rt2800_bbp_dcoc_read(struct rt2x00_dev *rt2x00dev, - const u8 reg, u8 *value) +static u8 rt2800_bbp_dcoc_read(struct rt2x00_dev *rt2x00dev, const u8 reg) { rt2800_bbp_write(rt2x00dev, 158, reg); - rt2800_bbp_read(rt2x00dev, 159, value); + return rt2800_bbp_read(rt2x00dev, 159); } static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev) @@ -6340,7 +6332,7 @@ static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev) u8 bbp; /* Apply Maximum Likelihood Detection (MLD) for 2 stream case */ - rt2800_bbp_read(rt2x00dev, 105, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 105); rt2x00_set_field8(&bbp, BBP105_MLD, rt2x00dev->default_ant.rx_chain_num == 2); rt2800_bbp_write(rt2x00dev, 105, bbp); @@ -6349,7 +6341,7 @@ static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev) rt2800_bbp4_mac_if_ctrl(rt2x00dev); /* Fix I/Q swap issue */ - rt2800_bbp_read(rt2x00dev, 1, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 1); bbp |= 0x04; rt2800_bbp_write(rt2x00dev, 1, bbp); @@ -6622,7 +6614,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40, rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); - rt2800_bbp_read(rt2x00dev, 4, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); rt2800_bbp_write(rt2x00dev, 4, bbp); @@ -6643,7 +6635,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40, rt2800_bbp_write(rt2x00dev, 25, 0x90); msleep(1); - rt2800_bbp_read(rt2x00dev, 55, &passband); + passband = rt2800_bbp_read(rt2x00dev, 55); if (passband) break; } @@ -6657,7 +6649,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40, rt2800_bbp_write(rt2x00dev, 25, 0x90); msleep(1); - rt2800_bbp_read(rt2x00dev, 55, &stopband); + stopband = rt2800_bbp_read(rt2x00dev, 55); if ((passband - stopband) <= filter_target) { rfcsr24++; @@ -6713,8 +6705,8 @@ static void rt2800_rx_filter_calibration(struct rt2x00_dev *rt2x00dev) /* * Save BBP 25 & 26 values for later use in channel switching (for 3052) */ - rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25); - rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26); + drv_data->bbp25 = rt2800_bbp_read(rt2x00dev, 25); + drv_data->bbp26 = rt2800_bbp_read(rt2x00dev, 26); /* * Set back to initial state @@ -6728,7 +6720,7 @@ static void rt2800_rx_filter_calibration(struct rt2x00_dev *rt2x00dev) /* * Set BBP back to BW20 */ - rt2800_bbp_read(rt2x00dev, 4, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); rt2800_bbp_write(rt2x00dev, 4, bbp); } @@ -6760,7 +6752,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3090)) { /* Turn off unused DAC1 and ADC1 to reduce power consumption */ - rt2800_bbp_read(rt2x00dev, 138, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 138); rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0); @@ -6846,7 +6838,7 @@ static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev) u16 eeprom; /* Turn off unused DAC1 and ADC1 to reduce power consumption */ - rt2800_bbp_read(rt2x00dev, 138, ®); + reg = rt2800_bbp_read(rt2x00dev, 138); rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) rt2x00_set_field8(®, BBP138_RX_ADC1, 0); @@ -7253,7 +7245,7 @@ static void rt3593_post_bbp_init(struct rt2x00_dev *rt2x00dev) u8 bbp; bool txbf_enabled = false; /* FIXME */ - rt2800_bbp_read(rt2x00dev, 105, &bbp); + bbp = rt2800_bbp_read(rt2x00dev, 105); if (rt2x00dev->default_ant.rx_chain_num == 1) rt2x00_set_field8(&bbp, BBP105_MLD, 0); else @@ -7367,8 +7359,8 @@ static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev) drv_data->calibration_bw40 = 0x2f; /* Save BBP 25 & 26 values for later use in channel switching */ - rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25); - rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26); + drv_data->bbp25 = rt2800_bbp_read(rt2x00dev, 25); + drv_data->bbp26 = rt2800_bbp_read(rt2x00dev, 26); rt2800_led_open_drain_enable(rt2x00dev); rt2800_normal_mode_setup_3593(rt2x00dev); @@ -7662,19 +7654,19 @@ static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, { u8 bbp_val; - rt2800_bbp_read(rt2x00dev, 21, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 21); bbp_val |= 0x1; rt2800_bbp_write(rt2x00dev, 21, bbp_val); usleep_range(100, 200); if (set_bw) { - rt2800_bbp_read(rt2x00dev, 4, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp_val, BBP4_BANDWIDTH, 2 * is_ht40); rt2800_bbp_write(rt2x00dev, 4, bbp_val); usleep_range(100, 200); } - rt2800_bbp_read(rt2x00dev, 21, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 21); bbp_val &= (~0x1); rt2800_bbp_write(rt2x00dev, 21, bbp_val); usleep_range(100, 200); @@ -7736,14 +7728,14 @@ static char rt2800_lp_tx_filter_bw_cal(struct rt2x00_dev *rt2x00dev) cnt = 0; do { usleep_range(500, 2000); - rt2800_bbp_read(rt2x00dev, 159, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 159); if (bbp_val == 0x02 || cnt == 20) break; cnt++; } while (cnt < 20); - rt2800_bbp_dcoc_read(rt2x00dev, 0x39, &bbp_val); + bbp_val = rt2800_bbp_dcoc_read(rt2x00dev, 0x39); cal_val = bbp_val & 0x7F; if (cal_val >= 0x40) cal_val -= 128; @@ -7776,10 +7768,10 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, MAC_RF_BYPASS0 = rt2800_register_read(rt2x00dev, RF_BYPASS0); /* save BBP registers */ - rt2800_bbp_read(rt2x00dev, 23, &savebbpr23); + savebbpr23 = rt2800_bbp_read(rt2x00dev, 23); - rt2800_bbp_dcoc_read(rt2x00dev, 0, &savebbp159r0); - rt2800_bbp_dcoc_read(rt2x00dev, 2, &savebbp159r2); + savebbp159r0 = rt2800_bbp_dcoc_read(rt2x00dev, 0); + savebbp159r2 = rt2800_bbp_dcoc_read(rt2x00dev, 2); /* Save RF registers */ saverfb5r00 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0); @@ -7832,7 +7824,7 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write_bank(rt2x00dev, 5, 0, rf_val); /* I-3 */ - rt2800_bbp_read(rt2x00dev, 23, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 23); bbp_val &= (~0x1F); bbp_val |= 0x10; rt2800_bbp_write(rt2x00dev, 23, bbp_val); @@ -7885,7 +7877,7 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, usleep_range(1000, 2000); - rt2800_bbp_dcoc_read(rt2x00dev, 2, &bbp_val); + bbp_val = rt2800_bbp_dcoc_read(rt2x00dev, 2); bbp_val &= (~0x6); rt2800_bbp_dcoc_write(rt2x00dev, 2, bbp_val); @@ -7893,7 +7885,7 @@ static void rt2800_bw_filter_calibration(struct rt2x00_dev *rt2x00dev, cal_r32_init = rt2800_lp_tx_filter_bw_cal(rt2x00dev); - rt2800_bbp_dcoc_read(rt2x00dev, 2, &bbp_val); + bbp_val = rt2800_bbp_dcoc_read(rt2x00dev, 2); bbp_val |= 0x6; rt2800_bbp_dcoc_write(rt2x00dev, 2, bbp_val); do_cal: @@ -7991,7 +7983,7 @@ do_cal: rt2800_bbp_dcoc_write(rt2x00dev, 0, savebbp159r0); rt2800_bbp_dcoc_write(rt2x00dev, 2, savebbp159r2); - rt2800_bbp_read(rt2x00dev, 4, &bbp_val); + bbp_val = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp_val, BBP4_BANDWIDTH, 2 * test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)); rt2800_bbp_write(rt2x00dev, 4, bbp_val); diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index f2864407eb6c..bd6ed943af3d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -86,10 +86,11 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -112,9 +113,11 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); + value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, @@ -202,15 +205,6 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -static u8 _rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) -{ - u8 value; - - rt61pci_bbp_read(rt2x00dev, word, &value); - - return value; -} - static const struct rt2x00debug rt61pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { @@ -229,7 +223,7 @@ static const struct rt2x00debug rt61pci_rt2x00debug = { .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = _rt61pci_bbp_read, + .read = rt61pci_bbp_read, .write = rt61pci_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), @@ -639,9 +633,9 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, u8 r4; u8 r77; - rt61pci_bbp_read(rt2x00dev, 3, &r3); - rt61pci_bbp_read(rt2x00dev, 4, &r4); - rt61pci_bbp_read(rt2x00dev, 77, &r77); + r3 = rt61pci_bbp_read(rt2x00dev, 3); + r4 = rt61pci_bbp_read(rt2x00dev, 4); + r77 = rt61pci_bbp_read(rt2x00dev, 77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325)); @@ -685,9 +679,9 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, u8 r4; u8 r77; - rt61pci_bbp_read(rt2x00dev, 3, &r3); - rt61pci_bbp_read(rt2x00dev, 4, &r4); - rt61pci_bbp_read(rt2x00dev, 77, &r77); + r3 = rt61pci_bbp_read(rt2x00dev, 3); + r4 = rt61pci_bbp_read(rt2x00dev, 4); + r77 = rt61pci_bbp_read(rt2x00dev, 77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, @@ -739,9 +733,9 @@ static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, u8 r4; u8 r77; - rt61pci_bbp_read(rt2x00dev, 3, &r3); - rt61pci_bbp_read(rt2x00dev, 4, &r4); - rt61pci_bbp_read(rt2x00dev, 77, &r77); + r3 = rt61pci_bbp_read(rt2x00dev, 3); + r4 = rt61pci_bbp_read(rt2x00dev, 4); + r77 = rt61pci_bbp_read(rt2x00dev, 77); /* * Configure the RX antenna. @@ -884,7 +878,7 @@ static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); - rt61pci_bbp_read(rt2x00dev, 3, &r3); + r3 = rt61pci_bbp_read(rt2x00dev, 3); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); rt61pci_bbp_write(rt2x00dev, 3, r3); @@ -1658,7 +1652,7 @@ static int rt61pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt61pci_bbp_read(rt2x00dev, 0, &value); + value = rt61pci_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index 5a64de7304f1..87742f370eea 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -84,10 +84,11 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static u8 rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { u32 reg; + u8 value; mutex_lock(&rt2x00dev->csr_mutex); @@ -110,9 +111,11 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, WAIT_FOR_BBP(rt2x00dev, ®); } - *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); + value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); + + return value; } static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, @@ -147,15 +150,6 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -static u8 _rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word) -{ - u8 value; - - rt73usb_bbp_read(rt2x00dev, word, &value); - - return value; -} - static const struct rt2x00debug rt73usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { @@ -174,7 +168,7 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = _rt73usb_bbp_read, + .read = rt73usb_bbp_read, .write = rt73usb_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), @@ -589,9 +583,9 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, u8 r77; u8 temp; - rt73usb_bbp_read(rt2x00dev, 3, &r3); - rt73usb_bbp_read(rt2x00dev, 4, &r4); - rt73usb_bbp_read(rt2x00dev, 77, &r77); + r3 = rt73usb_bbp_read(rt2x00dev, 3); + r4 = rt73usb_bbp_read(rt2x00dev, 4); + r77 = rt73usb_bbp_read(rt2x00dev, 77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); @@ -636,9 +630,9 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, u8 r4; u8 r77; - rt73usb_bbp_read(rt2x00dev, 3, &r3); - rt73usb_bbp_read(rt2x00dev, 4, &r4); - rt73usb_bbp_read(rt2x00dev, 77, &r77); + r3 = rt73usb_bbp_read(rt2x00dev, 3); + r4 = rt73usb_bbp_read(rt2x00dev, 4); + r77 = rt73usb_bbp_read(rt2x00dev, 77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, @@ -771,7 +765,7 @@ static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); - rt73usb_bbp_read(rt2x00dev, 3, &r3); + r3 = rt73usb_bbp_read(rt2x00dev, 3); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); rt73usb_bbp_write(rt2x00dev, 3, r3); @@ -1305,7 +1299,7 @@ static int rt73usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) u8 value; for (i = 0; i < REGISTER_USB_BUSY_COUNT; i++) { - rt73usb_bbp_read(rt2x00dev, 0, &value); + value = rt73usb_bbp_read(rt2x00dev, 0); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); -- cgit v1.2.3 From 38651683aa98399f2e08e7978b8df0a707051887 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:47:00 +0200 Subject: rt2x00: convert rt2x00_eeprom_read return type This is a semi-automated conversion to change rt2x00_eeprom_read() to return the register contents instead of passing them by value, resulting in much better object code. The majority of the patch was done using: sed -i 's:\(\(.*, .*\), &\(.*\));:\2 = \1);:' \ -i 's:= _\(rt2x00_eeprom_read\):= \1:' drivers/net/wireless/ralink/rt2x00/* Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 8 +++--- drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 16 ++++++------ drivers/net/wireless/ralink/rt2x00/rt2500usb.c | 34 +++++++++++++------------- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 6 ++--- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 10 ++------ drivers/net/wireless/ralink/rt2x00/rt61pci.c | 28 ++++++++++----------- drivers/net/wireless/ralink/rt2x00/rt73usb.c | 28 ++++++++++----------- 7 files changed, 62 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 0ab3d571aba4..73b919838a61 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -178,7 +178,7 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { - .read = _rt2x00_eeprom_read, + .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), @@ -950,7 +950,7 @@ static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) rt2400pci_bbp_write(rt2x00dev, 31, 0x00); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -1464,7 +1464,7 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_err(rt2x00dev, "Invalid EEPROM data detected\n"); return -EINVAL; @@ -1482,7 +1482,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index a4e2f7b8adf1..5fcee4855720 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -178,7 +178,7 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { - .read = _rt2x00_eeprom_read, + .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), @@ -1104,7 +1104,7 @@ static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev) rt2500pci_bbp_write(rt2x00dev, 62, 0x10); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -1590,7 +1590,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, @@ -1606,7 +1606,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0); @@ -1615,7 +1615,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, DEFAULT_RSSI_OFFSET); @@ -1636,7 +1636,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. @@ -1692,14 +1692,14 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Check if the BBP tuning should be enabled. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (!rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE)) __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); /* * Read the RSSI <-> dBm offset information. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET); rt2x00dev->rssi_offset = rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index 37c6684db4de..4497385a4fea 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -241,7 +241,7 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u16), }, .eeprom = { - .read = _rt2x00_eeprom_read, + .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), @@ -703,19 +703,19 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev, u16 eeprom; u16 value; - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24); value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R24_LOW); rt2500usb_bbp_write(rt2x00dev, 24, value); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25); value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R25_LOW); rt2500usb_bbp_write(rt2x00dev, 25, value); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61); value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R61_LOW); rt2500usb_bbp_write(rt2x00dev, 61, value); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC); value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER); rt2500usb_bbp_write(rt2x00dev, 17, value); @@ -949,7 +949,7 @@ static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev) rt2500usb_bbp_write(rt2x00dev, 75, 0xff); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -1339,7 +1339,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, @@ -1355,7 +1355,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0); @@ -1364,7 +1364,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI, DEFAULT_RSSI_OFFSET); @@ -1373,7 +1373,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_THRESHOLD, 45); rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE, word); @@ -1387,7 +1387,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) bbp = rt2500usb_bbp_read(rt2x00dev, 17); bbp -= 6; - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40); rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp); @@ -1398,7 +1398,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_LOW, 0x48); rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41); @@ -1406,7 +1406,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r17: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_LOW, 0x40); rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_HIGH, 0x80); @@ -1414,7 +1414,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r24: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_LOW, 0x40); rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_HIGH, 0x50); @@ -1422,7 +1422,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r25: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_LOW, 0x60); rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_HIGH, 0x6d); @@ -1442,7 +1442,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. @@ -1508,7 +1508,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read the RSSI <-> dBm offset information. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET); rt2x00dev->rssi_offset = rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 35c1206ed6ac..7998cc196ee4 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -416,7 +416,7 @@ static void rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev, unsigned int index; index = rt2800_eeprom_word_index(rt2x00dev, word); - rt2x00_eeprom_read(rt2x00dev, index, data); + *data = rt2x00_eeprom_read(rt2x00dev, index); } static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev, @@ -436,7 +436,7 @@ static void rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev, unsigned int index; index = rt2800_eeprom_word_index(rt2x00dev, array); - rt2x00_eeprom_read(rt2x00dev, index + offset, data); + *data = rt2x00_eeprom_read(rt2x00dev, index + offset); } static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) @@ -1244,7 +1244,7 @@ const struct rt2x00debug rt2800_rt2x00debug = { /* NOTE: The local EEPROM access functions can't * be used here, use the generic versions instead. */ - .read = _rt2x00_eeprom_read, + .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 36791f7ae2ce..1f38c338ca7a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1072,14 +1072,8 @@ static inline void *rt2x00_eeprom_addr(struct rt2x00_dev *rt2x00dev, return (void *)&rt2x00dev->eeprom[word]; } -static inline void rt2x00_eeprom_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u16 *data) -{ - *data = le16_to_cpu(rt2x00dev->eeprom[word]); -} - -static inline u16 _rt2x00_eeprom_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word) +static inline u16 rt2x00_eeprom_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word) { return le16_to_cpu(rt2x00dev->eeprom[word]); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index bd6ed943af3d..d5b8051466b4 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -216,7 +216,7 @@ static const struct rt2x00debug rt61pci_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { - .read = _rt2x00_eeprom_read, + .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), @@ -853,13 +853,13 @@ static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) lna_gain += 14; - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } else { if (rt2x00_has_cap_external_lna_a(rt2x00dev)) lna_gain += 14; - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); } @@ -1698,7 +1698,7 @@ static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) rt61pci_bbp_write(rt2x00dev, 107, 0x04); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -2417,7 +2417,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, @@ -2432,7 +2432,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0); rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0); @@ -2445,7 +2445,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_LED_LED_MODE, LED_MODE_DEFAULT); @@ -2453,7 +2453,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Led: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); @@ -2461,7 +2461,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); @@ -2477,7 +2477,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); @@ -2505,7 +2505,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. @@ -2552,7 +2552,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read frequency offset and RF programming sequence. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ)) __set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags); @@ -2561,7 +2561,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read external LNA informations. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); @@ -2592,7 +2592,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * switch to default led mode. */ #ifdef CONFIG_RT2X00_LIB_LEDS - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); value = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE); rt61pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index 87742f370eea..b736982c0126 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -161,7 +161,7 @@ static const struct rt2x00debug rt73usb_rt2x00debug = { .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { - .read = _rt2x00_eeprom_read, + .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, .word_base = EEPROM_BASE, .word_size = sizeof(u16), @@ -743,10 +743,10 @@ static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) lna_gain += 14; - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); } @@ -1346,7 +1346,7 @@ static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev) rt73usb_bbp_write(rt2x00dev, 107, 0x04); for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -1771,7 +1771,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, @@ -1786,14 +1786,14 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA, 0); rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_G, 0); rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_A, 0); @@ -1809,7 +1809,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Led: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0); @@ -1817,7 +1817,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0); @@ -1833,7 +1833,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word); } - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word); + word = rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0); rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0); @@ -1861,7 +1861,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA); /* * Identify RF chipset. @@ -1907,13 +1907,13 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read frequency offset. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ); rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); /* * Read external LNA informations. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) { __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); @@ -1924,7 +1924,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Store led settings, for correct led behaviour. */ #ifdef CONFIG_RT2X00_LIB_LEDS - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom); + eeprom = rt2x00_eeprom_read(rt2x00dev, EEPROM_LED); rt73usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); rt73usb_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); -- cgit v1.2.3 From 5c6a25855cbd057f361c51d98b763eef28175b0b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:47:01 +0200 Subject: rt2x00: convert rt2800_eeprom_read return type This is a semi-automated conversion to change rt2800_eeprom_read to return the register contents instead of passing them by value, resulting in much better object code. The majority of the patch was done using: sed -i 's:\(\(.*, .*\), &\(.*\));:\3 = \1);:' drivers/net/wireless/ralink/rt2x00/rt2800lib.c Some manual tweaking was required here to work around the line wraps. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 194 ++++++++++++------------- 1 file changed, 97 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 7998cc196ee4..5063169b7794 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -410,13 +410,13 @@ static void *rt2800_eeprom_addr(struct rt2x00_dev *rt2x00dev, return rt2x00_eeprom_addr(rt2x00dev, index); } -static void rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev, - const enum rt2800_eeprom_word word, u16 *data) +static u16 rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev, + const enum rt2800_eeprom_word word) { unsigned int index; index = rt2800_eeprom_word_index(rt2x00dev, word); - *data = rt2x00_eeprom_read(rt2x00dev, index); + return rt2x00_eeprom_read(rt2x00dev, index); } static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev, @@ -428,15 +428,14 @@ static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev, rt2x00_eeprom_write(rt2x00dev, index, data); } -static void rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev, - const enum rt2800_eeprom_word array, - unsigned int offset, - u16 *data) +static u16 rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev, + const enum rt2800_eeprom_word array, + unsigned int offset) { unsigned int index; index = rt2800_eeprom_word_index(rt2x00dev, array); - *data = rt2x00_eeprom_read(rt2x00dev, index + offset); + return rt2x00_eeprom_read(rt2x00dev, index + offset); } static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) @@ -848,16 +847,16 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2) u8 offset2; if (rt2x00dev->curr_band == NL80211_BAND_2GHZ) { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG); offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0); offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2); offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2); } else { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A); offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0); offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2); offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2); } @@ -1913,7 +1912,7 @@ static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev) led_r_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 0 : 3; if (led_g_mode != rt2x00_get_field32(reg, LED_CFG_G_LED_MODE) || led_r_mode != rt2x00_get_field32(reg, LED_CFG_R_LED_MODE)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ); led_ctrl = rt2x00_get_field16(eeprom, EEPROM_FREQ_LED_MODE); if (led_ctrl == 0 || led_ctrl > 0x40) { rt2x00_set_field32(®, LED_CFG_G_LED_MODE, led_g_mode); @@ -1988,8 +1987,8 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) rt2x00_rt(rt2x00dev, RT3090) || rt2x00_rt(rt2x00dev, RT3352) || rt2x00_rt(rt2x00dev, RT3390)) { - rt2800_eeprom_read(rt2x00dev, - EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, + EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY)) rt2800_set_ant_diversity(rt2x00dev, @@ -2032,28 +2031,28 @@ static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev, short lna_gain; if (libconf->rf.channel <= 14) { - rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_LNA); lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); } else if (libconf->rf.channel <= 64) { - rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_LNA); lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); } else if (libconf->rf.channel <= 128) { if (rt2x00_rt(rt2x00dev, RT3593)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2); lna_gain = rt2x00_get_field16(eeprom, EEPROM_EXT_LNA2_A1); } else { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2); lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); } } else { if (rt2x00_rt(rt2x00dev, RT3593)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2); lna_gain = rt2x00_get_field16(eeprom, EEPROM_EXT_LNA2_A2); } else { - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2); lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); } @@ -3361,11 +3360,11 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_ALC_CFG_0_LIMIT_0, max_power); rt2x00_set_field32(®, TX_ALC_CFG_0_LIMIT_1, max_power); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_INTERNAL_TX_ALC)) { /* init base power by eeprom target power */ - rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_INIT, - &target_power); + target_power = rt2800_eeprom_read(rt2x00dev, + EEPROM_TXPOWER_INIT); rt2x00_set_field32(®, TX_ALC_CFG_0_CH_INIT_0, target_power); rt2x00_set_field32(®, TX_ALC_CFG_0_CH_INIT_1, target_power); } @@ -3887,7 +3886,7 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) /* * First check if temperature compensation is supported. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (!rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC)) return 0; @@ -3900,62 +3899,62 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00 */ if (rt2x00dev->curr_band == NL80211_BAND_2GHZ) { - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1); tssi_bounds[0] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG1_MINUS4); tssi_bounds[1] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG1_MINUS3); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2); tssi_bounds[2] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG2_MINUS2); tssi_bounds[3] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG2_MINUS1); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3); tssi_bounds[4] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG3_REF); tssi_bounds[5] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG3_PLUS1); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4); tssi_bounds[6] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG4_PLUS2); tssi_bounds[7] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG4_PLUS3); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5); tssi_bounds[8] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG5_PLUS4); step = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_BG5_AGC_STEP); } else { - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1); tssi_bounds[0] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A1_MINUS4); tssi_bounds[1] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A1_MINUS3); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2); tssi_bounds[2] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A2_MINUS2); tssi_bounds[3] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A2_MINUS1); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3); tssi_bounds[4] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A3_REF); tssi_bounds[5] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A3_PLUS1); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4); tssi_bounds[6] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A4_PLUS2); tssi_bounds[7] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A4_PLUS3); - rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5); tssi_bounds[8] = rt2x00_get_field16(eeprom, EEPROM_TSSI_BOUND_A5_PLUS4); @@ -4001,7 +4000,7 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, u8 comp_type; int comp_value = 0; - rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA); /* * HT40 compensation not required. @@ -4079,13 +4078,13 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, * .11b data rate need add additional 4dbm * when calculating eirp txpower. */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - 1, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + 1); criterion = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); - rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, - &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER); if (band == NL80211_BAND_2GHZ) eirp_txpower_criterion = rt2x00_get_field16(eeprom, @@ -4154,8 +4153,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, offset += 8; /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset); /* CCK 1MBS,2MBS */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4202,8 +4201,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_0_EXT_OFDM12_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 1, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 1); /* OFDM 24MBS,36MBS */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4239,8 +4238,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_7_OFDM54_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 2, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 2); /* MCS 0,1 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4287,8 +4286,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_2_EXT_MCS6_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 3, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 3); /* MCS 7 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4335,8 +4334,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_3_EXT_MCS12_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 4, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 4); /* MCS 14 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4383,8 +4382,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_5_MCS18_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 5, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 5); /* MCS 20,21 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4420,8 +4419,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, TX_PWR_CFG_8_MCS23_CH2, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 6, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 6); /* STBC, MCS 0,1 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4464,8 +4463,8 @@ static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - offset + 7, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, + offset + 7); /* STBC, MCS 7 */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); @@ -4545,8 +4544,9 @@ static void rt2800_config_txpower_rt6352(struct rt2x00_dev *rt2x00dev, * board vendors expected when they populated the EEPROM... */ for (i = 0; i < 5; i++) { - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - i * 2, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + i * 2); data = eeprom; @@ -4562,8 +4562,9 @@ static void rt2800_config_txpower_rt6352(struct rt2x00_dev *rt2x00dev, gdata |= (t << 8); - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - (i * 2) + 1, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + (i * 2) + 1); t = eeprom & 0x3f; if (t == 32) @@ -4720,8 +4721,9 @@ static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, reg = rt2800_register_read(rt2x00dev, offset); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - i, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + i); is_rate_b = i ? 0 : 1; /* @@ -4769,8 +4771,9 @@ static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); /* read the next four txpower values */ - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE, - i + 1, &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_TXPOWER_BYRATE, + i + 1); is_rate_b = 0; /* @@ -5247,8 +5250,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) || rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, - &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST)) rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000002c); @@ -5283,8 +5285,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); if (rt2x00_rt_rev_lt(rt2x00dev, RT3593, REV_RT3593E)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, - &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST)) rt2800_register_write(rt2x00dev, TX_SW_CFG2, @@ -5748,7 +5749,7 @@ static void rt2800_disable_unused_dac_adc(struct rt2x00_dev *rt2x00dev) u8 value; value = rt2800_bbp_read(rt2x00dev, 138); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) value |= 0x20; if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) @@ -6195,7 +6196,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) rt2800_disable_unused_dac_adc(rt2x00dev); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY); ant = (div_mode == 3) ? 1 : 0; @@ -6281,7 +6282,7 @@ static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) rt2800_bbp4_mac_if_ctrl(rt2x00dev); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY); ant = (div_mode == 3) ? 1 : 0; value = rt2800_bbp_read(rt2x00dev, 152); @@ -6581,8 +6582,8 @@ static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) } for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_BBP_START, i, - &eeprom); + eeprom = rt2800_eeprom_read_from_array(rt2x00dev, + EEPROM_BBP_START, i); if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); @@ -6753,7 +6754,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3090)) { /* Turn off unused DAC1 and ADC1 to reduce power consumption */ bbp = rt2800_bbp_read(rt2x00dev, 138); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) @@ -6839,7 +6840,7 @@ static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev) /* Turn off unused DAC1 and ADC1 to reduce power consumption */ reg = rt2800_bbp_read(rt2x00dev, 138); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) rt2x00_set_field8(®, BBP138_RX_ADC1, 0); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) @@ -6945,8 +6946,7 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1); if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, - &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST)) rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 3); else @@ -8379,15 +8379,15 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize LED control */ - rt2800_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF); rt2800_mcu_request(rt2x00dev, MCU_LED_AG_CONF, 0xff, word & 0xff, (word >> 8) & 0xff); - rt2800_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF); rt2800_mcu_request(rt2x00dev, MCU_LED_ACT_CONF, 0xff, word & 0xff, (word >> 8) & 0xff); - rt2800_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY); rt2800_mcu_request(rt2x00dev, MCU_LED_LED_POLARITY, 0xff, word & 0xff, (word >> 8) & 0xff); @@ -8490,7 +8490,7 @@ static u8 rt2800_get_txmixer_gain_24g(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3593)) return 0; - rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG); if ((word & 0x00ff) != 0x00ff) return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_BG_VAL); @@ -8504,7 +8504,7 @@ static u8 rt2800_get_txmixer_gain_5g(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3593)) return 0; - rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A); if ((word & 0x00ff) != 0x00ff) return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_A_VAL); @@ -8532,7 +8532,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) mac = rt2800_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); rt2x00lib_set_mac_address(rt2x00dev, mac); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2); rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1); @@ -8549,7 +8549,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word); } - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_NIC_CONF1_HW_RADIO, 0); rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC, 0); @@ -8570,7 +8570,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word); } - rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ); if ((word & 0x00ff) == 0x00ff) { rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); rt2800_eeprom_write(rt2x00dev, EEPROM_FREQ, word); @@ -8592,10 +8592,10 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) * lna0 as correct value. Note that EEPROM_LNA * is never validated. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_LNA); default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) @@ -8604,7 +8604,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) drv_data->txmixer_gain_24g = rt2800_get_txmixer_gain_24g(rt2x00dev); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); if (!rt2x00_rt(rt2x00dev, RT3593)) { @@ -8617,14 +8617,14 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) drv_data->txmixer_gain_5g = rt2800_get_txmixer_gain_5g(rt2x00dev); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); - rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2); if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); if (!rt2x00_rt(rt2x00dev, RT3593)) { @@ -8636,7 +8636,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); if (rt2x00_rt(rt2x00dev, RT3593)) { - rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &word); + word = rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2); if (rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0x00 || rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0xff) rt2x00_set_field16(&word, EEPROM_EXT_LNA2_A1, @@ -8660,7 +8660,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read EEPROM word for configuration. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0); /* * Identify RF chipset by EEPROM value @@ -8671,7 +8671,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392) || rt2x00_rt(rt2x00dev, RT6352)) - rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf); + rf = rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID); else if (rt2x00_rt(rt2x00dev, RT3352)) rf = RF3322; else if (rt2x00_rt(rt2x00dev, RT5350)) @@ -8720,7 +8720,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00dev->default_ant.rx_chain_num = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH); - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_rt(rt2x00dev, RT3070) || rt2x00_rt(rt2x00dev, RT3090) || @@ -8774,7 +8774,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Read frequency offset and RF programming sequence. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ); rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); /* @@ -8791,7 +8791,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Check if support EIRP tx power limit feature. */ - rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER); if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) < EIRP_MAX_TX_POWER_LIMIT) @@ -8800,7 +8800,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Detect if device uses internal or external PA */ - rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); + eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); if (rt2x00_rt(rt2x00dev, RT3352)) { if (rt2x00_get_field16(eeprom, -- cgit v1.2.3 From b9b238726716bed2ba2f3c1cd755e2e5340dc6ef Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 17 May 2017 16:47:02 +0200 Subject: rt2x00: convert rt2x00_desc_read return type This is a semi-automated conversion to change rt2x00_desc_read to return the register contents instead of passing them by value, resulting in much better object code. The majority of the patch was done using: sed -i 's:\(\(.*, .*\), &\(.*\));:\2 = \1);:' \ -i 's:\(\<_rt2x00_desc_read\>(.*, .*\), &\(.*\));:\2 = \1);:' \ drivers/net/wireless/ralink/rt2x00/rt* Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2400pci.c | 32 +++++++++++----------- drivers/net/wireless/ralink/rt2x00/rt2500pci.c | 26 +++++++++--------- drivers/net/wireless/ralink/rt2x00/rt2500usb.c | 14 +++++----- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 12 ++++----- drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 14 +++++----- drivers/net/wireless/ralink/rt2x00/rt2800usb.c | 8 +++--- drivers/net/wireless/ralink/rt2x00/rt2x00queue.h | 12 +++------ drivers/net/wireless/ralink/rt2x00/rt61pci.c | 34 ++++++++++++------------ drivers/net/wireless/ralink/rt2x00/rt73usb.c | 18 ++++++------- 9 files changed, 83 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 73b919838a61..0bc8b0249c57 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -728,11 +728,11 @@ static bool rt2400pci_get_entry_state(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || rt2x00_get_field32(word, TXD_W0_VALID)); @@ -746,19 +746,19 @@ static void rt2400pci_clear_entry(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 2, &word); + word = rt2x00_desc_read(entry_priv->desc, 2); rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); rt2x00_desc_write(entry_priv->desc, 2, word); - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); rt2x00_desc_write(entry_priv->desc, 0, word); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); rt2x00_desc_write(entry_priv->desc, 0, word); @@ -1113,16 +1113,16 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, txdesc->length); rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, txdesc->length); rt2x00_desc_write(txd, 2, word); - rt2x00_desc_read(txd, 3, &word); + word = rt2x00_desc_read(txd, 3); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1); @@ -1131,7 +1131,7 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1); rt2x00_desc_write(txd, 3, word); - rt2x00_desc_read(txd, 4, &word); + word = rt2x00_desc_read(txd, 4); rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, txdesc->u.plcp.length_low); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8); @@ -1147,7 +1147,7 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry, * the device, whereby the device may take hold of the TXD before we * finished updating it. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, @@ -1228,10 +1228,10 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, u32 rx_low; u32 rx_high; - rt2x00_desc_read(entry_priv->desc, 0, &word0); - rt2x00_desc_read(entry_priv->desc, 2, &word2); - rt2x00_desc_read(entry_priv->desc, 3, &word3); - rt2x00_desc_read(entry_priv->desc, 4, &word4); + word0 = rt2x00_desc_read(entry_priv->desc, 0); + word2 = rt2x00_desc_read(entry_priv->desc, 2); + word3 = rt2x00_desc_read(entry_priv->desc, 3); + word4 = rt2x00_desc_read(entry_priv->desc, 4); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1285,7 +1285,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); entry_priv = entry->priv_data; - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index 5fcee4855720..1ff5434798ec 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -817,11 +817,11 @@ static bool rt2500pci_get_entry_state(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || rt2x00_get_field32(word, TXD_W0_VALID)); @@ -835,15 +835,15 @@ static void rt2500pci_clear_entry(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(entry_priv->desc, 1, word); - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); rt2x00_desc_write(entry_priv->desc, 0, word); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); rt2x00_desc_write(entry_priv->desc, 0, word); @@ -1266,18 +1266,18 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W2_AIFS, entry->queue->aifs); rt2x00_set_field32(&word, TXD_W2_CWMIN, entry->queue->cw_min); rt2x00_set_field32(&word, TXD_W2_CWMAX, entry->queue->cw_max); rt2x00_desc_write(txd, 2, word); - rt2x00_desc_read(txd, 3, &word); + word = rt2x00_desc_read(txd, 3); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->u.plcp.service); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, @@ -1286,7 +1286,7 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry, txdesc->u.plcp.length_high); rt2x00_desc_write(txd, 3, word); - rt2x00_desc_read(txd, 10, &word); + word = rt2x00_desc_read(txd, 10); rt2x00_set_field32(&word, TXD_W10_RTS, test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); rt2x00_desc_write(txd, 10, word); @@ -1296,7 +1296,7 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry, * the device, whereby the device may take hold of the TXD before we * finished updating it. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, @@ -1371,8 +1371,8 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, u32 word0; u32 word2; - rt2x00_desc_read(entry_priv->desc, 0, &word0); - rt2x00_desc_read(entry_priv->desc, 2, &word2); + word0 = rt2x00_desc_read(entry_priv->desc, 0); + word2 = rt2x00_desc_read(entry_priv->desc, 2); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1413,7 +1413,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); entry_priv = entry->priv_data; - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index 4497385a4fea..529e05999abb 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -1074,7 +1074,7 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); @@ -1092,14 +1092,14 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx); rt2x00_desc_write(txd, 0, word); - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); rt2x00_set_field32(&word, TXD_W1_AIFS, entry->queue->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, @@ -1247,8 +1247,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, /* * It is now safe to read the descriptor on all architectures. */ - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 1, &word1); + word0 = rt2x00_desc_read(rxd, 0); + word1 = rt2x00_desc_read(rxd, 1); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1260,8 +1260,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY; if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); - _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->iv[0] = _rt2x00_desc_read(rxd, 2); + rxdesc->iv[1] = _rt2x00_desc_read(rxd, 3); rxdesc->dev_flags |= RXDONE_CRYPTO_IV; /* ICV is located at the end of frame */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 5063169b7794..6e2e760d98b1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -785,7 +785,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, /* * Initialize TX Info descriptor */ - rt2x00_desc_read(txwi, 0, &word); + word = rt2x00_desc_read(txwi, 0); rt2x00_set_field32(&word, TXWI_W0_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, @@ -807,7 +807,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode); rt2x00_desc_write(txwi, 0, word); - rt2x00_desc_read(txwi, 1, &word); + word = rt2x00_desc_read(txwi, 1); rt2x00_set_field32(&word, TXWI_W1_ACK, test_bit(ENTRY_TXD_ACK, &txdesc->flags)); rt2x00_set_field32(&word, TXWI_W1_NSEQ, @@ -885,12 +885,12 @@ void rt2800_process_rxwi(struct queue_entry *entry, __le32 *rxwi = (__le32 *) entry->skb->data; u32 word; - rt2x00_desc_read(rxwi, 0, &word); + word = rt2x00_desc_read(rxwi, 0); rxdesc->cipher = rt2x00_get_field32(word, RXWI_W0_UDF); rxdesc->size = rt2x00_get_field32(word, RXWI_W0_MPDU_TOTAL_BYTE_COUNT); - rt2x00_desc_read(rxwi, 1, &word); + word = rt2x00_desc_read(rxwi, 1); if (rt2x00_get_field32(word, RXWI_W1_SHORT_GI)) rxdesc->enc_flags |= RX_ENC_FLAG_SHORT_GI; @@ -911,7 +911,7 @@ void rt2800_process_rxwi(struct queue_entry *entry, if (rxdesc->rate_mode == RATE_MODE_CCK) rxdesc->signal &= ~0x8; - rt2x00_desc_read(rxwi, 2, &word); + word = rt2x00_desc_read(rxwi, 2); /* * Convert descriptor AGC value to RSSI value. @@ -972,7 +972,7 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, * Obtain the status about this packet. */ txdesc.flags = 0; - rt2x00_desc_read(txwi, 0, &word); + word = rt2x00_desc_read(txwi, 0); mcs = rt2x00_get_field32(word, TXWI_W0_MCS); ampdu = rt2x00_get_field32(word, TXWI_W0_AMPDU); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c index 70ad20691bff..ee5276e233fa 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c @@ -109,7 +109,7 @@ void rt2800mmio_fill_rxdone(struct queue_entry *entry, __le32 *rxd = entry_priv->desc; u32 word; - rt2x00_desc_read(rxd, 3, &word); + word = rt2x00_desc_read(rxd, 3); if (rt2x00_get_field32(word, RXD_W3_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -175,7 +175,7 @@ static bool rt2800mmio_txdone_entry_check(struct queue_entry *entry, u32 status) wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID); txwi = rt2800_drv_get_txwi(entry); - rt2x00_desc_read(txwi, 1, &word); + word = rt2x00_desc_read(txwi, 1); tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); return (tx_wcid == wcid); @@ -696,11 +696,11 @@ bool rt2800mmio_get_entry_state(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); return (!rt2x00_get_field32(word, RXD_W1_DMA_DONE)); } else { - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); return (!rt2x00_get_field32(word, TXD_W1_DMA_DONE)); } @@ -715,11 +715,11 @@ void rt2800mmio_clear_entry(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, RXD_W0_SDP0, skbdesc->skb_dma); rt2x00_desc_write(entry_priv->desc, 0, word); - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0); rt2x00_desc_write(entry_priv->desc, 1, word); @@ -730,7 +730,7 @@ void rt2800mmio_clear_entry(struct queue_entry *entry) rt2x00mmio_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx); } else { - rt2x00_desc_read(entry_priv->desc, 1, &word); + word = rt2x00_desc_read(entry_priv->desc, 1); rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1); rt2x00_desc_write(entry_priv->desc, 1, word); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index 75555f806905..04a7debddb64 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -456,7 +456,7 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry, /* * Initialize TXINFO descriptor */ - rt2x00_desc_read(txi, 0, &word); + word = rt2x00_desc_read(txi, 0); /* * The size of TXINFO_W0_USB_DMA_TX_PKT_LEN is @@ -527,7 +527,7 @@ static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) */ txwi = rt2800usb_get_txwi(entry); - rt2x00_desc_read(txwi, 1, &word); + word = rt2x00_desc_read(txwi, 1); tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); @@ -652,7 +652,7 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, * | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad | * |<------------ rx_pkt_len -------------->| */ - rt2x00_desc_read(rxi, 0, &word); + word = rt2x00_desc_read(rxi, 0); rx_pkt_len = rt2x00_get_field32(word, RXINFO_W0_USB_DMA_RX_PKT_LEN); /* @@ -676,7 +676,7 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, /* * It is now safe to read the descriptor on all architectures. */ - rt2x00_desc_read(rxd, 0, &word); + word = rt2x00_desc_read(rxd, 0); if (rt2x00_get_field32(word, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h index 6055f36211b9..a15bae29917b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h @@ -642,11 +642,10 @@ static inline int rt2x00queue_dma_timeout(struct queue_entry *entry) * _rt2x00_desc_read - Read a word from the hardware descriptor. * @desc: Base descriptor address * @word: Word index from where the descriptor should be read. - * @value: Address where the descriptor value should be written into. */ -static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value) +static inline __le32 _rt2x00_desc_read(__le32 *desc, const u8 word) { - *value = desc[word]; + return desc[word]; } /** @@ -654,13 +653,10 @@ static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value) * function will take care of the byte ordering. * @desc: Base descriptor address * @word: Word index from where the descriptor should be read. - * @value: Address where the descriptor value should be written into. */ -static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value) +static inline u32 rt2x00_desc_read(__le32 *desc, const u8 word) { - __le32 tmp; - _rt2x00_desc_read(desc, word, &tmp); - *value = le32_to_cpu(tmp); + return le32_to_cpu(_rt2x00_desc_read(desc, word)); } /** diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index d5b8051466b4..234310200759 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -1386,11 +1386,11 @@ static bool rt61pci_get_entry_state(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || rt2x00_get_field32(word, TXD_W0_VALID)); @@ -1404,16 +1404,16 @@ static void rt61pci_clear_entry(struct queue_entry *entry) u32 word; if (entry->queue->qid == QID_RX) { - rt2x00_desc_read(entry_priv->desc, 5, &word); + word = rt2x00_desc_read(entry_priv->desc, 5); rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(entry_priv->desc, 5, word); - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); rt2x00_desc_write(entry_priv->desc, 0, word); } else { - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); rt2x00_desc_write(entry_priv->desc, 0, word); @@ -1879,7 +1879,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid); rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); @@ -1890,7 +1890,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, @@ -1904,7 +1904,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } - rt2x00_desc_read(txd, 5, &word); + word = rt2x00_desc_read(txd, 5); rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx); rt2x00_set_field32(&word, TXD_W5_TX_POWER, @@ -1913,12 +1913,12 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, rt2x00_desc_write(txd, 5, word); if (entry->queue->qid != QID_BEACON) { - rt2x00_desc_read(txd, 6, &word); + word = rt2x00_desc_read(txd, 6); rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, skbdesc->skb_dma); rt2x00_desc_write(txd, 6, word); - rt2x00_desc_read(txd, 11, &word); + word = rt2x00_desc_read(txd, 11); rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, txdesc->length); rt2x00_desc_write(txd, 11, word); @@ -1929,7 +1929,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, * the device, whereby the device may take hold of the TXD before we * finished updating it. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, TXD_W0_VALID, 1); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, @@ -2095,8 +2095,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, u32 word0; u32 word1; - rt2x00_desc_read(entry_priv->desc, 0, &word0); - rt2x00_desc_read(entry_priv->desc, 1, &word1); + word0 = rt2x00_desc_read(entry_priv->desc, 0); + word1 = rt2x00_desc_read(entry_priv->desc, 1); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -2105,11 +2105,11 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]); - _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->iv[1]); + rxdesc->iv[0] = _rt2x00_desc_read(entry_priv->desc, 2); + rxdesc->iv[1] = _rt2x00_desc_read(entry_priv->desc, 3); rxdesc->dev_flags |= RXDONE_CRYPTO_IV; - _rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv); + rxdesc->icv = _rt2x00_desc_read(entry_priv->desc, 4); rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* @@ -2198,7 +2198,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) entry = &queue->entries[index]; entry_priv = entry->priv_data; - rt2x00_desc_read(entry_priv->desc, 0, &word); + word = rt2x00_desc_read(entry_priv->desc, 0); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(word, TXD_W0_VALID)) diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index b736982c0126..fd913222abd1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -1462,7 +1462,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, /* * Start writing the descriptor words. */ - rt2x00_desc_read(txd, 0, &word); + word = rt2x00_desc_read(txd, 0); rt2x00_set_field32(&word, TXD_W0_BURST, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_VALID, 1); @@ -1488,7 +1488,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); rt2x00_desc_write(txd, 0, word); - rt2x00_desc_read(txd, 1, &word); + word = rt2x00_desc_read(txd, 1); rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid); rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); @@ -1498,7 +1498,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = rt2x00_desc_read(txd, 2); rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, @@ -1512,7 +1512,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } - rt2x00_desc_read(txd, 5, &word); + word = rt2x00_desc_read(txd, 5); rt2x00_set_field32(&word, TXD_W5_TX_POWER, TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); @@ -1694,8 +1694,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, /* * It is now safe to read the descriptor on all architectures. */ - rt2x00_desc_read(rxd, 0, &word0); - rt2x00_desc_read(rxd, 1, &word1); + word0 = rt2x00_desc_read(rxd, 0); + word1 = rt2x00_desc_read(rxd, 1); if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; @@ -1704,11 +1704,11 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR); if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); - _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->iv[0] = _rt2x00_desc_read(rxd, 2); + rxdesc->iv[1] = _rt2x00_desc_read(rxd, 3); rxdesc->dev_flags |= RXDONE_CRYPTO_IV; - _rt2x00_desc_read(rxd, 4, &rxdesc->icv); + rxdesc->icv = _rt2x00_desc_read(rxd, 4); rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* -- cgit v1.2.3 From c6c092dcb21e4def00f2b5e077d03434c38acfe4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 17 May 2017 18:12:16 +0200 Subject: ssb: Delete an error message for a failed memory allocation in ssb_devices_register() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Acked-by: Michael Büsch Signed-off-by: Kalle Valo --- drivers/ssb/main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index d1a750760cf3..65420a9f0e82 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -480,7 +480,6 @@ static int ssb_devices_register(struct ssb_bus *bus) devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL); if (!devwrap) { - ssb_err("Could not allocate device\n"); err = -ENOMEM; goto error; } -- cgit v1.2.3 From 1a79ddaa903b44cdf442d6bc5e4878337132aa54 Mon Sep 17 00:00:00 2001 From: Tom Gaudasinski Date: Thu, 18 May 2017 19:27:50 +1000 Subject: rt2x00: Add device ID for Epson WN7512BEP Make Epson WN7512BEP work by adding its device-id to rt2800usb. Device contains a Ralink RT3071L, registers as vendor Accton/Arcadyan. Signed-off-by: Tom Gaudasinski Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index 04a7debddb64..685b8e0cd67d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -1156,6 +1156,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x2001, 0x3c17) }, /* Panasonic */ { USB_DEVICE(0x083a, 0xb511) }, + /* Accton/Arcadyan/Epson */ + { USB_DEVICE(0x083a, 0xb512) }, /* Philips */ { USB_DEVICE(0x0471, 0x20dd) }, /* Ralink */ -- cgit v1.2.3 From 96e3baadd01a1608287fe848b5889184e7791dab Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:28 -0500 Subject: rtlwifi: btcoex: 23b 1ant: Switch antenna to wifi or BT. Since wifi and BT share the same physical antenna, we should switch antenna to fit every situation. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 326 ++++++++++++--------- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 3 + 2 files changed, 198 insertions(+), 131 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index f3704d7db4d5..3ff0d55e8f22 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -751,14 +751,18 @@ static void halbtc8723b1ant_sw_mechanism(struct btc_coexist *btcoexist, } static void halbtc8723b1ant_set_ant_path(struct btc_coexist *btcoexist, - u8 ant_pos_type, bool init_hw_cfg, - bool wifi_off) + u8 ant_pos_type, bool force_exec, + bool init_hw_cfg, bool wifi_off) { + struct rtl_priv *rtlpriv = btcoexist->adapter; struct btc_board_info *board_info = &btcoexist->board_info; - u32 fw_ver = 0, u32tmp = 0; + u32 fw_ver = 0, u32tmp = 0, cnt_bt_cal_chk = 0; bool pg_ext_switch = false; bool use_ext_switch = false; - u8 h2c_parameter[2] = {0}; + bool is_in_mp_mode = false; + u8 h2c_parameter[2] = {0}, u8tmp = 0; + + coex_dm->cur_ant_pos_type = ant_pos_type; btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); /* [31:16] = fw ver, [15:0] = fw sub ver */ @@ -768,24 +772,103 @@ static void halbtc8723b1ant_set_ant_path(struct btc_coexist *btcoexist, use_ext_switch = true; if (init_hw_cfg) { - /*BT select s0/s1 is controlled by WiFi */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + /* WiFi TRx Mask on */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x780); + /* remove due to interrupt is disabled that polling c2h will + * fail and delay 100ms. + */ - /*Force GNT_BT to Normal */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); - } else if (wifi_off) { - /*Force GNT_BT to High */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); - /*BT select s0/s1 is controlled by BT */ + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + } else { + /* set grant_bt to high */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + } + /* set wlan_act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* BT select s0/s1 is controlled by BT */ btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x39, 0x8, 0x1); + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + } else if (wifi_off) { + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + } else { + /* set grant_bt to high */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + } + /* set wlan_act to always low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_IS_IN_MP_MODE, + &is_in_mp_mode); + if (!is_in_mp_mode) + /* BT select s0/s1 is controlled by BT */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x20, 0x0); + else + /* BT select s0/s1 is controlled by WiFi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x20, 0x1); - /* 0x4c[24:23] = 00, Set Antenna control by BT_RFE_CTRL - * BT Vendor 0xac = 0xf002 + /* 0x4c[24:23]=00, Set Antenna control by BT_RFE_CTRL + * BT Vendor 0xac=0xf002 */ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); u32tmp &= ~BIT23; u32tmp &= ~BIT24; btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } else { + /* Use H2C to set GNT_BT to LOW */ + if (fw_ver >= 0x180000) { + if (btcoexist->btc_read_1byte(btcoexist, 0x765) != 0) { + h2c_parameter[0] = 0; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + } + } else { + /* BT calibration check */ + while (cnt_bt_cal_chk <= 20) { + u8tmp = btcoexist->btc_read_1byte(btcoexist, + 0x49d); + cnt_bt_cal_chk++; + if (u8tmp & BIT(0)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], ########### BT is calibrating (wait cnt=%d) ###########\n", + cnt_bt_cal_chk); + mdelay(50); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, + DBG_LOUD, + "[BTCoex], ********** BT is NOT calibrating (wait cnt=%d)**********\n", + cnt_bt_cal_chk); + break; + } + } + + /* set grant_bt to PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x0); + } + + if (btcoexist->btc_read_1byte(btcoexist, 0x76e) != 0xc) { + /* set wlan_act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + } + + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x67, 0x20, + 0x1); /* BT select s0/s1 is controlled by WiFi */ } if (use_ext_switch) { @@ -798,155 +881,130 @@ static void halbtc8723b1ant_set_ant_path(struct btc_coexist *btcoexist, u32tmp |= BIT24; btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + /* fixed internal switch S1->WiFi, S0->BT */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { - /* Main Ant to BT for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x64, 0x1, - 0x1); - /* tell firmware "no antenna inverse" */ h2c_parameter[0] = 0; - h2c_parameter[1] = 1; /*ext switch type*/ + /* ext switch type */ + h2c_parameter[1] = 1; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); } else { - /* Aux Ant to BT for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x64, 0x1, - 0x0); - /* tell firmware "antenna inverse" */ h2c_parameter[0] = 1; - h2c_parameter[1] = 1; /* ext switch type */ + /* ext switch type */ + h2c_parameter[1] = 1; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); } } - /* fixed internal switch first - * fixed internal switch S1->WiFi, S0->BT - */ - if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); - else /* fixed internal switch S0->WiFi, S1->BT */ - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); - - /* ext switch setting */ - switch (ant_pos_type) { - case BTC_ANT_PATH_WIFI: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x1); - else - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x2); - break; - case BTC_ANT_PATH_BT: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x2); - else - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x1); - break; - default: - case BTC_ANT_PATH_PTA: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x1); - else - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x92c, 0x3, - 0x2); - break; + if (force_exec || + (coex_dm->cur_ant_pos_type != coex_dm->pre_ant_pos_type)) { + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x1); + else + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x2); + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x2); + else + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x1); + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x1); + else + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, 0x2); + break; + } } - } else { if (init_hw_cfg) { - /* 0x4c[23] = 1, 0x4c[24] = 0 Antenna control by 0x64 */ + /* 0x4c[23] = 1, 0x4c[24] = 0, + * Antenna control by 0x64 + */ u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); u32tmp |= BIT23; u32tmp &= ~BIT24; btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + /* Fix Ext switch Main->S1, Aux->S0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + 0x0); + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { - /* Main Ant to WiFi for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x64, 0x1, - 0x0); - /* tell firmware "no antenna inverse" */ h2c_parameter[0] = 0; - h2c_parameter[1] = 0; /* internal switch type */ + /* internal switch type */ + h2c_parameter[1] = 0; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); } else { - /* Aux Ant to BT for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, - 0x64, 0x1, - 0x1); - /* tell firmware "antenna inverse" */ h2c_parameter[0] = 1; - h2c_parameter[1] = 0; /* internal switch type */ + /* internal switch type */ + h2c_parameter[1] = 0; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); } } - /* fixed external switch first - * Main->WiFi, Aux->BT - */ - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, - 0x3, 0x1); - else /* Main->BT, Aux->WiFi */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, - 0x3, 0x2); - - /* internal switch setting */ - switch (ant_pos_type) { - case BTC_ANT_PATH_WIFI: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x0); - else - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x280); - break; - case BTC_ANT_PATH_BT: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x280); - else - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x0); - break; - default: - case BTC_ANT_PATH_PTA: - if (board_info->btdm_ant_pos == - BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x200); - else - btcoexist->btc_write_2byte(btcoexist, 0x948, - 0x80); - break; + if (force_exec || + (coex_dm->cur_ant_pos_type != coex_dm->pre_ant_pos_type)) { + /* internal switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x0); + else + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x280); + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x280); + else + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x0); + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x200); + else + btcoexist->btc_write_4byte(btcoexist, + 0x948, 0x80); + break; + } } } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; } static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, @@ -1146,6 +1204,7 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, 0x0, 0x0, 0x0); halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); break; case 0: @@ -1155,6 +1214,7 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, 0x0, 0x0, 0x0); halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, false); break; case 9: @@ -1163,6 +1223,7 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, 0x0, 0x0, 0x0); halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, false, false); break; } @@ -1429,7 +1490,8 @@ static void halbtc8723b1ant_action_wifi_only(struct btc_coexist *btcoexist) { halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); - halbtc8723b1ant_set_ant_path(btcoexist, false, false, BTC_ANT_PATH_PTA); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); } /* check if BT is disabled */ @@ -2004,7 +2066,8 @@ static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist, btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); /* Antenna config */ - halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, true, false); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, FORCE_EXEC, + true, false); /* PTA parameter */ halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); } @@ -2323,7 +2386,7 @@ void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) coex_sta->under_ips = true; halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, - false, true); + FORCE_EXEC, false, true); /* set PTA control */ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); halbtc8723b1ant_coex_table_with_type(btcoexist, @@ -2728,7 +2791,8 @@ void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) btcoexist->stop_coex_dm = true; - halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, true); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, FORCE_EXEC, + false, true); halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); @@ -2749,8 +2813,8 @@ void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify to SLEEP\n"); btcoexist->stop_coex_dm = true; - halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, - true); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index d502a31812ab..da99addc8474 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -82,6 +82,9 @@ enum _BT_8723B_1ANT_COEX_ALGO { }; struct coex_dm_8723b_1ant { + /* hw setting */ + u8 pre_ant_pos_type; + u8 cur_ant_pos_type; /* fw mechanism */ bool cur_ignore_wlan_act; bool pre_ignore_wlan_act; -- cgit v1.2.3 From c01fd117e581193c0929ad70d6716be703b414e0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:29 -0500 Subject: rtlwifi: btcoex: 23b 1ant: need these information when scan Log the scan procedure, and update ap_num for future usage when scan done. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 30 ++++++++++++++++++++-- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 1 + 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 3ff0d55e8f22..cd7dd620c264 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2424,13 +2424,39 @@ void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; bool wifi_connected = false, bt_hs_on = false; + u8 u8tmpa, u8tmpb; + u32 u32tmp; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; bool bt_ctrl_agg_buf_size = false; u8 agg_buf_size = 5; - if (btcoexist->manual_control || btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (type == BTC_SCAN_START) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN START notify\n"); + /* Force antenna setup for no scan result issue */ + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", + u32tmp, u8tmpa, u8tmpb); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], SCAN FINISH notify\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + } + + if (coex_sta->bt_disabled) return; btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index da99addc8474..9909db880c26 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -163,6 +163,7 @@ struct coex_sta_8723b_1ant { bool c2h_bt_inquiry_page; u8 bt_retry_cnt; u8 bt_info_ext; + u8 scan_ap_num; bool cck_ever_lock; bool force_lps_on; u32 pop_event_cnt; -- cgit v1.2.3 From 0d4ae142262298c149ea60956bf108b6db011b58 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:30 -0500 Subject: rtlwifi: btcoex: 23b 1ant: adjust wifi duration for bt a2dp The larger the bt a2dp bit pool is, the more time bt needs to receive them. If we do not adjust the wifi duration, the voice quality will be low. Hence we reduce the time that wifi holds, to improve the a2dp service. If the bt is slave, it may receive a packet at any time, so we need to mark them as high priority packets in case of packet loss Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 326 +++++++++++++++------ .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 2 + 2 files changed, 246 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index cd7dd620c264..36fa9a27aa01 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1010,62 +1010,149 @@ static void halbtc8723b1ant_set_ant_path(struct btc_coexist *btcoexist, static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, bool turn_on, u8 type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool wifi_busy = false; u8 rssi_adjust_val = 0; + u8 ps_tdma_byte0_val = 0x51; + u8 ps_tdma_byte3_val = 0x10; + u8 ps_tdma_byte4_val = 0x50; + s8 wifi_duration_adjust = 0x0; + static bool pre_wifi_busy; coex_dm->cur_ps_tdma_on = turn_on; coex_dm->cur_ps_tdma = type; btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); - if (!force_exec) { - if (coex_dm->cur_ps_tdma_on) - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ******** TDMA(on, %d) *********\n", - coex_dm->cur_ps_tdma); - else - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ******** TDMA(off, %d) ********\n", - coex_dm->cur_ps_tdma); + if (wifi_busy != pre_wifi_busy) { + force_exec = true; + pre_wifi_busy = wifi_busy; + } + if (!force_exec) { if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) return; } + + if (coex_sta->scan_ap_num <= 5) { + wifi_duration_adjust = 5; + + if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + } else if (coex_sta->scan_ap_num >= 40) { + wifi_duration_adjust = -15; + + if (coex_sta->a2dp_bit_pool < 35) + wifi_duration_adjust = -5; + else if (coex_sta->a2dp_bit_pool < 45) + wifi_duration_adjust = -10; + } else if (coex_sta->scan_ap_num >= 20) { + wifi_duration_adjust = -10; + + if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + } else { + wifi_duration_adjust = 0; + + if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + } + + if ((type == 1) || (type == 2) || (type == 9) || (type == 11) || + (type == 101) || (type == 102) || (type == 109) || (type == 101)) { + if (!coex_sta->force_lps_on) { + /* Native power save TDMA, only for A2DP-only case + * 1/2/9/11 while wifi noisy threshold > 30 + */ + + /* no null-pkt */ + ps_tdma_byte0_val = 0x61; + /* no tx-pause at BT-slot */ + ps_tdma_byte3_val = 0x11; + /* 0x778 = d/1 toggle, no dynamic slot */ + ps_tdma_byte4_val = 0x10; + } else { + /* null-pkt */ + ps_tdma_byte0_val = 0x51; + /* tx-pause at BT-slot */ + ps_tdma_byte3_val = 0x10; + /* 0x778 = d/1 toggle, dynamic slot */ + ps_tdma_byte4_val = 0x50; + } + } else if ((type == 3) || (type == 13) || (type == 14) || + (type == 103) || (type == 113) || (type == 114)) { + /* null-pkt */ + ps_tdma_byte0_val = 0x51; + /* tx-pause at BT-slot */ + ps_tdma_byte3_val = 0x10; + /* 0x778 = d/1 toggle, no dynamic slot */ + ps_tdma_byte4_val = 0x10; + } else { /* native power save case */ + /* no null-pkt */ + ps_tdma_byte0_val = 0x61; + /* no tx-pause at BT-slot */ + ps_tdma_byte3_val = 0x11; + /* 0x778 = d/1 toggle, no dynamic slot */ + ps_tdma_byte4_val = 0x11; + /* psTdmaByte4Va is not define for 0x778 = d/1, 1/1 case */ + } + + /* if (bt_link_info->slave_role) */ + if ((bt_link_info->slave_role) && (bt_link_info->a2dp_exist)) + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + ps_tdma_byte4_val = ps_tdma_byte4_val | 0x1; + + if (type > 100) { + /* set antenna control by SW */ + ps_tdma_byte0_val = ps_tdma_byte0_val | 0x82; + /* set antenna no toggle, control by antenna diversity */ + ps_tdma_byte3_val = ps_tdma_byte3_val | 0x60; + } + if (turn_on) { switch (type) { default: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1a, - 0x1a, 0x0, 0x50); + 0x1a, 0x0, + ps_tdma_byte4_val); break; case 1: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x3a, - 0x03, 0x10, 0x50); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, + 0x3a + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); rssi_adjust_val = 11; break; case 2: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x2b, - 0x03, 0x10, 0x50); - rssi_adjust_val = 14; + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, + 0x2d + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 3: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1d, - 0x1d, 0x0, 0x52); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x30, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 4: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, - 0x3, 0x14, 0x0); - rssi_adjust_val = 17; + 0x3, 0x14, 0x0); break; case 5: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15, - 0x3, 0x11, 0x10); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x1f, 0x3, + ps_tdma_byte3_val, 0x11); break; case 6: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20, - 0x3, 0x11, 0x13); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x20, 0x3, + ps_tdma_byte3_val, 0x11); break; case 7: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc, @@ -1073,33 +1160,44 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, break; case 8: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, - 0x3, 0x10, 0x0); + 0x3, 0x10, 0x0); break; case 9: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21, - 0x3, 0x10, 0x50); - rssi_adjust_val = 18; + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 10: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, 0xa, 0x0, 0x40); break; case 11: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, - 0x03, 0x10, 0x50); - rssi_adjust_val = 20; + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 12: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x0a, - 0x0a, 0x0, 0x50); + 0x0a, 0x0, 0x50); break; case 13: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, - 0x15, 0x0, 0x50); + if (coex_sta->scan_ap_num <= 3) + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x40, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + else + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 14: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21, - 0x3, 0x10, 0x52); + if (coex_sta->scan_ap_num <= 3) + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, 0x51, 0x30, 0x3, 0x10, 0x50); + else + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 15: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, @@ -1107,97 +1205,166 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, break; case 16: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, - 0x3, 0x10, 0x0); - rssi_adjust_val = 18; + 0x3, 0x10, 0x0); break; case 18: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, - 0x3, 0x10, 0x0); - rssi_adjust_val = 14; + 0x3, 0x10, 0x0); break; case 20: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35, - 0x03, 0x11, 0x10); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x3f, 0x03, + ps_tdma_byte3_val, 0x10); break; case 21: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, - 0x03, 0x11, 0x11); + 0x03, 0x11, 0x11); break; case 22: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, - 0x03, 0x11, 0x10); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, 0x10); break; case 23: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, - 0x3, 0x31, 0x18); - rssi_adjust_val = 22; + 0x3, 0x31, 0x18); break; case 24: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, - 0x3, 0x31, 0x18); - rssi_adjust_val = 22; + 0x3, 0x31, 0x18); break; case 25: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); - rssi_adjust_val = 22; break; case 26: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); - rssi_adjust_val = 22; break; case 27: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, - 0x3, 0x31, 0x98); - rssi_adjust_val = 22; + 0x3, 0x31, 0x98); break; case 28: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x69, 0x25, - 0x3, 0x31, 0x0); + 0x3, 0x31, 0x0); break; case 29: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xab, 0x1a, - 0x1a, 0x1, 0x10); + 0x1a, 0x1, 0x10); break; case 30: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14, - 0x3, 0x10, 0x50); + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x30, + 0x3, 0x10, 0x10); break; case 31: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a, - 0x1a, 0, 0x58); + 0x1a, 0, 0x58); break; case 32: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa, - 0x3, 0x10, 0x0); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x35, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); break; case 33: - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25, - 0x3, 0x30, 0x90); + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x35, 0x3, + ps_tdma_byte3_val, 0x10); break; case 34: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x53, 0x1a, - 0x1a, 0x0, 0x10); + 0x1a, 0x0, 0x10); break; case 35: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x63, 0x1a, - 0x1a, 0x0, 0x10); + 0x1a, 0x0, 0x10); break; case 36: halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12, - 0x3, 0x14, 0x50); + 0x3, 0x14, 0x50); break; - /* SoftAP only with no sta associated, BT disable, - * TDMA mode for power saving - * here softap mode screen off will cost 70-80mA for phone - */ case 40: + /* SoftAP only with no sta associated,BT disable ,TDMA + * mode for power saving + * + * here softap mode screen off will cost 70-80mA for + * phone + */ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18, - 0x00, 0x10, 0x24); + 0x00, 0x10, 0x24); + break; + + case 101: + /* for 1-Ant translate to 2-Ant */ + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, + 0x3a + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 102: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, + 0x2d + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 103: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x3a, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 105: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x15, 0x3, + ps_tdma_byte3_val, 0x11); + break; + case 106: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x20, 0x3, + ps_tdma_byte3_val, 0x11); + break; + case 109: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 111: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 113: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 114: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 120: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x3f, 0x03, + ps_tdma_byte3_val, 0x10); + break; + case 122: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, 0x10); + break; + case 132: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 133: + halbtc8723b1ant_set_fw_ps_tdma( + btcoexist, ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, 0x11); break; } } else { + /* disable PS tdma */ switch (type) { case 8: /* PTA Control */ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x8, 0x0, @@ -1212,19 +1379,10 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, /* Software control, Antenna at BT side */ halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, 0x0, 0x0); - halbtc8723b1ant_set_ant_path(btcoexist, - BTC_ANT_PATH_BT, - FORCE_EXEC, - false, false); break; - case 9: - /* Software control, Antenna at WiFi side */ - halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, - 0x0, 0x0, 0x0); - halbtc8723b1ant_set_ant_path(btcoexist, - BTC_ANT_PATH_WIFI, - FORCE_EXEC, - false, false); + case 1: /* 2-Ant, 0x778=3, antenna control by ant diversity */ + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, 0x0, + 0x48, 0x0); break; } } @@ -1620,6 +1778,10 @@ static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy( { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + if ((coex_sta->low_priority_rx >= 950) && (!coex_sta->under_ips)) + bt_link_info->slave_role = true; + else + bt_link_info->slave_role = false; if (bt_link_info->hid_only) { /* HID */ btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, wifi_status); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 9909db880c26..557108494a87 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -180,6 +180,8 @@ struct coex_sta_8723b_1ant { bool cck_lock; bool pre_ccklock; + + u8 a2dp_bit_pool; }; /************************************************************************* -- cgit v1.2.3 From 8ffb5b6926875bf70c4d403a6cf96f7da65e6d74 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:31 -0500 Subject: rtlwifi: btcoex: 23b 1ant: add wifi_only argument to init_hwconfig In case of wifi_only, we can simply switch antenna to wifi. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 102 +++++++++------------ .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 4 +- 2 files changed, 47 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 36fa9a27aa01..71ce0fe886a3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2162,86 +2162,63 @@ static void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) /* sw all off */ halbtc8723b1ant_sw_mechanism(btcoexist, false); - halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); - halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); coex_sta->pop_event_cnt = 0; } static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist, - bool backup) + bool backup, bool wifi_only) { struct rtl_priv *rtlpriv = btcoexist->adapter; u32 u32tmp = 0; - u8 u8tmp = 0; - u32 cnt_bt_cal_chk = 0; + u8 u8tmpa = 0, u8tmpb = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], 1Ant Init HW Config!!\n"); - if (backup) {/* backup rf 0x1e value */ - coex_dm->backup_arfr_cnt1 = - btcoexist->btc_read_4byte(btcoexist, 0x430); - coex_dm->backup_arfr_cnt2 = - btcoexist->btc_read_4byte(btcoexist, 0x434); - coex_dm->backup_retry_limit = - btcoexist->btc_read_2byte(btcoexist, 0x42a); - coex_dm->backup_ampdu_max_time = - btcoexist->btc_read_1byte(btcoexist, 0x456); - } - - /* WiFi goto standby while GNT_BT 0-->1 */ - btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); - /* BT goto standby while GNT_BT 1-->0 */ - btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x500); - - btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); - btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); - - /* BT calibration check */ - while (cnt_bt_cal_chk <= 20) { - u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x49d); - cnt_bt_cal_chk++; - if (u32tmp & BIT0) { - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ########### BT calibration(cnt=%d) ###########\n", - cnt_bt_cal_chk); - mdelay(50); - } else { - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ********** BT NOT calibration (cnt=%d)**********\n", - cnt_bt_cal_chk); - break; - } - } + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = + (btcoexist->btc_read_1byte(btcoexist, 0xf1) & 0xf0) >> 4; + /* enable TBTT interrupt */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, 0x1); /* 0x790[5:0] = 0x5 */ - u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); - u8tmp &= 0xc0; - u8tmp |= 0x5; - btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); /* Enable counter statistics */ - /*0x76e[3] = 1, WLAN_Act control by PTA */ - btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + /* Antenna config */ - halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, FORCE_EXEC, - true, false); + if (wifi_only) + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, true, false); + else + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, true, false); + /* PTA parameter */ halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", + u32tmp, u8tmpa, u8tmpb); } /************************************************************** * extern function start with ex_halbtc8723b1ant_ **************************************************************/ -void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist) +void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, + bool wifi_only) { - halbtc8723b1ant_init_hw_config(btcoexist, true); - btcoexist->auto_report_1ant = true; + halbtc8723b1ant_init_hw_config(btcoexist, true, wifi_only); + btcoexist->stop_coex_dm = false; } void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) @@ -2558,7 +2535,7 @@ void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], IPS LEAVE notify\n"); coex_sta->under_ips = false; - halbtc8723b1ant_init_hw_config(btcoexist, false); + halbtc8723b1ant_init_hw_config(btcoexist, false, false); halbtc8723b1ant_init_coex_dm(btcoexist); halbtc8723b1ant_query_bt_info(btcoexist); } @@ -2989,6 +2966,8 @@ void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + btcoexist->stop_coex_dm = true; } void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) @@ -3000,18 +2979,27 @@ void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) if (BTC_WIFI_PNP_SLEEP == pnp_state) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify to SLEEP\n"); - btcoexist->stop_coex_dm = true; halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, FORCE_EXEC, false, true); halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + /* Driver do not leave IPS/LPS when driver is going to sleep, so + * BTCoexistence think wifi is still under IPS/LPS + * + * BT should clear UnderIPS/UnderLPS state to avoid mismatch + * state after wakeup. + */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + btcoexist->stop_coex_dm = true; } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify to WAKE UP\n"); btcoexist->stop_coex_dm = false; - halbtc8723b1ant_init_hw_config(btcoexist, false); + halbtc8723b1ant_init_hw_config(btcoexist, false, false); halbtc8723b1ant_init_coex_dm(btcoexist); halbtc8723b1ant_query_bt_info(btcoexist); } @@ -3024,9 +3012,7 @@ void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], *****************Coex DM Reset****************\n"); - halbtc8723b1ant_init_hw_config(btcoexist, false); - btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); - btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x0); + halbtc8723b1ant_init_hw_config(btcoexist, false, false); halbtc8723b1ant_init_coex_dm(btcoexist); } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 557108494a87..aadac2afc900 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -182,12 +182,14 @@ struct coex_sta_8723b_1ant { bool pre_ccklock; u8 a2dp_bit_pool; + u8 cut_version; }; /************************************************************************* * The following is interface which will notify coex module. *************************************************************************/ -void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, + bool wifi_only); void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist); void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); -- cgit v1.2.3 From f9c6ede79af346ac27cff8d867f4a19ea8d2931d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:32 -0500 Subject: rtlwifi: btcoex: 23b 1ant: Add power_on_setting This change is highly related to init_hwconfig that was decomposed into two parts for better program flow. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 69 ++++++++++++++++++++++ .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 1 + 2 files changed, 70 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 71ce0fe886a3..f565c9e7e17b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2213,6 +2213,75 @@ static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist, /************************************************************** * extern function start with ex_halbtc8723b1ant_ **************************************************************/ +void ex_halbtc8723b1ant_power_on_setting(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + u32 value; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "xxxxxxxxxxxxxxxx Execute 8723b 1-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + + btcoexist->stop_coex_dm = true; + + btcoexist->btc_write_1byte(btcoexist, 0x67, 0x20); + + /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT0 | BIT1); + + /* set GRAN_BT = 1 */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + /* set WLAN_ACT = 0 */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* S0 or S1 setting and Local register setting(By the setting fw can get + * ant number, S0/S1, ... info) + * + * Local setting bit define + * BIT0: "0" for no antenna inverse; "1" for antenna inverse + * BIT1: "0" for internal switch; "1" for external switch + * BIT2: "0" for one antenna; "1" for two antenna + * NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and + * BIT2 = 0 + */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + /* set to S1 */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x280); + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + value = 1; + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + u8tmp |= 0x1; /* antenna inverse */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + value = 0; + } + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + &value); + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x384, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, bool wifi_only) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index aadac2afc900..fd0620ef0987 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -188,6 +188,7 @@ struct coex_sta_8723b_1ant { /************************************************************************* * The following is interface which will notify coex module. *************************************************************************/ +void ex_halbtc8723b1ant_power_on_setting(struct btc_coexist *btcoexist); void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, bool wifi_only); void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist); -- cgit v1.2.3 From 7d0d2c14cc039823b3dcb22b2adc7e130d62f850 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:33 -0500 Subject: rtlwifi: btcoex: 23b 1ant: parse more BT information from C2H BT FW provide more BT status as clues, thus we also display them in coex log to help debug in field. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 98 +++++++++++++++++++--- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 5 ++ 2 files changed, 91 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index f565c9e7e17b..9509bf4a4635 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2887,12 +2887,48 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, coex_sta->bt_retry_cnt = /* [3:0] */ coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x20) + coex_sta->c2h_bt_remote_name_req = true; + else + coex_sta->c2h_bt_remote_name_req = false; + coex_sta->bt_rssi = - coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + coex_sta->bt_info_c2h[rsp_source][3] * 2 - 90; coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + if (coex_sta->bt_info_c2h[rsp_source][1] == 0x49) { + coex_sta->a2dp_bit_pool = + coex_sta->bt_info_c2h[rsp_source][6]; + } else { + coex_sta->a2dp_bit_pool = 0; + } + + coex_sta->bt_tx_rx_mask = + (coex_sta->bt_info_c2h[rsp_source][2] & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + + if (!coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG + * 0x3C != 0x15 => Need to switch BT TRx Mask + */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n"); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x15); + + /* BT TRx Mask lock 0x2c[0], 0x30[0] = 0 */ + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x2c, 0x7c44); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x30, 0x7c44); + } + /* Here we need to resend some wifi info to BT * because bt is reset and loss of the info. */ @@ -2938,6 +2974,8 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, else coex_sta->c2h_bt_inquiry_page = false; + coex_sta->num_of_profile = 0; + /* set link exist status */ if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { coex_sta->bt_link_exist = false; @@ -2950,22 +2988,43 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, } else { /* connection exists */ coex_sta->bt_link_exist = true; - if (bt_info & BT_INFO_8723B_1ANT_B_FTP) + if (bt_info & BT_INFO_8723B_1ANT_B_FTP) { coex_sta->pan_exist = true; - else + coex_sta->num_of_profile++; + } else { coex_sta->pan_exist = false; - if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) + } + if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) { coex_sta->a2dp_exist = true; - else + coex_sta->num_of_profile++; + } else { coex_sta->a2dp_exist = false; - if (bt_info & BT_INFO_8723B_1ANT_B_HID) + } + if (bt_info & BT_INFO_8723B_1ANT_B_HID) { coex_sta->hid_exist = true; - else + coex_sta->num_of_profile++; + } else { coex_sta->hid_exist = false; - if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) + } + if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) { coex_sta->sco_exist = true; - else + coex_sta->num_of_profile++; + } else { coex_sta->sco_exist = false; + } + + if ((!coex_sta->hid_exist) && + (!coex_sta->c2h_bt_inquiry_page) && + (!coex_sta->sco_exist)) { + if (coex_sta->high_priority_tx + + coex_sta->high_priority_rx >= + 160) { + coex_sta->hid_exist = true; + coex_sta->wrong_profile_notification++; + coex_sta->num_of_profile++; + bt_info = bt_info | 0x28; + } + } /* Add Hi-Pri Tx/Rx counter to avoid false detection */ if (((coex_sta->hid_exist) || (coex_sta->sco_exist)) && @@ -2974,11 +3033,27 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, (!coex_sta->c2h_bt_inquiry_page)) coex_sta->bt_hi_pri_link_exist = true; + if ((bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) && + (coex_sta->num_of_profile == 0)) { + if (coex_sta->low_priority_tx + + coex_sta->low_priority_rx >= + 160) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + coex_sta->wrong_profile_notification++; + bt_info = bt_info | 0x88; + } + } } halbtc8723b1ant_update_bt_link_info(btcoexist); - if (!(bt_info&BT_INFO_8723B_1ANT_B_CONNECTION)) { + /* mask profile bit for connect-ilde identification + * ( for CSR case: A2DP idle --> 0x41) + */ + bt_info = bt_info & 0x1f; + + if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT Non-Connected idle!\n"); @@ -3000,8 +3075,7 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); } else { - coex_dm->bt_status = - BT_8723B_1ANT_BT_STATUS_MAX; + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_MAX; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT Non-Defined state!!\n"); } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index fd0620ef0987..1cac98e3cc85 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -146,6 +146,7 @@ struct coex_sta_8723b_1ant { bool hid_exist; bool pan_exist; bool bt_hi_pri_link_exist; + u8 num_of_profile; bool under_lps; bool under_ips; @@ -157,10 +158,12 @@ struct coex_sta_8723b_1ant { u8 bt_rssi; u8 pre_bt_rssi_state; u8 pre_wifi_rssi_state[4]; + bool bt_tx_rx_mask; bool c2h_bt_info_req_sent; u8 bt_info_c2h[BT_INFO_SRC_8723B_1ANT_MAX][10]; u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX]; bool c2h_bt_inquiry_page; + bool c2h_bt_remote_name_req; u8 bt_retry_cnt; u8 bt_info_ext; u8 scan_ap_num; @@ -181,6 +184,8 @@ struct coex_sta_8723b_1ant { bool cck_lock; bool pre_ccklock; + u32 wrong_profile_notification; + u8 a2dp_bit_pool; u8 cut_version; }; -- cgit v1.2.3 From 53e18bcf3c7a8f7067b37c995733b3d3e6ab720d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:34 -0500 Subject: rtlwifi: btcoex: 23b 1ant: Setup register for BT WHCK test If BT is under WHCK, we enter a special mode. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 25 ++++++++++++++++++++++ .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 1 + 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 9509bf4a4635..4279678502d9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1701,6 +1701,18 @@ static void halbtc8723b1ant_monitor_bt_enable_disable(struct btc_coexist * Non-Software Coex Mechanism start * *****************************************************/ + +static void halbtc8723b1ant_action_bt_whck_test(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + static void halbtc8723b1ant_action_wifi_multiport(struct btc_coexist *btcoexist) { halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, @@ -2074,6 +2086,13 @@ static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) return; } + if (coex_sta->bt_whck_test) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], wifi is under IPS !!!\n"); + halbtc8723b1ant_action_bt_whck_test(btcoexist); + return; + } + if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY || coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY || coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) @@ -2883,6 +2902,12 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, "0x%02x, ", tmp_buf[i]); } + /* if 0xff, it means BT is under WHCK test */ + if (bt_info == 0xff) + coex_sta->bt_whck_test = true; + else + coex_sta->bt_whck_test = false; + if (rsp_source != BT_INFO_SRC_8723B_1ANT_WIFI_FW) { coex_sta->bt_retry_cnt = /* [3:0] */ coex_sta->bt_info_c2h[rsp_source][2] & 0xf; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 1cac98e3cc85..47b709159146 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -162,6 +162,7 @@ struct coex_sta_8723b_1ant { bool c2h_bt_info_req_sent; u8 bt_info_c2h[BT_INFO_SRC_8723B_1ANT_MAX][10]; u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX]; + bool bt_whck_test; bool c2h_bt_inquiry_page; bool c2h_bt_remote_name_req; u8 bt_retry_cnt; -- cgit v1.2.3 From 3ceac0a772b0b656a538c0d7a13cf881d00c195a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:35 -0500 Subject: rtlwifi: btcoex: 23b 1ant: Add rf status notification If driver announce wifi RF status is off, btc can switch antenna to BT. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 37 ++++++++++++++++++++++ .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 2 ++ .../realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 3 ++ 3 files changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 4279678502d9..5b44e32bf5b3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -3116,6 +3116,43 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, halbtc8723b1ant_run_coexist_mechanism(btcoexist); } +void ex_halbtc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u32 u32tmp; + u8 u8tmpa, u8tmpb, u8tmpc; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF Status notify\n"); + + if (type == BTC_RF_ON) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF is turned ON!!\n"); + btcoexist->stop_coex_dm = false; + } else if (type == BTC_RF_OFF) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RF is turned OFF!!\n"); + + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); + + halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + btcoexist->stop_coex_dm = true; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmpc = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x, 0x76e=0x%x\n", + u32tmp, u8tmpa, u8tmpb, u8tmpc); + } +} + void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 47b709159146..592a289c993c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -208,6 +208,8 @@ void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, u8 type); void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmpbuf, u8 length); +void ex_halbtc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, + u8 type); void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist); void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 6ce2fcadc144..e221adc0c048 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -30,6 +30,9 @@ #define NORMAL_EXEC false #define FORCE_EXEC true +#define BTC_RF_OFF 0x0 +#define BTC_RF_ON 0x1 + #define BTC_RF_A RF90_PATH_A #define BTC_RF_B RF90_PATH_B #define BTC_RF_C RF90_PATH_C -- cgit v1.2.3 From f9af7af4a10cbb0c763ef76e9de756cbfea3e09f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:36 -0500 Subject: rtlwifi: btcoex: 23b 1ant: fine tune connect notify When association starts, force antenna setup for no scan result issue. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 5b44e32bf5b3..61e8a7e95a91 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2737,13 +2737,28 @@ void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) bool wifi_connected = false, bt_hs_on = false; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; - bool bt_ctrl_agg_buf_size = false; + bool bt_ctrl_agg_buf_size = false, under_4way = false; u8 agg_buf_size = 5; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (btcoexist->manual_control || btcoexist->stop_coex_dm || coex_sta->bt_disabled) return; + if (type == BTC_ASSOCIATE_START) { + /* Force antenna setup for no scan result issue */ + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT START notify\n"); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], CONNECT FINISH notify\n"); + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); num_of_wifi_link = wifi_link_status>>16; -- cgit v1.2.3 From 29c1de91937a5f6204a9dabf9049c263b4a2b57c Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2017 10:59:37 -0500 Subject: rtlwifi: btcoex: 23b 1ant: Revise media status notify to fix no scan result issue Force antenna setup for no scan result issue Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 39 ++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 61e8a7e95a91..b8b50c13d911 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2804,18 +2804,53 @@ void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, u8 h2c_parameter[3] = {0}; u32 wifi_bw; u8 wifi_central_chnl; + bool wifi_under_b_mode = false; if (btcoexist->manual_control || btcoexist->stop_coex_dm || coex_sta->bt_disabled) return; - if (BTC_MEDIA_CONNECT == type) + if (type == BTC_MEDIA_CONNECT) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], MEDIA connect notify\n"); - else + /* Force antenna setup for no scan result issue */ + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + coex_dm->backup_arfr_cnt1 = + btcoexist->btc_read_4byte(btcoexist, 0x430); + coex_dm->backup_arfr_cnt2 = + btcoexist->btc_read_4byte(btcoexist, 0x434); + coex_dm->backup_retry_limit = + btcoexist->btc_read_2byte(btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = + btcoexist->btc_read_1byte(btcoexist, 0x456); + } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], MEDIA disconnect notify\n"); + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + coex_sta->cck_ever_lock = false; + } + /* only 2.4G we need to inform bt the chnl mask */ btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifi_central_chnl); -- cgit v1.2.3 From fa73a1ebe720c8360d6cce251487cb3917c16e09 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 May 2017 10:48:58 -0500 Subject: rtlwifi: btcoex: 23b 1ant: Special packets statistic in notification Count and log special packets of DHCP, EAPOL and ARP, and check whether the interface is in 4-way handshake. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 27 +++++++++++++++++++++- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index b8b50c13d911..188e248b2265 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2754,6 +2754,7 @@ void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) FORCE_EXEC, false, false); RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], CONNECT START notify\n"); + coex_dm->arp_cnt = 0; } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], CONNECT FINISH notify\n"); @@ -2844,6 +2845,7 @@ void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], MEDIA disconnect notify\n"); + coex_dm->arp_cnt = 0; btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ @@ -2884,13 +2886,36 @@ void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, bool bt_hs_on = false; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; - bool bt_ctrl_agg_buf_size = false; + bool bt_ctrl_agg_buf_size = false, under_4way = false; u8 agg_buf_size = 5; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (btcoexist->manual_control || btcoexist->stop_coex_dm || coex_sta->bt_disabled) return; + if (type == BTC_PACKET_DHCP || type == BTC_PACKET_EAPOL || + type == BTC_PACKET_ARP) { + if (type == BTC_PACKET_ARP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], special Packet ARP notify\n"); + + coex_dm->arp_cnt++; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], ARP Packet Count = %d\n", + coex_dm->arp_cnt); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], special Packet DHCP or EAPOL notify\n"); + } + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], special Packet [Type = %d] notify\n", + type); + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); num_of_wifi_link = wifi_link_status >> 16; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 592a289c993c..8df1036e36f1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -134,6 +134,7 @@ struct coex_dm_8723b_1ant { u8 cur_retry_limit_type; u8 pre_ampdu_time_type; u8 cur_ampdu_time_type; + u32 arp_cnt; u8 error_condition; }; -- cgit v1.2.3 From c34e42aa3e6e37a3625f88c96bd4923b93d83b6d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 May 2017 10:48:59 -0500 Subject: rtlwifi: btcoex: 23b 1ant: define wifi in high priority task. Add the definition of wifi in high priority task for bt inquiry. According to driver's notifications, btc will knows whether wifi is in high priority tasks or not. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 15 +++++++++++++++ .../wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 1 + 2 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 188e248b2265..185046227d15 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2662,6 +2662,7 @@ void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) return; if (type == BTC_SCAN_START) { + coex_sta->wifi_is_high_pri_task = true; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCAN START notify\n"); /* Force antenna setup for no scan result issue */ @@ -2676,6 +2677,7 @@ void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", u32tmp, u8tmpa, u8tmpb); } else { + coex_sta->wifi_is_high_pri_task = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCAN FINISH notify\n"); @@ -2748,6 +2750,8 @@ void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) return; if (type == BTC_ASSOCIATE_START) { + coex_sta->wifi_is_high_pri_task = true; + /* Force antenna setup for no scan result issue */ halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, @@ -2756,6 +2760,7 @@ void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], CONNECT START notify\n"); coex_dm->arp_cnt = 0; } else { + coex_sta->wifi_is_high_pri_task = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], CONNECT FINISH notify\n"); } @@ -2906,11 +2911,21 @@ void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], ARP Packet Count = %d\n", coex_dm->arp_cnt); + + if ((coex_dm->arp_cnt >= 10) && (!under_4way)) + /* if APR PKT > 10 after connect, do not go to + * ActionWifiConnectedSpecificPacket(btcoexist) + */ + coex_sta->wifi_is_high_pri_task = false; + else + coex_sta->wifi_is_high_pri_task = true; } else { + coex_sta->wifi_is_high_pri_task = true; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], special Packet DHCP or EAPOL notify\n"); } } else { + coex_sta->wifi_is_high_pri_task = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], special Packet [Type = %d] notify\n", type); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 8df1036e36f1..b71d4b40ab6c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -166,6 +166,7 @@ struct coex_sta_8723b_1ant { bool bt_whck_test; bool c2h_bt_inquiry_page; bool c2h_bt_remote_name_req; + bool wifi_is_high_pri_task; u8 bt_retry_cnt; u8 bt_info_ext; u8 scan_ap_num; -- cgit v1.2.3 From 5ae40d993576f829e386f27132a79fd61b5c75e6 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 May 2017 10:49:00 -0500 Subject: rtlwifi: btcoex: 23b 1ant: check more cases when bt is queing If bt is queing, we need to set the packet priority properly. Originally we only consider if wifi was connected or not, but now we also consider if bt is under abnormal scan or wifi is scanning, roaming or linking, and set the coex table. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 57 +++++++++++++++------- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 1 + 2 files changed, 40 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 185046227d15..e92ede844e3b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1732,35 +1732,56 @@ static void halbtc8723b1ant_action_bt_inquiry(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool wifi_connected = false, ap_enable = false; + bool wifi_busy = false, bt_busy = false; btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &ap_enable); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); - if (!wifi_connected) { - halbtc8723b1ant_power_save_state(btcoexist, - BTC_PS_WIFI_NATIVE, 0x0, 0x0); + if (coex_sta->bt_abnormal_scan) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } else if (!wifi_connected && !coex_sta->wifi_is_high_pri_task) { + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); - } else if (bt_link_info->sco_exist || bt_link_info->hid_only) { - /* SCO/HID-only busy */ + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (bt_link_info->sco_exist || bt_link_info->hid_exist || + bt_link_info->a2dp_exist) { + /* SCO/HID/A2DP busy */ halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); - } else { - if (ap_enable) - halbtc8723b1ant_power_save_state(btcoexist, - BTC_PS_WIFI_NATIVE, - 0x0, 0x0); + if (coex_sta->c2h_bt_remote_name_req) + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 33); else - halbtc8723b1ant_power_save_state(btcoexist, - BTC_PS_LPS_ON, - 0x50, 0x4); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->pan_exist || wifi_busy) { + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + if (coex_sta->c2h_bt_remote_name_req) + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 33); + else + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index b71d4b40ab6c..dc88d8ec3e54 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -148,6 +148,7 @@ struct coex_sta_8723b_1ant { bool pan_exist; bool bt_hi_pri_link_exist; u8 num_of_profile; + bool bt_abnormal_scan; bool under_lps; bool under_ips; -- cgit v1.2.3 From 8be514054d26baa94a14ad9c3e6c4cccf0478490 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 May 2017 10:49:01 -0500 Subject: rtlwifi: btcoex: 23b 1ant: remove verbose log from periodic function Simplify the debug trace log. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 33 ---------------------- 1 file changed, 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index e92ede844e3b..0b9d405e72eb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2377,11 +2377,6 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) "\r\n =========================================="); } - if (!board_info->bt_exist) { - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); - return; - } - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d", "Ant PG Num/ Ant Mech/ Ant Pos:", board_info->pg_ant_num, board_info->btdm_ant_num, @@ -3336,38 +3331,10 @@ void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; - struct btc_board_info *board_info = &btcoexist->board_info; - struct btc_stack_info *stack_info = &btcoexist->stack_info; - static u8 dis_ver_info_cnt; - u32 fw_ver = 0, bt_patch_ver = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], ==========================Periodical===========================\n"); - if (dis_ver_info_cnt <= 5) { - dis_ver_info_cnt += 1; - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", - board_info->pg_ant_num, board_info->btdm_ant_num, - board_info->btdm_ant_pos); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], BT stack/ hci ext ver = %s / %d\n", - stack_info->profile_notified ? "Yes" : "No", - stack_info->hci_version); - btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, - &bt_patch_ver); - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", - glcoex_ver_date_8723b_1ant, - glcoex_ver_8723b_1ant, fw_ver, - bt_patch_ver, bt_patch_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); - } - if (!btcoexist->auto_report_1ant) { halbtc8723b1ant_query_bt_info(btcoexist); halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); -- cgit v1.2.3 From 46b5689c3761a901872ce7bd4ecf21810b2577be Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 May 2017 10:49:02 -0500 Subject: rtlwifi: btcoex: 23b 1ant: Add coex_table_type to log Display coex_table_type in log. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 5 +++++ drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 1 + 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 0b9d405e72eb..80d577cd6549 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -570,6 +570,8 @@ static void halbtc8723b1ant_coex_table(struct btc_coexist *btcoexist, static void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist, bool force_exec, u8 type) { + coex_sta->coex_table_type = type; + switch (type) { case 0: halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, @@ -2520,6 +2522,9 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) coex_dm->error_condition); } + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d", + "Coex Table Type", coex_sta->coex_table_type); + /* Hw setting */ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Hw setting]============"); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index dc88d8ec3e54..3385a649d6c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -172,6 +172,7 @@ struct coex_sta_8723b_1ant { u8 bt_info_ext; u8 scan_ap_num; bool cck_ever_lock; + u8 coex_table_type; bool force_lps_on; u32 pop_event_cnt; -- cgit v1.2.3 From 056faad2e980c337fb8938793438c3dba2b78c17 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 May 2017 10:49:03 -0500 Subject: rtlwifi: btcoex: 23b 1ant: coex table fine tune Set register settings for coex table fine tune. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 56 +++++++++++++++++++--- 1 file changed, 50 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 80d577cd6549..9c4feb89144d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -587,24 +587,68 @@ static void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist, break; case 3: halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, - 0xaaaaaaaa, 0xffffff, 0x3); + 0x5a5a5a5a, 0xffffff, 0x3); break; case 4: - halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, - 0x5aaa5aaa, 0xffffff, 0x3); + if ((coex_sta->cck_ever_lock) && (coex_sta->scan_ap_num <= 5)) + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa5a5a, + 0xffffff, 0x3); + else + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, + 0xffffff, 0x3); break; case 5: - halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, - 0xaaaa5a5a, 0xffffff, 0x3); + if ((coex_sta->cck_ever_lock) && (coex_sta->scan_ap_num <= 5)) + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5aaa5a5a, + 0xffffff, 0x3); + else + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5aaa5a5a, + 0xffffff, 0x3); break; case 6: halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, - 0xaaaa5a5a, 0xffffff, 0x3); + 0xaaaaaaaa, 0xffffff, 0x3); break; case 7: halbtc8723b1ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); break; + case 8: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 9: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 10: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 11: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 12: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 13: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 14: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 15: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0xaaaaaaaa, 0xffffff, 0x3); + break; default: break; } -- cgit v1.2.3 From 1ecdc4363f994d98197dd41e5e26aa1d9c3d6455 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 May 2017 10:49:04 -0500 Subject: rtlwifi: btcoex: 23b 1ant: fine tune for wifi connected Fine tune the parameters in cases of bt_acl_busy and scan when wifi is connected. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 114 ++++++++++++++------- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 2 + 2 files changed, 79 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 9c4feb89144d..80522b91847c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1869,9 +1869,9 @@ static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy( } else if (bt_link_info->a2dp_only) { /* A2DP */ if (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 8); + true, 32); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 2); + NORMAL_EXEC, 4); coex_dm->auto_tdma_adjust = false; } else { btc8723b1ant_tdma_dur_adj_for_acl(btcoexist, @@ -1880,28 +1880,29 @@ static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy( NORMAL_EXEC, 1); coex_dm->auto_tdma_adjust = true; } - } else if (bt_link_info->hid_exist && - bt_link_info->a2dp_exist) { /* HID + A2DP */ + } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { + /* A2DP + PAN(OPP,FTP), HID + A2DP + PAN(OPP,FTP) */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) { + /* HID + A2DP */ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); coex_dm->auto_tdma_adjust = false; - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); - /* PAN(OPP,FTP), HID + PAN(OPP,FTP) */ + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); } else if (bt_link_info->pan_only || - (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + /* PAN(OPP,FTP), HID + PAN(OPP,FTP) */ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); - coex_dm->auto_tdma_adjust = false; - /* A2DP + PAN(OPP,FTP), HID + A2DP + PAN(OPP,FTP) */ - } else if ((bt_link_info->a2dp_exist && bt_link_info->pan_exist) || - (bt_link_info->hid_exist && bt_link_info->a2dp_exist && - bt_link_info->pan_exist)) { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); coex_dm->auto_tdma_adjust = false; } else { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + /* BT no-profile busy (0x9) */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); coex_dm->auto_tdma_adjust = false; } } @@ -1981,21 +1982,22 @@ static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist) /* tdma and coex table */ if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { - if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { + if (bt_link_info->a2dp_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 22); + true, 32); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); - } else if (bt_link_info->pan_only) { + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 20); + true, 22); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 2); + NORMAL_EXEC, 4); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); + NORMAL_EXEC, 4); } } else if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_SCO_BUSY || coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) { @@ -2003,6 +2005,8 @@ static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist) BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } @@ -2010,23 +2014,34 @@ static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist) static void halbtc8723b1ant_action_wifi_connected_special_packet( struct btc_coexist *btcoexist) { - bool hs_connecting = false; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_busy = false; - btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* no special packet process for both WiFi and BT very busy */ + if ((wifi_busy) && + ((bt_link_info->pan_exist) || (coex_sta->num_of_profile >= 2))) + return; halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); /* tdma and coex table */ - if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) || - (bt_link_info->sco_exist) || (bt_link_info->hid_only) || - (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); - } else { + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else if (bt_link_info->a2dp_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->pan_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } @@ -2071,10 +2086,29 @@ static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) if (!ap_enable && coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY && !btcoexist->bt_link_info.hid_only) { - if (!wifi_busy && btcoexist->bt_link_info.a2dp_only) - halbtc8723b1ant_power_save_state(btcoexist, + if (btcoexist->bt_link_info.a2dp_only) { + if (!wifi_busy) { + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + } else { /* busy */ + if (coex_sta->scan_ap_num >= + BT_8723B_1ANT_WIFI_NOISY_THRESH) + /* no force LPS, no PS-TDMA, + * use pure TDMA + */ + halbtc8723b1ant_power_save_state( + btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8723b1ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + } else if ((!coex_sta->pan_exist) && (!coex_sta->a2dp_exist) && + (!coex_sta->hid_exist)) + halbtc8723b1ant_power_save_state( + btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); else halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_LPS_ON, @@ -2098,6 +2132,9 @@ static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } @@ -2114,9 +2151,12 @@ static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 8); + true, 32); + halbtc8723b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 2); + NORMAL_EXEC, 4); } } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 3385a649d6c7..506961a1ca56 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -39,6 +39,8 @@ #define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2 +#define BT_8723B_1ANT_WIFI_NOISY_THRESH 50 + enum _BT_INFO_SRC_8723B_1ANT { BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0, BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1, -- cgit v1.2.3 From 40ca18823515608737c28214d38e90fc4387fa0c Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 May 2017 10:49:05 -0500 Subject: rtlwifi: btcoex: 23b 1ant: fine tune for wifi not connected Fine tune the parameters in cases of scan, assoc and auth when wifi isn't connected. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 37 ++++++++++++++-------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 80522b91847c..d938c8a4b180 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1914,7 +1914,9 @@ static void btc8723b1ant_action_wifi_not_conn(struct btc_coexist *btcoexist) 0x0, 0x0); /* tdma and coex table */ - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); } @@ -1928,16 +1930,16 @@ btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoexist) /* tdma and coex table */ if (coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) { - if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { + if (bt_link_info->a2dp_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 22); + true, 32); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 1); - } else if (bt_link_info->pan_only) { + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 20); + true, 22); halbtc8723b1ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 2); + NORMAL_EXEC, 4); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); @@ -1950,6 +1952,8 @@ btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoexist) BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); } else { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } } @@ -1962,14 +1966,19 @@ btc8723b1ant_act_wifi_not_conn_asso_auth(struct btc_coexist *btcoexist) halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); - if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) || - (bt_link_info->sco_exist) || (bt_link_info->hid_only) || - (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) { - halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); - } else { + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else if (bt_link_info->pan_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); } } -- cgit v1.2.3 From f9cbb5b4e90e78a4a7293283f278486a4a83e29d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 20 May 2017 10:49:06 -0500 Subject: rtlwifi: btcoex: 23b 1ant: fine tune for bt_sco_hid busy Fine tune the parameters in case of act_bt_sco_hid_only_busy. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index d938c8a4b180..5d780d8d7bbf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1843,7 +1843,7 @@ static void btc8723b1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist, /* tdma and coex table */ if (bt_link_info->sco_exist) { halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); - halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); } else { /* HID */ halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); -- cgit v1.2.3 From 86aeb82563b7b20f8b8050a065ce907bd3a2a4b1 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 20 May 2017 10:49:07 -0500 Subject: rtlwifi: btcoex: 23b 1ant: turn off ps and tdma mechanism when concurrent mode When wifi is under concurrent mode, we can not distinguish if it is the real PS or just a fake one by sending null data, so we turn it off in case of miracast scenario. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 100 +++++++++++++++------ .../realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 19 ++++ 2 files changed, 91 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 5d780d8d7bbf..0eea964584fb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1765,6 +1765,8 @@ static void halbtc8723b1ant_action_wifi_multiport(struct btc_coexist *btcoexist) 0x0, 0x0); halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } @@ -2174,12 +2176,15 @@ static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; - bool wifi_connected = false, bt_hs_on = false; + bool wifi_connected = false, bt_hs_on = false, wifi_busy = false; bool increase_scan_dev_num = false; bool bt_ctrl_agg_buf_size = false; + bool miracast_plus_bt = false; u8 agg_buf_size = 5; + u8 iot_peer = BTC_IOT_PEER_UNKNOWN; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; + u32 wifi_bw; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], RunCoexistMechanism()===>\n"); @@ -2216,46 +2221,85 @@ static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, &increase_scan_dev_num); - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); num_of_wifi_link = wifi_link_status >> 16; - if (num_of_wifi_link >= 2) { - halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + if (num_of_wifi_link >= 2 || + wifi_link_status & WIFI_P2P_GO_CONNECTED) { + if (bt_link_info->bt_link_exist) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, + 0, 1); + miracast_plus_bt = true; + } else { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, + 0, 0); + miracast_plus_bt = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, - bt_ctrl_agg_buf_size, - agg_buf_size); - halbtc8723b1ant_action_wifi_multiport(btcoexist); + bt_ctrl_agg_buf_size, agg_buf_size); + + if ((bt_link_info->a2dp_exist || wifi_busy) && + (coex_sta->c2h_bt_inquiry_page)) + halbtc8723b1ant_action_bt_inquiry(btcoexist); + else + halbtc8723b1ant_action_wifi_multiport(btcoexist); + return; } - if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) { - halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (bt_link_info->bt_link_exist && wifi_connected) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 0, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_IOT_PEER, &iot_peer); + + if (iot_peer != BTC_IOT_PEER_CISCO && + iot_peer != BTC_IOT_PEER_BROADCOM) { + if (bt_link_info->sco_exist) + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, + false, 0x5); + else + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, + false, 0x5); + } else { + if (bt_link_info->sco_exist) { + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, + false, 0x5); + } else { + if (wifi_bw == BTC_WIFI_BW_HT40) + halbtc8723b1ant_limited_rx( + btcoexist, NORMAL_EXEC, false, + true, 0x10); + else + halbtc8723b1ant_limited_rx( + btcoexist, NORMAL_EXEC, false, + true, 0x8); + } + } + + halbtc8723b1ant_sw_mechanism(btcoexist, true); } else { - if (wifi_connected) - halbtc8723b1ant_limited_tx(btcoexist, - NORMAL_EXEC, 1, 1, 1, 1); - else - halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, - 0, 0, 0, 0); - } + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); - if (bt_link_info->sco_exist) { - bt_ctrl_agg_buf_size = true; - agg_buf_size = 0x3; - } else if (bt_link_info->hid_exist) { - bt_ctrl_agg_buf_size = true; - agg_buf_size = 0x5; - } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) { - bt_ctrl_agg_buf_size = true; - agg_buf_size = 0x8; - } - halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, - bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + halbtc8723b1ant_sw_mechanism(btcoexist, false); + } btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); if (coex_sta->c2h_bt_inquiry_page) { diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index e221adc0c048..c5c360e011a9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -199,6 +199,24 @@ enum btc_wifi_pnp { BTC_WIFI_PNP_MAX }; +enum btc_iot_peer { + BTC_IOT_PEER_UNKNOWN = 0, + BTC_IOT_PEER_REALTEK = 1, + BTC_IOT_PEER_REALTEK_92SE = 2, + BTC_IOT_PEER_BROADCOM = 3, + BTC_IOT_PEER_RALINK = 4, + BTC_IOT_PEER_ATHEROS = 5, + BTC_IOT_PEER_CISCO = 6, + BTC_IOT_PEER_MERU = 7, + BTC_IOT_PEER_MARVELL = 8, + BTC_IOT_PEER_REALTEK_SOFTAP = 9, + BTC_IOT_PEER_SELF_SOFTAP = 10, /* Self is SoftAP */ + BTC_IOT_PEER_AIRGO = 11, + BTC_IOT_PEER_REALTEK_JAGUAR_BCUTAP = 12, + BTC_IOT_PEER_REALTEK_JAGUAR_CCUTAP = 13, + BTC_IOT_PEER_MAX, +}; + enum btc_get_type { /* type bool */ BTC_GET_BL_HS_OPERATION, @@ -238,6 +256,7 @@ enum btc_get_type { BTC_GET_U1_WIFI_HS_CHNL, BTC_GET_U1_MAC_PHY_MODE, BTC_GET_U1_AP_NUM, + BTC_GET_U1_IOT_PEER, /* for 1Ant */ BTC_GET_U1_LPS_MODE, -- cgit v1.2.3 From e578618934cbbdfdb02c5e2382be281fc8af1135 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 20 May 2017 00:25:39 +0300 Subject: rtlwifi: btcoex: 23b 1ant: initialize bt_disabled to false We only want to disable this if bt_disable_cnt is >= 2. Fixes: f66509e3d7c2 ("rtlwifi: btcoex: Remove 23b 1ant configuration parameter") Signed-off-by: Dan Carpenter Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 0eea964584fb..a0f3a18add25 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1704,7 +1704,7 @@ static void halbtc8723b1ant_monitor_bt_enable_disable(struct btc_coexist { struct rtl_priv *rtlpriv = btcoexist->adapter; static u32 bt_disable_cnt; - bool bt_active = true, bt_disabled; + bool bt_active = true, bt_disabled = false; if (coex_sta->high_priority_tx == 0 && coex_sta->high_priority_rx == 0 && coex_sta->low_priority_tx == 0 && -- cgit v1.2.3 From 98f44cb0655cbef0850ba7ff4c8213fb1bf9b6a2 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Thu, 11 May 2017 14:51:01 -0700 Subject: qtnfmac: introduce new FullMAC driver for Quantenna chipsets This patch adds support for new FullMAC WiFi driver for Quantenna QSR10G chipsets. QSR10G (aka Pearl) is Quantenna's 8x8, 160M, 11ac offering. QSR10G supports 2 simultaneous WMACs - one 5G and one 2G. 5G WMAC supports 160M, 8x8 configuration. FW supports up to 8 concurrent virtual interfaces on each WMAC. Patch introduces 2 new drivers: - qtnfmac.ko for interfacing with kernel wireless core - qtnfmac_pearl_pcie.ko for interfacing with hardware over PCIe interface Signed-off-by: Dmitrii Lebed Signed-off-by: Sergei Maksimenko Signed-off-by: Sergey Matyukevich Signed-off-by: Bindu Therthala Signed-off-by: Huizhao Wang Signed-off-by: Kamlesh Rath Signed-off-by: Avinash Patil Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/quantenna/Kconfig | 16 + drivers/net/wireless/quantenna/Makefile | 6 + drivers/net/wireless/quantenna/qtnfmac/Kconfig | 19 + drivers/net/wireless/quantenna/qtnfmac/Makefile | 31 + drivers/net/wireless/quantenna/qtnfmac/bus.h | 139 ++ drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 995 ++++++++++ drivers/net/wireless/quantenna/qtnfmac/cfg80211.h | 43 + drivers/net/wireless/quantenna/qtnfmac/commands.c | 1982 ++++++++++++++++++++ drivers/net/wireless/quantenna/qtnfmac/commands.h | 74 + drivers/net/wireless/quantenna/qtnfmac/core.c | 618 ++++++ drivers/net/wireless/quantenna/qtnfmac/core.h | 173 ++ drivers/net/wireless/quantenna/qtnfmac/debug.c | 46 + drivers/net/wireless/quantenna/qtnfmac/debug.h | 50 + drivers/net/wireless/quantenna/qtnfmac/event.c | 452 +++++ drivers/net/wireless/quantenna/qtnfmac/event.h | 27 + .../net/wireless/quantenna/qtnfmac/pearl/pcie.c | 1378 ++++++++++++++ .../quantenna/qtnfmac/pearl/pcie_bus_priv.h | 89 + .../wireless/quantenna/qtnfmac/pearl/pcie_ipc.h | 158 ++ .../quantenna/qtnfmac/pearl/pcie_regs_pearl.h | 353 ++++ drivers/net/wireless/quantenna/qtnfmac/qlink.h | 901 +++++++++ .../net/wireless/quantenna/qtnfmac/qlink_util.c | 71 + .../net/wireless/quantenna/qtnfmac/qlink_util.h | 80 + .../net/wireless/quantenna/qtnfmac/qtn_hw_ids.h | 32 + drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c | 176 ++ drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h | 80 + .../net/wireless/quantenna/qtnfmac/shm_ipc_defs.h | 46 + drivers/net/wireless/quantenna/qtnfmac/trans.c | 224 +++ drivers/net/wireless/quantenna/qtnfmac/trans.h | 57 + drivers/net/wireless/quantenna/qtnfmac/util.c | 114 ++ drivers/net/wireless/quantenna/qtnfmac/util.h | 45 + 32 files changed, 8477 insertions(+) create mode 100644 drivers/net/wireless/quantenna/Kconfig create mode 100644 drivers/net/wireless/quantenna/Makefile create mode 100644 drivers/net/wireless/quantenna/qtnfmac/Kconfig create mode 100644 drivers/net/wireless/quantenna/qtnfmac/Makefile create mode 100644 drivers/net/wireless/quantenna/qtnfmac/bus.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/cfg80211.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/cfg80211.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/commands.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/commands.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/core.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/core.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/debug.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/debug.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/event.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/event.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/qlink.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/qlink_util.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/qlink_util.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/shm_ipc_defs.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/trans.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/trans.h create mode 100644 drivers/net/wireless/quantenna/qtnfmac/util.c create mode 100644 drivers/net/wireless/quantenna/qtnfmac/util.h (limited to 'drivers') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8f5a3f4a43f2..166920ae23f8 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -45,6 +45,7 @@ source "drivers/net/wireless/rsi/Kconfig" source "drivers/net/wireless/st/Kconfig" source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zydas/Kconfig" +source "drivers/net/wireless/quantenna/Kconfig" config PCMCIA_RAYCS tristate "Aviator/Raytheon 2.4GHz wireless support" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index f00d42953fb8..54b41ac5f9c8 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/ obj-$(CONFIG_WLAN_VENDOR_ST) += st/ obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ +obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o diff --git a/drivers/net/wireless/quantenna/Kconfig b/drivers/net/wireless/quantenna/Kconfig new file mode 100644 index 000000000000..30943656e989 --- /dev/null +++ b/drivers/net/wireless/quantenna/Kconfig @@ -0,0 +1,16 @@ +config WLAN_VENDOR_QUANTENNA + bool "Quantenna wireless cards support" + default y + ---help--- + If you have a wireless card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about cards. If you say Y, you will be asked for + your specific card in the following questions. + +if WLAN_VENDOR_QUANTENNA + +source "drivers/net/wireless/quantenna/qtnfmac/Kconfig" + +endif # WLAN_VENDOR_QUANTENNA diff --git a/drivers/net/wireless/quantenna/Makefile b/drivers/net/wireless/quantenna/Makefile new file mode 100644 index 000000000000..baebfbde119e --- /dev/null +++ b/drivers/net/wireless/quantenna/Makefile @@ -0,0 +1,6 @@ +# +# Copyright (c) 2015-2016 Quantenna Communications, Inc. +# All rights reserved. +# + +obj-$(CONFIG_QTNFMAC) += qtnfmac/ diff --git a/drivers/net/wireless/quantenna/qtnfmac/Kconfig b/drivers/net/wireless/quantenna/qtnfmac/Kconfig new file mode 100644 index 000000000000..025fa6018550 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/Kconfig @@ -0,0 +1,19 @@ +config QTNFMAC + tristate + depends on QTNFMAC_PEARL_PCIE + default m if QTNFMAC_PEARL_PCIE=m + default y if QTNFMAC_PEARL_PCIE=y + +config QTNFMAC_PEARL_PCIE + tristate "Quantenna QSR10g PCIe support" + default n + depends on HAS_DMA && PCI && CFG80211 + select QTNFMAC + select FW_LOADER + select CRC32 + ---help--- + This option adds support for wireless adapters based on Quantenna + 802.11ac QSR10g (aka Pearl) FullMAC chipset running over PCIe. + + If you choose to build it as a module, two modules will be built: + qtnfmac.ko and qtnfmac_pearl_pcie.ko. diff --git a/drivers/net/wireless/quantenna/qtnfmac/Makefile b/drivers/net/wireless/quantenna/qtnfmac/Makefile new file mode 100644 index 000000000000..0d618e5e5f5b --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/Makefile @@ -0,0 +1,31 @@ +# +# Copyright (c) 2015-2016 Quantenna Communications, Inc. +# All rights reserved. +# + +ccflags-y += \ + -Idrivers/net/wireless/quantenna/qtnfmac + +obj-$(CONFIG_QTNFMAC) += qtnfmac.o +qtnfmac-objs += \ + core.o \ + commands.o \ + trans.o \ + cfg80211.o \ + event.o \ + util.o \ + qlink_util.o + +# + +obj-$(CONFIG_QTNFMAC_PEARL_PCIE) += qtnfmac_pearl_pcie.o + +qtnfmac_pearl_pcie-objs += \ + shm_ipc.o \ + pearl/pcie.o + +qtnfmac_pearl_pcie-$(CONFIG_DEBUG_FS) += debug.o + +# + +ccflags-y += -D__CHECK_ENDIAN diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h new file mode 100644 index 000000000000..dda05003d522 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015 Quantenna Communications + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef QTNFMAC_BUS_H +#define QTNFMAC_BUS_H + +#include +#include + +#define QTNF_MAX_MAC 3 + +enum qtnf_fw_state { + QTNF_FW_STATE_RESET, + QTNF_FW_STATE_FW_DNLD_DONE, + QTNF_FW_STATE_BOOT_DONE, + QTNF_FW_STATE_ACTIVE, + QTNF_FW_STATE_DEAD, +}; + +struct qtnf_bus; + +struct qtnf_bus_ops { + /* mgmt methods */ + int (*preinit)(struct qtnf_bus *); + void (*stop)(struct qtnf_bus *); + + /* control path methods */ + int (*control_tx)(struct qtnf_bus *, struct sk_buff *); + + /* data xfer methods */ + int (*data_tx)(struct qtnf_bus *, struct sk_buff *); + void (*data_tx_timeout)(struct qtnf_bus *, struct net_device *); + void (*data_rx_start)(struct qtnf_bus *); + void (*data_rx_stop)(struct qtnf_bus *); +}; + +struct qtnf_bus { + struct device *dev; + enum qtnf_fw_state fw_state; + u32 chip; + u32 chiprev; + const struct qtnf_bus_ops *bus_ops; + struct qtnf_wmac *mac[QTNF_MAX_MAC]; + struct qtnf_qlink_transport trans; + struct qtnf_hw_info hw_info; + char fwname[32]; + struct napi_struct mux_napi; + struct net_device mux_dev; + struct completion request_firmware_complete; + struct workqueue_struct *workqueue; + struct work_struct event_work; + struct mutex bus_lock; /* lock during command/event processing */ + struct dentry *dbg_dir; + /* bus private data */ + char bus_priv[0] __aligned(sizeof(void *)); +}; + +static inline void *get_bus_priv(struct qtnf_bus *bus) +{ + if (WARN(!bus, "qtnfmac: invalid bus pointer")) + return NULL; + + return &bus->bus_priv; +} + +/* callback wrappers */ + +static inline int qtnf_bus_preinit(struct qtnf_bus *bus) +{ + if (!bus->bus_ops->preinit) + return 0; + return bus->bus_ops->preinit(bus); +} + +static inline void qtnf_bus_stop(struct qtnf_bus *bus) +{ + if (!bus->bus_ops->stop) + return; + bus->bus_ops->stop(bus); +} + +static inline int qtnf_bus_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ + return bus->bus_ops->data_tx(bus, skb); +} + +static inline void +qtnf_bus_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) +{ + return bus->bus_ops->data_tx_timeout(bus, ndev); +} + +static inline int qtnf_bus_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ + return bus->bus_ops->control_tx(bus, skb); +} + +static inline void qtnf_bus_data_rx_start(struct qtnf_bus *bus) +{ + return bus->bus_ops->data_rx_start(bus); +} + +static inline void qtnf_bus_data_rx_stop(struct qtnf_bus *bus) +{ + return bus->bus_ops->data_rx_stop(bus); +} + +static __always_inline void qtnf_bus_lock(struct qtnf_bus *bus) +{ + mutex_lock(&bus->bus_lock); +} + +static __always_inline void qtnf_bus_unlock(struct qtnf_bus *bus) +{ + mutex_unlock(&bus->bus_lock); +} + +/* interface functions from common layer */ + +void qtnf_rx_frame(struct device *dev, struct sk_buff *rxp); +int qtnf_core_attach(struct qtnf_bus *bus); +void qtnf_core_detach(struct qtnf_bus *bus); +void qtnf_txflowblock(struct device *dev, bool state); +void qtnf_txcomplete(struct device *dev, struct sk_buff *txp, bool success); + +#endif /* QTNFMAC_BUS_H */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c new file mode 100644 index 000000000000..fc0ce2c09097 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -0,0 +1,995 @@ +/* + * Copyright (c) 2012-2012 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "cfg80211.h" +#include "commands.h" +#include "core.h" +#include "util.h" +#include "bus.h" + +/* Supported rates to be advertised to the cfg80211 */ +static struct ieee80211_rate qtnf_rates_2g[] = { + {.bitrate = 10, .hw_value = 2, }, + {.bitrate = 20, .hw_value = 4, }, + {.bitrate = 55, .hw_value = 11, }, + {.bitrate = 110, .hw_value = 22, }, + {.bitrate = 60, .hw_value = 12, }, + {.bitrate = 90, .hw_value = 18, }, + {.bitrate = 120, .hw_value = 24, }, + {.bitrate = 180, .hw_value = 36, }, + {.bitrate = 240, .hw_value = 48, }, + {.bitrate = 360, .hw_value = 72, }, + {.bitrate = 480, .hw_value = 96, }, + {.bitrate = 540, .hw_value = 108, }, +}; + +/* Supported rates to be advertised to the cfg80211 */ +static struct ieee80211_rate qtnf_rates_5g[] = { + {.bitrate = 60, .hw_value = 12, }, + {.bitrate = 90, .hw_value = 18, }, + {.bitrate = 120, .hw_value = 24, }, + {.bitrate = 180, .hw_value = 36, }, + {.bitrate = 240, .hw_value = 48, }, + {.bitrate = 360, .hw_value = 72, }, + {.bitrate = 480, .hw_value = 96, }, + {.bitrate = 540, .hw_value = 108, }, +}; + +/* Supported crypto cipher suits to be advertised to cfg80211 */ +static const u32 qtnf_cipher_suites[] = { + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, +}; + +/* Supported mgmt frame types to be advertised to cfg80211 */ +static const struct ieee80211_txrx_stypes +qtnf_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, + [NL80211_IFTYPE_AP] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, +}; + +static int +qtnf_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + u8 *mac_addr; + int ret; + + if (params) + mac_addr = params->macaddr; + else + mac_addr = NULL; + + qtnf_scan_done(vif->mac, true); + + ret = qtnf_cmd_send_change_intf_type(vif, type, mac_addr); + if (ret) { + pr_err("VIF%u.%u: failed to change VIF type: %d\n", + vif->mac->macid, vif->vifid, ret); + return ret; + } + + vif->wdev.iftype = type; + return 0; +} + +int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct net_device *netdev = wdev->netdev; + struct qtnf_vif *vif; + + if (WARN_ON(!netdev)) + return -EFAULT; + + vif = qtnf_netdev_get_priv(wdev->netdev); + + if (qtnf_cmd_send_del_intf(vif)) + pr_err("VIF%u.%u: failed to delete VIF\n", vif->mac->macid, + vif->vifid); + + /* Stop data */ + netif_tx_stop_all_queues(netdev); + if (netif_carrier_ok(netdev)) + netif_carrier_off(netdev); + + if (netdev->reg_state == NETREG_REGISTERED) + unregister_netdevice(netdev); + + vif->netdev->ieee80211_ptr = NULL; + vif->netdev = NULL; + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + eth_zero_addr(vif->mac_addr); + + return 0; +} + +static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_t, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct qtnf_wmac *mac; + struct qtnf_vif *vif; + u8 *mac_addr = NULL; + + mac = wiphy_priv(wiphy); + + if (!mac) + return ERR_PTR(-EFAULT); + + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_AP: + vif = qtnf_mac_get_free_vif(mac); + if (!vif) { + pr_err("MAC%u: no free VIF available\n", mac->macid); + return ERR_PTR(-EFAULT); + } + + eth_zero_addr(vif->mac_addr); + vif->bss_priority = QTNF_DEF_BSS_PRIORITY; + vif->wdev.wiphy = wiphy; + vif->wdev.iftype = type; + vif->sta_state = QTNF_STA_DISCONNECTED; + break; + default: + pr_err("MAC%u: unsupported IF type %d\n", mac->macid, type); + return ERR_PTR(-ENOTSUPP); + } + + if (params) + mac_addr = params->macaddr; + + if (qtnf_cmd_send_add_intf(vif, type, mac_addr)) { + pr_err("VIF%u.%u: failed to add VIF\n", mac->macid, vif->vifid); + goto err_cmd; + } + + if (!is_valid_ether_addr(vif->mac_addr)) { + pr_err("VIF%u.%u: FW reported bad MAC: %pM\n", + mac->macid, vif->vifid, vif->mac_addr); + goto err_mac; + } + + if (qtnf_core_net_attach(mac, vif, name, name_assign_t, type)) { + pr_err("VIF%u.%u: failed to attach netdev\n", mac->macid, + vif->vifid); + goto err_net; + } + + vif->wdev.netdev = vif->netdev; + return &vif->wdev; + +err_net: + vif->netdev = NULL; +err_mac: + qtnf_cmd_send_del_intf(vif); +err_cmd: + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + + return ERR_PTR(-EFAULT); +} + +static int qtnf_mgmt_set_appie(struct qtnf_vif *vif, + const struct cfg80211_beacon_data *info) +{ + int ret = 0; + + if (!info->beacon_ies || !info->beacon_ies_len) { + ret = qtnf_cmd_send_mgmt_set_appie(vif, QLINK_MGMT_FRAME_BEACON, + NULL, 0); + } else { + ret = qtnf_cmd_send_mgmt_set_appie(vif, QLINK_MGMT_FRAME_BEACON, + info->beacon_ies, + info->beacon_ies_len); + } + + if (ret) + goto out; + + if (!info->proberesp_ies || !info->proberesp_ies_len) { + ret = qtnf_cmd_send_mgmt_set_appie(vif, + QLINK_MGMT_FRAME_PROBE_RESP, + NULL, 0); + } else { + ret = qtnf_cmd_send_mgmt_set_appie(vif, + QLINK_MGMT_FRAME_PROBE_RESP, + info->proberesp_ies, + info->proberesp_ies_len); + } + + if (ret) + goto out; + + if (!info->assocresp_ies || !info->assocresp_ies_len) { + ret = qtnf_cmd_send_mgmt_set_appie(vif, + QLINK_MGMT_FRAME_ASSOC_RESP, + NULL, 0); + } else { + ret = qtnf_cmd_send_mgmt_set_appie(vif, + QLINK_MGMT_FRAME_ASSOC_RESP, + info->assocresp_ies, + info->assocresp_ies_len); + } + +out: + return ret; +} + +static int qtnf_change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *info) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_err("VIF%u.%u: not started\n", vif->mac->macid, vif->vifid); + return -EFAULT; + } + + return qtnf_mgmt_set_appie(vif, info); +} + +static int qtnf_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *settings) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + struct qtnf_bss_config *bss_cfg; + int ret; + + bss_cfg = &vif->bss_cfg; + + memset(bss_cfg, 0, sizeof(*bss_cfg)); + + bss_cfg->bcn_period = settings->beacon_interval; + bss_cfg->dtim = settings->dtim_period; + bss_cfg->auth_type = settings->auth_type; + bss_cfg->privacy = settings->privacy; + + bss_cfg->ssid_len = settings->ssid_len; + memcpy(&bss_cfg->ssid, settings->ssid, bss_cfg->ssid_len); + + memcpy(&bss_cfg->chandef, &settings->chandef, + sizeof(struct cfg80211_chan_def)); + memcpy(&bss_cfg->crypto, &settings->crypto, + sizeof(struct cfg80211_crypto_settings)); + + ret = qtnf_cmd_send_config_ap(vif); + if (ret) { + pr_err("VIF%u.%u: failed to push config to FW\n", + vif->mac->macid, vif->vifid); + goto out; + } + + if (!(vif->bss_status & QTNF_STATE_AP_CONFIG)) { + pr_err("VIF%u.%u: AP config failed in FW\n", vif->mac->macid, + vif->vifid); + ret = -EFAULT; + goto out; + } + + ret = qtnf_mgmt_set_appie(vif, &settings->beacon); + if (ret) { + pr_err("VIF%u.%u: failed to add IEs to beacon\n", + vif->mac->macid, vif->vifid); + goto out; + } + + ret = qtnf_cmd_send_start_ap(vif); + if (ret) { + pr_err("VIF%u.%u: failed to start AP\n", vif->mac->macid, + vif->vifid); + goto out; + } + + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_err("VIF%u.%u: FW failed to start AP operation\n", + vif->mac->macid, vif->vifid); + ret = -EFAULT; + } + +out: + return ret; +} + +static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_stop_ap(vif); + if (ret) { + pr_err("VIF%u.%u: failed to stop AP operation in FW\n", + vif->mac->macid, vif->vifid); + vif->bss_status &= ~QTNF_STATE_AP_START; + vif->bss_status &= ~QTNF_STATE_AP_CONFIG; + + netif_carrier_off(vif->netdev); + } + + return ret; +} + +static int qtnf_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_vif *vif; + int ret; + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", mac->macid); + return -EFAULT; + } + + if (changed & (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT)) { + pr_err("MAC%u: can't modify retry params\n", mac->macid); + return -EOPNOTSUPP; + } + + ret = qtnf_cmd_send_update_phy_params(mac, changed); + if (ret) + pr_err("MAC%u: failed to update PHY params\n", mac->macid); + + return ret; +} + +static void +qtnf_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, + u16 frame_type, bool reg) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev); + u16 mgmt_type; + u16 new_mask; + u16 qlink_frame_type = 0; + + mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; + + if (reg) + new_mask = vif->mgmt_frames_bitmask | BIT(mgmt_type); + else + new_mask = vif->mgmt_frames_bitmask & ~BIT(mgmt_type); + + if (new_mask == vif->mgmt_frames_bitmask) + return; + + switch (frame_type & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_REQ: + qlink_frame_type = QLINK_MGMT_FRAME_PROBE_REQ; + break; + case IEEE80211_STYPE_ACTION: + qlink_frame_type = QLINK_MGMT_FRAME_ACTION; + break; + default: + pr_warn("VIF%u.%u: unsupported frame type: %X\n", + vif->mac->macid, vif->vifid, + (frame_type & IEEE80211_FCTL_STYPE) >> 4); + return; + } + + if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg)) { + pr_warn("VIF%u.%u: failed to %sregister mgmt frame type 0x%x\n", + vif->mac->macid, vif->vifid, reg ? "" : "un", + frame_type); + return; + } + + vif->mgmt_frames_bitmask = new_mask; + pr_debug("VIF%u.%u: %sregistered mgmt frame type 0x%x\n", + vif->mac->macid, vif->vifid, reg ? "" : "un", frame_type); +} + +static int +qtnf_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev); + const struct ieee80211_mgmt *mgmt_frame = (void *)params->buf; + u32 short_cookie = prandom_u32(); + u16 flags = 0; + + *cookie = short_cookie; + + if (params->offchan) + flags |= QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN; + + if (params->no_cck) + flags |= QLINK_MGMT_FRAME_TX_FLAG_NO_CCK; + + if (params->dont_wait_for_ack) + flags |= QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT; + + pr_debug("%s freq:%u; FC:%.4X; DA:%pM; len:%zu; C:%.8X; FL:%.4X\n", + wdev->netdev->name, params->chan->center_freq, + le16_to_cpu(mgmt_frame->frame_control), mgmt_frame->da, + params->len, short_cookie, flags); + + return qtnf_cmd_send_mgmt_frame(vif, short_cookie, flags, + params->chan->center_freq, + params->buf, params->len); +} + +static int +qtnf_get_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_info *sinfo) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + + return qtnf_cmd_get_sta_info(vif, mac, sinfo); +} + +static int +qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + const struct qtnf_sta_node *sta_node; + int ret; + + sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx); + + if (unlikely(!sta_node)) + return -ENOENT; + + ether_addr_copy(mac, sta_node->mac_addr); + + ret = qtnf_cmd_get_sta_info(vif, sta_node->mac_addr, sinfo); + + if (unlikely(ret == -ENOENT)) { + qtnf_sta_list_del(&vif->sta_list, mac); + cfg80211_del_sta(vif->netdev, mac, GFP_KERNEL); + sinfo->filled = 0; + } + + return ret; +} + +static int qtnf_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_add_key(vif, key_index, pairwise, mac_addr, params); + if (ret) + pr_err("VIF%u.%u: failed to add key: cipher=%x idx=%u pw=%u\n", + vif->mac->macid, vif->vifid, params->cipher, key_index, + pairwise); + + return ret; +} + +static int qtnf_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool pairwise, const u8 *mac_addr) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_del_key(vif, key_index, pairwise, mac_addr); + if (ret) + pr_err("VIF%u.%u: failed to delete key: idx=%u pw=%u\n", + vif->mac->macid, vif->vifid, key_index, pairwise); + + return ret; +} + +static int qtnf_set_default_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, bool unicast, bool multicast) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_set_default_key(vif, key_index, unicast, multicast); + if (ret) + pr_err("VIF%u.%u: failed to set dflt key: idx=%u uc=%u mc=%u\n", + vif->mac->macid, vif->vifid, key_index, unicast, + multicast); + + return ret; +} + +static int +qtnf_set_default_mgmt_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_set_default_mgmt_key(vif, key_index); + if (ret) + pr_err("VIF%u.%u: failed to set default MGMT key: idx=%u\n", + vif->mac->macid, vif->vifid, key_index); + + return ret; +} + +static int +qtnf_change_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_parameters *params) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + ret = qtnf_cmd_send_change_sta(vif, mac, params); + if (ret) + pr_err("VIF%u.%u: failed to change STA %pM\n", + vif->mac->macid, vif->vifid, mac); + + return ret; +} + +static int +qtnf_del_station(struct wiphy *wiphy, struct net_device *dev, + struct station_del_parameters *params) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + if (params->mac && + (vif->wdev.iftype == NL80211_IFTYPE_AP) && + !is_broadcast_ether_addr(params->mac) && + !qtnf_sta_list_lookup(&vif->sta_list, params->mac)) + return 0; + + qtnf_scan_done(vif->mac, true); + + ret = qtnf_cmd_send_del_sta(vif, params); + if (ret) + pr_err("VIF%u.%u: failed to delete STA %pM\n", + vif->mac->macid, vif->vifid, params->mac); + return ret; +} + +static int +qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + int ret; + + mac->scan_req = request; + + ret = qtnf_cmd_send_scan(mac); + if (ret) + pr_err("MAC%u: failed to start scan\n", mac->macid); + + return ret; +} + +static int +qtnf_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + struct qtnf_bss_config *bss_cfg; + int ret; + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (vif->sta_state != QTNF_STA_DISCONNECTED) + return -EBUSY; + + bss_cfg = &vif->bss_cfg; + memset(bss_cfg, 0, sizeof(*bss_cfg)); + + bss_cfg->ssid_len = sme->ssid_len; + memcpy(&bss_cfg->ssid, sme->ssid, bss_cfg->ssid_len); + bss_cfg->chandef.chan = sme->channel; + bss_cfg->auth_type = sme->auth_type; + bss_cfg->privacy = sme->privacy; + bss_cfg->mfp = sme->mfp; + + if ((sme->bg_scan_period > 0) && + (sme->bg_scan_period <= QTNF_MAX_BG_SCAN_PERIOD)) + bss_cfg->bg_scan_period = sme->bg_scan_period; + else if (sme->bg_scan_period == -1) + bss_cfg->bg_scan_period = QTNF_DEFAULT_BG_SCAN_PERIOD; + else + bss_cfg->bg_scan_period = 0; /* disabled */ + + bss_cfg->connect_flags = 0; + + if (sme->flags & ASSOC_REQ_DISABLE_HT) + bss_cfg->connect_flags |= QLINK_STA_CONNECT_DISABLE_HT; + if (sme->flags & ASSOC_REQ_DISABLE_VHT) + bss_cfg->connect_flags |= QLINK_STA_CONNECT_DISABLE_VHT; + if (sme->flags & ASSOC_REQ_USE_RRM) + bss_cfg->connect_flags |= QLINK_STA_CONNECT_USE_RRM; + + memcpy(&bss_cfg->crypto, &sme->crypto, sizeof(bss_cfg->crypto)); + if (sme->bssid) + ether_addr_copy(bss_cfg->bssid, sme->bssid); + else + eth_zero_addr(bss_cfg->bssid); + + ret = qtnf_cmd_send_connect(vif, sme); + if (ret) { + pr_err("VIF%u.%u: failed to connect\n", vif->mac->macid, + vif->vifid); + return ret; + } + + vif->sta_state = QTNF_STA_CONNECTING; + return 0; +} + +static int +qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_vif *vif; + int ret; + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", mac->macid); + return -EFAULT; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + if (vif->sta_state == QTNF_STA_DISCONNECTED) + return 0; + + ret = qtnf_cmd_send_disconnect(vif, reason_code); + if (ret) { + pr_err("VIF%u.%u: failed to disconnect\n", mac->macid, + vif->vifid); + return ret; + } + + vif->sta_state = QTNF_STA_DISCONNECTED; + return 0; +} + +static struct cfg80211_ops qtn_cfg80211_ops = { + .add_virtual_intf = qtnf_add_virtual_intf, + .change_virtual_intf = qtnf_change_virtual_intf, + .del_virtual_intf = qtnf_del_virtual_intf, + .start_ap = qtnf_start_ap, + .change_beacon = qtnf_change_beacon, + .stop_ap = qtnf_stop_ap, + .set_wiphy_params = qtnf_set_wiphy_params, + .mgmt_frame_register = qtnf_mgmt_frame_register, + .mgmt_tx = qtnf_mgmt_tx, + .change_station = qtnf_change_station, + .del_station = qtnf_del_station, + .get_station = qtnf_get_station, + .dump_station = qtnf_dump_station, + .add_key = qtnf_add_key, + .del_key = qtnf_del_key, + .set_default_key = qtnf_set_default_key, + .set_default_mgmt_key = qtnf_set_default_mgmt_key, + .scan = qtnf_scan, + .connect = qtnf_connect, + .disconnect = qtnf_disconnect +}; + +static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *req) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_bus *bus; + struct qtnf_vif *vif; + struct qtnf_wmac *chan_mac; + int i; + enum nl80211_band band; + + bus = mac->bus; + + pr_debug("MAC%u: initiator=%d alpha=%c%c\n", mac->macid, req->initiator, + req->alpha2[0], req->alpha2[1]); + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", mac->macid); + return; + } + + /* ignore non-ISO3166 country codes */ + for (i = 0; i < sizeof(req->alpha2); i++) { + if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { + pr_err("MAC%u: not an ISO3166 code\n", mac->macid); + return; + } + } + if (!strncasecmp(req->alpha2, bus->hw_info.alpha2_code, + sizeof(req->alpha2))) { + pr_warn("MAC%u: unchanged country code\n", mac->macid); + return; + } + + if (qtnf_cmd_send_regulatory_config(mac, req->alpha2)) { + pr_err("MAC%u: failed to configure regulatory\n", mac->macid); + return; + } + + for (i = 0; i < bus->hw_info.num_mac; i++) { + chan_mac = bus->mac[i]; + + if (!chan_mac) + continue; + + if (!(bus->hw_info.mac_bitmap & BIT(i))) + continue; + + for (band = 0; band < NUM_NL80211_BANDS; ++band) { + if (!wiphy->bands[band]) + continue; + + if (qtnf_cmd_get_mac_chan_info(chan_mac, + wiphy->bands[band])) { + pr_err("MAC%u: can't get channel info\n", + chan_mac->macid); + qtnf_core_detach(bus); + + return; + } + } + } +} + +void qtnf_band_setup_htvht_caps(struct qtnf_mac_info *macinfo, + struct ieee80211_supported_band *band) +{ + struct ieee80211_sta_ht_cap *ht_cap; + struct ieee80211_sta_vht_cap *vht_cap; + + ht_cap = &band->ht_cap; + ht_cap->ht_supported = true; + memcpy(&ht_cap->cap, &macinfo->ht_cap.cap_info, + sizeof(u16)); + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; + memcpy(&ht_cap->mcs, &macinfo->ht_cap.mcs, + sizeof(ht_cap->mcs)); + + if (macinfo->phymode_cap & QLINK_PHYMODE_AC) { + vht_cap = &band->vht_cap; + vht_cap->vht_supported = true; + memcpy(&vht_cap->cap, + &macinfo->vht_cap.vht_cap_info, sizeof(u32)); + /* Update MCS support for VHT */ + memcpy(&vht_cap->vht_mcs, + &macinfo->vht_cap.supp_mcs, + sizeof(struct ieee80211_vht_mcs_info)); + } +} + +struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus) +{ + struct wiphy *wiphy; + + wiphy = wiphy_new(&qtn_cfg80211_ops, sizeof(struct qtnf_wmac)); + if (!wiphy) + return NULL; + + set_wiphy_dev(wiphy, bus->dev); + + return wiphy; +} + +static int qtnf_wiphy_setup_if_comb(struct wiphy *wiphy, + struct ieee80211_iface_combination *if_comb, + const struct qtnf_mac_info *mac_info) +{ + size_t max_interfaces = 0; + u16 interface_modes = 0; + size_t i; + + if (unlikely(!mac_info->limits || !mac_info->n_limits)) + return -ENOENT; + + if_comb->limits = mac_info->limits; + if_comb->n_limits = mac_info->n_limits; + + for (i = 0; i < mac_info->n_limits; i++) { + max_interfaces += mac_info->limits[i].max; + interface_modes |= mac_info->limits[i].types; + } + + if_comb->num_different_channels = 1; + if_comb->beacon_int_infra_match = true; + if_comb->max_interfaces = max_interfaces; + if_comb->radar_detect_widths = mac_info->radar_detect_widths; + wiphy->interface_modes = interface_modes; + + return 0; +} + +int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) +{ + struct wiphy *wiphy = priv_to_wiphy(mac); + struct ieee80211_iface_combination *iface_comb = NULL; + int ret; + + if (!wiphy) { + pr_err("invalid wiphy pointer\n"); + return -EFAULT; + } + + iface_comb = kzalloc(sizeof(*iface_comb), GFP_KERNEL); + if (!iface_comb) { + ret = -ENOMEM; + goto out; + } + + ret = qtnf_wiphy_setup_if_comb(wiphy, iface_comb, &mac->macinfo); + if (ret) + goto out; + + pr_info("MAC%u: phymode=%#x radar=%#x\n", mac->macid, + mac->macinfo.phymode_cap, mac->macinfo.radar_detect_widths); + + wiphy->frag_threshold = mac->macinfo.frag_thr; + wiphy->rts_threshold = mac->macinfo.rts_thr; + wiphy->retry_short = mac->macinfo.sretry_limit; + wiphy->retry_long = mac->macinfo.lretry_limit; + wiphy->coverage_class = mac->macinfo.coverage_class; + + wiphy->max_scan_ssids = QTNF_MAX_SSID_LIST_LENGTH; + wiphy->max_scan_ie_len = QTNF_MAX_VSIE_LEN; + wiphy->mgmt_stypes = qtnf_mgmt_stypes; + wiphy->max_remain_on_channel_duration = 5000; + + wiphy->iface_combinations = iface_comb; + wiphy->n_iface_combinations = 1; + + /* Initialize cipher suits */ + wiphy->cipher_suites = qtnf_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(qtnf_cipher_suites); + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | + WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | + WIPHY_FLAG_AP_UAPSD; + + wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; + + wiphy->available_antennas_tx = mac->macinfo.num_tx_chain; + wiphy->available_antennas_rx = mac->macinfo.num_rx_chain; + + wiphy->max_ap_assoc_sta = mac->macinfo.max_ap_assoc_sta; + + ether_addr_copy(wiphy->perm_addr, mac->macaddr); + + if (hw_info->hw_capab & QLINK_HW_SUPPORTS_REG_UPDATE) { + pr_debug("device supports REG_UPDATE\n"); + wiphy->reg_notifier = qtnf_cfg80211_reg_notifier; + pr_debug("hint regulatory about EP region: %c%c\n", + hw_info->alpha2_code[0], + hw_info->alpha2_code[1]); + regulatory_hint(wiphy, hw_info->alpha2_code); + } else { + pr_debug("device doesn't support REG_UPDATE\n"); + wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; + } + + ret = wiphy_register(wiphy); + +out: + if (ret < 0) { + kfree(iface_comb); + return ret; + } + + return 0; +} + +void qtnf_netdev_updown(struct net_device *ndev, bool up) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + + if (qtnf_cmd_send_updown_intf(vif, up)) + pr_err("failed to send up/down command to FW\n"); +} + +void qtnf_virtual_intf_cleanup(struct net_device *ndev) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + struct qtnf_wmac *mac = mac = wiphy_priv(vif->wdev.wiphy); + + if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { + switch (vif->sta_state) { + case QTNF_STA_DISCONNECTED: + break; + case QTNF_STA_CONNECTING: + cfg80211_connect_result(vif->netdev, + vif->bss_cfg.bssid, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + qtnf_disconnect(vif->wdev.wiphy, ndev, + WLAN_REASON_DEAUTH_LEAVING); + break; + case QTNF_STA_CONNECTED: + cfg80211_disconnected(vif->netdev, + WLAN_REASON_DEAUTH_LEAVING, + NULL, 0, 1, GFP_KERNEL); + qtnf_disconnect(vif->wdev.wiphy, ndev, + WLAN_REASON_DEAUTH_LEAVING); + break; + } + + vif->sta_state = QTNF_STA_DISCONNECTED; + qtnf_scan_done(mac, true); + } +} + +void qtnf_cfg80211_vif_reset(struct qtnf_vif *vif) +{ + if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { + switch (vif->sta_state) { + case QTNF_STA_CONNECTING: + cfg80211_connect_result(vif->netdev, + vif->bss_cfg.bssid, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + break; + case QTNF_STA_CONNECTED: + cfg80211_disconnected(vif->netdev, + WLAN_REASON_DEAUTH_LEAVING, + NULL, 0, 1, GFP_KERNEL); + break; + case QTNF_STA_DISCONNECTED: + break; + } + } + + cfg80211_shutdown_all_interfaces(vif->wdev.wiphy); + vif->sta_state = QTNF_STA_DISCONNECTED; +} + +void qtnf_band_init_rates(struct ieee80211_supported_band *band) +{ + switch (band->band) { + case NL80211_BAND_2GHZ: + band->bitrates = qtnf_rates_2g; + band->n_bitrates = ARRAY_SIZE(qtnf_rates_2g); + break; + case NL80211_BAND_5GHZ: + band->bitrates = qtnf_rates_5g; + band->n_bitrates = ARRAY_SIZE(qtnf_rates_5g); + break; + default: + band->bitrates = NULL; + band->n_bitrates = 0; + break; + } +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h new file mode 100644 index 000000000000..5bd33124a7c8 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_CFG80211_H_ +#define _QTN_FMAC_CFG80211_H_ + +#include + +#include "core.h" + +int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac); +int qtnf_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); +void qtnf_cfg80211_vif_reset(struct qtnf_vif *vif); +void qtnf_band_init_rates(struct ieee80211_supported_band *band); +void qtnf_band_setup_htvht_caps(struct qtnf_mac_info *macinfo, + struct ieee80211_supported_band *band); + +static inline void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted) +{ + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + + if (mac->scan_req) { + cfg80211_scan_done(mac->scan_req, &info); + mac->scan_req = NULL; + } +} + +#endif /* _QTN_FMAC_CFG80211_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c new file mode 100644 index 000000000000..f0a0cfa7d8a1 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -0,0 +1,1982 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +#include "cfg80211.h" +#include "core.h" +#include "qlink.h" +#include "qlink_util.h" +#include "bus.h" +#include "commands.h" + +static int qtnf_cmd_check_reply_header(const struct qlink_resp *resp, + u16 cmd_id, u8 mac_id, u8 vif_id, + size_t resp_size) +{ + if (unlikely(le16_to_cpu(resp->cmd_id) != cmd_id)) { + pr_warn("VIF%u.%u CMD%x: bad cmd_id in response: 0x%.4X\n", + mac_id, vif_id, cmd_id, le16_to_cpu(resp->cmd_id)); + return -EINVAL; + } + + if (unlikely(resp->macid != mac_id)) { + pr_warn("VIF%u.%u CMD%x: bad MAC in response: %u\n", + mac_id, vif_id, cmd_id, resp->macid); + return -EINVAL; + } + + if (unlikely(resp->vifid != vif_id)) { + pr_warn("VIF%u.%u CMD%x: bad VIF in response: %u\n", + mac_id, vif_id, cmd_id, resp->vifid); + return -EINVAL; + } + + if (unlikely(le16_to_cpu(resp->mhdr.len) < resp_size)) { + pr_warn("VIF%u.%u CMD%x: bad response size %u < %zu\n", + mac_id, vif_id, cmd_id, + le16_to_cpu(resp->mhdr.len), resp_size); + return -ENOSPC; + } + + return 0; +} + +static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, + struct sk_buff *cmd_skb, + struct sk_buff **response_skb, + u16 *result_code, + size_t const_resp_size, + size_t *var_resp_size) +{ + struct qlink_cmd *cmd; + const struct qlink_resp *resp; + struct sk_buff *resp_skb = NULL; + u16 cmd_id; + u8 mac_id, vif_id; + int ret; + + cmd = (struct qlink_cmd *)cmd_skb->data; + cmd_id = le16_to_cpu(cmd->cmd_id); + mac_id = cmd->macid; + vif_id = cmd->vifid; + cmd->mhdr.len = cpu_to_le16(cmd_skb->len); + + if (unlikely(bus->fw_state != QTNF_FW_STATE_ACTIVE && + le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT)) { + pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n", + mac_id, vif_id, le16_to_cpu(cmd->cmd_id), + bus->fw_state); + return -ENODEV; + } + + pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, + le16_to_cpu(cmd->cmd_id)); + + ret = qtnf_trans_send_cmd_with_resp(bus, cmd_skb, &resp_skb); + + if (unlikely(ret)) + goto out; + + resp = (const struct qlink_resp *)resp_skb->data; + ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id, + const_resp_size); + + if (unlikely(ret)) + goto out; + + if (likely(result_code)) + *result_code = le16_to_cpu(resp->result); + + /* Return length of variable part of response */ + if (response_skb && var_resp_size) + *var_resp_size = le16_to_cpu(resp->mhdr.len) - const_resp_size; + +out: + if (response_skb) + *response_skb = resp_skb; + else + consume_skb(resp_skb); + + return ret; +} + +static inline int qtnf_cmd_send(struct qtnf_bus *bus, + struct sk_buff *cmd_skb, + u16 *result_code) +{ + return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, result_code, + sizeof(struct qlink_resp), NULL); +} + +static struct sk_buff *qtnf_cmd_alloc_new_cmdskb(u8 macid, u8 vifid, u16 cmd_no, + size_t cmd_size) +{ + struct qlink_cmd *cmd; + struct sk_buff *cmd_skb; + + cmd_skb = __dev_alloc_skb(sizeof(*cmd) + + QTNF_MAX_CMD_BUF_SIZE, GFP_KERNEL); + if (unlikely(!cmd_skb)) { + pr_err("VIF%u.%u CMD %u: alloc failed\n", macid, vifid, cmd_no); + return NULL; + } + + memset(skb_put(cmd_skb, cmd_size), 0, cmd_size); + + cmd = (struct qlink_cmd *)cmd_skb->data; + cmd->mhdr.len = cpu_to_le16(cmd_skb->len); + cmd->mhdr.type = cpu_to_le16(QLINK_MSG_TYPE_CMD); + cmd->cmd_id = cpu_to_le16(cmd_no); + cmd->macid = macid; + cmd->vifid = vifid; + + return cmd_skb; +} + +int qtnf_cmd_send_start_ap(struct qtnf_vif *vif) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_START_AP, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + + vif->bss_status |= QTNF_STATE_AP_START; + netif_carrier_on(vif->netdev); + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_regulatory_config(struct qtnf_wmac *mac, const char *alpha2) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, + QLINK_CMD_REG_REGION, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_COUNTRY, alpha2, + QTNF_MAX_ALPHA_LEN); + + ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + + memcpy(mac->bus->hw_info.alpha2_code, alpha2, + sizeof(mac->bus->hw_info.alpha2_code)); +out: + return ret; +} + +int qtnf_cmd_send_config_ap(struct qtnf_vif *vif) +{ + struct sk_buff *cmd_skb; + struct qtnf_bss_config *bss_cfg = &vif->bss_cfg; + struct cfg80211_chan_def *chandef = &bss_cfg->chandef; + struct qlink_tlv_channel *qchan; + struct qlink_auth_encr aen; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + int i; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_CONFIG_AP, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, bss_cfg->ssid, + bss_cfg->ssid_len); + qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_BCN_PERIOD, + bss_cfg->bcn_period); + qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_DTIM, bss_cfg->dtim); + + qchan = (struct qlink_tlv_channel *)skb_put(cmd_skb, sizeof(*qchan)); + + memset(qchan, 0, sizeof(*qchan)); + qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); + qchan->hdr.len = cpu_to_le16(sizeof(*qchan) - + sizeof(struct qlink_tlv_hdr)); + qchan->hw_value = cpu_to_le16( + ieee80211_frequency_to_channel(chandef->chan->center_freq)); + + memset(&aen, 0, sizeof(aen)); + aen.auth_type = bss_cfg->auth_type; + aen.privacy = !!bss_cfg->privacy; + aen.mfp = bss_cfg->mfp; + aen.wpa_versions = cpu_to_le32(bss_cfg->crypto.wpa_versions); + aen.cipher_group = cpu_to_le32(bss_cfg->crypto.cipher_group); + aen.n_ciphers_pairwise = cpu_to_le32( + bss_cfg->crypto.n_ciphers_pairwise); + for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++) + aen.ciphers_pairwise[i] = cpu_to_le32( + bss_cfg->crypto.ciphers_pairwise[i]); + aen.n_akm_suites = cpu_to_le32( + bss_cfg->crypto.n_akm_suites); + for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) + aen.akm_suites[i] = cpu_to_le32( + bss_cfg->crypto.akm_suites[i]); + aen.control_port = bss_cfg->crypto.control_port; + aen.control_port_no_encrypt = + bss_cfg->crypto.control_port_no_encrypt; + aen.control_port_ethertype = cpu_to_le16(be16_to_cpu( + bss_cfg->crypto.control_port_ethertype)); + + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_CRYPTO, (u8 *)&aen, + sizeof(aen)); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + + vif->bss_status |= QTNF_STATE_AP_CONFIG; + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_STOP_AP, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + + vif->bss_status &= ~QTNF_STATE_AP_START; + vif->bss_status &= ~QTNF_STATE_AP_CONFIG; + + netif_carrier_off(vif->netdev); + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_mgmt_frame_register *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_REGISTER_MGMT, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_mgmt_frame_register *)cmd_skb->data; + cmd->frame_type = cpu_to_le16(frame_type); + cmd->do_register = reg; + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, + u16 freq, const u8 *buf, size_t len) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_mgmt_frame_tx *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) { + pr_warn("VIF%u.%u: frame is too big: %zu\n", vif->mac->macid, + vif->vifid, len); + return -E2BIG; + } + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_SEND_MGMT_FRAME, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_mgmt_frame_tx *)cmd_skb->data; + cmd->cookie = cpu_to_le32(cookie); + cmd->freq = cpu_to_le16(freq); + cmd->flags = cpu_to_le16(flags); + + if (len && buf) + qtnf_cmd_skb_put_buffer(cmd_skb, buf, len); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type, + const u8 *buf, size_t len) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_mgmt_append_ie *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) { + pr_warn("VIF%u.%u: %u frame is too big: %zu\n", vif->mac->macid, + vif->vifid, frame_type, len); + return -E2BIG; + } + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_MGMT_SET_APPIE, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_mgmt_append_ie *)cmd_skb->data; + cmd->type = frame_type; + cmd->flags = 0; + + /* If len == 0 then IE buf for specified frame type + * should be cleared on EP. + */ + if (len && buf) + qtnf_cmd_skb_put_buffer(cmd_skb, buf, len); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u frame %u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, frame_type, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +static void +qtnf_sta_info_parse_basic_counters(struct station_info *sinfo, + const struct qlink_sta_stat_basic_counters *counters) +{ + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES) | + BIT(NL80211_STA_INFO_TX_BYTES); + sinfo->rx_bytes = get_unaligned_le64(&counters->rx_bytes); + sinfo->tx_bytes = get_unaligned_le64(&counters->tx_bytes); + + sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) | + BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_BEACON_RX); + sinfo->rx_packets = get_unaligned_le32(&counters->rx_packets); + sinfo->tx_packets = get_unaligned_le32(&counters->tx_packets); + sinfo->rx_beacon = get_unaligned_le64(&counters->rx_beacons); + + sinfo->filled |= BIT(NL80211_STA_INFO_RX_DROP_MISC) | + BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->rx_dropped_misc = get_unaligned_le32(&counters->rx_dropped); + sinfo->tx_failed = get_unaligned_le32(&counters->tx_failed); +} + +static void +qtnf_sta_info_parse_rate(struct rate_info *rate_dst, + const struct qlink_sta_info_rate *rate_src) +{ + rate_dst->legacy = get_unaligned_le16(&rate_src->rate) * 10; + + rate_dst->mcs = rate_src->mcs; + rate_dst->nss = rate_src->nss; + rate_dst->flags = 0; + + switch (rate_src->bw) { + case QLINK_STA_INFO_RATE_BW_5: + rate_dst->bw = RATE_INFO_BW_5; + break; + case QLINK_STA_INFO_RATE_BW_10: + rate_dst->bw = RATE_INFO_BW_10; + break; + case QLINK_STA_INFO_RATE_BW_20: + rate_dst->bw = RATE_INFO_BW_20; + break; + case QLINK_STA_INFO_RATE_BW_40: + rate_dst->bw = RATE_INFO_BW_40; + break; + case QLINK_STA_INFO_RATE_BW_80: + rate_dst->bw = RATE_INFO_BW_80; + break; + case QLINK_STA_INFO_RATE_BW_160: + rate_dst->bw = RATE_INFO_BW_160; + break; + default: + rate_dst->bw = 0; + break; + } + + if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_HT_MCS) + rate_dst->flags |= RATE_INFO_FLAGS_MCS; + else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_VHT_MCS) + rate_dst->flags |= RATE_INFO_FLAGS_VHT_MCS; +} + +static void +qtnf_sta_info_parse_flags(struct nl80211_sta_flag_update *dst, + const struct qlink_sta_info_state *src) +{ + u32 mask, value; + + dst->mask = 0; + dst->set = 0; + + mask = le32_to_cpu(src->mask); + value = le32_to_cpu(src->value); + + if (mask & QLINK_STA_FLAG_AUTHORIZED) { + dst->mask |= BIT(NL80211_STA_FLAG_AUTHORIZED); + if (value & QLINK_STA_FLAG_AUTHORIZED) + dst->set |= BIT(NL80211_STA_FLAG_AUTHORIZED); + } + + if (mask & QLINK_STA_FLAG_SHORT_PREAMBLE) { + dst->mask |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); + if (value & QLINK_STA_FLAG_SHORT_PREAMBLE) + dst->set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); + } + + if (mask & QLINK_STA_FLAG_WME) { + dst->mask |= BIT(NL80211_STA_FLAG_WME); + if (value & QLINK_STA_FLAG_WME) + dst->set |= BIT(NL80211_STA_FLAG_WME); + } + + if (mask & QLINK_STA_FLAG_MFP) { + dst->mask |= BIT(NL80211_STA_FLAG_MFP); + if (value & QLINK_STA_FLAG_MFP) + dst->set |= BIT(NL80211_STA_FLAG_MFP); + } + + if (mask & QLINK_STA_FLAG_AUTHENTICATED) { + dst->mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED); + if (value & QLINK_STA_FLAG_AUTHENTICATED) + dst->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); + } + + if (mask & QLINK_STA_FLAG_TDLS_PEER) { + dst->mask |= BIT(NL80211_STA_FLAG_TDLS_PEER); + if (value & QLINK_STA_FLAG_TDLS_PEER) + dst->set |= BIT(NL80211_STA_FLAG_TDLS_PEER); + } + + if (mask & QLINK_STA_FLAG_ASSOCIATED) { + dst->mask |= BIT(NL80211_STA_FLAG_ASSOCIATED); + if (value & QLINK_STA_FLAG_ASSOCIATED) + dst->set |= BIT(NL80211_STA_FLAG_ASSOCIATED); + } +} + +static void +qtnf_sta_info_parse_generic_info(struct station_info *sinfo, + const struct qlink_sta_info_generic *info) +{ + sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME) | + BIT(NL80211_STA_INFO_INACTIVE_TIME); + sinfo->connected_time = get_unaligned_le32(&info->connected_time); + sinfo->inactive_time = get_unaligned_le32(&info->inactive_time); + + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) | + BIT(NL80211_STA_INFO_SIGNAL_AVG); + sinfo->signal = info->rssi - 120; + sinfo->signal_avg = info->rssi_avg - QLINK_RSSI_OFFSET; + + if (info->rx_rate.rate) { + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); + qtnf_sta_info_parse_rate(&sinfo->rxrate, &info->rx_rate); + } + + if (info->tx_rate.rate) { + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + qtnf_sta_info_parse_rate(&sinfo->txrate, &info->tx_rate); + } + + sinfo->filled |= BIT(NL80211_STA_INFO_STA_FLAGS); + qtnf_sta_info_parse_flags(&sinfo->sta_flags, &info->state); +} + +static int qtnf_cmd_sta_info_parse(struct station_info *sinfo, + const u8 *payload, size_t payload_size) +{ + const struct qlink_sta_stat_basic_counters *counters; + const struct qlink_sta_info_generic *sta_info; + u16 tlv_type; + u16 tlv_value_len; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + sinfo->filled = 0; + + tlv = (const struct qlink_tlv_hdr *)payload; + while (payload_size >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + if (tlv_full_len > payload_size) { + pr_warn("malformed TLV 0x%.2X; LEN: %u\n", + tlv_type, tlv_value_len); + return -EINVAL; + } + switch (tlv_type) { + case QTN_TLV_ID_STA_BASIC_COUNTERS: + if (unlikely(tlv_value_len < sizeof(*counters))) { + pr_err("invalid TLV size %.4X: %u\n", + tlv_type, tlv_value_len); + break; + } + + counters = (void *)tlv->val; + qtnf_sta_info_parse_basic_counters(sinfo, counters); + break; + case QTN_TLV_ID_STA_GENERIC_INFO: + if (unlikely(tlv_value_len < sizeof(*sta_info))) + break; + + sta_info = (void *)tlv->val; + qtnf_sta_info_parse_generic_info(sinfo, sta_info); + break; + default: + pr_warn("unexpected TLV type: %.4X\n", tlv_type); + break; + } + payload_size -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (payload_size) { + pr_warn("malformed TLV buf; bytes left: %zu\n", payload_size); + return -EINVAL; + } + + return 0; +} + +int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac, + struct station_info *sinfo) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + struct qlink_cmd_get_sta_info *cmd; + const struct qlink_resp_get_sta_info *resp; + size_t var_resp_len; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_GET_STA_INFO, + sizeof(*cmd)); + + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_get_sta_info *)cmd_skb->data; + ether_addr_copy(cmd->sta_addr, sta_mac); + + ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, + &res_code, sizeof(*resp), + &var_resp_len); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + switch (res_code) { + case QLINK_CMD_RESULT_ENOTFOUND: + pr_warn("VIF%u.%u: %pM STA not found\n", + vif->mac->macid, vif->vifid, sta_mac); + ret = -ENOENT; + break; + default: + pr_err("VIF%u.%u: can't get info for %pM: %u\n", + vif->mac->macid, vif->vifid, sta_mac, res_code); + ret = -EFAULT; + break; + } + goto out; + } + + resp = (const struct qlink_resp_get_sta_info *)resp_skb->data; + + if (unlikely(!ether_addr_equal(sta_mac, resp->sta_addr))) { + pr_err("VIF%u.%u: wrong mac in reply: %pM != %pM\n", + vif->mac->macid, vif->vifid, resp->sta_addr, sta_mac); + ret = -EINVAL; + goto out; + } + + ret = qtnf_cmd_sta_info_parse(sinfo, resp->info, var_resp_len); + +out: + qtnf_bus_unlock(vif->mac->bus); + consume_skb(resp_skb); + + return ret; +} + +static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif, + enum nl80211_iftype iftype, + u8 *mac_addr, + enum qlink_cmd_type cmd_type) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + struct qlink_cmd_manage_intf *cmd; + const struct qlink_resp_manage_intf *resp; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + cmd_type, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data; + + switch (iftype) { + case NL80211_IFTYPE_AP: + cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP); + break; + case NL80211_IFTYPE_STATION: + cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION); + break; + default: + pr_err("VIF%u.%u: unsupported type %d\n", vif->mac->macid, + vif->vifid, iftype); + ret = -EINVAL; + goto out; + } + + if (mac_addr) + ether_addr_copy(cmd->intf_info.mac_addr, mac_addr); + else + eth_zero_addr(cmd->intf_info.mac_addr); + + ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, + &res_code, sizeof(*resp), NULL); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD %d failed: %u\n", vif->mac->macid, + vif->vifid, cmd_type, res_code); + ret = -EFAULT; + goto out; + } + + resp = (const struct qlink_resp_manage_intf *)resp_skb->data; + ether_addr_copy(vif->mac_addr, resp->intf_info.mac_addr); + +out: + qtnf_bus_unlock(vif->mac->bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_send_add_intf(struct qtnf_vif *vif, + enum nl80211_iftype iftype, u8 *mac_addr) +{ + return qtnf_cmd_send_add_change_intf(vif, iftype, mac_addr, + QLINK_CMD_ADD_INTF); +} + +int qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif, + enum nl80211_iftype iftype, u8 *mac_addr) +{ + return qtnf_cmd_send_add_change_intf(vif, iftype, mac_addr, + QLINK_CMD_CHANGE_INTF); +} + +int qtnf_cmd_send_del_intf(struct qtnf_vif *vif) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_manage_intf *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_DEL_INTF, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data; + + switch (vif->wdev.iftype) { + case NL80211_IFTYPE_AP: + cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP); + break; + case NL80211_IFTYPE_STATION: + cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION); + break; + default: + pr_warn("VIF%u.%u: unsupported iftype %d\n", vif->mac->macid, + vif->vifid, vif->wdev.iftype); + ret = -EINVAL; + goto out; + } + + eth_zero_addr(cmd->intf_info.mac_addr); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +static int +qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, + const struct qlink_resp_get_hw_info *resp) +{ + struct qtnf_hw_info *hwinfo = &bus->hw_info; + + hwinfo->num_mac = resp->num_mac; + hwinfo->mac_bitmap = resp->mac_bitmap; + hwinfo->fw_ver = le32_to_cpu(resp->fw_ver); + hwinfo->ql_proto_ver = le16_to_cpu(resp->ql_proto_ver); + memcpy(hwinfo->alpha2_code, resp->alpha2_code, + sizeof(hwinfo->alpha2_code)); + hwinfo->total_tx_chain = resp->total_tx_chain; + hwinfo->total_rx_chain = resp->total_rx_chain; + hwinfo->hw_capab = le32_to_cpu(resp->hw_capab); + + pr_info("fw_version=%d, MACs map %#x, alpha2=\"%c%c\", chains Tx=%u Rx=%u\n", + hwinfo->fw_ver, hwinfo->mac_bitmap, + hwinfo->alpha2_code[0], hwinfo->alpha2_code[1], + hwinfo->total_tx_chain, hwinfo->total_rx_chain); + + return 0; +} + +static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, + const u8 *tlv_buf, size_t tlv_buf_size) +{ + struct ieee80211_iface_limit *limits = NULL; + const struct qlink_iface_limit *limit_record; + size_t record_count = 0, rec = 0; + u16 tlv_type, tlv_value_len, mask; + struct qlink_iface_comb_num *comb; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + mac->macinfo.n_limits = 0; + + tlv = (const struct qlink_tlv_hdr *)tlv_buf; + while (tlv_buf_size >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + if (tlv_full_len > tlv_buf_size) { + pr_warn("MAC%u: malformed TLV 0x%.2X; LEN: %u\n", + mac->macid, tlv_type, tlv_value_len); + return -EINVAL; + } + + switch (tlv_type) { + case QTN_TLV_ID_NUM_IFACE_COMB: + if (unlikely(tlv_value_len != sizeof(*comb))) + return -EINVAL; + + comb = (void *)tlv->val; + record_count = le16_to_cpu(comb->iface_comb_num); + + mac->macinfo.n_limits = record_count; + /* free earlier iface limits memory */ + kfree(mac->macinfo.limits); + mac->macinfo.limits = + kzalloc(sizeof(*mac->macinfo.limits) * + record_count, GFP_KERNEL); + + if (unlikely(!mac->macinfo.limits)) + return -ENOMEM; + + limits = mac->macinfo.limits; + break; + case QTN_TLV_ID_IFACE_LIMIT: + if (unlikely(!limits)) { + pr_warn("MAC%u: limits are not inited\n", + mac->macid); + return -EINVAL; + } + + if (unlikely(tlv_value_len != sizeof(*limit_record))) { + pr_warn("MAC%u: record size mismatch\n", + mac->macid); + return -EINVAL; + } + + limit_record = (void *)tlv->val; + limits[rec].max = le16_to_cpu(limit_record->max_num); + mask = le16_to_cpu(limit_record->type_mask); + limits[rec].types = qlink_iface_type_mask_to_nl(mask); + /* only AP and STA modes are supported */ + limits[rec].types &= BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION); + + pr_debug("MAC%u: MAX: %u; TYPES: %.4X\n", mac->macid, + limits[rec].max, limits[rec].types); + + if (limits[rec].types) + rec++; + break; + default: + break; + } + tlv_buf_size -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (tlv_buf_size) { + pr_warn("MAC%u: malformed TLV buf; bytes left: %zu\n", + mac->macid, tlv_buf_size); + return -EINVAL; + } + + if (mac->macinfo.n_limits != rec) { + pr_err("MAC%u: combination mismatch: reported=%zu parsed=%zu\n", + mac->macid, mac->macinfo.n_limits, rec); + return -EINVAL; + } + + return 0; +} + +static void +qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac, + const struct qlink_resp_get_mac_info *resp_info) +{ + struct qtnf_mac_info *mac_info; + struct qtnf_vif *vif; + + mac_info = &mac->macinfo; + + mac_info->bands_cap = resp_info->bands_cap; + mac_info->phymode_cap = resp_info->phymode_cap; + memcpy(&mac_info->dev_mac, &resp_info->dev_mac, + sizeof(mac_info->dev_mac)); + + ether_addr_copy(mac->macaddr, mac_info->dev_mac); + + vif = qtnf_mac_get_base_vif(mac); + if (vif) + ether_addr_copy(vif->mac_addr, mac->macaddr); + else + pr_err("could not get valid base vif\n"); + + mac_info->num_tx_chain = resp_info->num_tx_chain; + mac_info->num_rx_chain = resp_info->num_rx_chain; + + mac_info->max_ap_assoc_sta = le16_to_cpu(resp_info->max_ap_assoc_sta); + mac_info->radar_detect_widths = + qlink_chan_width_mask_to_nl(le16_to_cpu( + resp_info->radar_detect_widths)); + + memcpy(&mac_info->ht_cap, &resp_info->ht_cap, sizeof(mac_info->ht_cap)); + memcpy(&mac_info->vht_cap, &resp_info->vht_cap, + sizeof(mac_info->vht_cap)); +} + +static int +qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band, + struct qlink_resp_get_chan_info *resp, + size_t payload_len) +{ + u16 tlv_type; + size_t tlv_len; + const struct qlink_tlv_hdr *tlv; + const struct qlink_tlv_channel *qchan; + struct ieee80211_channel *chan; + unsigned int chidx = 0; + u32 qflags; + + kfree(band->channels); + band->channels = NULL; + + band->n_channels = resp->num_chans; + if (band->n_channels == 0) + return 0; + + band->channels = kcalloc(band->n_channels, sizeof(*chan), GFP_KERNEL); + if (!band->channels) { + band->n_channels = 0; + return -ENOMEM; + } + + tlv = (struct qlink_tlv_hdr *)resp->info; + + while (payload_len >= sizeof(*tlv)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_len = le16_to_cpu(tlv->len) + sizeof(*tlv); + + if (tlv_len > payload_len) { + pr_warn("malformed TLV 0x%.2X; LEN: %zu\n", + tlv_type, tlv_len); + goto error_ret; + } + + switch (tlv_type) { + case QTN_TLV_ID_CHANNEL: + if (unlikely(tlv_len != sizeof(*qchan))) { + pr_err("invalid channel TLV len %zu\n", + tlv_len); + goto error_ret; + } + + if (chidx == band->n_channels) { + pr_err("too many channel TLVs\n"); + goto error_ret; + } + + qchan = (const struct qlink_tlv_channel *)tlv; + chan = &band->channels[chidx++]; + qflags = le32_to_cpu(qchan->flags); + + chan->hw_value = le16_to_cpu(qchan->hw_value); + chan->band = band->band; + chan->center_freq = le16_to_cpu(qchan->center_freq); + chan->max_antenna_gain = (int)qchan->max_antenna_gain; + chan->max_power = (int)qchan->max_power; + chan->max_reg_power = (int)qchan->max_reg_power; + chan->beacon_found = qchan->beacon_found; + chan->dfs_cac_ms = le32_to_cpu(qchan->dfs_cac_ms); + chan->flags = 0; + + if (qflags & QLINK_CHAN_DISABLED) + chan->flags |= IEEE80211_CHAN_DISABLED; + + if (qflags & QLINK_CHAN_NO_IR) + chan->flags |= IEEE80211_CHAN_NO_IR; + + if (qflags & QLINK_CHAN_NO_HT40PLUS) + chan->flags |= IEEE80211_CHAN_NO_HT40PLUS; + + if (qflags & QLINK_CHAN_NO_HT40MINUS) + chan->flags |= IEEE80211_CHAN_NO_HT40MINUS; + + if (qflags & QLINK_CHAN_NO_OFDM) + chan->flags |= IEEE80211_CHAN_NO_OFDM; + + if (qflags & QLINK_CHAN_NO_80MHZ) + chan->flags |= IEEE80211_CHAN_NO_80MHZ; + + if (qflags & QLINK_CHAN_NO_160MHZ) + chan->flags |= IEEE80211_CHAN_NO_160MHZ; + + if (qflags & QLINK_CHAN_INDOOR_ONLY) + chan->flags |= IEEE80211_CHAN_INDOOR_ONLY; + + if (qflags & QLINK_CHAN_IR_CONCURRENT) + chan->flags |= IEEE80211_CHAN_IR_CONCURRENT; + + if (qflags & QLINK_CHAN_NO_20MHZ) + chan->flags |= IEEE80211_CHAN_NO_20MHZ; + + if (qflags & QLINK_CHAN_NO_10MHZ) + chan->flags |= IEEE80211_CHAN_NO_10MHZ; + + if (qflags & QLINK_CHAN_RADAR) { + chan->flags |= IEEE80211_CHAN_RADAR; + chan->dfs_state_entered = jiffies; + + if (qchan->dfs_state == QLINK_DFS_USABLE) + chan->dfs_state = NL80211_DFS_USABLE; + else if (qchan->dfs_state == + QLINK_DFS_AVAILABLE) + chan->dfs_state = NL80211_DFS_AVAILABLE; + else + chan->dfs_state = + NL80211_DFS_UNAVAILABLE; + } + + pr_debug("chan=%d flags=%#x max_pow=%d max_reg_pow=%d\n", + chan->hw_value, chan->flags, chan->max_power, + chan->max_reg_power); + break; + default: + pr_warn("unknown TLV type: %#x\n", tlv_type); + break; + } + + payload_len -= tlv_len; + tlv = (struct qlink_tlv_hdr *)((u8 *)tlv + tlv_len); + } + + if (payload_len) { + pr_err("malformed TLV buf; bytes left: %zu\n", payload_len); + goto error_ret; + } + + if (band->n_channels != chidx) { + pr_err("channel count mismatch: reported=%d, parsed=%d\n", + band->n_channels, chidx); + goto error_ret; + } + + return 0; + +error_ret: + kfree(band->channels); + band->channels = NULL; + band->n_channels = 0; + + return -EINVAL; +} + +static int qtnf_cmd_resp_proc_phy_params(struct qtnf_wmac *mac, + const u8 *payload, size_t payload_len) +{ + struct qtnf_mac_info *mac_info; + struct qlink_tlv_frag_rts_thr *phy_thr; + struct qlink_tlv_rlimit *limit; + struct qlink_tlv_cclass *class; + u16 tlv_type; + u16 tlv_value_len; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + mac_info = &mac->macinfo; + + tlv = (struct qlink_tlv_hdr *)payload; + while (payload_len >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + + if (tlv_full_len > payload_len) { + pr_warn("MAC%u: malformed TLV 0x%.2X; LEN: %u\n", + mac->macid, tlv_type, tlv_value_len); + return -EINVAL; + } + + switch (tlv_type) { + case QTN_TLV_ID_FRAG_THRESH: + phy_thr = (void *)tlv; + mac_info->frag_thr = (u32)le16_to_cpu(phy_thr->thr); + break; + case QTN_TLV_ID_RTS_THRESH: + phy_thr = (void *)tlv; + mac_info->rts_thr = (u32)le16_to_cpu(phy_thr->thr); + break; + case QTN_TLV_ID_SRETRY_LIMIT: + limit = (void *)tlv; + mac_info->sretry_limit = limit->rlimit; + break; + case QTN_TLV_ID_LRETRY_LIMIT: + limit = (void *)tlv; + mac_info->lretry_limit = limit->rlimit; + break; + case QTN_TLV_ID_COVERAGE_CLASS: + class = (void *)tlv; + mac_info->coverage_class = class->cclass; + break; + default: + pr_err("MAC%u: Unknown TLV type: %#x\n", mac->macid, + le16_to_cpu(tlv->type)); + break; + } + + payload_len -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (payload_len) { + pr_warn("MAC%u: malformed TLV buf; bytes left: %zu\n", + mac->macid, payload_len); + return -EINVAL; + } + + return 0; +} + +int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + const struct qlink_resp_get_mac_info *resp; + size_t var_data_len; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, + QLINK_CMD_MAC_INFO, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + sizeof(*resp), &var_data_len); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + + resp = (const struct qlink_resp_get_mac_info *)resp_skb->data; + qtnf_cmd_resp_proc_mac_info(mac, resp); + ret = qtnf_parse_variable_mac_info(mac, resp->var_info, var_data_len); + +out: + qtnf_bus_unlock(mac->bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_get_hw_info(struct qtnf_bus *bus) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + const struct qlink_resp_get_hw_info *resp; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, + QLINK_CMD_GET_HW_INFO, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code, + sizeof(*resp), NULL); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("cmd exec failed: 0x%.4X\n", res_code); + ret = -EFAULT; + goto out; + } + + resp = (const struct qlink_resp_get_hw_info *)resp_skb->data; + ret = qtnf_cmd_resp_proc_hw_info(bus, resp); + +out: + qtnf_bus_unlock(bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac, + struct ieee80211_supported_band *band) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + size_t info_len; + struct qlink_cmd_chans_info_get *cmd; + struct qlink_resp_get_chan_info *resp; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + u8 qband; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, + QLINK_CMD_CHANS_INFO_GET, + sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + switch (band->band) { + case NL80211_BAND_2GHZ: + qband = QLINK_BAND_2GHZ; + break; + case NL80211_BAND_5GHZ: + qband = QLINK_BAND_5GHZ; + break; + case NL80211_BAND_60GHZ: + qband = QLINK_BAND_60GHZ; + break; + default: + return -EINVAL; + } + + cmd = (struct qlink_cmd_chans_info_get *)cmd_skb->data; + cmd->band = qband; + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + sizeof(*resp), &info_len); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + + resp = (struct qlink_resp_get_chan_info *)resp_skb->data; + if (resp->band != qband) { + pr_err("MAC%u: reply band %u != cmd band %u\n", mac->macid, + resp->band, qband); + ret = -EINVAL; + goto out; + } + + ret = qtnf_cmd_resp_fill_channels_info(band, resp, info_len); + +out: + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + size_t response_size; + struct qlink_resp_phy_params *resp; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, + QLINK_CMD_PHY_PARAMS_GET, + sizeof(struct qlink_cmd)); + if (!cmd_skb) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + sizeof(*resp), &response_size); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + + resp = (struct qlink_resp_phy_params *)resp_skb->data; + ret = qtnf_cmd_resp_proc_phy_params(mac, resp->info, response_size); + +out: + qtnf_bus_unlock(mac->bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed) +{ + struct wiphy *wiphy = priv_to_wiphy(mac); + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, + QLINK_CMD_PHY_PARAMS_SET, + sizeof(struct qlink_cmd)); + if (!cmd_skb) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_FRAG_THRESH, + wiphy->frag_threshold); + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_RTS_THRESH, + wiphy->rts_threshold); + if (changed & WIPHY_PARAM_COVERAGE_CLASS) + qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS, + wiphy->coverage_class); + + ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(mac->bus); + return ret; +} + +int qtnf_cmd_send_init_fw(struct qtnf_bus *bus) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, + QLINK_CMD_FW_INIT, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send(bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("cmd exec failed: 0x%.4X\n", res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(bus); + return ret; +} + +void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus) +{ + struct sk_buff *cmd_skb; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, + QLINK_CMD_FW_DEINIT, + sizeof(struct qlink_cmd)); + if (!cmd_skb) + return; + + qtnf_bus_lock(bus); + + qtnf_cmd_send(bus, cmd_skb, NULL); + + qtnf_bus_unlock(bus); +} + +int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, + const u8 *mac_addr, struct key_params *params) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_add_key *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_ADD_KEY, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_add_key *)cmd_skb->data; + + if (mac_addr) + ether_addr_copy(cmd->addr, mac_addr); + else + eth_broadcast_addr(cmd->addr); + + cmd->cipher = cpu_to_le32(params->cipher); + cmd->key_index = key_index; + cmd->pairwise = pairwise; + + if (params->key && params->key_len > 0) + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_KEY, + params->key, + params->key_len); + + if (params->seq && params->seq_len > 0) + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_SEQ, + params->seq, + params->seq_len); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", + vif->mac->macid, vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, + const u8 *mac_addr) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_del_key *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_DEL_KEY, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_del_key *)cmd_skb->data; + + if (mac_addr) + ether_addr_copy(cmd->addr, mac_addr); + else + eth_broadcast_addr(cmd->addr); + + cmd->key_index = key_index; + cmd->pairwise = pairwise; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", + vif->mac->macid, vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index, + bool unicast, bool multicast) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_set_def_key *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_SET_DEFAULT_KEY, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_set_def_key *)cmd_skb->data; + cmd->key_index = key_index; + cmd->unicast = unicast; + cmd->multicast = multicast; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_set_def_mgmt_key *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_SET_DEFAULT_MGMT_KEY, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_set_def_mgmt_key *)cmd_skb->data; + cmd->key_index = key_index; + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +static u32 qtnf_encode_sta_flags(u32 flags) +{ + u32 code = 0; + + if (flags & BIT(NL80211_STA_FLAG_AUTHORIZED)) + code |= QLINK_STA_FLAG_AUTHORIZED; + if (flags & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) + code |= QLINK_STA_FLAG_SHORT_PREAMBLE; + if (flags & BIT(NL80211_STA_FLAG_WME)) + code |= QLINK_STA_FLAG_WME; + if (flags & BIT(NL80211_STA_FLAG_MFP)) + code |= QLINK_STA_FLAG_MFP; + if (flags & BIT(NL80211_STA_FLAG_AUTHENTICATED)) + code |= QLINK_STA_FLAG_AUTHENTICATED; + if (flags & BIT(NL80211_STA_FLAG_TDLS_PEER)) + code |= QLINK_STA_FLAG_TDLS_PEER; + if (flags & BIT(NL80211_STA_FLAG_ASSOCIATED)) + code |= QLINK_STA_FLAG_ASSOCIATED; + return code; +} + +int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, + struct station_parameters *params) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_change_sta *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_CHANGE_STA, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_change_sta *)cmd_skb->data; + ether_addr_copy(cmd->sta_addr, mac); + cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags( + params->sta_flags_mask)); + cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags( + params->sta_flags_set)); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_del_sta(struct qtnf_vif *vif, + struct station_del_parameters *params) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_del_sta *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_DEL_STA, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_del_sta *)cmd_skb->data; + + if (params->mac) + ether_addr_copy(cmd->sta_addr, params->mac); + else + eth_broadcast_addr(cmd->sta_addr); /* flush all stations */ + + cmd->subtype = params->subtype; + cmd->reason_code = cpu_to_le16(params->reason_code); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } + +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_scan(struct qtnf_wmac *mac) +{ + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + struct ieee80211_channel *sc; + struct cfg80211_scan_request *scan_req = mac->scan_req; + struct qlink_tlv_channel *qchan; + int n_channels; + int count = 0; + int ret; + u32 flags; + + if (scan_req->n_ssids > QTNF_MAX_SSID_LIST_LENGTH) { + pr_err("MAC%u: too many SSIDs in scan request\n", mac->macid); + return -EINVAL; + } + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, + QLINK_CMD_SCAN, + sizeof(struct qlink_cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + if (scan_req->n_ssids != 0) { + while (count < scan_req->n_ssids) { + qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, + scan_req->ssids[count].ssid, + scan_req->ssids[count].ssid_len); + count++; + } + } + + if (scan_req->ie_len != 0) + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_IE_SET, + scan_req->ie, + scan_req->ie_len); + + if (scan_req->n_channels) { + n_channels = scan_req->n_channels; + count = 0; + + while (n_channels != 0) { + sc = scan_req->channels[count]; + if (sc->flags & IEEE80211_CHAN_DISABLED) { + n_channels--; + continue; + } + + pr_debug("MAC%u: scan chan=%d, freq=%d, flags=%#x\n", + mac->macid, sc->hw_value, sc->center_freq, + sc->flags); + qchan = (struct qlink_tlv_channel *) + skb_put(cmd_skb, sizeof(*qchan)); + memset(qchan, 0, sizeof(*qchan)); + flags = 0; + + qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); + qchan->hdr.len = cpu_to_le16(sizeof(*qchan) - + sizeof(struct qlink_tlv_hdr)); + qchan->center_freq = cpu_to_le16(sc->center_freq); + qchan->hw_value = cpu_to_le16(sc->hw_value); + + if (sc->flags & IEEE80211_CHAN_NO_IR) + flags |= QLINK_CHAN_NO_IR; + + if (sc->flags & IEEE80211_CHAN_RADAR) + flags |= QLINK_CHAN_RADAR; + + qchan->flags = cpu_to_le32(flags); + n_channels--; + count++; + } + } + + ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + pr_debug("MAC%u: scan started\n", mac->macid); + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); + ret = -EFAULT; + goto out; + } +out: + qtnf_bus_unlock(mac->bus); + return ret; +} + +int qtnf_cmd_send_connect(struct qtnf_vif *vif, + struct cfg80211_connect_params *sme) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_connect *cmd; + struct qtnf_bss_config *bss_cfg = &vif->bss_cfg; + struct qlink_auth_encr aen; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + int i; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_CONNECT, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_connect *)cmd_skb->data; + + ether_addr_copy(cmd->bssid, bss_cfg->bssid); + + if (bss_cfg->chandef.chan) + cmd->freq = cpu_to_le16(bss_cfg->chandef.chan->center_freq); + + cmd->bg_scan_period = cpu_to_le16(bss_cfg->bg_scan_period); + + memset(&aen, 0, sizeof(aen)); + aen.auth_type = bss_cfg->auth_type; + aen.privacy = !!bss_cfg->privacy; + aen.mfp = bss_cfg->mfp; + aen.wpa_versions = cpu_to_le32(bss_cfg->crypto.wpa_versions); + aen.cipher_group = cpu_to_le32(bss_cfg->crypto.cipher_group); + aen.n_ciphers_pairwise = cpu_to_le32( + bss_cfg->crypto.n_ciphers_pairwise); + + for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++) + aen.ciphers_pairwise[i] = cpu_to_le32( + bss_cfg->crypto.ciphers_pairwise[i]); + + aen.n_akm_suites = cpu_to_le32(bss_cfg->crypto.n_akm_suites); + + for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) + aen.akm_suites[i] = cpu_to_le32( + bss_cfg->crypto.akm_suites[i]); + + aen.control_port = bss_cfg->crypto.control_port; + aen.control_port_no_encrypt = + bss_cfg->crypto.control_port_no_encrypt; + aen.control_port_ethertype = cpu_to_le16(be16_to_cpu( + bss_cfg->crypto.control_port_ethertype)); + + qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, bss_cfg->ssid, + bss_cfg->ssid_len); + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_CRYPTO, (u8 *)&aen, + sizeof(aen)); + + if (sme->ie_len != 0) + qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_IE_SET, + sme->ie, + sme->ie_len); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_disconnect *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_DISCONNECT, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(vif->mac->bus); + + cmd = (struct qlink_cmd_disconnect *)cmd_skb->data; + cmd->reason = cpu_to_le16(reason_code); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} + +int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up) +{ + struct sk_buff *cmd_skb; + struct qlink_cmd_updown *cmd; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_UPDOWN_INTF, + sizeof(*cmd)); + if (unlikely(!cmd_skb)) + return -ENOMEM; + + cmd = (struct qlink_cmd_updown *)cmd_skb->data; + cmd->if_up = !!up; + + qtnf_bus_lock(vif->mac->bus); + + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, + vif->vifid, res_code); + ret = -EFAULT; + goto out; + } +out: + qtnf_bus_unlock(vif->mac->bus); + return ret; +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.h b/drivers/net/wireless/quantenna/qtnfmac/commands.h new file mode 100644 index 000000000000..6c51854ef5e7 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 Quantenna Communications, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef QLINK_COMMANDS_H_ +#define QLINK_COMMANDS_H_ + +#include + +#include "core.h" +#include "bus.h" + +int qtnf_cmd_send_init_fw(struct qtnf_bus *bus); +void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus); +int qtnf_cmd_get_hw_info(struct qtnf_bus *bus); +int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac); +int qtnf_cmd_send_add_intf(struct qtnf_vif *vif, enum nl80211_iftype iftype, + u8 *mac_addr); +int qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif, + enum nl80211_iftype iftype, u8 *mac_addr); +int qtnf_cmd_send_del_intf(struct qtnf_vif *vif); +int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac, + struct ieee80211_supported_band *band); +int qtnf_cmd_send_regulatory_config(struct qtnf_wmac *mac, const char *alpha2); +int qtnf_cmd_send_config_ap(struct qtnf_vif *vif); +int qtnf_cmd_send_start_ap(struct qtnf_vif *vif); +int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif); +int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg); +int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, + u16 freq, const u8 *buf, size_t len); +int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type, + const u8 *buf, size_t len); +int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac, + struct station_info *sinfo); +int qtnf_cmd_send_phy_params(struct qtnf_wmac *mac, u16 cmd_action, + void *data_buf); +int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, + const u8 *mac_addr, struct key_params *params); +int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, + const u8 *mac_addr); +int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index, + bool unicast, bool multicast); +int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index); +int qtnf_cmd_send_add_sta(struct qtnf_vif *vif, const u8 *mac, + struct station_parameters *params); +int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, + struct station_parameters *params); +int qtnf_cmd_send_del_sta(struct qtnf_vif *vif, + struct station_del_parameters *params); + +int qtnf_cmd_resp_parse(struct qtnf_bus *bus, struct sk_buff *resp_skb); +int qtnf_cmd_resp_check(const struct qtnf_vif *vif, + const struct sk_buff *resp_skb, u16 cmd_id, + u16 *result, const u8 **payload, size_t *payload_size); +int qtnf_cmd_send_scan(struct qtnf_wmac *mac); +int qtnf_cmd_send_connect(struct qtnf_vif *vif, + struct cfg80211_connect_params *sme); +int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, + u16 reason_code); +int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, + bool up); + +#endif /* QLINK_COMMANDS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c new file mode 100644 index 000000000000..c5ac252464f4 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#include "core.h" +#include "bus.h" +#include "trans.h" +#include "commands.h" +#include "cfg80211.h" +#include "event.h" +#include "util.h" + +#define QTNF_DMP_MAX_LEN 48 +#define QTNF_PRIMARY_VIF_IDX 0 + +struct qtnf_frame_meta_info { + u8 magic_s; + u8 ifidx; + u8 macid; + u8 magic_e; +} __packed; + +struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid) +{ + struct qtnf_wmac *mac = NULL; + + if (unlikely(macid >= QTNF_MAX_MAC)) { + pr_err("invalid MAC index %u\n", macid); + return NULL; + } + + mac = bus->mac[macid]; + + if (unlikely(!mac)) { + pr_err("MAC%u: not initialized\n", macid); + return NULL; + } + + return mac; +} + +/* Netdev handler for open. + */ +static int qtnf_netdev_open(struct net_device *ndev) +{ + netif_carrier_off(ndev); + qtnf_netdev_updown(ndev, 1); + return 0; +} + +/* Netdev handler for close. + */ +static int qtnf_netdev_close(struct net_device *ndev) +{ + netif_carrier_off(ndev); + qtnf_virtual_intf_cleanup(ndev); + qtnf_netdev_updown(ndev, 0); + return 0; +} + +/* Netdev handler for data transmission. + */ +static int +qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct qtnf_vif *vif; + struct qtnf_wmac *mac; + + vif = qtnf_netdev_get_priv(ndev); + + if (unlikely(skb->dev != ndev)) { + pr_err_ratelimited("invalid skb->dev"); + dev_kfree_skb_any(skb); + return 0; + } + + if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)) { + pr_err_ratelimited("%s: VIF not initialized\n", ndev->name); + dev_kfree_skb_any(skb); + return 0; + } + + mac = vif->mac; + if (unlikely(!mac)) { + pr_err_ratelimited("%s: NULL mac pointer", ndev->name); + dev_kfree_skb_any(skb); + return 0; + } + + if (!skb->len || (skb->len > ETH_FRAME_LEN)) { + pr_err_ratelimited("%s: invalid skb len %d\n", ndev->name, + skb->len); + dev_kfree_skb_any(skb); + ndev->stats.tx_dropped++; + return 0; + } + + /* tx path is enabled: reset vif timeout */ + vif->cons_tx_timeout_cnt = 0; + + return qtnf_bus_data_tx(mac->bus, skb); +} + +/* Netdev handler for getting stats. + */ +static struct net_device_stats *qtnf_netdev_get_stats(struct net_device *dev) +{ + return &dev->stats; +} + +/* Netdev handler for transmission timeout. + */ +static void qtnf_netdev_tx_timeout(struct net_device *ndev) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + struct qtnf_wmac *mac; + struct qtnf_bus *bus; + + if (unlikely(!vif || !vif->mac || !vif->mac->bus)) + return; + + mac = vif->mac; + bus = mac->bus; + + pr_warn("VIF%u.%u: Tx timeout- %lu\n", mac->macid, vif->vifid, jiffies); + + qtnf_bus_data_tx_timeout(bus, ndev); + ndev->stats.tx_errors++; + + if (++vif->cons_tx_timeout_cnt > QTNF_TX_TIMEOUT_TRSHLD) { + pr_err("Tx timeout threshold exceeded !\n"); + pr_err("schedule interface %s reset !\n", netdev_name(ndev)); + queue_work(bus->workqueue, &vif->reset_work); + } +} + +/* Network device ops handlers */ +const struct net_device_ops qtnf_netdev_ops = { + .ndo_open = qtnf_netdev_open, + .ndo_stop = qtnf_netdev_close, + .ndo_start_xmit = qtnf_netdev_hard_start_xmit, + .ndo_tx_timeout = qtnf_netdev_tx_timeout, + .ndo_get_stats = qtnf_netdev_get_stats, +}; + +static int qtnf_mac_init_single_band(struct wiphy *wiphy, + struct qtnf_wmac *mac, + enum nl80211_band band) +{ + int ret; + + wiphy->bands[band] = kzalloc(sizeof(*wiphy->bands[band]), GFP_KERNEL); + if (!wiphy->bands[band]) + return -ENOMEM; + + wiphy->bands[band]->band = band; + + ret = qtnf_cmd_get_mac_chan_info(mac, wiphy->bands[band]); + if (ret) { + pr_err("MAC%u: band %u: failed to get chans info: %d\n", + mac->macid, band, ret); + return ret; + } + + qtnf_band_init_rates(wiphy->bands[band]); + qtnf_band_setup_htvht_caps(&mac->macinfo, wiphy->bands[band]); + + return 0; +} + +static int qtnf_mac_init_bands(struct qtnf_wmac *mac) +{ + struct wiphy *wiphy = priv_to_wiphy(mac); + int ret = 0; + + if (mac->macinfo.bands_cap & QLINK_BAND_2GHZ) { + ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_2GHZ); + if (ret) + goto out; + } + + if (mac->macinfo.bands_cap & QLINK_BAND_5GHZ) { + ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_5GHZ); + if (ret) + goto out; + } + + if (mac->macinfo.bands_cap & QLINK_BAND_60GHZ) + ret = qtnf_mac_init_single_band(wiphy, mac, NL80211_BAND_60GHZ); + +out: + return ret; +} + +struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac) +{ + struct qtnf_vif *vif; + int i; + + for (i = 0; i < QTNF_MAX_INTF; i++) { + vif = &mac->iflist[i]; + if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) + return vif; + } + + return NULL; +} + +struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac) +{ + struct qtnf_vif *vif; + + vif = &mac->iflist[QTNF_PRIMARY_VIF_IDX]; + + if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) + return NULL; + + return vif; +} + +static void qtnf_vif_reset_handler(struct work_struct *work) +{ + struct qtnf_vif *vif = container_of(work, struct qtnf_vif, reset_work); + + rtnl_lock(); + + if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) { + rtnl_unlock(); + return; + } + + /* stop tx completely */ + netif_tx_stop_all_queues(vif->netdev); + if (netif_carrier_ok(vif->netdev)) + netif_carrier_off(vif->netdev); + + qtnf_cfg80211_vif_reset(vif); + + rtnl_unlock(); +} + +static void qtnf_mac_init_primary_intf(struct qtnf_wmac *mac) +{ + struct qtnf_vif *vif = &mac->iflist[QTNF_PRIMARY_VIF_IDX]; + + vif->wdev.iftype = NL80211_IFTYPE_AP; + vif->bss_priority = QTNF_DEF_BSS_PRIORITY; + vif->wdev.wiphy = priv_to_wiphy(mac); + INIT_WORK(&vif->reset_work, qtnf_vif_reset_handler); + vif->cons_tx_timeout_cnt = 0; +} + +static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus, + unsigned int macid) +{ + struct wiphy *wiphy; + struct qtnf_wmac *mac; + unsigned int i; + + wiphy = qtnf_wiphy_allocate(bus); + if (!wiphy) + return ERR_PTR(-ENOMEM); + + mac = wiphy_priv(wiphy); + + mac->macid = macid; + mac->bus = bus; + + for (i = 0; i < QTNF_MAX_INTF; i++) { + memset(&mac->iflist[i], 0, sizeof(struct qtnf_vif)); + mac->iflist[i].wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + mac->iflist[i].mac = mac; + mac->iflist[i].vifid = i; + qtnf_sta_list_init(&mac->iflist[i].sta_list); + } + + qtnf_mac_init_primary_intf(mac); + bus->mac[macid] = mac; + + return mac; +} + +int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif, + const char *name, unsigned char name_assign_type, + enum nl80211_iftype iftype) +{ + struct wiphy *wiphy = priv_to_wiphy(mac); + struct net_device *dev; + void *qdev_vif; + int ret; + + dev = alloc_netdev_mqs(sizeof(struct qtnf_vif *), name, + name_assign_type, ether_setup, 1, 1); + if (!dev) { + memset(&vif->wdev, 0, sizeof(vif->wdev)); + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return -ENOMEM; + } + + vif->netdev = dev; + + dev->netdev_ops = &qtnf_netdev_ops; + dev->destructor = free_netdev; + dev_net_set(dev, wiphy_net(wiphy)); + dev->ieee80211_ptr = &vif->wdev; + dev->ieee80211_ptr->iftype = iftype; + ether_addr_copy(dev->dev_addr, vif->mac_addr); + SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->watchdog_timeo = QTNF_DEF_WDOG_TIMEOUT; + dev->tx_queue_len = 100; + + qdev_vif = netdev_priv(dev); + *((void **)qdev_vif) = vif; + + SET_NETDEV_DEV(dev, mac->bus->dev); + + ret = register_netdevice(dev); + if (ret) { + free_netdev(dev); + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + } + + return ret; +} + +static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid) +{ + struct qtnf_wmac *mac; + struct wiphy *wiphy; + struct qtnf_vif *vif; + unsigned int i; + enum nl80211_band band; + + mac = bus->mac[macid]; + + if (!mac) + return; + + wiphy = priv_to_wiphy(mac); + + for (i = 0; i < QTNF_MAX_INTF; i++) { + vif = &mac->iflist[i]; + rtnl_lock(); + if (vif->netdev && + vif->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) { + qtnf_virtual_intf_cleanup(vif->netdev); + qtnf_del_virtual_intf(wiphy, &vif->wdev); + } + rtnl_unlock(); + qtnf_sta_list_free(&vif->sta_list); + } + + if (mac->wiphy_registered) + wiphy_unregister(wiphy); + + for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; ++band) { + if (!wiphy->bands[band]) + continue; + + kfree(wiphy->bands[band]->channels); + wiphy->bands[band]->n_channels = 0; + + kfree(wiphy->bands[band]); + wiphy->bands[band] = NULL; + } + + kfree(mac->macinfo.limits); + kfree(wiphy->iface_combinations); + wiphy_free(wiphy); + bus->mac[macid] = NULL; +} + +static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid) +{ + struct qtnf_wmac *mac; + struct qtnf_vif *vif; + int ret; + + if (!(bus->hw_info.mac_bitmap & BIT(macid))) { + pr_info("MAC%u is not active in FW\n", macid); + return 0; + } + + mac = qtnf_core_mac_alloc(bus, macid); + if (IS_ERR(mac)) { + pr_err("MAC%u allocation failed\n", macid); + return PTR_ERR(mac); + } + + ret = qtnf_cmd_get_mac_info(mac); + if (ret) { + pr_err("MAC%u: failed to get info\n", macid); + goto error; + } + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not ready\n", macid); + ret = -EFAULT; + goto error; + } + + ret = qtnf_cmd_send_add_intf(vif, NL80211_IFTYPE_AP, vif->mac_addr); + if (ret) { + pr_err("MAC%u: failed to add VIF\n", macid); + goto error; + } + + ret = qtnf_cmd_send_get_phy_params(mac); + if (ret) { + pr_err("MAC%u: failed to get PHY settings\n", macid); + goto error; + } + + ret = qtnf_mac_init_bands(mac); + if (ret) { + pr_err("MAC%u: failed to init bands\n", macid); + goto error; + } + + ret = qtnf_wiphy_register(&bus->hw_info, mac); + if (ret) { + pr_err("MAC%u: wiphy registration failed\n", macid); + goto error; + } + + mac->wiphy_registered = 1; + + rtnl_lock(); + + ret = qtnf_core_net_attach(mac, vif, "wlan%d", NET_NAME_ENUM, + NL80211_IFTYPE_AP); + rtnl_unlock(); + + if (ret) { + pr_err("MAC%u: failed to attach netdev\n", macid); + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + vif->netdev = NULL; + goto error; + } + + pr_debug("MAC%u initialized\n", macid); + + return 0; + +error: + qtnf_core_mac_detach(bus, macid); + return ret; +} + +int qtnf_core_attach(struct qtnf_bus *bus) +{ + unsigned int i; + int ret; + + qtnf_trans_init(bus); + + bus->fw_state = QTNF_FW_STATE_BOOT_DONE; + qtnf_bus_data_rx_start(bus); + + bus->workqueue = alloc_ordered_workqueue("QTNF_BUS", 0); + if (!bus->workqueue) { + pr_err("failed to alloc main workqueue\n"); + ret = -ENOMEM; + goto error; + } + + INIT_WORK(&bus->event_work, qtnf_event_work_handler); + + ret = qtnf_cmd_send_init_fw(bus); + if (ret) { + pr_err("failed to init FW: %d\n", ret); + goto error; + } + + bus->fw_state = QTNF_FW_STATE_ACTIVE; + + ret = qtnf_cmd_get_hw_info(bus); + if (ret) { + pr_err("failed to get HW info: %d\n", ret); + goto error; + } + + if (bus->hw_info.ql_proto_ver != QLINK_PROTO_VER) { + pr_err("qlink version mismatch %u != %u\n", + QLINK_PROTO_VER, bus->hw_info.ql_proto_ver); + ret = -EPROTONOSUPPORT; + goto error; + } + + if (bus->hw_info.num_mac > QTNF_MAX_MAC) { + pr_err("no support for number of MACs=%u\n", + bus->hw_info.num_mac); + ret = -ERANGE; + goto error; + } + + for (i = 0; i < bus->hw_info.num_mac; i++) { + ret = qtnf_core_mac_attach(bus, i); + + if (ret) { + pr_err("MAC%u: attach failed: %d\n", i, ret); + goto error; + } + } + + return 0; + +error: + qtnf_core_detach(bus); + + return ret; +} +EXPORT_SYMBOL_GPL(qtnf_core_attach); + +void qtnf_core_detach(struct qtnf_bus *bus) +{ + unsigned int macid; + + qtnf_bus_data_rx_stop(bus); + + for (macid = 0; macid < QTNF_MAX_MAC; macid++) + qtnf_core_mac_detach(bus, macid); + + if (bus->fw_state == QTNF_FW_STATE_ACTIVE) + qtnf_cmd_send_deinit_fw(bus); + + bus->fw_state = QTNF_FW_STATE_DEAD; + + if (bus->workqueue) { + flush_workqueue(bus->workqueue); + destroy_workqueue(bus->workqueue); + } + + qtnf_trans_free(bus); +} +EXPORT_SYMBOL_GPL(qtnf_core_detach); + +static inline int qtnf_is_frame_meta_magic_valid(struct qtnf_frame_meta_info *m) +{ + return m->magic_s == 0xAB && m->magic_e == 0xBA; +} + +struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_frame_meta_info *meta; + struct net_device *ndev = NULL; + struct qtnf_wmac *mac; + struct qtnf_vif *vif; + + meta = (struct qtnf_frame_meta_info *) + (skb_tail_pointer(skb) - sizeof(*meta)); + + if (unlikely(!qtnf_is_frame_meta_magic_valid(meta))) { + pr_err_ratelimited("invalid magic 0x%x:0x%x\n", + meta->magic_s, meta->magic_e); + goto out; + } + + if (unlikely(meta->macid >= QTNF_MAX_MAC)) { + pr_err_ratelimited("invalid mac(%u)\n", meta->macid); + goto out; + } + + if (unlikely(meta->ifidx >= QTNF_MAX_INTF)) { + pr_err_ratelimited("invalid vif(%u)\n", meta->ifidx); + goto out; + } + + mac = bus->mac[meta->macid]; + + if (unlikely(!mac)) { + pr_err_ratelimited("mac(%d) does not exist\n", meta->macid); + goto out; + } + + vif = &mac->iflist[meta->ifidx]; + + if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)) { + pr_err_ratelimited("vif(%u) does not exists\n", meta->ifidx); + goto out; + } + + ndev = vif->netdev; + + if (unlikely(!ndev)) { + pr_err_ratelimited("netdev for wlan%u.%u does not exists\n", + meta->macid, meta->ifidx); + goto out; + } + + __skb_trim(skb, skb->len - sizeof(*meta)); + +out: + return ndev; +} +EXPORT_SYMBOL_GPL(qtnf_classify_skb); + +MODULE_AUTHOR("Quantenna Communications"); +MODULE_DESCRIPTION("Quantenna 802.11 wireless LAN FullMAC driver."); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h new file mode 100644 index 000000000000..a616434281cf --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_CORE_H_ +#define _QTN_FMAC_CORE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qlink.h" +#include "trans.h" + +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + +#define QTNF_MAX_SSID_LIST_LENGTH 2 +#define QTNF_MAX_VSIE_LEN 255 +#define QTNF_MAX_ALPHA_LEN 2 +#define QTNF_MAX_INTF 8 +#define QTNF_MAX_EVENT_QUEUE_LEN 255 +#define QTNF_DEFAULT_BG_SCAN_PERIOD 300 +#define QTNF_MAX_BG_SCAN_PERIOD 0xffff + +#define QTNF_DEF_BSS_PRIORITY 0 +#define QTNF_DEF_WDOG_TIMEOUT 5 +#define QTNF_TX_TIMEOUT_TRSHLD 100 + +#define QTNF_STATE_AP_CONFIG BIT(2) +#define QTNF_STATE_AP_START BIT(1) + +extern const struct net_device_ops qtnf_netdev_ops; +struct qtnf_bus; +struct qtnf_vif; + +struct qtnf_bss_config { + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 bssid[ETH_ALEN]; + size_t ssid_len; + u8 dtim; + u16 bcn_period; + u16 auth_type; + bool privacy; + enum nl80211_mfp mfp; + struct cfg80211_chan_def chandef; + struct cfg80211_crypto_settings crypto; + u16 bg_scan_period; + u32 connect_flags; +}; + +struct qtnf_sta_node { + struct list_head list; + u8 mac_addr[ETH_ALEN]; +}; + +struct qtnf_sta_list { + struct list_head head; + atomic_t size; +}; + +enum qtnf_sta_state { + QTNF_STA_DISCONNECTED, + QTNF_STA_CONNECTING, + QTNF_STA_CONNECTED +}; + +struct qtnf_vif { + struct wireless_dev wdev; + u8 vifid; + u8 bss_priority; + u8 bss_status; + enum qtnf_sta_state sta_state; + u16 mgmt_frames_bitmask; + struct net_device *netdev; + struct qtnf_wmac *mac; + u8 mac_addr[ETH_ALEN]; + struct work_struct reset_work; + struct qtnf_bss_config bss_cfg; + struct qtnf_sta_list sta_list; + unsigned long cons_tx_timeout_cnt; +}; + +struct qtnf_mac_info { + u8 bands_cap; + u8 phymode_cap; + u8 dev_mac[ETH_ALEN]; + u8 num_tx_chain; + u8 num_rx_chain; + u16 max_ap_assoc_sta; + u32 frag_thr; + u32 rts_thr; + u8 lretry_limit; + u8 sretry_limit; + u8 coverage_class; + u8 radar_detect_widths; + struct ieee80211_ht_cap ht_cap; + struct ieee80211_vht_cap vht_cap; + struct ieee80211_iface_limit *limits; + size_t n_limits; +}; + +struct qtnf_wmac { + u8 macid; + u8 wiphy_registered; + u8 macaddr[ETH_ALEN]; + struct qtnf_bus *bus; + struct qtnf_mac_info macinfo; + struct qtnf_vif iflist[QTNF_MAX_INTF]; + struct cfg80211_scan_request *scan_req; +}; + +struct qtnf_hw_info { + u8 num_mac; + u8 mac_bitmap; + u8 alpha2_code[QTNF_MAX_ALPHA_LEN]; + u32 fw_ver; + u16 ql_proto_ver; + u8 total_tx_chain; + u8 total_rx_chain; + u32 hw_capab; +}; + +struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac); +struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac); +struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus); +int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv, + const char *name, unsigned char name_assign_type, + enum nl80211_iftype iftype); +void qtnf_main_work_queue(struct work_struct *work); +int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed); +int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac); + +struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid); +struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb); +struct net_device *qtnf_classify_skb_no_mbss(struct qtnf_bus *bus, + struct sk_buff *skb); + +void qtnf_virtual_intf_cleanup(struct net_device *ndev); + +void qtnf_netdev_updown(struct net_device *ndev, bool up); + +static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev) +{ + return *((void **)netdev_priv(dev)); +} + +#endif /* _QTN_FMAC_CORE_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/debug.c b/drivers/net/wireless/quantenna/qtnfmac/debug.c new file mode 100644 index 000000000000..9f826b9ef5d9 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/debug.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "debug.h" + +#undef pr_fmt +#define pr_fmt(fmt) "qtnfmac dbg: %s: " fmt, __func__ + +void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name) +{ + bus->dbg_dir = debugfs_create_dir(name, NULL); + + if (IS_ERR_OR_NULL(bus->dbg_dir)) { + pr_warn("failed to create debugfs root dir\n"); + bus->dbg_dir = NULL; + } +} + +void qtnf_debugfs_remove(struct qtnf_bus *bus) +{ + debugfs_remove_recursive(bus->dbg_dir); + bus->dbg_dir = NULL; +} + +void qtnf_debugfs_add_entry(struct qtnf_bus *bus, const char *name, + int (*fn)(struct seq_file *seq, void *data)) +{ + struct dentry *entry; + + entry = debugfs_create_devm_seqfile(bus->dev, name, bus->dbg_dir, fn); + if (IS_ERR_OR_NULL(entry)) + pr_warn("failed to add entry (%s)\n", name); +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/debug.h b/drivers/net/wireless/quantenna/qtnfmac/debug.h new file mode 100644 index 000000000000..d6dd12b5d434 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/debug.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_DEBUG_H_ +#define _QTN_FMAC_DEBUG_H_ + +#include + +#include "core.h" +#include "bus.h" + +#ifdef CONFIG_DEBUG_FS + +void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name); +void qtnf_debugfs_remove(struct qtnf_bus *bus); +void qtnf_debugfs_add_entry(struct qtnf_bus *bus, const char *name, + int (*fn)(struct seq_file *seq, void *data)); + +#else + +static inline void qtnf_debugfs_init(struct qtnf_bus *bus, const char *name) +{ +} + +static inline void qtnf_debugfs_remove(struct qtnf_bus *bus) +{ +} + +static inline void +qtnf_debugfs_add_entry(struct qtnf_bus *bus, const char *name, + int (*fn)(struct seq_file *seq, void *data)) +{ +} + +#endif /* CONFIG_DEBUG_FS */ + +#endif /* _QTN_FMAC_DEBUG_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c new file mode 100644 index 000000000000..9b61e9a83670 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#include "cfg80211.h" +#include "core.h" +#include "qlink.h" +#include "bus.h" +#include "trans.h" +#include "util.h" +#include "event.h" + +static int +qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif, + const struct qlink_event_sta_assoc *sta_assoc, + u16 len) +{ + const u8 *sta_addr; + u16 frame_control; + struct station_info sinfo = { 0 }; + size_t payload_len; + u16 tlv_type; + u16 tlv_value_len; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + if (unlikely(len < sizeof(*sta_assoc))) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + mac->macid, vif->vifid, len, sizeof(*sta_assoc)); + return -EINVAL; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_AP) { + pr_err("VIF%u.%u: STA_ASSOC event when not in AP mode\n", + mac->macid, vif->vifid); + return -EPROTO; + } + + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_err("VIF%u.%u: STA_ASSOC event when AP is not started\n", + mac->macid, vif->vifid); + return -EPROTO; + } + + sta_addr = sta_assoc->sta_addr; + frame_control = le16_to_cpu(sta_assoc->frame_control); + + pr_debug("VIF%u.%u: MAC:%pM FC:%x\n", mac->macid, vif->vifid, sta_addr, + frame_control); + + qtnf_sta_list_add(&vif->sta_list, sta_addr); + + sinfo.assoc_req_ies = NULL; + sinfo.assoc_req_ies_len = 0; + + payload_len = len - sizeof(*sta_assoc); + tlv = (struct qlink_tlv_hdr *)sta_assoc->ies; + + while (payload_len >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + + if (tlv_full_len > payload_len) { + pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n", + mac->macid, vif->vifid, tlv_type, + tlv_value_len); + return -EINVAL; + } + + if (tlv_type == QTN_TLV_ID_IE_SET) { + sinfo.assoc_req_ies = tlv->val; + sinfo.assoc_req_ies_len = tlv_value_len; + } + + payload_len -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (payload_len) { + pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n", + mac->macid, vif->vifid, payload_len); + return -EINVAL; + } + + cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, &sinfo, + GFP_KERNEL); + + return 0; +} + +static int +qtnf_event_handle_sta_deauth(struct qtnf_wmac *mac, struct qtnf_vif *vif, + const struct qlink_event_sta_deauth *sta_deauth, + u16 len) +{ + const u8 *sta_addr; + u16 reason; + + if (unlikely(len < sizeof(*sta_deauth))) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + mac->macid, vif->vifid, len, + sizeof(struct qlink_event_sta_deauth)); + return -EINVAL; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_AP) { + pr_err("VIF%u.%u: STA_DEAUTH event when not in AP mode\n", + mac->macid, vif->vifid); + return -EPROTO; + } + + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_err("VIF%u.%u: STA_DEAUTH event when AP is not started\n", + mac->macid, vif->vifid); + return -EPROTO; + } + + sta_addr = sta_deauth->sta_addr; + reason = le16_to_cpu(sta_deauth->reason); + + pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid, + sta_addr, reason); + + if (qtnf_sta_list_del(&vif->sta_list, sta_addr)) + cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr, + GFP_KERNEL); + + return 0; +} + +static int +qtnf_event_handle_bss_join(struct qtnf_vif *vif, + const struct qlink_event_bss_join *join_info, + u16 len) +{ + if (unlikely(len < sizeof(*join_info))) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + vif->mac->macid, vif->vifid, len, + sizeof(struct qlink_event_bss_join)); + return -EINVAL; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { + pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + if (vif->sta_state != QTNF_STA_CONNECTING) { + pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid, + join_info->bssid); + + cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL, + 0, le16_to_cpu(join_info->status), GFP_KERNEL); + + if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) { + vif->sta_state = QTNF_STA_CONNECTED; + netif_carrier_on(vif->netdev); + } else { + vif->sta_state = QTNF_STA_DISCONNECTED; + } + + return 0; +} + +static int +qtnf_event_handle_bss_leave(struct qtnf_vif *vif, + const struct qlink_event_bss_leave *leave_info, + u16 len) +{ + if (unlikely(len < sizeof(*leave_info))) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + vif->mac->macid, vif->vifid, len, + sizeof(struct qlink_event_bss_leave)); + return -EINVAL; + } + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { + pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + if (vif->sta_state != QTNF_STA_CONNECTED) { + pr_err("VIF%u.%u: BSS_LEAVE event when STA is not connected\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid); + + cfg80211_disconnected(vif->netdev, leave_info->reason, NULL, 0, 0, + GFP_KERNEL); + + vif->sta_state = QTNF_STA_DISCONNECTED; + netif_carrier_off(vif->netdev); + + return 0; +} + +static int +qtnf_event_handle_mgmt_received(struct qtnf_vif *vif, + const struct qlink_event_rxmgmt *rxmgmt, + u16 len) +{ + const size_t min_len = sizeof(*rxmgmt) + + sizeof(struct ieee80211_hdr_3addr); + const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data; + const u16 frame_len = len - sizeof(*rxmgmt); + enum nl80211_rxmgmt_flags flags = 0; + + if (unlikely(len < min_len)) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + vif->mac->macid, vif->vifid, len, min_len); + return -EINVAL; + } + + if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED) + flags |= NL80211_RXMGMT_FLAG_ANSWERED; + + pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len, + le16_to_cpu(frame->frame_control), frame->addr2); + + cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq), + le32_to_cpu(rxmgmt->sig_dbm), rxmgmt->frame_data, + frame_len, flags); + + return 0; +} + +static int +qtnf_event_handle_scan_results(struct qtnf_vif *vif, + const struct qlink_event_scan_result *sr, + u16 len) +{ + struct cfg80211_bss *bss; + struct ieee80211_channel *channel; + struct wiphy *wiphy = priv_to_wiphy(vif->mac); + enum cfg80211_bss_frame_type frame_type; + size_t payload_len; + u16 tlv_type; + u16 tlv_value_len; + size_t tlv_full_len; + const struct qlink_tlv_hdr *tlv; + + const u8 *ies = NULL; + size_t ies_len = 0; + + if (len < sizeof(*sr)) { + pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid, + vif->vifid); + return -EINVAL; + } + + channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq)); + if (!channel) { + pr_err("VIF%u.%u: channel at %u MHz not found\n", + vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq)); + return -EINVAL; + } + + switch (sr->frame_type) { + case QLINK_BSS_FTYPE_BEACON: + frame_type = CFG80211_BSS_FTYPE_BEACON; + break; + case QLINK_BSS_FTYPE_PRESP: + frame_type = CFG80211_BSS_FTYPE_PRESP; + break; + default: + frame_type = CFG80211_BSS_FTYPE_UNKNOWN; + } + + payload_len = len - sizeof(*sr); + tlv = (struct qlink_tlv_hdr *)sr->payload; + + while (payload_len >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + + if (tlv_full_len > payload_len) { + pr_warn("VIF%u.%u: malformed TLV 0x%.2X; LEN: %u\n", + vif->mac->macid, vif->vifid, tlv_type, + tlv_value_len); + return -EINVAL; + } + + if (tlv_type == QTN_TLV_ID_IE_SET) { + ies = tlv->val; + ies_len = tlv_value_len; + } + + payload_len -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (payload_len) { + pr_warn("VIF%u.%u: malformed TLV buf; bytes left: %zu\n", + vif->mac->macid, vif->vifid, payload_len); + return -EINVAL; + } + + bss = cfg80211_inform_bss(wiphy, channel, frame_type, + sr->bssid, get_unaligned_le64(&sr->tsf), + le16_to_cpu(sr->capab), + le16_to_cpu(sr->bintval), ies, ies_len, + sr->signal, GFP_KERNEL); + if (!bss) + return -ENOMEM; + + cfg80211_put_bss(wiphy, bss); + + return 0; +} + +static int +qtnf_event_handle_scan_complete(struct qtnf_wmac *mac, + const struct qlink_event_scan_complete *status, + u16 len) +{ + if (len < sizeof(*status)) { + pr_err("MAC%u: payload is too short\n", mac->macid); + return -EINVAL; + } + + qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED); + + return 0; +} + +static int qtnf_event_parse(struct qtnf_wmac *mac, + const struct sk_buff *event_skb) +{ + const struct qlink_event *event; + struct qtnf_vif *vif = NULL; + int ret = -1; + u16 event_id; + u16 event_len; + + event = (const struct qlink_event *)event_skb->data; + event_id = le16_to_cpu(event->event_id); + event_len = le16_to_cpu(event->mhdr.len); + + if (likely(event->vifid < QTNF_MAX_INTF)) { + vif = &mac->iflist[event->vifid]; + } else { + pr_err("invalid vif(%u)\n", event->vifid); + return -EINVAL; + } + + switch (event_id) { + case QLINK_EVENT_STA_ASSOCIATED: + ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_STA_DEAUTH: + ret = qtnf_event_handle_sta_deauth(mac, vif, + (const void *)event, + event_len); + break; + case QLINK_EVENT_MGMT_RECEIVED: + ret = qtnf_event_handle_mgmt_received(vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_SCAN_RESULTS: + ret = qtnf_event_handle_scan_results(vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_SCAN_COMPLETE: + ret = qtnf_event_handle_scan_complete(mac, (const void *)event, + event_len); + break; + case QLINK_EVENT_BSS_JOIN: + ret = qtnf_event_handle_bss_join(vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_BSS_LEAVE: + ret = qtnf_event_handle_bss_leave(vif, (const void *)event, + event_len); + break; + default: + pr_warn("unknown event type: %x\n", event_id); + break; + } + + return ret; +} + +static int qtnf_event_process_skb(struct qtnf_bus *bus, + const struct sk_buff *skb) +{ + const struct qlink_event *event; + struct qtnf_wmac *mac; + int res; + + if (unlikely(!skb || skb->len < sizeof(*event))) { + pr_err("invalid event buffer\n"); + return -EINVAL; + } + + event = (struct qlink_event *)skb->data; + + mac = qtnf_core_get_mac(bus, event->macid); + + pr_debug("new event id:%x len:%u mac:%u vif:%u\n", + le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len), + event->macid, event->vifid); + + if (unlikely(!mac)) + return -ENXIO; + + qtnf_bus_lock(bus); + res = qtnf_event_parse(mac, skb); + qtnf_bus_unlock(bus); + + return res; +} + +void qtnf_event_work_handler(struct work_struct *work) +{ + struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work); + struct sk_buff_head *event_queue = &bus->trans.event_queue; + struct sk_buff *current_event_skb = skb_dequeue(event_queue); + + while (current_event_skb) { + qtnf_event_process_skb(bus, current_event_skb); + dev_kfree_skb_any(current_event_skb); + current_event_skb = skb_dequeue(event_queue); + } +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.h b/drivers/net/wireless/quantenna/qtnfmac/event.h new file mode 100644 index 000000000000..ae759b602c2a --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/event.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_EVENT_H_ +#define _QTN_FMAC_EVENT_H_ + +#include +#include + +#include "qlink.h" + +void qtnf_event_work_handler(struct work_struct *work); + +#endif /* _QTN_FMAC_EVENT_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c new file mode 100644 index 000000000000..4814d90c8040 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -0,0 +1,1378 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qtn_hw_ids.h" +#include "pcie_bus_priv.h" +#include "core.h" +#include "bus.h" +#include "debug.h" + +static bool use_msi = true; +module_param(use_msi, bool, 0644); +MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt"); + +static unsigned int tx_bd_size_param = 256; +module_param(tx_bd_size_param, uint, 0644); +MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size"); + +static unsigned int rx_bd_size_param = 256; +module_param(rx_bd_size_param, uint, 0644); +MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size"); + +static unsigned int rx_bd_reserved_param = 16; +module_param(rx_bd_reserved_param, uint, 0644); +MODULE_PARM_DESC(rx_bd_reserved_param, "Reserved RX descriptors"); + +static u8 flashboot = 1; +module_param(flashboot, byte, 0644); +MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS"); + +#define DRV_NAME "qtnfmac_pearl_pcie" + +static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg) +{ + writel(val, basereg); + + /* flush posted write */ + readl(basereg); +} + +static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask = (PCIE_HDP_INT_RX_BITS | PCIE_HDP_INT_TX_BITS); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + writel(0x0, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask |= PCIE_HDP_INT_RX_BITS; + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask &= ~PCIE_HDP_INT_RX_BITS; + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_en_txdone_irq(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask |= PCIE_HDP_INT_TX_BITS; + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_bus_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + priv->pcie_irq_mask &= ~PCIE_HDP_INT_TX_BITS; + writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static int qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) +{ + struct pci_dev *pdev = priv->pdev; + + /* fall back to legacy INTx interrupts by default */ + priv->msi_enabled = 0; + + /* check if MSI capability is available */ + if (use_msi) { + if (!pci_enable_msi(pdev)) { + pr_debug("MSI interrupt enabled\n"); + priv->msi_enabled = 1; + } else { + pr_warn("failed to enable MSI interrupts"); + } + } + + if (!priv->msi_enabled) { + pr_warn("legacy PCIE interrupts enabled\n"); + pci_intx(pdev, 1); + } + + return 0; +} + +static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv) +{ + void __iomem *reg = priv->sysctl_bar + PEARL_PCIE_CFG0_OFFSET; + u32 cfg; + + cfg = readl(reg); + cfg &= ~PEARL_ASSERT_INTX; + qtnf_non_posted_write(cfg, reg); +} + +static void qtnf_ipc_gen_ep_int(void *arg) +{ + const struct qtnf_pcie_bus_priv *priv = arg; + const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_IPC_IRQ); + void __iomem *reg = priv->sysctl_bar + + QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; + + qtnf_non_posted_write(data, reg); +} + +static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) +{ + void __iomem *vaddr; + dma_addr_t busaddr; + size_t len; + int ret; + + ret = pcim_iomap_regions(priv->pdev, 1 << index, DRV_NAME); + if (ret) + return IOMEM_ERR_PTR(ret); + + busaddr = pci_resource_start(priv->pdev, index); + vaddr = pcim_iomap_table(priv->pdev)[index]; + len = pci_resource_len(priv->pdev, index); + + pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n", + index, vaddr, &busaddr, (int)len); + + return vaddr; +} + +static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) +{ + struct qtnf_pcie_bus_priv *priv = arg; + struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); + struct sk_buff *skb; + + if (unlikely(len == 0)) { + pr_warn("zero length packet received\n"); + return; + } + + skb = __dev_alloc_skb(len, GFP_KERNEL); + + if (unlikely(!skb)) { + pr_err("failed to allocate skb\n"); + return; + } + + memcpy(skb_put(skb, len), buf, len); + + qtnf_trans_handle_rx_ctl_packet(bus, skb); +} + +static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv) +{ + struct qtnf_shm_ipc_region __iomem *ipc_tx_reg; + struct qtnf_shm_ipc_region __iomem *ipc_rx_reg; + const struct qtnf_shm_ipc_int ipc_int = { qtnf_ipc_gen_ep_int, priv }; + const struct qtnf_shm_ipc_rx_callback rx_callback = { + qtnf_pcie_control_rx_callback, priv }; + + ipc_tx_reg = &priv->bda->bda_shm_reg1; + ipc_rx_reg = &priv->bda->bda_shm_reg2; + + qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND, + ipc_tx_reg, priv->workqueue, + &ipc_int, &rx_callback); + qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND, + ipc_rx_reg, priv->workqueue, + &ipc_int, &rx_callback); + + return 0; +} + +static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) +{ + qtnf_shm_ipc_free(&priv->shm_ipc_ep_in); + qtnf_shm_ipc_free(&priv->shm_ipc_ep_out); +} + +static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) +{ + int ret; + + priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR); + if (IS_ERR_OR_NULL(priv->sysctl_bar)) { + pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR); + return ret; + } + + priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR); + if (IS_ERR_OR_NULL(priv->dmareg_bar)) { + pr_err("failed to map BAR%u\n", QTN_DMA_BAR); + return ret; + } + + priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR); + if (IS_ERR_OR_NULL(priv->epmem_bar)) { + pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR); + return ret; + } + + priv->pcie_reg_base = priv->dmareg_bar; + priv->bda = priv->epmem_bar; + writel(priv->msi_enabled, &priv->bda->bda_rc_msi_enabled); + + return 0; +} + +static int +qtnf_pcie_init_dma_mask(struct qtnf_pcie_bus_priv *priv, u64 dma_mask) +{ + int ret; + + ret = dma_supported(&priv->pdev->dev, dma_mask); + if (!ret) { + pr_err("DMA mask %llu not supported\n", dma_mask); + return ret; + } + + ret = pci_set_dma_mask(priv->pdev, dma_mask); + if (ret) { + pr_err("failed to set DMA mask %llu\n", dma_mask); + return ret; + } + + ret = pci_set_consistent_dma_mask(priv->pdev, dma_mask); + if (ret) { + pr_err("failed to set consistent DMA mask %llu\n", dma_mask); + return ret; + } + + return ret; +} + +static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv) +{ + struct pci_dev *pdev = priv->pdev; + struct pci_dev *parent; + int mps_p, mps_o, mps_m, mps; + int ret; + + /* current mps */ + mps_o = pcie_get_mps(pdev); + + /* maximum supported mps */ + mps_m = 128 << pdev->pcie_mpss; + + /* suggested new mps value */ + mps = mps_m; + + if (pdev->bus && pdev->bus->self) { + /* parent (bus) mps */ + parent = pdev->bus->self; + + if (pci_is_pcie(parent)) { + mps_p = pcie_get_mps(parent); + mps = min(mps_m, mps_p); + } + } + + ret = pcie_set_mps(pdev, mps); + if (ret) { + pr_err("failed to set mps to %d, keep using current %d\n", + mps, mps_o); + priv->mps = mps_o; + return; + } + + pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m); + priv->mps = mps; +} + +static int qtnf_is_state(__le32 __iomem *reg, u32 state) +{ + u32 s = readl(reg); + + return s & state; +} + +static void qtnf_set_state(__le32 __iomem *reg, u32 state) +{ + u32 s = readl(reg); + + qtnf_non_posted_write(state | s, reg); +} + +static void qtnf_clear_state(__le32 __iomem *reg, u32 state) +{ + u32 s = readl(reg); + + qtnf_non_posted_write(s & ~state, reg); +} + +static int qtnf_poll_state(__le32 __iomem *reg, u32 state, u32 delay_in_ms) +{ + u32 timeout = 0; + + while ((qtnf_is_state(reg, state) == 0)) { + usleep_range(1000, 1200); + if (++timeout > delay_in_ms) + return -1; + } + + return 0; +} + +static int alloc_skb_array(struct qtnf_pcie_bus_priv *priv) +{ + struct sk_buff **vaddr; + int len; + + len = priv->tx_bd_num * sizeof(*priv->tx_skb) + + priv->rx_bd_num * sizeof(*priv->rx_skb); + vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL); + + if (!vaddr) + return -ENOMEM; + + priv->tx_skb = vaddr; + + vaddr += priv->tx_bd_num; + priv->rx_skb = vaddr; + + return 0; +} + +static int alloc_bd_table(struct qtnf_pcie_bus_priv *priv) +{ + dma_addr_t paddr; + void *vaddr; + int len; + + len = priv->tx_bd_num * sizeof(struct qtnf_tx_bd) + + priv->rx_bd_num * sizeof(struct qtnf_rx_bd); + + vaddr = dmam_alloc_coherent(&priv->pdev->dev, len, &paddr, GFP_KERNEL); + if (!vaddr) + return -ENOMEM; + + /* tx bd */ + + memset(vaddr, 0, len); + + priv->bd_table_vaddr = vaddr; + priv->bd_table_paddr = paddr; + priv->bd_table_len = len; + + priv->tx_bd_vbase = vaddr; + priv->tx_bd_pbase = paddr; + + pr_debug("TX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); + + priv->tx_bd_reclaim_start = 0; + priv->tx_bd_index = 0; + priv->tx_queue_len = 0; + + /* rx bd */ + + vaddr = ((struct qtnf_tx_bd *)vaddr) + priv->tx_bd_num; + paddr += priv->tx_bd_num * sizeof(struct qtnf_tx_bd); + + priv->rx_bd_vbase = vaddr; + priv->rx_bd_pbase = paddr; + + writel(QTN_HOST_LO32(paddr), + PCIE_HDP_TX_HOST_Q_BASE_L(priv->pcie_reg_base)); + writel(QTN_HOST_HI32(paddr), + PCIE_HDP_TX_HOST_Q_BASE_H(priv->pcie_reg_base)); + writel(priv->rx_bd_num | (sizeof(struct qtnf_rx_bd)) << 16, + PCIE_HDP_TX_HOST_Q_SZ_CTRL(priv->pcie_reg_base)); + + priv->hw_txproc_wr_ptr = priv->rx_bd_num - rx_bd_reserved_param; + + writel(priv->hw_txproc_wr_ptr, + PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base)); + + pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); + + priv->rx_bd_index = 0; + + return 0; +} + +static int skb2rbd_attach(struct qtnf_pcie_bus_priv *priv, u16 rx_bd_index) +{ + struct qtnf_rx_bd *rxbd; + struct sk_buff *skb; + dma_addr_t paddr; + + skb = __dev_alloc_skb(SKB_BUF_SIZE + NET_IP_ALIGN, + GFP_ATOMIC); + if (!skb) { + priv->rx_skb[rx_bd_index] = NULL; + return -ENOMEM; + } + + priv->rx_skb[rx_bd_index] = skb; + + skb_reserve(skb, NET_IP_ALIGN); + + rxbd = &priv->rx_bd_vbase[rx_bd_index]; + + paddr = pci_map_single(priv->pdev, skb->data, + SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(priv->pdev, paddr)) { + pr_err("skb DMA mapping error: %pad\n", &paddr); + return -ENOMEM; + } + + writel(QTN_HOST_LO32(paddr), + PCIE_HDP_HHBM_BUF_PTR(priv->pcie_reg_base)); + writel(QTN_HOST_HI32(paddr), + PCIE_HDP_HHBM_BUF_PTR_H(priv->pcie_reg_base)); + + /* keep rx skb paddrs in rx buffer descriptors for cleanup purposes */ + rxbd->addr = cpu_to_le32(QTN_HOST_LO32(paddr)); + rxbd->addr_h = cpu_to_le32(QTN_HOST_HI32(paddr)); + + rxbd->info = 0x0; + + return 0; +} + +static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv) +{ + u16 i; + int ret = 0; + + memset(priv->rx_bd_vbase, 0x0, + priv->rx_bd_num * sizeof(struct qtnf_rx_bd)); + + for (i = 0; i < priv->rx_bd_num; i++) { + ret = skb2rbd_attach(priv, i); + if (ret) + break; + } + + return ret; +} + +/* all rx/tx activity should have ceased before calling this function */ +static void free_xfer_buffers(void *data) +{ + struct qtnf_pcie_bus_priv *priv = (struct qtnf_pcie_bus_priv *)data; + struct qtnf_rx_bd *rxbd; + dma_addr_t paddr; + int i; + + /* free rx buffers */ + for (i = 0; i < priv->rx_bd_num; i++) { + if (priv->rx_skb[i]) { + rxbd = &priv->rx_bd_vbase[i]; + paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), + le32_to_cpu(rxbd->addr)); + pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE, + PCI_DMA_FROMDEVICE); + + dev_kfree_skb_any(priv->rx_skb[i]); + } + } + + /* free tx buffers */ + for (i = 0; i < priv->tx_bd_num; i++) { + if (priv->tx_skb[i]) { + dev_kfree_skb_any(priv->tx_skb[i]); + priv->tx_skb[i] = NULL; + } + } +} + +static int qtnf_pcie_init_xfer(struct qtnf_pcie_bus_priv *priv) +{ + int ret; + + priv->tx_bd_num = tx_bd_size_param; + priv->rx_bd_num = rx_bd_size_param; + + ret = alloc_skb_array(priv); + if (ret) { + pr_err("failed to allocate skb array\n"); + return ret; + } + + ret = alloc_bd_table(priv); + if (ret) { + pr_err("failed to allocate bd table\n"); + return ret; + } + + ret = alloc_rx_buffers(priv); + if (ret) { + pr_err("failed to allocate rx buffers\n"); + return ret; + } + + return ret; +} + +static int qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv) +{ + struct qtnf_tx_bd *txbd; + struct sk_buff *skb; + dma_addr_t paddr; + int last_sent; + int count; + int i; + + last_sent = readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) + % priv->tx_bd_num; + i = priv->tx_bd_reclaim_start; + count = 0; + + while (i != last_sent) { + skb = priv->tx_skb[i]; + if (!skb) + break; + + txbd = &priv->tx_bd_vbase[i]; + paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), + le32_to_cpu(txbd->addr)); + pci_unmap_single(priv->pdev, paddr, skb->len, PCI_DMA_TODEVICE); + + if (skb->dev) { + skb->dev->stats.tx_packets++; + skb->dev->stats.tx_bytes += skb->len; + + if (netif_queue_stopped(skb->dev)) + netif_wake_queue(skb->dev); + } + + dev_kfree_skb_any(skb); + priv->tx_skb[i] = NULL; + priv->tx_queue_len--; + count++; + + if (++i >= priv->tx_bd_num) + i = 0; + } + + priv->tx_bd_reclaim_start = i; + priv->tx_reclaim_done += count; + priv->tx_reclaim_req++; + + return count; +} + +static bool qtnf_tx_queue_ready(struct qtnf_pcie_bus_priv *priv) +{ + if (priv->tx_queue_len >= priv->tx_bd_num - 1) { + pr_err_ratelimited("reclaim full Tx queue\n"); + qtnf_pcie_data_tx_reclaim(priv); + + if (priv->tx_queue_len >= priv->tx_bd_num - 1) { + priv->tx_full_count++; + return false; + } + } + + return true; +} + +static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + dma_addr_t txbd_paddr, skb_paddr; + struct qtnf_tx_bd *txbd; + unsigned long flags; + int len, i; + u32 info; + int ret = 0; + + spin_lock_irqsave(&priv->tx_lock, flags); + + priv->tx_done_count++; + + if (!qtnf_tx_queue_ready(priv)) { + if (skb->dev) + netif_stop_queue(skb->dev); + + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_BUSY; + } + + i = priv->tx_bd_index; + priv->tx_skb[i] = skb; + len = skb->len; + + skb_paddr = pci_map_single(priv->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(priv->pdev, skb_paddr)) { + pr_err("skb DMA mapping error: %pad\n", &skb_paddr); + ret = -ENOMEM; + goto tx_done; + } + + txbd = &priv->tx_bd_vbase[i]; + txbd->addr = cpu_to_le32(QTN_HOST_LO32(skb_paddr)); + txbd->addr_h = cpu_to_le32(QTN_HOST_HI32(skb_paddr)); + + info = (len & QTN_PCIE_TX_DESC_LEN_MASK) << QTN_PCIE_TX_DESC_LEN_SHIFT; + txbd->info = cpu_to_le32(info); + + /* sync up all descriptor updates before passing them to EP */ + dma_wmb(); + + /* write new TX descriptor to PCIE_RX_FIFO on EP */ + txbd_paddr = priv->tx_bd_pbase + i * sizeof(struct qtnf_tx_bd); + writel(QTN_HOST_LO32(txbd_paddr), + PCIE_HDP_HOST_WR_DESC0(priv->pcie_reg_base)); + writel(QTN_HOST_HI32(txbd_paddr), + PCIE_HDP_HOST_WR_DESC0_H(priv->pcie_reg_base)); + + if (++i >= priv->tx_bd_num) + i = 0; + + priv->tx_bd_index = i; + priv->tx_queue_len++; + +tx_done: + if (ret && skb) { + pr_err_ratelimited("drop skb\n"); + if (skb->dev) + skb->dev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + } + + spin_unlock_irqrestore(&priv->tx_lock, flags); + + return NETDEV_TX_OK; +} + +static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + + return qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); +} + +static irqreturn_t qtnf_interrupt(int irq, void *data) +{ + struct qtnf_bus *bus = (struct qtnf_bus *)data; + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + u32 status; + + priv->pcie_irq_count++; + status = readl(PCIE_HDP_INT_STATUS(priv->pcie_reg_base)); + + qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_in); + qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_out); + + if (!(status & priv->pcie_irq_mask)) + goto irq_done; + + if (status & PCIE_HDP_INT_RX_BITS) { + priv->pcie_irq_rx_count++; + qtnf_dis_rxdone_irq(priv); + napi_schedule(&bus->mux_napi); + } + + if (status & PCIE_HDP_INT_TX_BITS) { + priv->pcie_irq_tx_count++; + qtnf_dis_txdone_irq(priv); + tasklet_hi_schedule(&priv->reclaim_tq); + } + +irq_done: + /* H/W workaround: clean all bits, not only enabled */ + qtnf_non_posted_write(~0U, PCIE_HDP_INT_STATUS(priv->pcie_reg_base)); + + if (!priv->msi_enabled) + qtnf_deassert_intx(priv); + + return IRQ_HANDLED; +} + +static inline void hw_txproc_wr_ptr_inc(struct qtnf_pcie_bus_priv *priv) +{ + u32 index; + + index = priv->hw_txproc_wr_ptr; + + if (++index >= priv->rx_bd_num) + index = 0; + + priv->hw_txproc_wr_ptr = index; +} + +static int qtnf_rx_poll(struct napi_struct *napi, int budget) +{ + struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi); + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct net_device *ndev = NULL; + struct sk_buff *skb = NULL; + int processed = 0; + struct qtnf_rx_bd *rxbd; + dma_addr_t skb_paddr; + u32 descw; + u16 index; + int ret; + + index = priv->rx_bd_index; + rxbd = &priv->rx_bd_vbase[index]; + + descw = le32_to_cpu(rxbd->info); + + while ((descw & QTN_TXDONE_MASK) && (processed < budget)) { + skb = priv->rx_skb[index]; + + if (likely(skb)) { + skb_put(skb, QTN_GET_LEN(descw)); + + skb_paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), + le32_to_cpu(rxbd->addr)); + pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE, + PCI_DMA_FROMDEVICE); + + ndev = qtnf_classify_skb(bus, skb); + if (likely(ndev)) { + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += skb->len; + + skb->protocol = eth_type_trans(skb, ndev); + netif_receive_skb(skb); + } else { + pr_debug("drop untagged skb\n"); + bus->mux_dev.stats.rx_dropped++; + dev_kfree_skb_any(skb); + } + + processed++; + } else { + pr_err("missing rx_skb[%d]\n", index); + } + + /* attached rx buffer is passed upstream: map a new one */ + ret = skb2rbd_attach(priv, index); + if (likely(!ret)) { + if (++index >= priv->rx_bd_num) + index = 0; + + priv->rx_bd_index = index; + hw_txproc_wr_ptr_inc(priv); + + rxbd = &priv->rx_bd_vbase[index]; + descw = le32_to_cpu(rxbd->info); + } else { + pr_err("failed to allocate new rx_skb[%d]\n", index); + break; + } + + writel(priv->hw_txproc_wr_ptr, + PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base)); + } + + if (processed < budget) { + napi_complete(napi); + qtnf_en_rxdone_irq(priv); + } + + return processed; +} + +static void +qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + + tasklet_hi_schedule(&priv->reclaim_tq); +} + +static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + + qtnf_enable_hdp_irqs(priv); + napi_enable(&bus->mux_napi); +} + +static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + + napi_disable(&bus->mux_napi); + qtnf_disable_hdp_irqs(priv); +} + +static const struct qtnf_bus_ops qtnf_pcie_bus_ops = { + /* control path methods */ + .control_tx = qtnf_pcie_control_tx, + + /* data path methods */ + .data_tx = qtnf_pcie_data_tx, + .data_tx_timeout = qtnf_pcie_data_tx_timeout, + .data_rx_start = qtnf_pcie_data_rx_start, + .data_rx_stop = qtnf_pcie_data_rx_stop, +}; + +static int qtnf_ep_fw_send(struct qtnf_pcie_bus_priv *priv, uint32_t size, + int blk, const u8 *pblk, const u8 *fw) +{ + struct pci_dev *pdev = priv->pdev; + struct qtnf_bus *bus = pci_get_drvdata(pdev); + + struct qtnf_pcie_fw_hdr *hdr; + u8 *pdata; + + int hds = sizeof(*hdr); + struct sk_buff *skb = NULL; + int len = 0; + int ret; + + skb = __dev_alloc_skb(QTN_PCIE_FW_BUFSZ, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + skb->len = QTN_PCIE_FW_BUFSZ; + skb->dev = NULL; + + hdr = (struct qtnf_pcie_fw_hdr *)skb->data; + memcpy(hdr->boardflg, QTN_PCIE_BOARDFLG, strlen(QTN_PCIE_BOARDFLG)); + hdr->fwsize = cpu_to_le32(size); + hdr->seqnum = cpu_to_le32(blk); + + if (blk) + hdr->type = cpu_to_le32(QTN_FW_DSUB); + else + hdr->type = cpu_to_le32(QTN_FW_DBEGIN); + + pdata = skb->data + hds; + + len = QTN_PCIE_FW_BUFSZ - hds; + if (pblk >= (fw + size - len)) { + len = fw + size - pblk; + hdr->type = cpu_to_le32(QTN_FW_DEND); + } + + hdr->pktlen = cpu_to_le32(len); + memcpy(pdata, pblk, len); + hdr->crc = cpu_to_le32(~crc32(0, pdata, len)); + + ret = qtnf_pcie_data_tx(bus, skb); + + return (ret == NETDEV_TX_OK) ? len : 0; +} + +static int +qtnf_ep_fw_load(struct qtnf_pcie_bus_priv *priv, const u8 *fw, u32 fw_size) +{ + int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pcie_fw_hdr); + int blk_count = fw_size / blk_size + ((fw_size % blk_size) ? 1 : 0); + const u8 *pblk = fw; + int threshold = 0; + int blk = 0; + int len; + + pr_debug("FW upload started: fw_addr=0x%p size=%d\n", fw, fw_size); + + while (blk < blk_count) { + if (++threshold > 10000) { + pr_err("FW upload failed: too many retries\n"); + return -ETIMEDOUT; + } + + len = qtnf_ep_fw_send(priv, fw_size, blk, pblk, fw); + if (len <= 0) + continue; + + if (!((blk + 1) & QTN_PCIE_FW_DLMASK) || + (blk == (blk_count - 1))) { + qtnf_set_state(&priv->bda->bda_rc_state, + QTN_RC_FW_SYNC); + if (qtnf_poll_state(&priv->bda->bda_ep_state, + QTN_EP_FW_SYNC, + QTN_FW_DL_TIMEOUT_MS)) { + pr_err("FW upload failed: SYNC timed out\n"); + return -ETIMEDOUT; + } + + qtnf_clear_state(&priv->bda->bda_ep_state, + QTN_EP_FW_SYNC); + + if (qtnf_is_state(&priv->bda->bda_ep_state, + QTN_EP_FW_RETRY)) { + if (blk == (blk_count - 1)) { + int last_round = + blk_count & QTN_PCIE_FW_DLMASK; + blk -= last_round; + pblk -= ((last_round - 1) * + blk_size + len); + } else { + blk -= QTN_PCIE_FW_DLMASK; + pblk -= QTN_PCIE_FW_DLMASK * blk_size; + } + + qtnf_clear_state(&priv->bda->bda_ep_state, + QTN_EP_FW_RETRY); + + pr_warn("FW upload retry: block #%d\n", blk); + continue; + } + + qtnf_pcie_data_tx_reclaim(priv); + } + + pblk += len; + blk++; + } + + pr_debug("FW upload completed: totally sent %d blocks\n", blk); + return 0; +} + +static void qtnf_firmware_load(const struct firmware *fw, void *context) +{ + struct qtnf_pcie_bus_priv *priv = (void *)context; + struct pci_dev *pdev = priv->pdev; + struct qtnf_bus *bus = pci_get_drvdata(pdev); + int ret; + + if (!fw) { + pr_err("failed to get firmware %s\n", bus->fwname); + goto fw_load_err; + } + + ret = qtnf_ep_fw_load(priv, fw->data, fw->size); + if (ret) { + pr_err("FW upload error\n"); + goto fw_load_err; + } + + if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, + QTN_FW_DL_TIMEOUT_MS)) { + pr_err("FW bringup timed out\n"); + goto fw_load_err; + } + + bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; + pr_info("firmware is up and running\n"); + +fw_load_err: + + if (fw) + release_firmware(fw); + + complete(&bus->request_firmware_complete); +} + +static int qtnf_bringup_fw(struct qtnf_bus *bus) +{ + struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); + struct pci_dev *pdev = priv->pdev; + int ret; + u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; + + if (flashboot) + state |= QTN_RC_FW_FLASHBOOT; + + qtnf_set_state(&priv->bda->bda_rc_state, state); + + if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY, + QTN_FW_DL_TIMEOUT_MS)) { + pr_err("card is not ready\n"); + return -ETIMEDOUT; + } + + qtnf_clear_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY); + + if (flashboot) { + pr_info("Booting FW from flash\n"); + + if (!qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, + QTN_FW_DL_TIMEOUT_MS)) + bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; + + return 0; + } + + pr_info("starting firmware upload: %s\n", bus->fwname); + + ret = request_firmware_nowait(THIS_MODULE, 1, bus->fwname, &pdev->dev, + GFP_KERNEL, priv, qtnf_firmware_load); + if (ret < 0) + pr_err("request_firmware_nowait error %d\n", ret); + else + ret = 1; + + return ret; +} + +static void qtnf_reclaim_tasklet_fn(unsigned long data) +{ + struct qtnf_pcie_bus_priv *priv = (void *)data; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_lock, flags); + qtnf_pcie_data_tx_reclaim(priv); + spin_unlock_irqrestore(&priv->tx_lock, flags); + qtnf_en_txdone_irq(priv); +} + +static int qtnf_dbg_mps_show(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "%d\n", priv->mps); + + return 0; +} + +static int qtnf_dbg_msi_show(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "%u\n", priv->msi_enabled); + + return 0; +} + +static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "pcie_irq_count(%u)\n", priv->pcie_irq_count); + seq_printf(s, "pcie_irq_tx_count(%u)\n", priv->pcie_irq_tx_count); + seq_printf(s, "pcie_irq_rx_count(%u)\n", priv->pcie_irq_rx_count); + + return 0; +} + +static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count); + seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); + seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done); + seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); + seq_printf(s, "tx_bd_reclaim_start(%u)\n", priv->tx_bd_reclaim_start); + seq_printf(s, "tx_bd_index(%u)\n", priv->tx_bd_index); + seq_printf(s, "rx_bd_index(%u)\n", priv->rx_bd_index); + seq_printf(s, "tx_queue_len(%u)\n", priv->tx_queue_len); + + return 0; +} + +static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) +{ + struct qtnf_bus *bus = dev_get_drvdata(s->private); + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + + seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", + priv->shm_ipc_ep_in.tx_packet_count); + seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", + priv->shm_ipc_ep_in.rx_packet_count); + seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", + priv->shm_ipc_ep_out.tx_timeout_count); + seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", + priv->shm_ipc_ep_out.rx_packet_count); + + return 0; +} + +static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct qtnf_pcie_bus_priv *pcie_priv; + struct qtnf_bus *bus; + int ret; + + bus = devm_kzalloc(&pdev->dev, + sizeof(*bus) + sizeof(*pcie_priv), GFP_KERNEL); + if (!bus) { + ret = -ENOMEM; + goto err_init; + } + + pcie_priv = get_bus_priv(bus); + + pci_set_drvdata(pdev, bus); + bus->bus_ops = &qtnf_pcie_bus_ops; + bus->dev = &pdev->dev; + bus->fw_state = QTNF_FW_STATE_RESET; + pcie_priv->pdev = pdev; + + strcpy(bus->fwname, QTN_PCI_PEARL_FW_NAME); + init_completion(&bus->request_firmware_complete); + mutex_init(&bus->bus_lock); + spin_lock_init(&pcie_priv->irq_lock); + spin_lock_init(&pcie_priv->tx_lock); + + /* init stats */ + pcie_priv->tx_full_count = 0; + pcie_priv->tx_done_count = 0; + pcie_priv->pcie_irq_count = 0; + pcie_priv->pcie_irq_rx_count = 0; + pcie_priv->pcie_irq_tx_count = 0; + pcie_priv->tx_reclaim_done = 0; + pcie_priv->tx_reclaim_req = 0; + + pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE"); + if (!pcie_priv->workqueue) { + pr_err("failed to alloc bus workqueue\n"); + ret = -ENODEV; + goto err_priv; + } + + if (!pci_is_pcie(pdev)) { + pr_err("device %s is not PCI Express\n", pci_name(pdev)); + ret = -EIO; + goto err_base; + } + + qtnf_tune_pcie_mps(pcie_priv); + + ret = pcim_enable_device(pdev); + if (ret) { + pr_err("failed to init PCI device %x\n", pdev->device); + goto err_base; + } else { + pr_debug("successful init of PCI device %x\n", pdev->device); + } + + pcim_pin_device(pdev); + pci_set_master(pdev); + + ret = qtnf_pcie_init_irq(pcie_priv); + if (ret < 0) { + pr_err("irq init failed\n"); + goto err_base; + } + + ret = qtnf_pcie_init_memory(pcie_priv); + if (ret < 0) { + pr_err("PCIE memory init failed\n"); + goto err_base; + } + + ret = qtnf_pcie_init_shm_ipc(pcie_priv); + if (ret < 0) { + pr_err("PCIE SHM IPC init failed\n"); + goto err_base; + } + + ret = qtnf_pcie_init_dma_mask(pcie_priv, DMA_BIT_MASK(32)); + if (ret) { + pr_err("PCIE DMA mask init failed\n"); + goto err_base; + } + + ret = devm_add_action(&pdev->dev, free_xfer_buffers, (void *)pcie_priv); + if (ret) { + pr_err("custom release callback init failed\n"); + goto err_base; + } + + ret = qtnf_pcie_init_xfer(pcie_priv); + if (ret) { + pr_err("PCIE xfer init failed\n"); + goto err_base; + } + + /* init default irq settings */ + qtnf_init_hdp_irqs(pcie_priv); + + /* start with disabled irqs */ + qtnf_disable_hdp_irqs(pcie_priv); + + ret = devm_request_irq(&pdev->dev, pdev->irq, &qtnf_interrupt, 0, + "qtnf_pcie_irq", (void *)bus); + if (ret) { + pr_err("failed to request pcie irq %d\n", pdev->irq); + goto err_base; + } + + tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn, + (unsigned long)pcie_priv); + init_dummy_netdev(&bus->mux_dev); + netif_napi_add(&bus->mux_dev, &bus->mux_napi, + qtnf_rx_poll, 10); + + ret = qtnf_bringup_fw(bus); + if (ret < 0) + goto err_bringup_fw; + else if (ret) + wait_for_completion(&bus->request_firmware_complete); + + if (bus->fw_state != QTNF_FW_STATE_FW_DNLD_DONE) { + pr_err("failed to start FW\n"); + goto err_bringup_fw; + } + + if (qtnf_poll_state(&pcie_priv->bda->bda_ep_state, QTN_EP_FW_QLINK_DONE, + QTN_FW_QLINK_TIMEOUT_MS)) { + pr_err("FW runtime failure\n"); + goto err_bringup_fw; + } + + ret = qtnf_core_attach(bus); + if (ret) { + pr_err("failed to attach core\n"); + goto err_bringup_fw; + } + + qtnf_debugfs_init(bus, DRV_NAME); + qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); + qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); + qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); + qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); + qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); + + return 0; + +err_bringup_fw: + netif_napi_del(&bus->mux_napi); + +err_base: + flush_workqueue(pcie_priv->workqueue); + destroy_workqueue(pcie_priv->workqueue); + +err_priv: + pci_set_drvdata(pdev, NULL); + +err_init: + return ret; +} + +static void qtnf_pcie_remove(struct pci_dev *pdev) +{ + struct qtnf_pcie_bus_priv *priv; + struct qtnf_bus *bus; + + bus = pci_get_drvdata(pdev); + if (!bus) + return; + + priv = get_bus_priv(bus); + + qtnf_core_detach(bus); + netif_napi_del(&bus->mux_napi); + + flush_workqueue(priv->workqueue); + destroy_workqueue(priv->workqueue); + tasklet_kill(&priv->reclaim_tq); + + qtnf_debugfs_remove(bus); + + qtnf_pcie_free_shm_ipc(priv); +} + +#ifdef CONFIG_PM_SLEEP +static int qtnf_pcie_suspend(struct device *dev) +{ + return -EOPNOTSUPP; +} + +static int qtnf_pcie_resume(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_SLEEP +/* Power Management Hooks */ +static SIMPLE_DEV_PM_OPS(qtnf_pcie_pm_ops, qtnf_pcie_suspend, + qtnf_pcie_resume); +#endif + +static struct pci_device_id qtnf_pcie_devid_table[] = { + { + PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table); + +static struct pci_driver qtnf_pcie_drv_data = { + .name = DRV_NAME, + .id_table = qtnf_pcie_devid_table, + .probe = qtnf_pcie_probe, + .remove = qtnf_pcie_remove, +#ifdef CONFIG_PM_SLEEP + .driver = { + .pm = &qtnf_pcie_pm_ops, + }, +#endif +}; + +static int __init qtnf_pcie_register(void) +{ + pr_info("register Quantenna QSR10g FullMAC PCIE driver\n"); + return pci_register_driver(&qtnf_pcie_drv_data); +} + +static void __exit qtnf_pcie_exit(void) +{ + pr_info("unregister Quantenna QSR10g FullMAC PCIE driver\n"); + pci_unregister_driver(&qtnf_pcie_drv_data); +} + +module_init(qtnf_pcie_register); +module_exit(qtnf_pcie_exit); + +MODULE_AUTHOR("Quantenna Communications"); +MODULE_DESCRIPTION("Quantenna QSR10g PCIe bus driver for 802.11 wireless LAN."); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h new file mode 100644 index 000000000000..2a897db2bd79 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_PCIE_H_ +#define _QTN_FMAC_PCIE_H_ + +#include +#include + +#include "pcie_regs_pearl.h" +#include "pcie_ipc.h" +#include "shm_ipc.h" + +struct bus; + +struct qtnf_pcie_bus_priv { + struct pci_dev *pdev; + + /* lock for irq configuration changes */ + spinlock_t irq_lock; + + /* lock for tx operations */ + spinlock_t tx_lock; + u8 msi_enabled; + int mps; + + struct workqueue_struct *workqueue; + struct tasklet_struct reclaim_tq; + + void __iomem *sysctl_bar; + void __iomem *epmem_bar; + void __iomem *dmareg_bar; + + struct qtnf_shm_ipc shm_ipc_ep_in; + struct qtnf_shm_ipc shm_ipc_ep_out; + + struct qtnf_pcie_bda __iomem *bda; + void __iomem *pcie_reg_base; + + u16 tx_bd_num; + u16 rx_bd_num; + + struct sk_buff **tx_skb; + struct sk_buff **rx_skb; + + struct qtnf_tx_bd *tx_bd_vbase; + dma_addr_t tx_bd_pbase; + + struct qtnf_rx_bd *rx_bd_vbase; + dma_addr_t rx_bd_pbase; + + dma_addr_t bd_table_paddr; + void *bd_table_vaddr; + u32 bd_table_len; + + u32 hw_txproc_wr_ptr; + + u16 tx_bd_reclaim_start; + u16 tx_bd_index; + u32 tx_queue_len; + + u16 rx_bd_index; + + u32 pcie_irq_mask; + + /* diagnostics stats */ + u32 pcie_irq_count; + u32 pcie_irq_rx_count; + u32 pcie_irq_tx_count; + u32 tx_full_count; + u32 tx_done_count; + u32 tx_reclaim_done; + u32 tx_reclaim_req; +}; + +#endif /* _QTN_FMAC_PCIE_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h new file mode 100644 index 000000000000..e00d508fbcf0 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_PCIE_IPC_H_ +#define _QTN_FMAC_PCIE_IPC_H_ + +#include + +#include "shm_ipc_defs.h" + +/* bitmap for EP status and flags: updated by EP, read by RC */ +#define QTN_EP_HAS_UBOOT BIT(0) +#define QTN_EP_HAS_FIRMWARE BIT(1) +#define QTN_EP_REQ_UBOOT BIT(2) +#define QTN_EP_REQ_FIRMWARE BIT(3) +#define QTN_EP_ERROR_UBOOT BIT(4) +#define QTN_EP_ERROR_FIRMWARE BIT(5) + +#define QTN_EP_FW_LOADRDY BIT(8) +#define QTN_EP_FW_SYNC BIT(9) +#define QTN_EP_FW_RETRY BIT(10) +#define QTN_EP_FW_QLINK_DONE BIT(15) +#define QTN_EP_FW_DONE BIT(16) + +/* bitmap for RC status and flags: updated by RC, read by EP */ +#define QTN_RC_PCIE_LINK BIT(0) +#define QTN_RC_NET_LINK BIT(1) +#define QTN_RC_FW_FLASHBOOT BIT(5) +#define QTN_RC_FW_QLINK BIT(7) +#define QTN_RC_FW_LOADRDY BIT(8) +#define QTN_RC_FW_SYNC BIT(9) + +/* state transition timeouts */ +#define QTN_FW_DL_TIMEOUT_MS 3000 +#define QTN_FW_QLINK_TIMEOUT_MS 30000 + +#define PCIE_HDP_INT_RX_BITS (0 \ + | PCIE_HDP_INT_EP_TXDMA \ + | PCIE_HDP_INT_EP_TXEMPTY \ + ) + +#define PCIE_HDP_INT_TX_BITS (0 \ + | PCIE_HDP_INT_EP_RXDMA \ + ) + +#if BITS_PER_LONG == 64 +#define QTN_HOST_HI32(a) ((u32)(((u64)a) >> 32)) +#define QTN_HOST_LO32(a) ((u32)(((u64)a) & 0xffffffffUL)) +#define QTN_HOST_ADDR(h, l) ((((u64)h) << 32) | ((u64)l)) +#elif BITS_PER_LONG == 32 +#define QTN_HOST_HI32(a) 0 +#define QTN_HOST_LO32(a) ((u32)(((u32)a) & 0xffffffffUL)) +#define QTN_HOST_ADDR(h, l) ((u32)l) +#else +#error Unexpected BITS_PER_LONG value +#endif + +#define QTN_SYSCTL_BAR 0 +#define QTN_SHMEM_BAR 2 +#define QTN_DMA_BAR 3 + +#define QTN_PCIE_BDA_VERSION 0x1002 + +#define PCIE_BDA_NAMELEN 32 +#define PCIE_HHBM_MAX_SIZE 512 + +#define SKB_BUF_SIZE 2048 + +#define QTN_PCIE_BOARDFLG "PCIEQTN" +#define QTN_PCIE_FW_DLMASK 0xF +#define QTN_PCIE_FW_BUFSZ 2048 + +#define QTN_ENET_ADDR_LENGTH 6 + +#define QTN_TXDONE_MASK ((u32)0x80000000) +#define QTN_GET_LEN(x) ((x) & 0xFFFF) + +#define QTN_PCIE_TX_DESC_LEN_MASK 0xFFFF +#define QTN_PCIE_TX_DESC_LEN_SHIFT 0 +#define QTN_PCIE_TX_DESC_PORT_MASK 0xF +#define QTN_PCIE_TX_DESC_PORT_SHIFT 16 +#define QTN_PCIE_TX_DESC_TQE_BIT BIT(24) + +#define QTN_EP_LHOST_TQE_PORT 4 + +enum qtnf_pcie_bda_ipc_flags { + QTN_PCIE_IPC_FLAG_HBM_MAGIC = BIT(0), + QTN_PCIE_IPC_FLAG_SHM_PIO = BIT(1), +}; + +struct qtnf_pcie_bda { + __le16 bda_len; + __le16 bda_version; + __le32 bda_pci_endian; + __le32 bda_ep_state; + __le32 bda_rc_state; + __le32 bda_dma_mask; + __le32 bda_msi_addr; + __le32 bda_flashsz; + u8 bda_boardname[PCIE_BDA_NAMELEN]; + __le32 bda_rc_msi_enabled; + __le32 bda_hhbm_list[PCIE_HHBM_MAX_SIZE]; + __le32 bda_dsbw_start_index; + __le32 bda_dsbw_end_index; + __le32 bda_dsbw_total_bytes; + __le32 bda_rc_tx_bd_base; + __le32 bda_rc_tx_bd_num; + u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH]; + struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */ + struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */ +} __packed; + +struct qtnf_tx_bd { + __le32 addr; + __le32 addr_h; + __le32 info; + __le32 info_h; +} __packed; + +struct qtnf_rx_bd { + __le32 addr; + __le32 addr_h; + __le32 info; + __le32 info_h; + __le32 next_ptr; + __le32 next_ptr_h; +} __packed; + +enum qtnf_fw_loadtype { + QTN_FW_DBEGIN, + QTN_FW_DSUB, + QTN_FW_DEND, + QTN_FW_CTRL +}; + +struct qtnf_pcie_fw_hdr { + u8 boardflg[8]; + __le32 fwsize; + __le32 seqnum; + __le32 type; + __le32 pktlen; + __le32 crc; +} __packed; + +#endif /* _QTN_FMAC_PCIE_IPC_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h new file mode 100644 index 000000000000..78715b8a8ef9 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2015 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __PEARL_PCIE_H +#define __PEARL_PCIE_H + +#define PCIE_GEN2_BASE (0xe9000000) +#define PCIE_GEN3_BASE (0xe7000000) + +#define PEARL_CUR_PCIE_BASE (PCIE_GEN2_BASE) +#define PCIE_HDP_OFFSET (0x2000) + +#define PCIE_HDP_CTRL(base) ((base) + 0x2c00) +#define PCIE_HDP_AXI_CTRL(base) ((base) + 0x2c04) +#define PCIE_HDP_HOST_WR_DESC0(base) ((base) + 0x2c10) +#define PCIE_HDP_HOST_WR_DESC0_H(base) ((base) + 0x2c14) +#define PCIE_HDP_HOST_WR_DESC1(base) ((base) + 0x2c18) +#define PCIE_HDP_HOST_WR_DESC1_H(base) ((base) + 0x2c1c) +#define PCIE_HDP_HOST_WR_DESC2(base) ((base) + 0x2c20) +#define PCIE_HDP_HOST_WR_DESC2_H(base) ((base) + 0x2c24) +#define PCIE_HDP_HOST_WR_DESC3(base) ((base) + 0x2c28) +#define PCIE_HDP_HOST_WR_DESC4_H(base) ((base) + 0x2c2c) +#define PCIE_HDP_RX_INT_CTRL(base) ((base) + 0x2c30) +#define PCIE_HDP_TX_INT_CTRL(base) ((base) + 0x2c34) +#define PCIE_HDP_INT_STATUS(base) ((base) + 0x2c38) +#define PCIE_HDP_INT_EN(base) ((base) + 0x2c3c) +#define PCIE_HDP_RX_DESC0_PTR(base) ((base) + 0x2c40) +#define PCIE_HDP_RX_DESC0_NOE(base) ((base) + 0x2c44) +#define PCIE_HDP_RX_DESC1_PTR(base) ((base) + 0x2c48) +#define PCIE_HDP_RX_DESC1_NOE(base) ((base) + 0x2c4c) +#define PCIE_HDP_RX_DESC2_PTR(base) ((base) + 0x2c50) +#define PCIE_HDP_RX_DESC2_NOE(base) ((base) + 0x2c54) +#define PCIE_HDP_RX_DESC3_PTR(base) ((base) + 0x2c58) +#define PCIE_HDP_RX_DESC3_NOE(base) ((base) + 0x2c5c) + +#define PCIE_HDP_TX0_BASE_ADDR(base) ((base) + 0x2c60) +#define PCIE_HDP_TX1_BASE_ADDR(base) ((base) + 0x2c64) +#define PCIE_HDP_TX0_Q_CTRL(base) ((base) + 0x2c70) +#define PCIE_HDP_TX1_Q_CTRL(base) ((base) + 0x2c74) +#define PCIE_HDP_CFG0(base) ((base) + 0x2c80) +#define PCIE_HDP_CFG1(base) ((base) + 0x2c84) +#define PCIE_HDP_CFG2(base) ((base) + 0x2c88) +#define PCIE_HDP_CFG3(base) ((base) + 0x2c8c) +#define PCIE_HDP_CFG4(base) ((base) + 0x2c90) +#define PCIE_HDP_CFG5(base) ((base) + 0x2c94) +#define PCIE_HDP_CFG6(base) ((base) + 0x2c98) +#define PCIE_HDP_CFG7(base) ((base) + 0x2c9c) +#define PCIE_HDP_CFG8(base) ((base) + 0x2ca0) +#define PCIE_HDP_CFG9(base) ((base) + 0x2ca4) +#define PCIE_HDP_CFG10(base) ((base) + 0x2ca8) +#define PCIE_HDP_CFG11(base) ((base) + 0x2cac) +#define PCIE_INT(base) ((base) + 0x2cb0) +#define PCIE_INT_MASK(base) ((base) + 0x2cb4) +#define PCIE_MSI_MASK(base) ((base) + 0x2cb8) +#define PCIE_MSI_PNDG(base) ((base) + 0x2cbc) +#define PCIE_PRI_CFG(base) ((base) + 0x2cc0) +#define PCIE_PHY_CR(base) ((base) + 0x2cc4) +#define PCIE_HDP_CTAG_CTRL(base) ((base) + 0x2cf4) +#define PCIE_HDP_HHBM_BUF_PTR(base) ((base) + 0x2d00) +#define PCIE_HDP_HHBM_BUF_PTR_H(base) ((base) + 0x2d04) +#define PCIE_HDP_HHBM_BUF_FIFO_NOE(base) ((base) + 0x2d04) +#define PCIE_HDP_RX0DMA_CNT(base) ((base) + 0x2d10) +#define PCIE_HDP_RX1DMA_CNT(base) ((base) + 0x2d14) +#define PCIE_HDP_RX2DMA_CNT(base) ((base) + 0x2d18) +#define PCIE_HDP_RX3DMA_CNT(base) ((base) + 0x2d1c) +#define PCIE_HDP_TX0DMA_CNT(base) ((base) + 0x2d20) +#define PCIE_HDP_TX1DMA_CNT(base) ((base) + 0x2d24) +#define PCIE_HDP_RXDMA_CTRL(base) ((base) + 0x2d28) +#define PCIE_HDP_TX_HOST_Q_SZ_CTRL(base) ((base) + 0x2d2c) +#define PCIE_HDP_TX_HOST_Q_BASE_L(base) ((base) + 0x2d30) +#define PCIE_HDP_TX_HOST_Q_BASE_H(base) ((base) + 0x2d34) +#define PCIE_HDP_TX_HOST_Q_WR_PTR(base) ((base) + 0x2d38) +#define PCIE_HDP_TX_HOST_Q_RD_PTR(base) ((base) + 0x2d3c) +#define PCIE_HDP_TX_HOST_Q_STS(base) ((base) + 0x2d40) + +/* Host HBM pool registers */ +#define PCIE_HHBM_CSR_REG(base) ((base) + 0x2e00) +#define PCIE_HHBM_Q_BASE_REG(base) ((base) + 0x2e04) +#define PCIE_HHBM_Q_LIMIT_REG(base) ((base) + 0x2e08) +#define PCIE_HHBM_Q_WR_REG(base) ((base) + 0x2e0c) +#define PCIE_HHBM_Q_RD_REG(base) ((base) + 0x2e10) +#define PCIE_HHBM_POOL_DATA_0_H(base) ((base) + 0x2e90) +#define PCIE_HHBM_CONFIG(base) ((base) + 0x2f9c) +#define PCIE_HHBM_POOL_REQ_0(base) ((base) + 0x2f10) +#define PCIE_HHBM_POOL_DATA_0(base) ((base) + 0x2f40) +#define PCIE_HHBM_WATERMARK_MASKED_INT(base) ((base) + 0x2f68) +#define PCIE_HHBM_WATERMARK_INT(base) ((base) + 0x2f6c) +#define PCIE_HHBM_POOL_WATERMARK(base) ((base) + 0x2f70) +#define PCIE_HHBM_POOL_OVERFLOW_CNT(base) ((base) + 0x2f90) +#define PCIE_HHBM_POOL_UNDERFLOW_CNT(base) ((base) + 0x2f94) +#define HBM_INT_STATUS(base) ((base) + 0x2f9c) +#define PCIE_HHBM_POOL_CNFIG(base) ((base) + 0x2f9c) + +/* host HBM bit field definition */ +#define HHBM_CONFIG_SOFT_RESET (BIT(8)) +#define HHBM_WR_REQ (BIT(0)) +#define HHBM_RD_REQ (BIT(1)) +#define HHBM_DONE (BIT(31)) + +/* offsets for dual PCIE */ +#define PCIE_PORT_LINK_CTL(base) ((base) + 0x0710) +#define PCIE_GEN2_CTL(base) ((base) + 0x080C) +#define PCIE_GEN3_OFF(base) ((base) + 0x0890) +#define PCIE_ATU_CTRL1(base) ((base) + 0x0904) +#define PCIE_ATU_CTRL2(base) ((base) + 0x0908) +#define PCIE_ATU_BASE_LOW(base) ((base) + 0x090C) +#define PCIE_ATU_BASE_HIGH(base) ((base) + 0x0910) +#define PCIE_ATU_BASE_LIMIT(base) ((base) + 0x0914) +#define PCIE_ATU_TGT_LOW(base) ((base) + 0x0918) +#define PCIE_ATU_TGT_HIGH(base) ((base) + 0x091C) +#define PCIE_DMA_WR_ENABLE(base) ((base) + 0x097C) +#define PCIE_DMA_WR_CHWTLOW(base) ((base) + 0x0988) +#define PCIE_DMA_WR_CHWTHIG(base) ((base) + 0x098C) +#define PCIE_DMA_WR_INTSTS(base) ((base) + 0x09BC) +#define PCIE_DMA_WR_INTMASK(base) ((base) + 0x09C4) +#define PCIE_DMA_WR_INTCLER(base) ((base) + 0x09C8) +#define PCIE_DMA_WR_DONE_IMWR_ADDR_L(base) ((base) + 0x09D0) +#define PCIE_DMA_WR_DONE_IMWR_ADDR_H(base) ((base) + 0x09D4) +#define PCIE_DMA_WR_ABORT_IMWR_ADDR_L(base) ((base) + 0x09D8) +#define PCIE_DMA_WR_ABORT_IMWR_ADDR_H(base) ((base) + 0x09DC) +#define PCIE_DMA_WR_IMWR_DATA(base) ((base) + 0x09E0) +#define PCIE_DMA_WR_LL_ERR_EN(base) ((base) + 0x0A00) +#define PCIE_DMA_WR_DOORBELL(base) ((base) + 0x0980) +#define PCIE_DMA_RD_ENABLE(base) ((base) + 0x099C) +#define PCIE_DMA_RD_DOORBELL(base) ((base) + 0x09A0) +#define PCIE_DMA_RD_CHWTLOW(base) ((base) + 0x09A8) +#define PCIE_DMA_RD_CHWTHIG(base) ((base) + 0x09AC) +#define PCIE_DMA_RD_INTSTS(base) ((base) + 0x0A10) +#define PCIE_DMA_RD_INTMASK(base) ((base) + 0x0A18) +#define PCIE_DMA_RD_INTCLER(base) ((base) + 0x0A1C) +#define PCIE_DMA_RD_ERR_STS_L(base) ((base) + 0x0A24) +#define PCIE_DMA_RD_ERR_STS_H(base) ((base) + 0x0A28) +#define PCIE_DMA_RD_LL_ERR_EN(base) ((base) + 0x0A34) +#define PCIE_DMA_RD_DONE_IMWR_ADDR_L(base) ((base) + 0x0A3C) +#define PCIE_DMA_RD_DONE_IMWR_ADDR_H(base) ((base) + 0x0A40) +#define PCIE_DMA_RD_ABORT_IMWR_ADDR_L(base) ((base) + 0x0A44) +#define PCIE_DMA_RD_ABORT_IMWR_ADDR_H(base) ((base) + 0x0A48) +#define PCIE_DMA_RD_IMWR_DATA(base) ((base) + 0x0A4C) +#define PCIE_DMA_CHNL_CONTEXT(base) ((base) + 0x0A6C) +#define PCIE_DMA_CHNL_CNTRL(base) ((base) + 0x0A70) +#define PCIE_DMA_XFR_SIZE(base) ((base) + 0x0A78) +#define PCIE_DMA_SAR_LOW(base) ((base) + 0x0A7C) +#define PCIE_DMA_SAR_HIGH(base) ((base) + 0x0A80) +#define PCIE_DMA_DAR_LOW(base) ((base) + 0x0A84) +#define PCIE_DMA_DAR_HIGH(base) ((base) + 0x0A88) +#define PCIE_DMA_LLPTR_LOW(base) ((base) + 0x0A8C) +#define PCIE_DMA_LLPTR_HIGH(base) ((base) + 0x0A90) +#define PCIE_DMA_WRLL_ERR_ENB(base) ((base) + 0x0A00) +#define PCIE_DMA_RDLL_ERR_ENB(base) ((base) + 0x0A34) +#define PCIE_DMABD_CHNL_CNTRL(base) ((base) + 0x8000) +#define PCIE_DMABD_XFR_SIZE(base) ((base) + 0x8004) +#define PCIE_DMABD_SAR_LOW(base) ((base) + 0x8008) +#define PCIE_DMABD_SAR_HIGH(base) ((base) + 0x800c) +#define PCIE_DMABD_DAR_LOW(base) ((base) + 0x8010) +#define PCIE_DMABD_DAR_HIGH(base) ((base) + 0x8014) +#define PCIE_DMABD_LLPTR_LOW(base) ((base) + 0x8018) +#define PCIE_DMABD_LLPTR_HIGH(base) ((base) + 0x801c) +#define PCIE_WRDMA0_CHNL_CNTRL(base) ((base) + 0x8000) +#define PCIE_WRDMA0_XFR_SIZE(base) ((base) + 0x8004) +#define PCIE_WRDMA0_SAR_LOW(base) ((base) + 0x8008) +#define PCIE_WRDMA0_SAR_HIGH(base) ((base) + 0x800c) +#define PCIE_WRDMA0_DAR_LOW(base) ((base) + 0x8010) +#define PCIE_WRDMA0_DAR_HIGH(base) ((base) + 0x8014) +#define PCIE_WRDMA0_LLPTR_LOW(base) ((base) + 0x8018) +#define PCIE_WRDMA0_LLPTR_HIGH(base) ((base) + 0x801c) +#define PCIE_WRDMA1_CHNL_CNTRL(base) ((base) + 0x8020) +#define PCIE_WRDMA1_XFR_SIZE(base) ((base) + 0x8024) +#define PCIE_WRDMA1_SAR_LOW(base) ((base) + 0x8028) +#define PCIE_WRDMA1_SAR_HIGH(base) ((base) + 0x802c) +#define PCIE_WRDMA1_DAR_LOW(base) ((base) + 0x8030) +#define PCIE_WRDMA1_DAR_HIGH(base) ((base) + 0x8034) +#define PCIE_WRDMA1_LLPTR_LOW(base) ((base) + 0x8038) +#define PCIE_WRDMA1_LLPTR_HIGH(base) ((base) + 0x803c) +#define PCIE_RDDMA0_CHNL_CNTRL(base) ((base) + 0x8040) +#define PCIE_RDDMA0_XFR_SIZE(base) ((base) + 0x8044) +#define PCIE_RDDMA0_SAR_LOW(base) ((base) + 0x8048) +#define PCIE_RDDMA0_SAR_HIGH(base) ((base) + 0x804c) +#define PCIE_RDDMA0_DAR_LOW(base) ((base) + 0x8050) +#define PCIE_RDDMA0_DAR_HIGH(base) ((base) + 0x8054) +#define PCIE_RDDMA0_LLPTR_LOW(base) ((base) + 0x8058) +#define PCIE_RDDMA0_LLPTR_HIGH(base) ((base) + 0x805c) +#define PCIE_RDDMA1_CHNL_CNTRL(base) ((base) + 0x8060) +#define PCIE_RDDMA1_XFR_SIZE(base) ((base) + 0x8064) +#define PCIE_RDDMA1_SAR_LOW(base) ((base) + 0x8068) +#define PCIE_RDDMA1_SAR_HIGH(base) ((base) + 0x806c) +#define PCIE_RDDMA1_DAR_LOW(base) ((base) + 0x8070) +#define PCIE_RDDMA1_DAR_HIGH(base) ((base) + 0x8074) +#define PCIE_RDDMA1_LLPTR_LOW(base) ((base) + 0x8078) +#define PCIE_RDDMA1_LLPTR_HIGH(base) ((base) + 0x807c) + +#define PCIE_ID(base) ((base) + 0x0000) +#define PCIE_CMD(base) ((base) + 0x0004) +#define PCIE_BAR(base, n) ((base) + 0x0010 + ((n) << 2)) +#define PCIE_CAP_PTR(base) ((base) + 0x0034) +#define PCIE_MSI_LBAR(base) ((base) + 0x0054) +#define PCIE_MSI_CTRL(base) ((base) + 0x0050) +#define PCIE_MSI_ADDR_L(base) ((base) + 0x0054) +#define PCIE_MSI_ADDR_H(base) ((base) + 0x0058) +#define PCIE_MSI_DATA(base) ((base) + 0x005C) +#define PCIE_MSI_MASK_BIT(base) ((base) + 0x0060) +#define PCIE_MSI_PEND_BIT(base) ((base) + 0x0064) +#define PCIE_DEVCAP(base) ((base) + 0x0074) +#define PCIE_DEVCTLSTS(base) ((base) + 0x0078) + +#define PCIE_CMDSTS(base) ((base) + 0x0004) +#define PCIE_LINK_STAT(base) ((base) + 0x80) +#define PCIE_LINK_CTL2(base) ((base) + 0xa0) +#define PCIE_ASPM_L1_CTRL(base) ((base) + 0x70c) +#define PCIE_ASPM_LINK_CTRL(base) (PCIE_LINK_STAT) +#define PCIE_ASPM_L1_SUBSTATE_TIMING(base) ((base) + 0xB44) +#define PCIE_L1SUB_CTRL1(base) ((base) + 0x150) +#define PCIE_PMCSR(base) ((base) + 0x44) +#define PCIE_CFG_SPACE_LIMIT(base) ((base) + 0x100) + +/* PCIe link defines */ +#define PEARL_PCIE_LINKUP (0x7) +#define PEARL_PCIE_DATA_LINK (BIT(0)) +#define PEARL_PCIE_PHY_LINK (BIT(1)) +#define PEARL_PCIE_LINK_RST (BIT(3)) +#define PEARL_PCIE_FATAL_ERR (BIT(5)) +#define PEARL_PCIE_NONFATAL_ERR (BIT(6)) + +/* PCIe Lane defines */ +#define PCIE_G2_LANE_X1 ((BIT(0)) << 16) +#define PCIE_G2_LANE_X2 ((BIT(0) | BIT(1)) << 16) + +/* PCIe DLL link enable */ +#define PCIE_DLL_LINK_EN ((BIT(0)) << 5) + +#define PCIE_LINK_GEN1 (BIT(0)) +#define PCIE_LINK_GEN2 (BIT(1)) +#define PCIE_LINK_GEN3 (BIT(2)) +#define PCIE_LINK_MODE(x) (((x) >> 16) & 0x7) + +#define MSI_EN (BIT(0)) +#define MSI_64_EN (BIT(7)) +#define PCIE_MSI_ADDR_OFFSET(a) ((a) & 0xFFFF) +#define PCIE_MSI_ADDR_ALIGN(a) ((a) & (~0xFFFF)) + +#define PCIE_BAR_MASK(base, n) ((base) + 0x1010 + ((n) << 2)) +#define PCIE_MAX_BAR (6) + +#define PCIE_ATU_VIEW(base) ((base) + 0x0900) +#define PCIE_ATU_CTL1(base) ((base) + 0x0904) +#define PCIE_ATU_CTL2(base) ((base) + 0x0908) +#define PCIE_ATU_LBAR(base) ((base) + 0x090c) +#define PCIE_ATU_UBAR(base) ((base) + 0x0910) +#define PCIE_ATU_LAR(base) ((base) + 0x0914) +#define PCIE_ATU_LTAR(base) ((base) + 0x0918) +#define PCIE_ATU_UTAR(base) ((base) + 0x091c) + +#define PCIE_MSI_ADDR_LOWER(base) ((base) + 0x0820) +#define PCIE_MSI_ADDR_UPPER(base) ((base) + 0x0824) +#define PCIE_MSI_ENABLE(base) ((base) + 0x0828) +#define PCIE_MSI_MASK_RC(base) ((base) + 0x082c) +#define PCIE_MSI_STATUS(base) ((base) + 0x0830) +#define PEARL_PCIE_MSI_REGION (0xce000000) +#define PEARL_PCIE_MSI_DATA (0) +#define PCIE_MSI_GPIO(base) ((base) + 0x0888) + +#define PCIE_HDP_HOST_QUEUE_FULL (BIT(17)) +#define USE_BAR_MATCH_MODE +#define PCIE_ATU_OB_REGION (BIT(0)) +#define PCIE_ATU_EN_REGION (BIT(31)) +#define PCIE_ATU_EN_MATCH (BIT(30)) +#define PCIE_BASE_REGION (0xb0000000) +#define PCIE_MEM_MAP_SIZE (512 * 1024) + +#define PCIE_OB_REG_REGION (0xcf000000) +#define PCIE_CONFIG_REGION (0xcf000000) +#define PCIE_CONFIG_SIZE (4096) +#define PCIE_CONFIG_CH (1) + +/* inbound mapping */ +#define PCIE_IB_BAR0 (0x00000000) /* ddr */ +#define PCIE_IB_BAR0_CH (0) +#define PCIE_IB_BAR3 (0xe0000000) /* sys_reg */ +#define PCIE_IB_BAR3_CH (1) + +/* outbound mapping */ +#define PCIE_MEM_CH (0) +#define PCIE_REG_CH (1) +#define PCIE_MEM_REGION (0xc0000000) +#define PCIE_MEM_SIZE (0x000fffff) +#define PCIE_MEM_TAR (0x80000000) + +#define PCIE_MSI_REGION (0xce000000) +#define PCIE_MSI_SIZE (KBYTE(4) - 1) +#define PCIE_MSI_CH (1) + +/* size of config region */ +#define PCIE_CFG_SIZE (0x0000ffff) + +#define PCIE_ATU_DIR_IB (BIT(31)) +#define PCIE_ATU_DIR_OB (0) +#define PCIE_ATU_DIR_CFG (2) +#define PCIE_ATU_DIR_MATCH_IB (BIT(31) | BIT(30)) + +#define PCIE_DMA_WR_0 (0) +#define PCIE_DMA_WR_1 (1) +#define PCIE_DMA_RD_0 (2) +#define PCIE_DMA_RD_1 (3) + +#define PCIE_DMA_CHNL_CNTRL_CB (BIT(0)) +#define PCIE_DMA_CHNL_CNTRL_TCB (BIT(1)) +#define PCIE_DMA_CHNL_CNTRL_LLP (BIT(2)) +#define PCIE_DMA_CHNL_CNTRL_LIE (BIT(3)) +#define PCIE_DMA_CHNL_CNTRL_RIE (BIT(4)) +#define PCIE_DMA_CHNL_CNTRL_CSS (BIT(8)) +#define PCIE_DMA_CHNL_CNTRL_LLE (BIT(9)) +#define PCIE_DMA_CHNL_CNTRL_TLP (BIT(26)) + +#define PCIE_DMA_CHNL_CONTEXT_RD (BIT(31)) +#define PCIE_DMA_CHNL_CONTEXT_WR (0) +#define PCIE_MAX_BAR (6) + +/* PCIe HDP interrupt status definition */ +#define PCIE_HDP_INT_EP_RXDMA (BIT(0)) +#define PCIE_HDP_INT_HBM_UF (BIT(1)) +#define PCIE_HDP_INT_RX_LEN_ERR (BIT(2)) +#define PCIE_HDP_INT_RX_HDR_LEN_ERR (BIT(3)) +#define PCIE_HDP_INT_EP_TXDMA (BIT(12)) +#define PCIE_HDP_INT_EP_TXEMPTY (BIT(15)) +#define PCIE_HDP_INT_IPC (BIT(29)) + +/* PCIe interrupt status definition */ +#define PCIE_INT_MSI (BIT(24)) +#define PCIE_INT_INTX (BIT(23)) + +/* PCIe legacy INTx */ +#define PEARL_PCIE_CFG0_OFFSET (0x6C) +#define PEARL_ASSERT_INTX (BIT(9)) + +/* SYS CTL regs */ +#define QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET (0x001C) + +#define QTN_PEARL_IPC_IRQ_WORD(irq) (BIT(irq) | BIT(irq + 16)) +#define QTN_PEARL_LHOST_IPC_IRQ (6) + +#endif /* __PEARL_PCIE_H */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h new file mode 100644 index 000000000000..6eafc15e0065 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -0,0 +1,901 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_QLINK_H_ +#define _QTN_QLINK_H_ + +#include + +#define QLINK_PROTO_VER 3 + +#define QLINK_MACID_RSVD 0xFF +#define QLINK_VIFID_RSVD 0xFF + +/* Common QLINK protocol messages definitions. + */ + +/** + * enum qlink_msg_type - QLINK message types + * + * Used to distinguish between message types of QLINK protocol. + * + * @QLINK_MSG_TYPE_CMD: Message is carrying data of a command sent from + * driver to wireless hardware. + * @QLINK_MSG_TYPE_CMDRSP: Message is carrying data of a response to a command. + * Sent from wireless HW to driver in reply to previously issued command. + * @QLINK_MSG_TYPE_EVENT: Data for an event originated in wireless hardware and + * sent asynchronously to driver. + */ +enum qlink_msg_type { + QLINK_MSG_TYPE_CMD = 1, + QLINK_MSG_TYPE_CMDRSP = 2, + QLINK_MSG_TYPE_EVENT = 3 +}; + +/** + * struct qlink_msg_header - common QLINK protocol message header + * + * Portion of QLINK protocol header common for all message types. + * + * @type: Message type, one of &enum qlink_msg_type. + * @len: Total length of message including all headers. + */ +struct qlink_msg_header { + __le16 type; + __le16 len; +} __packed; + +/* Generic definitions of data and information carried in QLINK messages + */ + +enum qlink_hw_capab { + QLINK_HW_SUPPORTS_REG_UPDATE = BIT(0), +}; + +enum qlink_phy_mode { + QLINK_PHYMODE_BGN = BIT(0), + QLINK_PHYMODE_AN = BIT(1), + QLINK_PHYMODE_AC = BIT(2), +}; + +enum qlink_iface_type { + QLINK_IFTYPE_AP = 1, + QLINK_IFTYPE_STATION = 2, + QLINK_IFTYPE_ADHOC = 3, + QLINK_IFTYPE_MONITOR = 4, + QLINK_IFTYPE_WDS = 5, +}; + +/** + * struct qlink_intf_info - information on virtual interface. + * + * Data describing a single virtual interface. + * + * @if_type: Mode of interface operation, one of &enum qlink_iface_type + * @flags: interface flagsmap. + * @mac_addr: MAC address of virtual interface. + */ +struct qlink_intf_info { + __le16 if_type; + __le16 flags; + u8 mac_addr[ETH_ALEN]; + u8 rsvd[2]; +} __packed; + +enum qlink_sta_flags { + QLINK_STA_FLAG_INVALID = 0, + QLINK_STA_FLAG_AUTHORIZED = BIT(0), + QLINK_STA_FLAG_SHORT_PREAMBLE = BIT(1), + QLINK_STA_FLAG_WME = BIT(2), + QLINK_STA_FLAG_MFP = BIT(3), + QLINK_STA_FLAG_AUTHENTICATED = BIT(4), + QLINK_STA_FLAG_TDLS_PEER = BIT(5), + QLINK_STA_FLAG_ASSOCIATED = BIT(6), +}; + +enum qlink_channel_width { + QLINK_CHAN_WIDTH_5 = BIT(0), + QLINK_CHAN_WIDTH_10 = BIT(1), + QLINK_CHAN_WIDTH_20_NOHT = BIT(2), + QLINK_CHAN_WIDTH_20 = BIT(3), + QLINK_CHAN_WIDTH_40 = BIT(4), + QLINK_CHAN_WIDTH_80 = BIT(5), + QLINK_CHAN_WIDTH_80P80 = BIT(6), + QLINK_CHAN_WIDTH_160 = BIT(7), +}; + +/* QLINK Command messages related definitions + */ + +/** + * enum qlink_cmd_type - list of supported commands + * + * Commands are QLINK messages of type @QLINK_MSG_TYPE_CMD, sent by driver to + * wireless network device for processing. Device is expected to send back a + * reply message of type &QLINK_MSG_TYPE_CMDRSP, containing at least command + * execution status (one of &enum qlink_cmd_result) at least. Reply message + * may also contain data payload specific to the command type. + * + * @QLINK_CMD_CHANS_INFO_GET: for the specified MAC and specified band, get + * number of operational channels and information on each of the channel. + * This command is generic to a specified MAC, interface index must be set + * to QLINK_VIFID_RSVD in command header. + */ +enum qlink_cmd_type { + QLINK_CMD_FW_INIT = 0x0001, + QLINK_CMD_FW_DEINIT = 0x0002, + QLINK_CMD_REGISTER_MGMT = 0x0003, + QLINK_CMD_SEND_MGMT_FRAME = 0x0004, + QLINK_CMD_MGMT_SET_APPIE = 0x0005, + QLINK_CMD_PHY_PARAMS_GET = 0x0011, + QLINK_CMD_PHY_PARAMS_SET = 0x0012, + QLINK_CMD_GET_HW_INFO = 0x0013, + QLINK_CMD_MAC_INFO = 0x0014, + QLINK_CMD_ADD_INTF = 0x0015, + QLINK_CMD_DEL_INTF = 0x0016, + QLINK_CMD_CHANGE_INTF = 0x0017, + QLINK_CMD_UPDOWN_INTF = 0x0018, + QLINK_CMD_REG_REGION = 0x0019, + QLINK_CMD_CHANS_INFO_GET = 0x001A, + QLINK_CMD_CONFIG_AP = 0x0020, + QLINK_CMD_START_AP = 0x0021, + QLINK_CMD_STOP_AP = 0x0022, + QLINK_CMD_GET_STA_INFO = 0x0030, + QLINK_CMD_ADD_KEY = 0x0040, + QLINK_CMD_DEL_KEY = 0x0041, + QLINK_CMD_SET_DEFAULT_KEY = 0x0042, + QLINK_CMD_SET_DEFAULT_MGMT_KEY = 0x0043, + QLINK_CMD_CHANGE_STA = 0x0051, + QLINK_CMD_DEL_STA = 0x0052, + QLINK_CMD_SCAN = 0x0053, + QLINK_CMD_CONNECT = 0x0060, + QLINK_CMD_DISCONNECT = 0x0061, +}; + +/** + * struct qlink_cmd - QLINK command message header + * + * Header used for QLINK messages of QLINK_MSG_TYPE_CMD type. + * + * @mhdr: Common QLINK message header. + * @cmd_id: command id, one of &enum qlink_cmd_type. + * @seq_num: sequence number of command message, used for matching with + * response message. + * @macid: index of physical radio device the command is destined to or + * QLINK_MACID_RSVD if not applicable. + * @vifid: index of virtual wireless interface on specified @macid the command + * is destined to or QLINK_VIFID_RSVD if not applicable. + */ +struct qlink_cmd { + struct qlink_msg_header mhdr; + __le16 cmd_id; + __le16 seq_num; + u8 rsvd[2]; + u8 macid; + u8 vifid; +} __packed; + +/** + * struct qlink_cmd_manage_intf - interface management command + * + * Data for interface management commands QLINK_CMD_ADD_INTF, QLINK_CMD_DEL_INTF + * and QLINK_CMD_CHANGE_INTF. + * + * @intf_info: interface description. + */ +struct qlink_cmd_manage_intf { + struct qlink_cmd chdr; + struct qlink_intf_info intf_info; +} __packed; + +enum qlink_mgmt_frame_type { + QLINK_MGMT_FRAME_ASSOC_REQ = 0x00, + QLINK_MGMT_FRAME_ASSOC_RESP = 0x01, + QLINK_MGMT_FRAME_REASSOC_REQ = 0x02, + QLINK_MGMT_FRAME_REASSOC_RESP = 0x03, + QLINK_MGMT_FRAME_PROBE_REQ = 0x04, + QLINK_MGMT_FRAME_PROBE_RESP = 0x05, + QLINK_MGMT_FRAME_BEACON = 0x06, + QLINK_MGMT_FRAME_ATIM = 0x07, + QLINK_MGMT_FRAME_DISASSOC = 0x08, + QLINK_MGMT_FRAME_AUTH = 0x09, + QLINK_MGMT_FRAME_DEAUTH = 0x0A, + QLINK_MGMT_FRAME_ACTION = 0x0B, + + QLINK_MGMT_FRAME_TYPE_COUNT +}; + +/** + * struct qlink_cmd_mgmt_frame_register - data for QLINK_CMD_REGISTER_MGMT + * + * @frame_type: MGMT frame type the registration request describes, one of + * &enum qlink_mgmt_frame_type. + * @do_register: 0 - unregister, otherwise register for reception of specified + * MGMT frame type. + */ +struct qlink_cmd_mgmt_frame_register { + struct qlink_cmd chdr; + __le16 frame_type; + u8 do_register; +} __packed; + +enum qlink_mgmt_frame_tx_flags { + QLINK_MGMT_FRAME_TX_FLAG_NONE = 0, + QLINK_MGMT_FRAME_TX_FLAG_OFFCHAN = BIT(0), + QLINK_MGMT_FRAME_TX_FLAG_NO_CCK = BIT(1), + QLINK_MGMT_FRAME_TX_FLAG_ACK_NOWAIT = BIT(2), +}; + +/** + * struct qlink_cmd_mgmt_frame_tx - data for QLINK_CMD_SEND_MGMT_FRAME command + * + * @cookie: opaque request identifier. + * @freq: Frequency to use for frame transmission. + * @flags: Transmission flags, one of &enum qlink_mgmt_frame_tx_flags. + * @frame_data: frame to transmit. + */ +struct qlink_cmd_mgmt_frame_tx { + struct qlink_cmd chdr; + __le32 cookie; + __le16 freq; + __le16 flags; + u8 frame_data[0]; +} __packed; + +/** + * struct qlink_cmd_mgmt_append_ie - data for QLINK_CMD_MGMT_SET_APPIE command + * + * @type: type of MGMT frame to appent requested IEs to, one of + * &enum qlink_mgmt_frame_type. + * @flags: for future use. + * @ie_data: IEs data to append. + */ +struct qlink_cmd_mgmt_append_ie { + struct qlink_cmd chdr; + u8 type; + u8 flags; + u8 ie_data[0]; +} __packed; + +/** + * struct qlink_cmd_get_sta_info - data for QLINK_CMD_GET_STA_INFO command + * + * @sta_addr: MAC address of the STA statistics is requested for. + */ +struct qlink_cmd_get_sta_info { + struct qlink_cmd chdr; + u8 sta_addr[ETH_ALEN]; +} __packed; + +/** + * struct qlink_cmd_add_key - data for QLINK_CMD_ADD_KEY command. + * + * @key_index: index of the key being installed. + * @pairwise: whether to use pairwise key. + * @addr: MAC address of a STA key is being installed to. + * @cipher: cipher suite. + * @key_data: key data itself. + */ +struct qlink_cmd_add_key { + struct qlink_cmd chdr; + u8 key_index; + u8 pairwise; + u8 addr[ETH_ALEN]; + __le32 cipher; + u8 key_data[0]; +} __packed; + +/** + * struct qlink_cmd_del_key_req - data for QLINK_CMD_DEL_KEY command + * + * @key_index: index of the key being removed. + * @pairwise: whether to use pairwise key. + * @addr: MAC address of a STA for which a key is removed. + */ +struct qlink_cmd_del_key { + struct qlink_cmd chdr; + u8 key_index; + u8 pairwise; + u8 addr[ETH_ALEN]; +} __packed; + +/** + * struct qlink_cmd_set_def_key - data for QLINK_CMD_SET_DEFAULT_KEY command + * + * @key_index: index of the key to be set as default one. + * @unicast: key is unicast. + * @multicast: key is multicast. + */ +struct qlink_cmd_set_def_key { + struct qlink_cmd chdr; + u8 key_index; + u8 unicast; + u8 multicast; +} __packed; + +/** + * struct qlink_cmd_set_def_mgmt_key - data for QLINK_CMD_SET_DEFAULT_MGMT_KEY + * + * @key_index: index of the key to be set as default MGMT key. + */ +struct qlink_cmd_set_def_mgmt_key { + struct qlink_cmd chdr; + u8 key_index; +} __packed; + +/** + * struct qlink_cmd_change_sta - data for QLINK_CMD_CHANGE_STA command + * + * @sta_flags_mask: STA flags mask, bitmap of &enum qlink_sta_flags + * @sta_flags_set: STA flags values, bitmap of &enum qlink_sta_flags + * @sta_addr: address of the STA for which parameters are set. + */ +struct qlink_cmd_change_sta { + struct qlink_cmd chdr; + __le32 sta_flags_mask; + __le32 sta_flags_set; + u8 sta_addr[ETH_ALEN]; +} __packed; + +/** + * struct qlink_cmd_del_sta - data for QLINK_CMD_DEL_STA command. + * + * See &struct station_del_parameters + */ +struct qlink_cmd_del_sta { + struct qlink_cmd chdr; + __le16 reason_code; + u8 subtype; + u8 sta_addr[ETH_ALEN]; +} __packed; + +enum qlink_sta_connect_flags { + QLINK_STA_CONNECT_DISABLE_HT = BIT(0), + QLINK_STA_CONNECT_DISABLE_VHT = BIT(1), + QLINK_STA_CONNECT_USE_RRM = BIT(2), +}; + +/** + * struct qlink_cmd_connect - data for QLINK_CMD_CONNECT command + * + * @flags: for future use. + * @freq: center frequence of a channel which should be used to connect. + * @bg_scan_period: period of background scan. + * @bssid: BSSID of the BSS to connect to. + * @payload: variable portion of connection request. + */ +struct qlink_cmd_connect { + struct qlink_cmd chdr; + __le32 flags; + __le16 freq; + __le16 bg_scan_period; + u8 bssid[ETH_ALEN]; + u8 payload[0]; +} __packed; + +/** + * struct qlink_cmd_disconnect - data for QLINK_CMD_DISCONNECT command + * + * @reason: code of the reason of disconnect, see &enum ieee80211_reasoncode. + */ +struct qlink_cmd_disconnect { + struct qlink_cmd chdr; + __le16 reason; +} __packed; + +/** + * struct qlink_cmd_updown - data for QLINK_CMD_UPDOWN_INTF command + * + * @if_up: bring specified interface DOWN (if_up==0) or UP (otherwise). + * Interface is specified in common command header @chdr. + */ +struct qlink_cmd_updown { + struct qlink_cmd chdr; + u8 if_up; +} __packed; + +/** + * enum qlink_band - a list of frequency bands + * + * @QLINK_BAND_2GHZ: 2.4GHz band + * @QLINK_BAND_5GHZ: 5GHz band + * @QLINK_BAND_60GHZ: 60GHz band + */ +enum qlink_band { + QLINK_BAND_2GHZ = BIT(0), + QLINK_BAND_5GHZ = BIT(1), + QLINK_BAND_60GHZ = BIT(2), +}; + +/** + * struct qlink_cmd_chans_info_get - data for QLINK_CMD_CHANS_INFO_GET command + * + * @band: a PHY band for which channels info is needed, one of @enum qlink_band + */ +struct qlink_cmd_chans_info_get { + struct qlink_cmd chdr; + u8 band; +} __packed; + +/* QLINK Command Responses messages related definitions + */ + +enum qlink_cmd_result { + QLINK_CMD_RESULT_OK = 0, + QLINK_CMD_RESULT_INVALID, + QLINK_CMD_RESULT_ENOTSUPP, + QLINK_CMD_RESULT_ENOTFOUND, +}; + +/** + * struct qlink_resp - QLINK command response message header + * + * Header used for QLINK messages of QLINK_MSG_TYPE_CMDRSP type. + * + * @mhdr: see &struct qlink_msg_header. + * @cmd_id: command ID the response corresponds to, one of &enum qlink_cmd_type. + * @seq_num: sequence number of command message, used for matching with + * response message. + * @result: result of the command execution, one of &enum qlink_cmd_result. + * @macid: index of physical radio device the response is sent from or + * QLINK_MACID_RSVD if not applicable. + * @vifid: index of virtual wireless interface on specified @macid the response + * is sent from or QLINK_VIFID_RSVD if not applicable. + */ +struct qlink_resp { + struct qlink_msg_header mhdr; + __le16 cmd_id; + __le16 seq_num; + __le16 result; + u8 macid; + u8 vifid; +} __packed; + +/** + * struct qlink_resp_get_mac_info - response for QLINK_CMD_MAC_INFO command + * + * Data describing specific physical device providing wireless MAC + * functionality. + * + * @dev_mac: MAC address of physical WMAC device (used for first BSS on + * specified WMAC). + * @num_tx_chain: Number of transmit chains used by WMAC. + * @num_rx_chain: Number of receive chains used by WMAC. + * @vht_cap: VHT capabilities. + * @ht_cap: HT capabilities. + * @bands_cap: wireless bands WMAC can operate in, bitmap of &enum qlink_band. + * @phymode_cap: PHY modes WMAC can operate in, bitmap of &enum qlink_phy_mode. + * @max_ap_assoc_sta: Maximum number of associations supported by WMAC. + * @radar_detect_widths: bitmask of channels BW for which WMAC can detect radar. + * @var_info: variable-length WMAC info data. + */ +struct qlink_resp_get_mac_info { + struct qlink_resp rhdr; + u8 dev_mac[ETH_ALEN]; + u8 num_tx_chain; + u8 num_rx_chain; + struct ieee80211_vht_cap vht_cap; + struct ieee80211_ht_cap ht_cap; + u8 bands_cap; + u8 phymode_cap; + __le16 max_ap_assoc_sta; + __le16 radar_detect_widths; + u8 var_info[0]; +} __packed; + +/** + * struct qlink_resp_get_hw_info - response for QLINK_CMD_GET_HW_INFO command + * + * Description of wireless hardware capabilities and features. + * + * @fw_ver: wireless hardware firmware version. + * @hw_capab: Bitmap of capabilities supported by firmware. + * @ql_proto_ver: Version of QLINK protocol used by firmware. + * @country_code: country code ID firmware is configured to. + * @num_mac: Number of separate physical radio devices provided by hardware. + * @mac_bitmap: Bitmap of MAC IDs that are active and can be used in firmware. + * @total_tx_chains: total number of transmit chains used by device. + * @total_rx_chains: total number of receive chains. + */ +struct qlink_resp_get_hw_info { + struct qlink_resp rhdr; + __le32 fw_ver; + __le32 hw_capab; + __le16 ql_proto_ver; + u8 alpha2_code[2]; + u8 num_mac; + u8 mac_bitmap; + u8 total_tx_chain; + u8 total_rx_chain; +} __packed; + +/** + * struct qlink_resp_manage_intf - response for interface management commands + * + * Response data for QLINK_CMD_ADD_INTF and QLINK_CMD_CHANGE_INTF commands. + * + * @rhdr: Common Command Response message header. + * @intf_info: interface description. + */ +struct qlink_resp_manage_intf { + struct qlink_resp rhdr; + struct qlink_intf_info intf_info; +} __packed; + +/** + * struct qlink_resp_get_sta_info - response for QLINK_CMD_GET_STA_INFO command + * + * Response data containing statistics for specified STA. + * + * @sta_addr: MAC address of STA the response carries statistic for. + * @info: statistics for specified STA. + */ +struct qlink_resp_get_sta_info { + struct qlink_resp rhdr; + u8 sta_addr[ETH_ALEN]; + u8 info[0]; +} __packed; + +/** + * struct qlink_resp_get_chan_info - response for QLINK_CMD_CHANS_INFO_GET cmd + * + * @band: frequency band to which channels belong to, one of @enum qlink_band. + * @num_chans: total number of channels info data contained in reply data. + * @info: variable-length channels info. + */ +struct qlink_resp_get_chan_info { + struct qlink_resp rhdr; + u8 band; + u8 num_chans; + u8 rsvd[2]; + u8 info[0]; +} __packed; + +/** + * struct qlink_resp_phy_params - response for QLINK_CMD_PHY_PARAMS_GET command + * + * @info: variable-length array of PHY params. + */ +struct qlink_resp_phy_params { + struct qlink_resp rhdr; + u8 info[0]; +} __packed; + +/* QLINK Events messages related definitions + */ + +enum qlink_event_type { + QLINK_EVENT_STA_ASSOCIATED = 0x0021, + QLINK_EVENT_STA_DEAUTH = 0x0022, + QLINK_EVENT_MGMT_RECEIVED = 0x0023, + QLINK_EVENT_SCAN_RESULTS = 0x0024, + QLINK_EVENT_SCAN_COMPLETE = 0x0025, + QLINK_EVENT_BSS_JOIN = 0x0026, + QLINK_EVENT_BSS_LEAVE = 0x0027, +}; + +/** + * struct qlink_event - QLINK event message header + * + * Header used for QLINK messages of QLINK_MSG_TYPE_EVENT type. + * + * @mhdr: Common QLINK message header. + * @event_id: Specifies specific event ID, one of &enum qlink_event_type. + * @macid: index of physical radio device the event was generated on or + * QLINK_MACID_RSVD if not applicable. + * @vifid: index of virtual wireless interface on specified @macid the event + * was generated on or QLINK_VIFID_RSVD if not applicable. + */ +struct qlink_event { + struct qlink_msg_header mhdr; + __le16 event_id; + u8 macid; + u8 vifid; +} __packed; + +/** + * struct qlink_event_sta_assoc - data for QLINK_EVENT_STA_ASSOCIATED event + * + * @sta_addr: Address of a STA for which new association event was generated + * @frame_control: control bits from 802.11 ASSOC_REQUEST header. + * @payload: IEs from association request. + */ +struct qlink_event_sta_assoc { + struct qlink_event ehdr; + u8 sta_addr[ETH_ALEN]; + __le16 frame_control; + u8 ies[0]; +} __packed; + +/** + * struct qlink_event_sta_deauth - data for QLINK_EVENT_STA_DEAUTH event + * + * @sta_addr: Address of a deauthenticated STA. + * @reason: reason for deauthentication. + */ +struct qlink_event_sta_deauth { + struct qlink_event ehdr; + u8 sta_addr[ETH_ALEN]; + __le16 reason; +} __packed; + +/** + * struct qlink_event_bss_join - data for QLINK_EVENT_BSS_JOIN event + * + * @bssid: BSSID of a BSS which interface tried to joined. + * @status: status of joining attempt, see &enum ieee80211_statuscode. + */ +struct qlink_event_bss_join { + struct qlink_event ehdr; + u8 bssid[ETH_ALEN]; + __le16 status; +} __packed; + +/** + * struct qlink_event_bss_leave - data for QLINK_EVENT_BSS_LEAVE event + * + * @reason: reason of disconnecting from BSS. + */ +struct qlink_event_bss_leave { + struct qlink_event ehdr; + u16 reason; +} __packed; + +enum qlink_rxmgmt_flags { + QLINK_RXMGMT_FLAG_ANSWERED = 1 << 0, +}; + +/** + * struct qlink_event_rxmgmt - data for QLINK_EVENT_MGMT_RECEIVED event + * + * @freq: Frequency on which the frame was received in MHz. + * @sig_dbm: signal strength in dBm. + * @flags: bitmap of &enum qlink_rxmgmt_flags. + * @frame_data: data of Rx'd frame itself. + */ +struct qlink_event_rxmgmt { + struct qlink_event ehdr; + __le32 freq; + __le32 sig_dbm; + __le32 flags; + u8 frame_data[0]; +} __packed; + +enum qlink_frame_type { + QLINK_BSS_FTYPE_UNKNOWN, + QLINK_BSS_FTYPE_BEACON, + QLINK_BSS_FTYPE_PRESP, +}; + +/** + * struct qlink_event_scan_result - data for QLINK_EVENT_SCAN_RESULTS event + * + * @tsf: TSF timestamp indicating when scan results were generated. + * @freq: Center frequency of the channel where BSS for which the scan result + * event was generated was discovered. + * @capab: capabilities field. + * @bintval: beacon interval announced by discovered BSS. + * @signal: signal strength. + * @frame_type: frame type used to get scan result, see &enum qlink_frame_type. + * @bssid: BSSID announced by discovered BSS. + * @ssid_len: length of SSID announced by BSS. + * @ssid: SSID announced by discovered BSS. + * @payload: IEs that are announced by discovered BSS in its MGMt frames. + */ +struct qlink_event_scan_result { + struct qlink_event ehdr; + __le64 tsf; + __le16 freq; + __le16 capab; + __le16 bintval; + s8 signal; + u8 frame_type; + u8 bssid[ETH_ALEN]; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 payload[0]; +} __packed; + +/** + * enum qlink_scan_complete_flags - indicates result of scan request. + * + * @QLINK_SCAN_NONE: Scan request was processed. + * @QLINK_SCAN_ABORTED: Scan was aborted. + */ +enum qlink_scan_complete_flags { + QLINK_SCAN_NONE = 0, + QLINK_SCAN_ABORTED = BIT(0), +}; + +/** + * struct qlink_event_scan_complete - data for QLINK_EVENT_SCAN_COMPLETE event + * + * @flags: flags indicating the status of pending scan request, + * see &enum qlink_scan_complete_flags. + */ +struct qlink_event_scan_complete { + struct qlink_event ehdr; + __le32 flags; +} __packed; + +/* QLINK TLVs (Type-Length Values) definitions + */ + +enum qlink_tlv_id { + QTN_TLV_ID_FRAG_THRESH = 0x0201, + QTN_TLV_ID_RTS_THRESH = 0x0202, + QTN_TLV_ID_SRETRY_LIMIT = 0x0203, + QTN_TLV_ID_LRETRY_LIMIT = 0x0204, + QTN_TLV_ID_BCN_PERIOD = 0x0205, + QTN_TLV_ID_DTIM = 0x0206, + QTN_TLV_ID_CHANNEL = 0x020F, + QTN_TLV_ID_COVERAGE_CLASS = 0x0213, + QTN_TLV_ID_IFACE_LIMIT = 0x0214, + QTN_TLV_ID_NUM_IFACE_COMB = 0x0215, + QTN_TLV_ID_STA_BASIC_COUNTERS = 0x0300, + QTN_TLV_ID_STA_GENERIC_INFO = 0x0301, + QTN_TLV_ID_KEY = 0x0302, + QTN_TLV_ID_SEQ = 0x0303, + QTN_TLV_ID_CRYPTO = 0x0304, + QTN_TLV_ID_IE_SET = 0x0305, +}; + +struct qlink_tlv_hdr { + __le16 type; + __le16 len; + u8 val[0]; +} __packed; + +struct qlink_iface_limit { + __le16 max_num; + __le16 type_mask; +} __packed; + +struct qlink_iface_comb_num { + __le16 iface_comb_num; +} __packed; + +struct qlink_sta_stat_basic_counters { + __le64 rx_bytes; + __le64 tx_bytes; + __le64 rx_beacons; + __le32 rx_packets; + __le32 tx_packets; + __le32 rx_dropped; + __le32 tx_failed; +} __packed; + +enum qlink_sta_info_rate_flags { + QLINK_STA_INFO_RATE_FLAG_INVALID = 0, + QLINK_STA_INFO_RATE_FLAG_HT_MCS = BIT(0), + QLINK_STA_INFO_RATE_FLAG_VHT_MCS = BIT(1), + QLINK_STA_INFO_RATE_FLAG_SHORT_GI = BIT(2), + QLINK_STA_INFO_RATE_FLAG_60G = BIT(3), +}; + +enum qlink_sta_info_rate_bw { + QLINK_STA_INFO_RATE_BW_5 = 0, + QLINK_STA_INFO_RATE_BW_10 = 1, + QLINK_STA_INFO_RATE_BW_20 = 2, + QLINK_STA_INFO_RATE_BW_40 = 3, + QLINK_STA_INFO_RATE_BW_80 = 4, + QLINK_STA_INFO_RATE_BW_160 = 5, +}; + +/** + * struct qlink_sta_info_rate - STA rate statistics + * + * @rate: data rate in Mbps. + * @flags: bitmap of &enum qlink_sta_flags. + * @mcs: 802.11-defined MCS index. + * nss: Number of Spatial Streams. + * @bw: bandwidth, one of &enum qlink_sta_info_rate_bw. + */ +struct qlink_sta_info_rate { + __le16 rate; + u8 flags; + u8 mcs; + u8 nss; + u8 bw; +} __packed; + +struct qlink_sta_info_state { + __le32 mask; + __le32 value; +} __packed; + +#define QLINK_RSSI_OFFSET 120 + +struct qlink_sta_info_generic { + struct qlink_sta_info_state state; + __le32 connected_time; + __le32 inactive_time; + struct qlink_sta_info_rate rx_rate; + struct qlink_sta_info_rate tx_rate; + u8 rssi; + u8 rssi_avg; +} __packed; + +struct qlink_tlv_frag_rts_thr { + struct qlink_tlv_hdr hdr; + __le16 thr; +} __packed; + +struct qlink_tlv_rlimit { + struct qlink_tlv_hdr hdr; + u8 rlimit; +} __packed; + +struct qlink_tlv_cclass { + struct qlink_tlv_hdr hdr; + u8 cclass; +} __packed; + +enum qlink_dfs_state { + QLINK_DFS_USABLE, + QLINK_DFS_UNAVAILABLE, + QLINK_DFS_AVAILABLE, +}; + +enum qlink_channel_flags { + QLINK_CHAN_DISABLED = BIT(0), + QLINK_CHAN_NO_IR = BIT(1), + QLINK_CHAN_RADAR = BIT(3), + QLINK_CHAN_NO_HT40PLUS = BIT(4), + QLINK_CHAN_NO_HT40MINUS = BIT(5), + QLINK_CHAN_NO_OFDM = BIT(6), + QLINK_CHAN_NO_80MHZ = BIT(7), + QLINK_CHAN_NO_160MHZ = BIT(8), + QLINK_CHAN_INDOOR_ONLY = BIT(9), + QLINK_CHAN_IR_CONCURRENT = BIT(10), + QLINK_CHAN_NO_20MHZ = BIT(11), + QLINK_CHAN_NO_10MHZ = BIT(12), +}; + +struct qlink_tlv_channel { + struct qlink_tlv_hdr hdr; + __le16 hw_value; + __le16 center_freq; + __le32 flags; + u8 band; + u8 max_antenna_gain; + u8 max_power; + u8 max_reg_power; + __le32 dfs_cac_ms; + u8 dfs_state; + u8 beacon_found; + u8 rsvd[2]; +} __packed; + +#define QLINK_MAX_NR_CIPHER_SUITES 5 +#define QLINK_MAX_NR_AKM_SUITES 2 + +struct qlink_auth_encr { + __le32 wpa_versions; + __le32 cipher_group; + __le32 n_ciphers_pairwise; + __le32 ciphers_pairwise[QLINK_MAX_NR_CIPHER_SUITES]; + __le32 n_akm_suites; + __le32 akm_suites[QLINK_MAX_NR_AKM_SUITES]; + __le16 control_port_ethertype; + u8 auth_type; + u8 privacy; + u8 mfp; + u8 control_port; + u8 control_port_no_encrypt; +} __packed; + +#endif /* _QTN_QLINK_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c new file mode 100644 index 000000000000..49ae652ad9a3 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include + +#include "qlink_util.h" + +u16 qlink_iface_type_mask_to_nl(u16 qlink_mask) +{ + u16 result = 0; + + if (qlink_mask & QLINK_IFTYPE_AP) + result |= BIT(NL80211_IFTYPE_AP); + + if (qlink_mask & QLINK_IFTYPE_STATION) + result |= BIT(NL80211_IFTYPE_STATION); + + if (qlink_mask & QLINK_IFTYPE_ADHOC) + result |= BIT(NL80211_IFTYPE_ADHOC); + + if (qlink_mask & QLINK_IFTYPE_MONITOR) + result |= BIT(NL80211_IFTYPE_MONITOR); + + if (qlink_mask & QLINK_IFTYPE_WDS) + result |= BIT(NL80211_IFTYPE_WDS); + + return result; +} + +u8 qlink_chan_width_mask_to_nl(u16 qlink_mask) +{ + u8 result = 0; + + if (qlink_mask & QLINK_CHAN_WIDTH_5) + result |= BIT(NL80211_CHAN_WIDTH_5); + + if (qlink_mask & QLINK_CHAN_WIDTH_10) + result |= BIT(NL80211_CHAN_WIDTH_10); + + if (qlink_mask & QLINK_CHAN_WIDTH_20_NOHT) + result |= BIT(NL80211_CHAN_WIDTH_20_NOHT); + + if (qlink_mask & QLINK_CHAN_WIDTH_20) + result |= BIT(NL80211_CHAN_WIDTH_20); + + if (qlink_mask & QLINK_CHAN_WIDTH_40) + result |= BIT(NL80211_CHAN_WIDTH_40); + + if (qlink_mask & QLINK_CHAN_WIDTH_80) + result |= BIT(NL80211_CHAN_WIDTH_80); + + if (qlink_mask & QLINK_CHAN_WIDTH_80P80) + result |= BIT(NL80211_CHAN_WIDTH_80P80); + + if (qlink_mask & QLINK_CHAN_WIDTH_160) + result |= BIT(NL80211_CHAN_WIDTH_160); + + return result; +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h new file mode 100644 index 000000000000..d8de484b5995 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_QLINK_UTIL_H_ +#define _QTN_FMAC_QLINK_UTIL_H_ + +#include +#include + +#include "qlink.h" + +static inline void qtnf_cmd_skb_put_action(struct sk_buff *skb, u16 action) +{ + __le16 *buf_ptr; + + buf_ptr = (__le16 *)skb_put(skb, sizeof(action)); + *buf_ptr = cpu_to_le16(action); +} + +static inline void +qtnf_cmd_skb_put_buffer(struct sk_buff *skb, const u8 *buf_src, size_t len) +{ + u8 *buf_dst; + + buf_dst = skb_put(skb, len); + memcpy(buf_dst, buf_src, len); +} + +static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb, + u16 tlv_id, const u8 arr[], + size_t arr_len) +{ + struct qlink_tlv_hdr *hdr = + (void *)skb_put(skb, sizeof(*hdr) + arr_len); + + hdr->type = cpu_to_le16(tlv_id); + hdr->len = cpu_to_le16(arr_len); + memcpy(hdr->val, arr, arr_len); +} + +static inline void qtnf_cmd_skb_put_tlv_u8(struct sk_buff *skb, u16 tlv_id, + u8 value) +{ + struct qlink_tlv_hdr *hdr = + (void *)skb_put(skb, sizeof(*hdr) + sizeof(value)); + + hdr->type = cpu_to_le16(tlv_id); + hdr->len = cpu_to_le16(sizeof(value)); + *hdr->val = value; +} + +static inline void qtnf_cmd_skb_put_tlv_u16(struct sk_buff *skb, + u16 tlv_id, u16 value) +{ + struct qlink_tlv_hdr *hdr = + (void *)skb_put(skb, sizeof(*hdr) + sizeof(value)); + __le16 tmp = cpu_to_le16(value); + + hdr->type = cpu_to_le16(tlv_id); + hdr->len = cpu_to_le16(sizeof(value)); + memcpy(hdr->val, &tmp, sizeof(tmp)); +} + +u16 qlink_iface_type_mask_to_nl(u16 qlink_mask); +u8 qlink_chan_width_mask_to_nl(u16 qlink_mask); + +#endif /* _QTN_FMAC_QLINK_UTIL_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h new file mode 100644 index 000000000000..c4ad40d59085 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_HW_IDS_H_ +#define _QTN_HW_IDS_H_ + +#include + +#define PCIE_VENDOR_ID_QUANTENNA (0x1bb5) + +/* PCIE Device IDs */ + +#define PCIE_DEVICE_ID_QTN_PEARL (0x0008) + +/* FW names */ + +#define QTN_PCI_PEARL_FW_NAME "qtn/fmac_qsr10g.img" + +#endif /* _QTN_HW_IDS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c new file mode 100644 index 000000000000..aa106dd0a14b --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +#include "shm_ipc.h" + +#undef pr_fmt +#define pr_fmt(fmt) "qtnfmac shm_ipc: %s: " fmt, __func__ + +static bool qtnf_shm_ipc_has_new_data(struct qtnf_shm_ipc *ipc) +{ + const u32 flags = readl(&ipc->shm_region->headroom.hdr.flags); + + return (flags & QTNF_SHM_IPC_NEW_DATA); +} + +static void qtnf_shm_handle_new_data(struct qtnf_shm_ipc *ipc) +{ + size_t size; + bool rx_buff_ok = true; + struct qtnf_shm_ipc_region_header __iomem *shm_reg_hdr; + + shm_reg_hdr = &ipc->shm_region->headroom.hdr; + + size = readw(&shm_reg_hdr->data_len); + + if (unlikely(size == 0 || size > QTN_IPC_MAX_DATA_SZ)) { + pr_err("wrong rx packet size: %zu\n", size); + rx_buff_ok = false; + } else { + memcpy_fromio(ipc->rx_data, ipc->shm_region->data, size); + } + + writel(QTNF_SHM_IPC_ACK, &shm_reg_hdr->flags); + readl(&shm_reg_hdr->flags); /* flush PCIe write */ + + ipc->interrupt.fn(ipc->interrupt.arg); + + if (likely(rx_buff_ok)) { + ipc->rx_packet_count++; + ipc->rx_callback.fn(ipc->rx_callback.arg, ipc->rx_data, size); + } +} + +static void qtnf_shm_ipc_irq_work(struct work_struct *work) +{ + struct qtnf_shm_ipc *ipc = container_of(work, struct qtnf_shm_ipc, + irq_work); + + while (qtnf_shm_ipc_has_new_data(ipc)) + qtnf_shm_handle_new_data(ipc); +} + +static void qtnf_shm_ipc_irq_inbound_handler(struct qtnf_shm_ipc *ipc) +{ + u32 flags; + + flags = readl(&ipc->shm_region->headroom.hdr.flags); + + if (flags & QTNF_SHM_IPC_NEW_DATA) + queue_work(ipc->workqueue, &ipc->irq_work); +} + +static void qtnf_shm_ipc_irq_outbound_handler(struct qtnf_shm_ipc *ipc) +{ + u32 flags; + + if (!READ_ONCE(ipc->waiting_for_ack)) + return; + + flags = readl(&ipc->shm_region->headroom.hdr.flags); + + if (flags & QTNF_SHM_IPC_ACK) { + WRITE_ONCE(ipc->waiting_for_ack, 0); + complete(&ipc->tx_completion); + } +} + +int qtnf_shm_ipc_init(struct qtnf_shm_ipc *ipc, + enum qtnf_shm_ipc_direction direction, + struct qtnf_shm_ipc_region __iomem *shm_region, + struct workqueue_struct *workqueue, + const struct qtnf_shm_ipc_int *interrupt, + const struct qtnf_shm_ipc_rx_callback *rx_callback) +{ + BUILD_BUG_ON(offsetof(struct qtnf_shm_ipc_region, data) != + QTN_IPC_REG_HDR_SZ); + BUILD_BUG_ON(sizeof(struct qtnf_shm_ipc_region) > QTN_IPC_REG_SZ); + + ipc->shm_region = shm_region; + ipc->direction = direction; + ipc->interrupt = *interrupt; + ipc->rx_callback = *rx_callback; + ipc->tx_packet_count = 0; + ipc->rx_packet_count = 0; + ipc->workqueue = workqueue; + ipc->waiting_for_ack = 0; + ipc->tx_timeout_count = 0; + + switch (direction) { + case QTNF_SHM_IPC_OUTBOUND: + ipc->irq_handler = qtnf_shm_ipc_irq_outbound_handler; + break; + case QTNF_SHM_IPC_INBOUND: + ipc->irq_handler = qtnf_shm_ipc_irq_inbound_handler; + break; + default: + return -EINVAL; + } + + INIT_WORK(&ipc->irq_work, qtnf_shm_ipc_irq_work); + init_completion(&ipc->tx_completion); + + return 0; +} + +void qtnf_shm_ipc_free(struct qtnf_shm_ipc *ipc) +{ + complete_all(&ipc->tx_completion); +} + +int qtnf_shm_ipc_send(struct qtnf_shm_ipc *ipc, const u8 *buf, size_t size) +{ + int ret = 0; + struct qtnf_shm_ipc_region_header __iomem *shm_reg_hdr; + + shm_reg_hdr = &ipc->shm_region->headroom.hdr; + + if (unlikely(size > QTN_IPC_MAX_DATA_SZ)) + return -E2BIG; + + ipc->tx_packet_count++; + + writew(size, &shm_reg_hdr->data_len); + memcpy_toio(ipc->shm_region->data, buf, size); + + /* sync previous writes before proceeding */ + dma_wmb(); + + WRITE_ONCE(ipc->waiting_for_ack, 1); + + /* sync previous memory write before announcing new data ready */ + wmb(); + + writel(QTNF_SHM_IPC_NEW_DATA, &shm_reg_hdr->flags); + readl(&shm_reg_hdr->flags); /* flush PCIe write */ + + ipc->interrupt.fn(ipc->interrupt.arg); + + if (!wait_for_completion_timeout(&ipc->tx_completion, + QTN_SHM_IPC_ACK_TIMEOUT)) { + ret = -ETIMEDOUT; + ipc->tx_timeout_count++; + pr_err("TX ACK timeout\n"); + } + + /* now we're not waiting for ACK even in case of timeout */ + WRITE_ONCE(ipc->waiting_for_ack, 0); + + return ret; +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h new file mode 100644 index 000000000000..453dd6477b12 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_SHM_IPC_H_ +#define _QTN_FMAC_SHM_IPC_H_ + +#include +#include +#include +#include + +#include "shm_ipc_defs.h" + +#define QTN_SHM_IPC_ACK_TIMEOUT (2 * HZ) + +struct qtnf_shm_ipc_int { + void (*fn)(void *arg); + void *arg; +}; + +struct qtnf_shm_ipc_rx_callback { + void (*fn)(void *arg, const u8 *buf, size_t len); + void *arg; +}; + +enum qtnf_shm_ipc_direction { + QTNF_SHM_IPC_OUTBOUND = BIT(0), + QTNF_SHM_IPC_INBOUND = BIT(1), +}; + +struct qtnf_shm_ipc { + struct qtnf_shm_ipc_region __iomem *shm_region; + enum qtnf_shm_ipc_direction direction; + size_t tx_packet_count; + size_t rx_packet_count; + + size_t tx_timeout_count; + + u8 waiting_for_ack; + + u8 rx_data[QTN_IPC_MAX_DATA_SZ] __aligned(sizeof(u32)); + + struct qtnf_shm_ipc_int interrupt; + struct qtnf_shm_ipc_rx_callback rx_callback; + + void (*irq_handler)(struct qtnf_shm_ipc *ipc); + + struct workqueue_struct *workqueue; + struct work_struct irq_work; + struct completion tx_completion; +}; + +int qtnf_shm_ipc_init(struct qtnf_shm_ipc *ipc, + enum qtnf_shm_ipc_direction direction, + struct qtnf_shm_ipc_region __iomem *shm_region, + struct workqueue_struct *workqueue, + const struct qtnf_shm_ipc_int *interrupt, + const struct qtnf_shm_ipc_rx_callback *rx_callback); +void qtnf_shm_ipc_free(struct qtnf_shm_ipc *ipc); +int qtnf_shm_ipc_send(struct qtnf_shm_ipc *ipc, const u8 *buf, size_t size); + +static inline void qtnf_shm_ipc_irq_handler(struct qtnf_shm_ipc *ipc) +{ + ipc->irq_handler(ipc); +} + +#endif /* _QTN_FMAC_SHM_IPC_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc_defs.h b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc_defs.h new file mode 100644 index 000000000000..95a5f89a8b1a --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc_defs.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_SHM_IPC_DEFS_H_ +#define _QTN_FMAC_SHM_IPC_DEFS_H_ + +#include + +#define QTN_IPC_REG_HDR_SZ (32) +#define QTN_IPC_REG_SZ (4096) +#define QTN_IPC_MAX_DATA_SZ (QTN_IPC_REG_SZ - QTN_IPC_REG_HDR_SZ) + +enum qtnf_shm_ipc_region_flags { + QTNF_SHM_IPC_NEW_DATA = BIT(0), + QTNF_SHM_IPC_ACK = BIT(1), +}; + +struct qtnf_shm_ipc_region_header { + __le32 flags; + __le16 data_len; +} __packed; + +union qtnf_shm_ipc_region_headroom { + struct qtnf_shm_ipc_region_header hdr; + u8 headroom[QTN_IPC_REG_HDR_SZ]; +} __packed; + +struct qtnf_shm_ipc_region { + union qtnf_shm_ipc_region_headroom headroom; + u8 data[QTN_IPC_MAX_DATA_SZ]; +} __packed; + +#endif /* _QTN_FMAC_SHM_IPC_DEFS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/trans.c b/drivers/net/wireless/quantenna/qtnfmac/trans.c new file mode 100644 index 000000000000..ccddfebc508a --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/trans.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#include "core.h" +#include "commands.h" +#include "event.h" +#include "bus.h" + +#define QTNF_DEF_SYNC_CMD_TIMEOUT (5 * HZ) + +int qtnf_trans_send_cmd_with_resp(struct qtnf_bus *bus, struct sk_buff *cmd_skb, + struct sk_buff **response_skb) +{ + struct qtnf_cmd_ctl_node *ctl_node = &bus->trans.curr_cmd; + struct qlink_cmd *cmd = (void *)cmd_skb->data; + int ret = 0; + long status; + bool resp_not_handled = true; + struct sk_buff *resp_skb = NULL; + + if (unlikely(!response_skb)) + return -EFAULT; + + spin_lock(&ctl_node->resp_lock); + ctl_node->seq_num++; + cmd->seq_num = cpu_to_le16(ctl_node->seq_num); + WARN(ctl_node->resp_skb, "qtnfmac: response skb not empty\n"); + ctl_node->waiting_for_resp = true; + spin_unlock(&ctl_node->resp_lock); + + ret = qtnf_bus_control_tx(bus, cmd_skb); + dev_kfree_skb(cmd_skb); + + if (unlikely(ret)) + goto out; + + status = wait_for_completion_interruptible_timeout( + &ctl_node->cmd_resp_completion, + QTNF_DEF_SYNC_CMD_TIMEOUT); + + spin_lock(&ctl_node->resp_lock); + resp_not_handled = ctl_node->waiting_for_resp; + resp_skb = ctl_node->resp_skb; + ctl_node->resp_skb = NULL; + ctl_node->waiting_for_resp = false; + spin_unlock(&ctl_node->resp_lock); + + if (unlikely(status <= 0)) { + if (status == 0) { + ret = -ETIMEDOUT; + pr_err("response timeout\n"); + } else { + ret = -EINTR; + pr_debug("interrupted\n"); + } + } + + if (unlikely(!resp_skb || resp_not_handled)) { + if (!ret) + ret = -EFAULT; + + goto out; + } + + ret = 0; + *response_skb = resp_skb; + +out: + if (unlikely(resp_skb && resp_not_handled)) + dev_kfree_skb(resp_skb); + + return ret; +} + +static void qtnf_trans_signal_cmdresp(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_cmd_ctl_node *ctl_node = &bus->trans.curr_cmd; + const struct qlink_resp *resp = (const struct qlink_resp *)skb->data; + const u16 recvd_seq_num = le16_to_cpu(resp->seq_num); + + spin_lock(&ctl_node->resp_lock); + + if (unlikely(!ctl_node->waiting_for_resp)) { + pr_err("unexpected response\n"); + goto out_err; + } + + if (unlikely(recvd_seq_num != ctl_node->seq_num)) { + pr_err("seq num mismatch\n"); + goto out_err; + } + + ctl_node->resp_skb = skb; + ctl_node->waiting_for_resp = false; + + spin_unlock(&ctl_node->resp_lock); + + complete(&ctl_node->cmd_resp_completion); + return; + +out_err: + spin_unlock(&ctl_node->resp_lock); + dev_kfree_skb(skb); +} + +static int qtnf_trans_event_enqueue(struct qtnf_bus *bus, struct sk_buff *skb) +{ + struct qtnf_qlink_transport *trans = &bus->trans; + + if (likely(skb_queue_len(&trans->event_queue) < + trans->event_queue_max_len)) { + skb_queue_tail(&trans->event_queue, skb); + queue_work(bus->workqueue, &bus->event_work); + } else { + pr_warn("event dropped due to queue overflow\n"); + dev_kfree_skb(skb); + return -1; + } + + return 0; +} + +void qtnf_trans_init(struct qtnf_bus *bus) +{ + struct qtnf_qlink_transport *trans = &bus->trans; + + init_completion(&trans->curr_cmd.cmd_resp_completion); + spin_lock_init(&trans->curr_cmd.resp_lock); + + spin_lock(&trans->curr_cmd.resp_lock); + trans->curr_cmd.seq_num = 0; + trans->curr_cmd.waiting_for_resp = false; + trans->curr_cmd.resp_skb = NULL; + spin_unlock(&trans->curr_cmd.resp_lock); + + /* Init event handling related fields */ + skb_queue_head_init(&trans->event_queue); + trans->event_queue_max_len = QTNF_MAX_EVENT_QUEUE_LEN; +} + +static void qtnf_trans_free_events(struct qtnf_bus *bus) +{ + struct sk_buff_head *event_queue = &bus->trans.event_queue; + struct sk_buff *current_event_skb = skb_dequeue(event_queue); + + while (current_event_skb) { + dev_kfree_skb_any(current_event_skb); + current_event_skb = skb_dequeue(event_queue); + } +} + +void qtnf_trans_free(struct qtnf_bus *bus) +{ + if (!bus) { + pr_err("invalid bus pointer\n"); + return; + } + + qtnf_trans_free_events(bus); +} + +int qtnf_trans_handle_rx_ctl_packet(struct qtnf_bus *bus, struct sk_buff *skb) +{ + const struct qlink_msg_header *header = (void *)skb->data; + int ret = -1; + + if (unlikely(skb->len < sizeof(*header))) { + pr_warn("packet is too small: %u\n", skb->len); + dev_kfree_skb(skb); + return -EINVAL; + } + + if (unlikely(skb->len != le16_to_cpu(header->len))) { + pr_warn("cmd reply length mismatch: %u != %u\n", + skb->len, le16_to_cpu(header->len)); + dev_kfree_skb(skb); + return -EFAULT; + } + + switch (le16_to_cpu(header->type)) { + case QLINK_MSG_TYPE_CMDRSP: + if (unlikely(skb->len < sizeof(struct qlink_cmd))) { + pr_warn("cmd reply too short: %u\n", skb->len); + dev_kfree_skb(skb); + break; + } + + qtnf_trans_signal_cmdresp(bus, skb); + break; + case QLINK_MSG_TYPE_EVENT: + if (unlikely(skb->len < sizeof(struct qlink_event))) { + pr_warn("event too short: %u\n", skb->len); + dev_kfree_skb(skb); + break; + } + + ret = qtnf_trans_event_enqueue(bus, skb); + break; + default: + pr_warn("unknown packet type: %x\n", le16_to_cpu(header->type)); + dev_kfree_skb(skb); + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(qtnf_trans_handle_rx_ctl_packet); diff --git a/drivers/net/wireless/quantenna/qtnfmac/trans.h b/drivers/net/wireless/quantenna/qtnfmac/trans.h new file mode 100644 index 000000000000..9a473e07af0f --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/trans.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QTN_FMAC_TRANS_H_ +#define _QTN_FMAC_TRANS_H_ + +#include +#include +#include +#include + +#include "qlink.h" + +#define QTNF_CMD_FLAG_RESP_REQ BIT(0) + +#define QTNF_MAX_CMD_BUF_SIZE 2048 +#define QTNF_DEF_CMD_HROOM 4 + +struct qtnf_bus; + +struct qtnf_cmd_ctl_node { + struct completion cmd_resp_completion; + struct sk_buff *resp_skb; + u16 seq_num; + bool waiting_for_resp; + spinlock_t resp_lock; /* lock for resp_skb & waiting_for_resp changes */ +}; + +struct qtnf_qlink_transport { + struct qtnf_cmd_ctl_node curr_cmd; + struct sk_buff_head event_queue; + size_t event_queue_max_len; +}; + +void qtnf_trans_init(struct qtnf_bus *bus); +void qtnf_trans_free(struct qtnf_bus *bus); + +int qtnf_trans_send_next_cmd(struct qtnf_bus *bus); +int qtnf_trans_handle_rx_ctl_packet(struct qtnf_bus *bus, struct sk_buff *skb); +int qtnf_trans_send_cmd_with_resp(struct qtnf_bus *bus, + struct sk_buff *cmd_skb, + struct sk_buff **response_skb); + +#endif /* _QTN_FMAC_TRANS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/util.c b/drivers/net/wireless/quantenna/qtnfmac/util.c new file mode 100644 index 000000000000..ed38e87471bf --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/util.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015-2016 Quantenna Communications, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "util.h" + +void qtnf_sta_list_init(struct qtnf_sta_list *list) +{ + if (unlikely(!list)) + return; + + INIT_LIST_HEAD(&list->head); + atomic_set(&list->size, 0); +} + +struct qtnf_sta_node *qtnf_sta_list_lookup(struct qtnf_sta_list *list, + const u8 *mac) +{ + struct qtnf_sta_node *node; + + if (unlikely(!mac)) + return NULL; + + list_for_each_entry(node, &list->head, list) { + if (ether_addr_equal(node->mac_addr, mac)) + return node; + } + + return NULL; +} + +struct qtnf_sta_node *qtnf_sta_list_lookup_index(struct qtnf_sta_list *list, + size_t index) +{ + struct qtnf_sta_node *node; + + if (qtnf_sta_list_size(list) <= index) + return NULL; + + list_for_each_entry(node, &list->head, list) { + if (index-- == 0) + return node; + } + + return NULL; +} + +struct qtnf_sta_node *qtnf_sta_list_add(struct qtnf_sta_list *list, + const u8 *mac) +{ + struct qtnf_sta_node *node; + + if (unlikely(!mac)) + return NULL; + + node = qtnf_sta_list_lookup(list, mac); + + if (node) + goto done; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (unlikely(!node)) + goto done; + + ether_addr_copy(node->mac_addr, mac); + list_add_tail(&node->list, &list->head); + atomic_inc(&list->size); + +done: + return node; +} + +bool qtnf_sta_list_del(struct qtnf_sta_list *list, const u8 *mac) +{ + struct qtnf_sta_node *node; + bool ret = false; + + node = qtnf_sta_list_lookup(list, mac); + + if (node) { + list_del(&node->list); + atomic_dec(&list->size); + kfree(node); + ret = true; + } + + return ret; +} + +void qtnf_sta_list_free(struct qtnf_sta_list *list) +{ + struct qtnf_sta_node *node, *tmp; + + atomic_set(&list->size, 0); + + list_for_each_entry_safe(node, tmp, &list->head, list) { + list_del(&node->list); + kfree(node); + } + + INIT_LIST_HEAD(&list->head); +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/util.h b/drivers/net/wireless/quantenna/qtnfmac/util.h new file mode 100644 index 000000000000..0359eae8c24b --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/util.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 Quantenna Communications + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef QTNFMAC_UTIL_H +#define QTNFMAC_UTIL_H + +#include +#include "core.h" + +void qtnf_sta_list_init(struct qtnf_sta_list *list); + +struct qtnf_sta_node *qtnf_sta_list_lookup(struct qtnf_sta_list *list, + const u8 *mac); +struct qtnf_sta_node *qtnf_sta_list_lookup_index(struct qtnf_sta_list *list, + size_t index); +struct qtnf_sta_node *qtnf_sta_list_add(struct qtnf_sta_list *list, + const u8 *mac); +bool qtnf_sta_list_del(struct qtnf_sta_list *list, const u8 *mac); + +void qtnf_sta_list_free(struct qtnf_sta_list *list); + +static inline size_t qtnf_sta_list_size(const struct qtnf_sta_list *list) +{ + return atomic_read(&list->size); +} + +static inline bool qtnf_sta_list_empty(const struct qtnf_sta_list *list) +{ + return list_empty(&list->head); +} + +#endif /* QTNFMAC_UTIL_H */ -- cgit v1.2.3 From 48848a0690a36d0248255f6c3b7b6fd2a9948a57 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Tue, 23 May 2017 09:41:18 +0300 Subject: qede: Fix sparse warnings Solves the following warning in qede - - Several cases of missing cpu_to_le16() conversions - Adds 'static' to one function declaration - Removes dcbnl operation that's currently getting populated twice Signed-off-by: Manish Chopra Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_dcbnl.c | 1 - drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 10 ++++++---- drivers/net/ethernet/qlogic/qede/qede_fp.c | 25 ++++++++++++++----------- drivers/net/ethernet/qlogic/qede/qede_roce.c | 4 ++-- 4 files changed, 22 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_dcbnl.c b/drivers/net/ethernet/qlogic/qede/qede_dcbnl.c index a9e7379313db..6e7747b9b95e 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_dcbnl.c +++ b/drivers/net/ethernet/qlogic/qede/qede_dcbnl.c @@ -313,7 +313,6 @@ static const struct dcbnl_rtnl_ops qede_dcbnl_ops = { .ieee_setets = qede_dcbnl_ieee_setets, .ieee_getapp = qede_dcbnl_ieee_getapp, .ieee_setapp = qede_dcbnl_ieee_setapp, - .getdcbx = qede_dcbnl_getdcbx, .ieee_peer_getpfc = qede_dcbnl_ieee_peer_getpfc, .ieee_peer_getets = qede_dcbnl_ieee_peer_getets, .getstate = qede_dcbnl_getstate, diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 6c76a12c4e0d..6a03d3e66cff 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -1290,7 +1290,8 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, struct qede_tx_queue *txq = NULL; struct eth_tx_1st_bd *first_bd; dma_addr_t mapping; - int i, idx, val; + int i, idx; + u16 val; for_each_queue(i) { if (edev->fp_array[i].type & QEDE_FASTPATH_TX) { @@ -1312,7 +1313,8 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT; first_bd->data.bd_flags.bitfields = val; val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK; - first_bd->data.bitfields |= (val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT); + val = val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; + first_bd->data.bitfields |= cpu_to_le16(val); /* Map skb linear data for DMA and set in the first BD */ mapping = dma_map_single(&edev->pdev->dev, skb->data, @@ -1327,8 +1329,8 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, first_bd->data.nbds = 1; txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers; /* 'next page' entries are counted in the producer value */ - val = cpu_to_le16(qed_chain_get_prod_idx(&txq->tx_pbl)); - txq->tx_db.data.bd_prod = val; + val = qed_chain_get_prod_idx(&txq->tx_pbl); + txq->tx_db.data.bd_prod = cpu_to_le16(val); /* wmb makes sure that the BDs data is updated before updating the * producer, otherwise FW may read old data from the BDs. diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index 38c82658e5bd..892eb98290f6 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -335,6 +335,7 @@ static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp, struct qede_tx_queue *txq = fp->xdp_tx; struct eth_tx_1st_bd *first_bd; u16 idx = txq->sw_tx_prod; + u16 val; if (!qed_chain_get_elem_left(&txq->tx_pbl)) { txq->stopped_cnt++; @@ -346,9 +347,11 @@ static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp, memset(first_bd, 0, sizeof(*first_bd)); first_bd->data.bd_flags.bitfields = BIT(ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT); - first_bd->data.bitfields |= - (length & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) << - ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; + + val = (length & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) << + ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; + + first_bd->data.bitfields |= cpu_to_le16(val); first_bd->data.nbds = 1; /* We can safely ignore the offset, as it's 0 for XDP */ @@ -1424,7 +1427,7 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct eth_tx_2nd_bd *second_bd = NULL; struct eth_tx_3rd_bd *third_bd = NULL; struct eth_tx_bd *tx_data_bd = NULL; - u16 txq_index; + u16 txq_index, val = 0; u8 nbd = 0; dma_addr_t mapping; int rc, frag_idx = 0, ipv6_ext = 0; @@ -1513,8 +1516,8 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (xmit_type & XMIT_ENC) { first_bd->data.bd_flags.bitfields |= 1 << ETH_TX_1ST_BD_FLAGS_IP_CSUM_SHIFT; - first_bd->data.bitfields |= - 1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT; + + val |= (1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT); } /* Legacy FW had flipped behavior in regard to this bit - @@ -1522,8 +1525,7 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) * packets when it didn't need to. */ if (unlikely(txq->is_legacy)) - first_bd->data.bitfields ^= - 1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT; + val ^= (1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT); /* If the packet is IPv6 with extension header, indicate that * to FW and pass few params, since the device cracker doesn't @@ -1587,11 +1589,12 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev) data_split = true; } } else { - first_bd->data.bitfields |= - (skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) << - ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; + val |= ((skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) << + ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT); } + first_bd->data.bitfields = cpu_to_le16(val); + /* Handle fragmented skb */ /* special handle for frags inside 2nd and 3rd bds.. */ while (tx_data_bd && frag_idx < skb_shinfo(skb)->nr_frags) { diff --git a/drivers/net/ethernet/qlogic/qede/qede_roce.c b/drivers/net/ethernet/qlogic/qede/qede_roce.c index f00657ce7c8f..c0030fb8d842 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_roce.c +++ b/drivers/net/ethernet/qlogic/qede/qede_roce.c @@ -221,8 +221,8 @@ static void qede_roce_changeaddr(struct qede_dev *edev) qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_CHANGE_ADDR); } -struct qede_roce_event_work *qede_roce_get_free_event_node(struct qede_dev - *edev) +static struct qede_roce_event_work * +qede_roce_get_free_event_node(struct qede_dev *edev) { struct qede_roce_event_work *event_node = NULL; struct list_head *list_node = NULL; -- cgit v1.2.3 From 4f64675fac061746be112047fab5979e86768a08 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Tue, 23 May 2017 09:41:20 +0300 Subject: qed: !main_ptt for tunnel configuration Flows configuring tunnel ports in HW use the main_ptt which should be reserved for core-functionality. Signed-off-by: Manish Chopra Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 3 ++- drivers/net/ethernet/qlogic/qed/qed_l2.c | 17 +++++++++++++++-- drivers/net/ethernet/qlogic/qed/qed_sp.h | 3 +++ drivers/net/ethernet/qlogic/qed/qed_sp_commands.c | 14 +++++++++----- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 2 +- 5 files changed, 30 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 3fc3b2e03ef0..9dd28baba5a1 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1513,7 +1513,8 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, qed_int_igu_enable(p_hwfn, p_ptt, int_mode); /* send function start command */ - rc = qed_sp_pf_start(p_hwfn, p_tunn, p_hwfn->cdev->mf_mode, + rc = qed_sp_pf_start(p_hwfn, p_ptt, p_tunn, + p_hwfn->cdev->mf_mode, allow_npar_tx_switch); if (rc) { DP_NOTICE(p_hwfn, "Function start ramrod failed\n"); diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index fab6e697c3ab..93dd781cf61d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -2300,14 +2300,25 @@ static int qed_tunn_configure(struct qed_dev *cdev, for_each_hwfn(cdev, i) { struct qed_hwfn *hwfn = &cdev->hwfns[i]; + struct qed_ptt *p_ptt; struct qed_tunnel_info *tun; tun = &hwfn->cdev->tunnel; + if (IS_PF(cdev)) { + p_ptt = qed_ptt_acquire(hwfn); + if (!p_ptt) + return -EAGAIN; + } else { + p_ptt = NULL; + } - rc = qed_sp_pf_update_tunn_cfg(hwfn, &tunn_info, + rc = qed_sp_pf_update_tunn_cfg(hwfn, p_ptt, &tunn_info, QED_SPQ_MODE_EBLOCK, NULL); - if (rc) + if (rc) { + if (IS_PF(cdev)) + qed_ptt_release(hwfn, p_ptt); return rc; + } if (IS_PF_SRIOV(hwfn)) { u16 vxlan_port, geneve_port; @@ -2324,6 +2335,8 @@ static int qed_tunn_configure(struct qed_dev *cdev, qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG); } + if (IS_PF(cdev)) + qed_ptt_release(hwfn, p_ptt); } return 0; diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index c0b56b98d2ea..ef77de4de5f2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -391,6 +391,7 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn, * to the internal RAM of the UStorm by the Function Start Ramrod. * * @param p_hwfn + * @param p_ptt * @param p_tunn * @param mode * @param allow_npar_tx_switch @@ -399,6 +400,7 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn, */ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn, enum qed_mf_mode mode, bool allow_npar_tx_switch); @@ -432,6 +434,7 @@ int qed_sp_pf_update(struct qed_hwfn *p_hwfn); int qed_sp_pf_stop(struct qed_hwfn *p_hwfn); int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn, enum spq_mode comp_mode, struct qed_spq_comp_cb *p_comp_data); diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c index 5abcac64d969..ab09975343cb 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c @@ -253,17 +253,18 @@ static void qed_set_hw_tunn_mode(struct qed_hwfn *p_hwfn, } static void qed_set_hw_tunn_mode_port(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn) { if (p_tunn->vxlan_port.b_update_port) - qed_set_vxlan_dest_port(p_hwfn, p_hwfn->p_main_ptt, + qed_set_vxlan_dest_port(p_hwfn, p_ptt, p_tunn->vxlan_port.port); if (p_tunn->geneve_port.b_update_port) - qed_set_geneve_dest_port(p_hwfn, p_hwfn->p_main_ptt, + qed_set_geneve_dest_port(p_hwfn, p_ptt, p_tunn->geneve_port.port); - qed_set_hw_tunn_mode(p_hwfn, p_hwfn->p_main_ptt, p_tunn); + qed_set_hw_tunn_mode(p_hwfn, p_ptt, p_tunn); } static void @@ -303,6 +304,7 @@ qed_tunn_set_pf_start_params(struct qed_hwfn *p_hwfn, } int qed_sp_pf_start(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn, enum qed_mf_mode mode, bool allow_npar_tx_switch) { @@ -399,7 +401,8 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, rc = qed_spq_post(p_hwfn, p_ent, NULL); if (p_tunn) - qed_set_hw_tunn_mode_port(p_hwfn, &p_hwfn->cdev->tunnel); + qed_set_hw_tunn_mode_port(p_hwfn, p_ptt, + &p_hwfn->cdev->tunnel); return rc; } @@ -430,6 +433,7 @@ int qed_sp_pf_update(struct qed_hwfn *p_hwfn) /* Set pf update ramrod command params */ int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_tunnel_info *p_tunn, enum spq_mode comp_mode, struct qed_spq_comp_cb *p_comp_data) @@ -464,7 +468,7 @@ int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn, if (rc) return rc; - qed_set_hw_tunn_mode_port(p_hwfn, &p_hwfn->cdev->tunnel); + qed_set_hw_tunn_mode_port(p_hwfn, p_ptt, &p_hwfn->cdev->tunnel); return rc; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index f5ed54d611ec..71e392fe1d97 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -2209,7 +2209,7 @@ static void qed_iov_vf_mbx_update_tunn_param(struct qed_hwfn *p_hwfn, if (b_update_required) { u16 geneve_port; - rc = qed_sp_pf_update_tunn_cfg(p_hwfn, &tunn, + rc = qed_sp_pf_update_tunn_cfg(p_hwfn, p_ptt, &tunn, QED_SPQ_MODE_EBLOCK, NULL); if (rc) status = PFVF_STATUS_FAILURE; -- cgit v1.2.3 From fc561c8bfe831c1509b7f6af3f45fbea78632539 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Tue, 23 May 2017 09:41:21 +0300 Subject: qed: Log incorrectly installed board In case nvram layout of board is incorrect, board may exhibit peculiar oddities. Log such a rare event. Signed-off-by: Tomer Tayar Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 5 +++++ drivers/net/ethernet/qlogic/qed/qed_hsi.h | 2 ++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 9dd28baba5a1..b01df2400075 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1698,6 +1698,11 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) return mfw_rc; } + /* Check if there is a DID mismatch between nvm-cfg/efuse */ + if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) + DP_NOTICE(p_hwfn, + "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); + /* send DCBX attention request command */ DP_VERBOSE(p_hwfn, QED_MSG_DCB, diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index eedf79a026a2..4755d0b33b90 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -11655,6 +11655,8 @@ struct public_drv_mb { #define FW_MB_PARAM_GET_PF_RDMA_IWARP 0x2 #define FW_MB_PARAM_GET_PF_RDMA_BOTH 0x3 +#define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR (1 << 0) + u32 drv_pulse_mb; #define DRV_PULSE_SEQ_MASK 0x00007fff #define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000 -- cgit v1.2.3 From 78cea9ffaa34d289212a2444c2e357f7dabcf674 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Tue, 23 May 2017 09:41:22 +0300 Subject: qed: Drop the 's' from num_ports_in_engines The parameter reflects the number of physical ports connected to a single engine, not all. Signed-off-by: Tomer Tayar Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 2 +- drivers/net/ethernet/qlogic/qed/qed_dev.c | 36 +++++++++++++++---------------- drivers/net/ethernet/qlogic/qed/qed_mcp.h | 2 +- drivers/net/ethernet/qlogic/qed/qed_ptp.c | 4 ++-- 4 files changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index fd8cf31cce05..63c44c60eef3 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -633,7 +633,7 @@ struct qed_dev { #define CHIP_BOND_ID_SHIFT 0 u8 num_engines; - u8 num_ports_in_engines; + u8 num_ports_in_engine; u8 num_funcs_in_port; u8 path_id; diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index b01df2400075..51ae9071f3df 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -300,7 +300,7 @@ static void qed_init_qm_params(struct qed_hwfn *p_hwfn) qm_info->vport_wfq_en = 1; /* TC config is different for AH 4 port */ - four_port = p_hwfn->cdev->num_ports_in_engines == MAX_NUM_PORTS_K2; + four_port = p_hwfn->cdev->num_ports_in_engine == MAX_NUM_PORTS_K2; /* in AH 4 port we have fewer TCs per port */ qm_info->max_phys_tcs_per_port = four_port ? NUM_PHYS_TCS_4PORT_K2 : @@ -329,7 +329,7 @@ static void qed_init_qm_vport_params(struct qed_hwfn *p_hwfn) static void qed_init_qm_port_params(struct qed_hwfn *p_hwfn) { /* Initialize qm port parameters */ - u8 i, active_phys_tcs, num_ports = p_hwfn->cdev->num_ports_in_engines; + u8 i, active_phys_tcs, num_ports = p_hwfn->cdev->num_ports_in_engine; /* indicate how ooo and high pri traffic is dealt with */ active_phys_tcs = num_ports == MAX_NUM_PORTS_K2 ? @@ -693,7 +693,7 @@ static void qed_dp_init_qm_params(struct qed_hwfn *p_hwfn) qm_info->num_pf_rls, qed_get_pq_flags(p_hwfn)); /* port table */ - for (i = 0; i < p_hwfn->cdev->num_ports_in_engines; i++) { + for (i = 0; i < p_hwfn->cdev->num_ports_in_engine; i++) { port = &(qm_info->qm_port_params[i]); DP_VERBOSE(p_hwfn, NETIF_MSG_HW, @@ -823,7 +823,7 @@ static int qed_alloc_qm_data(struct qed_hwfn *p_hwfn) goto alloc_err; qm_info->qm_port_params = kzalloc(sizeof(*qm_info->qm_port_params) * - p_hwfn->cdev->num_ports_in_engines, + p_hwfn->cdev->num_ports_in_engine, GFP_KERNEL); if (!qm_info->qm_port_params) goto alloc_err; @@ -1108,7 +1108,7 @@ static int qed_calc_hw_mode(struct qed_hwfn *p_hwfn) return -EINVAL; } - switch (p_hwfn->cdev->num_ports_in_engines) { + switch (p_hwfn->cdev->num_ports_in_engine) { case 1: hw_mode |= 1 << MODE_PORTS_PER_ENG_1; break; @@ -1120,7 +1120,7 @@ static int qed_calc_hw_mode(struct qed_hwfn *p_hwfn) break; default: DP_NOTICE(p_hwfn, "num_ports_in_engine = %d not supported\n", - p_hwfn->cdev->num_ports_in_engines); + p_hwfn->cdev->num_ports_in_engine); return -EINVAL; } @@ -1253,7 +1253,7 @@ static int qed_hw_init_common(struct qed_hwfn *p_hwfn, } memset(¶ms, 0, sizeof(params)); - params.max_ports_per_engine = p_hwfn->cdev->num_ports_in_engines; + params.max_ports_per_engine = p_hwfn->cdev->num_ports_in_engine; params.max_phys_tcs_per_port = qm_info->max_phys_tcs_per_port; params.pf_rl_en = qm_info->pf_rl_en; params.pf_wfq_en = qm_info->pf_wfq_en; @@ -2245,7 +2245,7 @@ int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn, case QED_BDQ: if (!*p_resc_num) *p_resc_start = 0; - else if (p_hwfn->cdev->num_ports_in_engines == 4) + else if (p_hwfn->cdev->num_ports_in_engine == 4) *p_resc_start = p_hwfn->port_id; else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) *p_resc_start = p_hwfn->port_id; @@ -2662,15 +2662,15 @@ static void qed_hw_info_port_num_bb(struct qed_hwfn *p_hwfn, port_mode = qed_rd(p_hwfn, p_ptt, CNIG_REG_NW_PORT_MODE_BB_B0); if (port_mode < 3) { - p_hwfn->cdev->num_ports_in_engines = 1; + p_hwfn->cdev->num_ports_in_engine = 1; } else if (port_mode <= 5) { - p_hwfn->cdev->num_ports_in_engines = 2; + p_hwfn->cdev->num_ports_in_engine = 2; } else { DP_NOTICE(p_hwfn, "PORT MODE: %d not supported\n", - p_hwfn->cdev->num_ports_in_engines); + p_hwfn->cdev->num_ports_in_engine); - /* Default num_ports_in_engines to something */ - p_hwfn->cdev->num_ports_in_engines = 1; + /* Default num_ports_in_engine to something */ + p_hwfn->cdev->num_ports_in_engine = 1; } } @@ -2680,20 +2680,20 @@ static void qed_hw_info_port_num_ah(struct qed_hwfn *p_hwfn, u32 port; int i; - p_hwfn->cdev->num_ports_in_engines = 0; + p_hwfn->cdev->num_ports_in_engine = 0; for (i = 0; i < MAX_NUM_PORTS_K2; i++) { port = qed_rd(p_hwfn, p_ptt, CNIG_REG_NIG_PORT0_CONF_K2 + (i * 4)); if (port & 1) - p_hwfn->cdev->num_ports_in_engines++; + p_hwfn->cdev->num_ports_in_engine++; } - if (!p_hwfn->cdev->num_ports_in_engines) { + if (!p_hwfn->cdev->num_ports_in_engine) { DP_NOTICE(p_hwfn, "All NIG ports are inactive\n"); /* Default num_ports_in_engine to something */ - p_hwfn->cdev->num_ports_in_engines = 1; + p_hwfn->cdev->num_ports_in_engine = 1; } } @@ -4067,7 +4067,7 @@ static int qed_device_num_ports(struct qed_dev *cdev) if (cdev->num_hwfns > 1) return 1; - return cdev->num_ports_in_engines * qed_device_num_engines(cdev); + return cdev->num_ports_in_engine * qed_device_num_engines(cdev); } int qed_device_get_port_id(struct qed_dev *cdev) diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 2b09b8545236..3e5bffe3d4e2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -482,7 +482,7 @@ int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn, #define MCP_PF_ID(p_hwfn) MCP_PF_ID_BY_REL(p_hwfn, (p_hwfn)->rel_pf_id) #define MFW_PORT(_p_hwfn) ((_p_hwfn)->abs_pf_id % \ - ((_p_hwfn)->cdev->num_ports_in_engines * \ + ((_p_hwfn)->cdev->num_ports_in_engine * \ qed_device_num_engines((_p_hwfn)->cdev))) struct qed_mcp_info { diff --git a/drivers/net/ethernet/qlogic/qed/qed_ptp.c b/drivers/net/ethernet/qlogic/qed/qed_ptp.c index 434a164a76ed..5a90d69dc2f8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ptp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ptp.c @@ -80,7 +80,7 @@ static int qed_ptp_res_lock(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) /* MFW doesn't support resource locking, first PF on the port * has lock ownership. */ - if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engines) + if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engine) return 0; DP_INFO(p_hwfn, "PF doesn't have lock ownership\n"); @@ -108,7 +108,7 @@ static int qed_ptp_res_unlock(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) rc = qed_mcp_resc_unlock(p_hwfn, p_ptt, ¶ms); if (rc == -EINVAL) { /* MFW doesn't support locking, first PF has lock ownership */ - if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engines) { + if (p_hwfn->abs_pf_id < p_hwfn->cdev->num_ports_in_engine) { rc = 0; } else { DP_INFO(p_hwfn, "PF doesn't have lock ownership\n"); -- cgit v1.2.3 From c31a314b2346819531d3a6585988cef32171312e Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Tue, 23 May 2017 09:41:23 +0300 Subject: qed: Remove BB_A0 references A0 never went public, so no need to protect against it. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 6 ------ drivers/net/ethernet/qlogic/qed/qed_dev.c | 6 ------ 2 files changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 63c44c60eef3..2eb6031f0df1 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -598,16 +598,11 @@ struct qed_dev { enum qed_dev_type type; /* Translate type/revision combo into the proper conditions */ #define QED_IS_BB(dev) ((dev)->type == QED_DEV_TYPE_BB) -#define QED_IS_BB_A0(dev) (QED_IS_BB(dev) && \ - CHIP_REV_IS_A0(dev)) #define QED_IS_BB_B0(dev) (QED_IS_BB(dev) && \ CHIP_REV_IS_B0(dev)) #define QED_IS_AH(dev) ((dev)->type == QED_DEV_TYPE_AH) #define QED_IS_K2(dev) QED_IS_AH(dev) -#define QED_GET_TYPE(dev) (QED_IS_BB_A0(dev) ? CHIP_BB_A0 : \ - QED_IS_BB_B0(dev) ? CHIP_BB_B0 : CHIP_K2) - u16 vendor_id; u16 device_id; #define QED_DEV_ID_MASK 0xff00 @@ -621,7 +616,6 @@ struct qed_dev { u16 chip_rev; #define CHIP_REV_MASK 0xf #define CHIP_REV_SHIFT 12 -#define CHIP_REV_IS_A0(_cdev) (!(_cdev)->chip_rev) #define CHIP_REV_IS_B0(_cdev) ((_cdev)->chip_rev == 1) u16 chip_metal; diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 51ae9071f3df..3262aaa85b9a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -2812,12 +2812,6 @@ static int qed_get_dev_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) cdev->chip_num, cdev->chip_rev, cdev->chip_bond_id, cdev->chip_metal); - if (QED_IS_BB(cdev) && CHIP_REV_IS_A0(cdev)) { - DP_NOTICE(cdev->hwfns, - "The chip type/rev (BB A0) is not supported!\n"); - return -EINVAL; - } - return 0; } -- cgit v1.2.3 From 06892f2ea2bd6b146707e4ab367aa5b20eac0ba7 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Tue, 23 May 2017 09:41:24 +0300 Subject: qed: Flush slowpath tasklet on stop Today, driver has a synchronization point while closing the device which synchronizes its slowpath interrupt line. However, that's insufficient as that ISR would schedule the slowpath-tasklet - so even after ISR is over it's possible the handling of the interrupt has not completed. By doing a disable/enable on the taskelt we guarantee that all HW events that should no longer be genereated from that point onward in the flow are truly behind us. Signed-off-by: Tomer Tayar Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_main.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index f286daa59bbc..3043dcce125c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -606,6 +606,18 @@ int qed_slowpath_irq_req(struct qed_hwfn *hwfn) return rc; } +static void qed_slowpath_tasklet_flush(struct qed_hwfn *p_hwfn) +{ + /* Calling the disable function will make sure that any + * currently-running function is completed. The following call to the + * enable function makes this sequence a flush-like operation. + */ + if (p_hwfn->b_sp_dpc_enabled) { + tasklet_disable(p_hwfn->sp_dpc); + tasklet_enable(p_hwfn->sp_dpc); + } +} + void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) { struct qed_dev *cdev = p_hwfn->cdev; @@ -617,6 +629,8 @@ void qed_slowpath_irq_sync(struct qed_hwfn *p_hwfn) synchronize_irq(cdev->int_params.msix_table[id].vector); else synchronize_irq(cdev->pdev->irq); + + qed_slowpath_tasklet_flush(p_hwfn); } static void qed_slowpath_irq_free(struct qed_dev *cdev) -- cgit v1.2.3 From f855df220238436d10c3de67da0b1a280a2092b4 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Tue, 23 May 2017 09:41:25 +0300 Subject: qed: Enable RoCE parser searching on fp init Since we're closing the parser searching for RDMA when stoping the fastpath, we need to re-enable it when starting the fastpath once again. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 3262aaa85b9a..072d950cd8ee 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1948,6 +1948,13 @@ int qed_hw_start_fastpath(struct qed_hwfn *p_hwfn) if (!p_ptt) return -EAGAIN; + /* If roce info is allocated it means roce is initialized and should + * be enabled in searcher. + */ + if (p_hwfn->p_rdma_info && + p_hwfn->b_rdma_enabled_in_prs) + qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 0x1); + /* Re-open incoming traffic */ qed_wr(p_hwfn, p_ptt, NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x0); qed_ptt_release(p_hwfn, p_ptt); -- cgit v1.2.3 From ae33666ab89675968d77753d18452b1ef654c43a Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Tue, 23 May 2017 09:41:26 +0300 Subject: qed: Provide MBI information in dev_info Pass additional information about package installed on persistent memory so that protocol drivers would be able to log it. Signed-off-by: Tomer Tayar Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 6 ++++++ drivers/net/ethernet/qlogic/qed/qed_main.c | 3 +++ drivers/net/ethernet/qlogic/qed/qed_mcp.c | 30 ++++++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_mcp.h | 12 ++++++++++++ 4 files changed, 51 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 4755d0b33b90..802c162d8474 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -11782,6 +11782,12 @@ struct nvm_cfg1_glob { u32 led_global_settings; u32 generic_cont1; u32 mbi_version; +#define NVM_CFG1_GLOB_MBI_VERSION_0_MASK 0x000000FF +#define NVM_CFG1_GLOB_MBI_VERSION_0_OFFSET 0 +#define NVM_CFG1_GLOB_MBI_VERSION_1_MASK 0x0000FF00 +#define NVM_CFG1_GLOB_MBI_VERSION_1_OFFSET 8 +#define NVM_CFG1_GLOB_MBI_VERSION_2_MASK 0x00FF0000 +#define NVM_CFG1_GLOB_MBI_VERSION_2_OFFSET 16 u32 mbi_date; u32 misc_sig; u32 device_capabilities; diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 3043dcce125c..b5313c561fa2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -281,6 +281,9 @@ int qed_fill_dev_info(struct qed_dev *cdev, qed_mcp_get_mfw_ver(QED_LEADING_HWFN(cdev), ptt, &dev_info->mfw_rev, NULL); + qed_mcp_get_mbi_ver(QED_LEADING_HWFN(cdev), ptt, + &dev_info->mbi_version); + qed_mcp_get_flash_size(QED_LEADING_HWFN(cdev), ptt, &dev_info->flash_size); diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index b32e8190f3fb..fc49c75e6c4b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1523,6 +1523,36 @@ int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, return 0; } +int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *p_mbi_ver) +{ + u32 nvm_cfg_addr, nvm_cfg1_offset, mbi_ver_addr; + + if (IS_VF(p_hwfn->cdev)) + return -EINVAL; + + /* Read the address of the nvm_cfg */ + nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); + if (!nvm_cfg_addr) { + DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); + return -EINVAL; + } + + /* Read the offset of nvm_cfg1 */ + nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); + + mbi_ver_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + + offsetof(struct nvm_cfg1, glob) + + offsetof(struct nvm_cfg1_glob, mbi_version); + *p_mbi_ver = qed_rd(p_hwfn, p_ptt, + mbi_ver_addr) & + (NVM_CFG1_GLOB_MBI_VERSION_0_MASK | + NVM_CFG1_GLOB_MBI_VERSION_1_MASK | + NVM_CFG1_GLOB_MBI_VERSION_2_MASK); + + return 0; +} + int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type) { struct qed_hwfn *p_hwfn = &cdev->hwfns[0]; diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 3e5bffe3d4e2..40247593e772 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -255,6 +255,18 @@ int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 *p_mfw_ver, u32 *p_running_bundle_id); +/** + * @brief Get the MBI version value + * + * @param p_hwfn + * @param p_ptt + * @param p_mbi_ver - A pointer to a variable to be filled with the MBI version. + * + * @return int - 0 - operation was successful. + */ +int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u32 *p_mbi_ver); + /** * @brief Get media type value of the port. * -- cgit v1.2.3 From 6bc9f234ff75c15144fb9bc28d828a5ca11cd0a2 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Tue, 23 May 2017 09:41:27 +0300 Subject: qede: Log probe of PCI device Replace meaningless logged print ('Ending successfully qede probe') with a single-liner containing interesting information about probed device. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_main.c | 40 ++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index f0871e179e99..d496ba70ddb8 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -852,6 +852,43 @@ static void qede_update_pf_params(struct qed_dev *cdev) qed_ops->common->update_pf_params(cdev, &pf_params); } +#define QEDE_FW_VER_STR_SIZE 80 + +static void qede_log_probe(struct qede_dev *edev) +{ + struct qed_dev_info *p_dev_info = &edev->dev_info.common; + u8 buf[QEDE_FW_VER_STR_SIZE]; + size_t left_size; + + snprintf(buf, QEDE_FW_VER_STR_SIZE, + "Storm FW %d.%d.%d.%d, Management FW %d.%d.%d.%d", + p_dev_info->fw_major, p_dev_info->fw_minor, p_dev_info->fw_rev, + p_dev_info->fw_eng, + (p_dev_info->mfw_rev & QED_MFW_VERSION_3_MASK) >> + QED_MFW_VERSION_3_OFFSET, + (p_dev_info->mfw_rev & QED_MFW_VERSION_2_MASK) >> + QED_MFW_VERSION_2_OFFSET, + (p_dev_info->mfw_rev & QED_MFW_VERSION_1_MASK) >> + QED_MFW_VERSION_1_OFFSET, + (p_dev_info->mfw_rev & QED_MFW_VERSION_0_MASK) >> + QED_MFW_VERSION_0_OFFSET); + + left_size = QEDE_FW_VER_STR_SIZE - strlen(buf); + if (p_dev_info->mbi_version && left_size) + snprintf(buf + strlen(buf), left_size, + " [MBI %d.%d.%d]", + (p_dev_info->mbi_version & QED_MBI_VERSION_2_MASK) >> + QED_MBI_VERSION_2_OFFSET, + (p_dev_info->mbi_version & QED_MBI_VERSION_1_MASK) >> + QED_MBI_VERSION_1_OFFSET, + (p_dev_info->mbi_version & QED_MBI_VERSION_0_MASK) >> + QED_MBI_VERSION_0_OFFSET); + + pr_info("qede %02x:%02x.%02x: %s [%s]\n", edev->pdev->bus->number, + PCI_SLOT(edev->pdev->devfn), PCI_FUNC(edev->pdev->devfn), + buf, edev->ndev->name); +} + enum qede_probe_mode { QEDE_PROBE_NORMAL, }; @@ -945,8 +982,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, edev->rx_copybreak = QEDE_RX_HDR_SIZE; - DP_INFO(edev, "Ending successfully qede probe\n"); - + qede_log_probe(edev); return 0; err4: -- cgit v1.2.3 From 712c3cbf193fcadf0ba67da61432beb1a71e400b Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Tue, 23 May 2017 09:41:28 +0300 Subject: qed: Replace set_id() api with set_name() Current API between qed and protocol modules allows passing an additional private string - but it doesn't get utilized by qed anywhere. Clarify the API by removing it and renaming it 'set_name'. CC: Manish Rangankar Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 1 - drivers/net/ethernet/qlogic/qed/qed_main.c | 9 +++------ drivers/net/ethernet/qlogic/qede/qede_main.c | 4 ++-- drivers/scsi/qedf/qedf_main.c | 2 +- drivers/scsi/qedi/qedi_main.c | 2 +- 5 files changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 2eb6031f0df1..e0becec17b09 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -638,7 +638,6 @@ struct qed_dev { int pcie_width; int pcie_speed; - u8 ver_str[VER_SIZE]; /* Add MF related configuration */ u8 mcp_rev; diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index b5313c561fa2..c5bb80b9afc1 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -338,6 +338,7 @@ static struct qed_dev *qed_probe(struct pci_dev *pdev, if (!cdev) goto err0; + cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; cdev->protocol = params->protocol; if (params->is_vf) @@ -1128,17 +1129,13 @@ static int qed_slowpath_stop(struct qed_dev *cdev) return 0; } -static void qed_set_id(struct qed_dev *cdev, char name[NAME_SIZE], - char ver_str[VER_SIZE]) +static void qed_set_name(struct qed_dev *cdev, char name[NAME_SIZE]) { int i; memcpy(cdev->name, name, NAME_SIZE); for_each_hwfn(cdev, i) snprintf(cdev->hwfns[i].name, NAME_SIZE, "%s-%d", name, i); - - memcpy(cdev->ver_str, ver_str, VER_SIZE); - cdev->drv_type = DRV_ID_DRV_TYPE_LINUX; } static u32 qed_sb_init(struct qed_dev *cdev, @@ -1692,7 +1689,7 @@ const struct qed_common_ops qed_common_ops_pass = { .probe = &qed_probe, .remove = &qed_remove, .set_power_state = &qed_set_power_state, - .set_id = &qed_set_id, + .set_name = &qed_set_name, .update_pf_params = &qed_update_pf_params, .slowpath_start = &qed_slowpath_start, .slowpath_stop = &qed_slowpath_stop, diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index d496ba70ddb8..00c70625f8a4 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -259,7 +259,7 @@ static int qede_netdev_event(struct notifier_block *this, unsigned long event, /* Notify qed of the name change */ if (!edev->ops || !edev->ops->common) goto done; - edev->ops->common->set_id(edev->cdev, edev->ndev->name, "qede"); + edev->ops->common->set_name(edev->cdev, edev->ndev->name); break; case NETDEV_CHANGEADDR: edev = netdev_priv(ndev); @@ -967,7 +967,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, goto err4; } - edev->ops->common->set_id(cdev, edev->ndev->name, DRV_MODULE_VERSION); + edev->ops->common->set_name(cdev, edev->ndev->name); /* PTP not supported on VFs */ if (!is_vf) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index a5c97342fd5d..b97405ed6cae 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2954,7 +2954,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) "WWPN=%016llx.\n", qedf->wwnn, qedf->wwpn); sprintf(host_buf, "host_%d", host->host_no); - qed_ops->common->set_id(qedf->cdev, host_buf, QEDF_VERSION); + qed_ops->common->set_name(qedf->cdev, host_buf); /* Set xid max values */ diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 92775a8b74b1..073b3051bb8f 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1843,7 +1843,7 @@ static int __qedi_probe(struct pci_dev *pdev, int mode) qedi->mac); sprintf(host_buf, "host_%d", qedi->shost->host_no); - qedi_ops->common->set_id(qedi->cdev, host_buf, QEDI_MODULE_VERSION); + qedi_ops->common->set_name(qedi->cdev, host_buf); qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi); -- cgit v1.2.3 From b4d39b4b547f9287e05a725f4fb77dd5413dc3c9 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 23 May 2017 18:40:46 +0200 Subject: mlxsw: acl: Add tcp flags acl element Define new element for tcp flags and place it into scratch area. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h | 2 ++ drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h index c75e9141e3ec..9807ef814e42 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h @@ -56,6 +56,7 @@ enum mlxsw_afk_element { MLXSW_AFK_ELEMENT_SRC_L4_PORT, MLXSW_AFK_ELEMENT_VID, MLXSW_AFK_ELEMENT_PCP, + MLXSW_AFK_ELEMENT_TCP_FLAGS, MLXSW_AFK_ELEMENT_MAX, }; @@ -102,6 +103,7 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { MLXSW_AFK_ELEMENT_INFO_U32(IP_PROTO, 0x10, 0, 8), MLXSW_AFK_ELEMENT_INFO_U32(VID, 0x10, 8, 12), MLXSW_AFK_ELEMENT_INFO_U32(PCP, 0x10, 20, 3), + MLXSW_AFK_ELEMENT_INFO_U32(TCP_FLAGS, 0x10, 23, 9), MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x18, 0, 32), MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x1C, 0, 32), MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x18, 8), diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 7d87e23578a3..15b03485dc07 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -194,6 +194,7 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp, BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | BIT(FLOW_DISSECTOR_KEY_PORTS) | + BIT(FLOW_DISSECTOR_KEY_TCP) | BIT(FLOW_DISSECTOR_KEY_VLAN))) { dev_err(mlxsw_sp->bus_info->dev, "Unsupported key\n"); return -EOPNOTSUPP; -- cgit v1.2.3 From dea2d6457fce0e1829ae543b2c47d84e51a71445 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 23 May 2017 18:40:47 +0200 Subject: mlxsw: spectrum: Add acl block containing tcp flags for ipv4 Add acl block called "ipv4" which contains tcp flags. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.h index af7b7bad48df..85d5001a5818 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.h @@ -68,6 +68,11 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = { MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), }; +static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = { + MLXSW_AFK_ELEMENT_INST_U32(SRC_IP4, 0x00, 0, 32), + MLXSW_AFK_ELEMENT_INST_U32(TCP_FLAGS, 0x08, 8, 9), /* TCP_CONTROL+TCP_ECN */ +}; + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_ex[] = { MLXSW_AFK_ELEMENT_INST_U32(VID, 0x00, 0, 12), MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 29, 3), @@ -102,6 +107,7 @@ static const struct mlxsw_afk_block mlxsw_sp_afk_blocks[] = { MLXSW_AFK_BLOCK(0x12, mlxsw_sp_afk_element_info_l2_smac_ex), MLXSW_AFK_BLOCK(0x30, mlxsw_sp_afk_element_info_ipv4_sip), MLXSW_AFK_BLOCK(0x31, mlxsw_sp_afk_element_info_ipv4_dip), + MLXSW_AFK_BLOCK(0x32, mlxsw_sp_afk_element_info_ipv4), MLXSW_AFK_BLOCK(0x33, mlxsw_sp_afk_element_info_ipv4_ex), MLXSW_AFK_BLOCK(0x60, mlxsw_sp_afk_element_info_ipv6_dip), MLXSW_AFK_BLOCK(0x65, mlxsw_sp_afk_element_info_ipv6_ex1), -- cgit v1.2.3 From 8a41d845c4fd64e6bf909aafa977472689e8c7a5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 23 May 2017 18:40:48 +0200 Subject: mlxsw: spectrum_flower: Add support for tcp flags Allow to offload rules that contain tcp flags within the mask. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 1 + .../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 29 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 3a24289979d9..61a10f166f97 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -983,6 +983,7 @@ static const enum mlxsw_afk_element mlxsw_sp_acl_tcam_pattern_ipv4[] = { MLXSW_AFK_ELEMENT_SRC_L4_PORT, MLXSW_AFK_ELEMENT_VID, MLXSW_AFK_ELEMENT_PCP, + MLXSW_AFK_ELEMENT_TCP_FLAGS, }; static const enum mlxsw_afk_element mlxsw_sp_acl_tcam_pattern_ipv6[] = { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 15b03485dc07..739dc1ed759b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -178,6 +178,32 @@ static int mlxsw_sp_flower_parse_ports(struct mlxsw_sp *mlxsw_sp, return 0; } +static int mlxsw_sp_flower_parse_tcp(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_rule_info *rulei, + struct tc_cls_flower_offload *f, + u8 ip_proto) +{ + struct flow_dissector_key_tcp *key, *mask; + + if (!dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP)) + return 0; + + if (ip_proto != IPPROTO_TCP) { + dev_err(mlxsw_sp->bus_info->dev, "TCP keys supported only for TCP\n"); + return -EINVAL; + } + + key = skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_TCP, + f->key); + mask = skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_TCP, + f->mask); + mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_TCP_FLAGS, + ntohs(key->flags), ntohs(mask->flags)); + return 0; +} + static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp, struct net_device *dev, struct mlxsw_sp_acl_rule_info *rulei, @@ -284,6 +310,9 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_flower_parse_ipv6(rulei, f); err = mlxsw_sp_flower_parse_ports(mlxsw_sp, rulei, f, ip_proto); + if (err) + return err; + err = mlxsw_sp_flower_parse_tcp(mlxsw_sp, rulei, f, ip_proto); if (err) return err; -- cgit v1.2.3 From a0a32d3a0ed98c1ae17973533d87baaac7079279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 24 May 2017 00:26:07 +0200 Subject: net: phy: put genphy_config_init's EXPORT_SYMBOL directly after the function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit af6b6967d6e1 ("net: phy: export genphy_config_init()") introduced this EXPORT_SYMBOL and put it after gen10g_soft_reset() instead of directly after genphy_config_init. Probably this happend when the patch was applied because http://patchwork.ozlabs.org/patch/339622/ looks ok. Signed-off-by: Uwe Kleine-König Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1219eeab69d1..0780e9f9e167 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1571,13 +1571,13 @@ int genphy_config_init(struct phy_device *phydev) return 0; } +EXPORT_SYMBOL(genphy_config_init); static int gen10g_soft_reset(struct phy_device *phydev) { /* Do nothing for now */ return 0; } -EXPORT_SYMBOL(genphy_config_init); static int gen10g_config_init(struct phy_device *phydev) { -- cgit v1.2.3 From 26d732baa09daa196b426b6cb354783eb1c75ec5 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 23 May 2017 17:27:51 -0700 Subject: net: jme: Remove unused functions The functions jme_restart_tx_engine(), jme_pause_rx() and jme_resume_rx() are not used. Removing them fixes the following warnings when building with clang: drivers/net/ethernet/jme.c:694:1: error: unused function 'jme_restart_tx_engine' [-Werror,-Wunused-function] drivers/net/ethernet/jme.c:2393:20: error: unused function 'jme_pause_rx' [-Werror,-Wunused-function] drivers/net/ethernet/jme.c:2406:20: error: unused function 'jme_resume_rx' [-Werror,-Wunused-function] Signed-off-by: Matthias Kaehlcke Signed-off-by: David S. Miller --- drivers/net/ethernet/jme.c | 42 ------------------------------------------ 1 file changed, 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index f580b49e6b67..0e5083a48937 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -690,17 +690,6 @@ jme_enable_tx_engine(struct jme_adapter *jme) jme_mac_txclk_on(jme); } -static inline void -jme_restart_tx_engine(struct jme_adapter *jme) -{ - /* - * Restart TX Engine - */ - jwrite32(jme, JME_TXCS, jme->reg_txcs | - TXCS_SELECT_QUEUE0 | - TXCS_ENABLE); -} - static inline void jme_disable_tx_engine(struct jme_adapter *jme) { @@ -2382,37 +2371,6 @@ jme_tx_timeout(struct net_device *netdev) jme_reset_link(jme); } -static inline void jme_pause_rx(struct jme_adapter *jme) -{ - atomic_dec(&jme->link_changing); - - jme_set_rx_pcc(jme, PCC_OFF); - if (test_bit(JME_FLAG_POLL, &jme->flags)) { - JME_NAPI_DISABLE(jme); - } else { - tasklet_disable(&jme->rxclean_task); - tasklet_disable(&jme->rxempty_task); - } -} - -static inline void jme_resume_rx(struct jme_adapter *jme) -{ - struct dynpcc_info *dpi = &(jme->dpi); - - if (test_bit(JME_FLAG_POLL, &jme->flags)) { - JME_NAPI_ENABLE(jme); - } else { - tasklet_enable(&jme->rxclean_task); - tasklet_enable(&jme->rxempty_task); - } - dpi->cur = PCC_P1; - dpi->attempt = PCC_P1; - dpi->cnt = 0; - jme_set_rx_pcc(jme, PCC_P1); - - atomic_inc(&jme->link_changing); -} - static void jme_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) -- cgit v1.2.3 From 99a4cca216d98d48e5bc848b9e88131efa364fb6 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 24 May 2017 09:16:43 +0200 Subject: net-next: stmmac: Convert new_state to bool This patch convert new_state from int to bool since it store only 1 or 0 Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 27c12e732a8a..b944eabaa1ec 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -775,7 +775,7 @@ static void stmmac_adjust_link(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); struct phy_device *phydev = dev->phydev; unsigned long flags; - int new_state = 0; + bool new_state = false; if (!phydev) return; @@ -788,7 +788,7 @@ static void stmmac_adjust_link(struct net_device *dev) /* Now we make sure that we can be in full duplex mode. * If not, we operate in half-duplex mode. */ if (phydev->duplex != priv->oldduplex) { - new_state = 1; + new_state = true; if (!(phydev->duplex)) ctrl &= ~priv->hw->link.duplex; else @@ -800,7 +800,7 @@ static void stmmac_adjust_link(struct net_device *dev) stmmac_mac_flow_ctrl(priv, phydev->duplex); if (phydev->speed != priv->speed) { - new_state = 1; + new_state = true; switch (phydev->speed) { case 1000: if (priv->plat->has_gmac || @@ -839,11 +839,11 @@ static void stmmac_adjust_link(struct net_device *dev) writel(ctrl, priv->ioaddr + MAC_CTRL_REG); if (!priv->oldlink) { - new_state = 1; + new_state = true; priv->oldlink = 1; } } else if (priv->oldlink) { - new_state = 1; + new_state = true; priv->oldlink = 0; priv->speed = SPEED_UNKNOWN; priv->oldduplex = DUPLEX_UNKNOWN; -- cgit v1.2.3 From 50cb16d4fd1263c72f5d384a275a86a72b546121 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 24 May 2017 09:16:44 +0200 Subject: net-next: stmmac: Remove unnecessary parenthesis Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index b944eabaa1ec..cd398bafb5e9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -789,7 +789,7 @@ static void stmmac_adjust_link(struct net_device *dev) * If not, we operate in half-duplex mode. */ if (phydev->duplex != priv->oldduplex) { new_state = true; - if (!(phydev->duplex)) + if (!phydev->duplex) ctrl &= ~priv->hw->link.duplex; else ctrl |= priv->hw->link.duplex; -- cgit v1.2.3 From afbe17a3ad38e1c90bbb204b7f2accfbe9b9f2dc Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 24 May 2017 09:16:45 +0200 Subject: net-next: stmmac: use SPEED_xxx instead of raw value Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index cd398bafb5e9..e55382336868 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -802,12 +802,12 @@ static void stmmac_adjust_link(struct net_device *dev) if (phydev->speed != priv->speed) { new_state = true; switch (phydev->speed) { - case 1000: + case SPEED_1000: if (priv->plat->has_gmac || priv->plat->has_gmac4) ctrl &= ~priv->hw->link.port; break; - case 100: + case SPEED_100: if (priv->plat->has_gmac || priv->plat->has_gmac4) { ctrl |= priv->hw->link.port; @@ -816,7 +816,7 @@ static void stmmac_adjust_link(struct net_device *dev) ctrl &= ~priv->hw->link.port; } break; - case 10: + case SPEED_10: if (priv->plat->has_gmac || priv->plat->has_gmac4) { ctrl |= priv->hw->link.port; -- cgit v1.2.3 From 4d869b03b74d73205956381a967cab7e572144df Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 24 May 2017 09:16:46 +0200 Subject: net-next: stmmac: Convert old_link to bool This patch convert old_link from int to bool since it store only 1 or 0 Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 33efe7038cab..a916e13624eb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -104,7 +104,7 @@ struct stmmac_priv { /* TX Queue */ struct stmmac_tx_queue tx_queue[MTL_MAX_TX_QUEUES]; - int oldlink; + bool oldlink; int speed; int oldduplex; unsigned int flow_ctrl; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index e55382336868..9ec138dc04f9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -840,11 +840,11 @@ static void stmmac_adjust_link(struct net_device *dev) if (!priv->oldlink) { new_state = true; - priv->oldlink = 1; + priv->oldlink = true; } } else if (priv->oldlink) { new_state = true; - priv->oldlink = 0; + priv->oldlink = false; priv->speed = SPEED_UNKNOWN; priv->oldduplex = DUPLEX_UNKNOWN; } @@ -907,7 +907,7 @@ static int stmmac_init_phy(struct net_device *dev) char bus_id[MII_BUS_ID_SIZE]; int interface = priv->plat->interface; int max_speed = priv->plat->max_speed; - priv->oldlink = 0; + priv->oldlink = false; priv->speed = SPEED_UNKNOWN; priv->oldduplex = DUPLEX_UNKNOWN; @@ -4291,7 +4291,7 @@ int stmmac_suspend(struct device *dev) } spin_unlock_irqrestore(&priv->lock, flags); - priv->oldlink = 0; + priv->oldlink = false; priv->speed = SPEED_UNKNOWN; priv->oldduplex = DUPLEX_UNKNOWN; return 0; -- cgit v1.2.3 From ca84dfb9ab70849c2b01f30d658a8900cff9889d Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 24 May 2017 09:16:47 +0200 Subject: net-next: stmmac: rework the speed selection The current stmmac_adjust_link() part which handle speed have some if (has_platform) code and my dwmac-sun8i will add more of them. So we need to handle better speed selection. Moreover the struct link member speed and port are hard to guess their purpose. And their unique usage are to be combined for writing speed. So this patch replace speed/port by simpler speed10/speed100/speed1000/speed_mask variables. In dwmac4_core_init and dwmac1000_core_init, port/speed value was used directly without using the struct link. This patch convert also their usage to speedxxx. Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 8 ++++--- .../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 26 +++++++++++++--------- .../net/ethernet/stmicro/stmmac/dwmac100_core.c | 6 +++-- drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 26 +++++++++++++--------- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 21 ++++------------- 5 files changed, 43 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index b7ce3fbb5375..e82b4b70b7be 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -549,9 +549,11 @@ extern const struct stmmac_hwtimestamp stmmac_ptp; extern const struct stmmac_mode_ops dwmac4_ring_mode_ops; struct mac_link { - int port; - int duplex; - int speed; + u32 speed_mask; + u32 speed10; + u32 speed100; + u32 speed1000; + u32 duplex; }; struct mii_regs { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index f3d9305e5f70..8a86340ff2d3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -45,15 +45,17 @@ static void dwmac1000_core_init(struct mac_device_info *hw, int mtu) if (hw->ps) { value |= GMAC_CONTROL_TE; - if (hw->ps == SPEED_1000) { - value &= ~GMAC_CONTROL_PS; - } else { - value |= GMAC_CONTROL_PS; - - if (hw->ps == SPEED_10) - value &= ~GMAC_CONTROL_FES; - else - value |= GMAC_CONTROL_FES; + value &= ~hw->link.speed_mask; + switch (hw->ps) { + case SPEED_1000: + value |= hw->link.speed1000; + break; + case SPEED_100: + value |= hw->link.speed100; + break; + case SPEED_10: + value |= hw->link.speed10; + break; } } @@ -531,9 +533,11 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, mac->mac = &dwmac1000_ops; mac->dma = &dwmac1000_dma_ops; - mac->link.port = GMAC_CONTROL_PS; mac->link.duplex = GMAC_CONTROL_DM; - mac->link.speed = GMAC_CONTROL_FES; + mac->link.speed10 = GMAC_CONTROL_PS; + mac->link.speed100 = GMAC_CONTROL_PS | GMAC_CONTROL_FES; + mac->link.speed1000 = 0; + mac->link.speed_mask = GMAC_CONTROL_PS | GMAC_CONTROL_FES; mac->mii.addr = GMAC_MII_ADDR; mac->mii.data = GMAC_MII_DATA; mac->mii.addr_shift = 11; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index 1b3609105484..8ef517356313 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -175,9 +175,11 @@ struct mac_device_info *dwmac100_setup(void __iomem *ioaddr, int *synopsys_id) mac->mac = &dwmac100_ops; mac->dma = &dwmac100_dma_ops; - mac->link.port = MAC_CONTROL_PS; mac->link.duplex = MAC_CONTROL_F; - mac->link.speed = 0; + mac->link.speed10 = 0; + mac->link.speed100 = 0; + mac->link.speed1000 = 0; + mac->link.speed_mask = MAC_CONTROL_PS; mac->mii.addr = MAC_MII_ADDR; mac->mii.data = MAC_MII_DATA; mac->mii.addr_shift = 11; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 48793f2e9307..f233bf8b4ebb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -35,15 +35,17 @@ static void dwmac4_core_init(struct mac_device_info *hw, int mtu) if (hw->ps) { value |= GMAC_CONFIG_TE; - if (hw->ps == SPEED_1000) { - value &= ~GMAC_CONFIG_PS; - } else { - value |= GMAC_CONFIG_PS; - - if (hw->ps == SPEED_10) - value &= ~GMAC_CONFIG_FES; - else - value |= GMAC_CONFIG_FES; + value &= hw->link.speed_mask; + switch (hw->ps) { + case SPEED_1000: + value |= hw->link.speed1000; + break; + case SPEED_100: + value |= hw->link.speed100; + break; + case SPEED_10: + value |= hw->link.speed10; + break; } } @@ -747,9 +749,11 @@ struct mac_device_info *dwmac4_setup(void __iomem *ioaddr, int mcbins, if (mac->multicast_filter_bins) mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); - mac->link.port = GMAC_CONFIG_PS; mac->link.duplex = GMAC_CONFIG_DM; - mac->link.speed = GMAC_CONFIG_FES; + mac->link.speed10 = GMAC_CONFIG_PS; + mac->link.speed100 = GMAC_CONFIG_FES | GMAC_CONFIG_PS; + mac->link.speed1000 = 0; + mac->link.speed_mask = GMAC_CONFIG_FES | GMAC_CONFIG_PS; mac->mii.addr = GMAC_MDIO_ADDR; mac->mii.data = GMAC_MDIO_DATA; mac->mii.addr_shift = 21; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9ec138dc04f9..f158273eab9b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -801,29 +801,16 @@ static void stmmac_adjust_link(struct net_device *dev) if (phydev->speed != priv->speed) { new_state = true; + ctrl &= ~priv->hw->link.speed_mask; switch (phydev->speed) { case SPEED_1000: - if (priv->plat->has_gmac || - priv->plat->has_gmac4) - ctrl &= ~priv->hw->link.port; + ctrl |= priv->hw->link.speed1000; break; case SPEED_100: - if (priv->plat->has_gmac || - priv->plat->has_gmac4) { - ctrl |= priv->hw->link.port; - ctrl |= priv->hw->link.speed; - } else { - ctrl &= ~priv->hw->link.port; - } + ctrl |= priv->hw->link.speed100; break; case SPEED_10: - if (priv->plat->has_gmac || - priv->plat->has_gmac4) { - ctrl |= priv->hw->link.port; - ctrl &= ~(priv->hw->link.speed); - } else { - ctrl &= ~priv->hw->link.port; - } + ctrl |= priv->hw->link.speed10; break; default: netif_warn(priv, link, priv->dev, -- cgit v1.2.3 From 673c96e5af99b6f8eab3ce37afa11cb28c14cf2f Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Wed, 24 May 2017 22:24:38 -0400 Subject: be2net: Fix UE detection logic for BE3 On certain platforms BE3 chips may indicate spurious UEs (unrecoverable error). Because of the UE detection logic was disabled in the driver for BE3 chips. Because of this, even in cases of a real UE, a failover will not occur. This patch re-enables UE detection on BE3 and if a UE is detected, reads the POST register. If the POST register, reports either a FAT_LOG_STATE or a ARMFW_UE, then it means that a valid UE occurred in the chip. Signed-off-by: Suresh Reddy Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_hw.h | 3 +++ drivers/net/ethernet/emulex/benet/be_main.c | 27 +++++++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index 36e4232ed6b8..c967f45705d9 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -49,6 +49,9 @@ #define POST_STAGE_BE_RESET 0x3 /* Host wants to reset chip */ #define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */ #define POST_STAGE_RECOVERABLE_ERR 0xE000 /* Recoverable err detected */ +/* FW has detected a UE and is dumping FAT log data */ +#define POST_STAGE_FAT_LOG_START 0x0D00 +#define POST_STAGE_ARMFW_UE 0xF000 /*FW has asserted an UE*/ /* Lancer SLIPORT registers */ #define SLIPORT_STATUS_OFFSET 0x404 diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index f3a09ab55900..800055113583 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3241,8 +3241,9 @@ void be_detect_error(struct be_adapter *adapter) { u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0; u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; - u32 i; struct device *dev = &adapter->pdev->dev; + u16 val; + u32 i; if (be_check_error(adapter, BE_ERROR_HW)) return; @@ -3280,15 +3281,25 @@ void be_detect_error(struct be_adapter *adapter) ue_lo = (ue_lo & ~ue_lo_mask); ue_hi = (ue_hi & ~ue_hi_mask); - /* On certain platforms BE hardware can indicate spurious UEs. - * Allow HW to stop working completely in case of a real UE. - * Hence not setting the hw_error for UE detection. - */ - if (ue_lo || ue_hi) { + /* On certain platforms BE3 hardware can indicate + * spurious UEs. In case of a UE in the chip, + * the POST register correctly reports either a + * FAT_LOG_START state (FW is currently dumping + * FAT log data) or a ARMFW_UE state. Check for the + * above states to ascertain if the UE is valid or not. + */ + if (BE3_chip(adapter)) { + val = be_POST_stage_get(adapter); + if ((val & POST_STAGE_FAT_LOG_START) + != POST_STAGE_FAT_LOG_START && + (val & POST_STAGE_ARMFW_UE) + != POST_STAGE_ARMFW_UE) + return; + } + dev_err(dev, "Error detected in the adapter"); - if (skyhawk_chip(adapter)) - be_set_error(adapter, BE_ERROR_UE); + be_set_error(adapter, BE_ERROR_UE); for (i = 0; ue_lo; ue_lo >>= 1, i++) { if (ue_lo & 1) -- cgit v1.2.3 From aab0830a3811fc242b8cdd82655e98ed5387cc6a Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Wed, 24 May 2017 22:24:39 -0400 Subject: be2net: Update the driver version to 11.4.0.0 Signed-off-by: Suresh Reddy Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 50566243e6fa..674cf9d13b98 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -37,7 +37,7 @@ #include "be_hw.h" #include "be_roce.h" -#define DRV_VER "11.1.0.0" +#define DRV_VER "11.4.0.0" #define DRV_NAME "be2net" #define BE_NAME "Emulex BladeEngine2" #define BE3_NAME "Emulex BladeEngine3" -- cgit v1.2.3 From 410ed13cae39df563e31240992fcb32364d186a1 Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Tue, 23 May 2017 21:56:23 +0200 Subject: Add the mlxfw module for Mellanox firmware flash process The mlxfw module is in charge of common logic needed to flash Mellanox devices firmware, which consists of: - Parse the Mellanox Firmware Archive version 2 (MFA2) format, which is the format used to store the Mellanox firmware. The MFA2 format file can hold firmware for many different silicon variants, differentiated by a unique ID called PSID. In addition, the MFA2 file data section is compressed using xz compression to save both file-system space and memory at extraction time. - Implement the firmware flash state machine logic, which is a common logic for Mellanox products needed to flash the firmware to the device. As the module is shared between different Mellanox products, it defines a set of callbacks to be implemented by the specific driver for hardware interaction. Signed-off-by: Yotam Gigi Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/Kconfig | 1 + drivers/net/ethernet/mellanox/Makefile | 1 + drivers/net/ethernet/mellanox/mlxfw/Kconfig | 6 + drivers/net/ethernet/mellanox/mlxfw/Makefile | 2 + drivers/net/ethernet/mellanox/mlxfw/mlxfw.h | 102 ++++ drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c | 273 +++++++++ drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c | 620 +++++++++++++++++++++ drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h | 66 +++ .../net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h | 60 ++ .../ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h | 103 ++++ .../net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h | 98 ++++ .../ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c | 126 +++++ .../ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h | 71 +++ 13 files changed, 1529 insertions(+) create mode 100644 drivers/net/ethernet/mellanox/mlxfw/Kconfig create mode 100644 drivers/net/ethernet/mellanox/mlxfw/Makefile create mode 100644 drivers/net/ethernet/mellanox/mlxfw/mlxfw.h create mode 100644 drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c create mode 100644 drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c create mode 100644 drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h create mode 100644 drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h create mode 100644 drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h create mode 100644 drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h create mode 100644 drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c create mode 100644 drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig index d54701047401..84a200764111 100644 --- a/drivers/net/ethernet/mellanox/Kconfig +++ b/drivers/net/ethernet/mellanox/Kconfig @@ -19,5 +19,6 @@ if NET_VENDOR_MELLANOX source "drivers/net/ethernet/mellanox/mlx4/Kconfig" source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig" source "drivers/net/ethernet/mellanox/mlxsw/Kconfig" +source "drivers/net/ethernet/mellanox/mlxfw/Kconfig" endif # NET_VENDOR_MELLANOX diff --git a/drivers/net/ethernet/mellanox/Makefile b/drivers/net/ethernet/mellanox/Makefile index 2e2a5ec509ac..016aa263bc04 100644 --- a/drivers/net/ethernet/mellanox/Makefile +++ b/drivers/net/ethernet/mellanox/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/ obj-$(CONFIG_MLX5_CORE) += mlx5/core/ obj-$(CONFIG_MLXSW_CORE) += mlxsw/ +obj-$(CONFIG_MLXFW) += mlxfw/ diff --git a/drivers/net/ethernet/mellanox/mlxfw/Kconfig b/drivers/net/ethernet/mellanox/mlxfw/Kconfig new file mode 100644 index 000000000000..56b60ac7bc34 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/Kconfig @@ -0,0 +1,6 @@ +# +# Mellanox firmware flash library configuration +# + +config MLXFW + tristate "mlxfw" if COMPILE_TEST diff --git a/drivers/net/ethernet/mellanox/mlxfw/Makefile b/drivers/net/ethernet/mellanox/mlxfw/Makefile new file mode 100644 index 000000000000..7448b301104c --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MLXFW) += mlxfw.o +mlxfw-objs := mlxfw_fsm.o mlxfw_mfa2_tlv_multi.o mlxfw_mfa2.o diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h new file mode 100644 index 000000000000..beea4ba83495 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h @@ -0,0 +1,102 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MLXFW_H +#define _MLXFW_H + +#include + +enum mlxfw_fsm_state { + MLXFW_FSM_STATE_IDLE, + MLXFW_FSM_STATE_LOCKED, + MLXFW_FSM_STATE_INITIALIZE, + MLXFW_FSM_STATE_DOWNLOAD, + MLXFW_FSM_STATE_VERIFY, + MLXFW_FSM_STATE_APPLY, + MLXFW_FSM_STATE_ACTIVATE, +}; + +enum mlxfw_fsm_state_err { + MLXFW_FSM_STATE_ERR_OK, + MLXFW_FSM_STATE_ERR_ERROR, + MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR, + MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE, + MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY, + MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED, + MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED, + MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE, + MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT, + MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET, + MLXFW_FSM_STATE_ERR_MAX, +}; + +struct mlxfw_dev; + +struct mlxfw_dev_ops { + int (*component_query)(struct mlxfw_dev *mlxfw_dev, u16 component_index, + u32 *p_max_size, u8 *p_align_bits, + u16 *p_max_write_size); + + int (*fsm_lock)(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle); + + int (*fsm_component_update)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + u16 component_index, u32 component_size); + + int (*fsm_block_download)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + u8 *data, u16 size, u32 offset); + + int (*fsm_component_verify)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + u16 component_index); + + int (*fsm_activate)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); + + int (*fsm_query_state)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + enum mlxfw_fsm_state *fsm_state, + enum mlxfw_fsm_state_err *fsm_state_err); + + void (*fsm_cancel)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); + + void (*fsm_release)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); +}; + +struct mlxfw_dev { + const struct mlxfw_dev_ops *ops; + const char *psid; + u16 psid_size; +}; + +int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + const struct firmware *firmware); + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c new file mode 100644 index 000000000000..2cf89126fb23 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c @@ -0,0 +1,273 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw.c + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define pr_fmt(fmt) "mlxfw: " fmt + +#include +#include +#include + +#include "mlxfw.h" +#include "mlxfw_mfa2.h" + +#define MLXFW_FSM_STATE_WAIT_CYCLE_MS 200 +#define MLXFW_FSM_STATE_WAIT_TIMEOUT_MS 30000 +#define MLXFW_FSM_STATE_WAIT_ROUNDS \ + (MLXFW_FSM_STATE_WAIT_TIMEOUT_MS / MLXFW_FSM_STATE_WAIT_CYCLE_MS) +#define MLXFW_FSM_MAX_COMPONENT_SIZE (10 * (1 << 20)) + +static const char * const mlxfw_fsm_state_err_str[] = { + [MLXFW_FSM_STATE_ERR_ERROR] = + "general error", + [MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] = + "component hash mismatch", + [MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] = + "component not applicable", + [MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] = + "unknown key", + [MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] = + "authentication failed", + [MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] = + "component was not signed", + [MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] = + "key not applicable", + [MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] = + "bad format", + [MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] = + "pending reset", + [MLXFW_FSM_STATE_ERR_MAX] = + "unknown error" +}; + +static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + enum mlxfw_fsm_state fsm_state) +{ + enum mlxfw_fsm_state_err fsm_state_err; + enum mlxfw_fsm_state curr_fsm_state; + int times; + int err; + + times = MLXFW_FSM_STATE_WAIT_ROUNDS; +retry: + err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle, + &curr_fsm_state, &fsm_state_err); + if (err) + return err; + + if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) { + pr_err("Firmware flash failed: %s\n", + mlxfw_fsm_state_err_str[fsm_state_err]); + return -EINVAL; + } + if (curr_fsm_state != fsm_state) { + if (--times == 0) { + pr_err("Timeout reached on FSM state change"); + return -ETIMEDOUT; + } + msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS); + goto retry; + } + return 0; +} + +#define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1)) +#define MLXFW_ALIGN_UP(x, align_bits) \ + MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits)) + +static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev, + u32 fwhandle, + struct mlxfw_mfa2_component *comp) +{ + u16 comp_max_write_size; + u8 comp_align_bits; + u32 comp_max_size; + u16 block_size; + u8 *block_ptr; + u32 offset; + int err; + + err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index, + &comp_max_size, &comp_align_bits, + &comp_max_write_size); + if (err) + return err; + + comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE); + if (comp->data_size > comp_max_size) { + pr_err("Component %d is of size %d which is bigger than limit %d\n", + comp->index, comp->data_size, comp_max_size); + return -EINVAL; + } + + comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size, + comp_align_bits); + + pr_debug("Component update\n"); + err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle, + comp->index, + comp->data_size); + if (err) + return err; + + err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, + MLXFW_FSM_STATE_DOWNLOAD); + if (err) + goto err_out; + + pr_debug("Component download\n"); + for (offset = 0; + offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits); + offset += comp_max_write_size) { + block_ptr = comp->data + offset; + block_size = (u16) min_t(u32, comp->data_size - offset, + comp_max_write_size); + err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle, + block_ptr, block_size, + offset); + if (err) + goto err_out; + } + + pr_debug("Component verify\n"); + err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle, + comp->index); + if (err) + goto err_out; + + err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED); + if (err) + goto err_out; + return 0; + +err_out: + mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle); + return err; +} + +static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + struct mlxfw_mfa2_file *mfa2_file) +{ + u32 component_count; + int err; + int i; + + err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid, + mlxfw_dev->psid_size, + &component_count); + if (err) { + pr_err("Could not find device PSID in MFA2 file\n"); + return err; + } + + for (i = 0; i < component_count; i++) { + struct mlxfw_mfa2_component *comp; + + comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid, + mlxfw_dev->psid_size, i); + if (IS_ERR(comp)) + return PTR_ERR(comp); + + pr_info("Flashing component type %d\n", comp->index); + err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp); + mlxfw_mfa2_file_component_put(comp); + if (err) + return err; + } + return 0; +} + +int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + const struct firmware *firmware) +{ + struct mlxfw_mfa2_file *mfa2_file; + u32 fwhandle; + int err; + + if (!mlxfw_mfa2_check(firmware)) { + pr_err("Firmware file is not MFA2\n"); + return -EINVAL; + } + + mfa2_file = mlxfw_mfa2_file_init(firmware); + if (IS_ERR(mfa2_file)) + return PTR_ERR(mfa2_file); + + pr_info("Initialize firmware flash process\n"); + err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle); + if (err) { + pr_err("Could not lock the firmware FSM\n"); + goto err_fsm_lock; + } + + err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, + MLXFW_FSM_STATE_LOCKED); + if (err) + goto err_state_wait_idle_to_locked; + + err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file); + if (err) + goto err_flash_components; + + pr_debug("Activate image\n"); + err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle); + if (err) { + pr_err("Could not activate the downloaded image\n"); + goto err_fsm_activate; + } + + err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED); + if (err) + goto err_state_wait_activate_to_locked; + + pr_debug("Handle release\n"); + mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle); + + pr_info("Firmware flash done.\n"); + mlxfw_mfa2_file_fini(mfa2_file); + return 0; + +err_state_wait_activate_to_locked: +err_fsm_activate: +err_flash_components: +err_state_wait_idle_to_locked: + mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle); +err_fsm_lock: + mlxfw_mfa2_file_fini(mfa2_file); + return err; +} +EXPORT_SYMBOL(mlxfw_firmware_flash); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Yotam Gigi "); +MODULE_DESCRIPTION("Mellanox firmware flash lib"); diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c new file mode 100644 index 000000000000..7e9589061d30 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c @@ -0,0 +1,620 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define pr_fmt(fmt) "mlxfw_mfa2: " fmt + +#include +#include +#include +#include +#include "mlxfw_mfa2.h" +#include "mlxfw_mfa2_file.h" +#include "mlxfw_mfa2_tlv.h" +#include "mlxfw_mfa2_format.h" +#include "mlxfw_mfa2_tlv_multi.h" + +/* MFA2 FILE + * +----------------------------------+ + * | MFA2 finger print | + * +----------------------------------+ + * | package descriptor multi_tlv | + * | +------------------------------+ | +-----------------+ + * | | package descriptor tlv +-----> |num_devices=n | + * | +------------------------------+ | |num_components=m | + * +----------------------------------+ |CB offset | + * | device descriptor multi_tlv | |... | + * | +------------------------------+ | | | + * | | PSID tlv | | +-----------------+ + * | +------------------------------+ | + * | | component index tlv | | + * | +------------------------------+ | + * +----------------------------------+ + * | component descriptor multi_tlv | + * | +------------------------------+ | +-----------------+ + * | | component descriptor tlv +-----> |Among others: | + * | +------------------------------+ | |CB offset=o | + * +----------------------------------+ |comp index=i | + * | | |... | + * | | | | + * | | +-----------------+ + * | COMPONENT BLOCK (CB) | + * | | + * | | + * | | + * +----------------------------------+ + * + * On the top level, an MFA2 file contains: + * - Fingerprint + * - Several multi_tlvs (TLVs of type MLXFW_MFA2_TLV_MULTI, as defined in + * mlxfw_mfa2_format.h) + * - Compresses content block + * + * The first multi_tlv + * ------------------- + * The first multi TLV is treated as package descriptor, and expected to have a + * first TLV child of type MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR which contains all + * the global information needed to parse the file. Among others, it contains + * the number of device descriptors and component descriptor following this + * multi TLV. + * + * The device descriptor multi_tlv + * ------------------------------- + * The multi TLVs following the package descriptor are treated as device + * descriptor, and are expected to have the following children: + * - PSID TLV child of type MLXFW_MFA2_TLV_PSID containing that device PSID. + * - Component index of type MLXFW_MFA2_TLV_COMPONENT_PTR that contains that + * device component index. + * + * The component descriptor multi_tlv + * ---------------------------------- + * The multi TLVs following the device descriptor multi TLVs are treated as + * component descriptor, and are expected to have a first child of type + * MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR that contains mostly the component index, + * needed for the flash process and the offset to the binary within the + * component block. + */ + +static const u8 mlxfw_mfa2_fingerprint[] = "MLNX.MFA2.XZ.00!"; +static const int mlxfw_mfa2_fingerprint_len = + sizeof(mlxfw_mfa2_fingerprint) - 1; + +static const u8 mlxfw_mfa2_comp_magic[] = "#BIN.COMPONENT!#"; +static const int mlxfw_mfa2_comp_magic_len = sizeof(mlxfw_mfa2_comp_magic) - 1; + +bool mlxfw_mfa2_check(const struct firmware *fw) +{ + if (fw->size < sizeof(mlxfw_mfa2_fingerprint)) + return false; + + return memcmp(fw->data, mlxfw_mfa2_fingerprint, + mlxfw_mfa2_fingerprint_len) == 0; +} + +static bool +mlxfw_mfa2_tlv_multi_validate(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 idx; + + /* Check that all children are valid */ + mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) { + if (!tlv) { + pr_err("Multi has invalid child"); + return false; + } + } + return true; +} + +static bool +mlxfw_mfa2_file_dev_validate(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *dev_tlv, + u16 dev_idx) +{ + const struct mlxfw_mfa2_tlv_component_ptr *cptr; + const struct mlxfw_mfa2_tlv_multi *multi; + const struct mlxfw_mfa2_tlv_psid *psid; + const struct mlxfw_mfa2_tlv *tlv; + u16 cptr_count; + u16 cptr_idx; + int err; + + pr_debug("Device %d\n", dev_idx); + + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv); + if (!multi) { + pr_err("Device %d is not a valid TLV error\n", dev_idx); + return false; + } + + if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi)) + return false; + + /* Validate the device has PSID tlv */ + tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi, + MLXFW_MFA2_TLV_PSID, 0); + if (!tlv) { + pr_err("Device %d does not have PSID\n", dev_idx); + return false; + } + + psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv); + if (!psid) { + pr_err("Device %d PSID TLV is not valid\n", dev_idx); + return false; + } + + print_hex_dump_debug(" -- Device PSID ", DUMP_PREFIX_NONE, 16, 16, + psid->psid, be16_to_cpu(tlv->len), true); + + /* Validate the device has COMPONENT_PTR */ + err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, multi, + MLXFW_MFA2_TLV_COMPONENT_PTR, + &cptr_count); + if (err) + return false; + + if (cptr_count == 0) { + pr_err("Device %d has no components\n", dev_idx); + return false; + } + + for (cptr_idx = 0; cptr_idx < cptr_count; cptr_idx++) { + tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi, + MLXFW_MFA2_TLV_COMPONENT_PTR, + cptr_idx); + if (!tlv) + return false; + + cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, tlv); + if (!cptr) { + pr_err("Device %d COMPONENT_PTR TLV is not valid\n", + dev_idx); + return false; + } + + pr_debug(" -- Component index %d\n", + be16_to_cpu(cptr->component_index)); + } + return true; +} + +static bool +mlxfw_mfa2_file_comp_validate(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *comp_tlv, + u16 comp_idx) +{ + const struct mlxfw_mfa2_tlv_component_descriptor *cdesc; + const struct mlxfw_mfa2_tlv_multi *multi; + const struct mlxfw_mfa2_tlv *tlv; + + pr_debug("Component %d\n", comp_idx); + + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv); + if (!multi) { + pr_err("Component %d is not a valid TLV error\n", comp_idx); + return false; + } + + if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi)) + return false; + + /* Check that component have COMPONENT_DESCRIPTOR as first child */ + tlv = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi); + if (!tlv) { + pr_err("Component descriptor %d multi TLV error\n", comp_idx); + return false; + } + + cdesc = mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, tlv); + if (!cdesc) { + pr_err("Component %d does not have a valid descriptor\n", + comp_idx); + return false; + } + pr_debug(" -- Component type %d\n", be16_to_cpu(cdesc->identifier)); + pr_debug(" -- Offset 0x%llx and size %d\n", + ((u64) be32_to_cpu(cdesc->cb_offset_h) << 32) + | be32_to_cpu(cdesc->cb_offset_l), be32_to_cpu(cdesc->size)); + + return true; +} + +static bool mlxfw_mfa2_file_validate(const struct mlxfw_mfa2_file *mfa2_file) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 idx; + + pr_debug("Validating file\n"); + + /* check that all the devices exist */ + mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_dev, + mfa2_file->dev_count) { + if (!tlv) { + pr_err("Device TLV error\n"); + return false; + } + + /* Check each device */ + if (!mlxfw_mfa2_file_dev_validate(mfa2_file, tlv, idx)) + return false; + } + + /* check that all the components exist */ + mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_component, + mfa2_file->component_count) { + if (!tlv) { + pr_err("Device TLV error\n"); + return false; + } + + /* Check each component */ + if (!mlxfw_mfa2_file_comp_validate(mfa2_file, tlv, idx)) + return false; + } + return true; +} + +struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw) +{ + const struct mlxfw_mfa2_tlv_package_descriptor *pd; + const struct mlxfw_mfa2_tlv_multi *multi; + const struct mlxfw_mfa2_tlv *multi_child; + const struct mlxfw_mfa2_tlv *first_tlv; + struct mlxfw_mfa2_file *mfa2_file; + const void *first_tlv_ptr; + const void *cb_top_ptr; + + mfa2_file = kcalloc(1, sizeof(*mfa2_file), GFP_KERNEL); + if (!mfa2_file) + return ERR_PTR(-ENOMEM); + + mfa2_file->fw = fw; + first_tlv_ptr = fw->data + NLA_ALIGN(mlxfw_mfa2_fingerprint_len); + first_tlv = mlxfw_mfa2_tlv_get(mfa2_file, first_tlv_ptr); + if (!first_tlv) { + pr_err("Could not parse package descriptor TLV\n"); + goto err_out; + } + + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, first_tlv); + if (!multi) { + pr_err("First TLV is not of valid multi type\n"); + goto err_out; + } + + multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi); + if (!multi_child) + goto err_out; + + pd = mlxfw_mfa2_tlv_package_descriptor_get(mfa2_file, multi_child); + if (!pd) { + pr_err("Could not parse package descriptor TLV\n"); + goto err_out; + } + + mfa2_file->first_dev = mlxfw_mfa2_tlv_next(mfa2_file, first_tlv); + if (!mfa2_file->first_dev) { + pr_err("First device TLV is not valid\n"); + goto err_out; + } + + mfa2_file->dev_count = be16_to_cpu(pd->num_devices); + mfa2_file->first_component = mlxfw_mfa2_tlv_advance(mfa2_file, + mfa2_file->first_dev, + mfa2_file->dev_count); + mfa2_file->component_count = be16_to_cpu(pd->num_components); + mfa2_file->cb = fw->data + NLA_ALIGN(be32_to_cpu(pd->cb_offset)); + if (!mlxfw_mfa2_valid_ptr(mfa2_file, mfa2_file->cb)) { + pr_err("Component block is out side the file\n"); + goto err_out; + } + mfa2_file->cb_archive_size = be32_to_cpu(pd->cb_archive_size); + cb_top_ptr = mfa2_file->cb + mfa2_file->cb_archive_size - 1; + if (!mlxfw_mfa2_valid_ptr(mfa2_file, cb_top_ptr)) { + pr_err("Component block size is too big\n"); + goto err_out; + } + + if (!mlxfw_mfa2_file_validate(mfa2_file)) + goto err_out; + return mfa2_file; +err_out: + kfree(mfa2_file); + return ERR_PTR(-EINVAL); +} + +static const struct mlxfw_mfa2_tlv_multi * +mlxfw_mfa2_tlv_dev_get(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, u16 psid_size) +{ + const struct mlxfw_mfa2_tlv_psid *tlv_psid; + const struct mlxfw_mfa2_tlv_multi *dev_multi; + const struct mlxfw_mfa2_tlv *dev_tlv; + const struct mlxfw_mfa2_tlv *tlv; + u32 idx; + + /* for each device tlv */ + mlxfw_mfa2_tlv_foreach(mfa2_file, dev_tlv, idx, mfa2_file->first_dev, + mfa2_file->dev_count) { + if (!dev_tlv) + return NULL; + + dev_multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv); + if (!dev_multi) + return NULL; + + /* find psid child and compare */ + tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi, + MLXFW_MFA2_TLV_PSID, 0); + if (!tlv) + return NULL; + if (be16_to_cpu(tlv->len) != psid_size) + continue; + + tlv_psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv); + if (!tlv_psid) + return NULL; + + if (memcmp(psid, tlv_psid->psid, psid_size) == 0) + return dev_multi; + } + + return NULL; +} + +int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, u32 psid_size, + u32 *p_count) +{ + const struct mlxfw_mfa2_tlv_multi *dev_multi; + u16 count; + int err; + + dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size); + if (!dev_multi) + return -EINVAL; + + err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, dev_multi, + MLXFW_MFA2_TLV_COMPONENT_PTR, + &count); + if (err) + return err; + + *p_count = count; + return 0; +} + +static int mlxfw_mfa2_xz_dec_run(struct xz_dec *xz_dec, struct xz_buf *xz_buf, + bool *finished) +{ + enum xz_ret xz_ret; + + xz_ret = xz_dec_run(xz_dec, xz_buf); + + switch (xz_ret) { + case XZ_STREAM_END: + *finished = true; + return 0; + case XZ_OK: + *finished = false; + return 0; + case XZ_MEM_ERROR: + pr_err("xz no memory\n"); + return -ENOMEM; + case XZ_DATA_ERROR: + pr_err("xz file corrupted\n"); + return -EINVAL; + case XZ_FORMAT_ERROR: + pr_err("xz format not found\n"); + return -EINVAL; + case XZ_OPTIONS_ERROR: + pr_err("unsupported xz option\n"); + return -EINVAL; + case XZ_MEMLIMIT_ERROR: + pr_err("xz dictionary too small\n"); + return -EINVAL; + default: + pr_err("xz error %d\n", xz_ret); + return -EINVAL; + } +} + +static int mlxfw_mfa2_file_cb_offset_xz(const struct mlxfw_mfa2_file *mfa2_file, + off_t off, size_t size, u8 *buf) +{ + struct xz_dec *xz_dec; + struct xz_buf dec_buf; + off_t curr_off = 0; + bool finished; + int err; + + xz_dec = xz_dec_init(XZ_DYNALLOC, (u32) -1); + if (!xz_dec) + return -EINVAL; + + dec_buf.in_size = mfa2_file->cb_archive_size; + dec_buf.in = mfa2_file->cb; + dec_buf.in_pos = 0; + dec_buf.out = buf; + + /* decode up to the offset */ + do { + dec_buf.out_pos = 0; + dec_buf.out_size = min_t(size_t, size, off - curr_off); + if (dec_buf.out_size == 0) + break; + + err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished); + if (err) + goto out; + if (finished) { + pr_err("xz section too short\n"); + err = -EINVAL; + goto out; + } + curr_off += dec_buf.out_pos; + } while (curr_off != off); + + /* decode the needed section */ + dec_buf.out_pos = 0; + dec_buf.out_size = size; + err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished); + if (err) + goto out; +out: + xz_dec_end(xz_dec); + return err; +} + +static const struct mlxfw_mfa2_tlv_component_descriptor * +mlxfw_mfa2_file_component_tlv_get(const struct mlxfw_mfa2_file *mfa2_file, + u16 comp_index) +{ + const struct mlxfw_mfa2_tlv_multi *multi; + const struct mlxfw_mfa2_tlv *multi_child; + const struct mlxfw_mfa2_tlv *comp_tlv; + + if (comp_index > mfa2_file->component_count) + return NULL; + + comp_tlv = mlxfw_mfa2_tlv_advance(mfa2_file, mfa2_file->first_component, + comp_index); + if (!comp_tlv) + return NULL; + + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv); + if (!multi) + return NULL; + + multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi); + if (!multi_child) + return NULL; + + return mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, multi_child); +} + +struct mlxfw_mfa2_comp_data { + struct mlxfw_mfa2_component comp; + u8 buff[0]; +}; + +static const struct mlxfw_mfa2_tlv_component_descriptor * +mlxfw_mfa2_file_component_find(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, int psid_size, + int component_index) +{ + const struct mlxfw_mfa2_tlv_component_ptr *cptr; + const struct mlxfw_mfa2_tlv_multi *dev_multi; + const struct mlxfw_mfa2_tlv *cptr_tlv; + u16 comp_idx; + + dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size); + if (!dev_multi) + return NULL; + + cptr_tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi, + MLXFW_MFA2_TLV_COMPONENT_PTR, + component_index); + if (!cptr_tlv) + return NULL; + + cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, cptr_tlv); + if (!cptr) + return NULL; + + comp_idx = be16_to_cpu(cptr->component_index); + return mlxfw_mfa2_file_component_tlv_get(mfa2_file, comp_idx); +} + +struct mlxfw_mfa2_component * +mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, int psid_size, + int component_index) +{ + const struct mlxfw_mfa2_tlv_component_descriptor *comp; + struct mlxfw_mfa2_comp_data *comp_data; + u32 comp_buf_size; + off_t cb_offset; + u32 comp_size; + int err; + + comp = mlxfw_mfa2_file_component_find(mfa2_file, psid, psid_size, + component_index); + if (!comp) + return ERR_PTR(-EINVAL); + + cb_offset = (u64) be32_to_cpu(comp->cb_offset_h) << 32 | + be32_to_cpu(comp->cb_offset_l); + comp_size = be32_to_cpu(comp->size); + comp_buf_size = comp_size + mlxfw_mfa2_comp_magic_len; + + comp_data = kmalloc(sizeof(*comp_data) + comp_buf_size, GFP_KERNEL); + if (!comp_data) + return ERR_PTR(-ENOMEM); + comp_data->comp.data_size = comp_size; + comp_data->comp.index = be16_to_cpu(comp->identifier); + err = mlxfw_mfa2_file_cb_offset_xz(mfa2_file, cb_offset, comp_buf_size, + comp_data->buff); + if (err) { + pr_err("Component could not be reached in CB\n"); + goto err_out; + } + + if (memcmp(comp_data->buff, mlxfw_mfa2_comp_magic, + mlxfw_mfa2_comp_magic_len) != 0) { + pr_err("Component has wrong magic\n"); + goto err_out; + } + + comp_data->comp.data = comp_data->buff + mlxfw_mfa2_comp_magic_len; + return &comp_data->comp; +err_out: + kfree(comp_data); + return ERR_PTR(err); +} + +void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *comp) +{ + const struct mlxfw_mfa2_comp_data *comp_data; + + comp_data = container_of(comp, struct mlxfw_mfa2_comp_data, comp); + kfree(comp_data); +} + +void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file) +{ + kfree(mfa2_file); +} diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h new file mode 100644 index 000000000000..20472aa139cd --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h @@ -0,0 +1,66 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MLXFW_MFA2_H +#define _MLXFW_MFA2_H + +#include +#include "mlxfw.h" + +struct mlxfw_mfa2_component { + u16 index; + u32 data_size; + u8 *data; +}; + +struct mlxfw_mfa2_file; + +bool mlxfw_mfa2_check(const struct firmware *fw); + +struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw); + +int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, u32 psid_size, + u32 *p_count); + +struct mlxfw_mfa2_component * +mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file, + const char *psid, int psid_size, + int component_index); + +void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *component); + +void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file); + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h new file mode 100644 index 000000000000..f667942b1ea3 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h @@ -0,0 +1,60 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MLXFW_MFA2_FILE_H +#define _MLXFW_MFA2_FILE_H + +#include +#include + +struct mlxfw_mfa2_file { + const struct firmware *fw; + const struct mlxfw_mfa2_tlv *first_dev; + u16 dev_count; + const struct mlxfw_mfa2_tlv *first_component; + u16 component_count; + const void *cb; /* components block */ + u32 cb_archive_size; /* size of compressed components block */ +}; + +static inline bool mlxfw_mfa2_valid_ptr(const struct mlxfw_mfa2_file *mfa2_file, + const void *ptr) +{ + const void *valid_to = mfa2_file->fw->data + mfa2_file->fw->size; + const void *valid_from = mfa2_file->fw->data; + + return ptr > valid_from && ptr < valid_to; +} + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h new file mode 100644 index 000000000000..dd66737c033d --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h @@ -0,0 +1,103 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _MLXFW_MFA2_FORMAT_H +#define _MLXFW_MFA2_FORMAT_H + +#include "mlxfw_mfa2_file.h" +#include "mlxfw_mfa2_tlv.h" + +enum mlxfw_mfa2_tlv_type { + MLXFW_MFA2_TLV_MULTI_PART = 0x01, + MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR = 0x02, + MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR = 0x04, + MLXFW_MFA2_TLV_COMPONENT_PTR = 0x22, + MLXFW_MFA2_TLV_PSID = 0x2A, +}; + +enum mlxfw_mfa2_compression_type { + MLXFW_MFA2_COMPRESSION_TYPE_NONE, + MLXFW_MFA2_COMPRESSION_TYPE_XZ, +}; + +struct mlxfw_mfa2_tlv_package_descriptor { + __be16 num_components; + __be16 num_devices; + __be32 cb_offset; + __be32 cb_archive_size; + __be32 cb_size_h; + __be32 cb_size_l; + u8 padding[3]; + u8 cv_compression; + __be32 user_data_offset; +} __packed; + +MLXFW_MFA2_TLV(package_descriptor, struct mlxfw_mfa2_tlv_package_descriptor, + MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR); + +struct mlxfw_mfa2_tlv_multi { + __be16 num_extensions; + __be16 total_len; +} __packed; + +MLXFW_MFA2_TLV(multi, struct mlxfw_mfa2_tlv_multi, + MLXFW_MFA2_TLV_MULTI_PART); + +struct mlxfw_mfa2_tlv_psid { + u8 psid[0]; +} __packed; + +MLXFW_MFA2_TLV_VARSIZE(psid, struct mlxfw_mfa2_tlv_psid, + MLXFW_MFA2_TLV_PSID); + +struct mlxfw_mfa2_tlv_component_ptr { + __be16 storage_id; + __be16 component_index; + __be32 storage_address; +} __packed; + +MLXFW_MFA2_TLV(component_ptr, struct mlxfw_mfa2_tlv_component_ptr, + MLXFW_MFA2_TLV_COMPONENT_PTR); + +struct mlxfw_mfa2_tlv_component_descriptor { + __be16 pldm_classification; + __be16 identifier; + __be32 cb_offset_h; + __be32 cb_offset_l; + __be32 size; +} __packed; + +MLXFW_MFA2_TLV(component_descriptor, struct mlxfw_mfa2_tlv_component_descriptor, + MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR); + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h new file mode 100644 index 000000000000..cc013e77b326 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h @@ -0,0 +1,98 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MLXFW_MFA2_TLV_H +#define _MLXFW_MFA2_TLV_H + +#include +#include "mlxfw_mfa2_file.h" + +struct mlxfw_mfa2_tlv { + u8 version; + u8 type; + __be16 len; + u8 data[0]; +} __packed; + +static inline const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_get(const struct mlxfw_mfa2_file *mfa2_file, const void *ptr) +{ + if (!mlxfw_mfa2_valid_ptr(mfa2_file, ptr) || + !mlxfw_mfa2_valid_ptr(mfa2_file, ptr + sizeof(struct mlxfw_mfa2_tlv))) + return NULL; + return ptr; +} + +static inline const void * +mlxfw_mfa2_tlv_payload_get(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *tlv, u8 payload_type, + size_t payload_size, bool varsize) +{ + void *tlv_top; + + tlv_top = (void *) tlv + be16_to_cpu(tlv->len) - 1; + if (!mlxfw_mfa2_valid_ptr(mfa2_file, tlv) || + !mlxfw_mfa2_valid_ptr(mfa2_file, tlv_top)) + return NULL; + if (tlv->type != payload_type) + return NULL; + if (varsize && (be16_to_cpu(tlv->len) < payload_size)) + return NULL; + if (!varsize && (be16_to_cpu(tlv->len) != payload_size)) + return NULL; + + return tlv->data; +} + +#define MLXFW_MFA2_TLV(name, payload_type, tlv_type) \ +static inline const payload_type * \ +mlxfw_mfa2_tlv_ ## name ## _get(const struct mlxfw_mfa2_file *mfa2_file, \ + const struct mlxfw_mfa2_tlv *tlv) \ +{ \ + return mlxfw_mfa2_tlv_payload_get(mfa2_file, tlv, \ + tlv_type, sizeof(payload_type), \ + false); \ +} + +#define MLXFW_MFA2_TLV_VARSIZE(name, payload_type, tlv_type) \ +static inline const payload_type * \ +mlxfw_mfa2_tlv_ ## name ## _get(const struct mlxfw_mfa2_file *mfa2_file, \ + const struct mlxfw_mfa2_tlv *tlv) \ +{ \ + return mlxfw_mfa2_tlv_payload_get(mfa2_file, tlv, \ + tlv_type, sizeof(payload_type), \ + true); \ +} + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c new file mode 100644 index 000000000000..0094b92a233b --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c @@ -0,0 +1,126 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define pr_fmt(fmt) "MFA2: " fmt + +#include "mlxfw_mfa2_tlv_multi.h" +#include + +#define MLXFW_MFA2_TLV_TOTAL_SIZE(tlv) \ + NLA_ALIGN(sizeof(*(tlv)) + be16_to_cpu((tlv)->len)) + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_multi_child(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi) +{ + size_t multi_len; + + multi_len = NLA_ALIGN(sizeof(struct mlxfw_mfa2_tlv_multi)); + return mlxfw_mfa2_tlv_get(mfa2_file, (void *) multi + multi_len); +} + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_next(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *tlv) +{ + const struct mlxfw_mfa2_tlv_multi *multi; + u16 tlv_len; + void *next; + + tlv_len = MLXFW_MFA2_TLV_TOTAL_SIZE(tlv); + + if (tlv->type == MLXFW_MFA2_TLV_MULTI_PART) { + multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, tlv); + tlv_len = NLA_ALIGN(tlv_len + be16_to_cpu(multi->total_len)); + } + + next = (void *) tlv + tlv_len; + return mlxfw_mfa2_tlv_get(mfa2_file, next); +} + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_advance(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *from_tlv, u16 count) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 idx; + + mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, from_tlv, count) + if (!tlv) + return NULL; + return tlv; +} + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_multi_child_find(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi, + enum mlxfw_mfa2_tlv_type type, u16 index) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 skip = 0; + u16 idx; + + mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) { + if (!tlv) { + pr_err("TLV parsing error\n"); + return NULL; + } + if (tlv->type == type) + if (skip++ == index) + return tlv; + } + return NULL; +} + +int mlxfw_mfa2_tlv_multi_child_count(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi, + enum mlxfw_mfa2_tlv_type type, + u16 *p_count) +{ + const struct mlxfw_mfa2_tlv *tlv; + u16 count = 0; + u16 idx; + + mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) { + if (!tlv) { + pr_err("TLV parsing error\n"); + return -EINVAL; + } + + if (tlv->type == type) + count++; + } + *p_count = count; + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h new file mode 100644 index 000000000000..2c667894f3a2 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h @@ -0,0 +1,71 @@ +/* + * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Yotam Gigi + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _MLXFW_MFA2_TLV_MULTI_H +#define _MLXFW_MFA2_TLV_MULTI_H + +#include "mlxfw_mfa2_tlv.h" +#include "mlxfw_mfa2_format.h" +#include "mlxfw_mfa2_file.h" + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_multi_child(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi); + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_next(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *tlv); + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_advance(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv *from_tlv, u16 count); + +const struct mlxfw_mfa2_tlv * +mlxfw_mfa2_tlv_multi_child_find(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi, + enum mlxfw_mfa2_tlv_type type, u16 index); + +int mlxfw_mfa2_tlv_multi_child_count(const struct mlxfw_mfa2_file *mfa2_file, + const struct mlxfw_mfa2_tlv_multi *multi, + enum mlxfw_mfa2_tlv_type type, + u16 *p_count); + +#define mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, from_tlv, count) \ + for (idx = 0, tlv = from_tlv; idx < (count); \ + idx++, tlv = mlxfw_mfa2_tlv_next(mfa2_file, tlv)) + +#define mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) \ + mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, \ + mlxfw_mfa2_tlv_multi_child(mfa2_file, multi), \ + be16_to_cpu(multi->num_extensions) + 1) +#endif -- cgit v1.2.3 From 4f2402d46ba7b83d05809bbce892296f86aa30af Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Tue, 23 May 2017 21:56:24 +0200 Subject: mlxsw: reg: Add Management Component Query Information register The MCQI register queries information about firmware components. It will be needed by the mlxfw module to query various options about the components, such as their max size, alignment and max write size. Signed-off-by: Yotam Gigi Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 84 +++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 83b277c8090e..adb385f5ebb7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -5643,6 +5643,89 @@ static inline void mlxsw_reg_mlcr_pack(char *payload, u8 local_port, MLXSW_REG_MLCR_DURATION_MAX : 0); } +/* MCQI - Management Component Query Information + * --------------------------------------------- + * This register allows querying information about firmware components. + */ +#define MLXSW_REG_MCQI_ID 0x9061 +#define MLXSW_REG_MCQI_BASE_LEN 0x18 +#define MLXSW_REG_MCQI_CAP_LEN 0x14 +#define MLXSW_REG_MCQI_LEN (MLXSW_REG_MCQI_BASE_LEN + MLXSW_REG_MCQI_CAP_LEN) + +MLXSW_REG_DEFINE(mcqi, MLXSW_REG_MCQI_ID, MLXSW_REG_MCQI_LEN); + +/* reg_mcqi_component_index + * Index of the accessed component. + * Access: Index + */ +MLXSW_ITEM32(reg, mcqi, component_index, 0x00, 0, 16); + +enum mlxfw_reg_mcqi_info_type { + MLXSW_REG_MCQI_INFO_TYPE_CAPABILITIES, +}; + +/* reg_mcqi_info_type + * Component properties set. + * Access: RW + */ +MLXSW_ITEM32(reg, mcqi, info_type, 0x08, 0, 5); + +/* reg_mcqi_offset + * The requested/returned data offset from the section start, given in bytes. + * Must be DWORD aligned. + * Access: RW + */ +MLXSW_ITEM32(reg, mcqi, offset, 0x10, 0, 32); + +/* reg_mcqi_data_size + * The requested/returned data size, given in bytes. If data_size is not DWORD + * aligned, the last bytes are zero padded. + * Access: RW + */ +MLXSW_ITEM32(reg, mcqi, data_size, 0x14, 0, 16); + +/* reg_mcqi_cap_max_component_size + * Maximum size for this component, given in bytes. + * Access: RO + */ +MLXSW_ITEM32(reg, mcqi, cap_max_component_size, 0x20, 0, 32); + +/* reg_mcqi_cap_log_mcda_word_size + * Log 2 of the access word size in bytes. Read and write access must be aligned + * to the word size. Write access must be done for an integer number of words. + * Access: RO + */ +MLXSW_ITEM32(reg, mcqi, cap_log_mcda_word_size, 0x24, 28, 4); + +/* reg_mcqi_cap_mcda_max_write_size + * Maximal write size for MCDA register + * Access: RO + */ +MLXSW_ITEM32(reg, mcqi, cap_mcda_max_write_size, 0x24, 0, 16); + +static inline void mlxsw_reg_mcqi_pack(char *payload, u16 component_index) +{ + MLXSW_REG_ZERO(mcqi, payload); + mlxsw_reg_mcqi_component_index_set(payload, component_index); + mlxsw_reg_mcqi_info_type_set(payload, + MLXSW_REG_MCQI_INFO_TYPE_CAPABILITIES); + mlxsw_reg_mcqi_offset_set(payload, 0); + mlxsw_reg_mcqi_data_size_set(payload, MLXSW_REG_MCQI_CAP_LEN); +} + +static inline void mlxsw_reg_mcqi_unpack(char *payload, + u32 *p_cap_max_component_size, + u8 *p_cap_log_mcda_word_size, + u16 *p_cap_mcda_max_write_size) +{ + *p_cap_max_component_size = + mlxsw_reg_mcqi_cap_max_component_size_get(payload); + *p_cap_log_mcda_word_size = + mlxsw_reg_mcqi_cap_log_mcda_word_size_get(payload); + *p_cap_mcda_max_write_size = + mlxsw_reg_mcqi_cap_mcda_max_write_size_get(payload); +} + /* MPSC - Monitoring Packet Sampling Configuration Register * -------------------------------------------------------- * MPSC Register is used to configure the Packet Sampling mechanism. @@ -6221,6 +6304,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mpar), MLXSW_REG(mlcr), MLXSW_REG(mpsc), + MLXSW_REG(mcqi), MLXSW_REG(mgpc), MLXSW_REG(sbpr), MLXSW_REG(sbcm), -- cgit v1.2.3 From 191839de90f8890e8742b65a656695de335cf0d2 Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Tue, 23 May 2017 21:56:25 +0200 Subject: mlxsw: reg: Add Management Component Control register The MCC register allows controlling and querying the firmware flash state machine (FSM). Signed-off-by: Yotam Gigi Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 83 +++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index adb385f5ebb7..f3c768ce5ee0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -5726,6 +5726,88 @@ static inline void mlxsw_reg_mcqi_unpack(char *payload, mlxsw_reg_mcqi_cap_mcda_max_write_size_get(payload); } +/* MCC - Management Component Control + * ---------------------------------- + * Controls the firmware component and updates the FSM. + */ +#define MLXSW_REG_MCC_ID 0x9062 +#define MLXSW_REG_MCC_LEN 0x1C + +MLXSW_REG_DEFINE(mcc, MLXSW_REG_MCC_ID, MLXSW_REG_MCC_LEN); + +enum mlxsw_reg_mcc_instruction { + MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01, + MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02, + MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03, + MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04, + MLXSW_REG_MCC_INSTRUCTION_ACTIVATE = 0x06, + MLXSW_REG_MCC_INSTRUCTION_CANCEL = 0x08, +}; + +/* reg_mcc_instruction + * Command to be executed by the FSM. + * Applicable for write operation only. + * Access: RW + */ +MLXSW_ITEM32(reg, mcc, instruction, 0x00, 0, 8); + +/* reg_mcc_component_index + * Index of the accessed component. Applicable only for commands that + * refer to components. Otherwise, this field is reserved. + * Access: Index + */ +MLXSW_ITEM32(reg, mcc, component_index, 0x04, 0, 16); + +/* reg_mcc_update_handle + * Token representing the current flow executed by the FSM. + * Access: WO + */ +MLXSW_ITEM32(reg, mcc, update_handle, 0x08, 0, 24); + +/* reg_mcc_error_code + * Indicates the successful completion of the instruction, or the reason it + * failed + * Access: RO + */ +MLXSW_ITEM32(reg, mcc, error_code, 0x0C, 8, 8); + +/* reg_mcc_control_state + * Current FSM state + * Access: RO + */ +MLXSW_ITEM32(reg, mcc, control_state, 0x0C, 0, 4); + +/* reg_mcc_component_size + * Component size in bytes. Valid for UPDATE_COMPONENT instruction. Specifying + * the size may shorten the update time. Value 0x0 means that size is + * unspecified. + * Access: WO + */ +MLXSW_ITEM32(reg, mcc, component_size, 0x10, 0, 32); + +static inline void mlxsw_reg_mcc_pack(char *payload, + enum mlxsw_reg_mcc_instruction instr, + u16 component_index, u32 update_handle, + u32 component_size) +{ + MLXSW_REG_ZERO(mcc, payload); + mlxsw_reg_mcc_instruction_set(payload, instr); + mlxsw_reg_mcc_component_index_set(payload, component_index); + mlxsw_reg_mcc_update_handle_set(payload, update_handle); + mlxsw_reg_mcc_component_size_set(payload, component_size); +} + +static inline void mlxsw_reg_mcc_unpack(char *payload, u32 *p_update_handle, + u8 *p_error_code, u8 *p_control_state) +{ + if (p_update_handle) + *p_update_handle = mlxsw_reg_mcc_update_handle_get(payload); + if (p_error_code) + *p_error_code = mlxsw_reg_mcc_error_code_get(payload); + if (p_control_state) + *p_control_state = mlxsw_reg_mcc_control_state_get(payload); +} + /* MPSC - Monitoring Packet Sampling Configuration Register * -------------------------------------------------------- * MPSC Register is used to configure the Packet Sampling mechanism. @@ -6305,6 +6387,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mlcr), MLXSW_REG(mpsc), MLXSW_REG(mcqi), + MLXSW_REG(mcc), MLXSW_REG(mgpc), MLXSW_REG(sbpr), MLXSW_REG(sbcm), -- cgit v1.2.3 From 4625d59d6d2cd8eda5f3590e1cf453ca64142d5e Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Tue, 23 May 2017 21:56:26 +0200 Subject: mlxsw: reg: Add Management Component Data Access register The MCDA register allows reading and writing a firmware component. Signed-off-by: Yotam Gigi Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index f3c768ce5ee0..182150afd5ad 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -5808,6 +5808,57 @@ static inline void mlxsw_reg_mcc_unpack(char *payload, u32 *p_update_handle, *p_control_state = mlxsw_reg_mcc_control_state_get(payload); } +/* MCDA - Management Component Data Access + * --------------------------------------- + * This register allows reading and writing a firmware component. + */ +#define MLXSW_REG_MCDA_ID 0x9063 +#define MLXSW_REG_MCDA_BASE_LEN 0x10 +#define MLXSW_REG_MCDA_MAX_DATA_LEN 0x80 +#define MLXSW_REG_MCDA_LEN \ + (MLXSW_REG_MCDA_BASE_LEN + MLXSW_REG_MCDA_MAX_DATA_LEN) + +MLXSW_REG_DEFINE(mcda, MLXSW_REG_MCDA_ID, MLXSW_REG_MCDA_LEN); + +/* reg_mcda_update_handle + * Token representing the current flow executed by the FSM. + * Access: RW + */ +MLXSW_ITEM32(reg, mcda, update_handle, 0x00, 0, 24); + +/* reg_mcda_offset + * Offset of accessed address relative to component start. Accesses must be in + * accordance to log_mcda_word_size in MCQI reg. + * Access: RW + */ +MLXSW_ITEM32(reg, mcda, offset, 0x04, 0, 32); + +/* reg_mcda_size + * Size of the data accessed, given in bytes. + * Access: RW + */ +MLXSW_ITEM32(reg, mcda, size, 0x08, 0, 16); + +/* reg_mcda_data + * Data block accessed. + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, mcda, data, 0x10, 0, 32, 4, 0, false); + +static inline void mlxsw_reg_mcda_pack(char *payload, u32 update_handle, + u32 offset, u16 size, u8 *data) +{ + int i; + + MLXSW_REG_ZERO(mcda, payload); + mlxsw_reg_mcda_update_handle_set(payload, update_handle); + mlxsw_reg_mcda_offset_set(payload, offset); + mlxsw_reg_mcda_size_set(payload, size); + + for (i = 0; i < size / 4; i++) + mlxsw_reg_mcda_data_set(payload, i, *(u32 *) &data[i * 4]); +} + /* MPSC - Monitoring Packet Sampling Configuration Register * -------------------------------------------------------- * MPSC Register is used to configure the Packet Sampling mechanism. @@ -6388,6 +6439,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mpsc), MLXSW_REG(mcqi), MLXSW_REG(mcc), + MLXSW_REG(mcda), MLXSW_REG(mgpc), MLXSW_REG(sbpr), MLXSW_REG(sbcm), -- cgit v1.2.3 From e5e5c88a1f29096f8a6768975d3f987f7eb59d67 Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Tue, 23 May 2017 21:56:27 +0200 Subject: mlxsw: spectrum: Add the needed callbacks for mlxfw integration The mlxfw module defines several needed callbacks in order to flash the device's firmware. As the mlxfw module is shared between several different drivers, those callbacks are the glue functionality that is responsible for hardware interaction. Add those callbacks using the MCQI, MCC, MCDA registers. Signed-off-by: Yotam Gigi Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 166 +++++++++++++++++++++++++ 1 file changed, 166 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 8a165bbfcedc..b533a53090f2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -68,6 +68,7 @@ #include "txheader.h" #include "spectrum_cnt.h" #include "spectrum_dpipe.h" +#include "../mlxfw/mlxfw.h" static const char mlxsw_sp_driver_name[] = "mlxsw_spectrum"; static const char mlxsw_sp_driver_version[] = "1.0"; @@ -140,6 +141,171 @@ MLXSW_ITEM32(tx, hdr, fid, 0x08, 0, 16); */ MLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4); +struct mlxsw_sp_mlxfw_dev { + struct mlxfw_dev mlxfw_dev; + struct mlxsw_sp *mlxsw_sp; +}; + +static int mlxsw_sp_component_query(struct mlxfw_dev *mlxfw_dev, + u16 component_index, u32 *p_max_size, + u8 *p_align_bits, u16 *p_max_write_size) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcqi_pl[MLXSW_REG_MCQI_LEN]; + int err; + + mlxsw_reg_mcqi_pack(mcqi_pl, component_index); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mcqi), mcqi_pl); + if (err) + return err; + mlxsw_reg_mcqi_unpack(mcqi_pl, p_max_size, p_align_bits, + p_max_write_size); + + *p_align_bits = max_t(u8, *p_align_bits, 2); + *p_max_write_size = min_t(u16, *p_max_write_size, + MLXSW_REG_MCDA_MAX_DATA_LEN); + return 0; +} + +static int mlxsw_sp_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + u8 control_state; + int err; + + mlxsw_reg_mcc_pack(mcc_pl, 0, 0, 0, 0); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); + if (err) + return err; + + mlxsw_reg_mcc_unpack(mcc_pl, fwhandle, NULL, &control_state); + if (control_state != MLXFW_FSM_STATE_IDLE) + return -EBUSY; + + mlxsw_reg_mcc_pack(mcc_pl, + MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE, + 0, *fwhandle, 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static int mlxsw_sp_fsm_component_update(struct mlxfw_dev *mlxfw_dev, + u32 fwhandle, u16 component_index, + u32 component_size) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT, + component_index, fwhandle, component_size); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static int mlxsw_sp_fsm_block_download(struct mlxfw_dev *mlxfw_dev, + u32 fwhandle, u8 *data, u16 size, + u32 offset) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcda_pl[MLXSW_REG_MCDA_LEN]; + + mlxsw_reg_mcda_pack(mcda_pl, fwhandle, offset, size, data); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcda), mcda_pl); +} + +static int mlxsw_sp_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, + u32 fwhandle, u16 component_index) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT, + component_index, fwhandle, 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static int mlxsw_sp_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_ACTIVATE, 0, + fwhandle, 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static int mlxsw_sp_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + enum mlxfw_fsm_state *fsm_state, + enum mlxfw_fsm_state_err *fsm_state_err) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + u8 control_state; + u8 error_code; + int err; + + mlxsw_reg_mcc_pack(mcc_pl, 0, 0, fwhandle, 0); + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); + if (err) + return err; + + mlxsw_reg_mcc_unpack(mcc_pl, NULL, &error_code, &control_state); + *fsm_state = control_state; + *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code, + MLXFW_FSM_STATE_ERR_MAX); + return 0; +} + +static void mlxsw_sp_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_CANCEL, 0, + fwhandle, 0); + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static void mlxsw_sp_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) +{ + struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = + container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + char mcc_pl[MLXSW_REG_MCC_LEN]; + + mlxsw_reg_mcc_pack(mcc_pl, + MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0, + fwhandle, 0); + mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl); +} + +static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = { + .component_query = mlxsw_sp_component_query, + .fsm_lock = mlxsw_sp_fsm_lock, + .fsm_component_update = mlxsw_sp_fsm_component_update, + .fsm_block_download = mlxsw_sp_fsm_block_download, + .fsm_component_verify = mlxsw_sp_fsm_component_verify, + .fsm_activate = mlxsw_sp_fsm_activate, + .fsm_query_state = mlxsw_sp_fsm_query_state, + .fsm_cancel = mlxsw_sp_fsm_cancel, + .fsm_release = mlxsw_sp_fsm_release +}; + int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, unsigned int counter_index, u64 *packets, u64 *bytes) -- cgit v1.2.3 From c41d007588c1b6dac9f6d08c92d7449a8c2bfef8 Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Tue, 23 May 2017 21:56:28 +0200 Subject: mlxsw: core: Create the mlxsw_fw_rev struct This struct was previously an anonymous struct defined inside the mlxsw_bus_info struct. Extract it to a struct named mlxsw_fw_rev, as it will be needed later by the spectrum driver. Signed-off-by: Yotam Gigi Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 7fb35395adf5..6e966af72fc4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -344,15 +344,17 @@ struct mlxsw_bus { u8 features; }; +struct mlxsw_fw_rev { + u16 major; + u16 minor; + u16 subminor; +}; + struct mlxsw_bus_info { const char *device_kind; const char *device_name; struct device *dev; - struct { - u16 major; - u16 minor; - u16 subminor; - } fw_rev; + struct mlxsw_fw_rev fw_rev; u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN]; u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN]; }; -- cgit v1.2.3 From 6b7421992b8d6ab8da5d5f3afae17fb5515fd633 Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Tue, 23 May 2017 21:56:29 +0200 Subject: mlxsw: spectrum: Validate firmware revision on init Make the spectrum module check the current device firmware version, and if it is below the supported version, use the libfirmware API to request a firmware file with the supported firmware version and flash it to the device using the mlxfw module. The firmware file names are expected to be of Mellanox Firmware Archive version 2 (MFA2) format and their name are expected to be in the following pattern: "mlxsw_spectrum-...mfa2". Signed-off-by: Yotam Gigi Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/Kconfig | 1 + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 67 ++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig index ef23eaedc2ff..b9f80c2a8ae9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig @@ -75,6 +75,7 @@ config MLXSW_SPECTRUM depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV && VLAN_8021Q depends on PSAMPLE || PSAMPLE=n select PARMAN + select MLXFW default m ---help--- This driver supports Mellanox Technologies Spectrum Ethernet diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index b533a53090f2..9594e9d215e8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -70,6 +70,21 @@ #include "spectrum_dpipe.h" #include "../mlxfw/mlxfw.h" +#define MLXSW_FWREV_MAJOR 13 +#define MLXSW_FWREV_MINOR 1420 +#define MLXSW_FWREV_SUBMINOR 122 + +static const struct mlxsw_fw_rev mlxsw_sp_supported_fw_rev = { + .major = MLXSW_FWREV_MAJOR, + .minor = MLXSW_FWREV_MINOR, + .subminor = MLXSW_FWREV_SUBMINOR +}; + +#define MLXSW_SP_FW_FILENAME \ + "mlxsw_spectrum-" __stringify(MLXSW_FWREV_MAJOR) \ + "." __stringify(MLXSW_FWREV_MINOR) \ + "." __stringify(MLXSW_FWREV_SUBMINOR) ".mfa2" + static const char mlxsw_sp_driver_name[] = "mlxsw_spectrum"; static const char mlxsw_sp_driver_version[] = "1.0"; @@ -306,6 +321,51 @@ static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = { .fsm_release = mlxsw_sp_fsm_release }; +static bool mlxsw_sp_fw_rev_ge(const struct mlxsw_fw_rev *a, + const struct mlxsw_fw_rev *b) +{ + if (a->major != b->major) + return a->major > b->major; + if (a->minor != b->minor) + return a->minor > b->minor; + return a->subminor >= b->subminor; +} + +static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp) +{ + const struct mlxsw_fw_rev *rev = &mlxsw_sp->bus_info->fw_rev; + struct mlxsw_sp_mlxfw_dev mlxsw_sp_mlxfw_dev = { + .mlxfw_dev = { + .ops = &mlxsw_sp_mlxfw_dev_ops, + .psid = mlxsw_sp->bus_info->psid, + .psid_size = strlen(mlxsw_sp->bus_info->psid), + }, + .mlxsw_sp = mlxsw_sp + }; + const struct firmware *firmware; + int err; + + if (mlxsw_sp_fw_rev_ge(rev, &mlxsw_sp_supported_fw_rev)) + return 0; + + dev_info(mlxsw_sp->bus_info->dev, "The firmware version %d.%d.%d out of data\n", + rev->major, rev->minor, rev->subminor); + dev_info(mlxsw_sp->bus_info->dev, "Upgrading firmware using file %s\n", + MLXSW_SP_FW_FILENAME); + + err = request_firmware_direct(&firmware, MLXSW_SP_FW_FILENAME, + mlxsw_sp->bus_info->dev); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Could not request firmware file %s\n", + MLXSW_SP_FW_FILENAME); + return err; + } + + err = mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware); + release_firmware(firmware); + return err; +} + int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, unsigned int counter_index, u64 *packets, u64 *bytes) @@ -3559,6 +3619,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, INIT_LIST_HEAD(&mlxsw_sp->fids); INIT_LIST_HEAD(&mlxsw_sp->vfids.list); + err = mlxsw_sp_fw_rev_validate(mlxsw_sp); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Could not upgrade firmware\n"); + return err; + } + err = mlxsw_sp_base_mac_get(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to get base mac\n"); @@ -4930,3 +4996,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Jiri Pirko "); MODULE_DESCRIPTION("Mellanox Spectrum driver"); MODULE_DEVICE_TABLE(pci, mlxsw_sp_pci_id_table); +MODULE_FIRMWARE(MLXSW_SP_FW_FILENAME); -- cgit v1.2.3 From 03ea01e9db82203e83b306b6c61d2cc9f0da4199 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 23 May 2017 21:56:30 +0200 Subject: mlxsw: spectrum_router: Adjust RIF configuration for new firmware versions In new firmware versions, when configuring a {Port, VID} as a router interface, the driver is responsible for enabling the STP filter and disabling learning. Otherwise, packets are discarded. This change doesn't break existing firmware versions, but is required for newer firmware versions. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 3cc7d52fd6ce..8165b1148bce 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -3109,7 +3110,9 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, struct net_device *l3_dev) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; + u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); struct mlxsw_sp_rif *rif; + int err; rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); if (!rif) { @@ -3118,20 +3121,39 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, return PTR_ERR(rif); } + err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, false); + if (err) + goto err_port_vid_learning_set; + + err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, + BR_STATE_FORWARDING); + if (err) + goto err_port_vid_stp_set; + mlxsw_sp_vport_fid_set(mlxsw_sp_vport, rif->f); rif->f->ref_count++; netdev_dbg(mlxsw_sp_vport->dev, "Joined FID=%d\n", rif->f->fid); return 0; + +err_port_vid_stp_set: + mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); +err_port_vid_learning_set: + if (rif->f->ref_count == 0) + mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, rif); + return err; } static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport) { struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); + u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); + mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, BR_STATE_BLOCKING); + mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); if (--f->ref_count == 0) mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, f->rif); -- cgit v1.2.3 From 346cfe8482bf491f6e3e88ea89bc0d6be2b02efd Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 26 May 2017 01:03:31 -0700 Subject: nfp: move mutex init out of net code Move mutex init to main file close to structure allocation. This will allow mutex to be taken before net code runs (e.g. from devlink callbacks). While at it remember to destroy the mutex. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 4 ++++ drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index bb586ce1ea06..3a131559153a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -342,6 +343,7 @@ static int nfp_pci_probe(struct pci_dev *pdev, } INIT_LIST_HEAD(&pf->vnics); INIT_LIST_HEAD(&pf->ports); + mutex_init(&pf->lock); pci_set_drvdata(pdev, pf); pf->pdev = pdev; @@ -380,6 +382,7 @@ err_cpp_free: nfp_cpp_free(pf->cpp); err_disable_msix: pci_set_drvdata(pdev, NULL); + mutex_destroy(&pf->lock); kfree(pf); err_rel_regions: pci_release_regions(pdev); @@ -404,6 +407,7 @@ static void nfp_pci_remove(struct pci_dev *pdev) nfp_cpp_free(pf->cpp); kfree(pf->eth_tbl); + mutex_destroy(&pf->lock); kfree(pf); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index dd1118c7e1a4..5139c13b6e53 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -641,7 +641,6 @@ int nfp_net_pci_probe(struct nfp_pf *pf) int err; INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_vnics); - mutex_init(&pf->lock); /* Verify that the board has completed initialization */ if (!nfp_is_ready(pf->cpp)) { -- cgit v1.2.3 From 1851f93fd2ee3dc0f3a6813385010a5d7ec1aabd Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 26 May 2017 01:03:32 -0700 Subject: nfp: add devlink support Add initial devlink support. This patch simply switches allocation of per-adapter structure to devlink's priv and register devlink with empty ops table. See following patches for implementation of particular ops. We should now clear the app pointer on exit, this is how devlink callbacks will know app is not initialized. Signed-off-by: Simon Horman Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 1 + drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 39 +++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_main.c | 24 +++++++++++--- drivers/net/ethernet/netronome/nfp/nfp_main.h | 3 ++ drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 1 + 5 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_devlink.c (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index e8333283ada6..95f6b97b5d71 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -15,6 +15,7 @@ nfp-objs := \ nfpcore/nfp_rtsym.o \ nfpcore/nfp_target.o \ nfp_app.o \ + nfp_devlink.o \ nfp_main.o \ nfp_net_common.o \ nfp_net_ethtool.o \ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c new file mode 100644 index 000000000000..a8a52b3ff42b --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "nfp_main.h" + +const struct devlink_ops nfp_devlink_ops = { +}; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 3a131559153a..f22f56c9218f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "nfpcore/nfp.h" #include "nfpcore/nfp_cpp.h" @@ -316,6 +317,7 @@ static void nfp_fw_unload(struct nfp_pf *pf) static int nfp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { + struct devlink *devlink; struct nfp_pf *pf; int err; @@ -336,11 +338,12 @@ static int nfp_pci_probe(struct pci_dev *pdev, goto err_pci_disable; } - pf = kzalloc(sizeof(*pf), GFP_KERNEL); - if (!pf) { + devlink = devlink_alloc(&nfp_devlink_ops, sizeof(*pf)); + if (!devlink) { err = -ENOMEM; goto err_rel_regions; } + pf = devlink_priv(devlink); INIT_LIST_HEAD(&pf->vnics); INIT_LIST_HEAD(&pf->ports); mutex_init(&pf->lock); @@ -362,10 +365,14 @@ static int nfp_pci_probe(struct pci_dev *pdev, nfp_hwinfo_lookup(pf->cpp, "assembly.revision"), nfp_hwinfo_lookup(pf->cpp, "cpld.version")); - err = nfp_nsp_init(pdev, pf); + err = devlink_register(devlink, &pdev->dev); if (err) goto err_cpp_free; + err = nfp_nsp_init(pdev, pf); + if (err) + goto err_devlink_unreg; + nfp_pcie_sriov_read_nfd_limit(pf); err = nfp_net_pci_probe(pf); @@ -378,12 +385,14 @@ err_fw_unload: if (pf->fw_loaded) nfp_fw_unload(pf); kfree(pf->eth_tbl); +err_devlink_unreg: + devlink_unregister(devlink); err_cpp_free: nfp_cpp_free(pf->cpp); err_disable_msix: pci_set_drvdata(pdev, NULL); mutex_destroy(&pf->lock); - kfree(pf); + devlink_free(devlink); err_rel_regions: pci_release_regions(pdev); err_pci_disable: @@ -395,11 +404,16 @@ err_pci_disable: static void nfp_pci_remove(struct pci_dev *pdev) { struct nfp_pf *pf = pci_get_drvdata(pdev); + struct devlink *devlink; + + devlink = priv_to_devlink(pf); nfp_net_pci_remove(pf); nfp_pcie_sriov_disable(pdev); + devlink_unregister(devlink); + if (pf->fw_loaded) nfp_fw_unload(pf); @@ -408,7 +422,7 @@ static void nfp_pci_remove(struct pci_dev *pdev) kfree(pf->eth_tbl); mutex_destroy(&pf->lock); - kfree(pf); + devlink_free(devlink); pci_release_regions(pdev); pci_disable_device(pdev); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 991c4cba0bbf..526db8029dea 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -47,6 +47,7 @@ #include struct dentry; +struct devlink_ops; struct pci_dev; struct nfp_cpp; @@ -107,6 +108,8 @@ struct nfp_pf { extern struct pci_driver nfp_netvf_pci_driver; +extern const struct devlink_ops nfp_devlink_ops; + int nfp_net_pci_probe(struct nfp_pf *pf); void nfp_net_pci_remove(struct nfp_pf *pf); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 5139c13b6e53..8f5a240c8d2f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -502,6 +502,7 @@ static int nfp_net_pf_app_init(struct nfp_pf *pf) static void nfp_net_pf_app_clean(struct nfp_pf *pf) { nfp_app_free(pf->app); + pf->app = NULL; } static void nfp_net_pci_remove_finish(struct nfp_pf *pf) -- cgit v1.2.3 From 71f8a116b5c4b4957c56a2f1a5bd2a7e19d6d400 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 26 May 2017 01:03:33 -0700 Subject: nfp: add helper for cleaning up vNICs We will soon have to invoke more clean up for vNICs. Move the cleanup callbacks into a helper. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 8f5a240c8d2f..b0a6ec4fe097 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -418,6 +418,12 @@ err_free_prev: return err; } +static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn) +{ + nfp_net_debugfs_dir_clean(&nn->debugfs_dir); + nfp_net_clean(nn); +} + static int nfp_net_pf_spawn_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, void __iomem *tx_bar, @@ -480,10 +486,8 @@ nfp_net_pf_spawn_vnics(struct nfp_pf *pf, return 0; err_prev_deinit: - list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list) { - nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_clean(nn); - } + list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list) + nfp_net_pf_clean_vnic(pf, nn); nfp_net_irqs_disable(pf->pdev); err_vec_free: kfree(pf->irq_entries); @@ -585,9 +589,7 @@ static void nfp_net_refresh_vnics(struct work_struct *work) if (!nn->port || nn->port->type != NFP_PORT_INVALID) continue; - nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - nfp_net_clean(nn); - + nfp_net_pf_clean_vnic(pf, nn); nfp_net_pf_free_vnic(pf, nn); } @@ -760,11 +762,8 @@ void nfp_net_pci_remove(struct nfp_pf *pf) if (list_empty(&pf->vnics)) goto out; - list_for_each_entry(nn, &pf->vnics, vnic_list) { - nfp_net_debugfs_dir_clean(&nn->debugfs_dir); - - nfp_net_clean(nn); - } + list_for_each_entry(nn, &pf->vnics, vnic_list) + nfp_net_pf_clean_vnic(pf, nn); nfp_net_pf_free_vnics(pf); -- cgit v1.2.3 From 53e7a08f0da16eb67daf616405b0579e98565cdc Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 26 May 2017 01:03:34 -0700 Subject: nfp: register ports as devlink ports Extend nfp_port to contain devlink_port structures. Register the ports to allow users inspecting device ports. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 45 +++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 13 +++++++ drivers/net/ethernet/netronome/nfp/nfp_port.h | 8 ++++ 3 files changed, 66 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index a8a52b3ff42b..2cfcb66b04bb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -31,9 +31,54 @@ * SOFTWARE. */ +#include #include +#include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" #include "nfp_main.h" +#include "nfp_port.h" + +static int +nfp_devlink_fill_eth_port(struct nfp_port *port, + struct nfp_eth_table_port *copy) +{ + struct nfp_eth_table_port *eth_port; + + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) + return -EINVAL; + + memcpy(copy, eth_port, sizeof(*eth_port)); + + return 0; +} const struct devlink_ops nfp_devlink_ops = { }; + +int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port) +{ + struct nfp_eth_table_port eth_port; + struct devlink *devlink; + int ret; + + rtnl_lock(); + ret = nfp_devlink_fill_eth_port(port, ð_port); + rtnl_unlock(); + if (ret) + return ret; + + devlink_port_type_eth_set(&port->dl_port, port->netdev); + if (eth_port.is_split) + devlink_port_split_set(&port->dl_port, eth_port.label_port); + + devlink = priv_to_devlink(app->pf); + + return devlink_port_register(devlink, &port->dl_port, port->eth_id); +} + +void nfp_devlink_port_unregister(struct nfp_port *port) +{ + devlink_port_unregister(&port->dl_port); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index b0a6ec4fe097..b733c97677fb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -354,9 +354,20 @@ nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id) nfp_net_debugfs_vnic_add(nn, pf->ddir, id); + if (nn->port) { + err = nfp_devlink_port_register(pf->app, nn->port); + if (err) + goto err_dfs_clean; + } + nfp_net_info(nn); return 0; + +err_dfs_clean: + nfp_net_debugfs_dir_clean(&nn->debugfs_dir); + nfp_net_clean(nn); + return err; } static int @@ -420,6 +431,8 @@ err_free_prev: static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn) { + if (nn->port) + nfp_devlink_port_unregister(nn->port); nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_clean(nn); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 641617de41cc..36a540b514be 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -34,6 +34,8 @@ #ifndef _NFP_PORT_H_ #define _NFP_PORT_H_ +#include + struct net_device; struct nfp_app; struct nfp_port; @@ -66,6 +68,7 @@ enum nfp_port_flags { * @type: what port type does the entity represent * @flags: port flags * @app: backpointer to the app structure + * @dl_port: devlink port structure * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme * @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry * @port_list: entry on pf's list of ports @@ -78,6 +81,8 @@ struct nfp_port { struct nfp_app *app; + struct devlink_port dl_port; + unsigned int eth_id; struct nfp_eth_table_port *eth_port; @@ -99,4 +104,7 @@ void nfp_port_free(struct nfp_port *port); int nfp_net_refresh_eth_port(struct nfp_port *port); void nfp_net_refresh_port_table(struct nfp_port *port); +int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port); +void nfp_devlink_port_unregister(struct nfp_port *port); + #endif -- cgit v1.2.3 From f0b81195381f0fd9ec84009a0e5a4bb12ccc9637 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 26 May 2017 01:03:35 -0700 Subject: nfp: calculate total port lanes for split For port splitting we will need to know the total number of lanes in a port. Calculate that based on eth_table information. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 3 +++ drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index 36b21e4dc56d..84a1d20adae1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -96,6 +96,7 @@ enum nfp_eth_aneg { * @override_changed: is media reconfig pending? * * @port_type: one of %PORT_* defines for ethtool + * @port_lanes: total number of lanes on the port (sum of lanes of all subports) * @is_split: is interface part of a split port */ struct nfp_eth_table { @@ -127,6 +128,8 @@ struct nfp_eth_table { /* Computed fields */ u8 port_type; + unsigned int port_lanes; + bool is_split; } ports[0]; }; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c index 639438d8313a..b0f8785c064f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c @@ -186,17 +186,19 @@ nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src, } static void -nfp_eth_mark_split_ports(struct nfp_cpp *cpp, struct nfp_eth_table *table) +nfp_eth_calc_port_geometry(struct nfp_cpp *cpp, struct nfp_eth_table *table) { unsigned int i, j; for (i = 0; i < table->count; i++) for (j = 0; j < table->count; j++) { - if (i == j) - continue; if (table->ports[i].label_port != table->ports[j].label_port) continue; + table->ports[i].port_lanes += table->ports[j].lanes; + + if (i == j) + continue; if (table->ports[i].label_subport == table->ports[j].label_subport) nfp_warn(cpp, @@ -205,7 +207,6 @@ nfp_eth_mark_split_ports(struct nfp_cpp *cpp, struct nfp_eth_table *table) table->ports[i].label_subport); table->ports[i].is_split = true; - break; } } @@ -289,7 +290,7 @@ __nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp) nfp_eth_port_translate(nsp, &entries[i], i, &table->ports[j++]); - nfp_eth_mark_split_ports(cpp, table); + nfp_eth_calc_port_geometry(cpp, table); for (i = 0; i < table->count; i++) nfp_eth_calc_port_type(cpp, &table->ports[i]); -- cgit v1.2.3 From ec8b1fbe682deb376062c5ed04ef9c78160ffbf0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 26 May 2017 01:03:36 -0700 Subject: nfp: support port splitting via devlink Add support for configuring port split with devlink. Add devlink callbacks to validate requested config and call NSP helpers. Getting the right nfp_port structure can be done with simple iteration. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 97 +++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 23 ++++-- drivers/net/ethernet/netronome/nfp/nfp_port.c | 19 +++++ drivers/net/ethernet/netronome/nfp/nfp_port.h | 4 + 4 files changed, 136 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index 2cfcb66b04bb..2609a0f28e81 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -54,7 +54,104 @@ nfp_devlink_fill_eth_port(struct nfp_port *port, return 0; } +static int +nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf, unsigned int port_index, + struct nfp_eth_table_port *copy) +{ + struct nfp_port *port; + + port = nfp_port_from_id(pf, NFP_PORT_PHYS_PORT, port_index); + + return nfp_devlink_fill_eth_port(port, copy); +} + +static int +nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes) +{ + struct nfp_nsp *nsp; + int ret; + + nsp = nfp_eth_config_start(pf->cpp, idx); + if (IS_ERR(nsp)) + return PTR_ERR(nsp); + + ret = __nfp_eth_set_split(nsp, lanes); + if (ret) { + nfp_eth_config_cleanup_end(nsp); + return ret; + } + + ret = nfp_eth_config_commit_end(nsp); + if (ret < 0) + return ret; + if (ret) /* no change */ + return 0; + + return nfp_net_refresh_port_table_sync(pf); +} + +static int +nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index, + unsigned int count) +{ + struct nfp_pf *pf = devlink_priv(devlink); + struct nfp_eth_table_port eth_port; + int ret; + + if (count < 2) + return -EINVAL; + + mutex_lock(&pf->lock); + + rtnl_lock(); + ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port); + rtnl_unlock(); + if (ret) + goto out; + + if (eth_port.is_split || eth_port.port_lanes % count) { + ret = -EINVAL; + goto out; + } + + ret = nfp_devlink_set_lanes(pf, eth_port.index, + eth_port.port_lanes / count); +out: + mutex_unlock(&pf->lock); + + return ret; +} + +static int +nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index) +{ + struct nfp_pf *pf = devlink_priv(devlink); + struct nfp_eth_table_port eth_port; + int ret; + + mutex_lock(&pf->lock); + + rtnl_lock(); + ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, ð_port); + rtnl_unlock(); + if (ret) + goto out; + + if (!eth_port.is_split) { + ret = -EINVAL; + goto out; + } + + ret = nfp_devlink_set_lanes(pf, eth_port.index, eth_port.port_lanes); +out: + mutex_unlock(&pf->lock); + + return ret; +} + const struct devlink_ops nfp_devlink_ops = { + .port_split = nfp_devlink_port_split, + .port_unsplit = nfp_devlink_port_unsplit, }; int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index b733c97677fb..388759e047d8 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -561,19 +562,17 @@ nfp_net_eth_port_update(struct nfp_cpp *cpp, struct nfp_port *port, return 0; } -static void nfp_net_refresh_vnics(struct work_struct *work) +int nfp_net_refresh_port_table_sync(struct nfp_pf *pf) { - struct nfp_pf *pf = container_of(work, struct nfp_pf, - port_refresh_work); struct nfp_eth_table *eth_table; struct nfp_net *nn, *next; struct nfp_port *port; - mutex_lock(&pf->lock); + lockdep_assert_held(&pf->lock); /* Check for nfp_net_pci_remove() racing against us */ if (list_empty(&pf->vnics)) - goto out; + return 0; /* Update state of all ports */ rtnl_lock(); @@ -587,7 +586,7 @@ static void nfp_net_refresh_vnics(struct work_struct *work) set_bit(NFP_PORT_CHANGED, &port->flags); rtnl_unlock(); nfp_err(pf->cpp, "Error refreshing port config!\n"); - goto out; + return -EIO; } list_for_each_entry(port, &pf->ports, port_list) @@ -608,7 +607,17 @@ static void nfp_net_refresh_vnics(struct work_struct *work) if (list_empty(&pf->vnics)) nfp_net_pci_remove_finish(pf); -out: + + return 0; +} + +static void nfp_net_refresh_vnics(struct work_struct *work) +{ + struct nfp_pf *pf = container_of(work, struct nfp_pf, + port_refresh_work); + + mutex_lock(&pf->lock); + nfp_net_refresh_port_table_sync(pf); mutex_unlock(&pf->lock); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 3beed4167e2f..a17410ac01ab 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -31,6 +31,8 @@ * SOFTWARE. */ +#include + #include "nfpcore/nfp_nsp.h" #include "nfp_app.h" #include "nfp_main.h" @@ -48,6 +50,23 @@ struct nfp_port *nfp_port_from_netdev(struct net_device *netdev) return nn->port; } +struct nfp_port * +nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id) +{ + struct nfp_port *port; + + lockdep_assert_held(&pf->lock); + + if (type != NFP_PORT_PHYS_PORT) + return NULL; + + list_for_each_entry(port, &pf->ports, port_list) + if (port->eth_id == id) + return port; + + return NULL; +} + struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port) { if (!port) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 36a540b514be..4d1a9b3fed41 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -38,6 +38,7 @@ struct net_device; struct nfp_app; +struct nfp_pf; struct nfp_port; /** @@ -90,6 +91,8 @@ struct nfp_port { }; struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); +struct nfp_port * +nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id); struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port); struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port); @@ -103,6 +106,7 @@ void nfp_port_free(struct nfp_port *port); int nfp_net_refresh_eth_port(struct nfp_port *port); void nfp_net_refresh_port_table(struct nfp_port *port); +int nfp_net_refresh_port_table_sync(struct nfp_pf *pf); int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port); void nfp_devlink_port_unregister(struct nfp_port *port); -- cgit v1.2.3 From 5568363f0cb358305b90ab3d3330f757943f6d0d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 25 May 2017 09:21:41 -0700 Subject: net: phy: Create sysfs reciprocal links for attached_dev/phydev There is currently no way for a program scanning /sys to know whether a network device is attached to a particular PHY device, just like the PHY device is not pointed back to its attached network device. Create a symbolic link in the network device's namespace named "phydev" which points to the PHY device and create a symbolic link in the PHY device's namespace named "attached_dev" that points back to the network device. These links are set up during phy_attach_direct() and removed during phy_detach() for symetry. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 0780e9f9e167..f84414b8f2ee 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -960,6 +960,15 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev->attached_dev = dev; dev->phydev = phydev; + err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj, + "attached_dev"); + if (err) + goto error; + + err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj, + "phydev"); + if (err) + goto error; phydev->dev_flags = flags; @@ -1050,6 +1059,8 @@ void phy_detach(struct phy_device *phydev) struct mii_bus *bus; int i; + sysfs_remove_link(&dev->dev.kobj, "phydev"); + sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev"); phydev->attached_dev->phydev = NULL; phydev->attached_dev = NULL; phy_suspend(phydev); -- cgit v1.2.3 From d5c7d9b934dc07261e97088681e3753b3f5eba80 Mon Sep 17 00:00:00 2001 From: Prasad Kanneganti Date: Thu, 25 May 2017 10:42:14 -0700 Subject: liquidio: fix rare pci_driver.probe failure of VF driver There's a rare pci_driver.probe failure of the VF driver that's caused by PF/VF handshake going out of sync. The culprit is octeon_mbox_write() who ignores an ack timeout condition; it just keeps unconditionally writing all elements of mbox_cmd->data[] even when the other side is not ready for them. Fix it by making each write of mbox_cmd->data[i] conditional to having previously received an ack. Also fix the octeon_mbox_state enum such that each state gets a unique value. Also add ULL suffix to numeric literals in macro definitions. Signed-off-by: Prasad Kanneganti Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c | 5 ++++- drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c index 5cca73b8880b..57af7df74ced 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c @@ -178,7 +178,10 @@ int octeon_mbox_write(struct octeon_device *oct, break; } } - writeq(mbox_cmd->data[i], mbox->mbox_write_reg); + if (ret == OCTEON_MBOX_STATUS_SUCCESS) + writeq(mbox_cmd->data[i], mbox->mbox_write_reg); + else + break; } } diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h index c9376fe075bc..1def22afeff1 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h @@ -20,16 +20,16 @@ /* Macros for Mail Box Communication */ -#define OCTEON_MBOX_DATA_MAX 32 +#define OCTEON_MBOX_DATA_MAX 32 #define OCTEON_VF_ACTIVE 0x1 #define OCTEON_VF_FLR_REQUEST 0x2 #define OCTEON_PF_CHANGED_VF_MACADDR 0x4 /*Macro for Read acknowldgement*/ -#define OCTEON_PFVFACK 0xffffffffffffffff -#define OCTEON_PFVFSIG 0x1122334455667788 -#define OCTEON_PFVFERR 0xDEADDEADDEADDEAD +#define OCTEON_PFVFACK 0xffffffffffffffffULL +#define OCTEON_PFVFSIG 0x1122334455667788ULL +#define OCTEON_PFVFERR 0xDEADDEADDEADDEADULL #define LIO_MBOX_WRITE_WAIT_CNT 1000 #define LIO_MBOX_WRITE_WAIT_TIME msecs_to_jiffies(1) @@ -74,8 +74,8 @@ enum octeon_mbox_state { OCTEON_MBOX_STATE_REQUEST_RECEIVED = 4, OCTEON_MBOX_STATE_RESPONSE_PENDING = 8, OCTEON_MBOX_STATE_RESPONSE_RECEIVING = 16, - OCTEON_MBOX_STATE_RESPONSE_RECEIVED = 16, - OCTEON_MBOX_STATE_ERROR = 32 + OCTEON_MBOX_STATE_RESPONSE_RECEIVED = 32, + OCTEON_MBOX_STATE_ERROR = 64 }; struct octeon_mbox { -- cgit v1.2.3 From a55667e6f258408f1e7ddcf645d76d67a5ab3d92 Mon Sep 17 00:00:00 2001 From: Prasad Kanneganti Date: Thu, 25 May 2017 10:54:29 -0700 Subject: liquidio: fix inaccurate count of napi-processed rx packets reported to Octeon lio_enable_irq (called by napi poll) is reporting to Octeon an inaccurate count of processed rx packets causing Octeon to eventually stop forwarding packets to the host. Fix it by using this formula for an accurate count: processed rx packets = droq->pkt_count - droq->pkts_pending Also increase SOFT_COMMAND_BUFFER_SIZE to match what the firmware expects. Signed-off-by: Prasad Kanneganti Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/octeon_device.c | 6 ++++-- drivers/net/ethernet/cavium/liquidio/octeon_iq.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index b5be7074f3de..3b7cc9320deb 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -1429,13 +1429,15 @@ int lio_get_device_id(void *dev) void lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq) { u64 instr_cnt; + u32 pkts_pend; struct octeon_device *oct = NULL; /* the whole thing needs to be atomic, ideally */ if (droq) { + pkts_pend = (u32)atomic_read(&droq->pkts_pending); spin_lock_bh(&droq->lock); - writel(droq->pkt_count, droq->pkts_sent_reg); - droq->pkt_count = 0; + writel(droq->pkt_count - pkts_pend, droq->pkts_sent_reg); + droq->pkt_count = pkts_pend; /* this write needs to be flushed before we release the lock */ mmiowb(); spin_unlock_bh(&droq->lock); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h index 5063a12613e5..5c3c8da976f7 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_iq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_iq.h @@ -251,7 +251,7 @@ union octeon_instr_64B { /** The size of each buffer in soft command buffer pool */ -#define SOFT_COMMAND_BUFFER_SIZE 1536 +#define SOFT_COMMAND_BUFFER_SIZE 2048 struct octeon_soft_command { /** Soft command buffer info. */ -- cgit v1.2.3 From 3ea17bc7bc023e9fb8b2a4ef255faa0ef5c0ae5e Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 25 May 2017 21:42:05 +0200 Subject: net: phy: marvell: #defines for copper and fibre pages Replace magic numbers for PHY pages with symbolic names. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 88cd97b44ba6..bb067026353a 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -650,7 +650,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) mdelay(500); - err = marvell_set_page(phydev, 0); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) return err; @@ -662,7 +662,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) if (err < 0) return err; - err = marvell_set_page(phydev, 2); + err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC); @@ -671,7 +671,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp); if (err < 0) return err; - err = marvell_set_page(phydev, 0); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) return err; @@ -892,7 +892,7 @@ static int m88e1510_config_init(struct phy_device *phydev) return err; /* Reset page selection */ - err = marvell_set_page(phydev, 0); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) return err; } @@ -922,7 +922,7 @@ static int m88e1118_config_init(struct phy_device *phydev) int err; /* Change address */ - err = marvell_set_page(phydev, 2); + err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; @@ -932,7 +932,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Change address */ - err = marvell_set_page(phydev, 3); + err = marvell_set_page(phydev, MII_88E1318S_PHY_LED_PAGE); if (err < 0) return err; @@ -949,7 +949,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = marvell_set_page(phydev, 0); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) return err; @@ -961,7 +961,7 @@ static int m88e1149_config_init(struct phy_device *phydev) int err; /* Change address */ - err = marvell_set_page(phydev, 2); + err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; @@ -975,7 +975,7 @@ static int m88e1149_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = marvell_set_page(phydev, 0); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) return err; @@ -1409,7 +1409,7 @@ static void m88e1318_get_wol(struct phy_device *phydev, MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) wol->wolopts |= WAKE_MAGIC; - if (marvell_set_page(phydev, 0x00) < 0) + if (marvell_set_page(phydev, MII_M1111_COPPER) < 0) return; } @@ -1422,7 +1422,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, if (wol->wolopts & WAKE_MAGIC) { /* Explicitly switch to page 0x00, just to be sure */ - err = marvell_set_page(phydev, 0x00); + err = marvell_set_page(phydev, MII_M1111_COPPER); if (err < 0) return err; -- cgit v1.2.3 From 975b388c912e62288c78bffdf4b2bf5fa21ee725 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 25 May 2017 21:42:06 +0200 Subject: net: phy: marvell: More hidden page changes refactored EXT_ADDR_PAGE is the same meaning as MII_MARVELL_PHY_PAGE, i.e. change page. Replace it will calls to the helpers. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 62 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index bb067026353a..3c577a177b2c 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -54,7 +54,6 @@ #define MII_M1011_PHY_SCR_MDI_X 0x0020 #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 -#define MII_M1145_PHY_EXT_ADDR_PAGE 0x16 #define MII_M1145_PHY_EXT_SR 0x1b #define MII_M1145_PHY_EXT_CR 0x14 #define MII_M1145_RGMII_RX_DELAY 0x0080 @@ -92,6 +91,7 @@ #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) #define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4)) +#define MII_88E1121_MISC_TEST_PAGE 6 #define MII_88E1121_MISC_TEST 0x1a #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00 #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8 @@ -760,11 +760,7 @@ static int m88e1111_config_init_sgmii(struct phy_device *phydev) return err; /* make sure copper is selected */ - err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE); - if (err < 0) - return err; - - return phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, err & (~0xff)); + return marvell_set_page(phydev, MII_M1111_COPPER); } static int m88e1111_config_init_rtbi(struct phy_device *phydev) @@ -1554,6 +1550,7 @@ static void marvell_get_stats(struct phy_device *phydev, #ifdef CONFIG_HWMON static int m88e1121_get_temp(struct phy_device *phydev, long *temp) { + int oldpage; int ret; int val; @@ -1561,7 +1558,13 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp) mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); + oldpage = marvell_get_page(phydev); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } + + ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (ret < 0) goto error; @@ -1593,7 +1596,7 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp) *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; @@ -1670,13 +1673,20 @@ static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { static int m88e1510_get_temp(struct phy_device *phydev, long *temp) { + int oldpage; int ret; *temp = 0; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); + oldpage = marvell_get_page(phydev); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } + + ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (ret < 0) goto error; @@ -1687,7 +1697,7 @@ static int m88e1510_get_temp(struct phy_device *phydev, long *temp) *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; @@ -1695,13 +1705,19 @@ error: int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) { + int oldpage; int ret; *temp = 0; mutex_lock(&phydev->lock); + oldpage = marvell_get_page(phydev); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); + ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (ret < 0) goto error; @@ -1715,7 +1731,7 @@ int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) *temp *= 1000; error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; @@ -1723,11 +1739,18 @@ error: int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) { + int oldpage; int ret; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); + oldpage = marvell_get_page(phydev); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } + + ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (ret < 0) goto error; @@ -1742,7 +1765,7 @@ int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) (temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT)); error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; @@ -1750,13 +1773,20 @@ error: int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) { + int oldpage; int ret; *alarm = false; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); + oldpage = marvell_get_page(phydev); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } + + ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (ret < 0) goto error; @@ -1766,7 +1796,7 @@ int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; -- cgit v1.2.3 From 53798328ce682c038a7cc3960f6f63531e6a26db Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 25 May 2017 21:42:07 +0200 Subject: net: phy: marvell: helper to get and set page There is a common pattern of first reading the currently selected page and then changing to another page. Add a helper to do this. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 75 ++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 3c577a177b2c..ed338af61cdd 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -199,6 +199,19 @@ static int marvell_set_page(struct phy_device *phydev, int page) return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); } +static int marvell_get_set_page(struct phy_device *phydev, int page) +{ + int oldpage = marvell_get_page(phydev); + + if (oldpage < 0) + return oldpage; + + if (page != oldpage) + return marvell_set_page(phydev, page); + + return 0; +} + static int marvell_ack_interrupt(struct phy_device *phydev) { int err; @@ -452,11 +465,9 @@ static int m88e1121_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = marvell_get_page(phydev); - - err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); - if (err < 0) - return err; + oldpage = marvell_get_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); + if (oldpage < 0) + return oldpage; if (phy_interface_is_rgmii(phydev)) { mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & @@ -493,11 +504,9 @@ static int m88e1318_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = marvell_get_page(phydev); - - err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); - if (err < 0) - return err; + oldpage = marvell_get_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); + if (oldpage < 0) + return oldpage; mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG); mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD; @@ -843,11 +852,9 @@ static int m88e1121_config_init(struct phy_device *phydev) { int err, oldpage; - oldpage = marvell_get_page(phydev); - - err = marvell_set_page(phydev, MII_88E1121_PHY_LED_PAGE); - if (err < 0) - return err; + oldpage = marvell_get_set_page(phydev, MII_88E1121_PHY_LED_PAGE); + if (oldpage < 0) + return oldpage; /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL, @@ -1516,12 +1523,11 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) { struct marvell_hw_stat stat = marvell_hw_stats[i]; struct marvell_priv *priv = phydev->priv; - int err, oldpage, val; + int oldpage, val; u64 ret; - oldpage = marvell_get_page(phydev); - err = marvell_set_page(phydev, stat.page); - if (err < 0) + oldpage = marvell_get_set_page(phydev, stat.page); + if (oldpage < 0) return UINT64_MAX; val = phy_read(phydev, stat.reg); @@ -1558,16 +1564,12 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp) mutex_lock(&phydev->lock); - oldpage = marvell_get_page(phydev); + oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; } - ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); - if (ret < 0) - goto error; - /* Enable temperature sensor */ ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) @@ -1680,16 +1682,12 @@ static int m88e1510_get_temp(struct phy_device *phydev, long *temp) mutex_lock(&phydev->lock); - oldpage = marvell_get_page(phydev); + oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; } - ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); - if (ret < 0) - goto error; - ret = phy_read(phydev, MII_88E1510_TEMP_SENSOR); if (ret < 0) goto error; @@ -1711,16 +1709,13 @@ int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) *temp = 0; mutex_lock(&phydev->lock); - oldpage = marvell_get_page(phydev); + + oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; } - ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); - if (ret < 0) - goto error; - ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) goto error; @@ -1744,16 +1739,12 @@ int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) mutex_lock(&phydev->lock); - oldpage = marvell_get_page(phydev); + oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; } - ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); - if (ret < 0) - goto error; - ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) goto error; @@ -1780,16 +1771,12 @@ int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) mutex_lock(&phydev->lock); - oldpage = marvell_get_page(phydev); + oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; } - ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); - if (ret < 0) - goto error; - ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) goto error; -- cgit v1.2.3 From 52295666edbaeee71d7089976c751ba59b354449 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 25 May 2017 21:42:08 +0200 Subject: net: phy: marvell: Uniform page names Bring all the page names together, remove the repeats, and make them uniform. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 94 +++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index ed338af61cdd..2bd83920f565 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -41,6 +41,12 @@ #include #define MII_MARVELL_PHY_PAGE 22 +#define MII_MARVELL_COPPER_PAGE 0x00 +#define MII_MARVELL_FIBER_PAGE 0x01 +#define MII_MARVELL_MSCR_PAGE 0x02 +#define MII_MARVELL_LED_PAGE 0x03 +#define MII_MARVELL_MISC_TEST_PAGE 0x06 +#define MII_MARVELL_WOL_PAGE 0x11 #define MII_M1011_IEVENT 0x13 #define MII_M1011_IEVENT_CLEAR 0x0000 @@ -82,16 +88,11 @@ #define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000 #define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000 -#define MII_M1111_COPPER 0 -#define MII_M1111_FIBER 1 - -#define MII_88E1121_PHY_MSCR_PAGE 2 #define MII_88E1121_PHY_MSCR_REG 21 #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) #define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4)) -#define MII_88E1121_MISC_TEST_PAGE 6 #define MII_88E1121_MISC_TEST 0x1a #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00 #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8 @@ -112,7 +113,6 @@ #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) /* LED Timer Control Register */ -#define MII_88E1318S_PHY_LED_PAGE 0x03 #define MII_88E1318S_PHY_LED_TCR 0x12 #define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) @@ -123,13 +123,11 @@ #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 -#define MII_88E1318S_PHY_WOL_PAGE 0x11 #define MII_88E1318S_PHY_WOL_CTRL 0x10 #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) #define MII_88E1121_PHY_LED_CTRL 16 -#define MII_88E1121_PHY_LED_PAGE 3 #define MII_88E1121_PHY_LED_DEF 0x0030 #define MII_M1011_PHY_STATUS 0x11 @@ -465,7 +463,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = marvell_get_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (oldpage < 0) return oldpage; @@ -504,7 +502,7 @@ static int m88e1318_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = marvell_get_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (oldpage < 0) return oldpage; @@ -615,7 +613,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev) { int err; - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; @@ -625,7 +623,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev) goto error; /* Then the fiber link */ - err = marvell_set_page(phydev, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -633,10 +631,10 @@ static int m88e1510_config_aneg(struct phy_device *phydev) if (err < 0) goto error; - return marvell_set_page(phydev, MII_M1111_COPPER); + return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); error: - marvell_set_page(phydev, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -659,7 +657,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) mdelay(500); - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -671,7 +669,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) if (err < 0) return err; - err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (err < 0) return err; temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC); @@ -680,7 +678,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp); if (err < 0) return err; - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -769,7 +767,7 @@ static int m88e1111_config_init_sgmii(struct phy_device *phydev) return err; /* make sure copper is selected */ - return marvell_set_page(phydev, MII_M1111_COPPER); + return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); } static int m88e1111_config_init_rtbi(struct phy_device *phydev) @@ -852,7 +850,7 @@ static int m88e1121_config_init(struct phy_device *phydev) { int err, oldpage; - oldpage = marvell_get_set_page(phydev, MII_88E1121_PHY_LED_PAGE); + oldpage = marvell_get_set_page(phydev, MII_MARVELL_LED_PAGE); if (oldpage < 0) return oldpage; @@ -895,7 +893,7 @@ static int m88e1510_config_init(struct phy_device *phydev) return err; /* Reset page selection */ - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; } @@ -925,7 +923,7 @@ static int m88e1118_config_init(struct phy_device *phydev) int err; /* Change address */ - err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (err < 0) return err; @@ -935,7 +933,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Change address */ - err = marvell_set_page(phydev, MII_88E1318S_PHY_LED_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); if (err < 0) return err; @@ -952,7 +950,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -964,7 +962,7 @@ static int m88e1149_config_init(struct phy_device *phydev) int err; /* Change address */ - err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (err < 0) return err; @@ -978,7 +976,7 @@ static int m88e1149_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -1248,7 +1246,7 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) /* Detect and update the link, but return if there * was an error */ - if (page == MII_M1111_FIBER) + if (page == MII_MARVELL_FIBER_PAGE) fiber = 1; else fiber = 0; @@ -1281,11 +1279,11 @@ static int marvell_read_status(struct phy_device *phydev) /* Check the fiber mode first */ if (phydev->supported & SUPPORTED_FIBRE && phydev->interface != PHY_INTERFACE_MODE_SGMII) { - err = marvell_set_page(phydev, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; - err = marvell_read_status_page(phydev, MII_M1111_FIBER); + err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1300,15 +1298,15 @@ static int marvell_read_status(struct phy_device *phydev) return 0; /* If fiber link is down, check and save copper mode state */ - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; } - return marvell_read_status_page(phydev, MII_M1111_COPPER); + return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); error: - marvell_set_page(phydev, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -1323,7 +1321,7 @@ static int marvell_suspend(struct phy_device *phydev) /* Suspend the fiber mode first */ if (!(phydev->supported & SUPPORTED_FIBRE)) { - err = marvell_set_page(phydev, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1333,7 +1331,7 @@ static int marvell_suspend(struct phy_device *phydev) goto error; /* Then, the copper link */ - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; } @@ -1342,7 +1340,7 @@ static int marvell_suspend(struct phy_device *phydev) return genphy_suspend(phydev); error: - marvell_set_page(phydev, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -1357,7 +1355,7 @@ static int marvell_resume(struct phy_device *phydev) /* Resume the fiber mode first */ if (!(phydev->supported & SUPPORTED_FIBRE)) { - err = marvell_set_page(phydev, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1367,7 +1365,7 @@ static int marvell_resume(struct phy_device *phydev) goto error; /* Then, the copper link */ - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; } @@ -1376,7 +1374,7 @@ static int marvell_resume(struct phy_device *phydev) return genphy_resume(phydev); error: - marvell_set_page(phydev, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -1405,14 +1403,14 @@ static void m88e1318_get_wol(struct phy_device *phydev, wol->supported = WAKE_MAGIC; wol->wolopts = 0; - if (marvell_set_page(phydev, MII_88E1318S_PHY_WOL_PAGE) < 0) + if (marvell_set_page(phydev, MII_MARVELL_WOL_PAGE) < 0) return; if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) wol->wolopts |= WAKE_MAGIC; - if (marvell_set_page(phydev, MII_M1111_COPPER) < 0) + if (marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE) < 0) return; } @@ -1425,7 +1423,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, if (wol->wolopts & WAKE_MAGIC) { /* Explicitly switch to page 0x00, just to be sure */ - err = marvell_set_page(phydev, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -1436,7 +1434,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, if (err < 0) return err; - err = marvell_set_page(phydev, MII_88E1318S_PHY_LED_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); if (err < 0) return err; @@ -1449,7 +1447,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, if (err < 0) return err; - err = marvell_set_page(phydev, MII_88E1318S_PHY_WOL_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); if (err < 0) return err; @@ -1478,7 +1476,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, if (err < 0) return err; } else { - err = marvell_set_page(phydev, MII_88E1318S_PHY_WOL_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); if (err < 0) return err; @@ -1564,7 +1562,7 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp) mutex_lock(&phydev->lock); - oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; @@ -1682,7 +1680,7 @@ static int m88e1510_get_temp(struct phy_device *phydev, long *temp) mutex_lock(&phydev->lock); - oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; @@ -1710,7 +1708,7 @@ int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) mutex_lock(&phydev->lock); - oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; @@ -1739,7 +1737,7 @@ int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) mutex_lock(&phydev->lock); - oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; @@ -1771,7 +1769,7 @@ int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) mutex_lock(&phydev->lock); - oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE); + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); if (oldpage < 0) { mutex_unlock(&phydev->lock); return oldpage; -- cgit v1.2.3 From 03d1da3c050b9d0f9536ccd0965af91ab8e1df63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 25 May 2017 22:55:11 +0200 Subject: net: ethernet: ax88796: support generating a random mac address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of falling back to 00:00:00:00:00:00 generate a random address if none is provided via platform data or from the device's register space. Signed-off-by: Uwe Kleine-König Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/8390/ax88796.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index b0a3b85fc6f8..2f0ee3d7ceb1 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -723,6 +723,12 @@ static int ax_init_dev(struct net_device *dev) ax->plat->mac_addr) memcpy(dev->dev_addr, ax->plat->mac_addr, ETH_ALEN); + if (!is_valid_ether_addr(dev->dev_addr)) { + eth_hw_addr_random(dev); + dev_info(&dev->dev, "Using random MAC address: %pM\n", + dev->dev_addr); + } + ax_reset_8390(dev); ei_local->name = "AX88796"; -- cgit v1.2.3 From 10fa5bfcd69730765b496c7d91c5df0da7019489 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 26 May 2017 01:03:20 +0200 Subject: net: dsa: mv88e6xxx: Move phy functions into phy.[ch] The upcoming SERDES support will need to make use of PHY functions. Move them out into a file of there own. No code changes. Signed-off-by: Andrew Lunn Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/Makefile | 1 + drivers/net/dsa/mv88e6xxx/chip.c | 233 +------------------------------- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 2 +- drivers/net/dsa/mv88e6xxx/phy.c | 246 ++++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/phy.h | 37 +++++ 5 files changed, 287 insertions(+), 232 deletions(-) create mode 100644 drivers/net/dsa/mv88e6xxx/phy.c create mode 100644 drivers/net/dsa/mv88e6xxx/phy.h (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile index 6edd869c8d6f..e4372eaf3bc5 100644 --- a/drivers/net/dsa/mv88e6xxx/Makefile +++ b/drivers/net/dsa/mv88e6xxx/Makefile @@ -4,4 +4,5 @@ mv88e6xxx-objs += global1.o mv88e6xxx-objs += global1_atu.o mv88e6xxx-objs += global1_vtu.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o +mv88e6xxx-objs += phy.o mv88e6xxx-objs += port.o diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 41de250dbcc3..724f3b09e077 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -36,6 +36,7 @@ #include "mv88e6xxx.h" #include "global1.h" #include "global2.h" +#include "phy.h" #include "port.h" static void assert_reg_lock(struct mv88e6xxx_chip *chip) @@ -221,21 +222,7 @@ int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val) return 0; } -static int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 *val) -{ - return mv88e6xxx_read(chip, addr, reg, val); -} - -static int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 val) -{ - return mv88e6xxx_write(chip, addr, reg, val); -} - -static struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) +struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) { struct mv88e6xxx_mdio_bus *mdio_bus; @@ -247,94 +234,6 @@ static struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) return mdio_bus->bus; } -static int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, - int reg, u16 *val) -{ - int addr = phy; /* PHY devices addresses start at 0x0 */ - struct mii_bus *bus; - - bus = mv88e6xxx_default_mdio_bus(chip); - if (!bus) - return -EOPNOTSUPP; - - if (!chip->info->ops->phy_read) - return -EOPNOTSUPP; - - return chip->info->ops->phy_read(chip, bus, addr, reg, val); -} - -static int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, - int reg, u16 val) -{ - int addr = phy; /* PHY devices addresses start at 0x0 */ - struct mii_bus *bus; - - bus = mv88e6xxx_default_mdio_bus(chip); - if (!bus) - return -EOPNOTSUPP; - - if (!chip->info->ops->phy_write) - return -EOPNOTSUPP; - - return chip->info->ops->phy_write(chip, bus, addr, reg, val); -} - -static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page) -{ - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE)) - return -EOPNOTSUPP; - - return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); -} - -static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy) -{ - int err; - - /* Restore PHY page Copper 0x0 for access via the registered MDIO bus */ - err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER); - if (unlikely(err)) { - dev_err(chip->dev, "failed to restore PHY %d page Copper (%d)\n", - phy, err); - } -} - -static int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy, - u8 page, int reg, u16 *val) -{ - int err; - - /* There is no paging for registers 22 */ - if (reg == PHY_PAGE) - return -EINVAL; - - err = mv88e6xxx_phy_page_get(chip, phy, page); - if (!err) { - err = mv88e6xxx_phy_read(chip, phy, reg, val); - mv88e6xxx_phy_page_put(chip, phy); - } - - return err; -} - -static int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, - u8 page, int reg, u16 val) -{ - int err; - - /* There is no paging for registers 22 */ - if (reg == PHY_PAGE) - return -EINVAL; - - err = mv88e6xxx_phy_page_get(chip, phy, page); - if (!err) { - err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); - mv88e6xxx_phy_page_put(chip, phy); - } - - return err; -} - static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) { return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER, @@ -560,122 +459,6 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update) return mv88e6xxx_write(chip, addr, reg, val); } -static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip) -{ - if (!chip->info->ops->ppu_disable) - return 0; - - return chip->info->ops->ppu_disable(chip); -} - -static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip) -{ - if (!chip->info->ops->ppu_enable) - return 0; - - return chip->info->ops->ppu_enable(chip); -} - -static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly) -{ - struct mv88e6xxx_chip *chip; - - chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work); - - mutex_lock(&chip->reg_lock); - - if (mutex_trylock(&chip->ppu_mutex)) { - if (mv88e6xxx_ppu_enable(chip) == 0) - chip->ppu_disabled = 0; - mutex_unlock(&chip->ppu_mutex); - } - - mutex_unlock(&chip->reg_lock); -} - -static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps) -{ - struct mv88e6xxx_chip *chip = (void *)_ps; - - schedule_work(&chip->ppu_work); -} - -static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip) -{ - int ret; - - mutex_lock(&chip->ppu_mutex); - - /* If the PHY polling unit is enabled, disable it so that - * we can access the PHY registers. If it was already - * disabled, cancel the timer that is going to re-enable - * it. - */ - if (!chip->ppu_disabled) { - ret = mv88e6xxx_ppu_disable(chip); - if (ret < 0) { - mutex_unlock(&chip->ppu_mutex); - return ret; - } - chip->ppu_disabled = 1; - } else { - del_timer(&chip->ppu_timer); - ret = 0; - } - - return ret; -} - -static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip) -{ - /* Schedule a timer to re-enable the PHY polling unit. */ - mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10)); - mutex_unlock(&chip->ppu_mutex); -} - -static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip) -{ - mutex_init(&chip->ppu_mutex); - INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work); - setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer, - (unsigned long)chip); -} - -static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip) -{ - del_timer_sync(&chip->ppu_timer); -} - -static int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 *val) -{ - int err; - - err = mv88e6xxx_ppu_access_get(chip); - if (!err) { - err = mv88e6xxx_read(chip, addr, reg, val); - mv88e6xxx_ppu_access_put(chip); - } - - return err; -} - -static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 val) -{ - int err; - - err = mv88e6xxx_ppu_access_get(chip); - if (!err) { - err = mv88e6xxx_write(chip, addr, reg, val); - mv88e6xxx_ppu_access_put(chip); - } - - return err; -} - static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, int speed, int duplex, phy_interface_t mode) @@ -3914,18 +3697,6 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev) return chip; } -static void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip) -{ - if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) - mv88e6xxx_ppu_state_init(chip); -} - -static void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip) -{ - if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) - mv88e6xxx_ppu_state_destroy(chip); -} - static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int sw_addr) { diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 77236cd72df2..45b387c780a8 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -942,5 +942,5 @@ int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update); int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask); - +struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip); #endif diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c new file mode 100644 index 000000000000..0e6c72b93c8f --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -0,0 +1,246 @@ +/* + * Marvell 88e6xxx Ethernet switch PHY and PPU support + * + * Copyright (c) 2008 Marvell Semiconductor + * + * Copyright (c) 2017 Andrew Lunn + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include + +#include "mv88e6xxx.h" +#include "phy.h" + +int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val) +{ + return mv88e6xxx_read(chip, addr, reg, val); +} + +int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 val) +{ + return mv88e6xxx_write(chip, addr, reg, val); +} + +int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, int reg, u16 *val) +{ + int addr = phy; /* PHY devices addresses start at 0x0 */ + struct mii_bus *bus; + + bus = mv88e6xxx_default_mdio_bus(chip); + if (!bus) + return -EOPNOTSUPP; + + if (!chip->info->ops->phy_read) + return -EOPNOTSUPP; + + return chip->info->ops->phy_read(chip, bus, addr, reg, val); +} + +int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, int reg, u16 val) +{ + int addr = phy; /* PHY devices addresses start at 0x0 */ + struct mii_bus *bus; + + bus = mv88e6xxx_default_mdio_bus(chip); + if (!bus) + return -EOPNOTSUPP; + + if (!chip->info->ops->phy_write) + return -EOPNOTSUPP; + + return chip->info->ops->phy_write(chip, bus, addr, reg, val); +} + +static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page) +{ + if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE)) + return -EOPNOTSUPP; + + return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); +} + +static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy) +{ + int err; + + /* Restore PHY page Copper 0x0 for access via the registered + * MDIO bus + */ + err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER); + if (unlikely(err)) { + dev_err(chip->dev, + "failed to restore PHY %d page Copper (%d)\n", + phy, err); + } +} + +int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy, + u8 page, int reg, u16 *val) +{ + int err; + + /* There is no paging for registers 22 */ + if (reg == PHY_PAGE) + return -EINVAL; + + err = mv88e6xxx_phy_page_get(chip, phy, page); + if (!err) { + err = mv88e6xxx_phy_read(chip, phy, reg, val); + mv88e6xxx_phy_page_put(chip, phy); + } + + return err; +} + +int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, + u8 page, int reg, u16 val) +{ + int err; + + /* There is no paging for registers 22 */ + if (reg == PHY_PAGE) + return -EINVAL; + + err = mv88e6xxx_phy_page_get(chip, phy, page); + if (!err) { + err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); + mv88e6xxx_phy_page_put(chip, phy); + } + + return err; +} + +static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip) +{ + if (!chip->info->ops->ppu_disable) + return 0; + + return chip->info->ops->ppu_disable(chip); +} + +int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip) +{ + if (!chip->info->ops->ppu_enable) + return 0; + + return chip->info->ops->ppu_enable(chip); +} + +static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly) +{ + struct mv88e6xxx_chip *chip; + + chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work); + + mutex_lock(&chip->reg_lock); + + if (mutex_trylock(&chip->ppu_mutex)) { + if (mv88e6xxx_ppu_enable(chip) == 0) + chip->ppu_disabled = 0; + mutex_unlock(&chip->ppu_mutex); + } + + mutex_unlock(&chip->reg_lock); +} + +static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps) +{ + struct mv88e6xxx_chip *chip = (void *)_ps; + + schedule_work(&chip->ppu_work); +} + +static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip) +{ + int ret; + + mutex_lock(&chip->ppu_mutex); + + /* If the PHY polling unit is enabled, disable it so that + * we can access the PHY registers. If it was already + * disabled, cancel the timer that is going to re-enable + * it. + */ + if (!chip->ppu_disabled) { + ret = mv88e6xxx_ppu_disable(chip); + if (ret < 0) { + mutex_unlock(&chip->ppu_mutex); + return ret; + } + chip->ppu_disabled = 1; + } else { + del_timer(&chip->ppu_timer); + ret = 0; + } + + return ret; +} + +static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip) +{ + /* Schedule a timer to re-enable the PHY polling unit. */ + mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10)); + mutex_unlock(&chip->ppu_mutex); +} + +static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip) +{ + mutex_init(&chip->ppu_mutex); + INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work); + setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer, + (unsigned long)chip); +} + +static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip) +{ + del_timer_sync(&chip->ppu_timer); +} + +int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val) +{ + int err; + + err = mv88e6xxx_ppu_access_get(chip); + if (!err) { + err = mv88e6xxx_read(chip, addr, reg, val); + mv88e6xxx_ppu_access_put(chip); + } + + return err; +} + +int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 val) +{ + int err; + + err = mv88e6xxx_ppu_access_get(chip); + if (!err) { + err = mv88e6xxx_write(chip, addr, reg, val); + mv88e6xxx_ppu_access_put(chip); + } + + return err; +} + +void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip) +{ + if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) + mv88e6xxx_ppu_state_init(chip); +} + +void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip) +{ + if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) + mv88e6xxx_ppu_state_destroy(chip); +} diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h new file mode 100644 index 000000000000..0961d781b726 --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/phy.h @@ -0,0 +1,37 @@ +/* + * Marvell 88E6xxx PHY access + * + * Copyright (c) 2008 Marvell Semiconductor + * + * Copyright (c) 2017 Andrew Lunn + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _MV88E6XXX_PHY_H +#define _MV88E6XXX_PHY_H + +int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val); +int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 val); +int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, + int reg, u16 *val); +int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, + int reg, u16 val); +int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy, + u8 page, int reg, u16 *val); +int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, + u8 page, int reg, u16 val); +int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val); +int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 val); +int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip); +void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip); +void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip); + +#endif /*_MV88E6XXX_PHY_H */ -- cgit v1.2.3 From 6d91782f0f140ae515732a9543a0ae3f9f3140ce Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 26 May 2017 01:03:21 +0200 Subject: net: dsa: mv88e6xxx: Refactor mv88e6352 SERDES code into an op The mv88e6390 family has a different SERDES implementation. Refactor the mv88e6352 code into an ops function, so we can later add the mv88e6390 code. Signed-off-by: Andrew Lunn Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/Makefile | 1 + drivers/net/dsa/mv88e6xxx/chip.c | 64 +++++++++--------------------- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 6 +-- drivers/net/dsa/mv88e6xxx/serdes.c | 75 +++++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/serdes.h | 24 +++++++++++ 5 files changed, 122 insertions(+), 48 deletions(-) create mode 100644 drivers/net/dsa/mv88e6xxx/serdes.c create mode 100644 drivers/net/dsa/mv88e6xxx/serdes.h (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile index e4372eaf3bc5..5cd5551461e3 100644 --- a/drivers/net/dsa/mv88e6xxx/Makefile +++ b/drivers/net/dsa/mv88e6xxx/Makefile @@ -6,3 +6,4 @@ mv88e6xxx-objs += global1_vtu.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o mv88e6xxx-objs += phy.o mv88e6xxx-objs += port.o +mv88e6xxx-objs += serdes.o diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 724f3b09e077..bc7b345d91d3 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -38,6 +38,7 @@ #include "global2.h" #include "phy.h" #include "port.h" +#include "serdes.h" static void assert_reg_lock(struct mv88e6xxx_chip *chip) { @@ -234,18 +235,6 @@ struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip) return mdio_bus->bus; } -static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) -{ - return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER, - reg, val); -} - -static int mv88e6xxx_serdes_write(struct mv88e6xxx_chip *chip, int reg, u16 val) -{ - return mv88e6xxx_phy_page_write(chip, ADDR_SERDES, SERDES_PAGE_FIBER, - reg, val); -} - static void mv88e6xxx_g1_irq_mask(struct irq_data *d) { struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); @@ -1733,24 +1722,6 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) return mv88e6xxx_software_reset(chip); } -static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip) -{ - u16 val; - int err; - - /* Clear Power Down bit */ - err = mv88e6xxx_serdes_read(chip, MII_BMCR, &val); - if (err) - return err; - - if (val & BMCR_PDOWN) { - val &= ~BMCR_PDOWN; - err = mv88e6xxx_serdes_write(chip, MII_BMCR, val); - } - - return err; -} - static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, enum mv88e6xxx_frame_mode frame, u16 egress, u16 etype) @@ -1832,6 +1803,15 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) return 0; } +static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, + bool on) +{ + if (chip->info->ops->serdes_power) + return chip->info->ops->serdes_power(chip, port, on); + + return 0; +} + static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) { struct dsa_switch *ds = chip->ds; @@ -1882,22 +1862,12 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) if (err) return err; - /* If this port is connected to a SerDes, make sure the SerDes is not - * powered down. + /* If this port is connected to a SerDes, make sure the SerDes is + * powered up. */ - if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_SERDES)) { - err = mv88e6xxx_port_read(chip, port, PORT_STATUS, ®); - if (err) - return err; - reg &= PORT_STATUS_CMODE_MASK; - if ((reg == PORT_STATUS_CMODE_100BASE_X) || - (reg == PORT_STATUS_CMODE_1000BASE_X) || - (reg == PORT_STATUS_CMODE_SGMII)) { - err = mv88e6xxx_serdes_power_on(chip); - if (err < 0) - return err; - } - } + err = mv88e6xxx_serdes_power(chip, port, true); + if (err) + return err; /* Port Control 2: don't force a good FCS, set the maximum frame size to * 10240 bytes, disable 802.1q tags checking, don't discard tagged or @@ -2662,6 +2632,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .serdes_power = mv88e6352_serdes_power, }; static const struct mv88e6xxx_ops mv88e6175_ops = { @@ -2726,6 +2697,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .serdes_power = mv88e6352_serdes_power, }; static const struct mv88e6xxx_ops mv88e6185_ops = { @@ -2882,6 +2854,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .serdes_power = mv88e6352_serdes_power, }; static const struct mv88e6xxx_ops mv88e6290_ops = { @@ -3104,6 +3077,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, + .serdes_power = mv88e6352_serdes_power, }; static const struct mv88e6xxx_ops mv88e6390_ops = { diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 45b387c780a8..fb996491b111 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -37,9 +37,6 @@ #define PHY_PAGE 0x16 #define PHY_PAGE_COPPER 0x00 -#define ADDR_SERDES 0x0f -#define SERDES_PAGE_FIBER 0x01 - #define PORT_STATUS 0x00 #define PORT_STATUS_PAUSE_EN BIT(15) #define PORT_STATUS_MY_PAUSE BIT(14) @@ -884,6 +881,9 @@ struct mv88e6xxx_ops { /* Can be either in g1 or g2, so don't use a prefix */ int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip); + /* Power on/off a SERDES interface */ + int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on); + /* VLAN Translation Unit operations */ int (*vtu_getnext)(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry); diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c new file mode 100644 index 000000000000..235f5f0c30ae --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -0,0 +1,75 @@ +/* + * Marvell 88E6xxx SERDES manipulation, via SMI bus + * + * Copyright (c) 2008 Marvell Semiconductor + * + * Copyright (c) 2017 Andrew Lunn + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +#include "mv88e6xxx.h" +#include "phy.h" +#include "port.h" +#include "serdes.h" + +static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg, + u16 *val) +{ + return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES, + MV88E6352_SERDES_PAGE_FIBER, + reg, val); +} + +static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg, + u16 val) +{ + return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES, + MV88E6352_SERDES_PAGE_FIBER, + reg, val); +} + +static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on) +{ + u16 val, new_val; + int err; + + err = mv88e6352_serdes_read(chip, MII_BMCR, &val); + if (err) + return err; + + if (on) + new_val = val & ~BMCR_PDOWN; + else + new_val = val | BMCR_PDOWN; + + if (val != new_val) + err = mv88e6352_serdes_write(chip, MII_BMCR, new_val); + + return err; +} + +int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) +{ + int err; + u8 cmode; + + err = mv88e6xxx_port_get_cmode(chip, port, &cmode); + if (err) + return err; + + if ((cmode == PORT_STATUS_CMODE_100BASE_X) || + (cmode == PORT_STATUS_CMODE_1000BASE_X) || + (cmode == PORT_STATUS_CMODE_SGMII)) { + err = mv88e6352_serdes_power_set(chip, on); + if (err < 0) + return err; + } + + return 0; +} diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h new file mode 100644 index 000000000000..a690be09ac52 --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -0,0 +1,24 @@ +/* + * Marvell 88E6xxx SERDES manipulation, via SMI bus + * + * Copyright (c) 2008 Marvell Semiconductor + * + * Copyright (c) 2016 Andrew Lunn + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _MV88E6XXX_SERDES_H +#define _MV88E6XXX_SERDES_H + +#include "mv88e6xxx.h" + +#define MV88E6352_ADDR_SERDES 0x0f +#define MV88E6352_SERDES_PAGE_FIBER 0x01 + +int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); + +#endif -- cgit v1.2.3 From ba9b989dc77d9f0a0968ff6bc13ad762d3bf468e Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 26 May 2017 01:03:22 +0200 Subject: net: dsa: mv88e6xxx: Remove SERDES flag Now that we use an op for SERDES operations, we don't need a flag for it. Remove it. Signed-off-by: Andrew Lunn Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 23 ++--------------------- drivers/net/dsa/mv88e6xxx/phy.c | 3 --- 2 files changed, 2 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index fb996491b111..9087cb009cc3 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h @@ -508,14 +508,6 @@ enum mv88e6xxx_cap { MV88E6XXX_CAP_SMI_CMD, /* (0x00) SMI Command */ MV88E6XXX_CAP_SMI_DATA, /* (0x01) SMI Data */ - /* PHY Registers. - */ - MV88E6XXX_CAP_PHY_PAGE, /* (0x16) Page Register */ - - /* Fiber/SERDES Registers (SMI address F). - */ - MV88E6XXX_CAP_SERDES, - /* Switch Global (1) Registers. */ MV88E6XXX_CAP_G1_ATU_FID, /* (0x01) ATU FID Register */ @@ -550,10 +542,6 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_SMI_CMD BIT_ULL(MV88E6XXX_CAP_SMI_CMD) #define MV88E6XXX_FLAG_SMI_DATA BIT_ULL(MV88E6XXX_CAP_SMI_DATA) -#define MV88E6XXX_FLAG_PHY_PAGE BIT_ULL(MV88E6XXX_CAP_PHY_PAGE) - -#define MV88E6XXX_FLAG_SERDES BIT_ULL(MV88E6XXX_CAP_SERDES) - #define MV88E6XXX_FLAG_G1_VTU_FID BIT_ULL(MV88E6XXX_CAP_G1_VTU_FID) #define MV88E6XXX_FLAG_GLOBAL2 BIT_ULL(MV88E6XXX_CAP_GLOBAL2) @@ -574,11 +562,6 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_SMI_CMD | \ MV88E6XXX_FLAG_SMI_DATA) -/* Fiber/SERDES Registers at SMI address F, page 1 */ -#define MV88E6XXX_FLAGS_SERDES \ - (MV88E6XXX_FLAG_PHY_PAGE | \ - MV88E6XXX_FLAG_SERDES) - #define MV88E6XXX_FLAGS_FAMILY_6095 \ (MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ @@ -626,8 +609,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_INT | \ MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP | \ - MV88E6XXX_FLAGS_SERDES) + MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6351 \ (MV88E6XXX_FLAG_G1_VTU_FID | \ @@ -648,8 +630,7 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP | \ - MV88E6XXX_FLAGS_SERDES) + MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6390 \ (MV88E6XXX_FLAG_EEE | \ diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c index 0e6c72b93c8f..0d3e8aaedf50 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.c +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -62,9 +62,6 @@ int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, int reg, u16 val) static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page) { - if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE)) - return -EOPNOTSUPP; - return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); } -- cgit v1.2.3 From 6335e9f2446b44139ac0722a81759a2b2f90bb4c Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 26 May 2017 01:03:23 +0200 Subject: net: dsa: mv88e6xxx: mv88e6390X SERDES support The mv88e6390X family has 8 SERDES lanes. These can be used for 2 10Gbps ports, ports 9 or 10. If these ports are used at slower speeds, the SERDES lanes become available for other ports for 1000Base-X. Signed-off-by: Andrew Lunn Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 6 ++ drivers/net/dsa/mv88e6xxx/serdes.c | 154 +++++++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/serdes.h | 24 ++++++ 3 files changed, 184 insertions(+) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index bc7b345d91d3..4e58d9a82d9e 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2757,6 +2757,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6190x_ops = { @@ -2789,6 +2790,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6191_ops = { @@ -2821,6 +2823,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6240_ops = { @@ -2888,6 +2891,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6320_ops = { @@ -3113,6 +3117,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_ops mv88e6390x_ops = { @@ -3147,6 +3152,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, }; static const struct mv88e6xxx_info mv88e6xxx_table[] = { diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 235f5f0c30ae..53795676bd70 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -13,6 +13,7 @@ #include +#include "global2.h" #include "mv88e6xxx.h" #include "phy.h" #include "port.h" @@ -73,3 +74,156 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) return 0; } + +/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ +static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on) +{ + u16 val, new_val; + int reg_c45; + int err; + + reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE | + MV88E6390_PCS_CONTROL_1; + err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val); + if (err) + return err; + + if (on) + new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET | + MV88E6390_PCS_CONTROL_1_LOOPBACK | + MV88E6390_PCS_CONTROL_1_PDOWN); + else + new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN; + + if (val != new_val) + err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val); + + return err; +} + +/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ +static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr, + bool on) +{ + u16 val, new_val; + int reg_c45; + int err; + + reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE | + MV88E6390_SGMII_CONTROL; + err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val); + if (err) + return err; + + if (on) + new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET | + MV88E6390_SGMII_CONTROL_LOOPBACK | + MV88E6390_SGMII_CONTROL_PDOWN); + else + new_val = val | MV88E6390_SGMII_CONTROL_PDOWN; + + if (val != new_val) + err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val); + + return err; +} + +static int mv88e6390_serdes_lower(struct mv88e6xxx_chip *chip, u8 cmode, + int port_donor, int lane, bool rxaui, bool on) +{ + int err; + u8 cmode_donor; + + err = mv88e6xxx_port_get_cmode(chip, port_donor, &cmode_donor); + if (err) + return err; + + switch (cmode_donor) { + case PORT_STATUS_CMODE_RXAUI: + if (!rxaui) + break; + /* Fall through */ + case PORT_STATUS_CMODE_1000BASE_X: + case PORT_STATUS_CMODE_SGMII: + case PORT_STATUS_CMODE_2500BASEX: + if (cmode == PORT_STATUS_CMODE_1000BASE_X || + cmode == PORT_STATUS_CMODE_SGMII) + return mv88e6390_serdes_sgmii(chip, lane, on); + } + return 0; +} + +static int mv88e6390_serdes_port9(struct mv88e6xxx_chip *chip, u8 cmode, + bool on) +{ + switch (cmode) { + case PORT_STATUS_CMODE_1000BASE_X: + case PORT_STATUS_CMODE_SGMII: + return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT9_LANE0, on); + case PORT_STATUS_CMODE_XAUI: + case PORT_STATUS_CMODE_RXAUI: + case PORT_STATUS_CMODE_2500BASEX: + return mv88e6390_serdes_10g(chip, MV88E6390_PORT9_LANE0, on); + } + + return 0; +} + +static int mv88e6390_serdes_port10(struct mv88e6xxx_chip *chip, u8 cmode, + bool on) +{ + switch (cmode) { + case PORT_STATUS_CMODE_SGMII: + return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT10_LANE0, on); + case PORT_STATUS_CMODE_XAUI: + case PORT_STATUS_CMODE_RXAUI: + case PORT_STATUS_CMODE_1000BASE_X: + case PORT_STATUS_CMODE_2500BASEX: + return mv88e6390_serdes_10g(chip, MV88E6390_PORT10_LANE0, on); + } + + return 0; +} + +int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) +{ + u8 cmode; + int err; + + err = mv88e6xxx_port_get_cmode(chip, port, &cmode); + if (err) + return cmode; + + switch (port) { + case 2: + return mv88e6390_serdes_lower(chip, cmode, 9, + MV88E6390_PORT9_LANE1, + false, on); + case 3: + return mv88e6390_serdes_lower(chip, cmode, 9, + MV88E6390_PORT9_LANE2, + true, on); + case 4: + return mv88e6390_serdes_lower(chip, cmode, 9, + MV88E6390_PORT9_LANE3, + true, on); + case 5: + return mv88e6390_serdes_lower(chip, cmode, 10, + MV88E6390_PORT10_LANE1, + false, on); + case 6: + return mv88e6390_serdes_lower(chip, cmode, 10, + MV88E6390_PORT10_LANE2, + true, on); + case 7: + return mv88e6390_serdes_lower(chip, cmode, 10, + MV88E6390_PORT10_LANE3, + true, on); + case 9: + return mv88e6390_serdes_port9(chip, cmode, on); + case 10: + return mv88e6390_serdes_port10(chip, cmode, on); + } + + return 0; +} diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index a690be09ac52..eb3ceaef790f 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -19,6 +19,30 @@ #define MV88E6352_ADDR_SERDES 0x0f #define MV88E6352_SERDES_PAGE_FIBER 0x01 +#define MV88E6390_PORT9_LANE0 0x09 +#define MV88E6390_PORT9_LANE1 0x12 +#define MV88E6390_PORT9_LANE2 0x13 +#define MV88E6390_PORT9_LANE3 0x14 +#define MV88E6390_PORT10_LANE0 0x0a +#define MV88E6390_PORT10_LANE1 0x15 +#define MV88E6390_PORT10_LANE2 0x16 +#define MV88E6390_PORT10_LANE3 0x17 +#define MV88E6390_SERDES_DEVICE (4 << 16) + +/* 10GBASE-R and 10GBASE-X4/X2 */ +#define MV88E6390_PCS_CONTROL_1 0x1000 +#define MV88E6390_PCS_CONTROL_1_RESET BIT(15) +#define MV88E6390_PCS_CONTROL_1_LOOPBACK BIT(14) +#define MV88E6390_PCS_CONTROL_1_SPEED BIT(13) +#define MV88E6390_PCS_CONTROL_1_PDOWN BIT(11) + +/* 1000BASE-X and SGMII */ +#define MV88E6390_SGMII_CONTROL 0x2000 +#define MV88E6390_SGMII_CONTROL_RESET BIT(15) +#define MV88E6390_SGMII_CONTROL_LOOPBACK BIT(14) +#define MV88E6390_SGMII_CONTROL_PDOWN BIT(11) + int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); +int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); #endif -- cgit v1.2.3 From 04aca9938255fc7097b3fb5700f408524656f2e2 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 26 May 2017 01:03:24 +0200 Subject: dsa: mv88e6xxx: Enable/Disable SERDES on port enable/disable Implement the port enable/disable callbacks, which enable/disable the SERDES interfaces, if applicable. This should save a bit of power/heat. We also need to enable SERDES on CPU and DSA ports, so keep the existing call to the op, but make it conditional. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 50 +++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 4e58d9a82d9e..c2f38f6770aa 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1806,10 +1806,16 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) { - if (chip->info->ops->serdes_power) - return chip->info->ops->serdes_power(chip, port, on); + int err = 0; - return 0; + if (chip->info->ops->serdes_power) { + err = chip->info->ops->serdes_power(chip, port, on); + if (err) + dev_err(chip->dev, + "Failed to change SERDES power: %d\n", err); + } + + return err; } static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) @@ -1862,12 +1868,15 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) if (err) return err; - /* If this port is connected to a SerDes, make sure the SerDes is - * powered up. + /* Enable the SERDES interface for DSA and CPU ports. Normal + * ports SERDES are enabled when the port is enabled, thus + * saving a bit of power. */ - err = mv88e6xxx_serdes_power(chip, port, true); - if (err) - return err; + if ((dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) { + err = mv88e6xxx_serdes_power(chip, port, true); + if (err) + return err; + } /* Port Control 2: don't force a good FCS, set the maximum frame size to * 10240 bytes, disable 802.1q tags checking, don't discard tagged or @@ -1969,6 +1978,29 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, 0x0000); } +static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct mv88e6xxx_chip *chip = ds->priv; + int err = 0; + + mutex_lock(&chip->reg_lock); + mv88e6xxx_serdes_power(chip, port, true); + mutex_unlock(&chip->reg_lock); + + return err; +} + +static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct mv88e6xxx_chip *chip = ds->priv; + + mutex_lock(&chip->reg_lock); + mv88e6xxx_serdes_power(chip, port, false); + mutex_unlock(&chip->reg_lock); +} + static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) { int err; @@ -3809,6 +3841,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .get_strings = mv88e6xxx_get_strings, .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, .get_sset_count = mv88e6xxx_get_sset_count, + .port_enable = mv88e6xxx_port_enable, + .port_disable = mv88e6xxx_port_disable, .set_eee = mv88e6xxx_set_eee, .get_eee = mv88e6xxx_get_eee, .get_eeprom_len = mv88e6xxx_get_eeprom_len, -- cgit v1.2.3 From 4aafc368daac7781576ca6144622254adf469a15 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:25 +0200 Subject: mlxsw: spectrum: Set port's mode according to FID mappings We currently transition the port to "Virtual mode" upon the creation of its first VLAN upper, as we need to classify incoming packets to a FID using {Port, VID} and not only the VID. However, it's more appropriate to transition the port to this mode when the {Port, VID} are actually mapped to a FID. Either during the enslavement of the VLAN upper to a VLAN-unaware bridge or the configuration of a router port. Do this change now in preparation for the introduction of the FID core, where this operation will be encapsulated. To prevent regressions, this patch also explicitly configures an OVS slave to "Virtual mode". Otherwise, a packet that didn't hit an ACL rule could be classified to an existing FID based on a global VID-to-FID mapping, thus not incurring a FID mis-classification, which would otherwise trap the packet to the CPU to be processed by the OVS daemon. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 55 ++++++++++++---------- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 11 +++++ .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 23 ++++++++- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 2 +- 4 files changed, 63 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 9594e9d215e8..5d673363154b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1398,7 +1398,7 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, return 0; } -static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) { enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; u16 vid, last_visited_vid; @@ -1428,7 +1428,7 @@ err_port_vid_to_fid_set: return err; } -static int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) { enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; u16 vid; @@ -1501,16 +1501,6 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, if (!mlxsw_sp_vport) return -ENOMEM; - /* When adding the first VLAN interface on a bridged port we need to - * transition all the active 802.1Q bridge VLANs to use explicit - * {Port, VID} to FID mappings and set the port's mode to Virtual mode. - */ - if (list_is_singular(&mlxsw_sp_port->vports_list)) { - err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); - if (err) - goto err_port_vp_mode_trans; - } - err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged); if (err) goto err_port_add_vid; @@ -1518,9 +1508,6 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, return 0; err_port_add_vid: - if (list_is_singular(&mlxsw_sp_port->vports_list)) - mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); -err_port_vp_mode_trans: mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); return err; } @@ -1551,13 +1538,6 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, if (f && !WARN_ON(!f->leave)) f->leave(mlxsw_sp_vport); - /* When removing the last VLAN interface on a bridged port we need to - * transition all active 802.1Q bridge VLANs to use VID to FID - * mappings and set port's mode to VLAN mode. - */ - if (list_is_singular(&mlxsw_sp_port->vports_list)) - mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); - mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); return 0; @@ -4382,9 +4362,12 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) { int err; - err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true); + err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); if (err) return err; + err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true); + if (err) + goto err_port_stp_set; err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 2, VLAN_N_VID - 1, true, false); if (err) @@ -4393,6 +4376,8 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) err_port_vlan_set: mlxsw_sp_port_stp_set(mlxsw_sp_port, false); +err_port_stp_set: + mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); return err; } @@ -4401,6 +4386,7 @@ static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port) mlxsw_sp_port_vlan_set(mlxsw_sp_port, 2, VLAN_N_VID - 1, false, false); mlxsw_sp_port_stp_set(mlxsw_sp_port, false); + mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); } static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, @@ -4695,6 +4681,7 @@ static int mlxsw_sp_vport_fid_map(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport, struct net_device *br_dev) { + struct mlxsw_sp_port *mlxsw_sp_port; struct mlxsw_sp_fid *f; int err; @@ -4713,6 +4700,13 @@ static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport, if (err) goto err_vport_fid_map; + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + if (mlxsw_sp_port->nr_port_vid_map++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + mlxsw_sp_vport_fid_set(mlxsw_sp_vport, f); f->ref_count++; @@ -4720,6 +4714,9 @@ static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport, return 0; +err_port_vp_mode_trans: + mlxsw_sp_port->nr_port_vid_map--; + mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false); err_vport_fid_map: mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false); err_vport_flood_set: @@ -4731,17 +4728,25 @@ err_vport_flood_set: static void mlxsw_sp_vport_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport) { struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); + struct mlxsw_sp_port *mlxsw_sp_port; netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); + mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); + f->ref_count--; + + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + if (mlxsw_sp_port->nr_port_vid_map == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp_port->nr_port_vid_map--; + mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false); mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false); mlxsw_sp_port_fdb_flush(mlxsw_sp_vport, f->fid); - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); - if (--f->ref_count == 0) + if (f->ref_count == 0) mlxsw_sp_vfid_destroy(mlxsw_sp_vport->mlxsw_sp, f); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 7caf175211a8..277a432af319 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -253,6 +253,7 @@ struct mlxsw_sp_port { struct delayed_work update_dw; } hw_stats; struct mlxsw_sp_port_sample *sample; + unsigned int nr_port_vid_map; /* {Port, VID} => FID mappings */ }; bool mlxsw_sp_port_dev_check(const struct net_device *dev); @@ -343,6 +344,14 @@ mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port, return NULL; } +static inline struct mlxsw_sp_port * +mlxsw_sp_vport_port(const struct mlxsw_sp_port *mlxsw_sp_vport) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; + + return mlxsw_sp->ports[mlxsw_sp_vport->local_port]; +} + static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp, u16 fid) { @@ -446,6 +455,8 @@ int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, bool learn_enable); int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port); +int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port); #ifdef CONFIG_MLXSW_SPECTRUM_DCB diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 8165b1148bce..cb5e86ad0f66 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3111,6 +3111,7 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); + struct mlxsw_sp_port *mlxsw_sp_port; struct mlxsw_sp_rif *rif; int err; @@ -3130,6 +3131,13 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, if (err) goto err_port_vid_stp_set; + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + if (mlxsw_sp_port->nr_port_vid_map++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + mlxsw_sp_vport_fid_set(mlxsw_sp_vport, rif->f); rif->f->ref_count++; @@ -3137,6 +3145,9 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, return 0; +err_port_vp_mode_trans: + mlxsw_sp_port->nr_port_vid_map--; + mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, BR_STATE_BLOCKING); err_port_vid_stp_set: mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); err_port_vid_learning_set: @@ -3149,13 +3160,21 @@ static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport) { struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); + struct mlxsw_sp_port *mlxsw_sp_port; netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); + f->ref_count--; + mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); + + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + if (mlxsw_sp_port->nr_port_vid_map == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp_port->nr_port_vid_map--; mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, BR_STATE_BLOCKING); mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); - if (--f->ref_count == 0) + + if (f->ref_count == 0) mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, f->rif); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index ea0f4a5787c3..0d173bebcf3a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -617,7 +617,7 @@ static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid, /* If port doesn't have vPorts, then it can use the global * VID-to-FID mapping. */ - if (list_empty(&mlxsw_sp_port->vports_list)) + if (mlxsw_sp_port->nr_port_vid_map == 0) return 0; return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, valid, fid, fid); -- cgit v1.2.3 From 31a08a523ae453f7eaf5ad6c1da99d6199141b14 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:26 +0200 Subject: mlxsw: spectrum: Introduce Port-VLAN structure This is the first step in the transition from the vPort model to a unified Port-VLAN structure. The new structure is defined and created / destroyed upon invocation of the 8021q ndos, but it's not actually used throughout the code. Subsequent patches will initialize it correctly and also create / destroy it upon switchdev's VLAN object. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 48 ++++++++++++++++++++++++-- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 23 ++++++++++++ 2 files changed, 68 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 5d673363154b..6f5f01151c49 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1480,10 +1480,34 @@ static void mlxsw_sp_port_vport_destroy(struct mlxsw_sp_port *mlxsw_sp_vport) kfree(mlxsw_sp_vport); } +static struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + mlxsw_sp_port_vlan = kzalloc(sizeof(*mlxsw_sp_port_vlan), GFP_KERNEL); + if (!mlxsw_sp_port_vlan) + return ERR_PTR(-ENOMEM); + + mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port; + mlxsw_sp_port_vlan->vid = vid; + list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list); + + return mlxsw_sp_port_vlan; +} + +static void +mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) +{ + list_del(&mlxsw_sp_port_vlan->list); + kfree(mlxsw_sp_port_vlan); +} + static int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto, u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_port *mlxsw_sp_vport; bool untagged = vid == 1; int err; @@ -1494,12 +1518,19 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, if (!vid) return 0; - if (mlxsw_sp_port_vport_find(mlxsw_sp_port, vid)) + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (mlxsw_sp_port_vlan) return 0; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid); + if (IS_ERR(mlxsw_sp_port_vlan)) + return PTR_ERR(mlxsw_sp_port_vlan); + mlxsw_sp_vport = mlxsw_sp_port_vport_create(mlxsw_sp_port, vid); - if (!mlxsw_sp_vport) - return -ENOMEM; + if (!mlxsw_sp_vport) { + err = -ENOMEM; + goto err_port_vport_create; + } err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged); if (err) @@ -1509,6 +1540,8 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, err_port_add_vid: mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); +err_port_vport_create: + mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); return err; } @@ -1516,6 +1549,7 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, __be16 __always_unused proto, u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_port *mlxsw_sp_vport; struct mlxsw_sp_fid *f; @@ -1525,6 +1559,10 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, if (!vid) return 0; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return 0; + mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); if (WARN_ON(!mlxsw_sp_vport)) return 0; @@ -1540,6 +1578,8 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); + mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); + return 0; } @@ -2720,6 +2760,7 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, err = -ENOMEM; goto err_port_untagged_vlans_alloc; } + INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list); INIT_LIST_HEAD(&mlxsw_sp_port->vports_list); INIT_LIST_HEAD(&mlxsw_sp_port->mall_tc_list); @@ -2926,6 +2967,7 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) kfree(mlxsw_sp_port->untagged_vlans); kfree(mlxsw_sp_port->active_vlans); WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vports_list)); + WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list)); free_netdev(mlxsw_sp_port->dev); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 277a432af319..c4ac648f39bf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -203,6 +203,13 @@ struct mlxsw_sp_port_sample { bool truncate; }; +struct mlxsw_sp_port_vlan { + struct list_head list; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp_fid *fid; + u16 vid; +}; + struct mlxsw_sp_port { struct net_device *dev; struct mlxsw_sp_port_pcpu_stats __percpu *pcpu_stats; @@ -254,6 +261,7 @@ struct mlxsw_sp_port { } hw_stats; struct mlxsw_sp_port_sample *sample; unsigned int nr_port_vid_map; /* {Port, VID} => FID mappings */ + struct list_head vlans_list; }; bool mlxsw_sp_port_dev_check(const struct net_device *dev); @@ -279,6 +287,21 @@ mlxsw_sp_port_lagged_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id, u8 port_index) return mlxsw_sp_port && mlxsw_sp_port->lagged ? mlxsw_sp_port : NULL; } +static inline struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_find_by_vid(const struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + if (mlxsw_sp_port_vlan->vid == vid) + return mlxsw_sp_port_vlan; + } + + return NULL; +} + static inline u16 mlxsw_sp_vport_vid_get(const struct mlxsw_sp_port *mlxsw_sp_vport) { -- cgit v1.2.3 From ce95e1545681dd73fa73ac12a06135c4fcdb47cc Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:27 +0200 Subject: mlxsw: spectrum: Change signature of FID leave function When a vPort is destroyed, it leaves the FID it's currently mapped to (if any) and drops the reference. The FID's leave function expects to get the vPort as its argument, but this will have to change when the vPort model is retired. Change the function signature to expect a Port-VLAN struct instead and patch the call sites accordingly. The code introduced in this patch will be removed later in the patchset, but this intermediary step is required in order to ease the code review. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 42 +++++++++++++++------- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 3 +- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 23 +++++++----- 3 files changed, 47 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 6f5f01151c49..acc3a1a76d1b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1574,7 +1574,7 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, */ f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); if (f && !WARN_ON(!f->leave)) - f->leave(mlxsw_sp_vport); + f->leave(mlxsw_sp_port_vlan); mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); @@ -4192,6 +4192,7 @@ static void mlxsw_sp_port_pvid_vport_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, struct net_device *lag_dev, u16 lag_id) { + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_port *mlxsw_sp_vport; struct mlxsw_sp_fid *f; @@ -4199,12 +4200,13 @@ mlxsw_sp_port_pvid_vport_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, if (WARN_ON(!mlxsw_sp_vport)) return; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); /* If vPort is assigned a RIF, then leave it since it's no * longer valid. */ f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); if (f) - f->leave(mlxsw_sp_vport); + f->leave(mlxsw_sp_port_vlan); mlxsw_sp_vport->lag_id = lag_id; mlxsw_sp_vport->lagged = 1; @@ -4214,6 +4216,7 @@ mlxsw_sp_port_pvid_vport_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, static void mlxsw_sp_port_pvid_vport_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port) { + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_port *mlxsw_sp_vport; struct mlxsw_sp_fid *f; @@ -4221,9 +4224,10 @@ mlxsw_sp_port_pvid_vport_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port) if (WARN_ON(!mlxsw_sp_vport)) return; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); if (f) - f->leave(mlxsw_sp_vport); + f->leave(mlxsw_sp_port_vlan); mlxsw_sp_vport->dev = mlxsw_sp_port->dev; mlxsw_sp_vport->lagged = 0; @@ -4652,7 +4656,8 @@ static int mlxsw_sp_vfid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create) return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); } -static void mlxsw_sp_vport_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport); +static void +mlxsw_sp_port_vlan_vfid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); static struct mlxsw_sp_fid *mlxsw_sp_vfid_create(struct mlxsw_sp *mlxsw_sp, struct net_device *br_dev) @@ -4679,7 +4684,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_vfid_create(struct mlxsw_sp *mlxsw_sp, if (!f) goto err_allocate_vfid; - f->leave = mlxsw_sp_vport_vfid_leave; + f->leave = mlxsw_sp_port_vlan_vfid_leave; f->fid = fid; f->dev = br_dev; @@ -4767,17 +4772,22 @@ err_vport_flood_set: return err; } -static void mlxsw_sp_vport_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport) +static void +mlxsw_sp_port_vlan_vfid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp_port *mlxsw_sp_vport; + u16 vid = mlxsw_sp_port_vlan->vid; + struct mlxsw_sp_fid *f; + + mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); + f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); f->ref_count--; - mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); if (mlxsw_sp_port->nr_port_vid_map == 1) mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); mlxsw_sp_port->nr_port_vid_map--; @@ -4797,11 +4807,15 @@ static int mlxsw_sp_vport_bridge_join(struct mlxsw_sp_port *mlxsw_sp_vport, { struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct net_device *dev = mlxsw_sp_vport->dev; + struct mlxsw_sp_port *mlxsw_sp_port; int err; + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); if (f && !WARN_ON(!f->leave)) - f->leave(mlxsw_sp_vport); + f->leave(mlxsw_sp_port_vlan); err = mlxsw_sp_vport_vfid_join(mlxsw_sp_vport, br_dev); if (err) { @@ -4826,17 +4840,21 @@ static int mlxsw_sp_vport_bridge_join(struct mlxsw_sp_port *mlxsw_sp_vport, return 0; err_port_vid_learning_set: - mlxsw_sp_vport_vfid_leave(mlxsw_sp_vport); + mlxsw_sp_port_vlan_vfid_leave(mlxsw_sp_port_vlan); return err; } static void mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport) { u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_port *mlxsw_sp_port; mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, false); - mlxsw_sp_vport_vfid_leave(mlxsw_sp_vport); + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + mlxsw_sp_port_vlan_vfid_leave(mlxsw_sp_port_vlan); mlxsw_sp_vport->learning = 0; mlxsw_sp_vport->learning_sync = 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index c4ac648f39bf..b72ecf39a273 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -70,6 +70,7 @@ #define MLXSW_SP_KVD_LINEAR_SIZE 65536 /* entries */ #define MLXSW_SP_KVD_GRANULARITY 128 +struct mlxsw_sp_port_vlan; struct mlxsw_sp_port; struct mlxsw_sp_rif; @@ -79,7 +80,7 @@ struct mlxsw_sp_upper { }; struct mlxsw_sp_fid { - void (*leave)(struct mlxsw_sp_port *mlxsw_sp_vport); + void (*leave)(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); struct list_head list; unsigned int ref_count; struct net_device *dev; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index cb5e86ad0f66..6a1de24168f3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2945,7 +2945,8 @@ static int mlxsw_sp_vport_rif_sp_op(struct mlxsw_sp_port *mlxsw_sp_vport, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); } -static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport); +static void +mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); static u16 mlxsw_sp_rif_sp_to_fid(u16 rif_index) { @@ -2961,7 +2962,7 @@ mlxsw_sp_rfid_alloc(u16 fid, struct net_device *l3_dev) if (!f) return NULL; - f->leave = mlxsw_sp_vport_rif_sp_leave; + f->leave = mlxsw_sp_port_vlan_rif_sp_leave; f->ref_count = 0; f->dev = l3_dev; f->fid = fid; @@ -3156,18 +3157,22 @@ err_port_vid_learning_set: return err; } -static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport) +static void +mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp_port *mlxsw_sp_vport; + u16 vid = mlxsw_sp_port_vlan->vid; + struct mlxsw_sp_fid *f; + + mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); + f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); f->ref_count--; mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); - mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); if (mlxsw_sp_port->nr_port_vid_map == 1) mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); mlxsw_sp_port->nr_port_vid_map--; @@ -3183,17 +3188,19 @@ static int mlxsw_sp_inetaddr_vport_event(struct net_device *l3_dev, unsigned long event, u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(port_dev); + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_port *mlxsw_sp_vport; mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); if (WARN_ON(!mlxsw_sp_vport)) return -EINVAL; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); switch (event) { case NETDEV_UP: return mlxsw_sp_vport_rif_sp_join(mlxsw_sp_vport, l3_dev); case NETDEV_DOWN: - mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport); + mlxsw_sp_port_vlan_rif_sp_leave(mlxsw_sp_port_vlan); break; } -- cgit v1.2.3 From 7cbecf245ade1739f34e00a10b2cdedd851bd7f4 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:28 +0200 Subject: mlxsw: spectrum_router: Replace vPorts with Port-VLAN We're going to get rid of vPorts completely later in the patchset, but the router code is self-contained, so it's a good candidate to start the transition with. Convert all the functions that expects to operate on a vPort to operate on a Port-VLAN instead. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 + .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 137 ++++++++++----------- 2 files changed, 67 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index acc3a1a76d1b..e04d2ed34d7e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1499,6 +1499,10 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) static void mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + + if (fid && !WARN_ON(!fid->leave)) + fid->leave(mlxsw_sp_port_vlan); list_del(&mlxsw_sp_port_vlan->list); kfree(mlxsw_sp_port_vlan); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 6a1de24168f3..ef8e8a12c001 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2917,30 +2917,23 @@ static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp) return MLXSW_SP_INVALID_INDEX_RIF; } -static void mlxsw_sp_vport_rif_sp_attr_get(struct mlxsw_sp_port *mlxsw_sp_vport, - bool *p_lagged, u16 *p_system_port) -{ - u8 local_port = mlxsw_sp_vport->local_port; - - *p_lagged = mlxsw_sp_vport->lagged; - *p_system_port = *p_lagged ? mlxsw_sp_vport->lag_id : local_port; -} - -static int mlxsw_sp_vport_rif_sp_op(struct mlxsw_sp_port *mlxsw_sp_vport, - u16 vr_id, struct net_device *l3_dev, - u16 rif_index, bool create) +static int +mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + u16 vr_id, struct net_device *l3_dev, + u16 rif_index, bool create) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; - bool lagged = mlxsw_sp_vport->lagged; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + bool lagged = mlxsw_sp_port->lagged; char ritr_pl[MLXSW_REG_RITR_LEN]; u16 system_port; + system_port = lagged ? mlxsw_sp_port->lag_id : + mlxsw_sp_port->local_port; mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, rif_index, vr_id, l3_dev->mtu, l3_dev->dev_addr); - - mlxsw_sp_vport_rif_sp_attr_get(mlxsw_sp_vport, &lagged, &system_port); mlxsw_reg_ritr_sp_if_pack(ritr_pl, lagged, system_port, - mlxsw_sp_vport_vid_get(mlxsw_sp_vport)); + mlxsw_sp_port_vlan->vid); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); } @@ -3009,10 +3002,11 @@ int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif) } static struct mlxsw_sp_rif * -mlxsw_sp_vport_rif_sp_create(struct mlxsw_sp_port *mlxsw_sp_vport, - struct net_device *l3_dev) +mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + struct net_device *l3_dev) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u32 tb_id = l3mdev_fib_table(l3_dev); struct mlxsw_sp_vr *vr; struct mlxsw_sp_fid *f; @@ -3028,10 +3022,10 @@ mlxsw_sp_vport_rif_sp_create(struct mlxsw_sp_port *mlxsw_sp_vport, if (IS_ERR(vr)) return ERR_CAST(vr); - err = mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, - rif_index, true); + err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, + rif_index, true); if (err) - goto err_vport_rif_sp_op; + goto err_port_vlan_rif_sp_op; fid = mlxsw_sp_rif_sp_to_fid(rif_index); err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true); @@ -3055,7 +3049,7 @@ mlxsw_sp_vport_rif_sp_create(struct mlxsw_sp_port *mlxsw_sp_vport, err = mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); if (err) - netdev_dbg(mlxsw_sp_vport->dev, + netdev_dbg(mlxsw_sp_port->dev, "Counter alloc Failed err=%d\n", err); } @@ -3070,17 +3064,19 @@ err_rif_alloc: err_rfid_alloc: mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); err_rif_fdb_op: - mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, rif_index, - false); -err_vport_rif_sp_op: + mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, + rif_index, false); +err_port_vlan_rif_sp_op: mlxsw_sp_vr_put(vr); return ERR_PTR(err); } -static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport, - struct mlxsw_sp_rif *rif) +static void +mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + struct mlxsw_sp_rif *rif) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; struct net_device *l3_dev = rif->dev; struct mlxsw_sp_fid *f = rif->f; @@ -3102,58 +3098,57 @@ static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport, mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); - mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, rif_index, - false); + mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, + rif_index, false); + mlxsw_sp_vr_put(vr); } -static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, - struct net_device *l3_dev) +static int +mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + struct net_device *l3_dev) { - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + u16 vid = mlxsw_sp_port_vlan->vid; struct mlxsw_sp_rif *rif; int err; - rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp_port->mlxsw_sp, l3_dev); if (!rif) { - rif = mlxsw_sp_vport_rif_sp_create(mlxsw_sp_vport, l3_dev); + rif = mlxsw_sp_port_vlan_rif_sp_create(mlxsw_sp_port_vlan, + l3_dev); if (IS_ERR(rif)) return PTR_ERR(rif); } - err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, false); + err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); if (err) goto err_port_vid_learning_set; - err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, + err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_FORWARDING); if (err) goto err_port_vid_stp_set; - mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); if (mlxsw_sp_port->nr_port_vid_map++ == 0) { err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); if (err) goto err_port_vp_mode_trans; } - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, rif->f); + mlxsw_sp_port_vlan->fid = rif->f; rif->f->ref_count++; - netdev_dbg(mlxsw_sp_vport->dev, "Joined FID=%d\n", rif->f->fid); - return 0; err_port_vp_mode_trans: mlxsw_sp_port->nr_port_vid_map--; - mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, BR_STATE_BLOCKING); + mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING); err_port_vid_stp_set: - mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); err_port_vid_learning_set: if (rif->f->ref_count == 0) - mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, rif); + mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp_port_vlan, rif); return err; } @@ -3161,44 +3156,37 @@ static void mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp_port *mlxsw_sp_vport; + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; u16 vid = mlxsw_sp_port_vlan->vid; - struct mlxsw_sp_fid *f; - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - - netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); - - f->ref_count--; - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); + fid->ref_count--; + mlxsw_sp_port_vlan->fid = NULL; if (mlxsw_sp_port->nr_port_vid_map == 1) mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); mlxsw_sp_port->nr_port_vid_map--; - mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, BR_STATE_BLOCKING); - mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); + mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING); + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); - if (f->ref_count == 0) - mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, f->rif); + if (fid->ref_count == 0) + mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp_port_vlan, fid->rif); } -static int mlxsw_sp_inetaddr_vport_event(struct net_device *l3_dev, - struct net_device *port_dev, - unsigned long event, u16 vid) +static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, + struct net_device *port_dev, + unsigned long event, u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(port_dev); struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_port *mlxsw_sp_vport; - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (WARN_ON(!mlxsw_sp_vport)) - return -EINVAL; mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; switch (event) { case NETDEV_UP: - return mlxsw_sp_vport_rif_sp_join(mlxsw_sp_vport, l3_dev); + return mlxsw_sp_port_vlan_rif_sp_join(mlxsw_sp_port_vlan, + l3_dev); case NETDEV_DOWN: mlxsw_sp_port_vlan_rif_sp_leave(mlxsw_sp_port_vlan); break; @@ -3215,7 +3203,7 @@ static int mlxsw_sp_inetaddr_port_event(struct net_device *port_dev, netif_is_ovs_port(port_dev)) return 0; - return mlxsw_sp_inetaddr_vport_event(port_dev, port_dev, event, 1); + return mlxsw_sp_inetaddr_port_vlan_event(port_dev, port_dev, event, 1); } static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev, @@ -3228,8 +3216,9 @@ static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev, netdev_for_each_lower_dev(lag_dev, port_dev, iter) { if (mlxsw_sp_port_dev_check(port_dev)) { - err = mlxsw_sp_inetaddr_vport_event(l3_dev, port_dev, - event, vid); + err = mlxsw_sp_inetaddr_port_vlan_event(l3_dev, + port_dev, + event, vid); if (err) return err; } @@ -3444,8 +3433,8 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev, u16 vid = vlan_dev_vlan_id(vlan_dev); if (mlxsw_sp_port_dev_check(real_dev)) - return mlxsw_sp_inetaddr_vport_event(vlan_dev, real_dev, event, - vid); + return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev, real_dev, + event, vid); else if (netif_is_lag_master(real_dev)) return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event, vid); -- cgit v1.2.3 From f0cebd81c9cec7395da71b43b9c02c000068907a Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:29 +0200 Subject: mlxsw: spectrum: Don't lose bridge port device during enslavement Currently, when port netdevs (or their uppers) are enslaved to a bridge, we simply propagate the CHANGEUPPER event all the way down and lose the context of the actual netdevice used as the bridge port. This leads to a lot of information hanging off the ports (and vPorts), which doesn't logically belong there, such as mrouter indication and unknown unicast flood state. Following patches are going to put the mlxsw_sp_port struct on diet and instead introduce a bridge port struct, where the above mentioned information belongs. But in order to do that, we need to be able to determine the bridge port netdevice, so propagate it down. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 67 +++++++++++++++++--------- 1 file changed, 44 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index e04d2ed34d7e..29d9439f6f12 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4026,6 +4026,7 @@ static void mlxsw_sp_master_bridge_dec(struct mlxsw_sp *mlxsw_sp) } static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, struct net_device *br_dev) { struct net_device *dev = mlxsw_sp_port->dev; @@ -4053,7 +4054,9 @@ static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, return 0; } -static void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port) +static void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, + struct net_device *br_dev) { struct net_device *dev = mlxsw_sp_port->dev; @@ -4302,7 +4305,7 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, if (mlxsw_sp_port->bridged) { mlxsw_sp_port_active_vlans_del(mlxsw_sp_port); - mlxsw_sp_port_bridge_leave(mlxsw_sp_port); + mlxsw_sp_port_bridge_leave(mlxsw_sp_port, NULL, NULL); } if (lag->ref_count == 1) @@ -4439,7 +4442,8 @@ static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port) mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); } -static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, +static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, + struct net_device *dev, unsigned long event, void *ptr) { struct netdev_notifier_changeupper_info *info; @@ -4492,9 +4496,12 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, } else if (netif_is_bridge_master(upper_dev)) { if (info->linking) err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, + lower_dev, upper_dev); else - mlxsw_sp_port_bridge_leave(mlxsw_sp_port); + mlxsw_sp_port_bridge_leave(mlxsw_sp_port, + lower_dev, + upper_dev); } else if (netif_is_lag_master(upper_dev)) { if (info->linking) err = mlxsw_sp_port_lag_join(mlxsw_sp_port, @@ -4541,15 +4548,18 @@ static int mlxsw_sp_netdevice_port_lower_event(struct net_device *dev, return 0; } -static int mlxsw_sp_netdevice_port_event(struct net_device *dev, +static int mlxsw_sp_netdevice_port_event(struct net_device *lower_dev, + struct net_device *port_dev, unsigned long event, void *ptr) { switch (event) { case NETDEV_PRECHANGEUPPER: case NETDEV_CHANGEUPPER: - return mlxsw_sp_netdevice_port_upper_event(dev, event, ptr); + return mlxsw_sp_netdevice_port_upper_event(lower_dev, port_dev, + event, ptr); case NETDEV_CHANGELOWERSTATE: - return mlxsw_sp_netdevice_port_lower_event(dev, event, ptr); + return mlxsw_sp_netdevice_port_lower_event(port_dev, event, + ptr); } return 0; @@ -4564,7 +4574,8 @@ static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev, netdev_for_each_lower_dev(lag_dev, dev, iter) { if (mlxsw_sp_port_dev_check(dev)) { - ret = mlxsw_sp_netdevice_port_event(dev, event, ptr); + ret = mlxsw_sp_netdevice_port_event(lag_dev, dev, event, + ptr); if (ret) return ret; } @@ -4807,6 +4818,7 @@ mlxsw_sp_port_vlan_vfid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) } static int mlxsw_sp_vport_bridge_join(struct mlxsw_sp_port *mlxsw_sp_vport, + struct net_device *brport_dev, struct net_device *br_dev) { struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); @@ -4848,7 +4860,9 @@ err_port_vid_learning_set: return err; } -static void mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport) +static void mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport, + struct net_device *brport_dev, + struct net_device *br_dev) { u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; @@ -4885,9 +4899,10 @@ mlxsw_sp_port_master_bridge_check(const struct mlxsw_sp_port *mlxsw_sp_port, return true; } -static int mlxsw_sp_netdevice_vport_event(struct net_device *dev, - unsigned long event, void *ptr, - u16 vid) +static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, + struct net_device *dev, + unsigned long event, void *ptr, + u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); struct netdev_notifier_changeupper_info *info = ptr; @@ -4919,9 +4934,12 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev, if (netif_is_bridge_master(upper_dev)) { if (info->linking) err = mlxsw_sp_vport_bridge_join(mlxsw_sp_vport, + vlan_dev, upper_dev); else - mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport); + mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport, + vlan_dev, + upper_dev); } else { err = -EINVAL; WARN_ON(1); @@ -4932,9 +4950,10 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev, return err; } -static int mlxsw_sp_netdevice_lag_vport_event(struct net_device *lag_dev, - unsigned long event, void *ptr, - u16 vid) +static int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev, + struct net_device *lag_dev, + unsigned long event, + void *ptr, u16 vid) { struct net_device *dev; struct list_head *iter; @@ -4942,8 +4961,9 @@ static int mlxsw_sp_netdevice_lag_vport_event(struct net_device *lag_dev, netdev_for_each_lower_dev(lag_dev, dev, iter) { if (mlxsw_sp_port_dev_check(dev)) { - ret = mlxsw_sp_netdevice_vport_event(dev, event, ptr, - vid); + ret = mlxsw_sp_netdevice_port_vlan_event(vlan_dev, dev, + event, ptr, + vid); if (ret) return ret; } @@ -4959,11 +4979,12 @@ static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev, u16 vid = vlan_dev_vlan_id(vlan_dev); if (mlxsw_sp_port_dev_check(real_dev)) - return mlxsw_sp_netdevice_vport_event(real_dev, event, ptr, - vid); + return mlxsw_sp_netdevice_port_vlan_event(vlan_dev, real_dev, + event, ptr, vid); else if (netif_is_lag_master(real_dev)) - return mlxsw_sp_netdevice_lag_vport_event(real_dev, event, ptr, - vid); + return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev, + real_dev, event, + ptr, vid); return 0; } @@ -4988,7 +5009,7 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused, else if (mlxsw_sp_is_vrf_event(event, ptr)) err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr); else if (mlxsw_sp_port_dev_check(dev)) - err = mlxsw_sp_netdevice_port_event(dev, event, ptr); + err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr); else if (netif_is_lag_master(dev)) err = mlxsw_sp_netdevice_lag_event(dev, event, ptr); else if (netif_is_bridge_master(dev)) -- cgit v1.2.3 From ed9ddd3aadac36869579d9075dd68067f87878cf Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:30 +0200 Subject: mlxsw: spectrum: Don't create FIDs upon creation of VLAN uppers Up until now we used to create FIDs upon the creation of VLAN uppers on top of the VLAN-aware bridge. This was done so that in case a router interface (RIF) was configured on top of the bridge, the FID would already be there. Instead, simplify the code and only create the FID upon RIF creation. This is an intermediary step towards the introduction of the common FID core, in which this code would be completely removed. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 95 +--------------------- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 16 +++- 2 files changed, 13 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 29d9439f6f12..f4c31f668e8d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3982,17 +3982,6 @@ int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid) return mlxsw_sp_port_fdb_flush_by_port_fid(mlxsw_sp_port, fid); } -static void mlxsw_sp_master_bridge_gone_sync(struct mlxsw_sp *mlxsw_sp) -{ - struct mlxsw_sp_fid *f, *tmp; - - list_for_each_entry_safe(f, tmp, &mlxsw_sp->fids, list) - if (--f->ref_count == 0) - mlxsw_sp_fid_destroy(mlxsw_sp, f); - else - WARN_ON_ONCE(1); -} - static bool mlxsw_sp_master_bridge_check(struct mlxsw_sp *mlxsw_sp, struct net_device *br_dev) { @@ -4014,15 +4003,8 @@ static void mlxsw_sp_master_bridge_dec(struct mlxsw_sp *mlxsw_sp) { struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp); - if (--master_bridge->ref_count == 0) { + if (--master_bridge->ref_count == 0) master_bridge->dev = NULL; - /* It's possible upper VLAN devices are still holding - * references to underlying FIDs. Drop the reference - * and release the resources if it was the last one. - * If it wasn't, then something bad happened. - */ - mlxsw_sp_master_bridge_gone_sync(mlxsw_sp); - } } static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, @@ -4584,79 +4566,6 @@ static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev, return 0; } -static int mlxsw_sp_master_bridge_vlan_link(struct mlxsw_sp *mlxsw_sp, - struct net_device *vlan_dev) -{ - u16 fid = vlan_dev_vlan_id(vlan_dev); - struct mlxsw_sp_fid *f; - - f = mlxsw_sp_fid_find(mlxsw_sp, fid); - if (!f) { - f = mlxsw_sp_fid_create(mlxsw_sp, fid); - if (IS_ERR(f)) - return PTR_ERR(f); - } - - f->ref_count++; - - return 0; -} - -static void mlxsw_sp_master_bridge_vlan_unlink(struct mlxsw_sp *mlxsw_sp, - struct net_device *vlan_dev) -{ - u16 fid = vlan_dev_vlan_id(vlan_dev); - struct mlxsw_sp_fid *f; - - f = mlxsw_sp_fid_find(mlxsw_sp, fid); - if (f && f->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); - if (f && --f->ref_count == 0) - mlxsw_sp_fid_destroy(mlxsw_sp, f); -} - -static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev, - unsigned long event, void *ptr) -{ - struct netdev_notifier_changeupper_info *info; - struct net_device *upper_dev; - struct mlxsw_sp *mlxsw_sp; - int err = 0; - - mlxsw_sp = mlxsw_sp_lower_get(br_dev); - if (!mlxsw_sp) - return 0; - - info = ptr; - - switch (event) { - case NETDEV_PRECHANGEUPPER: - upper_dev = info->upper_dev; - if (!is_vlan_dev(upper_dev)) - return -EINVAL; - if (is_vlan_dev(upper_dev) && - br_dev != mlxsw_sp_master_bridge(mlxsw_sp)->dev) - return -EINVAL; - break; - case NETDEV_CHANGEUPPER: - upper_dev = info->upper_dev; - if (is_vlan_dev(upper_dev)) { - if (info->linking) - err = mlxsw_sp_master_bridge_vlan_link(mlxsw_sp, - upper_dev); - else - mlxsw_sp_master_bridge_vlan_unlink(mlxsw_sp, - upper_dev); - } else { - err = -EINVAL; - WARN_ON(1); - } - break; - } - - return err; -} - static u16 mlxsw_sp_avail_vfid_get(const struct mlxsw_sp *mlxsw_sp) { return find_first_zero_bit(mlxsw_sp->vfids.mapped, @@ -5012,8 +4921,6 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused, err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr); else if (netif_is_lag_master(dev)) err = mlxsw_sp_netdevice_lag_event(dev, event, ptr); - else if (netif_is_bridge_master(dev)) - err = mlxsw_sp_netdevice_bridge_event(dev, event, ptr); else if (is_vlan_dev(dev)) err = mlxsw_sp_netdevice_vlan_event(dev, event, ptr); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index ef8e8a12c001..c582180e9354 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3239,16 +3239,24 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev, static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, struct net_device *l3_dev) { - u16 fid; + struct mlxsw_sp_fid *fid; + u16 fid_index; if (is_vlan_dev(l3_dev)) - fid = vlan_dev_vlan_id(l3_dev); + fid_index = vlan_dev_vlan_id(l3_dev); else if (mlxsw_sp_master_bridge(mlxsw_sp)->dev == l3_dev) - fid = 1; + fid_index = 1; else return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev); - return mlxsw_sp_fid_find(mlxsw_sp, fid); + fid = mlxsw_sp_fid_find(mlxsw_sp, fid_index); + if (fid) + return fid; + + fid = mlxsw_sp_fid_create(mlxsw_sp, fid_index); + if (IS_ERR(fid)) + return NULL; + return fid; } static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp) -- cgit v1.2.3 From c57529e1d5d882fbd6383163e2cb2e4ba3118174 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:31 +0200 Subject: mlxsw: spectrum: Replace vPorts with Port-VLAN As explained in the cover letter, since the introduction of the bridge offload in the mlxsw driver, information related to the offloaded bridge and bridge ports was stored in the individual port struct, mlxsw_sp_port. This lead to a bloated struct storing both physical properties of the port (e.g., autoneg status) as well as logical properties of an upper bridge port (e.g., learning, mrouter indication). While this might work well for simple devices, it proved to be hard to extend when stacked devices were taken into account and more advanced use-cases (e.g., IGMP snooping) considered. This patch removes the excess information from the above struct and instead stores it in more appropriate structs that represent the bridge port, the bridge itself and a VLAN configured on the bridge port. The membership of a port in a bridge is denoted using the Port-VLAN struct, which points to the bridge port and also member in the bridge VLAN group of the VLAN it represents. This allows us to completely remove the vPort abstraction and consolidate many of the code paths relating to VLAN-aware and unaware bridges. Note that the FID / vFID code is currently duplicated, but this will soon go away when the common FID core will be introduced. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 775 ++------- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 118 +- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 6 +- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 1769 ++++++++++++++------ 4 files changed, 1423 insertions(+), 1245 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index f4c31f668e8d..3b6056ae457a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1401,120 +1401,146 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) { enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - u16 vid, last_visited_vid; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_fid *fid; + u16 vid; int err; - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, vid, - vid); - if (err) { - last_visited_vid = vid; + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + fid = mlxsw_sp_port_vlan->fid; + + if (!fid || fid->fid >= MLXSW_SP_VFID_BASE) + continue; + + vid = mlxsw_sp_port_vlan->vid; + err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, + fid->fid, vid); + if (err) goto err_port_vid_to_fid_set; - } } err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); - if (err) { - last_visited_vid = VLAN_N_VID; - goto err_port_vid_to_fid_set; - } + if (err) + goto err_port_vp_mode_set; return 0; +err_port_vp_mode_set: err_port_vid_to_fid_set: - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, last_visited_vid) - mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, vid, + list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, + &mlxsw_sp_port->vlans_list, list) { + fid = mlxsw_sp_port_vlan->fid; + + if (!fid || fid->fid >= MLXSW_SP_VFID_BASE) + continue; + + vid = mlxsw_sp_port_vlan->vid; + mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid->fid, vid); + } return err; } int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) { enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - u16 vid; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; int err; err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); if (err) return err; - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, - vid, vid); - if (err) - return err; + list_for_each_entry_reverse(mlxsw_sp_port_vlan, + &mlxsw_sp_port->vlans_list, list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid || fid->fid >= MLXSW_SP_VFID_BASE) + continue; + + mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid->fid, + vid); } return 0; } -static struct mlxsw_sp_port * -mlxsw_sp_port_vport_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +static void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port) { - struct mlxsw_sp_port *mlxsw_sp_vport; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp; - mlxsw_sp_vport = kzalloc(sizeof(*mlxsw_sp_vport), GFP_KERNEL); - if (!mlxsw_sp_vport) - return NULL; - - /* dev will be set correctly after the VLAN device is linked - * with the real device. In case of bridge SELF invocation, dev - * will remain as is. - */ - mlxsw_sp_vport->dev = mlxsw_sp_port->dev; - mlxsw_sp_vport->mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - mlxsw_sp_vport->local_port = mlxsw_sp_port->local_port; - mlxsw_sp_vport->stp_state = BR_STATE_FORWARDING; - mlxsw_sp_vport->lagged = mlxsw_sp_port->lagged; - mlxsw_sp_vport->lag_id = mlxsw_sp_port->lag_id; - mlxsw_sp_vport->vport.vid = vid; - - list_add(&mlxsw_sp_vport->vport.list, &mlxsw_sp_port->vports_list); - - return mlxsw_sp_vport; -} - -static void mlxsw_sp_port_vport_destroy(struct mlxsw_sp_port *mlxsw_sp_vport) -{ - list_del(&mlxsw_sp_vport->vport.list); - kfree(mlxsw_sp_vport); + list_for_each_entry_safe(mlxsw_sp_port_vlan, tmp, + &mlxsw_sp_port->vlans_list, list) + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); } static struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + bool untagged = vid == 1; + int err; + + err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, untagged); + if (err) + return ERR_PTR(err); mlxsw_sp_port_vlan = kzalloc(sizeof(*mlxsw_sp_port_vlan), GFP_KERNEL); - if (!mlxsw_sp_port_vlan) - return ERR_PTR(-ENOMEM); + if (!mlxsw_sp_port_vlan) { + err = -ENOMEM; + goto err_port_vlan_alloc; + } mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port; mlxsw_sp_port_vlan->vid = vid; list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list); return mlxsw_sp_port_vlan; + +err_port_vlan_alloc: + mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); + return ERR_PTR(err); } static void mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { - struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + u16 vid = mlxsw_sp_port_vlan->vid; - if (fid && !WARN_ON(!fid->leave)) - fid->leave(mlxsw_sp_port_vlan); list_del(&mlxsw_sp_port_vlan->list); kfree(mlxsw_sp_port_vlan); + mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); +} + +struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (mlxsw_sp_port_vlan) + return mlxsw_sp_port_vlan; + + return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid); +} + +void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) +{ + if (mlxsw_sp_port_vlan->bridge_port) + mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); + else if (mlxsw_sp_port_vlan->fid) + mlxsw_sp_port_vlan->fid->leave(mlxsw_sp_port_vlan); + + mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); } static int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto, u16 vid) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_port *mlxsw_sp_vport; - bool untagged = vid == 1; - int err; /* VLAN 0 is added to HW filter when device goes up, but it is * reserved in our case, so simply return. @@ -1522,31 +1548,7 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, if (!vid) return 0; - mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); - if (mlxsw_sp_port_vlan) - return 0; - - mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid); - if (IS_ERR(mlxsw_sp_port_vlan)) - return PTR_ERR(mlxsw_sp_port_vlan); - - mlxsw_sp_vport = mlxsw_sp_port_vport_create(mlxsw_sp_port, vid); - if (!mlxsw_sp_vport) { - err = -ENOMEM; - goto err_port_vport_create; - } - - err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged); - if (err) - goto err_port_add_vid; - - return 0; - -err_port_add_vid: - mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); -err_port_vport_create: - mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); - return err; + return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_get(mlxsw_sp_port, vid)); } static int mlxsw_sp_port_kill_vid(struct net_device *dev, @@ -1554,8 +1556,6 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_port *mlxsw_sp_vport; - struct mlxsw_sp_fid *f; /* VLAN 0 is removed from HW filter when device goes down, but * it is reserved in our case, so simply return. @@ -1564,25 +1564,9 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, return 0; mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); - if (WARN_ON(!mlxsw_sp_port_vlan)) - return 0; - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (WARN_ON(!mlxsw_sp_vport)) + if (!mlxsw_sp_port_vlan) return 0; - - mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, false, false); - - /* Drop FID reference. If this was the last reference the - * resources will be freed. - */ - f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - if (f && !WARN_ON(!f->leave)) - f->leave(mlxsw_sp_port_vlan); - - mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); - - mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); return 0; } @@ -2720,24 +2704,12 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) return 0; } -static int mlxsw_sp_port_pvid_vport_create(struct mlxsw_sp_port *mlxsw_sp_port) -{ - mlxsw_sp_port->pvid = 1; - - return mlxsw_sp_port_add_vid(mlxsw_sp_port->dev, 0, 1); -} - -static int mlxsw_sp_port_pvid_vport_destroy(struct mlxsw_sp_port *mlxsw_sp_port) -{ - return mlxsw_sp_port_kill_vid(mlxsw_sp_port->dev, 0, 1); -} - static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, bool split, u8 module, u8 width, u8 lane) { + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_port *mlxsw_sp_port; struct net_device *dev; - size_t bytes; int err; dev = alloc_etherdev(sizeof(struct mlxsw_sp_port)); @@ -2748,24 +2720,13 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, mlxsw_sp_port->dev = dev; mlxsw_sp_port->mlxsw_sp = mlxsw_sp; mlxsw_sp_port->local_port = local_port; + mlxsw_sp_port->pvid = 1; mlxsw_sp_port->split = split; mlxsw_sp_port->mapping.module = module; mlxsw_sp_port->mapping.width = width; mlxsw_sp_port->mapping.lane = lane; mlxsw_sp_port->link.autoneg = 1; - bytes = DIV_ROUND_UP(VLAN_N_VID, BITS_PER_BYTE); - mlxsw_sp_port->active_vlans = kzalloc(bytes, GFP_KERNEL); - if (!mlxsw_sp_port->active_vlans) { - err = -ENOMEM; - goto err_port_active_vlans_alloc; - } - mlxsw_sp_port->untagged_vlans = kzalloc(bytes, GFP_KERNEL); - if (!mlxsw_sp_port->untagged_vlans) { - err = -ENOMEM; - goto err_port_untagged_vlans_alloc; - } INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list); - INIT_LIST_HEAD(&mlxsw_sp_port->vports_list); INIT_LIST_HEAD(&mlxsw_sp_port->mall_tc_list); mlxsw_sp_port->pcpu_stats = @@ -2877,11 +2838,11 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_port_vp_mode_set; } - err = mlxsw_sp_port_pvid_vport_create(mlxsw_sp_port); - if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create PVID vPort\n", + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); + if (IS_ERR(mlxsw_sp_port_vlan)) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n", mlxsw_sp_port->local_port); - goto err_port_pvid_vport_create; + goto err_port_vlan_get; } mlxsw_sp_port_switchdev_init(mlxsw_sp_port); @@ -2902,8 +2863,8 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, err_register_netdev: mlxsw_sp->ports[local_port] = NULL; mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); - mlxsw_sp_port_pvid_vport_destroy(mlxsw_sp_port); -err_port_pvid_vport_create: + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); +err_port_vlan_get: err_port_vp_mode_set: mlxsw_sp_port_dcb_fini(mlxsw_sp_port); err_port_dcb_init: @@ -2922,10 +2883,6 @@ err_alloc_hw_stats: err_alloc_sample: free_percpu(mlxsw_sp_port->pcpu_stats); err_alloc_stats: - kfree(mlxsw_sp_port->untagged_vlans); -err_port_untagged_vlans_alloc: - kfree(mlxsw_sp_port->active_vlans); -err_port_active_vlans_alloc: free_netdev(dev); return err; } @@ -2961,16 +2918,13 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */ mlxsw_sp->ports[local_port] = NULL; mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); - mlxsw_sp_port_pvid_vport_destroy(mlxsw_sp_port); + mlxsw_sp_port_vlan_flush(mlxsw_sp_port); mlxsw_sp_port_dcb_fini(mlxsw_sp_port); mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port); kfree(mlxsw_sp_port->hw_stats.cache); kfree(mlxsw_sp_port->sample); free_percpu(mlxsw_sp_port->pcpu_stats); - kfree(mlxsw_sp_port->untagged_vlans); - kfree(mlxsw_sp_port->active_vlans); - WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vports_list)); WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list)); free_netdev(mlxsw_sp_port->dev); } @@ -3622,16 +3576,14 @@ static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); } -static int mlxsw_sp_vfid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create); - static int mlxsw_sp_dummy_fid_init(struct mlxsw_sp *mlxsw_sp) { - return mlxsw_sp_vfid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, true); + return mlxsw_sp_fid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, true); } static void mlxsw_sp_dummy_fid_fini(struct mlxsw_sp *mlxsw_sp) { - mlxsw_sp_vfid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, false); + mlxsw_sp_fid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, false); } static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, @@ -3847,7 +3799,7 @@ static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev, void *data) return ret; } -static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev) +struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev) { struct mlxsw_sp_port *mlxsw_sp_port; @@ -3899,166 +3851,6 @@ void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port) dev_put(mlxsw_sp_port->dev); } -static bool mlxsw_sp_lag_port_fid_member(struct mlxsw_sp_port *lag_port, - u16 fid) -{ - if (mlxsw_sp_fid_is_vfid(fid)) - return mlxsw_sp_port_vport_find_by_fid(lag_port, fid); - else - return test_bit(fid, lag_port->active_vlans); -} - -static bool mlxsw_sp_port_fdb_should_flush(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - u8 local_port = mlxsw_sp_port->local_port; - u16 lag_id = mlxsw_sp_port->lag_id; - u64 max_lag_members; - int i, count = 0; - - if (!mlxsw_sp_port->lagged) - return true; - - max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core, - MAX_LAG_MEMBERS); - for (i = 0; i < max_lag_members; i++) { - struct mlxsw_sp_port *lag_port; - - lag_port = mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i); - if (!lag_port || lag_port->local_port == local_port) - continue; - if (mlxsw_sp_lag_port_fid_member(lag_port, fid)) - count++; - } - - return !count; -} - -static int -mlxsw_sp_port_fdb_flush_by_port_fid(const struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char sfdf_pl[MLXSW_REG_SFDF_LEN]; - - mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID); - mlxsw_reg_sfdf_fid_set(sfdf_pl, fid); - mlxsw_reg_sfdf_port_fid_system_port_set(sfdf_pl, - mlxsw_sp_port->local_port); - - netdev_dbg(mlxsw_sp_port->dev, "FDB flushed using Port=%d, FID=%d\n", - mlxsw_sp_port->local_port, fid); - - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); -} - -static int -mlxsw_sp_port_fdb_flush_by_lag_id_fid(const struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char sfdf_pl[MLXSW_REG_SFDF_LEN]; - - mlxsw_reg_sfdf_pack(sfdf_pl, MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID); - mlxsw_reg_sfdf_fid_set(sfdf_pl, fid); - mlxsw_reg_sfdf_lag_fid_lag_id_set(sfdf_pl, mlxsw_sp_port->lag_id); - - netdev_dbg(mlxsw_sp_port->dev, "FDB flushed using LAG ID=%d, FID=%d\n", - mlxsw_sp_port->lag_id, fid); - - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); -} - -int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid) -{ - if (!mlxsw_sp_port_fdb_should_flush(mlxsw_sp_port, fid)) - return 0; - - if (mlxsw_sp_port->lagged) - return mlxsw_sp_port_fdb_flush_by_lag_id_fid(mlxsw_sp_port, - fid); - else - return mlxsw_sp_port_fdb_flush_by_port_fid(mlxsw_sp_port, fid); -} - -static bool mlxsw_sp_master_bridge_check(struct mlxsw_sp *mlxsw_sp, - struct net_device *br_dev) -{ - struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp); - - return !master_bridge->dev || master_bridge->dev == br_dev; -} - -static void mlxsw_sp_master_bridge_inc(struct mlxsw_sp *mlxsw_sp, - struct net_device *br_dev) -{ - struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp); - - master_bridge->dev = br_dev; - master_bridge->ref_count++; -} - -static void mlxsw_sp_master_bridge_dec(struct mlxsw_sp *mlxsw_sp) -{ - struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp); - - if (--master_bridge->ref_count == 0) - master_bridge->dev = NULL; -} - -static int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, - struct net_device *brport_dev, - struct net_device *br_dev) -{ - struct net_device *dev = mlxsw_sp_port->dev; - int err; - - /* When port is not bridged untagged packets are tagged with - * PVID=VID=1, thereby creating an implicit VLAN interface in - * the device. Remove it and let bridge code take care of its - * own VLANs. - */ - err = mlxsw_sp_port_kill_vid(dev, 0, 1); - if (err) - return err; - - mlxsw_sp_master_bridge_inc(mlxsw_sp_port->mlxsw_sp, br_dev); - - mlxsw_sp_port->learning = 1; - mlxsw_sp_port->learning_sync = 1; - mlxsw_sp_port->uc_flood = 1; - mlxsw_sp_port->mc_flood = 1; - mlxsw_sp_port->mc_router = 0; - mlxsw_sp_port->mc_disabled = 1; - mlxsw_sp_port->bridged = 1; - - return 0; -} - -static void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, - struct net_device *brport_dev, - struct net_device *br_dev) -{ - struct net_device *dev = mlxsw_sp_port->dev; - - mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); - - mlxsw_sp_master_bridge_dec(mlxsw_sp_port->mlxsw_sp); - - mlxsw_sp_port->learning = 0; - mlxsw_sp_port->learning_sync = 0; - mlxsw_sp_port->uc_flood = 0; - mlxsw_sp_port->mc_flood = 0; - mlxsw_sp_port->mc_router = 0; - mlxsw_sp_port->bridged = 0; - - /* Add implicit VLAN interface in the device, so that untagged - * packets will be classified to the default vFID. - */ - mlxsw_sp_port_add_vid(dev, 0, 1); -} - static int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id) { char sldr_pl[MLXSW_REG_SLDR_LEN]; @@ -4177,55 +3969,11 @@ static int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp, return -EBUSY; } -static void -mlxsw_sp_port_pvid_vport_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, - struct net_device *lag_dev, u16 lag_id) -{ - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_port *mlxsw_sp_vport; - struct mlxsw_sp_fid *f; - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1); - if (WARN_ON(!mlxsw_sp_vport)) - return; - - mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); - /* If vPort is assigned a RIF, then leave it since it's no - * longer valid. - */ - f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - if (f) - f->leave(mlxsw_sp_port_vlan); - - mlxsw_sp_vport->lag_id = lag_id; - mlxsw_sp_vport->lagged = 1; - mlxsw_sp_vport->dev = lag_dev; -} - -static void -mlxsw_sp_port_pvid_vport_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port) -{ - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_port *mlxsw_sp_vport; - struct mlxsw_sp_fid *f; - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1); - if (WARN_ON(!mlxsw_sp_vport)) - return; - - mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); - f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - if (f) - f->leave(mlxsw_sp_port_vlan); - - mlxsw_sp_vport->dev = mlxsw_sp_port->dev; - mlxsw_sp_vport->lagged = 0; -} - static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, struct net_device *lag_dev) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_upper *lag; u16 lag_id; u8 port_index; @@ -4258,7 +4006,10 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port->lagged = 1; lag->ref_count++; - mlxsw_sp_port_pvid_vport_lag_join(mlxsw_sp_port, lag_dev, lag_id); + /* Port is no longer usable as a router interface */ + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); + if (mlxsw_sp_port_vlan->fid) + mlxsw_sp_port_vlan->fid->leave(mlxsw_sp_port_vlan); return 0; @@ -4285,10 +4036,8 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_lag_col_port_disable(mlxsw_sp_port, lag_id); mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id); - if (mlxsw_sp_port->bridged) { - mlxsw_sp_port_active_vlans_del(mlxsw_sp_port); - mlxsw_sp_port_bridge_leave(mlxsw_sp_port, NULL, NULL); - } + /* Any VLANs configured on the port are no longer valid */ + mlxsw_sp_port_vlan_flush(mlxsw_sp_port); if (lag->ref_count == 1) mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); @@ -4298,7 +4047,9 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port->lagged = 0; lag->ref_count--; - mlxsw_sp_port_pvid_vport_lag_leave(mlxsw_sp_port); + mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); + /* Make sure untagged frames are allowed to ingress */ + mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); } static int mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port *mlxsw_sp_port, @@ -4340,34 +4091,6 @@ static int mlxsw_sp_port_lag_changed(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_sp_port_lag_tx_en_set(mlxsw_sp_port, info->tx_enabled); } -static int mlxsw_sp_port_vlan_link(struct mlxsw_sp_port *mlxsw_sp_port, - struct net_device *vlan_dev) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - u16 vid = vlan_dev_vlan_id(vlan_dev); - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (WARN_ON(!mlxsw_sp_vport)) - return -EINVAL; - - mlxsw_sp_vport->dev = vlan_dev; - - return 0; -} - -static void mlxsw_sp_port_vlan_unlink(struct mlxsw_sp_port *mlxsw_sp_port, - struct net_device *vlan_dev) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - u16 vid = vlan_dev_vlan_id(vlan_dev); - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (WARN_ON(!mlxsw_sp_vport)) - return; - - mlxsw_sp_vport->dev = mlxsw_sp_port->dev; -} - static int mlxsw_sp_port_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) { @@ -4448,10 +4171,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, return -EINVAL; if (!info->linking) break; - /* HW limitation forbids to put ports to multiple bridges. */ - if (netif_is_bridge_master(upper_dev) && - !mlxsw_sp_master_bridge_check(mlxsw_sp, upper_dev)) - return -EINVAL; if (netif_is_lag_master(upper_dev) && !mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev, info->upper_info)) @@ -4468,14 +4187,7 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, break; case NETDEV_CHANGEUPPER: upper_dev = info->upper_dev; - if (is_vlan_dev(upper_dev)) { - if (info->linking) - err = mlxsw_sp_port_vlan_link(mlxsw_sp_port, - upper_dev); - else - mlxsw_sp_port_vlan_unlink(mlxsw_sp_port, - upper_dev); - } else if (netif_is_bridge_master(upper_dev)) { + if (netif_is_bridge_master(upper_dev)) { if (info->linking) err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, lower_dev, @@ -4496,9 +4208,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, err = mlxsw_sp_port_ovs_join(mlxsw_sp_port); else mlxsw_sp_port_ovs_leave(mlxsw_sp_port); - } else { - err = -EINVAL; - WARN_ON(1); } break; } @@ -4566,248 +4275,6 @@ static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev, return 0; } -static u16 mlxsw_sp_avail_vfid_get(const struct mlxsw_sp *mlxsw_sp) -{ - return find_first_zero_bit(mlxsw_sp->vfids.mapped, - MLXSW_SP_VFID_MAX); -} - -static int mlxsw_sp_vfid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create) -{ - char sfmr_pl[MLXSW_REG_SFMR_LEN]; - - mlxsw_reg_sfmr_pack(sfmr_pl, !create, fid, 0); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); -} - -static void -mlxsw_sp_port_vlan_vfid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); - -static struct mlxsw_sp_fid *mlxsw_sp_vfid_create(struct mlxsw_sp *mlxsw_sp, - struct net_device *br_dev) -{ - struct device *dev = mlxsw_sp->bus_info->dev; - struct mlxsw_sp_fid *f; - u16 vfid, fid; - int err; - - vfid = mlxsw_sp_avail_vfid_get(mlxsw_sp); - if (vfid == MLXSW_SP_VFID_MAX) { - dev_err(dev, "No available vFIDs\n"); - return ERR_PTR(-ERANGE); - } - - fid = mlxsw_sp_vfid_to_fid(vfid); - err = mlxsw_sp_vfid_op(mlxsw_sp, fid, true); - if (err) { - dev_err(dev, "Failed to create FID=%d\n", fid); - return ERR_PTR(err); - } - - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (!f) - goto err_allocate_vfid; - - f->leave = mlxsw_sp_port_vlan_vfid_leave; - f->fid = fid; - f->dev = br_dev; - - list_add(&f->list, &mlxsw_sp->vfids.list); - set_bit(vfid, mlxsw_sp->vfids.mapped); - - return f; - -err_allocate_vfid: - mlxsw_sp_vfid_op(mlxsw_sp, fid, false); - return ERR_PTR(-ENOMEM); -} - -static void mlxsw_sp_vfid_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *f) -{ - u16 vfid = mlxsw_sp_fid_to_vfid(f->fid); - u16 fid = f->fid; - - clear_bit(vfid, mlxsw_sp->vfids.mapped); - list_del(&f->list); - - if (f->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); - - kfree(f); - - mlxsw_sp_vfid_op(mlxsw_sp, fid, false); -} - -static int mlxsw_sp_vport_fid_map(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, - bool valid) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - - return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_vport, mt, valid, fid, - vid); -} - -static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport, - struct net_device *br_dev) -{ - struct mlxsw_sp_port *mlxsw_sp_port; - struct mlxsw_sp_fid *f; - int err; - - f = mlxsw_sp_vfid_find(mlxsw_sp_vport->mlxsw_sp, br_dev); - if (!f) { - f = mlxsw_sp_vfid_create(mlxsw_sp_vport->mlxsw_sp, br_dev); - if (IS_ERR(f)) - return PTR_ERR(f); - } - - err = mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, true); - if (err) - goto err_vport_flood_set; - - err = mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, true); - if (err) - goto err_vport_fid_map; - - mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); - if (mlxsw_sp_port->nr_port_vid_map++ == 0) { - err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); - if (err) - goto err_port_vp_mode_trans; - } - - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, f); - f->ref_count++; - - netdev_dbg(mlxsw_sp_vport->dev, "Joined FID=%d\n", f->fid); - - return 0; - -err_port_vp_mode_trans: - mlxsw_sp_port->nr_port_vid_map--; - mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false); -err_vport_fid_map: - mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false); -err_vport_flood_set: - if (!f->ref_count) - mlxsw_sp_vfid_destroy(mlxsw_sp_vport->mlxsw_sp, f); - return err; -} - -static void -mlxsw_sp_port_vlan_vfid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) -{ - struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp_port *mlxsw_sp_vport; - u16 vid = mlxsw_sp_port_vlan->vid; - struct mlxsw_sp_fid *f; - - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - - netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); - - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); - f->ref_count--; - - if (mlxsw_sp_port->nr_port_vid_map == 1) - mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); - mlxsw_sp_port->nr_port_vid_map--; - - mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false); - - mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false); - - mlxsw_sp_port_fdb_flush(mlxsw_sp_vport, f->fid); - - if (f->ref_count == 0) - mlxsw_sp_vfid_destroy(mlxsw_sp_vport->mlxsw_sp, f); -} - -static int mlxsw_sp_vport_bridge_join(struct mlxsw_sp_port *mlxsw_sp_vport, - struct net_device *brport_dev, - struct net_device *br_dev) -{ - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct net_device *dev = mlxsw_sp_vport->dev; - struct mlxsw_sp_port *mlxsw_sp_port; - int err; - - mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); - mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); - if (f && !WARN_ON(!f->leave)) - f->leave(mlxsw_sp_port_vlan); - - err = mlxsw_sp_vport_vfid_join(mlxsw_sp_vport, br_dev); - if (err) { - netdev_err(dev, "Failed to join vFID\n"); - return err; - } - - err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); - if (err) { - netdev_err(dev, "Failed to enable learning\n"); - goto err_port_vid_learning_set; - } - - mlxsw_sp_vport->learning = 1; - mlxsw_sp_vport->learning_sync = 1; - mlxsw_sp_vport->uc_flood = 1; - mlxsw_sp_vport->mc_flood = 1; - mlxsw_sp_vport->mc_router = 0; - mlxsw_sp_vport->mc_disabled = 1; - mlxsw_sp_vport->bridged = 1; - - return 0; - -err_port_vid_learning_set: - mlxsw_sp_port_vlan_vfid_leave(mlxsw_sp_port_vlan); - return err; -} - -static void mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport, - struct net_device *brport_dev, - struct net_device *br_dev) -{ - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_port *mlxsw_sp_port; - - mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, false); - - mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); - mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); - mlxsw_sp_port_vlan_vfid_leave(mlxsw_sp_port_vlan); - - mlxsw_sp_vport->learning = 0; - mlxsw_sp_vport->learning_sync = 0; - mlxsw_sp_vport->uc_flood = 0; - mlxsw_sp_vport->mc_flood = 0; - mlxsw_sp_vport->mc_router = 0; - mlxsw_sp_vport->bridged = 0; -} - -static bool -mlxsw_sp_port_master_bridge_check(const struct mlxsw_sp_port *mlxsw_sp_port, - const struct net_device *br_dev) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - - list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list, - vport.list) { - struct net_device *dev = mlxsw_sp_vport_dev_get(mlxsw_sp_vport); - - if (dev && dev == br_dev) - return false; - } - - return true; -} - static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, struct net_device *dev, unsigned long event, void *ptr, @@ -4815,40 +4282,26 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); struct netdev_notifier_changeupper_info *info = ptr; - struct mlxsw_sp_port *mlxsw_sp_vport; struct net_device *upper_dev; int err = 0; - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - if (!mlxsw_sp_vport) - return 0; - switch (event) { case NETDEV_PRECHANGEUPPER: upper_dev = info->upper_dev; if (!netif_is_bridge_master(upper_dev)) return -EINVAL; - if (!info->linking) - break; - /* We can't have multiple VLAN interfaces configured on - * the same port and being members in the same bridge. - */ - if (netif_is_bridge_master(upper_dev) && - !mlxsw_sp_port_master_bridge_check(mlxsw_sp_port, - upper_dev)) - return -EINVAL; break; case NETDEV_CHANGEUPPER: upper_dev = info->upper_dev; if (netif_is_bridge_master(upper_dev)) { if (info->linking) - err = mlxsw_sp_vport_bridge_join(mlxsw_sp_vport, - vlan_dev, - upper_dev); + err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, + vlan_dev, + upper_dev); else - mlxsw_sp_vport_bridge_leave(mlxsw_sp_vport, - vlan_dev, - upper_dev); + mlxsw_sp_port_bridge_leave(mlxsw_sp_port, + vlan_dev, + upper_dev); } else { err = -EINVAL; WARN_ON(1); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index b72ecf39a273..8c511ff19f84 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -204,11 +204,15 @@ struct mlxsw_sp_port_sample { bool truncate; }; +struct mlxsw_sp_bridge_port; + struct mlxsw_sp_port_vlan { struct list_head list; struct mlxsw_sp_port *mlxsw_sp_port; struct mlxsw_sp_fid *fid; u16 vid; + struct mlxsw_sp_bridge_port *bridge_port; + struct list_head bridge_vlan_node; }; struct mlxsw_sp_port { @@ -216,23 +220,10 @@ struct mlxsw_sp_port { struct mlxsw_sp_port_pcpu_stats __percpu *pcpu_stats; struct mlxsw_sp *mlxsw_sp; u8 local_port; - u8 stp_state; - u16 learning:1, - learning_sync:1, - uc_flood:1, - mc_flood:1, - mc_router:1, - mc_disabled:1, - bridged:1, - lagged:1, + u8 lagged:1, split:1; u16 pvid; u16 lag_id; - struct { - struct list_head list; - struct mlxsw_sp_fid *f; - u16 vid; - } vport; struct { u8 tx_pause:1, rx_pause:1, @@ -248,11 +239,6 @@ struct mlxsw_sp_port { u8 width; u8 lane; } mapping; - /* 802.1Q bridge VLANs */ - unsigned long *active_vlans; - unsigned long *untagged_vlans; - /* VLAN interfaces */ - struct list_head vports_list; /* TC handles */ struct list_head mall_tc_list; struct { @@ -267,6 +253,7 @@ struct mlxsw_sp_port { bool mlxsw_sp_port_dev_check(const struct net_device *dev); struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev); +struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev); struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); @@ -303,79 +290,6 @@ mlxsw_sp_port_vlan_find_by_vid(const struct mlxsw_sp_port *mlxsw_sp_port, return NULL; } -static inline u16 -mlxsw_sp_vport_vid_get(const struct mlxsw_sp_port *mlxsw_sp_vport) -{ - return mlxsw_sp_vport->vport.vid; -} - -static inline bool -mlxsw_sp_port_is_vport(const struct mlxsw_sp_port *mlxsw_sp_port) -{ - u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - - return vid != 0; -} - -static inline void mlxsw_sp_vport_fid_set(struct mlxsw_sp_port *mlxsw_sp_vport, - struct mlxsw_sp_fid *f) -{ - mlxsw_sp_vport->vport.f = f; -} - -static inline struct mlxsw_sp_fid * -mlxsw_sp_vport_fid_get(const struct mlxsw_sp_port *mlxsw_sp_vport) -{ - return mlxsw_sp_vport->vport.f; -} - -static inline struct net_device * -mlxsw_sp_vport_dev_get(const struct mlxsw_sp_port *mlxsw_sp_vport) -{ - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - - return f ? f->dev : NULL; -} - -static inline struct mlxsw_sp_port * -mlxsw_sp_port_vport_find(const struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - - list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list, - vport.list) { - if (mlxsw_sp_vport_vid_get(mlxsw_sp_vport) == vid) - return mlxsw_sp_vport; - } - - return NULL; -} - -static inline struct mlxsw_sp_port * -mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) -{ - struct mlxsw_sp_port *mlxsw_sp_vport; - - list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list, - vport.list) { - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); - - if (f && f->fid == fid) - return mlxsw_sp_vport; - } - - return NULL; -} - -static inline struct mlxsw_sp_port * -mlxsw_sp_vport_port(const struct mlxsw_sp_port *mlxsw_sp_vport) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; - - return mlxsw_sp->ports[mlxsw_sp_vport->local_port]; -} - static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp, u16 fid) { @@ -444,10 +358,8 @@ int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port, u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells); u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes); -struct mlxsw_sp_upper *mlxsw_sp_master_bridge(const struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); -int mlxsw_sp_port_vlan_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port); int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, @@ -455,14 +367,19 @@ int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, u16 vid_end, bool is_member, bool untagged); -int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, - bool set); -void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid); int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, bool adding); struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid); -void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f); +int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, bool valid); +void +mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); +int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, + struct net_device *br_dev); +void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, + struct net_device *br_dev); + int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index, bool dwrr, u8 dwrr_weight); @@ -481,6 +398,9 @@ int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port); int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port); +struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); #ifdef CONFIG_MLXSW_SPECTRUM_DCB diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index c582180e9354..7f1054f4511b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3244,7 +3244,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, if (is_vlan_dev(l3_dev)) fid_index = vlan_dev_vlan_id(l3_dev); - else if (mlxsw_sp_master_bridge(mlxsw_sp)->dev == l3_dev) + else if (br_vlan_enabled(l3_dev)) fid_index = 1; else return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev); @@ -3437,7 +3437,6 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev, unsigned long event) { struct net_device *real_dev = vlan_dev_real_dev(vlan_dev); - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(vlan_dev); u16 vid = vlan_dev_vlan_id(vlan_dev); if (mlxsw_sp_port_dev_check(real_dev)) @@ -3446,8 +3445,7 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev, else if (netif_is_lag_master(real_dev)) return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event, vid); - else if (netif_is_bridge_master(real_dev) && - mlxsw_sp_master_bridge(mlxsw_sp)->dev == real_dev) + else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev)) return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev, event); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 0d173bebcf3a..b17b224f2b1c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -52,6 +52,8 @@ #include "core.h" #include "reg.h" +struct mlxsw_sp_bridge_ops; + struct mlxsw_sp_bridge { struct mlxsw_sp *mlxsw_sp; struct { @@ -63,58 +65,376 @@ struct mlxsw_sp_bridge { #define MLXSW_SP_MAX_AGEING_TIME 1000000 #define MLXSW_SP_DEFAULT_AGEING_TIME 300 u32 ageing_time; - struct mlxsw_sp_upper master_bridge; + bool vlan_enabled_exists; + struct list_head bridges_list; struct list_head mids_list; DECLARE_BITMAP(mids_bitmap, MLXSW_SP_MID_MAX); + const struct mlxsw_sp_bridge_ops *bridge_8021q_ops; + const struct mlxsw_sp_bridge_ops *bridge_8021d_ops; +}; + +struct mlxsw_sp_bridge_device { + struct net_device *dev; + struct list_head list; + struct list_head ports_list; + u8 vlan_enabled:1, + multicast_enabled:1; + const struct mlxsw_sp_bridge_ops *ops; +}; + +struct mlxsw_sp_bridge_port { + struct net_device *dev; + struct mlxsw_sp_bridge_device *bridge_device; + struct list_head list; + struct list_head vlans_list; + unsigned int ref_count; + u8 stp_state; + unsigned long flags; + bool mrouter; + bool lagged; + union { + u16 lag_id; + u16 system_port; + }; +}; + +struct mlxsw_sp_bridge_vlan { + struct list_head list; + struct list_head port_vlan_list; + u16 vid; + u8 egress_untagged:1, + pvid:1; }; -struct mlxsw_sp_upper *mlxsw_sp_master_bridge(const struct mlxsw_sp *mlxsw_sp) +struct mlxsw_sp_bridge_ops { + int (*port_join)(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port); + void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port); +}; + +static int +mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_bridge_port *bridge_port, + u16 fid_index); + +static struct mlxsw_sp_bridge_device * +mlxsw_sp_bridge_device_find(const struct mlxsw_sp_bridge *bridge, + const struct net_device *br_dev) { - return &mlxsw_sp->bridge->master_bridge; + struct mlxsw_sp_bridge_device *bridge_device; + + list_for_each_entry(bridge_device, &bridge->bridges_list, list) + if (bridge_device->dev == br_dev) + return bridge_device; + + return NULL; } -static u16 mlxsw_sp_port_vid_to_fid_get(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid) +static struct mlxsw_sp_bridge_device * +mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge, + struct net_device *br_dev) { - struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_port); - u16 fid = vid; + struct device *dev = bridge->mlxsw_sp->bus_info->dev; + struct mlxsw_sp_bridge_device *bridge_device; + bool vlan_enabled = br_vlan_enabled(br_dev); - fid = f ? f->fid : fid; + if (vlan_enabled && bridge->vlan_enabled_exists) { + dev_err(dev, "Only one VLAN-aware bridge is supported\n"); + return ERR_PTR(-EINVAL); + } - if (!fid) - fid = mlxsw_sp_port->pvid; + bridge_device = kzalloc(sizeof(*bridge_device), GFP_KERNEL); + if (!bridge_device) + return ERR_PTR(-ENOMEM); + + bridge_device->dev = br_dev; + bridge_device->vlan_enabled = vlan_enabled; + bridge_device->multicast_enabled = br_multicast_enabled(br_dev); + INIT_LIST_HEAD(&bridge_device->ports_list); + if (vlan_enabled) { + bridge->vlan_enabled_exists = true; + bridge_device->ops = bridge->bridge_8021q_ops; + } else { + bridge_device->ops = bridge->bridge_8021d_ops; + } + list_add(&bridge_device->list, &bridge->bridges_list); - return fid; + return bridge_device; } -static struct mlxsw_sp_port * -mlxsw_sp_port_orig_get(struct net_device *dev, - struct mlxsw_sp_port *mlxsw_sp_port) +static void +mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge, + struct mlxsw_sp_bridge_device *bridge_device) { - struct mlxsw_sp_port *mlxsw_sp_vport; - struct mlxsw_sp_fid *fid; - u16 vid; + list_del(&bridge_device->list); + if (bridge_device->vlan_enabled) + bridge->vlan_enabled_exists = false; + WARN_ON(!list_empty(&bridge_device->ports_list)); + kfree(bridge_device); +} - if (netif_is_bridge_master(dev)) { - fid = mlxsw_sp_vfid_find(mlxsw_sp_port->mlxsw_sp, - dev); - if (fid) { - mlxsw_sp_vport = - mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port, - fid->fid); - WARN_ON(!mlxsw_sp_vport); - return mlxsw_sp_vport; - } +static struct mlxsw_sp_bridge_device * +mlxsw_sp_bridge_device_get(struct mlxsw_sp_bridge *bridge, + struct net_device *br_dev) +{ + struct mlxsw_sp_bridge_device *bridge_device; + + bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev); + if (bridge_device) + return bridge_device; + + return mlxsw_sp_bridge_device_create(bridge, br_dev); +} + +static void +mlxsw_sp_bridge_device_put(struct mlxsw_sp_bridge *bridge, + struct mlxsw_sp_bridge_device *bridge_device) +{ + if (list_empty(&bridge_device->ports_list)) + mlxsw_sp_bridge_device_destroy(bridge, bridge_device); +} + +static struct mlxsw_sp_bridge_port * +__mlxsw_sp_bridge_port_find(const struct mlxsw_sp_bridge_device *bridge_device, + const struct net_device *brport_dev) +{ + struct mlxsw_sp_bridge_port *bridge_port; + + list_for_each_entry(bridge_port, &bridge_device->ports_list, list) { + if (bridge_port->dev == brport_dev) + return bridge_port; + } + + return NULL; +} + +static struct mlxsw_sp_bridge_port * +mlxsw_sp_bridge_port_find(struct mlxsw_sp_bridge *bridge, + struct net_device *brport_dev) +{ + struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev); + struct mlxsw_sp_bridge_device *bridge_device; + + if (!br_dev) + return NULL; + + bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev); + if (!bridge_device) + return NULL; + + return __mlxsw_sp_bridge_port_find(bridge_device, brport_dev); +} + +static struct mlxsw_sp_bridge_port * +mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device, + struct net_device *brport_dev) +{ + struct mlxsw_sp_bridge_port *bridge_port; + struct mlxsw_sp_port *mlxsw_sp_port; + + bridge_port = kzalloc(sizeof(*bridge_port), GFP_KERNEL); + if (!bridge_port) + return NULL; + + mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(brport_dev); + bridge_port->lagged = mlxsw_sp_port->lagged; + if (bridge_port->lagged) + bridge_port->lag_id = mlxsw_sp_port->lag_id; + else + bridge_port->system_port = mlxsw_sp_port->local_port; + bridge_port->dev = brport_dev; + bridge_port->bridge_device = bridge_device; + bridge_port->stp_state = BR_STATE_DISABLED; + bridge_port->flags = BR_LEARNING | BR_FLOOD | BR_LEARNING_SYNC; + INIT_LIST_HEAD(&bridge_port->vlans_list); + list_add(&bridge_port->list, &bridge_device->ports_list); + bridge_port->ref_count = 1; + + return bridge_port; +} + +static void +mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port *bridge_port) +{ + list_del(&bridge_port->list); + WARN_ON(!list_empty(&bridge_port->vlans_list)); + kfree(bridge_port); +} + +static bool +mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port * + bridge_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_port->dev); + + /* In case ports were pulled from out of a bridged LAG, then + * it's possible the reference count isn't zero, yet the bridge + * port should be destroyed, as it's no longer an upper of ours. + */ + if (!mlxsw_sp && list_empty(&bridge_port->vlans_list)) + return true; + else if (bridge_port->ref_count == 0) + return true; + else + return false; +} + +static struct mlxsw_sp_bridge_port * +mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge, + struct net_device *brport_dev) +{ + struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev); + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + int err; + + bridge_port = mlxsw_sp_bridge_port_find(bridge, brport_dev); + if (bridge_port) { + bridge_port->ref_count++; + return bridge_port; + } + + bridge_device = mlxsw_sp_bridge_device_get(bridge, br_dev); + if (IS_ERR(bridge_device)) + return ERR_CAST(bridge_device); + + bridge_port = mlxsw_sp_bridge_port_create(bridge_device, brport_dev); + if (!bridge_port) { + err = -ENOMEM; + goto err_bridge_port_create; + } + + return bridge_port; + +err_bridge_port_create: + mlxsw_sp_bridge_device_put(bridge, bridge_device); + return ERR_PTR(err); +} + +static void mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge *bridge, + struct mlxsw_sp_bridge_port *bridge_port) +{ + struct mlxsw_sp_bridge_device *bridge_device; + + bridge_port->ref_count--; + if (!mlxsw_sp_bridge_port_should_destroy(bridge_port)) + return; + bridge_device = bridge_port->bridge_device; + mlxsw_sp_bridge_port_destroy(bridge_port); + mlxsw_sp_bridge_device_put(bridge, bridge_device); +} + +static struct mlxsw_sp_port_vlan * +mlxsw_sp_port_vlan_find_by_bridge(struct mlxsw_sp_port *mlxsw_sp_port, + const struct mlxsw_sp_bridge_device * + bridge_device, + u16 vid) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + if (!mlxsw_sp_port_vlan->bridge_port) + continue; + if (mlxsw_sp_port_vlan->bridge_port->bridge_device != + bridge_device) + continue; + if (bridge_device->vlan_enabled && + mlxsw_sp_port_vlan->vid != vid) + continue; + return mlxsw_sp_port_vlan; } - if (!is_vlan_dev(dev)) - return mlxsw_sp_port; + return NULL; +} + +static struct mlxsw_sp_port_vlan* +mlxsw_sp_port_vlan_find_by_fid(struct mlxsw_sp_port *mlxsw_sp_port, + u16 fid_index) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + + if (fid && fid->fid == fid_index) + return mlxsw_sp_port_vlan; + } + + return NULL; +} + +static struct mlxsw_sp_bridge_vlan * +mlxsw_sp_bridge_vlan_find(const struct mlxsw_sp_bridge_port *bridge_port, + u16 vid) +{ + struct mlxsw_sp_bridge_vlan *bridge_vlan; + + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { + if (bridge_vlan->vid == vid) + return bridge_vlan; + } + + return NULL; +} + +static struct mlxsw_sp_bridge_vlan * +mlxsw_sp_bridge_vlan_create(struct mlxsw_sp_bridge_port *bridge_port, u16 vid) +{ + struct mlxsw_sp_bridge_vlan *bridge_vlan; + + bridge_vlan = kzalloc(sizeof(*bridge_vlan), GFP_KERNEL); + if (!bridge_vlan) + return NULL; + + INIT_LIST_HEAD(&bridge_vlan->port_vlan_list); + bridge_vlan->vid = vid; + list_add(&bridge_vlan->list, &bridge_port->vlans_list); - vid = vlan_dev_vlan_id(dev); - mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid); - WARN_ON(!mlxsw_sp_vport); + return bridge_vlan; +} + +static void +mlxsw_sp_bridge_vlan_destroy(struct mlxsw_sp_bridge_vlan *bridge_vlan) +{ + list_del(&bridge_vlan->list); + WARN_ON(!list_empty(&bridge_vlan->port_vlan_list)); + kfree(bridge_vlan); +} + +static struct mlxsw_sp_bridge_vlan * +mlxsw_sp_bridge_vlan_get(struct mlxsw_sp_bridge_port *bridge_port, u16 vid) +{ + struct mlxsw_sp_bridge_vlan *bridge_vlan; + + bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); + if (bridge_vlan) + return bridge_vlan; - return mlxsw_sp_vport; + return mlxsw_sp_bridge_vlan_create(bridge_port, vid); +} + +static void mlxsw_sp_bridge_vlan_put(struct mlxsw_sp_bridge_vlan *bridge_vlan) +{ + if (list_empty(&bridge_vlan->port_vlan_list)) + mlxsw_sp_bridge_vlan_destroy(bridge_vlan); +} + +static void mlxsw_sp_port_bridge_flags_get(struct mlxsw_sp_bridge *bridge, + struct net_device *dev, + unsigned long *brport_flags) +{ + struct mlxsw_sp_bridge_port *bridge_port; + + bridge_port = mlxsw_sp_bridge_port_find(bridge, dev); + if (WARN_ON(!bridge_port)) + return; + + memcpy(brport_flags, &bridge_port->flags, sizeof(*brport_flags)); } static int mlxsw_sp_port_attr_get(struct net_device *dev, @@ -123,10 +443,6 @@ static int mlxsw_sp_port_attr_get(struct net_device *dev, struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - mlxsw_sp_port = mlxsw_sp_port_orig_get(attr->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; - switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: attr->u.ppid.id_len = sizeof(mlxsw_sp->base_mac); @@ -134,10 +450,8 @@ static int mlxsw_sp_port_attr_get(struct net_device *dev, attr->u.ppid.id_len); break; case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: - attr->u.brport_flags = - (mlxsw_sp_port->learning ? BR_LEARNING : 0) | - (mlxsw_sp_port->learning_sync ? BR_LEARNING_SYNC : 0) | - (mlxsw_sp_port->uc_flood ? BR_FLOOD : 0); + mlxsw_sp_port_bridge_flags_get(mlxsw_sp->bridge, attr->orig_dev, + &attr->u.brport_flags); break; default: return -EOPNOTSUPP; @@ -146,237 +460,213 @@ static int mlxsw_sp_port_attr_get(struct net_device *dev, return 0; } +static int +mlxsw_sp_port_bridge_vlan_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_vlan *bridge_vlan, + u8 state) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list, + bridge_vlan_node) { + if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port) + continue; + return mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, + bridge_vlan->vid, state); + } + + return 0; +} + static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_trans *trans, + struct net_device *orig_dev, u8 state) { - u16 vid; + struct mlxsw_sp_bridge_port *bridge_port; + struct mlxsw_sp_bridge_vlan *bridge_vlan; int err; if (switchdev_trans_ph_prepare(trans)) return 0; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, state); - if (err) - return err; - mlxsw_sp_port->stp_state = state; + /* It's possible we failed to enslave the port, yet this + * operation is executed due to it being deferred. + */ + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge, + orig_dev); + if (!bridge_port) return 0; - } - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, state); + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { + err = mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port, + bridge_vlan, state); if (err) - return err; + goto err_port_bridge_vlan_stp_set; } - mlxsw_sp_port->stp_state = state; + + bridge_port->stp_state = state; return 0; + +err_port_bridge_vlan_stp_set: + list_for_each_entry_continue_reverse(bridge_vlan, + &bridge_port->vlans_list, list) + mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port, bridge_vlan, + bridge_port->stp_state); + return err; } -static int __mlxsw_sp_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 idx_begin, u16 idx_end, - enum mlxsw_sp_flood_table table, - bool set) +static int mlxsw_sp_port_fid_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_table table, + bool member) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u16 local_port = mlxsw_sp_port->local_port; enum mlxsw_flood_table_type table_type; - u16 range = idx_end - idx_begin + 1; + u16 flood_index = fid->fid; char *sftr_pl; int err; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) + table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; + if (mlxsw_sp_fid_is_vfid(fid->fid)) { table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID; - else - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; + flood_index = mlxsw_sp_fid_to_vfid(fid->fid); + } sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); if (!sftr_pl) return -ENOMEM; - mlxsw_reg_sftr_pack(sftr_pl, table, idx_begin, - table_type, range, local_port, set); + mlxsw_reg_sftr_pack(sftr_pl, table, flood_index, table_type, 1, + local_port, member); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl); kfree(sftr_pl); return err; } -static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, - u16 idx_begin, u16 idx_end, bool uc_set, - bool bc_set, bool mc_set) +static int +mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_vlan *bridge_vlan, + enum mlxsw_sp_flood_table table, + bool member) { - int err; - - err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_UC, uc_set); - if (err) - return err; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_BC, bc_set); - if (err) - goto err_flood_bm_set; + list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list, + bridge_vlan_node) { + if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port) + continue; + return mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, + mlxsw_sp_port_vlan->fid, + table, member); + } - err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_MC, mc_set); - if (err) - goto err_flood_mc_set; return 0; - -err_flood_mc_set: - __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_BC, !bc_set); -err_flood_bm_set: - __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, idx_begin, idx_end, - MLXSW_SP_FLOOD_TABLE_UC, !uc_set); - return err; } -static int mlxsw_sp_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, - enum mlxsw_sp_flood_table table, - bool set) +static int +mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_port *bridge_port, + enum mlxsw_sp_flood_table table, + bool member) { - struct net_device *dev = mlxsw_sp_port->dev; - u16 vid, last_visited_vid; + struct mlxsw_sp_bridge_vlan *bridge_vlan; int err; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - u16 fid = mlxsw_sp_vport_fid_get(mlxsw_sp_port)->fid; - u16 vfid = mlxsw_sp_fid_to_vfid(fid); - - return __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vfid, - vfid, table, set); - } - - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vid, vid, - table, set); - if (err) { - last_visited_vid = vid; - goto err_port_flood_set; - } + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { + err = mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, + bridge_vlan, table, + member); + if (err) + goto err_port_bridge_vlan_flood_set; } return 0; -err_port_flood_set: - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, last_visited_vid) - __mlxsw_sp_port_flood_table_set(mlxsw_sp_port, vid, vid, table, - !set); - netdev_err(dev, "Failed to configure unicast flooding\n"); +err_port_bridge_vlan_flood_set: + list_for_each_entry_continue_reverse(bridge_vlan, + &bridge_port->vlans_list, list) + mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, bridge_vlan, + table, !member); return err; } -static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port, - struct switchdev_trans *trans, - bool mc_disabled) +static int +mlxsw_sp_port_bridge_vlan_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_vlan *bridge_vlan, + bool set) { - int set; - int err = 0; - - if (switchdev_trans_ph_prepare(trans)) - return 0; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + u16 vid = bridge_vlan->vid; - if (mlxsw_sp_port->mc_router != mlxsw_sp_port->mc_flood) { - set = mc_disabled ? - mlxsw_sp_port->mc_flood : mlxsw_sp_port->mc_router; - err = mlxsw_sp_port_flood_table_set(mlxsw_sp_port, - MLXSW_SP_FLOOD_TABLE_MC, - set); + list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list, + bridge_vlan_node) { + if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port) + continue; + return mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, set); } - if (!err) - mlxsw_sp_port->mc_disabled = mc_disabled; - - return err; -} - -int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, - bool set) -{ - bool mc_set = set; - u16 vfid; - - /* In case of vFIDs, index into the flooding table is relative to - * the start of the vFIDs range. - */ - vfid = mlxsw_sp_fid_to_vfid(fid); - - if (set) - mc_set = mlxsw_sp_vport->mc_disabled ? - mlxsw_sp_vport->mc_flood : mlxsw_sp_vport->mc_router; - - return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set, set, - mc_set); + return 0; } -static int mlxsw_sp_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, - bool set) +static int +mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_port *bridge_port, + bool set) { - u16 vid; + struct mlxsw_sp_bridge_vlan *bridge_vlan; int err; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - - return mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, set); - } - - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { - err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, set); + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { + err = mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port, + bridge_vlan, set); if (err) - goto err_port_vid_learning_set; + goto err_port_bridge_vlan_learning_set; } return 0; -err_port_vid_learning_set: - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) - mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, !set); +err_port_bridge_vlan_learning_set: + list_for_each_entry_continue_reverse(bridge_vlan, + &bridge_port->vlans_list, list) + mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port, + bridge_vlan, !set); return err; } static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_trans *trans, + struct net_device *orig_dev, unsigned long brport_flags) { - unsigned long learning = mlxsw_sp_port->learning ? BR_LEARNING : 0; - unsigned long uc_flood = mlxsw_sp_port->uc_flood ? BR_FLOOD : 0; + struct mlxsw_sp_bridge_port *bridge_port; int err; if (switchdev_trans_ph_prepare(trans)) return 0; - if ((uc_flood ^ brport_flags) & BR_FLOOD) { - err = mlxsw_sp_port_flood_table_set(mlxsw_sp_port, - MLXSW_SP_FLOOD_TABLE_UC, - !mlxsw_sp_port->uc_flood); - if (err) - return err; - } + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge, + orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; - if ((learning ^ brport_flags) & BR_LEARNING) { - err = mlxsw_sp_port_learning_set(mlxsw_sp_port, - !mlxsw_sp_port->learning); - if (err) - goto err_port_learning_set; - } + err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, + MLXSW_SP_FLOOD_TABLE_UC, + brport_flags & BR_FLOOD); + if (err) + return err; - mlxsw_sp_port->uc_flood = brport_flags & BR_FLOOD ? 1 : 0; - mlxsw_sp_port->learning = brport_flags & BR_LEARNING ? 1 : 0; - mlxsw_sp_port->learning_sync = brport_flags & BR_LEARNING_SYNC ? 1 : 0; + err = mlxsw_sp_bridge_port_learning_set(mlxsw_sp_port, bridge_port, + brport_flags & BR_LEARNING); + if (err) + return err; - return 0; + memcpy(&bridge_port->flags, &brport_flags, sizeof(brport_flags)); -err_port_learning_set: - if ((uc_flood ^ brport_flags) & BR_FLOOD) - mlxsw_sp_port_flood_table_set(mlxsw_sp_port, - MLXSW_SP_FLOOD_TABLE_UC, - mlxsw_sp_port->uc_flood); - return err; + return 0; } static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time) @@ -417,29 +707,77 @@ static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, bool vlan_enabled) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; - /* SWITCHDEV_TRANS_PREPARE phase */ - if ((!vlan_enabled) && - (mlxsw_sp->bridge->master_bridge.dev == orig_dev)) { - netdev_err(mlxsw_sp_port->dev, "Bridge must be vlan-aware\n"); + if (!switchdev_trans_ph_prepare(trans)) + return 0; + + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_device)) return -EINVAL; - } - return 0; + if (bridge_device->vlan_enabled == vlan_enabled) + return 0; + + netdev_err(bridge_device->dev, "VLAN filtering can't be changed for existing bridge\n"); + return -EINVAL; } static int mlxsw_sp_port_attr_mc_router_set(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_trans *trans, + struct net_device *orig_dev, bool is_port_mc_router) { + struct mlxsw_sp_bridge_port *bridge_port; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge, + orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + if (!bridge_port->bridge_device->multicast_enabled) + return 0; + + return mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, + MLXSW_SP_FLOOD_TABLE_MC, + is_port_mc_router); +} + +static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct switchdev_trans *trans, + struct net_device *orig_dev, + bool mc_disabled) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + int err; + if (switchdev_trans_ph_prepare(trans)) return 0; - mlxsw_sp_port->mc_router = is_port_mc_router; - if (!mlxsw_sp_port->mc_disabled) - return mlxsw_sp_port_flood_table_set(mlxsw_sp_port, - MLXSW_SP_FLOOD_TABLE_MC, - is_port_mc_router); + /* It's possible we failed to enslave the port, yet this + * operation is executed due to it being deferred. + */ + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev); + if (!bridge_device) + return 0; + + list_for_each_entry(bridge_port, &bridge_device->ports_list, list) { + enum mlxsw_sp_flood_table table = MLXSW_SP_FLOOD_TABLE_MC; + bool member = mc_disabled ? true : bridge_port->mrouter; + + err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, + bridge_port, table, + member); + if (err) + return err; + } + + bridge_device->multicast_enabled = !mc_disabled; return 0; } @@ -449,19 +787,17 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev, struct switchdev_trans *trans) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); - int err = 0; - - mlxsw_sp_port = mlxsw_sp_port_orig_get(attr->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; + int err; switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_STP_STATE: err = mlxsw_sp_port_attr_stp_state_set(mlxsw_sp_port, trans, + attr->orig_dev, attr->u.stp_state); break; case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: err = mlxsw_sp_port_attr_br_flags_set(mlxsw_sp_port, trans, + attr->orig_dev, attr->u.brport_flags); break; case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: @@ -475,10 +811,12 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev, break; case SWITCHDEV_ATTR_ID_PORT_MROUTER: err = mlxsw_sp_port_attr_mc_router_set(mlxsw_sp_port, trans, + attr->orig_dev, attr->u.mrouter); break; case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED: err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port, trans, + attr->orig_dev, attr->u.mc_disabled); break; default: @@ -489,178 +827,337 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev, return err; } -static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create) +static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) { + return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : + MLXSW_REG_SFMR_OP_DESTROY_FID; +} + +int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, bool valid) +{ + u16 fid_offset = fid_index < MLXSW_SP_VFID_BASE ? fid_index : 0; char sfmr_pl[MLXSW_REG_SFMR_LEN]; - mlxsw_reg_sfmr_pack(sfmr_pl, !create, fid, fid); + mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index, + fid_offset); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); } -static int mlxsw_sp_fid_map(struct mlxsw_sp *mlxsw_sp, u16 fid, bool valid) +static int mlxsw_sp_fid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + bool valid) { enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID; char svfa_pl[MLXSW_REG_SVFA_LEN]; - mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid, fid); + mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, fid_index); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); } -static struct mlxsw_sp_fid *mlxsw_sp_fid_alloc(u16 fid) +struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, + u16 fid_index) { - struct mlxsw_sp_fid *f; + struct mlxsw_sp_fid *fid; + int err; - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (!f) - return NULL; + err = mlxsw_sp_fid_op(mlxsw_sp, fid_index, true); + if (err) + return ERR_PTR(err); + + err = mlxsw_sp_fid_map(mlxsw_sp, fid_index, true); + if (err) + goto err_fid_map; + + fid = kzalloc(sizeof(*fid), GFP_KERNEL); + if (!fid) { + err = -ENOMEM; + goto err_allocate_fid; + } + + fid->fid = fid_index; + fid->ref_count = 1; + list_add(&fid->list, &mlxsw_sp->fids); + + return fid; + +err_allocate_fid: + mlxsw_sp_fid_map(mlxsw_sp, fid_index, false); +err_fid_map: + mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); + return ERR_PTR(err); +} - f->fid = fid; +static void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid) +{ + u16 fid_index = fid->fid; - return f; + list_del(&fid->list); + if (fid->rif) + mlxsw_sp_rif_bridge_destroy(mlxsw_sp, fid->rif); + kfree(fid); + mlxsw_sp_fid_map(mlxsw_sp, fid_index, false); + mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); } -struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid) +static struct mlxsw_sp_fid *mlxsw_sp_vfid_create(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev) { - struct mlxsw_sp_fid *f; + u16 vfid_index, fid_index; + struct mlxsw_sp_fid *fid; int err; - err = mlxsw_sp_fid_op(mlxsw_sp, fid, true); - if (err) - return ERR_PTR(err); + vfid_index = find_first_zero_bit(mlxsw_sp->vfids.mapped, + MLXSW_SP_VFID_MAX); + if (vfid_index == MLXSW_SP_VFID_MAX) + return ERR_PTR(-ENOBUFS); - /* Although all the ports member in the FID might be using a - * {Port, VID} to FID mapping, we create a global VID-to-FID - * mapping. This allows a port to transition to VLAN mode, - * knowing the global mapping exists. - */ - err = mlxsw_sp_fid_map(mlxsw_sp, fid, true); + fid_index = mlxsw_sp_vfid_to_fid(vfid_index); + err = mlxsw_sp_fid_op(mlxsw_sp, fid_index, true); if (err) - goto err_fid_map; + return ERR_PTR(err); - f = mlxsw_sp_fid_alloc(fid); - if (!f) { + fid = kzalloc(sizeof(*fid), GFP_KERNEL); + if (!fid) { err = -ENOMEM; goto err_allocate_fid; } - list_add(&f->list, &mlxsw_sp->fids); + fid->fid = fid_index; + fid->ref_count = 1; + fid->dev = dev; + list_add(&fid->list, &mlxsw_sp->vfids.list); + __set_bit(vfid_index, mlxsw_sp->vfids.mapped); + + return fid; - return f; +err_allocate_fid: + mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); + return ERR_PTR(err); +} + +static void mlxsw_sp_vfid_destroy(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid) +{ + u16 vfid_index = mlxsw_sp_fid_to_vfid(fid->fid); + u16 fid_index = fid->fid; + + __clear_bit(vfid_index, mlxsw_sp->vfids.mapped); + list_del(&fid->list); + if (fid->rif) + mlxsw_sp_rif_bridge_destroy(mlxsw_sp, fid->rif); + kfree(fid); + mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); +} + +static struct mlxsw_sp_fid *__mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, + u16 fid_index) +{ + struct mlxsw_sp_fid *fid; + + fid = mlxsw_sp_fid_find(mlxsw_sp, fid_index); + if (fid) { + fid->ref_count++; + return fid; + } + + return mlxsw_sp_fid_create(mlxsw_sp, fid_index); +} + +static struct mlxsw_sp_fid *mlxsw_sp_vfid_get(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev) +{ + struct mlxsw_sp_fid *fid; + + fid = mlxsw_sp_vfid_find(mlxsw_sp, dev); + if (fid) { + fid->ref_count++; + return fid; + } -err_allocate_fid: - mlxsw_sp_fid_map(mlxsw_sp, fid, false); -err_fid_map: - mlxsw_sp_fid_op(mlxsw_sp, fid, false); - return ERR_PTR(err); + return mlxsw_sp_vfid_create(mlxsw_sp, dev); } -void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f) +static struct mlxsw_sp_fid * +mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, u16 vid, + struct mlxsw_sp_bridge_device *bridge_device) { - u16 fid = f->fid; + if (bridge_device->vlan_enabled) + return __mlxsw_sp_fid_get(mlxsw_sp, vid); + else + return mlxsw_sp_vfid_get(mlxsw_sp, bridge_device->dev); +} - list_del(&f->list); +static void __mlxsw_sp_fid_put(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid) +{ + if (--fid->ref_count == 0) + mlxsw_sp_fid_destroy(mlxsw_sp, fid); +} - if (f->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); +static void mlxsw_sp_vfid_put(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid) +{ + if (--fid->ref_count == 0) + mlxsw_sp_vfid_destroy(mlxsw_sp, fid); +} - kfree(f); +static void mlxsw_sp_fid_put(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid *fid) +{ + if (!mlxsw_sp_fid_is_vfid(fid->fid)) + __mlxsw_sp_fid_put(mlxsw_sp, fid); + else + mlxsw_sp_vfid_put(mlxsw_sp, fid); +} - mlxsw_sp_fid_map(mlxsw_sp, fid, false); +static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port) +{ + const struct mlxsw_sp_bridge_device *bridge_device; - mlxsw_sp_fid_op(mlxsw_sp, fid, false); + bridge_device = bridge_port->bridge_device; + return !bridge_device->multicast_enabled ? true : bridge_port->mrouter; } -static int __mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) +static int __mlxsw_sp_port_vid_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid, u16 fid_index) { - struct mlxsw_sp_fid *f; + enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; + int err; - if (test_bit(fid, mlxsw_sp_port->active_vlans)) - return 0; + err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, fid_index, + vid); + if (err) + return err; - f = mlxsw_sp_fid_find(mlxsw_sp_port->mlxsw_sp, fid); - if (!f) { - f = mlxsw_sp_fid_create(mlxsw_sp_port->mlxsw_sp, fid); - if (IS_ERR(f)) - return PTR_ERR(f); + if (mlxsw_sp_port->nr_port_vid_map++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; } - f->ref_count++; + return 0; + +err_port_vp_mode_trans: + mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, vid); + return err; +} + +static int __mlxsw_sp_port_vid_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid, u16 fid_index) +{ + enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - netdev_dbg(mlxsw_sp_port->dev, "Joined FID=%d\n", fid); + if (mlxsw_sp_port->nr_port_vid_map == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp_port->nr_port_vid_map--; + + mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, vid); return 0; } -static void __mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) +static int mlxsw_sp_port_vid_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid, u16 fid_index) { - struct mlxsw_sp_fid *f; - - f = mlxsw_sp_fid_find(mlxsw_sp_port->mlxsw_sp, fid); - if (WARN_ON(!f)) - return; + enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - netdev_dbg(mlxsw_sp_port->dev, "Left FID=%d\n", fid); + if (mlxsw_sp_fid_is_vfid(fid_index)) + return __mlxsw_sp_port_vid_fid_map(mlxsw_sp_port, vid, + fid_index); - mlxsw_sp_port_fdb_flush(mlxsw_sp_port, fid); + if (mlxsw_sp_port->nr_port_vid_map == 0) + return 0; - if (--f->ref_count == 0) - mlxsw_sp_fid_destroy(mlxsw_sp_port->mlxsw_sp, f); + return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, fid_index, + fid_index); } -static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid, - bool valid) +static int mlxsw_sp_port_vid_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid, u16 fid_index) { enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - /* If port doesn't have vPorts, then it can use the global - * VID-to-FID mapping. - */ + if (mlxsw_sp_fid_is_vfid(fid_index)) + return __mlxsw_sp_port_vid_fid_unmap(mlxsw_sp_port, vid, + fid_index); + if (mlxsw_sp_port->nr_port_vid_map == 0) return 0; - return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, valid, fid, fid); + return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, + fid_index); } -static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid) +static int +mlxsw_sp_port_vlan_fid_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + struct mlxsw_sp_bridge_port *bridge_port) { - bool mc_flood; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u16 vid = mlxsw_sp_port_vlan->vid; + struct mlxsw_sp_fid *fid; int err; - err = __mlxsw_sp_port_fid_join(mlxsw_sp_port, fid); + fid = mlxsw_sp_fid_get(mlxsw_sp, vid, bridge_port->bridge_device); + if (IS_ERR(fid)) + return PTR_ERR(fid); + + err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, + MLXSW_SP_FLOOD_TABLE_UC, + bridge_port->flags & BR_FLOOD); if (err) - return err; + goto err_port_fid_uc_flood_set; - mc_flood = mlxsw_sp_port->mc_disabled ? - mlxsw_sp_port->mc_flood : mlxsw_sp_port->mc_router; + err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, + MLXSW_SP_FLOOD_TABLE_MC, + mlxsw_sp_mc_flood(bridge_port)); + if (err) + goto err_port_fid_mc_flood_set; - err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid, fid, - mlxsw_sp_port->uc_flood, true, - mc_flood); + err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, + MLXSW_SP_FLOOD_TABLE_BC, true); if (err) - goto err_port_flood_set; + goto err_port_fid_bc_flood_set; - err = mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, true); + err = mlxsw_sp_port_vid_fid_map(mlxsw_sp_port, vid, fid->fid); if (err) - goto err_port_fid_map; + goto err_port_vid_fid_map; + + mlxsw_sp_port_vlan->fid = fid; return 0; -err_port_fid_map: - __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid, fid, false, false, false); -err_port_flood_set: - __mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid); +err_port_vid_fid_map: + mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_BC, + false); +err_port_fid_bc_flood_set: + mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_MC, + false); +err_port_fid_mc_flood_set: + mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_UC, + false); +err_port_fid_uc_flood_set: + mlxsw_sp_fid_put(mlxsw_sp, fid); return err; } -static void mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port, - u16 fid) +static void +mlxsw_sp_port_vlan_fid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { - mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false); - __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid, fid, false, - false, false); - __mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid); + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + mlxsw_sp_port_vlan->fid = NULL; + mlxsw_sp_port_vid_fid_unmap(mlxsw_sp_port, vid, fid->fid); + mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_BC, + false); + mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_MC, + false); + mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_UC, + false); + mlxsw_sp_fid_put(mlxsw_sp, fid); } static u16 @@ -675,52 +1172,124 @@ mlxsw_sp_port_pvid_determine(const struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_sp_port->pvid; } -static int mlxsw_sp_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, - bool is_untagged, bool is_pvid) +static int +mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + struct mlxsw_sp_bridge_port *bridge_port) { - u16 pvid = mlxsw_sp_port_pvid_determine(mlxsw_sp_port, vid, is_pvid); - u16 old_pvid = mlxsw_sp_port->pvid; + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp_bridge_vlan *bridge_vlan; + u16 vid = mlxsw_sp_port_vlan->vid; int err; - err = mlxsw_sp_port_fid_join(mlxsw_sp_port, vid); - if (err) - return err; - - err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, - is_untagged); - if (err) - goto err_port_vlan_set; + /* No need to continue if only VLAN flags were changed */ + if (mlxsw_sp_port_vlan->bridge_port) + return 0; - err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid); + err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port); if (err) - goto err_port_pvid_set; + return err; err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, - mlxsw_sp_port->learning); + bridge_port->flags & BR_LEARNING); if (err) goto err_port_vid_learning_set; err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, - mlxsw_sp_port->stp_state); + bridge_port->stp_state); if (err) goto err_port_vid_stp_set; - if (is_untagged) - __set_bit(vid, mlxsw_sp_port->untagged_vlans); - else - __clear_bit(vid, mlxsw_sp_port->untagged_vlans); - __set_bit(vid, mlxsw_sp_port->active_vlans); + bridge_vlan = mlxsw_sp_bridge_vlan_get(bridge_port, vid); + if (!bridge_vlan) { + err = -ENOMEM; + goto err_bridge_vlan_get; + } + + list_add(&mlxsw_sp_port_vlan->bridge_vlan_node, + &bridge_vlan->port_vlan_list); + + mlxsw_sp_bridge_port_get(mlxsw_sp_port->mlxsw_sp->bridge, + bridge_port->dev); + mlxsw_sp_port_vlan->bridge_port = bridge_port; return 0; +err_bridge_vlan_get: + mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED); err_port_vid_stp_set: mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); err_port_vid_learning_set: + mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan); + return err; +} + +void +mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) +{ + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + struct mlxsw_sp_bridge_vlan *bridge_vlan; + struct mlxsw_sp_bridge_port *bridge_port; + u16 vid = mlxsw_sp_port_vlan->vid; + bool last; + + bridge_port = mlxsw_sp_port_vlan->bridge_port; + bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); + last = list_is_singular(&bridge_vlan->port_vlan_list); + + list_del(&mlxsw_sp_port_vlan->bridge_vlan_node); + mlxsw_sp_bridge_vlan_put(bridge_vlan); + mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED); + mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); + if (last) + mlxsw_sp_bridge_port_fdb_flush(mlxsw_sp_port->mlxsw_sp, + bridge_port, fid->fid); + mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan); + + mlxsw_sp_bridge_port_put(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port); + mlxsw_sp_port_vlan->bridge_port = NULL; +} + +static int +mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_port *bridge_port, + u16 vid, bool is_untagged, bool is_pvid) +{ + u16 pvid = mlxsw_sp_port_pvid_determine(mlxsw_sp_port, vid, is_pvid); + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_vlan *bridge_vlan; + u16 old_pvid = mlxsw_sp_port->pvid; + int err; + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, vid); + if (IS_ERR(mlxsw_sp_port_vlan)) + return PTR_ERR(mlxsw_sp_port_vlan); + + err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, + is_untagged); + if (err) + goto err_port_vlan_set; + + err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid); + if (err) + goto err_port_pvid_set; + + err = mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port); + if (err) + goto err_port_vlan_bridge_join; + + bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); + bridge_vlan->egress_untagged = is_untagged; + bridge_vlan->pvid = is_pvid; + + return 0; + +err_port_vlan_bridge_join: mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid); err_port_pvid_set: mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); err_port_vlan_set: - mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid); + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); return err; } @@ -730,16 +1299,27 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, { bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = vlan->obj.orig_dev; + struct mlxsw_sp_bridge_port *bridge_port; u16 vid; if (switchdev_trans_ph_prepare(trans)) return 0; + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + if (!bridge_port->bridge_device->vlan_enabled) + return 0; + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { int err; - err = mlxsw_sp_port_vlan_add(mlxsw_sp_port, vid, flag_untagged, - flag_pvid); + err = mlxsw_sp_bridge_port_vlan_add(mlxsw_sp_port, bridge_port, + vid, flag_untagged, + flag_pvid); if (err) return err; } @@ -747,6 +1327,29 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, return 0; } +static enum mlxsw_reg_sfdf_flush_type mlxsw_sp_fdb_flush_type(bool lagged) +{ + return lagged ? MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID : + MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID; +} + +static int +mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_bridge_port *bridge_port, + u16 fid_index) +{ + bool lagged = bridge_port->lagged; + char sfdf_pl[MLXSW_REG_SFDF_LEN]; + u16 system_port; + + system_port = lagged ? bridge_port->lag_id : bridge_port->system_port; + mlxsw_reg_sfdf_pack(sfdf_pl, mlxsw_sp_fdb_flush_type(lagged)); + mlxsw_reg_sfdf_fid_set(sfdf_pl, fid_index); + mlxsw_reg_sfdf_port_fid_system_port_set(sfdf_pl, system_port); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl); +} + static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic) { return dynamic ? MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_INGRESS : @@ -822,24 +1425,39 @@ mlxsw_sp_port_fdb_static_add(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_fdb *fdb, struct switchdev_trans *trans) { - u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, fdb->vid); - u16 lag_vid = 0; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = fdb->obj.orig_dev; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + u16 fid_index, vid; if (switchdev_trans_ph_prepare(trans)) return 0; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - lag_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - } + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + bridge_device = bridge_port->bridge_device; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, + bridge_device, + fdb->vid); + if (!mlxsw_sp_port_vlan) + return 0; + + fid_index = mlxsw_sp_port_vlan->fid->fid; + vid = mlxsw_sp_port_vlan->vid; if (!mlxsw_sp_port->lagged) - return mlxsw_sp_port_fdb_uc_op(mlxsw_sp_port->mlxsw_sp, + return mlxsw_sp_port_fdb_uc_op(mlxsw_sp, mlxsw_sp_port->local_port, - fdb->addr, fid, true, false); + fdb->addr, fid_index, true, + false); else - return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp_port->mlxsw_sp, + return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, mlxsw_sp_port->lag_id, - fdb->addr, fid, lag_vid, + fdb->addr, fid_index, vid, true, false); } @@ -939,17 +1557,34 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_trans *trans) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = mdb->obj.orig_dev; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct net_device *dev = mlxsw_sp_port->dev; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_mid *mid; - u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, mdb->vid); + u16 fid_index; int err = 0; if (switchdev_trans_ph_prepare(trans)) return 0; - mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid); + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + bridge_device = bridge_port->bridge_device; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, + bridge_device, + mdb->vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; + + fid_index = mlxsw_sp_port_vlan->fid->fid; + + mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index); if (!mid) { - mid = __mlxsw_sp_mc_alloc(mlxsw_sp, mdb->addr, fid); + mid = __mlxsw_sp_mc_alloc(mlxsw_sp, mdb->addr, fid_index); if (!mid) { netdev_err(dev, "Unable to allocate MC group\n"); return -ENOMEM; @@ -965,8 +1600,8 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port, } if (mid->ref_count == 1) { - err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid, mid->mid, - true); + err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid_index, + mid->mid, true); if (err) { netdev_err(dev, "Unable to set MC SFD\n"); goto err_out; @@ -987,15 +1622,8 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); int err = 0; - mlxsw_sp_port = mlxsw_sp_port_orig_get(obj->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; - switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) - return 0; - err = mlxsw_sp_port_vlans_add(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_VLAN(obj), trans); @@ -1018,57 +1646,78 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, return err; } -static void mlxsw_sp_port_vlan_del(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +static void +mlxsw_sp_bridge_port_vlan_del(struct mlxsw_sp_port *mlxsw_sp_port, + struct mlxsw_sp_bridge_port *bridge_port, u16 vid) { u16 pvid = mlxsw_sp_port->pvid == vid ? 0 : vid; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - __clear_bit(vid, mlxsw_sp_port->active_vlans); - mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED); - mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return; + + mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid); mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); - mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid); + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); } static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_vlan *vlan) { + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = vlan->obj.orig_dev; + struct mlxsw_sp_bridge_port *bridge_port; u16 vid; - for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) - mlxsw_sp_port_vlan_del(mlxsw_sp_port, vid); + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; - return 0; -} + if (!bridge_port->bridge_device->vlan_enabled) + return 0; -void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port) -{ - u16 vid; + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) + mlxsw_sp_bridge_port_vlan_del(mlxsw_sp_port, bridge_port, vid); - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) - mlxsw_sp_port_vlan_del(mlxsw_sp_port, vid); + return 0; } static int mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_fdb *fdb) { - u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, fdb->vid); - u16 lag_vid = 0; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = fdb->obj.orig_dev; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + u16 fid_index, vid; + + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - lag_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - } + bridge_device = bridge_port->bridge_device; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, + bridge_device, + fdb->vid); + if (!mlxsw_sp_port_vlan) + return 0; + + fid_index = mlxsw_sp_port_vlan->fid->fid; + vid = mlxsw_sp_port_vlan->vid; if (!mlxsw_sp_port->lagged) - return mlxsw_sp_port_fdb_uc_op(mlxsw_sp_port->mlxsw_sp, + return mlxsw_sp_port_fdb_uc_op(mlxsw_sp, mlxsw_sp_port->local_port, - fdb->addr, fid, - false, false); + fdb->addr, fid_index, false, + false); else - return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp_port->mlxsw_sp, + return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, mlxsw_sp_port->lag_id, - fdb->addr, fid, lag_vid, + fdb->addr, fid_index, vid, false, false); } @@ -1076,13 +1725,30 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_mdb *mdb) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = mdb->obj.orig_dev; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; struct net_device *dev = mlxsw_sp_port->dev; + struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_mid *mid; - u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, mdb->vid); + u16 fid_index; u16 mid_idx; int err = 0; - mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid); + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + bridge_device = bridge_port->bridge_device; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, + bridge_device, + mdb->vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; + + fid_index = mlxsw_sp_port_vlan->fid->fid; + + mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index); if (!mid) { netdev_err(dev, "Unable to remove port from MC DB\n"); return -EINVAL; @@ -1094,8 +1760,8 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port, mid_idx = mid->mid; if (__mlxsw_sp_mc_dec_ref(mlxsw_sp, mid)) { - err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid, mid_idx, - false); + err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid_index, + mid_idx, false); if (err) netdev_err(dev, "Unable to remove MC SFD\n"); } @@ -1109,15 +1775,8 @@ static int mlxsw_sp_port_obj_del(struct net_device *dev, struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); int err = 0; - mlxsw_sp_port = mlxsw_sp_port_orig_get(obj->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; - switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) - return 0; - err = mlxsw_sp_port_vlans_del(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_VLAN(obj)); break; @@ -1156,32 +1815,32 @@ static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb, - struct net_device *orig_dev) + switchdev_obj_dump_cb_t *cb) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct mlxsw_sp_port *tmp; - struct mlxsw_sp_fid *f; - u16 vport_fid; - char *sfd_pl; + struct net_device *orig_dev = fdb->obj.orig_dev; + struct mlxsw_sp_bridge_port *bridge_port; + u16 lag_id, fid_index; char mac[ETH_ALEN]; - u16 fid; - u8 local_port; - u16 lag_id; - u8 num_rec; int stored_err = 0; - int i; + char *sfd_pl; + u8 num_rec; int err; + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (!bridge_port) + return 0; + sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); if (!sfd_pl) return -ENOMEM; - f = mlxsw_sp_vport_fid_get(mlxsw_sp_port); - vport_fid = f ? f->fid : 0; - mlxsw_reg_sfd_pack(sfd_pl, MLXSW_REG_SFD_OP_QUERY_DUMP, 0); do { + struct mlxsw_sp_port *tmp; + u8 local_port; + int i; + mlxsw_reg_sfd_num_rec_set(sfd_pl, MLXSW_REG_SFD_REC_MAX_COUNT); err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); if (err) @@ -1198,48 +1857,44 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port, for (i = 0; i < num_rec; i++) { switch (mlxsw_reg_sfd_rec_type_get(sfd_pl, i)) { case MLXSW_REG_SFD_REC_TYPE_UNICAST: - mlxsw_reg_sfd_uc_unpack(sfd_pl, i, mac, &fid, + mlxsw_reg_sfd_uc_unpack(sfd_pl, i, mac, + &fid_index, &local_port); - if (local_port == mlxsw_sp_port->local_port) { - if (vport_fid && vport_fid == fid) - fdb->vid = 0; - else if (!vport_fid && - !mlxsw_sp_fid_is_vfid(fid)) - fdb->vid = fid; - else - continue; - ether_addr_copy(fdb->addr, mac); - fdb->ndm_state = NUD_REACHABLE; - err = cb(&fdb->obj); - if (err) - stored_err = err; - } + if (bridge_port->lagged) + continue; + if (bridge_port->system_port != local_port) + continue; + if (bridge_port->bridge_device->vlan_enabled) + fdb->vid = fid_index; + else + fdb->vid = 0; + ether_addr_copy(fdb->addr, mac); + fdb->ndm_state = NUD_REACHABLE; + err = cb(&fdb->obj); + if (err) + stored_err = err; break; case MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG: mlxsw_reg_sfd_uc_lag_unpack(sfd_pl, i, - mac, &fid, &lag_id); + mac, &fid_index, + &lag_id); + if (!bridge_port->lagged) + continue; + if (bridge_port->lag_id != lag_id) + continue; tmp = mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id); - if (tmp && tmp->local_port == - mlxsw_sp_port->local_port) { - /* LAG records can only point to LAG - * devices or VLAN devices on top. - */ - if (!netif_is_lag_master(orig_dev) && - !is_vlan_dev(orig_dev)) - continue; - if (vport_fid && vport_fid == fid) - fdb->vid = 0; - else if (!vport_fid && - !mlxsw_sp_fid_is_vfid(fid)) - fdb->vid = fid; - else - continue; - ether_addr_copy(fdb->addr, mac); - fdb->ndm_state = NUD_REACHABLE; - err = cb(&fdb->obj); - if (err) - stored_err = err; - } + if (tmp->local_port != + mlxsw_sp_port->local_port) + continue; + if (bridge_port->bridge_device->vlan_enabled) + fdb->vid = fid_index; + else + fdb->vid = 0; + ether_addr_copy(fdb->addr, mac); + fdb->ndm_state = NUD_REACHABLE; + err = cb(&fdb->obj); + if (err) + stored_err = err; break; } } @@ -1254,28 +1909,32 @@ static int mlxsw_sp_port_vlan_dump(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_obj_port_vlan *vlan, switchdev_obj_dump_cb_t *cb) { - u16 vid; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = vlan->obj.orig_dev; + struct mlxsw_sp_bridge_port *bridge_port; + struct mlxsw_sp_bridge_vlan *bridge_vlan; int err = 0; - if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) { - vlan->flags = 0; - vlan->vid_begin = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - vlan->vid_end = mlxsw_sp_vport_vid_get(mlxsw_sp_port); - return cb(&vlan->obj); - } + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (WARN_ON(!bridge_port)) + return -EINVAL; + + if (!bridge_port->bridge_device->vlan_enabled) + return 0; - for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) { + list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { vlan->flags = 0; - if (vid == mlxsw_sp_port->pvid) + if (bridge_vlan->pvid) vlan->flags |= BRIDGE_VLAN_INFO_PVID; - if (test_bit(vid, mlxsw_sp_port->untagged_vlans)) + if (bridge_vlan->egress_untagged) vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; - vlan->vid_begin = vid; - vlan->vid_end = vid; + vlan->vid_begin = bridge_vlan->vid; + vlan->vid_end = bridge_vlan->vid; err = cb(&vlan->obj); if (err) break; } + return err; } @@ -1286,10 +1945,6 @@ static int mlxsw_sp_port_obj_dump(struct net_device *dev, struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); int err = 0; - mlxsw_sp_port = mlxsw_sp_port_orig_get(obj->orig_dev, mlxsw_sp_port); - if (!mlxsw_sp_port) - return -EINVAL; - switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: err = mlxsw_sp_port_vlan_dump(mlxsw_sp_port, @@ -1297,8 +1952,7 @@ static int mlxsw_sp_port_obj_dump(struct net_device *dev, break; case SWITCHDEV_OBJ_ID_PORT_FDB: err = mlxsw_sp_port_fdb_dump(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_FDB(obj), cb, - obj->orig_dev); + SWITCHDEV_OBJ_PORT_FDB(obj), cb); break; default: err = -EOPNOTSUPP; @@ -1316,6 +1970,154 @@ static const struct switchdev_ops mlxsw_sp_port_switchdev_ops = { .switchdev_port_obj_dump = mlxsw_sp_port_obj_dump, }; +static int +mlxsw_sp_bridge_8021q_port_join(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + if (is_vlan_dev(bridge_port->dev)) + return -EINVAL; + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; + + /* Let VLAN-aware bridge take care of its own VLANs */ + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); + + return 0; +} + +static void +mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); + /* Make sure untagged frames are allowed to ingress */ + mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); +} + +static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = { + .port_join = mlxsw_sp_bridge_8021q_port_join, + .port_leave = mlxsw_sp_bridge_8021q_port_leave, +}; + +static bool +mlxsw_sp_port_is_br_member(const struct mlxsw_sp_port *mlxsw_sp_port, + const struct net_device *br_dev) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + if (mlxsw_sp_port_vlan->bridge_port && + mlxsw_sp_port_vlan->bridge_port->bridge_device->dev == + br_dev) + return true; + } + + return false; +} + +static int +mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_fid *fid; + u16 vid; + + if (!is_vlan_dev(bridge_port->dev)) + return -EINVAL; + vid = vlan_dev_vlan_id(bridge_port->dev); + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; + fid = mlxsw_sp_port_vlan->fid; + + if (mlxsw_sp_port_is_br_member(mlxsw_sp_port, bridge_device->dev)) { + netdev_err(mlxsw_sp_port->dev, "Can't bridge VLAN uppers of the same port\n"); + return -EINVAL; + } + + /* Port is no longer usable as a router interface */ + if (fid) + fid->leave(mlxsw_sp_port_vlan); + + return mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port); +} + +static void +mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device, + struct mlxsw_sp_bridge_port *bridge_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + u16 vid = vlan_dev_vlan_id(bridge_port->dev); + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return; + + mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); +} + +static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = { + .port_join = mlxsw_sp_bridge_8021d_port_join, + .port_leave = mlxsw_sp_bridge_8021d_port_leave, +}; + +int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, + struct net_device *br_dev) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + int err; + + bridge_port = mlxsw_sp_bridge_port_get(mlxsw_sp->bridge, brport_dev); + if (IS_ERR(bridge_port)) + return PTR_ERR(bridge_port); + bridge_device = bridge_port->bridge_device; + + err = bridge_device->ops->port_join(bridge_device, bridge_port, + mlxsw_sp_port); + if (err) + goto err_port_join; + + return 0; + +err_port_join: + mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port); + return err; +} + +void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *brport_dev, + struct net_device *br_dev) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); + if (!bridge_device) + return; + bridge_port = __mlxsw_sp_bridge_port_find(bridge_device, brport_dev); + if (!bridge_port) + return; + + bridge_device->ops->port_leave(bridge_device, bridge_port, + mlxsw_sp_port); + mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port); +} + static void mlxsw_sp_fdb_call_notifiers(bool learning_sync, bool adding, char *mac, u16 vid, struct net_device *dev) @@ -1335,6 +2137,9 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, char *sfn_pl, int rec_index, bool adding) { + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_port *mlxsw_sp_port; char mac[ETH_ALEN]; u8 local_port; @@ -1349,22 +2154,21 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, goto just_remove; } - if (mlxsw_sp_fid_is_vfid(fid)) { - struct mlxsw_sp_port *mlxsw_sp_vport; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid); + if (!mlxsw_sp_port_vlan) { + netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n"); + goto just_remove; + } - mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port, - fid); - if (!mlxsw_sp_vport) { - netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n"); - goto just_remove; - } - vid = 0; - /* Override the physical port with the vPort. */ - mlxsw_sp_port = mlxsw_sp_vport; - } else { - vid = fid; + bridge_port = mlxsw_sp_port_vlan->bridge_port; + if (!bridge_port) { + netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n"); + goto just_remove; } + bridge_device = bridge_port->bridge_device; + vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0; + do_fdb_op: err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding, true); @@ -1375,8 +2179,8 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning_sync, - adding, mac, vid, mlxsw_sp_port->dev); + mlxsw_sp_fdb_call_notifiers(bridge_port->flags & BR_LEARNING_SYNC, + adding, mac, vid, bridge_port->dev); return; just_remove: @@ -1389,8 +2193,10 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp, char *sfn_pl, int rec_index, bool adding) { + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_port *mlxsw_sp_port; - struct net_device *dev; char mac[ETH_ALEN]; u16 lag_vid = 0; u16 lag_id; @@ -1405,26 +2211,22 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp, goto just_remove; } - if (mlxsw_sp_fid_is_vfid(fid)) { - struct mlxsw_sp_port *mlxsw_sp_vport; - - mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port, - fid); - if (!mlxsw_sp_vport) { - netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n"); - goto just_remove; - } + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid); + if (!mlxsw_sp_port_vlan) { + netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n"); + goto just_remove; + } - lag_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); - dev = mlxsw_sp_vport->dev; - vid = 0; - /* Override the physical port with the vPort. */ - mlxsw_sp_port = mlxsw_sp_vport; - } else { - dev = mlxsw_sp_lag_get(mlxsw_sp, lag_id)->dev; - vid = fid; + bridge_port = mlxsw_sp_port_vlan->bridge_port; + if (!bridge_port) { + netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n"); + goto just_remove; } + bridge_device = bridge_port->bridge_device; + vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0; + lag_vid = mlxsw_sp_port_vlan->vid; + do_fdb_op: err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid, adding, true); @@ -1435,8 +2237,8 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning_sync, adding, mac, - vid, dev); + mlxsw_sp_fdb_call_notifiers(bridge_port->flags & BR_LEARNING_SYNC, + adding, mac, vid, bridge_port->dev); return; just_remove: @@ -1540,8 +2342,12 @@ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp) mlxsw_sp->bridge = bridge; bridge->mlxsw_sp = mlxsw_sp; + INIT_LIST_HEAD(&mlxsw_sp->bridge->bridges_list); INIT_LIST_HEAD(&mlxsw_sp->bridge->mids_list); + bridge->bridge_8021q_ops = &mlxsw_sp_bridge_8021q_ops; + bridge->bridge_8021d_ops = &mlxsw_sp_bridge_8021d_ops; + return mlxsw_sp_fdb_init(mlxsw_sp); } @@ -1549,6 +2355,7 @@ void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp) { mlxsw_sp_fdb_fini(mlxsw_sp); WARN_ON(!list_empty(&mlxsw_sp->bridge->mids_list)); + WARN_ON(!list_empty(&mlxsw_sp->bridge->bridges_list)); kfree(mlxsw_sp->bridge); } -- cgit v1.2.3 From caa3ddf8e39022ee2cd87835bc400b9c516fcd95 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:32 +0200 Subject: mlxsw: spectrum_router: Allocate FID prior to RIF configuration The following patches are going to re-arrange the FID and RIF code, so that when the RIF is configured to the device based on the information present in the RIF struct (which points to a FID). For this reason, move the FID allocation to just before the RIF configuration. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 25 +++++++++++----------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 7f1054f4511b..c8d136c51444 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3018,26 +3018,26 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) return ERR_PTR(-ERANGE); + fid = mlxsw_sp_rif_sp_to_fid(rif_index); + f = mlxsw_sp_rfid_alloc(fid, l3_dev); + if (!f) + return ERR_PTR(-ENOMEM); + vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); - if (IS_ERR(vr)) - return ERR_CAST(vr); + if (IS_ERR(vr)) { + err = PTR_ERR(vr); + goto err_vr_get; + } err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, rif_index, true); if (err) goto err_port_vlan_rif_sp_op; - fid = mlxsw_sp_rif_sp_to_fid(rif_index); err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true); if (err) goto err_rif_fdb_op; - f = mlxsw_sp_rfid_alloc(fid, l3_dev); - if (!f) { - err = -ENOMEM; - goto err_rfid_alloc; - } - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f); if (!rif) { err = -ENOMEM; @@ -3060,14 +3060,14 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, return rif; err_rif_alloc: - kfree(f); -err_rfid_alloc: mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); err_rif_fdb_op: mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, rif_index, false); err_port_vlan_rif_sp_op: mlxsw_sp_vr_put(vr); +err_vr_get: + kfree(f); return ERR_PTR(err); } @@ -3094,14 +3094,13 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, kfree(rif); - kfree(f); - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, rif_index, false); mlxsw_sp_vr_put(vr); + kfree(f); } static int -- cgit v1.2.3 From a13a594da06c437afa546888ddba64d3bd2db06d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:33 +0200 Subject: mlxsw: spectrum_router: Allocate RIF prior to its configuration In the following patches the RIF's configuration function is going to expect a RIF struct with all the necessary information. Therefore, allocate the RIF just before it's configured to the device. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 40 ++++++++++------------ 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index c8d136c51444..e81d45c8a827 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3029,6 +3029,12 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, goto err_vr_get; } + rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f); + if (!rif) { + err = -ENOMEM; + goto err_rif_alloc; + } + err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, rif_index, true); if (err) @@ -3038,12 +3044,6 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, if (err) goto err_rif_fdb_op; - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f); - if (!rif) { - err = -ENOMEM; - goto err_rif_alloc; - } - if (devlink_dpipe_table_counter_enabled(priv_to_devlink(mlxsw_sp->core), MLXSW_SP_DPIPE_TABLE_NAME_ERIF)) { err = mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, @@ -3059,12 +3059,12 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, return rif; -err_rif_alloc: - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); err_rif_fdb_op: mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, rif_index, false); err_port_vlan_rif_sp_op: + kfree(rif); +err_rif_alloc: mlxsw_sp_vr_put(vr); err_vr_get: kfree(f); @@ -3092,13 +3092,11 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, mlxsw_sp->router->rifs[rif_index] = NULL; f->rif = NULL; - kfree(rif); - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, rif_index, false); - + kfree(rif); mlxsw_sp_vr_put(vr); kfree(f); } @@ -3343,6 +3341,12 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, if (err) goto err_port_flood_set; + rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f); + if (!rif) { + err = -ENOMEM; + goto err_rif_alloc; + } + err = mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index, true); if (err) @@ -3352,12 +3356,6 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, if (err) goto err_rif_fdb_op; - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f); - if (!rif) { - err = -ENOMEM; - goto err_rif_alloc; - } - f->rif = rif; mlxsw_sp->router->rifs[rif_index] = rif; vr->rif_count++; @@ -3366,12 +3364,12 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, return 0; -err_rif_alloc: - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false); err_rif_fdb_op: mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index, false); err_rif_bridge_op: + kfree(rif); +err_rif_alloc: mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); err_port_flood_set: mlxsw_sp_vr_put(vr); @@ -3392,13 +3390,13 @@ void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, mlxsw_sp->router->rifs[rif_index] = NULL; f->rif = NULL; - kfree(rif); - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false); mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index, false); + kfree(rif); + mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); mlxsw_sp_vr_put(vr); -- cgit v1.2.3 From 4d93ceebf09b0e85adc8048752eea39785b300bf Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:34 +0200 Subject: mlxsw: spectrum_router: Extend the RIF struct Currently, when a Subport RIF is configured, the LAG status and VLAN of the underlying port are read from the port itself. This is problematic, as we would like to have common code to configure all types of RIFs, which aren't necessarily bound to a port. Instead, embed the RIF in a struct specific to the Subport type, which contains all the necessary information. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 31 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index e81d45c8a827..28ba5d323a37 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -97,6 +97,16 @@ struct mlxsw_sp_rif { bool counter_egress_valid; }; +struct mlxsw_sp_rif_subport { + struct mlxsw_sp_rif common; + union { + u16 system_port; + u16 lag_id; + }; + u16 vid; + bool lag; +}; + static unsigned int * mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif, enum mlxsw_sp_rif_counter_dir dir) @@ -2965,11 +2975,13 @@ mlxsw_sp_rfid_alloc(u16 fid, struct net_device *l3_dev) static struct mlxsw_sp_rif * mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, - struct mlxsw_sp_fid *f) + struct mlxsw_sp_fid *f, bool is_subport) { + size_t size = is_subport ? sizeof(struct mlxsw_sp_rif_subport) : + sizeof(struct mlxsw_sp_rif); struct mlxsw_sp_rif *rif; - rif = kzalloc(sizeof(*rif), GFP_KERNEL); + rif = kzalloc(size, GFP_KERNEL); if (!rif) return NULL; @@ -3007,6 +3019,7 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_rif_subport *rif_subport; u32 tb_id = l3mdev_fib_table(l3_dev); struct mlxsw_sp_vr *vr; struct mlxsw_sp_fid *f; @@ -3029,12 +3042,22 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, goto err_vr_get; } - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f); + rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, true); if (!rif) { err = -ENOMEM; goto err_rif_alloc; } + rif_subport = container_of(rif, struct mlxsw_sp_rif_subport, common); + rif_subport->vid = mlxsw_sp_port_vlan->vid; + if (mlxsw_sp_port->lagged) { + rif_subport->lag = true; + rif_subport->lag_id = mlxsw_sp_port->lag_id; + } else { + rif_subport->lag = false; + rif_subport->system_port = mlxsw_sp_port->local_port; + } + err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, rif_index, true); if (err) @@ -3341,7 +3364,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, if (err) goto err_port_flood_set; - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f); + rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, false); if (!rif) { err = -ENOMEM; goto err_rif_alloc; -- cgit v1.2.3 From ab01ae916911d11af9f4375b8276378b9474400c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:35 +0200 Subject: mlxsw: spectrum_router: Configure RIFs based on RIF struct All the information necessary for the configuration of RIFs can now be found in the RIF struct itself, so reduce the arguments list. This gets us one step closer to the common RIF core. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 56 +++++++++------------- 1 file changed, 23 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 28ba5d323a37..73cc5195068f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2928,22 +2928,20 @@ static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp) } static int -mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, - u16 vr_id, struct net_device *l3_dev, - u16 rif_index, bool create) +mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_rif *rif, bool create) { - struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - bool lagged = mlxsw_sp_port->lagged; + struct mlxsw_sp_rif_subport *rif_subport; char ritr_pl[MLXSW_REG_RITR_LEN]; - u16 system_port; - system_port = lagged ? mlxsw_sp_port->lag_id : - mlxsw_sp_port->local_port; - mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, rif_index, - vr_id, l3_dev->mtu, l3_dev->dev_addr); - mlxsw_reg_ritr_sp_if_pack(ritr_pl, lagged, system_port, - mlxsw_sp_port_vlan->vid); + rif_subport = container_of(rif, struct mlxsw_sp_rif_subport, common); + mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, + rif->rif_index, rif->vr_id, rif->dev->mtu, + rif->dev->dev_addr); + mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag, + rif_subport->lag ? rif_subport->lag_id : + rif_subport->system_port, + rif_subport->vid); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); } @@ -3058,8 +3056,7 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, rif_subport->system_port = mlxsw_sp_port->local_port; } - err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, - rif_index, true); + err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, true); if (err) goto err_port_vlan_rif_sp_op; @@ -3083,8 +3080,7 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, return rif; err_rif_fdb_op: - mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, - rif_index, false); + mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false); err_port_vlan_rif_sp_op: kfree(rif); err_rif_alloc: @@ -3117,8 +3113,7 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); - mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp_port_vlan, vr->id, l3_dev, - rif_index, false); + mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false); kfree(rif); mlxsw_sp_vr_put(vr); kfree(f); @@ -3326,18 +3321,16 @@ static enum mlxsw_reg_ritr_if_type mlxsw_sp_rif_type_get(u16 fid) return MLXSW_REG_RITR_VLAN_IF; } -static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp, u16 vr_id, - struct net_device *l3_dev, - u16 fid, u16 rif, - bool create) +static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_rif *rif, bool create) { enum mlxsw_reg_ritr_if_type rif_type; char ritr_pl[MLXSW_REG_RITR_LEN]; - rif_type = mlxsw_sp_rif_type_get(fid); - mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif, vr_id, l3_dev->mtu, - l3_dev->dev_addr); - mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, fid); + rif_type = mlxsw_sp_rif_type_get(rif->f->fid); + mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif->rif_index, + rif->vr_id, rif->dev->mtu, rif->dev->dev_addr); + mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, rif->f->fid); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); } @@ -3370,8 +3363,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, goto err_rif_alloc; } - err = mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, - rif_index, true); + err = mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, true); if (err) goto err_rif_bridge_op; @@ -3388,8 +3380,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, return 0; err_rif_fdb_op: - mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index, - false); + mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); err_rif_bridge_op: kfree(rif); err_rif_alloc: @@ -3415,8 +3406,7 @@ void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false); - mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index, - false); + mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); kfree(rif); -- cgit v1.2.3 From 1b8f09a05f33dbced2e48cd1c6d3ee524739ff63 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:36 +0200 Subject: mlxsw: spectrum_router: Destroy RIF only based on its struct Now that all the information to create a RIF is contained within the RIF struct itself, we can also simplify the destruction logic. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 73cc5195068f..41c85dcfa99f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3091,11 +3091,9 @@ err_vr_get: } static void -mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, +mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif) { - struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; struct net_device *l3_dev = rif->dev; struct mlxsw_sp_fid *f = rif->f; @@ -3124,11 +3122,12 @@ mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct net_device *l3_dev) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u16 vid = mlxsw_sp_port_vlan->vid; struct mlxsw_sp_rif *rif; int err; - rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp_port->mlxsw_sp, l3_dev); + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); if (!rif) { rif = mlxsw_sp_port_vlan_rif_sp_create(mlxsw_sp_port_vlan, l3_dev); @@ -3163,7 +3162,7 @@ err_port_vid_stp_set: mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); err_port_vid_learning_set: if (rif->f->ref_count == 0) - mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp_port_vlan, rif); + mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif); return err; } @@ -3171,6 +3170,7 @@ static void mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; u16 vid = mlxsw_sp_port_vlan->vid; @@ -3184,7 +3184,7 @@ mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); if (fid->ref_count == 0) - mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp_port_vlan, fid->rif); + mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, fid->rif); } static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, -- cgit v1.2.3 From 8e3482d6adef158d362e46cae1415940bf0f9b07 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:37 +0200 Subject: mlxsw: spectrum_router: Flood packets to router after RIF creation If a packet ingress the router but can't be assigned an ingress RIF, it's dropped. Therefore, in the case of RIF configured on top of a bridge, it makes sense to start flooding broadcast packets to the router only after the RIF was created. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 41c85dcfa99f..32bf6584e050 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3353,10 +3353,6 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, if (IS_ERR(vr)) return PTR_ERR(vr); - err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true); - if (err) - goto err_port_flood_set; - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, false); if (!rif) { err = -ENOMEM; @@ -3367,6 +3363,10 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, if (err) goto err_rif_bridge_op; + err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true); + if (err) + goto err_port_flood_set; + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, true); if (err) goto err_rif_fdb_op; @@ -3380,12 +3380,12 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, return 0; err_rif_fdb_op: + mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); +err_port_flood_set: mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); err_rif_bridge_op: kfree(rif); err_rif_alloc: - mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); -err_port_flood_set: mlxsw_sp_vr_put(vr); return err; } @@ -3406,12 +3406,12 @@ void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false); + mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); + mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); kfree(rif); - mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); - mlxsw_sp_vr_put(vr); netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif_index); -- cgit v1.2.3 From c9ec53f03460b374c5565c09beac2aec5dfc5cbc Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:38 +0200 Subject: mlxsw: spectrum_router: Determine VR first when creating RIF All RIF types are associated with a virtual router (VR), so determine VR first when creating a RIF. That way, we can more easily integrate the common RIF core in the following patches. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 38 +++++++++++++--------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 32bf6584e050..0c0ec2aa1933 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3025,19 +3025,21 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, u16 fid, rif_index; int err; + vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); + if (IS_ERR(vr)) + return ERR_CAST(vr); + rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp); - if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) - return ERR_PTR(-ERANGE); + if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) { + err = -ERANGE; + goto err_avail_rif_get; + } fid = mlxsw_sp_rif_sp_to_fid(rif_index); f = mlxsw_sp_rfid_alloc(fid, l3_dev); - if (!f) - return ERR_PTR(-ENOMEM); - - vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); - if (IS_ERR(vr)) { - err = PTR_ERR(vr); - goto err_vr_get; + if (!f) { + err = -ENOMEM; + goto err_rfid_alloc; } rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, true); @@ -3084,9 +3086,10 @@ err_rif_fdb_op: err_port_vlan_rif_sp_op: kfree(rif); err_rif_alloc: - mlxsw_sp_vr_put(vr); -err_vr_get: kfree(f); +err_rfid_alloc: +err_avail_rif_get: + mlxsw_sp_vr_put(vr); return ERR_PTR(err); } @@ -3113,8 +3116,8 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false); kfree(rif); - mlxsw_sp_vr_put(vr); kfree(f); + mlxsw_sp_vr_put(vr); } static int @@ -3345,14 +3348,16 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, u16 rif_index; int err; - rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp); - if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) - return -ERANGE; - vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); if (IS_ERR(vr)) return PTR_ERR(vr); + rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp); + if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) { + err = -ERANGE; + goto err_avail_rif_get; + } + rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, false); if (!rif) { err = -ENOMEM; @@ -3386,6 +3391,7 @@ err_port_flood_set: err_rif_bridge_op: kfree(rif); err_rif_alloc: +err_avail_rif_get: mlxsw_sp_vr_put(vr); return err; } -- cgit v1.2.3 From a110748725450adb86cb4b20b24dd8c4e0cc2d8f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:39 +0200 Subject: mlxsw: spectrum: Implement common FID core The device supports three types of FIDs. 802.1Q and 802.1D FIDs for VLAN-aware and VLAN-unaware bridges (respectively) and rFIDs to transport packets to the router block. The different users (e.g., bridge, router, ACLs) of the FIDs infrastructure need not know about the internal FIDs implementation and can therefore interact with it using a restricted set of exported functions. By encapsulating the entire FID logic and hiding it from the rest of the driver we get a code base that it much simpler and easier to work with and extend. For example, in the current Spectrum ASIC only 802.1D FIDs can be assigned a VNI, but future ASICs will also support 802.1Q FIDs. With this patch in place, support for future ASICs can be easily added by implementing a new FID operations according to their capabilities. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 +- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 192 +--- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 123 ++- drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 17 + drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 978 +++++++++++++++++++++ .../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 6 +- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 301 +++---- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 419 ++------- 8 files changed, 1278 insertions(+), 761 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile index 2fb8c6585ac7..62fc42f396bb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Makefile +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -16,7 +16,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \ spectrum_switchdev.o spectrum_router.o \ spectrum_kvdl.o spectrum_acl_tcam.o \ spectrum_acl.o spectrum_flower.o \ - spectrum_cnt.o spectrum_dpipe.o + spectrum_cnt.o spectrum_dpipe.o \ + spectrum_fid.o mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o mlxsw_minimal-objs := minimal.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 3b6056ae457a..666bcf4854e6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -870,8 +870,7 @@ static int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid) swid); } -static int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, - bool enable) +int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; char svpe_pl[MLXSW_REG_SVPE_LEN]; @@ -880,18 +879,6 @@ static int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svpe), svpe_pl); } -int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, - enum mlxsw_reg_svfa_mt mt, bool valid, u16 fid, - u16 vid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char svfa_pl[MLXSW_REG_SVFA_LEN]; - - mlxsw_reg_svfa_pack(svfa_pl, mlxsw_sp_port->local_port, mt, valid, - fid, vid); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); -} - int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, bool learn_enable) { @@ -1398,75 +1385,6 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, return 0; } -int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_fid *fid; - u16 vid; - int err; - - list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, - list) { - fid = mlxsw_sp_port_vlan->fid; - - if (!fid || fid->fid >= MLXSW_SP_VFID_BASE) - continue; - - vid = mlxsw_sp_port_vlan->vid; - err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, - fid->fid, vid); - if (err) - goto err_port_vid_to_fid_set; - } - - err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); - if (err) - goto err_port_vp_mode_set; - - return 0; - -err_port_vp_mode_set: -err_port_vid_to_fid_set: - list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, - &mlxsw_sp_port->vlans_list, list) { - fid = mlxsw_sp_port_vlan->fid; - - if (!fid || fid->fid >= MLXSW_SP_VFID_BASE) - continue; - - vid = mlxsw_sp_port_vlan->vid; - mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid->fid, - vid); - } - return err; -} - -int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - int err; - - err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); - if (err) - return err; - - list_for_each_entry_reverse(mlxsw_sp_port_vlan, - &mlxsw_sp_port->vlans_list, list) { - struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; - u16 vid = mlxsw_sp_port_vlan->vid; - - if (!fid || fid->fid >= MLXSW_SP_VFID_BASE) - continue; - - mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid->fid, - vid); - } - - return 0; -} - static void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp; @@ -1529,10 +1447,12 @@ mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + if (mlxsw_sp_port_vlan->bridge_port) mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); - else if (mlxsw_sp_port_vlan->fid) - mlxsw_sp_port_vlan->fid->leave(mlxsw_sp_port_vlan); + else if (fid) + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); } @@ -2831,11 +2751,11 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_port_dcb_init; } - err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + err = mlxsw_sp_port_fids_init(mlxsw_sp_port); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set non-virtual mode\n", + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize FIDs\n", mlxsw_sp_port->local_port); - goto err_port_vp_mode_set; + goto err_port_fids_init; } mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); @@ -2865,7 +2785,8 @@ err_register_netdev: mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); err_port_vlan_get: -err_port_vp_mode_set: + mlxsw_sp_port_fids_fini(mlxsw_sp_port); +err_port_fids_init: mlxsw_sp_port_dcb_fini(mlxsw_sp_port); err_port_dcb_init: err_port_ets_init: @@ -2919,6 +2840,7 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) mlxsw_sp->ports[local_port] = NULL; mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); mlxsw_sp_port_vlan_flush(mlxsw_sp_port); + mlxsw_sp_port_fids_fini(mlxsw_sp_port); mlxsw_sp_port_dcb_fini(mlxsw_sp_port); mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port); @@ -3478,57 +3400,6 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) } } -static int __mlxsw_sp_flood_init(struct mlxsw_core *mlxsw_core, - enum mlxsw_reg_sfgc_type type, - enum mlxsw_reg_sfgc_bridge_type bridge_type) -{ - enum mlxsw_flood_table_type table_type; - enum mlxsw_sp_flood_table flood_table; - char sfgc_pl[MLXSW_REG_SFGC_LEN]; - - if (bridge_type == MLXSW_REG_SFGC_BRIDGE_TYPE_VFID) - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID; - else - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; - - switch (type) { - case MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST: - flood_table = MLXSW_SP_FLOOD_TABLE_UC; - break; - case MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4: - flood_table = MLXSW_SP_FLOOD_TABLE_MC; - break; - default: - flood_table = MLXSW_SP_FLOOD_TABLE_BC; - } - - mlxsw_reg_sfgc_pack(sfgc_pl, type, bridge_type, table_type, - flood_table); - return mlxsw_reg_write(mlxsw_core, MLXSW_REG(sfgc), sfgc_pl); -} - -static int mlxsw_sp_flood_init(struct mlxsw_sp *mlxsw_sp) -{ - int type, err; - - for (type = 0; type < MLXSW_REG_SFGC_TYPE_MAX; type++) { - if (type == MLXSW_REG_SFGC_TYPE_RESERVED) - continue; - - err = __mlxsw_sp_flood_init(mlxsw_sp->core, type, - MLXSW_REG_SFGC_BRIDGE_TYPE_VFID); - if (err) - return err; - - err = __mlxsw_sp_flood_init(mlxsw_sp->core, type, - MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID); - if (err) - return err; - } - - return 0; -} - static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) { char slcr_pl[MLXSW_REG_SLCR_LEN]; @@ -3576,16 +3447,6 @@ static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); } -static int mlxsw_sp_dummy_fid_init(struct mlxsw_sp *mlxsw_sp) -{ - return mlxsw_sp_fid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, true); -} - -static void mlxsw_sp_dummy_fid_fini(struct mlxsw_sp *mlxsw_sp) -{ - mlxsw_sp_fid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, false); -} - static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, const struct mlxsw_bus_info *mlxsw_bus_info) { @@ -3594,8 +3455,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->core = mlxsw_core; mlxsw_sp->bus_info = mlxsw_bus_info; - INIT_LIST_HEAD(&mlxsw_sp->fids); - INIT_LIST_HEAD(&mlxsw_sp->vfids.list); err = mlxsw_sp_fw_rev_validate(mlxsw_sp); if (err) { @@ -3609,16 +3468,16 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return err; } - err = mlxsw_sp_traps_init(mlxsw_sp); + err = mlxsw_sp_fids_init(mlxsw_sp); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n"); + dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n"); return err; } - err = mlxsw_sp_flood_init(mlxsw_sp); + err = mlxsw_sp_traps_init(mlxsw_sp); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize flood tables\n"); - goto err_flood_init; + dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n"); + goto err_traps_init; } err = mlxsw_sp_buffers_init(mlxsw_sp); @@ -3669,12 +3528,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_dpipe_init; } - err = mlxsw_sp_dummy_fid_init(mlxsw_sp); - if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to init dummy FID\n"); - goto err_dummy_fid_init; - } - err = mlxsw_sp_ports_create(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n"); @@ -3684,8 +3537,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return 0; err_ports_create: - mlxsw_sp_dummy_fid_fini(mlxsw_sp); -err_dummy_fid_init: mlxsw_sp_dpipe_fini(mlxsw_sp); err_dpipe_init: mlxsw_sp_counter_pool_fini(mlxsw_sp); @@ -3702,8 +3553,9 @@ err_switchdev_init: err_lag_init: mlxsw_sp_buffers_fini(mlxsw_sp); err_buffers_init: -err_flood_init: mlxsw_sp_traps_fini(mlxsw_sp); +err_traps_init: + mlxsw_sp_fids_fini(mlxsw_sp); return err; } @@ -3712,7 +3564,6 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); mlxsw_sp_ports_remove(mlxsw_sp); - mlxsw_sp_dummy_fid_fini(mlxsw_sp); mlxsw_sp_dpipe_fini(mlxsw_sp); mlxsw_sp_counter_pool_fini(mlxsw_sp); mlxsw_sp_acl_fini(mlxsw_sp); @@ -3722,8 +3573,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_lag_fini(mlxsw_sp); mlxsw_sp_buffers_fini(mlxsw_sp); mlxsw_sp_traps_fini(mlxsw_sp); - WARN_ON(!list_empty(&mlxsw_sp->vfids.list)); - WARN_ON(!list_empty(&mlxsw_sp->fids)); + mlxsw_sp_fids_fini(mlxsw_sp); } static struct mlxsw_config_profile mlxsw_sp_config_profile = { @@ -3739,7 +3589,7 @@ static struct mlxsw_config_profile mlxsw_sp_config_profile = { .max_fid_offset_flood_tables = 3, .fid_offset_flood_table_size = VLAN_N_VID - 1, .max_fid_flood_tables = 3, - .fid_flood_table_size = MLXSW_SP_VFID_MAX, + .fid_flood_table_size = MLXSW_SP_FID_8021D_MAX, .used_max_ib_mc = 1, .max_ib_mc = 0, .used_max_pkey = 1, @@ -4009,7 +3859,7 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, /* Port is no longer usable as a router interface */ mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); if (mlxsw_sp_port_vlan->fid) - mlxsw_sp_port_vlan->fid->leave(mlxsw_sp_port_vlan); + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 8c511ff19f84..c542b33e44c0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -54,12 +54,7 @@ #include "core_acl_flex_keys.h" #include "core_acl_flex_actions.h" -#define MLXSW_SP_VFID_BASE VLAN_N_VID -#define MLXSW_SP_VFID_MAX 1024 /* Bridged VLAN interfaces */ - -#define MLXSW_SP_DUMMY_FID 15359 - -#define MLXSW_SP_RFID_BASE 15360 +#define MLXSW_SP_FID_8021D_MAX 1024 #define MLXSW_SP_MID_MAX 7000 @@ -70,7 +65,6 @@ #define MLXSW_SP_KVD_LINEAR_SIZE 65536 /* entries */ #define MLXSW_SP_KVD_GRANULARITY 128 -struct mlxsw_sp_port_vlan; struct mlxsw_sp_port; struct mlxsw_sp_rif; @@ -79,13 +73,19 @@ struct mlxsw_sp_upper { unsigned int ref_count; }; -struct mlxsw_sp_fid { - void (*leave)(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); - struct list_head list; - unsigned int ref_count; - struct net_device *dev; - struct mlxsw_sp_rif *rif; - u16 fid; +enum mlxsw_sp_rif_type { + MLXSW_SP_RIF_TYPE_SUBPORT, + MLXSW_SP_RIF_TYPE_VLAN, + MLXSW_SP_RIF_TYPE_FID, + MLXSW_SP_RIF_TYPE_MAX, +}; + +enum mlxsw_sp_fid_type { + MLXSW_SP_FID_TYPE_8021Q, + MLXSW_SP_FID_TYPE_8021D, + MLXSW_SP_FID_TYPE_RFID, + MLXSW_SP_FID_TYPE_DUMMY, + MLXSW_SP_FID_TYPE_MAX, }; struct mlxsw_sp_mid { @@ -96,21 +96,6 @@ struct mlxsw_sp_mid { unsigned int ref_count; }; -static inline u16 mlxsw_sp_vfid_to_fid(u16 vfid) -{ - return MLXSW_SP_VFID_BASE + vfid; -} - -static inline u16 mlxsw_sp_fid_to_vfid(u16 fid) -{ - return fid - MLXSW_SP_VFID_BASE; -} - -static inline bool mlxsw_sp_fid_is_vfid(u16 fid) -{ - return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_DUMMY_FID; -} - enum mlxsw_sp_span_type { MLXSW_SP_SPAN_EGRESS, MLXSW_SP_SPAN_INGRESS @@ -154,13 +139,9 @@ struct mlxsw_sp_bridge; struct mlxsw_sp_router; struct mlxsw_sp_acl; struct mlxsw_sp_counter_pool; +struct mlxsw_sp_fid_core; struct mlxsw_sp { - struct { - struct list_head list; - DECLARE_BITMAP(mapped, MLXSW_SP_VFID_MAX); - } vfids; - struct list_head fids; /* VLAN-aware bridge FIDs */ struct mlxsw_sp_port **ports; struct mlxsw_core *core; const struct mlxsw_bus_info *bus_info; @@ -171,6 +152,7 @@ struct mlxsw_sp { struct mlxsw_sp_bridge *bridge; struct mlxsw_sp_router *router; struct mlxsw_sp_acl *acl; + struct mlxsw_sp_fid_core *fid_core; struct { DECLARE_BITMAP(usage, MLXSW_SP_KVD_LINEAR_SIZE); } kvdl; @@ -205,6 +187,7 @@ struct mlxsw_sp_port_sample { }; struct mlxsw_sp_bridge_port; +struct mlxsw_sp_fid; struct mlxsw_sp_port_vlan { struct list_head list; @@ -247,7 +230,6 @@ struct mlxsw_sp_port { struct delayed_work update_dw; } hw_stats; struct mlxsw_sp_port_sample *sample; - unsigned int nr_port_vid_map; /* {Port, VID} => FID mappings */ struct list_head vlans_list; }; @@ -290,35 +272,10 @@ mlxsw_sp_port_vlan_find_by_vid(const struct mlxsw_sp_port *mlxsw_sp_port, return NULL; } -static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp, - u16 fid) -{ - struct mlxsw_sp_fid *f; - - list_for_each_entry(f, &mlxsw_sp->fids, list) - if (f->fid == fid) - return f; - - return NULL; -} - -static inline struct mlxsw_sp_fid * -mlxsw_sp_vfid_find(const struct mlxsw_sp *mlxsw_sp, - const struct net_device *br_dev) -{ - struct mlxsw_sp_fid *f; - - list_for_each_entry(f, &mlxsw_sp->vfids.list, list) - if (f->dev == br_dev) - return f; - - return NULL; -} - -enum mlxsw_sp_flood_table { - MLXSW_SP_FLOOD_TABLE_UC, - MLXSW_SP_FLOOD_TABLE_BC, - MLXSW_SP_FLOOD_TABLE_MC, +enum mlxsw_sp_flood_type { + MLXSW_SP_FLOOD_TYPE_UC, + MLXSW_SP_FLOOD_TYPE_BC, + MLXSW_SP_FLOOD_TYPE_MC, }; int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp); @@ -362,15 +319,10 @@ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, - enum mlxsw_reg_svfa_mt mt, bool valid, u16 fid, - u16 vid); int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, u16 vid_end, bool is_member, bool untagged); int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, bool adding); -struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid); -int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, bool valid); void mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, @@ -393,11 +345,10 @@ int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 next_index, u32 maxrate); int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, u8 state); +int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable); int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, bool learn_enable); int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); -int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port); struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); @@ -426,10 +377,11 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused, int mlxsw_sp_netdevice_router_port_event(struct net_device *dev); int mlxsw_sp_inetaddr_event(struct notifier_block *unused, unsigned long event, void *ptr); -void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *rif); int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, struct netdev_notifier_changeupper_info *info); +void +mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); +void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif); int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count, u32 *p_entry_index); @@ -535,6 +487,8 @@ int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule *rule, u64 *packets, u64 *bytes, u64 *last_use); +struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp); + int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp); @@ -554,4 +508,27 @@ int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, unsigned int counter_index); +int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_type packet_type, u8 local_port, + bool member); +int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid); +u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid); +enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid); +void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif); +struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid); +struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, + int br_ifindex); +struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, + u16 rif_index); +struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid); +int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port); +void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port); +int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp); + #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 317f7b14627f..1da889a044df 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -53,6 +53,7 @@ struct mlxsw_sp_acl { struct mlxsw_sp *mlxsw_sp; struct mlxsw_afk *afk; struct mlxsw_afa *afa; + struct mlxsw_sp_fid *dummy_fid; const struct mlxsw_sp_acl_ops *ops; struct rhashtable ruleset_ht; struct list_head rules; @@ -112,6 +113,11 @@ static const struct rhashtable_params mlxsw_sp_acl_rule_ht_params = { .automatic_shrinking = true, }; +struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp->acl->dummy_fid; +} + static struct mlxsw_sp_acl_ruleset * mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_acl_profile_ops *ops) @@ -676,6 +682,7 @@ static const struct mlxsw_afa_ops mlxsw_sp_act_afa_ops = { int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) { const struct mlxsw_sp_acl_ops *acl_ops = &mlxsw_sp_acl_tcam_ops; + struct mlxsw_sp_fid *fid; struct mlxsw_sp_acl *acl; int err; @@ -706,6 +713,13 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_rhashtable_init; + fid = mlxsw_sp_fid_dummy_get(mlxsw_sp); + if (IS_ERR(fid)) { + err = PTR_ERR(fid); + goto err_fid_get; + } + acl->dummy_fid = fid; + INIT_LIST_HEAD(&acl->rules); err = acl_ops->init(mlxsw_sp, acl->priv); if (err) @@ -721,6 +735,8 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) return 0; err_acl_ops_init: + mlxsw_sp_fid_put(fid); +err_fid_get: rhashtable_destroy(&acl->ruleset_ht); err_rhashtable_init: mlxsw_afa_destroy(acl->afa); @@ -739,6 +755,7 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp) cancel_delayed_work_sync(&mlxsw_sp->acl->rule_activity_update.dw); acl_ops->fini(mlxsw_sp, acl->priv); WARN_ON(!list_empty(&acl->rules)); + mlxsw_sp_fid_put(acl->dummy_fid); rhashtable_destroy(&acl->ruleset_ht); mlxsw_afa_destroy(acl->afa); mlxsw_afk_destroy(acl->afk); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c new file mode 100644 index 000000000000..379bbe001dd9 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -0,0 +1,978 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Ido Schimmel + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "spectrum.h" +#include "reg.h" + +struct mlxsw_sp_fid_family; + +struct mlxsw_sp_fid_core { + struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX]; + unsigned int *port_fid_mappings; +}; + +struct mlxsw_sp_fid { + struct list_head list; + struct mlxsw_sp_rif *rif; + unsigned int ref_count; + u16 fid_index; + struct mlxsw_sp_fid_family *fid_family; +}; + +struct mlxsw_sp_fid_8021q { + struct mlxsw_sp_fid common; + u16 vid; +}; + +struct mlxsw_sp_fid_8021d { + struct mlxsw_sp_fid common; + int br_ifindex; +}; + +struct mlxsw_sp_flood_table { + enum mlxsw_sp_flood_type packet_type; + enum mlxsw_reg_sfgc_bridge_type bridge_type; + enum mlxsw_flood_table_type table_type; + int table_index; +}; + +struct mlxsw_sp_fid_ops { + void (*setup)(struct mlxsw_sp_fid *fid, const void *arg); + int (*configure)(struct mlxsw_sp_fid *fid); + void (*deconfigure)(struct mlxsw_sp_fid *fid); + int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg, + u16 *p_fid_index); + bool (*compare)(const struct mlxsw_sp_fid *fid, + const void *arg); + u16 (*flood_index)(const struct mlxsw_sp_fid *fid); + int (*port_vid_map)(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *port, u16 vid); + void (*port_vid_unmap)(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *port, u16 vid); +}; + +struct mlxsw_sp_fid_family { + enum mlxsw_sp_fid_type type; + size_t fid_size; + u16 start_index; + u16 end_index; + struct list_head fids_list; + unsigned long *fids_bitmap; + const struct mlxsw_sp_flood_table *flood_tables; + int nr_flood_tables; + enum mlxsw_sp_rif_type rif_type; + const struct mlxsw_sp_fid_ops *ops; + struct mlxsw_sp *mlxsw_sp; +}; + +static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1, +}; + +static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, + [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, + [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, +}; + +static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, +}; + +static const int *mlxsw_sp_packet_type_sfgc_types[] = { + [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types, + [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, + [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, +}; + +static const struct mlxsw_sp_flood_table * +mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_type packet_type) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + int i; + + for (i = 0; i < fid_family->nr_flood_tables; i++) { + if (fid_family->flood_tables[i].packet_type != packet_type) + continue; + return &fid_family->flood_tables[i]; + } + + return NULL; +} + +int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_type packet_type, u8 local_port, + bool member) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; + const struct mlxsw_sp_flood_table *flood_table; + char *sftr_pl; + int err; + + if (WARN_ON(!fid_family->flood_tables || !ops->flood_index)) + return -EINVAL; + + flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type); + if (!flood_table) + return -ESRCH; + + sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); + if (!sftr_pl) + return -ENOMEM; + + mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index, + ops->flood_index(fid), flood_table->table_type, 1, + local_port, member); + err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr), + sftr_pl); + kfree(sftr_pl); + return err; +} + +int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + if (WARN_ON(!fid->fid_family->ops->port_vid_map)) + return -EINVAL; + return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid); +} + +void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid); +} + +enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_family->rif_type; +} + +u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_index; +} + +enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_family->type; +} + +void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif) +{ + fid->rif = rif; +} + +static struct mlxsw_sp_fid_8021q * +mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid) +{ + return container_of(fid, struct mlxsw_sp_fid_8021q, common); +} + +static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) +{ + u16 vid = *(u16 *) arg; + + mlxsw_sp_fid_8021q_fid(fid)->vid = vid; +} + +static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) +{ + return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : + MLXSW_REG_SFMR_OP_DESTROY_FID; +} + +static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + u16 fid_offset, bool valid) +{ + char sfmr_pl[MLXSW_REG_SFMR_LEN]; + + mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index, + fid_offset); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); +} + +static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + u16 vid, bool valid) +{ + enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID; + char svfa_pl[MLXSW_REG_SVFA_LEN]; + + mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, vid); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); +} + +static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + u8 local_port, u16 vid, bool valid) +{ + enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; + char svfa_pl[MLXSW_REG_SVFA_LEN]; + + mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); +} + +static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + struct mlxsw_sp_fid_8021q *fid_8021q; + int err; + + err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true); + if (err) + return err; + + fid_8021q = mlxsw_sp_fid_8021q_fid(fid); + err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, + true); + if (err) + goto err_fid_map; + + return 0; + +err_fid_map: + mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); + return err; +} + +static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + struct mlxsw_sp_fid_8021q *fid_8021q; + + fid_8021q = mlxsw_sp_fid_8021q_fid(fid); + mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false); + mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); +} + +static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + u16 vid = *(u16 *) arg; + + /* Use 1:1 mapping for simplicity although not a must */ + if (vid < fid_family->start_index || vid > fid_family->end_index) + return -EINVAL; + *p_fid_index = vid; + + return 0; +} + +static bool +mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) +{ + u16 vid = *(u16 *) arg; + + return mlxsw_sp_fid_8021q_fid(fid)->vid == vid; +} + +static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_index; +} + +static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + /* In case there are no {Port, VID} => FID mappings on the port, + * we can use the global VID => FID mapping we created when the + * FID was configured. + */ + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) + return 0; + return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, + vid, true); +} + +static void +mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) + return; + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid, + false); +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = { + .setup = mlxsw_sp_fid_8021q_setup, + .configure = mlxsw_sp_fid_8021q_configure, + .deconfigure = mlxsw_sp_fid_8021q_deconfigure, + .index_alloc = mlxsw_sp_fid_8021q_index_alloc, + .compare = mlxsw_sp_fid_8021q_compare, + .flood_index = mlxsw_sp_fid_8021q_flood_index, + .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap, +}; + +static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = { + { + .packet_type = MLXSW_SP_FLOOD_TYPE_UC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, + .table_index = 0, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_MC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, + .table_index = 1, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_BC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, + .table_index = 2, + }, +}; + +/* Range and flood configuration must match mlxsw_config_profile */ +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = { + .type = MLXSW_SP_FID_TYPE_8021Q, + .fid_size = sizeof(struct mlxsw_sp_fid_8021q), + .start_index = 1, + .end_index = VLAN_VID_MASK, + .flood_tables = mlxsw_sp_fid_8021q_flood_tables, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables), + .rif_type = MLXSW_SP_RIF_TYPE_VLAN, + .ops = &mlxsw_sp_fid_8021q_ops, +}; + +static struct mlxsw_sp_fid_8021d * +mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) +{ + return container_of(fid, struct mlxsw_sp_fid_8021d, common); +} + +static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) +{ + int br_ifindex = *(int *) arg; + + mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex; +} + +static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true); +} + +static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid) +{ + mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); +} + +static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + u16 nr_fids, fid_index; + + nr_fids = fid_family->end_index - fid_family->start_index + 1; + fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids); + if (fid_index == nr_fids) + return -ENOBUFS; + *p_fid_index = fid_family->start_index + fid_index; + + return 0; +} + +static bool +mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg) +{ + int br_ifindex = *(int *) arg; + + return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex; +} + +static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_index - fid->fid_family->start_index; +} + +static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + int err; + + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid) + continue; + + err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, + vid, true); + if (err) + goto err_fid_port_vid_map; + } + + err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); + if (err) + goto err_port_vp_mode_set; + + return 0; + +err_port_vp_mode_set: +err_fid_port_vid_map: + list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, + &mlxsw_sp_port->vlans_list, list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid) + continue; + + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, + false); + } + return err; +} + +static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + + list_for_each_entry_reverse(mlxsw_sp_port_vlan, + &mlxsw_sp_port->vlans_list, list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid) + continue; + + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, + false); + } +} + +static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + int err; + + err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, true); + if (err) + return err; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + + return 0; + +err_port_vp_mode_trans: + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, false); + return err; +} + +static void +mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, false); +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { + .setup = mlxsw_sp_fid_8021d_setup, + .configure = mlxsw_sp_fid_8021d_configure, + .deconfigure = mlxsw_sp_fid_8021d_deconfigure, + .index_alloc = mlxsw_sp_fid_8021d_index_alloc, + .compare = mlxsw_sp_fid_8021d_compare, + .flood_index = mlxsw_sp_fid_8021d_flood_index, + .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, +}; + +static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { + { + .packet_type = MLXSW_SP_FLOOD_TYPE_UC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, + .table_index = 0, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_MC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, + .table_index = 1, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_BC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, + .table_index = 2, + }, +}; + +/* Range and flood configuration must match mlxsw_config_profile */ +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = { + .type = MLXSW_SP_FID_TYPE_8021D, + .fid_size = sizeof(struct mlxsw_sp_fid_8021d), + .start_index = VLAN_N_VID, + .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1, + .flood_tables = mlxsw_sp_fid_8021d_flood_tables, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .rif_type = MLXSW_SP_RIF_TYPE_FID, + .ops = &mlxsw_sp_fid_8021d_ops, +}; + +static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) +{ + /* rFIDs are allocated by the device during init */ + return 0; +} + +static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid) +{ +} + +static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + u16 rif_index = *(u16 *) arg; + + *p_fid_index = fid->fid_family->start_index + rif_index; + + return 0; +} + +static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid, + const void *arg) +{ + u16 rif_index = *(u16 *) arg; + + return fid->fid_index == rif_index + fid->fid_family->start_index; +} + +static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + int err; + + /* We only need to transition the port to virtual mode since + * {Port, VID} => FID is done by the firmware upon RIF creation. + */ + if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + + return 0; + +err_port_vp_mode_trans: + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; + return err; +} + +static void +mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { + .configure = mlxsw_sp_fid_rfid_configure, + .deconfigure = mlxsw_sp_fid_rfid_deconfigure, + .index_alloc = mlxsw_sp_fid_rfid_index_alloc, + .compare = mlxsw_sp_fid_rfid_compare, + .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap, +}; + +#define MLXSW_SP_RFID_BASE (15 * 1024) +#define MLXSW_SP_RFID_MAX 1024 + +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { + .type = MLXSW_SP_FID_TYPE_RFID, + .fid_size = sizeof(struct mlxsw_sp_fid), + .start_index = MLXSW_SP_RFID_BASE, + .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1, + .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, + .ops = &mlxsw_sp_fid_rfid_ops, +}; + +static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + + return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true); +} + +static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid) +{ + mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); +} + +static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + *p_fid_index = fid->fid_family->start_index; + + return 0; +} + +static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid, + const void *arg) +{ + return true; +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { + .configure = mlxsw_sp_fid_dummy_configure, + .deconfigure = mlxsw_sp_fid_dummy_deconfigure, + .index_alloc = mlxsw_sp_fid_dummy_index_alloc, + .compare = mlxsw_sp_fid_dummy_compare, +}; + +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = { + .type = MLXSW_SP_FID_TYPE_DUMMY, + .fid_size = sizeof(struct mlxsw_sp_fid), + .start_index = MLXSW_SP_RFID_BASE - 1, + .end_index = MLXSW_SP_RFID_BASE - 1, + .ops = &mlxsw_sp_fid_dummy_ops, +}; + +static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = { + [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_family, + [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family, + [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, + [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family, +}; + +static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_type type, + const void *arg) +{ + struct mlxsw_sp_fid_family *fid_family; + struct mlxsw_sp_fid *fid; + u16 fid_index; + int err; + + fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; + list_for_each_entry(fid, &fid_family->fids_list, list) { + if (!fid->fid_family->ops->compare(fid, arg)) + continue; + fid->ref_count++; + return fid; + } + + fid = kzalloc(fid_family->fid_size, GFP_KERNEL); + if (!fid) + return ERR_PTR(-ENOMEM); + fid->fid_family = fid_family; + + err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index); + if (err) + goto err_index_alloc; + fid->fid_index = fid_index; + __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); + + if (fid->fid_family->ops->setup) + fid->fid_family->ops->setup(fid, arg); + + err = fid->fid_family->ops->configure(fid); + if (err) + goto err_configure; + + list_add(&fid->list, &fid_family->fids_list); + fid->ref_count++; + return fid; + +err_configure: + __clear_bit(fid_index - fid_family->start_index, + fid_family->fids_bitmap); +err_index_alloc: + kfree(fid); + return ERR_PTR(err); +} + +void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + if (--fid->ref_count == 1 && fid->rif) { + /* Destroy the associated RIF and let it drop the last + * reference on the FID. + */ + return mlxsw_sp_rif_destroy(fid_family->mlxsw_sp, fid->rif); + } else if (fid->ref_count == 0) { + list_del(&fid->list); + fid->fid_family->ops->deconfigure(fid); + __clear_bit(fid->fid_index - fid_family->start_index, + fid_family->fids_bitmap); + kfree(fid); + } +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, + int br_ifindex) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, + u16 rif_index) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index); +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL); +} + +static int +mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table) +{ + enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; + const int *sfgc_packet_types; + int i; + + sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; + for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + char sfgc_pl[MLXSW_REG_SFGC_LEN]; + int err; + + if (!sfgc_packet_types[i]) + continue; + mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type, + flood_table->table_type, + flood_table->table_index); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + } + + return 0; +} + +static int +mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) +{ + int i; + + for (i = 0; i < fid_family->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table; + int err; + + flood_table = &fid_family->flood_tables[i]; + err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table); + if (err) + return err; + } + + return 0; +} + +static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_fid_family *tmpl) +{ + u16 nr_fids = tmpl->end_index - tmpl->start_index + 1; + struct mlxsw_sp_fid_family *fid_family; + int err; + + fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL); + if (!fid_family) + return -ENOMEM; + + fid_family->mlxsw_sp = mlxsw_sp; + INIT_LIST_HEAD(&fid_family->fids_list); + fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids), + sizeof(unsigned long), GFP_KERNEL); + if (!fid_family->fids_bitmap) { + err = -ENOMEM; + goto err_alloc_fids_bitmap; + } + + if (fid_family->flood_tables) { + err = mlxsw_sp_fid_flood_tables_init(fid_family); + if (err) + goto err_fid_flood_tables_init; + } + + mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family; + + return 0; + +err_fid_flood_tables_init: + kfree(fid_family->fids_bitmap); +err_alloc_fids_bitmap: + kfree(fid_family); + return err; +} + +static void +mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid_family *fid_family) +{ + mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; + kfree(fid_family->fids_bitmap); + WARN_ON_ONCE(!list_empty(&fid_family->fids_list)); + kfree(fid_family); +} + +int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + + /* Track number of FIDs configured on the port with mapping type + * PORT_VID_TO_FID, so that we know when to transition the port + * back to non-virtual (VLAN) mode. + */ + mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; + + return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); +} + +void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + + mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; +} + +int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) +{ + unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); + struct mlxsw_sp_fid_core *fid_core; + int err, i; + + fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL); + if (!fid_core) + return -ENOMEM; + mlxsw_sp->fid_core = fid_core; + + fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int), + GFP_KERNEL); + if (!fid_core->port_fid_mappings) { + err = -ENOMEM; + goto err_alloc_port_fid_mappings; + } + + for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) { + err = mlxsw_sp_fid_family_register(mlxsw_sp, + mlxsw_sp_fid_family_arr[i]); + + if (err) + goto err_fid_ops_register; + } + + return 0; + +err_fid_ops_register: + for (i--; i >= 0; i--) { + struct mlxsw_sp_fid_family *fid_family; + + fid_family = fid_core->fid_family_arr[i]; + mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family); + } + kfree(fid_core->port_fid_mappings); +err_alloc_port_fid_mappings: + kfree(fid_core); + return err; +} + +void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) +{ + struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; + int i; + + for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) + mlxsw_sp_fid_family_unregister(mlxsw_sp, + fid_core->fid_family_arr[i]); + kfree(fid_core->port_fid_mappings); + kfree(fid_core); +} diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 739dc1ed759b..ed75c6a85bc3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -70,9 +70,13 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, } else if (is_tcf_mirred_egress_redirect(a)) { int ifindex = tcf_mirred_ifindex(a); struct net_device *out_dev; + struct mlxsw_sp_fid *fid; + u16 fid_index; + fid = mlxsw_sp_acl_dummy_fid(mlxsw_sp); + fid_index = mlxsw_sp_fid_index(fid); err = mlxsw_sp_acl_rulei_act_fid_set(mlxsw_sp, rulei, - MLXSW_SP_DUMMY_FID); + fid_index); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 0c0ec2aa1933..3c2e47deca0c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -86,7 +86,7 @@ struct mlxsw_sp_rif { struct list_head nexthop_list; struct list_head neigh_list; struct net_device *dev; - struct mlxsw_sp_fid *f; + struct mlxsw_sp_fid *fid; unsigned char addr[ETH_ALEN]; int mtu; u16 rif_index; @@ -2946,34 +2946,9 @@ mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp *mlxsw_sp, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); } -static void -mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); - -static u16 mlxsw_sp_rif_sp_to_fid(u16 rif_index) -{ - return MLXSW_SP_RFID_BASE + rif_index; -} - -static struct mlxsw_sp_fid * -mlxsw_sp_rfid_alloc(u16 fid, struct net_device *l3_dev) -{ - struct mlxsw_sp_fid *f; - - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (!f) - return NULL; - - f->leave = mlxsw_sp_port_vlan_rif_sp_leave; - f->ref_count = 0; - f->dev = l3_dev; - f->fid = fid; - - return f; -} - static struct mlxsw_sp_rif * mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, - struct mlxsw_sp_fid *f, bool is_subport) + struct mlxsw_sp_fid *fid, bool is_subport) { size_t size = is_subport ? sizeof(struct mlxsw_sp_rif_subport) : sizeof(struct mlxsw_sp_rif); @@ -2990,7 +2965,7 @@ mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, rif->vr_id = vr_id; rif->dev = l3_dev; rif->rif_index = rif_index; - rif->f = f; + rif->fid = fid; return rif; } @@ -3019,10 +2994,10 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_rif_subport *rif_subport; u32 tb_id = l3mdev_fib_table(l3_dev); - struct mlxsw_sp_vr *vr; - struct mlxsw_sp_fid *f; struct mlxsw_sp_rif *rif; - u16 fid, rif_index; + struct mlxsw_sp_fid *fid; + struct mlxsw_sp_vr *vr; + u16 rif_index; int err; vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); @@ -3035,14 +3010,13 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, goto err_avail_rif_get; } - fid = mlxsw_sp_rif_sp_to_fid(rif_index); - f = mlxsw_sp_rfid_alloc(fid, l3_dev); - if (!f) { - err = -ENOMEM; - goto err_rfid_alloc; + fid = mlxsw_sp_fid_rfid_get(mlxsw_sp, rif_index); + if (IS_ERR(fid)) { + err = PTR_ERR(fid); + goto err_fid_get; } - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, true); + rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, true); if (!rif) { err = -ENOMEM; goto err_rif_alloc; @@ -3062,7 +3036,8 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, if (err) goto err_port_vlan_rif_sp_op; - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, + mlxsw_sp_fid_index(fid), true); if (err) goto err_rif_fdb_op; @@ -3075,7 +3050,7 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, "Counter alloc Failed err=%d\n", err); } - f->rif = rif; + mlxsw_sp_fid_rif_set(fid, rif); mlxsw_sp->router->rifs[rif_index] = rif; vr->rif_count++; @@ -3086,8 +3061,8 @@ err_rif_fdb_op: err_port_vlan_rif_sp_op: kfree(rif); err_rif_alloc: - kfree(f); -err_rfid_alloc: + mlxsw_sp_fid_put(fid); +err_fid_get: err_avail_rif_get: mlxsw_sp_vr_put(vr); return ERR_PTR(err); @@ -3099,9 +3074,8 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; struct net_device *l3_dev = rif->dev; - struct mlxsw_sp_fid *f = rif->f; + struct mlxsw_sp_fid *fid = rif->fid; u16 rif_index = rif->rif_index; - u16 fid = f->fid; mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); @@ -3110,24 +3084,25 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp, vr->rif_count--; mlxsw_sp->router->rifs[rif_index] = NULL; - f->rif = NULL; - - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); + mlxsw_sp_fid_rif_set(fid, NULL); + mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid), + false); mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false); kfree(rif); - kfree(f); + mlxsw_sp_fid_put(fid); mlxsw_sp_vr_put(vr); } static int -mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, +mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct net_device *l3_dev) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u16 vid = mlxsw_sp_port_vlan->vid; struct mlxsw_sp_rif *rif; + struct mlxsw_sp_fid *fid; int err; rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); @@ -3138,6 +3113,12 @@ mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, return PTR_ERR(rif); } + /* FID was already created, just take a reference */ + fid = mlxsw_sp_fid_rfid_get(mlxsw_sp_port->mlxsw_sp, rif->rif_index); + err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid); + if (err) + goto err_fid_port_vid_map; + err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); if (err) goto err_port_vid_learning_set; @@ -3147,47 +3128,37 @@ mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, if (err) goto err_port_vid_stp_set; - if (mlxsw_sp_port->nr_port_vid_map++ == 0) { - err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); - if (err) - goto err_port_vp_mode_trans; - } - - mlxsw_sp_port_vlan->fid = rif->f; - rif->f->ref_count++; + mlxsw_sp_port_vlan->fid = fid; return 0; -err_port_vp_mode_trans: - mlxsw_sp_port->nr_port_vid_map--; - mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING); err_port_vid_stp_set: mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); err_port_vid_learning_set: - if (rif->f->ref_count == 0) - mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif); + mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); +err_fid_port_vid_map: + mlxsw_sp_fid_put(fid); return err; } -static void -mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) +void +mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; u16 vid = mlxsw_sp_port_vlan->vid; - fid->ref_count--; - mlxsw_sp_port_vlan->fid = NULL; + if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID)) + return; - if (mlxsw_sp_port->nr_port_vid_map == 1) - mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); - mlxsw_sp_port->nr_port_vid_map--; + mlxsw_sp_port_vlan->fid = NULL; mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING); mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); - - if (fid->ref_count == 0) - mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, fid->rif); + mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); + /* If router port holds the last reference on the rFID, then the + * associated Sub-port RIF will be destroyed. + */ + mlxsw_sp_fid_put(fid); } static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, @@ -3203,10 +3174,10 @@ static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, switch (event) { case NETDEV_UP: - return mlxsw_sp_port_vlan_rif_sp_join(mlxsw_sp_port_vlan, + return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan, l3_dev); case NETDEV_DOWN: - mlxsw_sp_port_vlan_rif_sp_leave(mlxsw_sp_port_vlan); + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); break; } @@ -3254,96 +3225,65 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev, return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1); } -static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, - struct net_device *l3_dev) -{ - struct mlxsw_sp_fid *fid; - u16 fid_index; - - if (is_vlan_dev(l3_dev)) - fid_index = vlan_dev_vlan_id(l3_dev); - else if (br_vlan_enabled(l3_dev)) - fid_index = 1; - else - return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev); - - fid = mlxsw_sp_fid_find(mlxsw_sp, fid_index); - if (fid) - return fid; - - fid = mlxsw_sp_fid_create(mlxsw_sp, fid_index); - if (IS_ERR(fid)) - return NULL; - return fid; -} - static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp) { return mlxsw_core_max_ports(mlxsw_sp->core) + 1; } -static enum mlxsw_flood_table_type mlxsw_sp_flood_table_type_get(u16 fid) -{ - return mlxsw_sp_fid_is_vfid(fid) ? MLXSW_REG_SFGC_TABLE_TYPE_FID : - MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; -} - -static u16 mlxsw_sp_flood_table_index_get(u16 fid) -{ - return mlxsw_sp_fid_is_vfid(fid) ? mlxsw_sp_fid_to_vfid(fid) : fid; -} - -static int mlxsw_sp_router_port_flood_set(struct mlxsw_sp *mlxsw_sp, u16 fid, - bool set) -{ - u8 router_port = mlxsw_sp_router_port(mlxsw_sp); - enum mlxsw_flood_table_type table_type; - char *sftr_pl; - u16 index; - int err; - - sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); - if (!sftr_pl) - return -ENOMEM; - - table_type = mlxsw_sp_flood_table_type_get(fid); - index = mlxsw_sp_flood_table_index_get(fid); - mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BC, index, table_type, - 1, router_port, set); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl); - - kfree(sftr_pl); - return err; -} - -static enum mlxsw_reg_ritr_if_type mlxsw_sp_rif_type_get(u16 fid) +static enum mlxsw_reg_ritr_if_type +mlxsw_sp_rif_type_ritr_if_type(enum mlxsw_sp_rif_type rif_type) { - if (mlxsw_sp_fid_is_vfid(fid)) - return MLXSW_REG_RITR_FID_IF; - else + switch (rif_type) { + case MLXSW_SP_RIF_TYPE_SUBPORT: + return MLXSW_REG_RITR_SP_IF; + case MLXSW_SP_RIF_TYPE_VLAN: return MLXSW_REG_RITR_VLAN_IF; + case MLXSW_SP_RIF_TYPE_FID: + return MLXSW_REG_RITR_FID_IF; + default: + WARN_ON(1); + return 0; + } } static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_rif *rif, bool create) { - enum mlxsw_reg_ritr_if_type rif_type; + enum mlxsw_reg_ritr_if_type ritr_if_type; + enum mlxsw_sp_rif_type rif_type; char ritr_pl[MLXSW_REG_RITR_LEN]; - rif_type = mlxsw_sp_rif_type_get(rif->f->fid); + rif_type = mlxsw_sp_fid_rif_type(rif->fid); + ritr_if_type = mlxsw_sp_rif_type_ritr_if_type(rif_type); mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif->rif_index, rif->vr_id, rif->dev->mtu, rif->dev->dev_addr); - mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, rif->f->fid); + mlxsw_reg_ritr_fid_set(ritr_pl, ritr_if_type, + mlxsw_sp_fid_index(rif->fid)); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); } +static struct mlxsw_sp_fid * +mlxsw_sp_rif_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, + const struct net_device *dev) +{ + if (netif_is_bridge_master(dev) && !br_vlan_enabled(dev)) + return mlxsw_sp_fid_8021d_get(mlxsw_sp, dev->ifindex); + else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev)) + return mlxsw_sp_fid_8021q_get(mlxsw_sp, 1); + else if (is_vlan_dev(dev) && + netif_is_bridge_master(vlan_dev_real_dev(dev))) + return mlxsw_sp_fid_8021q_get(mlxsw_sp, vlan_dev_vlan_id(dev)); + else + return ERR_PTR(-EINVAL); +} + static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, - struct net_device *l3_dev, - struct mlxsw_sp_fid *f) + struct net_device *l3_dev) { u32 tb_id = l3mdev_fib_table(l3_dev); struct mlxsw_sp_rif *rif; + struct mlxsw_sp_fid *fid; struct mlxsw_sp_vr *vr; u16 rif_index; int err; @@ -3358,7 +3298,13 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, goto err_avail_rif_get; } - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, false); + fid = mlxsw_sp_rif_bridge_fid_get(mlxsw_sp, l3_dev); + if (IS_ERR(fid)) { + err = PTR_ERR(fid); + goto err_fid_get; + } + + rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, false); if (!rif) { err = -ENOMEM; goto err_rif_alloc; @@ -3368,15 +3314,17 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, if (err) goto err_rif_bridge_op; - err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), true); if (err) - goto err_port_flood_set; + goto err_fid_bc_flood_set; - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, true); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, + mlxsw_sp_fid_index(fid), true); if (err) goto err_rif_fdb_op; - f->rif = rif; + mlxsw_sp_fid_rif_set(fid, rif); mlxsw_sp->router->rifs[rif_index] = rif; vr->rif_count++; @@ -3385,64 +3333,58 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, return 0; err_rif_fdb_op: - mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); -err_port_flood_set: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), false); +err_fid_bc_flood_set: mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); err_rif_bridge_op: kfree(rif); err_rif_alloc: + mlxsw_sp_fid_put(fid); +err_fid_get: err_avail_rif_get: mlxsw_sp_vr_put(vr); return err; } -void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *rif) +static void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_rif *rif) { struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; struct net_device *l3_dev = rif->dev; - struct mlxsw_sp_fid *f = rif->f; + struct mlxsw_sp_fid *fid = rif->fid; u16 rif_index = rif->rif_index; mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); vr->rif_count--; mlxsw_sp->router->rifs[rif_index] = NULL; - f->rif = NULL; - - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false); - - mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); + mlxsw_sp_fid_rif_set(fid, NULL); + mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid), + false); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), false); mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); - kfree(rif); - + mlxsw_sp_fid_put(fid); mlxsw_sp_vr_put(vr); netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif_index); } static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev, - struct net_device *br_dev, unsigned long event) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev); - struct mlxsw_sp_fid *f; - - /* FID can either be an actual FID if the L3 device is the - * VLAN-aware bridge or a VLAN device on top. Otherwise, the - * L3 device is a VLAN-unaware bridge and we get a vFID. - */ - f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev); - if (WARN_ON(!f)) - return -EINVAL; + struct mlxsw_sp_rif *rif; switch (event) { case NETDEV_UP: - return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f); + return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev); case NETDEV_DOWN: - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); + mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif); break; } @@ -3462,8 +3404,7 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev, return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event, vid); else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev)) - return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev, - event); + return mlxsw_sp_inetaddr_bridge_event(vlan_dev, event); return 0; } @@ -3476,7 +3417,7 @@ static int __mlxsw_sp_inetaddr_event(struct net_device *dev, else if (netif_is_lag_master(dev)) return mlxsw_sp_inetaddr_lag_event(dev, event); else if (netif_is_bridge_master(dev)) - return mlxsw_sp_inetaddr_bridge_event(dev, dev, event); + return mlxsw_sp_inetaddr_bridge_event(dev, event); else if (is_vlan_dev(dev)) return mlxsw_sp_inetaddr_vlan_event(dev, event); else @@ -3526,6 +3467,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) { struct mlxsw_sp *mlxsw_sp; struct mlxsw_sp_rif *rif; + u16 fid_index; int err; mlxsw_sp = mlxsw_sp_lower_get(dev); @@ -3535,8 +3477,9 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); if (!rif) return 0; + fid_index = mlxsw_sp_fid_index(rif->fid); - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, false); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false); if (err) return err; @@ -3545,7 +3488,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) if (err) goto err_rif_edit; - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, rif->f->fid, true); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, fid_index, true); if (err) goto err_rif_fdb_op; @@ -3559,7 +3502,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) err_rif_fdb_op: mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu); err_rif_edit: - mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, true); + mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true); return err; } @@ -3612,6 +3555,14 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, return err; } +void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif) +{ + if (mlxsw_sp_fid_rif_type(rif->fid) == MLXSW_SP_RIF_TYPE_SUBPORT) + mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif); + else + mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif); +} + static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp) { u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index b17b224f2b1c..edcc273d7597 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -113,6 +113,9 @@ struct mlxsw_sp_bridge_ops { void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device, struct mlxsw_sp_bridge_port *bridge_port, struct mlxsw_sp_port *mlxsw_sp_port); + struct mlxsw_sp_fid * + (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid); }; static int @@ -361,7 +364,7 @@ mlxsw_sp_port_vlan_find_by_fid(struct mlxsw_sp_port *mlxsw_sp_port, list) { struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; - if (fid && fid->fid == fid_index) + if (fid && mlxsw_sp_fid_index(fid) == fid_index) return mlxsw_sp_port_vlan; } @@ -517,40 +520,10 @@ err_port_bridge_vlan_stp_set: return err; } -static int mlxsw_sp_port_fid_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, - struct mlxsw_sp_fid *fid, - enum mlxsw_sp_flood_table table, - bool member) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - u16 local_port = mlxsw_sp_port->local_port; - enum mlxsw_flood_table_type table_type; - u16 flood_index = fid->fid; - char *sftr_pl; - int err; - - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; - if (mlxsw_sp_fid_is_vfid(fid->fid)) { - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID; - flood_index = mlxsw_sp_fid_to_vfid(fid->fid); - } - - sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); - if (!sftr_pl) - return -ENOMEM; - - mlxsw_reg_sftr_pack(sftr_pl, table, flood_index, table_type, 1, - local_port, member); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl); - - kfree(sftr_pl); - return err; -} - static int mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, struct mlxsw_sp_bridge_vlan *bridge_vlan, - enum mlxsw_sp_flood_table table, + enum mlxsw_sp_flood_type packet_type, bool member) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; @@ -559,9 +532,10 @@ mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, bridge_vlan_node) { if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port) continue; - return mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, - mlxsw_sp_port_vlan->fid, - table, member); + return mlxsw_sp_fid_flood_set(mlxsw_sp_port_vlan->fid, + packet_type, + mlxsw_sp_port->local_port, + member); } return 0; @@ -570,7 +544,7 @@ mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, struct mlxsw_sp_bridge_port *bridge_port, - enum mlxsw_sp_flood_table table, + enum mlxsw_sp_flood_type packet_type, bool member) { struct mlxsw_sp_bridge_vlan *bridge_vlan; @@ -578,7 +552,8 @@ mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { err = mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, - bridge_vlan, table, + bridge_vlan, + packet_type, member); if (err) goto err_port_bridge_vlan_flood_set; @@ -590,7 +565,7 @@ err_port_bridge_vlan_flood_set: list_for_each_entry_continue_reverse(bridge_vlan, &bridge_port->vlans_list, list) mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, bridge_vlan, - table, !member); + packet_type, !member); return err; } @@ -654,7 +629,7 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, return -EINVAL; err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, - MLXSW_SP_FLOOD_TABLE_UC, + MLXSW_SP_FLOOD_TYPE_UC, brport_flags & BR_FLOOD); if (err) return err; @@ -742,7 +717,7 @@ static int mlxsw_sp_port_attr_mc_router_set(struct mlxsw_sp_port *mlxsw_sp_port, return 0; return mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, - MLXSW_SP_FLOOD_TABLE_MC, + MLXSW_SP_FLOOD_TYPE_MC, is_port_mc_router); } @@ -767,12 +742,12 @@ static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port, return 0; list_for_each_entry(bridge_port, &bridge_device->ports_list, list) { - enum mlxsw_sp_flood_table table = MLXSW_SP_FLOOD_TABLE_MC; + enum mlxsw_sp_flood_type packet_type = MLXSW_SP_FLOOD_TYPE_MC; bool member = mc_disabled ? true : bridge_port->mrouter; err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, - bridge_port, table, - member); + bridge_port, + packet_type, member); if (err) return err; } @@ -827,189 +802,6 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev, return err; } -static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) -{ - return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : - MLXSW_REG_SFMR_OP_DESTROY_FID; -} - -int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, bool valid) -{ - u16 fid_offset = fid_index < MLXSW_SP_VFID_BASE ? fid_index : 0; - char sfmr_pl[MLXSW_REG_SFMR_LEN]; - - mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index, - fid_offset); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); -} - -static int mlxsw_sp_fid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, - bool valid) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID; - char svfa_pl[MLXSW_REG_SVFA_LEN]; - - mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, fid_index); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); -} - -struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, - u16 fid_index) -{ - struct mlxsw_sp_fid *fid; - int err; - - err = mlxsw_sp_fid_op(mlxsw_sp, fid_index, true); - if (err) - return ERR_PTR(err); - - err = mlxsw_sp_fid_map(mlxsw_sp, fid_index, true); - if (err) - goto err_fid_map; - - fid = kzalloc(sizeof(*fid), GFP_KERNEL); - if (!fid) { - err = -ENOMEM; - goto err_allocate_fid; - } - - fid->fid = fid_index; - fid->ref_count = 1; - list_add(&fid->list, &mlxsw_sp->fids); - - return fid; - -err_allocate_fid: - mlxsw_sp_fid_map(mlxsw_sp, fid_index, false); -err_fid_map: - mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); - return ERR_PTR(err); -} - -static void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - u16 fid_index = fid->fid; - - list_del(&fid->list); - if (fid->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, fid->rif); - kfree(fid); - mlxsw_sp_fid_map(mlxsw_sp, fid_index, false); - mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); -} - -static struct mlxsw_sp_fid *mlxsw_sp_vfid_create(struct mlxsw_sp *mlxsw_sp, - struct net_device *dev) -{ - u16 vfid_index, fid_index; - struct mlxsw_sp_fid *fid; - int err; - - vfid_index = find_first_zero_bit(mlxsw_sp->vfids.mapped, - MLXSW_SP_VFID_MAX); - if (vfid_index == MLXSW_SP_VFID_MAX) - return ERR_PTR(-ENOBUFS); - - fid_index = mlxsw_sp_vfid_to_fid(vfid_index); - err = mlxsw_sp_fid_op(mlxsw_sp, fid_index, true); - if (err) - return ERR_PTR(err); - - fid = kzalloc(sizeof(*fid), GFP_KERNEL); - if (!fid) { - err = -ENOMEM; - goto err_allocate_fid; - } - - fid->fid = fid_index; - fid->ref_count = 1; - fid->dev = dev; - list_add(&fid->list, &mlxsw_sp->vfids.list); - __set_bit(vfid_index, mlxsw_sp->vfids.mapped); - - return fid; - -err_allocate_fid: - mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); - return ERR_PTR(err); -} - -static void mlxsw_sp_vfid_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - u16 vfid_index = mlxsw_sp_fid_to_vfid(fid->fid); - u16 fid_index = fid->fid; - - __clear_bit(vfid_index, mlxsw_sp->vfids.mapped); - list_del(&fid->list); - if (fid->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, fid->rif); - kfree(fid); - mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); -} - -static struct mlxsw_sp_fid *__mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, - u16 fid_index) -{ - struct mlxsw_sp_fid *fid; - - fid = mlxsw_sp_fid_find(mlxsw_sp, fid_index); - if (fid) { - fid->ref_count++; - return fid; - } - - return mlxsw_sp_fid_create(mlxsw_sp, fid_index); -} - -static struct mlxsw_sp_fid *mlxsw_sp_vfid_get(struct mlxsw_sp *mlxsw_sp, - struct net_device *dev) -{ - struct mlxsw_sp_fid *fid; - - fid = mlxsw_sp_vfid_find(mlxsw_sp, dev); - if (fid) { - fid->ref_count++; - return fid; - } - - return mlxsw_sp_vfid_create(mlxsw_sp, dev); -} - -static struct mlxsw_sp_fid * -mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, u16 vid, - struct mlxsw_sp_bridge_device *bridge_device) -{ - if (bridge_device->vlan_enabled) - return __mlxsw_sp_fid_get(mlxsw_sp, vid); - else - return mlxsw_sp_vfid_get(mlxsw_sp, bridge_device->dev); -} - -static void __mlxsw_sp_fid_put(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - if (--fid->ref_count == 0) - mlxsw_sp_fid_destroy(mlxsw_sp, fid); -} - -static void mlxsw_sp_vfid_put(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - if (--fid->ref_count == 0) - mlxsw_sp_vfid_destroy(mlxsw_sp, fid); -} - -static void mlxsw_sp_fid_put(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - if (!mlxsw_sp_fid_is_vfid(fid->fid)) - __mlxsw_sp_fid_put(mlxsw_sp, fid); - else - mlxsw_sp_vfid_put(mlxsw_sp, fid); -} - static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port) { const struct mlxsw_sp_bridge_device *bridge_device; @@ -1018,126 +810,53 @@ static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port) return !bridge_device->multicast_enabled ? true : bridge_port->mrouter; } -static int __mlxsw_sp_port_vid_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, u16 fid_index) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - int err; - - err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, fid_index, - vid); - if (err) - return err; - - if (mlxsw_sp_port->nr_port_vid_map++ == 0) { - err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); - if (err) - goto err_port_vp_mode_trans; - } - - return 0; - -err_port_vp_mode_trans: - mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, vid); - return err; -} - -static int __mlxsw_sp_port_vid_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, u16 fid_index) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - - if (mlxsw_sp_port->nr_port_vid_map == 1) - mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); - mlxsw_sp_port->nr_port_vid_map--; - - mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, vid); - - return 0; -} - -static int mlxsw_sp_port_vid_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, u16 fid_index) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - - if (mlxsw_sp_fid_is_vfid(fid_index)) - return __mlxsw_sp_port_vid_fid_map(mlxsw_sp_port, vid, - fid_index); - - if (mlxsw_sp_port->nr_port_vid_map == 0) - return 0; - - return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, fid_index, - fid_index); -} - -static int mlxsw_sp_port_vid_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, u16 fid_index) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - - if (mlxsw_sp_fid_is_vfid(fid_index)) - return __mlxsw_sp_port_vid_fid_unmap(mlxsw_sp_port, vid, - fid_index); - - if (mlxsw_sp_port->nr_port_vid_map == 0) - return 0; - - return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, - fid_index); -} - static int mlxsw_sp_port_vlan_fid_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct mlxsw_sp_bridge_port *bridge_port) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; + u8 local_port = mlxsw_sp_port->local_port; u16 vid = mlxsw_sp_port_vlan->vid; struct mlxsw_sp_fid *fid; int err; - fid = mlxsw_sp_fid_get(mlxsw_sp, vid, bridge_port->bridge_device); + bridge_device = bridge_port->bridge_device; + fid = bridge_device->ops->fid_get(bridge_device, vid); if (IS_ERR(fid)) return PTR_ERR(fid); - err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, - MLXSW_SP_FLOOD_TABLE_UC, - bridge_port->flags & BR_FLOOD); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, + bridge_port->flags & BR_FLOOD); if (err) - goto err_port_fid_uc_flood_set; + goto err_fid_uc_flood_set; - err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, - MLXSW_SP_FLOOD_TABLE_MC, - mlxsw_sp_mc_flood(bridge_port)); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, + mlxsw_sp_mc_flood(bridge_port)); if (err) - goto err_port_fid_mc_flood_set; + goto err_fid_mc_flood_set; - err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, - MLXSW_SP_FLOOD_TABLE_BC, true); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, + true); if (err) - goto err_port_fid_bc_flood_set; + goto err_fid_bc_flood_set; - err = mlxsw_sp_port_vid_fid_map(mlxsw_sp_port, vid, fid->fid); + err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid); if (err) - goto err_port_vid_fid_map; + goto err_fid_port_vid_map; mlxsw_sp_port_vlan->fid = fid; return 0; -err_port_vid_fid_map: - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_BC, - false); -err_port_fid_bc_flood_set: - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_MC, - false); -err_port_fid_mc_flood_set: - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_UC, - false); -err_port_fid_uc_flood_set: - mlxsw_sp_fid_put(mlxsw_sp, fid); +err_fid_port_vid_map: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false); +err_fid_bc_flood_set: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false); +err_fid_mc_flood_set: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false); +err_fid_uc_flood_set: + mlxsw_sp_fid_put(fid); return err; } @@ -1145,19 +864,16 @@ static void mlxsw_sp_port_vlan_fid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u8 local_port = mlxsw_sp_port->local_port; u16 vid = mlxsw_sp_port_vlan->vid; mlxsw_sp_port_vlan->fid = NULL; - mlxsw_sp_port_vid_fid_unmap(mlxsw_sp_port, vid, fid->fid); - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_BC, - false); - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_MC, - false); - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_UC, - false); - mlxsw_sp_fid_put(mlxsw_sp, fid); + mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false); + mlxsw_sp_fid_put(fid); } static u16 @@ -1233,6 +949,10 @@ mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) u16 vid = mlxsw_sp_port_vlan->vid; bool last; + if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021Q && + mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021D)) + return; + bridge_port = mlxsw_sp_port_vlan->bridge_port; bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); last = list_is_singular(&bridge_vlan->port_vlan_list); @@ -1243,7 +963,8 @@ mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); if (last) mlxsw_sp_bridge_port_fdb_flush(mlxsw_sp_port->mlxsw_sp, - bridge_port, fid->fid); + bridge_port, + mlxsw_sp_fid_index(fid)); mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan); mlxsw_sp_bridge_port_put(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port); @@ -1446,7 +1167,7 @@ mlxsw_sp_port_fdb_static_add(struct mlxsw_sp_port *mlxsw_sp_port, if (!mlxsw_sp_port_vlan) return 0; - fid_index = mlxsw_sp_port_vlan->fid->fid; + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); vid = mlxsw_sp_port_vlan->vid; if (!mlxsw_sp_port->lagged) @@ -1580,7 +1301,7 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port, if (WARN_ON(!mlxsw_sp_port_vlan)) return -EINVAL; - fid_index = mlxsw_sp_port_vlan->fid->fid; + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index); if (!mid) { @@ -1706,7 +1427,7 @@ mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port, if (!mlxsw_sp_port_vlan) return 0; - fid_index = mlxsw_sp_port_vlan->fid->fid; + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); vid = mlxsw_sp_port_vlan->vid; if (!mlxsw_sp_port->lagged) @@ -1746,7 +1467,7 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port, if (WARN_ON(!mlxsw_sp_port_vlan)) return -EINVAL; - fid_index = mlxsw_sp_port_vlan->fid->fid; + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index); if (!mid) { @@ -2000,9 +1721,19 @@ mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device, mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); } +static struct mlxsw_sp_fid * +mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + + return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid); +} + static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = { .port_join = mlxsw_sp_bridge_8021q_port_join, .port_leave = mlxsw_sp_bridge_8021q_port_leave, + .fid_get = mlxsw_sp_bridge_8021q_fid_get, }; static bool @@ -2028,7 +1759,6 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device, struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_fid *fid; u16 vid; if (!is_vlan_dev(bridge_port->dev)) @@ -2038,7 +1768,6 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device, mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); if (WARN_ON(!mlxsw_sp_port_vlan)) return -EINVAL; - fid = mlxsw_sp_port_vlan->fid; if (mlxsw_sp_port_is_br_member(mlxsw_sp_port, bridge_device->dev)) { netdev_err(mlxsw_sp_port->dev, "Can't bridge VLAN uppers of the same port\n"); @@ -2046,8 +1775,8 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device, } /* Port is no longer usable as a router interface */ - if (fid) - fid->leave(mlxsw_sp_port_vlan); + if (mlxsw_sp_port_vlan->fid) + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); return mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port); } @@ -2067,9 +1796,19 @@ mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device, mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); } +static struct mlxsw_sp_fid * +mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + + return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex); +} + static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = { .port_join = mlxsw_sp_bridge_8021d_port_join, .port_leave = mlxsw_sp_bridge_8021d_port_leave, + .fid_get = mlxsw_sp_bridge_8021d_fid_get, }; int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, -- cgit v1.2.3 From e4f3c1c17b6d101af5474e8c72b38aa0baaf719d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 26 May 2017 08:37:40 +0200 Subject: mlxsw: spectrum_router: Implement common RIF core The mlxsw driver currently implements three types of RIFs. VLAN and FID RIFs for L3 interfaces on top of VLAN-aware and VLAN-unaware bridges (respectively) and Subport RIFs for all other L3 interfaces. All the RIF types follow a common configuration procedure, which only differs in the type-specific bits. The patch exploits this fact and consolidates the common code paths, thereby simplifying the code and making it more extensible. This work also prepares the driver for use with future ASICs, where the range of the Subport RIFs will be extended and their configuration modified accordingly. By merely implementing a new RIF operations and selecting it during initialization, the same driver could be re-used. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 6 +- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 16 +- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 552 ++++++++++++--------- 3 files changed, 337 insertions(+), 237 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index c542b33e44c0..1a834109bda1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -381,7 +381,7 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, struct netdev_notifier_changeupper_info *info); void mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); -void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif); +void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif); int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count, u32 *p_entry_index); @@ -519,6 +519,10 @@ enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid); u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid); enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid); void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif); +enum mlxsw_sp_rif_type +mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_type type); +u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid); struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid); struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, int br_ifindex); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 379bbe001dd9..c7590aea1aee 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -205,12 +205,26 @@ void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif) fid->rif = rif; } +enum mlxsw_sp_rif_type +mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_type type) +{ + struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; + + return fid_core->fid_family_arr[type]->rif_type; +} + static struct mlxsw_sp_fid_8021q * mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid) { return container_of(fid, struct mlxsw_sp_fid_8021q, common); } +u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid) +{ + return mlxsw_sp_fid_8021q_fid(fid)->vid; +} + static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) { u16 vid = *(u16 *) arg; @@ -780,7 +794,7 @@ void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) /* Destroy the associated RIF and let it drop the last * reference on the FID. */ - return mlxsw_sp_rif_destroy(fid_family->mlxsw_sp, fid->rif); + return mlxsw_sp_rif_destroy(fid->rif); } else if (fid->ref_count == 0) { list_del(&fid->list); fid->fid_family->ops->deconfigure(fid); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 3c2e47deca0c..a4272c351e3a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -59,6 +59,7 @@ struct mlxsw_sp_vr; struct mlxsw_sp_lpm_tree; +struct mlxsw_sp_rif_ops; struct mlxsw_sp_router { struct mlxsw_sp *mlxsw_sp; @@ -80,6 +81,7 @@ struct mlxsw_sp_router { struct list_head nexthop_neighs_list; bool aborted; struct notifier_block fib_nb; + const struct mlxsw_sp_rif_ops **rif_ops_arr; }; struct mlxsw_sp_rif { @@ -91,12 +93,25 @@ struct mlxsw_sp_rif { int mtu; u16 rif_index; u16 vr_id; + const struct mlxsw_sp_rif_ops *ops; + struct mlxsw_sp *mlxsw_sp; + unsigned int counter_ingress; bool counter_ingress_valid; unsigned int counter_egress; bool counter_egress_valid; }; +struct mlxsw_sp_rif_params { + struct net_device *dev; + union { + u16 system_port; + u16 lag_id; + }; + u16 vid; + bool lag; +}; + struct mlxsw_sp_rif_subport { struct mlxsw_sp_rif common; union { @@ -107,6 +122,17 @@ struct mlxsw_sp_rif_subport { bool lag; }; +struct mlxsw_sp_rif_ops { + enum mlxsw_sp_rif_type type; + size_t rif_size; + + void (*setup)(struct mlxsw_sp_rif *rif, + const struct mlxsw_sp_rif_params *params); + int (*configure)(struct mlxsw_sp_rif *rif); + void (*deconfigure)(struct mlxsw_sp_rif *rif); + struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif); +}; + static unsigned int * mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif, enum mlxsw_sp_rif_counter_dir dir) @@ -255,6 +281,25 @@ void mlxsw_sp_rif_counter_free(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_rif_counter_valid_set(rif, dir, false); } +static void mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + struct devlink *devlink; + + devlink = priv_to_devlink(mlxsw_sp->core); + if (!devlink_dpipe_table_counter_enabled(devlink, + MLXSW_SP_DPIPE_TABLE_NAME_ERIF)) + return; + mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); +} + +static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + + mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); +} + static struct mlxsw_sp_rif * mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, const struct net_device *dev); @@ -2915,6 +2960,25 @@ static bool mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, return false; } +static enum mlxsw_sp_rif_type +mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp, + const struct net_device *dev) +{ + enum mlxsw_sp_fid_type type; + + /* RIF type is derived from the type of the underlying FID */ + if (is_vlan_dev(dev) && netif_is_bridge_master(vlan_dev_real_dev(dev))) + type = MLXSW_SP_FID_TYPE_8021Q; + else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev)) + type = MLXSW_SP_FID_TYPE_8021Q; + else if (netif_is_bridge_master(dev)) + type = MLXSW_SP_FID_TYPE_8021D; + else + type = MLXSW_SP_FID_TYPE_RFID; + + return mlxsw_sp_fid_type_rif_type(mlxsw_sp, type); +} + #define MLXSW_SP_INVALID_INDEX_RIF 0xffff static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp) { @@ -2927,34 +2991,13 @@ static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp) return MLXSW_SP_INVALID_INDEX_RIF; } -static int -mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp *mlxsw_sp, - const struct mlxsw_sp_rif *rif, bool create) -{ - struct mlxsw_sp_rif_subport *rif_subport; - char ritr_pl[MLXSW_REG_RITR_LEN]; - - rif_subport = container_of(rif, struct mlxsw_sp_rif_subport, common); - mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, - rif->rif_index, rif->vr_id, rif->dev->mtu, - rif->dev->dev_addr); - mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag, - rif_subport->lag ? rif_subport->lag_id : - rif_subport->system_port, - rif_subport->vid); - - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); -} - -static struct mlxsw_sp_rif * -mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, - struct mlxsw_sp_fid *fid, bool is_subport) +static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, + u16 vr_id, + struct net_device *l3_dev) { - size_t size = is_subport ? sizeof(struct mlxsw_sp_rif_subport) : - sizeof(struct mlxsw_sp_rif); struct mlxsw_sp_rif *rif; - rif = kzalloc(size, GFP_KERNEL); + rif = kzalloc(rif_size, GFP_KERNEL); if (!rif) return NULL; @@ -2965,7 +3008,6 @@ mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, rif->vr_id = vr_id; rif->dev = l3_dev; rif->rif_index = rif_index; - rif->fid = fid; return rif; } @@ -2987,19 +3029,21 @@ int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif) } static struct mlxsw_sp_rif * -mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, - struct net_device *l3_dev) +mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_rif_params *params) { - struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct mlxsw_sp_rif_subport *rif_subport; - u32 tb_id = l3mdev_fib_table(l3_dev); + u32 tb_id = l3mdev_fib_table(params->dev); + const struct mlxsw_sp_rif_ops *ops; + enum mlxsw_sp_rif_type type; struct mlxsw_sp_rif *rif; struct mlxsw_sp_fid *fid; struct mlxsw_sp_vr *vr; u16 rif_index; int err; + type = mlxsw_sp_dev_rif_type(mlxsw_sp, params->dev); + ops = mlxsw_sp->router->rif_ops_arr[type]; + vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); if (IS_ERR(vr)) return ERR_CAST(vr); @@ -3010,46 +3054,34 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, goto err_avail_rif_get; } - fid = mlxsw_sp_fid_rfid_get(mlxsw_sp, rif_index); - if (IS_ERR(fid)) { - err = PTR_ERR(fid); - goto err_fid_get; - } - - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, true); + rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, params->dev); if (!rif) { err = -ENOMEM; goto err_rif_alloc; } + rif->mlxsw_sp = mlxsw_sp; + rif->ops = ops; - rif_subport = container_of(rif, struct mlxsw_sp_rif_subport, common); - rif_subport->vid = mlxsw_sp_port_vlan->vid; - if (mlxsw_sp_port->lagged) { - rif_subport->lag = true; - rif_subport->lag_id = mlxsw_sp_port->lag_id; - } else { - rif_subport->lag = false; - rif_subport->system_port = mlxsw_sp_port->local_port; + fid = ops->fid_get(rif); + if (IS_ERR(fid)) { + err = PTR_ERR(fid); + goto err_fid_get; } + rif->fid = fid; - err = mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, true); + if (ops->setup) + ops->setup(rif, params); + + err = ops->configure(rif); if (err) - goto err_port_vlan_rif_sp_op; + goto err_configure; - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, params->dev->dev_addr, mlxsw_sp_fid_index(fid), true); if (err) goto err_rif_fdb_op; - if (devlink_dpipe_table_counter_enabled(priv_to_devlink(mlxsw_sp->core), - MLXSW_SP_DPIPE_TABLE_NAME_ERIF)) { - err = mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, - MLXSW_SP_RIF_COUNTER_EGRESS); - if (err) - netdev_dbg(mlxsw_sp_port->dev, - "Counter alloc Failed err=%d\n", err); - } - + mlxsw_sp_rif_counters_alloc(rif); mlxsw_sp_fid_rif_set(fid, rif); mlxsw_sp->router->rifs[rif_index] = rif; vr->rif_count++; @@ -3057,43 +3089,53 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, return rif; err_rif_fdb_op: - mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false); -err_port_vlan_rif_sp_op: - kfree(rif); -err_rif_alloc: + ops->deconfigure(rif); +err_configure: mlxsw_sp_fid_put(fid); err_fid_get: + kfree(rif); +err_rif_alloc: err_avail_rif_get: mlxsw_sp_vr_put(vr); return ERR_PTR(err); } -static void -mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *rif) +void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) { - struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; - struct net_device *l3_dev = rif->dev; + const struct mlxsw_sp_rif_ops *ops = rif->ops; + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; struct mlxsw_sp_fid *fid = rif->fid; - u16 rif_index = rif->rif_index; + struct mlxsw_sp_vr *vr; mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); - - mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS); - mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_INGRESS); + vr = &mlxsw_sp->router->vrs[rif->vr_id]; vr->rif_count--; - mlxsw_sp->router->rifs[rif_index] = NULL; + mlxsw_sp->router->rifs[rif->rif_index] = NULL; mlxsw_sp_fid_rif_set(fid, NULL); - - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid), - false); - mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false); - kfree(rif); + mlxsw_sp_rif_counters_free(rif); + mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->dev->dev_addr, + mlxsw_sp_fid_index(fid), false); + ops->deconfigure(rif); mlxsw_sp_fid_put(fid); + kfree(rif); mlxsw_sp_vr_put(vr); } +static void +mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params, + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) +{ + struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; + + params->vid = mlxsw_sp_port_vlan->vid; + params->lag = mlxsw_sp_port->lagged; + if (params->lag) + params->lag_id = mlxsw_sp_port->lag_id; + else + params->system_port = mlxsw_sp_port->local_port; +} + static int mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct net_device *l3_dev) @@ -3107,14 +3149,18 @@ mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); if (!rif) { - rif = mlxsw_sp_port_vlan_rif_sp_create(mlxsw_sp_port_vlan, - l3_dev); + struct mlxsw_sp_rif_params params = { + .dev = l3_dev, + }; + + mlxsw_sp_rif_subport_params_init(¶ms, mlxsw_sp_port_vlan); + rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms); if (IS_ERR(rif)) return PTR_ERR(rif); } /* FID was already created, just take a reference */ - fid = mlxsw_sp_fid_rfid_get(mlxsw_sp_port->mlxsw_sp, rif->rif_index); + fid = rif->ops->fid_get(rif); err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid); if (err) goto err_fid_port_vid_map; @@ -3225,166 +3271,24 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev, return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1); } -static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp) -{ - return mlxsw_core_max_ports(mlxsw_sp->core) + 1; -} - -static enum mlxsw_reg_ritr_if_type -mlxsw_sp_rif_type_ritr_if_type(enum mlxsw_sp_rif_type rif_type) -{ - switch (rif_type) { - case MLXSW_SP_RIF_TYPE_SUBPORT: - return MLXSW_REG_RITR_SP_IF; - case MLXSW_SP_RIF_TYPE_VLAN: - return MLXSW_REG_RITR_VLAN_IF; - case MLXSW_SP_RIF_TYPE_FID: - return MLXSW_REG_RITR_FID_IF; - default: - WARN_ON(1); - return 0; - } -} - -static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp, - const struct mlxsw_sp_rif *rif, bool create) -{ - enum mlxsw_reg_ritr_if_type ritr_if_type; - enum mlxsw_sp_rif_type rif_type; - char ritr_pl[MLXSW_REG_RITR_LEN]; - - rif_type = mlxsw_sp_fid_rif_type(rif->fid); - ritr_if_type = mlxsw_sp_rif_type_ritr_if_type(rif_type); - mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif->rif_index, - rif->vr_id, rif->dev->mtu, rif->dev->dev_addr); - mlxsw_reg_ritr_fid_set(ritr_pl, ritr_if_type, - mlxsw_sp_fid_index(rif->fid)); - - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); -} - -static struct mlxsw_sp_fid * -mlxsw_sp_rif_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, - const struct net_device *dev) -{ - if (netif_is_bridge_master(dev) && !br_vlan_enabled(dev)) - return mlxsw_sp_fid_8021d_get(mlxsw_sp, dev->ifindex); - else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev)) - return mlxsw_sp_fid_8021q_get(mlxsw_sp, 1); - else if (is_vlan_dev(dev) && - netif_is_bridge_master(vlan_dev_real_dev(dev))) - return mlxsw_sp_fid_8021q_get(mlxsw_sp, vlan_dev_vlan_id(dev)); - else - return ERR_PTR(-EINVAL); -} - -static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, - struct net_device *l3_dev) -{ - u32 tb_id = l3mdev_fib_table(l3_dev); - struct mlxsw_sp_rif *rif; - struct mlxsw_sp_fid *fid; - struct mlxsw_sp_vr *vr; - u16 rif_index; - int err; - - vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); - if (IS_ERR(vr)) - return PTR_ERR(vr); - - rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp); - if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) { - err = -ERANGE; - goto err_avail_rif_get; - } - - fid = mlxsw_sp_rif_bridge_fid_get(mlxsw_sp, l3_dev); - if (IS_ERR(fid)) { - err = PTR_ERR(fid); - goto err_fid_get; - } - - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, false); - if (!rif) { - err = -ENOMEM; - goto err_rif_alloc; - } - - err = mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, true); - if (err) - goto err_rif_bridge_op; - - err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, - mlxsw_sp_router_port(mlxsw_sp), true); - if (err) - goto err_fid_bc_flood_set; - - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, - mlxsw_sp_fid_index(fid), true); - if (err) - goto err_rif_fdb_op; - - mlxsw_sp_fid_rif_set(fid, rif); - mlxsw_sp->router->rifs[rif_index] = rif; - vr->rif_count++; - - netdev_dbg(l3_dev, "RIF=%d created\n", rif_index); - - return 0; - -err_rif_fdb_op: - mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, - mlxsw_sp_router_port(mlxsw_sp), false); -err_fid_bc_flood_set: - mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); -err_rif_bridge_op: - kfree(rif); -err_rif_alloc: - mlxsw_sp_fid_put(fid); -err_fid_get: -err_avail_rif_get: - mlxsw_sp_vr_put(vr); - return err; -} - -static void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *rif) -{ - struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; - struct net_device *l3_dev = rif->dev; - struct mlxsw_sp_fid *fid = rif->fid; - u16 rif_index = rif->rif_index; - - mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); - - vr->rif_count--; - mlxsw_sp->router->rifs[rif_index] = NULL; - mlxsw_sp_fid_rif_set(fid, NULL); - - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid), - false); - mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, - mlxsw_sp_router_port(mlxsw_sp), false); - mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); - kfree(rif); - mlxsw_sp_fid_put(fid); - mlxsw_sp_vr_put(vr); - - netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif_index); -} - static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev, unsigned long event) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev); + struct mlxsw_sp_rif_params params = { + .dev = l3_dev, + }; struct mlxsw_sp_rif *rif; switch (event) { case NETDEV_UP: - return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev); + rif = mlxsw_sp_rif_create(mlxsw_sp, ¶ms); + if (IS_ERR(rif)) + return PTR_ERR(rif); + break; case NETDEV_DOWN: rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif); + mlxsw_sp_rif_destroy(rif); break; } @@ -3555,14 +3459,189 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, return err; } -void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif) +static struct mlxsw_sp_rif_subport * +mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif) { - if (mlxsw_sp_fid_rif_type(rif->fid) == MLXSW_SP_RIF_TYPE_SUBPORT) - mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif); + return container_of(rif, struct mlxsw_sp_rif_subport, common); +} + +static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif, + const struct mlxsw_sp_rif_params *params) +{ + struct mlxsw_sp_rif_subport *rif_subport; + + rif_subport = mlxsw_sp_rif_subport_rif(rif); + rif_subport->vid = params->vid; + rif_subport->lag = params->lag; + if (params->lag) + rif_subport->lag_id = params->lag_id; else - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif); + rif_subport->system_port = params->system_port; +} + +static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + struct mlxsw_sp_rif_subport *rif_subport; + char ritr_pl[MLXSW_REG_RITR_LEN]; + + rif_subport = mlxsw_sp_rif_subport_rif(rif); + mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF, + rif->rif_index, rif->vr_id, rif->dev->mtu, + rif->dev->dev_addr); + mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag, + rif_subport->lag ? rif_subport->lag_id : + rif_subport->system_port, + rif_subport->vid); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); +} + +static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif) +{ + return mlxsw_sp_rif_subport_op(rif, true); } +static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif) +{ + mlxsw_sp_rif_subport_op(rif, false); +} + +static struct mlxsw_sp_fid * +mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif) +{ + return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index); +} + +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops = { + .type = MLXSW_SP_RIF_TYPE_SUBPORT, + .rif_size = sizeof(struct mlxsw_sp_rif_subport), + .setup = mlxsw_sp_rif_subport_setup, + .configure = mlxsw_sp_rif_subport_configure, + .deconfigure = mlxsw_sp_rif_subport_deconfigure, + .fid_get = mlxsw_sp_rif_subport_fid_get, +}; + +static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif *rif, + enum mlxsw_reg_ritr_if_type type, + u16 vid_fid, bool enable) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + char ritr_pl[MLXSW_REG_RITR_LEN]; + + mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id, + rif->dev->mtu, rif->dev->dev_addr); + mlxsw_reg_ritr_fid_set(ritr_pl, type, vid_fid); + + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); +} + +static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_core_max_ports(mlxsw_sp->core) + 1; +} + +static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); + int err; + + err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, true); + if (err) + return err; + + err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), true); + if (err) + goto err_fid_bc_flood_set; + + return 0; + +err_fid_bc_flood_set: + mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false); + return err; +} + +static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); + + mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), false); + mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false); +} + +static struct mlxsw_sp_fid * +mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif) +{ + u16 vid = is_vlan_dev(rif->dev) ? vlan_dev_vlan_id(rif->dev) : 1; + + return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid); +} + +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops = { + .type = MLXSW_SP_RIF_TYPE_VLAN, + .rif_size = sizeof(struct mlxsw_sp_rif), + .configure = mlxsw_sp_rif_vlan_configure, + .deconfigure = mlxsw_sp_rif_vlan_deconfigure, + .fid_get = mlxsw_sp_rif_vlan_fid_get, +}; + +static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + u16 fid_index = mlxsw_sp_fid_index(rif->fid); + int err; + + err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, + true); + if (err) + return err; + + err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), true); + if (err) + goto err_fid_bc_flood_set; + + return 0; + +err_fid_bc_flood_set: + mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false); + return err; +} + +static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif) +{ + struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + u16 fid_index = mlxsw_sp_fid_index(rif->fid); + + mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), false); + mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false); +} + +static struct mlxsw_sp_fid * +mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif) +{ + return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif->dev->ifindex); +} + +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = { + .type = MLXSW_SP_RIF_TYPE_FID, + .rif_size = sizeof(struct mlxsw_sp_rif), + .configure = mlxsw_sp_rif_fid_configure, + .deconfigure = mlxsw_sp_rif_fid_deconfigure, + .fid_get = mlxsw_sp_rif_fid_fid_get, +}; + +static const struct mlxsw_sp_rif_ops *mlxsw_sp_rif_ops_arr[] = { + [MLXSW_SP_RIF_TYPE_SUBPORT] = &mlxsw_sp_rif_subport_ops, + [MLXSW_SP_RIF_TYPE_VLAN] = &mlxsw_sp_rif_vlan_ops, + [MLXSW_SP_RIF_TYPE_FID] = &mlxsw_sp_rif_fid_ops, +}; + static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp) { u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); @@ -3572,6 +3651,9 @@ static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp) GFP_KERNEL); if (!mlxsw_sp->router->rifs) return -ENOMEM; + + mlxsw_sp->router->rif_ops_arr = mlxsw_sp_rif_ops_arr; + return 0; } -- cgit v1.2.3 From d944c3d60ac9ec6968d97ac5704155d0afac5216 Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 26 May 2017 10:30:13 -0400 Subject: ibmvnic: Track state of adapter napis Track the state of ibmvnic napis. The driver can get into states where it can be reset when napis are already disabled and attempting to disable them again will cause the driver to hang. Signed-off-by: John Allen Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 37 ++++++++++++++++++++++++++++--------- drivers/net/ethernet/ibm/ibmvnic.h | 1 + 2 files changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 27f79339e9a8..4997de425b5c 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -518,6 +518,32 @@ static void release_error_buffers(struct ibmvnic_adapter *adapter) spin_unlock_irqrestore(&adapter->error_list_lock, flags); } +static void ibmvnic_napi_enable(struct ibmvnic_adapter *adapter) +{ + int i; + + if (adapter->napi_enabled) + return; + + for (i = 0; i < adapter->req_rx_queues; i++) + napi_enable(&adapter->napi[i]); + + adapter->napi_enabled = true; +} + +static void ibmvnic_napi_disable(struct ibmvnic_adapter *adapter) +{ + int i; + + if (!adapter->napi_enabled) + return; + + for (i = 0; i < adapter->req_rx_queues; i++) + napi_disable(&adapter->napi[i]); + + adapter->napi_enabled = false; +} + static int ibmvnic_login(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); @@ -674,9 +700,7 @@ static int __ibmvnic_open(struct net_device *netdev) adapter->state = VNIC_OPENING; replenish_pools(adapter); - - for (i = 0; i < adapter->req_rx_queues; i++) - napi_enable(&adapter->napi[i]); + ibmvnic_napi_enable(adapter); /* We're ready to receive frames, enable the sub-crq interrupts and * set the logical link state to up @@ -779,12 +803,7 @@ static int __ibmvnic_close(struct net_device *netdev) adapter->state = VNIC_CLOSING; netif_tx_stop_all_queues(netdev); - - if (adapter->napi) { - for (i = 0; i < adapter->req_rx_queues; i++) - napi_disable(&adapter->napi[i]); - } - + ibmvnic_napi_disable(adapter); clean_tx_pools(adapter); if (adapter->tx_scrq) { diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 4702b48cfa44..4816e0425025 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1031,4 +1031,5 @@ struct ibmvnic_adapter { struct list_head rwi_list; struct work_struct ibmvnic_reset; bool resetting; + bool napi_enabled; }; -- cgit v1.2.3 From 017892c1ec15d4efcb30edf9fb56a64c889540c3 Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 26 May 2017 10:30:19 -0400 Subject: ibmvnic: Handle failover after failed init crq Handle case where phyp sends a failover after failing to send the init crq. Signed-off-by: John Allen Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 11 ++++++++++- drivers/net/ethernet/ibm/ibmvnic.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 4997de425b5c..1f7cf6fbe150 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3167,6 +3167,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, switch (gen_crq->cmd) { case IBMVNIC_CRQ_INIT: dev_info(dev, "Partner initialized\n"); + adapter->from_passive_init = true; + complete(&adapter->init_done); break; case IBMVNIC_CRQ_INIT_COMPLETE: dev_info(dev, "Partner initialization complete\n"); @@ -3481,11 +3483,18 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) return rc; } + adapter->from_passive_init = false; + init_completion(&adapter->init_done); ibmvnic_send_crq_init(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { dev_err(dev, "Initialization sequence timed out\n"); - release_crq_queue(adapter); + return -1; + } + + if (adapter->from_passive_init) { + adapter->state = VNIC_OPEN; + adapter->from_passive_init = false; return -1; } diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 4816e0425025..fa6ac4e4a16e 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1031,5 +1031,5 @@ struct ibmvnic_adapter { struct list_head rwi_list; struct work_struct ibmvnic_reset; bool resetting; - bool napi_enabled; + bool napi_enabled, from_passive_init; }; -- cgit v1.2.3 From 2ce9e4efbf4289ce48144ec4986f58033890fb6d Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 26 May 2017 10:30:25 -0400 Subject: ibmvnic: Send gratuitous arp on reset Send gratuitous arp after any reset. Signed-off-by: John Allen Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 1f7cf6fbe150..465a8fafd95b 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1273,6 +1273,7 @@ static int do_reset(struct ibmvnic_adapter *adapter, for (i = 0; i < adapter->req_rx_queues; i++) napi_schedule(&adapter->napi[i]); + netdev_notify_peers(netdev); return 0; } -- cgit v1.2.3 From 10f7621588b86d181a167c1535d0754eb5a58ba8 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 26 May 2017 10:30:31 -0400 Subject: ibmvnic: Fix cleanup of SKB's on driver close A race condition occurs when closing the driver. Free'ing of skb's can race between the close routine and ibmvnic_tx_interrupt. To fix this we move the claenup of tx pools during close to after the sub-CRQ interrupts are disabled. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 465a8fafd95b..0f705e68755f 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -804,7 +804,6 @@ static int __ibmvnic_close(struct net_device *netdev) adapter->state = VNIC_CLOSING; netif_tx_stop_all_queues(netdev); ibmvnic_napi_disable(adapter); - clean_tx_pools(adapter); if (adapter->tx_scrq) { for (i = 0; i < adapter->req_tx_queues; i++) @@ -833,6 +832,7 @@ static int __ibmvnic_close(struct net_device *netdev) } } + clean_tx_pools(adapter); adapter->state = VNIC_CLOSED; return rc; } -- cgit v1.2.3 From 8cb31cfc9448e2ce0bda899eb15f74bc0a875d90 Mon Sep 17 00:00:00 2001 From: John Allen Date: Fri, 26 May 2017 10:30:37 -0400 Subject: ibmvnic: Non-fatal error handling Handle non-fatal error conditions. The process to do this when resetting the driver is to just do __ibmvnic_close followed by __ibmvnic_open. Signed-off-by: John Allen Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 56 +++++++++++++++++++++----------------- drivers/net/ethernet/ibm/ibmvnic.h | 1 + 2 files changed, 32 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 0f705e68755f..def867aaa422 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1225,37 +1225,41 @@ static int do_reset(struct ibmvnic_adapter *adapter, if (rc) return rc; - /* remove the closed state so when we call open it appears - * we are coming from the probed state. - */ - adapter->state = VNIC_PROBED; + if (adapter->reset_reason != VNIC_RESET_NON_FATAL) { + /* remove the closed state so when we call open it appears + * we are coming from the probed state. + */ + adapter->state = VNIC_PROBED; - release_resources(adapter); - release_sub_crqs(adapter); - release_crq_queue(adapter); + release_resources(adapter); + release_sub_crqs(adapter); + release_crq_queue(adapter); - rc = ibmvnic_init(adapter); - if (rc) - return 0; + rc = ibmvnic_init(adapter); + if (rc) + return 0; - /* If the adapter was in PROBE state prior to the reset, exit here. */ - if (reset_state == VNIC_PROBED) - return 0; + /* If the adapter was in PROBE state prior to the reset, + * exit here. + */ + if (reset_state == VNIC_PROBED) + return 0; - rc = ibmvnic_login(netdev); - if (rc) { - adapter->state = VNIC_PROBED; - return 0; - } + rc = ibmvnic_login(netdev); + if (rc) { + adapter->state = VNIC_PROBED; + return 0; + } - rtnl_lock(); - rc = init_resources(adapter); - rtnl_unlock(); - if (rc) - return rc; + rtnl_lock(); + rc = init_resources(adapter); + rtnl_unlock(); + if (rc) + return rc; - if (reset_state == VNIC_CLOSED) - return 0; + if (reset_state == VNIC_CLOSED) + return 0; + } rc = __ibmvnic_open(netdev); if (rc) { @@ -2763,6 +2767,8 @@ static void handle_error_indication(union ibmvnic_crq *crq, if (crq->error_indication.flags & IBMVNIC_FATAL_ERROR) ibmvnic_reset(adapter, VNIC_RESET_FATAL); + else + ibmvnic_reset(adapter, VNIC_RESET_NON_FATAL); } static void handle_change_mac_rsp(union ibmvnic_crq *crq, diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index fa6ac4e4a16e..7e2300e64a47 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -925,6 +925,7 @@ enum vnic_state {VNIC_PROBING = 1, enum ibmvnic_reset_reason {VNIC_RESET_FAILOVER = 1, VNIC_RESET_MOBILITY, VNIC_RESET_FATAL, + VNIC_RESET_NON_FATAL, VNIC_RESET_TIMEOUT}; struct ibmvnic_rwi { -- cgit v1.2.3 From b8c80b8413eec7ae154cdad692a7fd1cb32d0370 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 26 May 2017 10:30:42 -0400 Subject: ibmvnic: Halt TX and report carrier off on H_CLOSED return code This patch disables transmissions and reports carrier off if xmit function returns that the hardware TX queue is closed. The driver can then await a signal from firmware to determine the correct reset method. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index def867aaa422..1c3f1edea9db 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1111,8 +1111,14 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb_any(skb); tx_buff->skb = NULL; - if (lpar_rc == H_CLOSED) - netif_stop_subqueue(netdev, queue_num); + if (lpar_rc == H_CLOSED) { + /* Disable TX and report carrier off if queue is closed. + * Firmware guarantees that a signal will be sent to the + * driver, triggering a reset or some other action. + */ + netif_tx_stop_all_queues(netdev); + netif_carrier_off(netdev); + } tx_send_failed++; tx_dropped++; -- cgit v1.2.3 From f185a49a77bd34309fd6af6c5c7695386d010534 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 26 May 2017 10:30:48 -0400 Subject: ibmvnic: Deactivate RX pool buffer replenishment on H_CLOSED If H_CLOSED is returned, halt RX buffer replenishment activity until firmware sends a notification that the driver can reset. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 1c3f1edea9db..47421e4052c3 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -200,6 +200,15 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter, dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); } +static void deactivate_rx_pools(struct ibmvnic_adapter *adapter) +{ + int i; + + for (i = 0; i < be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + i++) + adapter->rx_pool[i].active = 0; +} + static void replenish_rx_pool(struct ibmvnic_adapter *adapter, struct ibmvnic_rx_pool *pool) { @@ -217,6 +226,9 @@ static void replenish_rx_pool(struct ibmvnic_adapter *adapter, int index; int i; + if (!pool->active) + return; + handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) + be32_to_cpu(adapter->login_rsp_buf-> off_rxadd_subcrqs)); @@ -287,6 +299,15 @@ failure: dev_kfree_skb_any(skb); adapter->replenish_add_buff_failure++; atomic_add(buffers_added, &pool->available); + + if (lpar_rc == H_CLOSED) { + /* Disable buffer pool replenishment and report carrier off if + * queue is closed. Firmware guarantees that a signal will + * be sent to the driver, triggering a reset. + */ + deactivate_rx_pools(adapter); + netif_carrier_off(adapter->netdev); + } } static void replenish_pools(struct ibmvnic_adapter *adapter) -- cgit v1.2.3 From 152ce47dc48280182ab58539a721dadb3d7a8575 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 26 May 2017 10:30:54 -0400 Subject: ibmvnic: Check adapter state during ibmvnic_poll We do not want to process any receive frames if the ibmvnic_poll routine is invoked while a reset is in process. Also, before replenishing the rx pools in the ibmvnic_poll, we want to make sure the adapter is not in the process of closing. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 47421e4052c3..760352f7f98d 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1435,6 +1435,10 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget) struct ibmvnic_adapter *adapter = netdev_priv(netdev); int scrq_num = (int)(napi - adapter->napi); int frames_processed = 0; + + if (adapter->resetting) + return 0; + restart_poll: while (frames_processed < budget) { struct sk_buff *skb; @@ -1493,7 +1497,9 @@ restart_poll: netdev->stats.rx_bytes += length; frames_processed++; } - replenish_rx_pool(adapter, &adapter->rx_pool[scrq_num]); + + if (adapter->state != VNIC_CLOSING) + replenish_rx_pool(adapter, &adapter->rx_pool[scrq_num]); if (frames_processed < budget) { enable_scrq_irq(adapter, adapter->rx_scrq[scrq_num]); -- cgit v1.2.3 From 28cde751021abb16458b858da3403bd7c511c0d7 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 26 May 2017 10:31:00 -0400 Subject: ibmvnic: Reset the CRQ queue during driver reset When a driver reset operation occurs there is not a need to release the CRQ resources and re-allocate them. Instead a reset of the CRQ will suffice. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 760352f7f98d..b9b0c693ce01 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1260,7 +1260,6 @@ static int do_reset(struct ibmvnic_adapter *adapter, release_resources(adapter); release_sub_crqs(adapter); - release_crq_queue(adapter); rc = ibmvnic_init(adapter); if (rc) @@ -3517,7 +3516,14 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) unsigned long timeout = msecs_to_jiffies(30000); int rc; - rc = init_crq_queue(adapter); + if (adapter->resetting) { + rc = ibmvnic_reset_crq(adapter); + if (!rc) + rc = vio_enable_interrupts(adapter->vdev); + } else { + rc = init_crq_queue(adapter); + } + if (rc) { dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc); return rc; -- cgit v1.2.3 From 8c0543adca2bb17808e46a24eb6e6247181a10b1 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 26 May 2017 10:31:06 -0400 Subject: ibmvnic: Reset tx/rx pools on driver reset When resetting the ibmvnic driver there is not a need to release and re-allocate the resources for the tx and rx pools. These resources can just be reset to avoid the re-allocations. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 71 +++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index b9b0c693ce01..5661a043f5e5 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -163,6 +163,16 @@ static long h_reg_sub_crq(unsigned long unit_address, unsigned long token, return rc; } +static void reset_long_term_buff(struct ibmvnic_adapter *adapter, + struct ibmvnic_long_term_buff *ltb) +{ + memset(ltb->buff, 0, ltb->size); + + init_completion(&adapter->fw_done); + send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); + wait_for_completion(&adapter->fw_done); +} + static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb, int size) { @@ -352,6 +362,32 @@ static int init_stats_token(struct ibmvnic_adapter *adapter) return 0; } +static int reset_rx_pools(struct ibmvnic_adapter *adapter) +{ + struct ibmvnic_rx_pool *rx_pool; + int rx_scrqs; + int i, j; + + rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + for (i = 0; i < rx_scrqs; i++) { + rx_pool = &adapter->rx_pool[i]; + + reset_long_term_buff(adapter, &rx_pool->long_term_buff); + + for (j = 0; j < rx_pool->size; j++) + rx_pool->free_map[j] = j; + + memset(rx_pool->rx_buff, 0, + rx_pool->size * sizeof(struct ibmvnic_rx_buff)); + + atomic_set(&rx_pool->available, 0); + rx_pool->next_alloc = 0; + rx_pool->next_free = 0; + } + + return 0; +} + static void release_rx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_rx_pool *rx_pool; @@ -453,6 +489,32 @@ static int init_rx_pools(struct net_device *netdev) return 0; } +static int reset_tx_pools(struct ibmvnic_adapter *adapter) +{ + struct ibmvnic_tx_pool *tx_pool; + int tx_scrqs; + int i, j; + + tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); + for (i = 0; i < tx_scrqs; i++) { + tx_pool = &adapter->tx_pool[i]; + + reset_long_term_buff(adapter, &tx_pool->long_term_buff); + + memset(tx_pool->tx_buff, 0, + adapter->req_tx_entries_per_subcrq * + sizeof(struct ibmvnic_tx_buff)); + + for (j = 0; j < adapter->req_tx_entries_per_subcrq; j++) + tx_pool->free_map[j] = j; + + tx_pool->consumer_index = 0; + tx_pool->producer_index = 0; + } + + return 0; +} + static void release_tx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_tx_pool *tx_pool; @@ -1258,7 +1320,6 @@ static int do_reset(struct ibmvnic_adapter *adapter, */ adapter->state = VNIC_PROBED; - release_resources(adapter); release_sub_crqs(adapter); rc = ibmvnic_init(adapter); @@ -1277,9 +1338,11 @@ static int do_reset(struct ibmvnic_adapter *adapter, return 0; } - rtnl_lock(); - rc = init_resources(adapter); - rtnl_unlock(); + rc = reset_tx_pools(adapter); + if (rc) + return rc; + + rc = reset_rx_pools(adapter); if (rc) return rc; -- cgit v1.2.3 From 57a49436f4e8a76a9125c44d084d12b2c6e6206c Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 26 May 2017 10:31:12 -0400 Subject: ibmvnic: Reset sub-crqs during driver reset When the ibmvnic driver is resetting, we can just reset the sub crqs instead of releasing all of their resources and re-allocting them. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 46 +++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 5661a043f5e5..8dcf58088178 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1320,8 +1320,6 @@ static int do_reset(struct ibmvnic_adapter *adapter, */ adapter->state = VNIC_PROBED; - release_sub_crqs(adapter); - rc = ibmvnic_init(adapter); if (rc) return 0; @@ -1728,6 +1726,45 @@ static const struct ethtool_ops ibmvnic_ethtool_ops = { /* Routines for managing CRQs/sCRQs */ +static int reset_one_sub_crq_queue(struct ibmvnic_adapter *adapter, + struct ibmvnic_sub_crq_queue *scrq) +{ + int rc; + + if (scrq->irq) { + free_irq(scrq->irq, scrq); + irq_dispose_mapping(scrq->irq); + scrq->irq = 0; + } + + memset(scrq->msgs, 0, 2 * PAGE_SIZE); + scrq->cur = 0; + + rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token, + 4 * PAGE_SIZE, &scrq->crq_num, &scrq->hw_irq); + return rc; +} + +static int reset_sub_crq_queues(struct ibmvnic_adapter *adapter) +{ + int i, rc; + + for (i = 0; i < adapter->req_tx_queues; i++) { + rc = reset_one_sub_crq_queue(adapter, adapter->tx_scrq[i]); + if (rc) + return rc; + } + + for (i = 0; i < adapter->req_rx_queues; i++) { + rc = reset_one_sub_crq_queue(adapter, adapter->rx_scrq[i]); + if (rc) + return rc; + } + + rc = init_sub_crq_irqs(adapter); + return rc; +} + static void release_sub_crq_queue(struct ibmvnic_adapter *adapter, struct ibmvnic_sub_crq_queue *scrq) { @@ -3607,7 +3644,10 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) return -1; } - rc = init_sub_crqs(adapter); + if (adapter->resetting) + rc = reset_sub_crq_queues(adapter); + else + rc = init_sub_crqs(adapter); if (rc) { dev_err(dev, "Initialization of sub crqs failed\n"); release_crq_queue(adapter); -- cgit v1.2.3 From 7a7e96e09d463c7c3d51a51c539ae4352085ed18 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Sat, 27 May 2017 10:14:35 -0400 Subject: bonding: Prevent duplicate userspace notification Whenever a user changes bonding options, a NETDEV_CHANGEINFODATA notificatin is generated which results in a rtnelink message to be sent. While runnig 'ip monitor', we can actually see 2 messages, one a result of the event, and the other a result of state change that is generated bo netdev_state_change(). However, this is not always the case. If bonding changes were done via sysfs or ifenslave (old ioctl interface), then only 1 message is seen. This patch removes duplicate messages in the case of using netlink to configure bonding. It introduceds a separte function that triggers a netdev event and uses that function in the syfs and ioctl cases. This was discovered while auditing all the different envents and continues the effort of cleaning up duplicated netlink messages. CC: David Ahern CC: Jiri Pirko Signed-off-by: Vladislav Yasevich Acked-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 ++- drivers/net/bonding/bond_options.c | 27 +++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2359478b977f..d4484d1a8164 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3488,7 +3488,8 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd case BOND_CHANGE_ACTIVE_OLD: case SIOCBONDCHANGEACTIVE: bond_opt_initstr(&newval, slave_dev->name); - res = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval); + res = __bond_opt_set_notify(bond, BOND_OPT_ACTIVE_SLAVE, + &newval); break; default: res = -EOPNOTSUPP; diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 1bcbb8913e17..8ca683396fcc 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -673,7 +673,30 @@ int __bond_opt_set(struct bonding *bond, out: if (ret) bond_opt_error_interpret(bond, opt, ret, val); - else if (bond->dev->reg_state == NETREG_REGISTERED) + + return ret; +} +/** + * __bond_opt_set_notify - set a bonding option + * @bond: target bond device + * @option: option to set + * @val: value to set it to + * + * This function is used to change the bond's option value and trigger + * a notification to user sapce. It can be used for both enabling/changing + * an option and for disabling it. RTNL lock must be obtained before calling + * this function. + */ +int __bond_opt_set_notify(struct bonding *bond, + unsigned int option, struct bond_opt_value *val) +{ + int ret = -ENOENT; + + ASSERT_RTNL(); + + ret = __bond_opt_set(bond, option, val); + + if (!ret && (bond->dev->reg_state == NETREG_REGISTERED)) call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev); return ret; @@ -696,7 +719,7 @@ int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf) if (!rtnl_trylock()) return restart_syscall(); bond_opt_initstr(&optval, buf); - ret = __bond_opt_set(bond, option, &optval); + ret = __bond_opt_set_notify(bond, option, &optval); rtnl_unlock(); return ret; -- cgit v1.2.3 From 523a89041c319bc0f6df60627ccb2413f441fb84 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 26 May 2017 18:02:42 -0400 Subject: net: dsa: mv88e6xxx: handle SERDES error appropriately mv88e6xxx_serdes_power returns an error, so no need to print an error message inside of it. Rather print it in its caller when the error is ignored, which is in the mv88e6xxx_port_disable void function. Catch and return its error in the counterpart mv88e6xxx_port_enable. Fixes: 04aca9938255 ("dsa: mv88e6xxx: Enable/Disable SERDES on port enable/disable") Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index c2f38f6770aa..742c0eae7fa3 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1806,16 +1806,10 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) { - int err = 0; - - if (chip->info->ops->serdes_power) { - err = chip->info->ops->serdes_power(chip, port, on); - if (err) - dev_err(chip->dev, - "Failed to change SERDES power: %d\n", err); - } + if (chip->info->ops->serdes_power) + return chip->info->ops->serdes_power(chip, port, on); - return err; + return 0; } static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) @@ -1982,10 +1976,10 @@ static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, struct phy_device *phydev) { struct mv88e6xxx_chip *chip = ds->priv; - int err = 0; + int err; mutex_lock(&chip->reg_lock); - mv88e6xxx_serdes_power(chip, port, true); + err = mv88e6xxx_serdes_power(chip, port, true); mutex_unlock(&chip->reg_lock); return err; @@ -1997,7 +1991,8 @@ static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port, struct mv88e6xxx_chip *chip = ds->priv; mutex_lock(&chip->reg_lock); - mv88e6xxx_serdes_power(chip, port, false); + if (mv88e6xxx_serdes_power(chip, port, false)) + dev_err(chip->dev, "failed to power off SERDES\n"); mutex_unlock(&chip->reg_lock); } -- cgit v1.2.3 From a3995460491d4570af8e99ad34ddf6d1948254d9 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sat, 27 May 2017 10:42:25 -0700 Subject: net: phy: Relax error checking on sysfs_create_link() Some Ethernet drivers will attach/connect to a PHY device before calling register_netdevice() which is responsible for calling netdev_register_kobject() which would do the network device's kobject initialization. In such a case, sysfs_create_link() would return -ENOENT because the network device's kobject is not ready yet, and we would fail to connect to the PHY device. In order to keep things simple and symetrical, we just take the success path as indicative of the ability to access the network device's kobject, and create the second link if that's the case. Fixes: 5568363f0cb3 ("net: phy: Create sysfs reciprocal links for attached_dev/phydev") Reported-by: Woojung Hung Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index f84414b8f2ee..37a1e98908e3 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -960,15 +960,27 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev->attached_dev = dev; dev->phydev = phydev; + + /* Some Ethernet drivers try to connect to a PHY device before + * calling register_netdevice() -> netdev_register_kobject() and + * does the dev->dev.kobj initialization. Here we only check for + * success which indicates that the network device kobject is + * ready. Once we do that we still need to keep track of whether + * links were successfully set up or not for phy_detach() to + * remove them accordingly. + */ + phydev->sysfs_links = false; + err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj, "attached_dev"); - if (err) - goto error; + if (!err) { + err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj, + "phydev"); + if (err) + goto error; - err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj, - "phydev"); - if (err) - goto error; + phydev->sysfs_links = true; + } phydev->dev_flags = flags; @@ -1059,8 +1071,10 @@ void phy_detach(struct phy_device *phydev) struct mii_bus *bus; int i; - sysfs_remove_link(&dev->dev.kobj, "phydev"); - sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev"); + if (phydev->sysfs_links) { + sysfs_remove_link(&dev->dev.kobj, "phydev"); + sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev"); + } phydev->attached_dev->phydev = NULL; phydev->attached_dev = NULL; phy_suspend(phydev); -- cgit v1.2.3 From d935bc84c9403f30afedc2212e6dafe7669a738d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:52:52 -0700 Subject: nfp: add MAY_USE_DEVLINK dependency Fix build with DEVLINK=m and NFP=y. Fixes: 1851f93fd2ee ("nfp: add devlink support") Reported-by: kbuild test robot Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/Kconfig b/drivers/net/ethernet/netronome/Kconfig index 967d7ca8c28c..0d5a7b9203a4 100644 --- a/drivers/net/ethernet/netronome/Kconfig +++ b/drivers/net/ethernet/netronome/Kconfig @@ -19,6 +19,7 @@ config NFP tristate "Netronome(R) NFP4000/NFP6000 NIC driver" depends on PCI && PCI_MSI depends on VXLAN || VXLAN=n + depends on MAY_USE_DEVLINK ---help--- This driver supports the Netronome(R) NFP4000/NFP6000 based cards working as a advanced Ethernet NIC. It works with both -- cgit v1.2.3 From 9d3727595b11ab8f2837b54922efd2998f2cade5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Casc=C3=B3n?= Date: Sun, 28 May 2017 17:52:53 -0700 Subject: nfp: add set_mac_address support while the interface is up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose FW app ability to change MAC address at runtime. Make sure we only depend on it if FW app advertised the right capability. Signed-off-by: Pablo Cascón Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 44 +++++++++++++++++----- drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h | 2 + 2 files changed, 36 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index b3f5c8af6789..9312a737fbc9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2123,17 +2123,16 @@ void nfp_net_coalesce_write_cfg(struct nfp_net *nn) /** * nfp_net_write_mac_addr() - Write mac address to the device control BAR * @nn: NFP Net device to reconfigure + * @addr: MAC address to write * * Writes the MAC address from the netdev to the device control BAR. Does not * perform the required reconfig. We do a bit of byte swapping dance because * firmware is LE. */ -static void nfp_net_write_mac_addr(struct nfp_net *nn) +static void nfp_net_write_mac_addr(struct nfp_net *nn, const u8 *addr) { - nn_writel(nn, NFP_NET_CFG_MACADDR + 0, - get_unaligned_be32(nn->dp.netdev->dev_addr)); - nn_writew(nn, NFP_NET_CFG_MACADDR + 6, - get_unaligned_be16(nn->dp.netdev->dev_addr + 4)); + nn_writel(nn, NFP_NET_CFG_MACADDR + 0, get_unaligned_be32(addr)); + nn_writew(nn, NFP_NET_CFG_MACADDR + 6, get_unaligned_be16(addr + 4)); } static void nfp_net_vec_clear_ring_data(struct nfp_net *nn, unsigned int idx) @@ -2238,7 +2237,7 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn) nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, nn->dp.num_rx_rings == 64 ? 0xffffffffffffffffULL : ((u64)1 << nn->dp.num_rx_rings) - 1); - nfp_net_write_mac_addr(nn); + nfp_net_write_mac_addr(nn, nn->dp.netdev->dev_addr); nn_writel(nn, NFP_NET_CFG_MTU, nn->dp.netdev->mtu); @@ -2997,6 +2996,27 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) } } +static int nfp_net_set_mac_address(struct net_device *netdev, void *addr) +{ + struct nfp_net *nn = netdev_priv(netdev); + struct sockaddr *saddr = addr; + int err; + + err = eth_prepare_mac_addr_change(netdev, addr); + if (err) + return err; + + nfp_net_write_mac_addr(nn, saddr->sa_data); + + err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_MACADDR); + if (err) + return err; + + eth_commit_mac_addr_change(netdev, addr); + + return 0; +} + const struct net_device_ops nfp_net_netdev_ops = { .ndo_open = nfp_net_netdev_open, .ndo_stop = nfp_net_netdev_close, @@ -3006,7 +3026,7 @@ const struct net_device_ops nfp_net_netdev_ops = { .ndo_tx_timeout = nfp_net_tx_timeout, .ndo_set_rx_mode = nfp_net_set_rx_mode, .ndo_change_mtu = nfp_net_change_mtu, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = nfp_net_set_mac_address, .ndo_set_features = nfp_net_set_features, .ndo_features_check = nfp_net_features_check, .ndo_get_phys_port_name = nfp_port_get_phys_port_name, @@ -3029,7 +3049,7 @@ void nfp_net_info(struct nfp_net *nn) nn->fw_ver.resv, nn->fw_ver.class, nn->fw_ver.major, nn->fw_ver.minor, nn->max_mtu); - nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", nn->cap, nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "", nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "", @@ -3051,7 +3071,8 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_NVGRE ? "NVGRE " : "", nfp_net_ebpf_capable(nn) ? "BPF " : "", nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ? - "RXCSUM_COMPLETE " : ""); + "RXCSUM_COMPLETE " : "", + nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR ? "LIVE_ADDR " : ""); } /** @@ -3211,7 +3232,7 @@ int nfp_net_init(struct nfp_net *nn) if (nn->dp.chained_metadata_format && nn->fw_ver.major != 4) nn->cap &= ~NFP_NET_CFG_CTRL_RSS; - nfp_net_write_mac_addr(nn); + nfp_net_write_mac_addr(nn, nn->dp.netdev->dev_addr); /* Determine RX packet/metadata boundary offset */ if (nn->fw_ver.major >= 2) { @@ -3241,6 +3262,9 @@ int nfp_net_init(struct nfp_net *nn) * and netdev->hw_features advertises which features are * supported. By default we enable most features. */ + if (nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR) + netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + netdev->hw_features = NETIF_F_HIGHDMA; if (nn->cap & NFP_NET_CFG_CTRL_RXCSUM_ANY) { netdev->hw_features |= NETIF_F_RXCSUM; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index df75b8dc3617..c8208bf370e0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -135,6 +135,7 @@ #define NFP_NET_CFG_CTRL_LSO2 (0x1 << 28) /* LSO/TSO (version 2) */ #define NFP_NET_CFG_CTRL_RSS2 (0x1 << 29) /* RSS (version 2) */ #define NFP_NET_CFG_CTRL_CSUM_COMPLETE (0x1 << 30) /* Checksum complete */ +#define NFP_NET_CFG_CTRL_LIVE_ADDR (0x1 << 31) /* live MAC addr change */ #define NFP_NET_CFG_CTRL_LSO_ANY (NFP_NET_CFG_CTRL_LSO | \ NFP_NET_CFG_CTRL_LSO2) @@ -157,6 +158,7 @@ #define NFP_NET_CFG_UPDATE_IRQMOD (0x1 << 8) /* IRQ mod change */ #define NFP_NET_CFG_UPDATE_VXLAN (0x1 << 9) /* VXLAN port change */ #define NFP_NET_CFG_UPDATE_BPF (0x1 << 10) /* BPF program load */ +#define NFP_NET_CFG_UPDATE_MACADDR (0x1 << 11) /* MAC address change */ #define NFP_NET_CFG_UPDATE_ERR (0x1 << 31) /* A error occurred */ #define NFP_NET_CFG_TXRS_ENABLE 0x0008 #define NFP_NET_CFG_RXRS_ENABLE 0x0010 -- cgit v1.2.3 From 651e1f2f19995c7585f34688331cda4f88e8df47 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:52:54 -0700 Subject: nfp: set driver VF limit PCI subsystem has support for drivers limiting the number of VFs available below what the IOV capability claims. Make use of it. While at it remove the #ifdef/#endif on CONFIG_PCI_IOV, it was there to avoid unnecessary warnings in case device read failed but kernel doesn't have SR-IOV support anyway. Device reads should not fail. Note that we still need the driver-internal check for the case where max VFs is 0 since PCI subsystem treats 0 as limit not set. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index f22f56c9218f..ba174e163834 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -73,20 +73,22 @@ static const struct pci_device_id nfp_pci_device_ids[] = { }; MODULE_DEVICE_TABLE(pci, nfp_pci_device_ids); -static void nfp_pcie_sriov_read_nfd_limit(struct nfp_pf *pf) +static int nfp_pcie_sriov_read_nfd_limit(struct nfp_pf *pf) { -#ifdef CONFIG_PCI_IOV int err; pf->limit_vfs = nfp_rtsym_read_le(pf->cpp, "nfd_vf_cfg_max_vfs", &err); if (!err) - return; + return pci_sriov_set_totalvfs(pf->pdev, pf->limit_vfs); pf->limit_vfs = ~0; + pci_sriov_set_totalvfs(pf->pdev, 0); /* 0 is unset */ /* Allow any setting for backwards compatibility if symbol not found */ - if (err != -ENOENT) - nfp_warn(pf->cpp, "Warning: VF limit read failed: %d\n", err); -#endif + if (err == -ENOENT) + return 0; + + nfp_warn(pf->cpp, "Warning: VF limit read failed: %d\n", err); + return err; } static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs) @@ -373,14 +375,18 @@ static int nfp_pci_probe(struct pci_dev *pdev, if (err) goto err_devlink_unreg; - nfp_pcie_sriov_read_nfd_limit(pf); + err = nfp_pcie_sriov_read_nfd_limit(pf); + if (err) + goto err_fw_unload; err = nfp_net_pci_probe(pf); if (err) - goto err_fw_unload; + goto err_sriov_unlimit; return 0; +err_sriov_unlimit: + pci_sriov_set_totalvfs(pf->pdev, 0); err_fw_unload: if (pf->fw_loaded) nfp_fw_unload(pf); @@ -411,6 +417,7 @@ static void nfp_pci_remove(struct pci_dev *pdev) nfp_net_pci_remove(pf); nfp_pcie_sriov_disable(pdev); + pci_sriov_set_totalvfs(pf->pdev, 0); devlink_unregister(devlink); -- cgit v1.2.3 From 09b857945b21706d432f6e4e1c9e5028be5f14ff Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:52:55 -0700 Subject: nfp: don't set aux pointers if ioremap failed If ioremap of PCIe ctrl memory failed we can still get to it through PCI config space, therefore we allow ioremap() to fail. When if fails, however, we must leave all the IOMEM pointers as NULL. Currently we would calculate csr and em pointers, adding offsets to the potential NULL value and therefore making the NULL-checks throughout the code ineffective. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c index 43dc68e01274..1fde213d5b83 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c @@ -639,19 +639,23 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) nfp6000_bar_write(nfp, bar, barcfg_msix_general); nfp->expl.data = bar->iomem + NFP_PCIE_SRAM + 0x1000; + + if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 || + nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) { + nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0); + } else { + int pf = nfp->pdev->devfn & 7; + + nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(pf); + } + nfp->iomem.em = bar->iomem + NFP_PCIE_EM; } if (nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP4000 || - nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) { - nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(0); + nfp->pdev->device == PCI_DEVICE_ID_NETRONOME_NFP6000) expl_groups = 4; - } else { - int pf = nfp->pdev->devfn & 7; - - nfp->iomem.csr = bar->iomem + NFP_PCIE_BAR(pf); + else expl_groups = 1; - } - nfp->iomem.em = bar->iomem + NFP_PCIE_EM; /* Configure, and lock, BAR0.1 for PCIe XPB (MSI-X PBA) */ bar = &nfp->bar[1]; -- cgit v1.2.3 From 321b5e9afe2d2b31f78b60724d58a9d02888bb57 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:52:56 -0700 Subject: nfp: only try to get to PCIe ctrl memory if BARs are wide enough For accessing PCIe ctrl memory we depend on the BAR aperture being large enough to reach all registers. Since the BAR aperture can be set in the flash make sure the driver won't oops the kernel when the PCIe configuration is unusual. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c index 1fde213d5b83..597ac8febb63 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c @@ -119,6 +119,11 @@ #define NFP_PCIE_EM 0x020000 #define NFP_PCIE_SRAM 0x000000 +/* Minimal size of the PCIe cfg memory we depend on being mapped, + * queue controller and DMA controller don't have to be covered. + */ +#define NFP_PCI_MIN_MAP_SIZE 0x080000 + #define NFP_PCIE_P2C_FIXED_SIZE(bar) (1 << (bar)->bitsize) #define NFP_PCIE_P2C_BULK_SIZE(bar) (1 << (bar)->bitsize) #define NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(bar, x) ((x) << ((bar)->bitsize - 2)) @@ -628,8 +633,9 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) /* Configure, and lock, BAR0.0 for General Target use (MSI-X SRAM) */ bar = &nfp->bar[0]; - bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar), - nfp_bar_resource_len(bar)); + if (nfp_bar_resource_len(bar) >= NFP_PCI_MIN_MAP_SIZE) + bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar), + nfp_bar_resource_len(bar)); if (bar->iomem) { dev_info(nfp->dev, "BAR0.0 RESERVED: General Mapping/MSI-X SRAM\n"); -- cgit v1.2.3 From 8b3d5a47ae6b93654e39b543e33ded07c06fa8a9 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:52:57 -0700 Subject: nfp: support long reads and writes with the cpp helpers nfp_cpp_{read,write}() helpers perform device memory mapping (setting the PCIe -> NOC translation BARs) and accessing it. They, however, currently implicitly expect that the length of entire operation will fit in one BAR translation window. There is a number of 16MB windows available, and we don't really need to access such large areas today. If the user, however, manages to trick the driver into making a big mapping (e.g. by providing a huge fake FW file), the driver will print a warning saying "No suitable BAR found for request" and a stack trace - which most users find concerning. To be future-proof and not scare users with warnings, make the nfp_cpp_{read,write}() helpers do accesses chunk by chunk if the area size is large. Set the notion of "large" to 2MB, which is the size of the smallest BAR window. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 3 + .../ethernet/netronome/nfp/nfpcore/nfp_cppcore.c | 87 +++++++++++++++++----- 2 files changed, 72 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index 154b0b594184..8d46b9acb69f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -42,6 +42,7 @@ #include #include +#include #ifndef NFP_SUBSYS #define NFP_SUBSYS "nfp" @@ -59,6 +60,8 @@ #define PCI_64BIT_BAR_COUNT 3 #define NFP_CPP_NUM_TARGETS 16 +/* Max size of area it should be safe to request */ +#define NFP_CPP_SAFE_AREA_SIZE SZ_2M struct device; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c index e2abba4c3a3f..5672d309d07d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c @@ -924,18 +924,9 @@ area_cache_put(struct nfp_cpp *cpp, struct nfp_cpp_area_cache *cache) mutex_unlock(&cpp->area_cache_mutex); } -/** - * nfp_cpp_read() - read from CPP target - * @cpp: CPP handle - * @destination: CPP id - * @address: offset into CPP target - * @kernel_vaddr: kernel buffer for result - * @length: number of bytes to read - * - * Return: length of io, or -ERRNO - */ -int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, - unsigned long long address, void *kernel_vaddr, size_t length) +static int __nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, + unsigned long long address, void *kernel_vaddr, + size_t length) { struct nfp_cpp_area_cache *cache; struct nfp_cpp_area *area; @@ -968,18 +959,43 @@ int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, } /** - * nfp_cpp_write() - write to CPP target + * nfp_cpp_read() - read from CPP target * @cpp: CPP handle * @destination: CPP id * @address: offset into CPP target - * @kernel_vaddr: kernel buffer to read from - * @length: number of bytes to write + * @kernel_vaddr: kernel buffer for result + * @length: number of bytes to read * * Return: length of io, or -ERRNO */ -int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, - unsigned long long address, - const void *kernel_vaddr, size_t length) +int nfp_cpp_read(struct nfp_cpp *cpp, u32 destination, + unsigned long long address, void *kernel_vaddr, + size_t length) +{ + size_t n, offset; + int ret; + + for (offset = 0; offset < length; offset += n) { + unsigned long long r_addr = address + offset; + + /* make first read smaller to align to safe window */ + n = min_t(size_t, length - offset, + ALIGN(r_addr + 1, NFP_CPP_SAFE_AREA_SIZE) - r_addr); + + ret = __nfp_cpp_read(cpp, destination, address + offset, + kernel_vaddr + offset, n); + if (ret < 0) + return ret; + if (ret != n) + return offset + n; + } + + return length; +} + +static int __nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, + unsigned long long address, + const void *kernel_vaddr, size_t length) { struct nfp_cpp_area_cache *cache; struct nfp_cpp_area *area; @@ -1011,6 +1027,41 @@ int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, return err; } +/** + * nfp_cpp_write() - write to CPP target + * @cpp: CPP handle + * @destination: CPP id + * @address: offset into CPP target + * @kernel_vaddr: kernel buffer to read from + * @length: number of bytes to write + * + * Return: length of io, or -ERRNO + */ +int nfp_cpp_write(struct nfp_cpp *cpp, u32 destination, + unsigned long long address, + const void *kernel_vaddr, size_t length) +{ + size_t n, offset; + int ret; + + for (offset = 0; offset < length; offset += n) { + unsigned long long w_addr = address + offset; + + /* make first write smaller to align to safe window */ + n = min_t(size_t, length - offset, + ALIGN(w_addr + 1, NFP_CPP_SAFE_AREA_SIZE) - w_addr); + + ret = __nfp_cpp_write(cpp, destination, address + offset, + kernel_vaddr + offset, n); + if (ret < 0) + return ret; + if (ret != n) + return offset + n; + } + + return length; +} + /* Return the correct CPP address, and fixup xpb_addr as needed. */ static u32 nfp_xpb_to_cpp(struct nfp_cpp *cpp, u32 *xpb_addr) { -- cgit v1.2.3 From 2ed4b36d03f9f6e71fe0c5a15941b2ff0bac99ad Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:52:58 -0700 Subject: nfp: shorten CPP core probe logs We currently print reserved BAR mappings info as we create them. This makes the probe logs longer than necessary. Print into a buffer instead and log all the info as a single line. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c index 597ac8febb63..cd678323bacb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c @@ -588,9 +588,15 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) NFP_PCIE_BAR_PCIE2CPP_MapType( NFP_PCIE_BAR_PCIE2CPP_MapType_EXPLICIT3), }; + char status_msg[196] = {}; struct nfp_bar *bar; int i, bars_free; int expl_groups; + char *msg, *end; + + msg = status_msg + + snprintf(status_msg, sizeof(status_msg) - 1, "RESERVED BARs: "); + end = status_msg + sizeof(status_msg) - 1; bar = &nfp->bar[0]; for (i = 0; i < ARRAY_SIZE(nfp->bar); i++, bar++) { @@ -637,8 +643,7 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar), nfp_bar_resource_len(bar)); if (bar->iomem) { - dev_info(nfp->dev, - "BAR0.0 RESERVED: General Mapping/MSI-X SRAM\n"); + msg += snprintf(msg, end - msg, "0.0: General/MSI-X SRAM, "); atomic_inc(&bar->refcnt); bars_free--; @@ -665,7 +670,7 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) /* Configure, and lock, BAR0.1 for PCIe XPB (MSI-X PBA) */ bar = &nfp->bar[1]; - dev_info(nfp->dev, "BAR0.1 RESERVED: PCIe XPB/MSI-X PBA\n"); + msg += snprintf(msg, end - msg, "0.1: PCIe XPB/MSI-X PBA, "); atomic_inc(&bar->refcnt); bars_free--; @@ -684,9 +689,8 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) bar->iomem = ioremap_nocache(nfp_bar_resource_start(bar), nfp_bar_resource_len(bar)); if (bar->iomem) { - dev_info(nfp->dev, - "BAR0.%d RESERVED: Explicit%d Mapping\n", - 4 + i, i); + msg += snprintf(msg, end - msg, + "0.%d: Explicit%d, ", 4 + i, i); atomic_inc(&bar->refcnt); bars_free--; @@ -704,8 +708,7 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface) sort(&nfp->bar[0], nfp->bars, sizeof(nfp->bar[0]), bar_cmp, NULL); - dev_info(nfp->dev, "%d NFP PCI2CPP BARs, %d free\n", - nfp->bars, bars_free); + dev_info(nfp->dev, "%sfree: %d/%d\n", status_msg, bars_free, nfp->bars); return 0; } -- cgit v1.2.3 From a87853f383afd6cb1cbda982d895e9cadf435098 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:52:59 -0700 Subject: nfp: support variable NSP response lengths We want to support extendable commands, where newer versions of the management FW may provide more information. Zero out the communication buffer before passing control to NSP. This way if management FW is old and only fills in first N bytes, the remaining ones will be zeros which extended ABI fields should reserve as not supported/not available. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index 2fa9247bb23d..58cc3d532769 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -419,6 +419,14 @@ static int nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, if (err < 0) return err; } + /* Zero out remaining part of the buffer */ + if (out_buf && out_size && out_size > in_size) { + memset(out_buf, 0, out_size - in_size); + err = nfp_cpp_write(cpp, cpp_id, cpp_buf + in_size, + out_buf, out_size - in_size); + if (err < 0) + return err; + } ret = nfp_nsp_command(nsp, code, option, cpp_id, cpp_buf); if (ret < 0) -- cgit v1.2.3 From eefbde7e10026273a81f54ab3b76e959f4f0ef09 Mon Sep 17 00:00:00 2001 From: David Brunecz Date: Sun, 28 May 2017 17:53:00 -0700 Subject: nfp: add hwmon support Add support for retrieving temperature and power sensor and limits via NSP. Signed-off-by: David Brunecz Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 1 + drivers/net/ethernet/netronome/nfp/nfp_hwmon.c | 192 +++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_main.c | 21 ++- drivers/net/ethernet/netronome/nfp/nfp_main.h | 10 ++ drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h | 2 + .../net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c | 8 + .../net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 12 ++ .../ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c | 47 ++++- 8 files changed, 286 insertions(+), 7 deletions(-) create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_hwmon.c (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 95f6b97b5d71..83039c65e061 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -16,6 +16,7 @@ nfp-objs := \ nfpcore/nfp_target.o \ nfp_app.o \ nfp_devlink.o \ + nfp_hwmon.o \ nfp_main.o \ nfp_net_common.o \ nfp_net_ethtool.o \ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c b/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c new file mode 100644 index 000000000000..f0dcf45aeec1 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_hwmon.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "nfpcore/nfp_cpp.h" +#include "nfpcore/nfp_nsp.h" +#include "nfp_main.h" + +#define NFP_TEMP_MAX (95 * 1000) +#define NFP_TEMP_CRIT (105 * 1000) + +#define NFP_POWER_MAX (25 * 1000 * 1000) + +static int nfp_hwmon_sensor_id(enum hwmon_sensor_types type, int channel) +{ + if (type == hwmon_temp) + return NFP_SENSOR_CHIP_TEMPERATURE; + if (type == hwmon_power) + return NFP_SENSOR_ASSEMBLY_POWER + channel; + return -EINVAL; +} + +static int +nfp_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + static const struct { + enum hwmon_sensor_types type; + u32 attr; + long val; + } const_vals[] = { + { hwmon_temp, hwmon_temp_max, NFP_TEMP_MAX }, + { hwmon_temp, hwmon_temp_crit, NFP_TEMP_CRIT }, + { hwmon_power, hwmon_power_max, NFP_POWER_MAX }, + }; + struct nfp_pf *pf = dev_get_drvdata(dev); + enum nfp_nsp_sensor_id id; + int err, i; + + for (i = 0; i < ARRAY_SIZE(const_vals); i++) + if (const_vals[i].type == type && const_vals[i].attr == attr) { + *val = const_vals[i].val; + return 0; + } + + err = nfp_hwmon_sensor_id(type, channel); + if (err < 0) + return err; + id = err; + + if (!(pf->nspi->sensor_mask & BIT(id))) + return -EOPNOTSUPP; + + if (type == hwmon_temp && attr == hwmon_temp_input) + return nfp_hwmon_read_sensor(pf->cpp, id, val); + if (type == hwmon_power && attr == hwmon_power_input) + return nfp_hwmon_read_sensor(pf->cpp, id, val); + + return -EINVAL; +} + +static umode_t +nfp_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, + int channel) +{ + if (type == hwmon_temp) { + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_crit: + case hwmon_temp_max: + return 0444; + } + } else if (type == hwmon_power) { + switch (attr) { + case hwmon_power_input: + case hwmon_power_max: + return 0444; + } + } + return 0; +} + +static u32 nfp_chip_config[] = { + HWMON_C_REGISTER_TZ, + 0 +}; + +static const struct hwmon_channel_info nfp_chip = { + .type = hwmon_chip, + .config = nfp_chip_config, +}; + +static u32 nfp_temp_config[] = { + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT, + 0 +}; + +static const struct hwmon_channel_info nfp_temp = { + .type = hwmon_temp, + .config = nfp_temp_config, +}; + +static u32 nfp_power_config[] = { + HWMON_P_INPUT | HWMON_P_MAX, + HWMON_P_INPUT, + HWMON_P_INPUT, + 0 +}; + +static const struct hwmon_channel_info nfp_power = { + .type = hwmon_power, + .config = nfp_power_config, +}; + +static const struct hwmon_channel_info *nfp_hwmon_info[] = { + &nfp_chip, + &nfp_temp, + &nfp_power, + NULL +}; + +static const struct hwmon_ops nfp_hwmon_ops = { + .is_visible = nfp_hwmon_is_visible, + .read = nfp_hwmon_read, +}; + +static const struct hwmon_chip_info nfp_chip_info = { + .ops = &nfp_hwmon_ops, + .info = nfp_hwmon_info, +}; + +int nfp_hwmon_register(struct nfp_pf *pf) +{ + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + if (!pf->nspi) { + nfp_warn(pf->cpp, "not registering HWMON (no NSP info)\n"); + return 0; + } + if (!pf->nspi->sensor_mask) { + nfp_info(pf->cpp, + "not registering HWMON (NSP doesn't report sensors)\n"); + return 0; + } + + pf->hwmon_dev = hwmon_device_register_with_info(&pf->pdev->dev, "nfp", + pf, &nfp_chip_info, + NULL); + return PTR_ERR_OR_ZERO(pf->hwmon_dev); +} + +void nfp_hwmon_unregister(struct nfp_pf *pf) +{ + if (!IS_REACHABLE(CONFIG_HWMON) || !pf->hwmon_dev) + return; + + hwmon_device_unregister(pf->hwmon_dev); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index ba174e163834..68cd34d5a9fb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -257,7 +257,6 @@ exit_release_fw: static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf) { - struct nfp_nsp_identify *nspi; struct nfp_nsp *nsp; int err; @@ -274,11 +273,9 @@ static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf) pf->eth_tbl = __nfp_eth_read_ports(pf->cpp, nsp); - nspi = __nfp_nsp_identify(nsp); - if (nspi) { - dev_info(&pdev->dev, "BSP: %s\n", nspi->version); - kfree(nspi); - } + pf->nspi = __nfp_nsp_identify(nsp); + if (pf->nspi) + dev_info(&pdev->dev, "BSP: %s\n", pf->nspi->version); err = nfp_fw_load(pdev, pf, nsp); if (err < 0) { @@ -383,14 +380,23 @@ static int nfp_pci_probe(struct pci_dev *pdev, if (err) goto err_sriov_unlimit; + err = nfp_hwmon_register(pf); + if (err) { + dev_err(&pdev->dev, "Failed to register hwmon info\n"); + goto err_net_remove; + } + return 0; +err_net_remove: + nfp_net_pci_remove(pf); err_sriov_unlimit: pci_sriov_set_totalvfs(pf->pdev, 0); err_fw_unload: if (pf->fw_loaded) nfp_fw_unload(pf); kfree(pf->eth_tbl); + kfree(pf->nspi); err_devlink_unreg: devlink_unregister(devlink); err_cpp_free: @@ -412,6 +418,8 @@ static void nfp_pci_remove(struct pci_dev *pdev) struct nfp_pf *pf = pci_get_drvdata(pdev); struct devlink *devlink; + nfp_hwmon_unregister(pf); + devlink = priv_to_devlink(pf); nfp_net_pci_remove(pf); @@ -428,6 +436,7 @@ static void nfp_pci_remove(struct pci_dev *pdev) nfp_cpp_free(pf->cpp); kfree(pf->eth_tbl); + kfree(pf->nspi); mutex_destroy(&pf->lock); devlink_free(devlink); pci_release_regions(pdev); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 526db8029dea..20fad76da5aa 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -47,12 +47,14 @@ #include struct dentry; +struct device; struct devlink_ops; struct pci_dev; struct nfp_cpp; struct nfp_cpp_area; struct nfp_eth_table; +struct nfp_nsp_identify; /** * struct nfp_pf - NFP PF-specific device structure @@ -67,6 +69,8 @@ struct nfp_eth_table; * @num_vfs: Number of SR-IOV VFs enabled * @fw_loaded: Is the firmware loaded? * @eth_tbl: NSP ETH table + * @nspi: NSP identification info + * @hwmon_dev: pointer to hwmon device * @ddir: Per-device debugfs directory * @max_data_vnics: Number of data vNICs app firmware supports * @num_vnics: Number of vNICs spawned @@ -94,6 +98,9 @@ struct nfp_pf { bool fw_loaded; struct nfp_eth_table *eth_tbl; + struct nfp_nsp_identify *nspi; + + struct device *hwmon_dev; struct dentry *ddir; @@ -113,4 +120,7 @@ extern const struct devlink_ops nfp_devlink_ops; int nfp_net_pci_probe(struct nfp_pf *pf); void nfp_net_pci_remove(struct nfp_pf *pf); +int nfp_hwmon_register(struct nfp_pf *pf); +void nfp_hwmon_unregister(struct nfp_pf *pf); + #endif /* NFP_MAIN_H */ diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h index 4df2ce261b3f..94641b4c2c55 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h @@ -64,6 +64,8 @@ int nfp_nsp_read_eth_table(struct nfp_nsp *state, void *buf, unsigned int size); int nfp_nsp_write_eth_table(struct nfp_nsp *state, const void *buf, unsigned int size); int nfp_nsp_read_identify(struct nfp_nsp *state, void *buf, unsigned int size); +int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask, + void *buf, unsigned int size); /* Implemented in nfp_resource.c */ diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index 58cc3d532769..eefdb756d74e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -93,6 +93,7 @@ enum nfp_nsp_cmd { SPCODE_FW_LOAD = 6, /* Load fw from buffer, len in option */ SPCODE_ETH_RESCAN = 7, /* Rescan ETHs, write ETH_TABLE to buf */ SPCODE_ETH_CONTROL = 8, /* Update media config from buffer */ + SPCODE_NSP_SENSORS = 12, /* Read NSP sensor(s) */ SPCODE_NSP_IDENTIFY = 13, /* Read NSP version */ }; @@ -506,3 +507,10 @@ int nfp_nsp_read_identify(struct nfp_nsp *state, void *buf, unsigned int size) return nfp_nsp_command_buf(state, SPCODE_NSP_IDENTIFY, size, NULL, 0, buf, size); } + +int nfp_nsp_read_sensors(struct nfp_nsp *state, unsigned int sensor_mask, + void *buf, unsigned int size) +{ + return nfp_nsp_command_buf(state, SPCODE_NSP_SENSORS, sensor_mask, + NULL, 0, buf, size); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index 84a1d20adae1..26d7dcea4fd9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -160,6 +160,7 @@ int __nfp_eth_set_split(struct nfp_nsp *nsp, unsigned int lanes); * @primary: version of primarary bootloader * @secondary: version id of secondary bootloader * @nsp: version id of NSP + * @sensor_mask: mask of present sensors available on NIC */ struct nfp_nsp_identify { char version[40]; @@ -170,8 +171,19 @@ struct nfp_nsp_identify { u16 primary; u16 secondary; u16 nsp; + u64 sensor_mask; }; struct nfp_nsp_identify *__nfp_nsp_identify(struct nfp_nsp *nsp); +enum nfp_nsp_sensor_id { + NFP_SENSOR_CHIP_TEMPERATURE, + NFP_SENSOR_ASSEMBLY_POWER, + NFP_SENSOR_ASSEMBLY_12V_POWER, + NFP_SENSOR_ASSEMBLY_3V3_POWER, +}; + +int nfp_hwmon_read_sensor(struct nfp_cpp *cpp, enum nfp_nsp_sensor_id id, + long *val); + #endif diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c index e7a263de3731..5d362f87af08 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_cmds.c @@ -46,7 +46,8 @@ struct nsp_identify { __le16 primary; __le16 secondary; __le16 nsp; - __le16 reserved; + u8 reserved[6]; + __le64 sensor_mask; }; struct nfp_nsp_identify *__nfp_nsp_identify(struct nfp_nsp *nsp) @@ -82,8 +83,52 @@ struct nfp_nsp_identify *__nfp_nsp_identify(struct nfp_nsp *nsp) nspi->primary = le16_to_cpu(ni->primary); nspi->secondary = le16_to_cpu(ni->secondary); nspi->nsp = le16_to_cpu(ni->nsp); + nspi->sensor_mask = le64_to_cpu(ni->sensor_mask); exit_free: kfree(ni); return nspi; } + +struct nfp_sensors { + __le32 chip_temp; + __le32 assembly_power; + __le32 assembly_12v_power; + __le32 assembly_3v3_power; +}; + +int nfp_hwmon_read_sensor(struct nfp_cpp *cpp, enum nfp_nsp_sensor_id id, + long *val) +{ + struct nfp_sensors s; + struct nfp_nsp *nsp; + int ret; + + nsp = nfp_nsp_open(cpp); + if (IS_ERR(nsp)) + return PTR_ERR(nsp); + + ret = nfp_nsp_read_sensors(nsp, BIT(id), &s, sizeof(s)); + nfp_nsp_close(nsp); + + if (ret < 0) + return ret; + + switch (id) { + case NFP_SENSOR_CHIP_TEMPERATURE: + *val = le32_to_cpu(s.chip_temp); + break; + case NFP_SENSOR_ASSEMBLY_POWER: + *val = le32_to_cpu(s.assembly_power); + break; + case NFP_SENSOR_ASSEMBLY_12V_POWER: + *val = le32_to_cpu(s.assembly_12v_power); + break; + case NFP_SENSOR_ASSEMBLY_3V3_POWER: + *val = le32_to_cpu(s.assembly_3v3_power); + break; + default: + return -EINVAL; + } + return 0; +} -- cgit v1.2.3 From 9b5655767c6763f0322d8292f3d9dbc43816d22e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:53:01 -0700 Subject: nfp: don't wait for resources indefinitely There is currently no timeout to the resource and lock acquiring loops. We printed warnings and depended on user sending a signal to the waiting process to stop the waiting. This doesn't work very well when wait happens out of a work queue. The simplest example of that is PCI probe. When user loads the module and card is in a broken state modprobe will wait forever and signals sent to it will not actually reach the probing thread. Make sure all wait loops have a time out. Set the upper wait time to 60 seconds to stay on the safe side. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 5 +++++ drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c | 9 +++++++-- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c | 10 ++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index 8d46b9acb69f..0a46c0984e68 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -63,6 +63,11 @@ /* Max size of area it should be safe to request */ #define NFP_CPP_SAFE_AREA_SIZE SZ_2M +/* NFP_MUTEX_WAIT_* are timeouts in seconds when waiting for a mutex */ +#define NFP_MUTEX_WAIT_FIRST_WARN 15 +#define NFP_MUTEX_WAIT_NEXT_WARN 5 +#define NFP_MUTEX_WAIT_ERROR 60 + struct device; struct nfp_cpp_area; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c index 8a99c189efa8..f7b958181126 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mutex.c @@ -195,7 +195,8 @@ void nfp_cpp_mutex_free(struct nfp_cpp_mutex *mutex) */ int nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex) { - unsigned long warn_at = jiffies + 15 * HZ; + unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ; + unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ; unsigned int timeout_ms = 1; int err; @@ -214,12 +215,16 @@ int nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex) return -ERESTARTSYS; if (time_is_before_eq_jiffies(warn_at)) { - warn_at = jiffies + 60 * HZ; + warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ; nfp_warn(mutex->cpp, "Warning: waiting for NFP mutex [depth:%hd target:%d addr:%llx key:%08x]\n", mutex->depth, mutex->target, mutex->address, mutex->key); } + if (time_is_before_eq_jiffies(err_at)) { + nfp_err(mutex->cpp, "Error: mutex wait timed out\n"); + return -EBUSY; + } } return err; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c index 2d15a7c9d0de..072612263dab 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c @@ -181,7 +181,8 @@ err_unlock_dev: struct nfp_resource * nfp_resource_acquire(struct nfp_cpp *cpp, const char *name) { - unsigned long warn_at = jiffies + 15 * HZ; + unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ; + unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ; struct nfp_cpp_mutex *dev_mutex; struct nfp_resource *res; int err; @@ -214,10 +215,15 @@ nfp_resource_acquire(struct nfp_cpp *cpp, const char *name) } if (time_is_before_eq_jiffies(warn_at)) { - warn_at = jiffies + 60 * HZ; + warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ; nfp_warn(cpp, "Warning: waiting for NFP resource %s\n", name); } + if (time_is_before_eq_jiffies(err_at)) { + nfp_err(cpp, "Error: resource %s timed out\n", name); + err = -EBUSY; + goto err_free; + } } nfp_cpp_mutex_free(dev_mutex); -- cgit v1.2.3 From 193d6218ba801c88a5f3ef1bb2357e39074b3cdc Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:53:02 -0700 Subject: nfp: fix print format for ring pointers in ring dumps Ring pointers are unsigned. Fix the print formats to avoid showing users negative values. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c index 6cf1b234eecd..8c52c0e8379c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c @@ -62,7 +62,7 @@ static int nfp_net_debugfs_rx_q_read(struct seq_file *file, void *data) fl_rd_p = nfp_qcp_rd_ptr_read(rx_ring->qcp_fl); fl_wr_p = nfp_qcp_wr_ptr_read(rx_ring->qcp_fl); - seq_printf(file, "RX[%02d,%02d]: cnt=%d dma=%pad host=%p H_RD=%d H_WR=%d FL_RD=%d FL_WR=%d\n", + seq_printf(file, "RX[%02d,%02d]: cnt=%u dma=%pad host=%p H_RD=%u H_WR=%u FL_RD=%u FL_WR=%u\n", rx_ring->idx, rx_ring->fl_qcidx, rx_ring->cnt, &rx_ring->dma, rx_ring->rxds, rx_ring->rd_p, rx_ring->wr_p, fl_rd_p, fl_wr_p); @@ -146,7 +146,7 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data) d_rd_p = nfp_qcp_rd_ptr_read(tx_ring->qcp_q); d_wr_p = nfp_qcp_wr_ptr_read(tx_ring->qcp_q); - seq_printf(file, "TX[%02d,%02d%s]: cnt=%d dma=%pad host=%p H_RD=%d H_WR=%d D_RD=%d D_WR=%d\n", + seq_printf(file, "TX[%02d,%02d%s]: cnt=%u dma=%pad host=%p H_RD=%u H_WR=%u D_RD=%u D_WR=%u\n", tx_ring->idx, tx_ring->qcidx, tx_ring == r_vec->tx_ring ? "" : "xdp", tx_ring->cnt, &tx_ring->dma, tx_ring->txds, -- cgit v1.2.3 From 770f0cea19510098cb01ac87370e800b53a6bf5d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:53:03 -0700 Subject: nfp: don't add ring size to index calculations Adding ring size to index calculation is pointless, since index will be masked with ring size - 1. Suggested-by: David Laight Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 9312a737fbc9..68013d048e9d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -928,7 +928,7 @@ static void nfp_net_tx_complete(struct nfp_net_tx_ring *tx_ring) if (qcp_rd_p == tx_ring->qcp_rd_p) return; - todo = D_IDX(tx_ring, qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p); + todo = D_IDX(tx_ring, qcp_rd_p - tx_ring->qcp_rd_p); while (todo--) { idx = D_IDX(tx_ring, tx_ring->rd_p++); @@ -999,7 +999,7 @@ static bool nfp_net_xdp_complete(struct nfp_net_tx_ring *tx_ring) if (qcp_rd_p == tx_ring->qcp_rd_p) return true; - todo = D_IDX(tx_ring, qcp_rd_p + tx_ring->cnt - tx_ring->qcp_rd_p); + todo = D_IDX(tx_ring, qcp_rd_p - tx_ring->qcp_rd_p); done_all = todo <= NFP_NET_XDP_MAX_COMPLETE; todo = min(todo, NFP_NET_XDP_MAX_COMPLETE); -- cgit v1.2.3 From 9ed9ea7084f34fcb1d962a4fbd012fe8a2942df8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sun, 28 May 2017 17:53:04 -0700 Subject: nfp: don't keep count for free buffers delayed kick We only kick RX free buffer queue controller every NFP_NET_FL_BATCH (currently 16) entries. This means that we will always kick the QC when write ring index is divisable by NFP_NET_FL_BATCH. There is no need to keep counts. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 3 --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 7 ++----- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 7882d2604835..cb7114309656 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -328,8 +328,6 @@ struct nfp_net_rx_buf { * @idx: Ring index from Linux's perspective * @fl_qcidx: Queue Controller Peripheral (QCP) queue index for the freelist * @qcp_fl: Pointer to base of the QCP freelist queue - * @wr_ptr_add: Accumulated number of buffers to add to QCP write pointer - * (used for free list batching) * @rxbufs: Array of transmitted FL/RX buffers * @rxds: Virtual address of FL/RX ring in host memory * @dma: DMA address of the FL/RX ring @@ -343,7 +341,6 @@ struct nfp_net_rx_ring { u32 rd_p; u32 idx; - u32 wr_ptr_add; int fl_qcidx; u8 __iomem *qcp_fl; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 68013d048e9d..c9a140376621 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1212,14 +1212,12 @@ static void nfp_net_rx_give_one(const struct nfp_net_dp *dp, dma_addr + dp->rx_dma_off); rx_ring->wr_p++; - rx_ring->wr_ptr_add++; - if (rx_ring->wr_ptr_add >= NFP_NET_FL_BATCH) { + if (!(rx_ring->wr_p % NFP_NET_FL_BATCH)) { /* Update write pointer of the freelist queue. Make * sure all writes are flushed before telling the hardware. */ wmb(); - nfp_qcp_wr_ptr_add(rx_ring->qcp_fl, rx_ring->wr_ptr_add); - rx_ring->wr_ptr_add = 0; + nfp_qcp_wr_ptr_add(rx_ring->qcp_fl, NFP_NET_FL_BATCH); } } @@ -1245,7 +1243,6 @@ static void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring) memset(rx_ring->rxds, 0, sizeof(*rx_ring->rxds) * rx_ring->cnt); rx_ring->wr_p = 0; rx_ring->rd_p = 0; - rx_ring->wr_ptr_add = 0; } /** -- cgit v1.2.3 From 05930d18c8240482d6332c57b4aba87e846444c9 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Mon, 29 May 2017 09:53:05 +0300 Subject: qed: Add missing static/local dcbx info Some getters are not getting filled with the correct information regarding local DCBx. Fixes: 49632b5822ea ("qed: Add support for static dcbx.") Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index b83fe1d9e988..efe309e51b3b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -1460,7 +1460,7 @@ static u8 qed_dcbnl_getcap(struct qed_dev *cdev, int capid, u8 *cap) break; case DCB_CAP_ATTR_DCBX: *cap = (DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE | - DCB_CAP_DCBX_VER_IEEE); + DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_STATIC); break; default: *cap = false; @@ -1534,6 +1534,8 @@ static u8 qed_dcbnl_getdcbx(struct qed_dev *cdev) mode |= DCB_CAP_DCBX_VER_IEEE; if (dcbx_info->operational.cee) mode |= DCB_CAP_DCBX_VER_CEE; + if (dcbx_info->operational.local) + mode |= DCB_CAP_DCBX_STATIC; DP_VERBOSE(hwfn, QED_MSG_DCB, "dcb mode = %d\n", mode); kfree(dcbx_info); -- cgit v1.2.3 From dfc268f6c1ac485b12923059f9fac55ec0522bb7 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Mon, 29 May 2017 09:53:06 +0300 Subject: qed: Correct DCBx update scheme Instead of using a boolean value that propagates to FW configuration, use the proper firmware HSI values. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 17 +++++++++-------- drivers/net/ethernet/qlogic/qed/qed_dcbx.h | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index efe309e51b3b..64c2e7cfa822 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -191,17 +191,19 @@ static void qed_dcbx_set_params(struct qed_dcbx_results *p_data, struct qed_hw_info *p_info, bool enable, - bool update, u8 prio, u8 tc, enum dcbx_protocol_type type, enum qed_pci_personality personality) { /* PF update ramrod data */ - p_data->arr[type].update = update; p_data->arr[type].enable = enable; p_data->arr[type].priority = prio; p_data->arr[type].tc = tc; + if (enable) + p_data->arr[type].update = UPDATE_DCB; + else + p_data->arr[type].update = DONT_UPDATE_DCB_DSCP; /* QM reconf data */ if (p_info->personality == personality) @@ -213,7 +215,6 @@ static void qed_dcbx_update_app_info(struct qed_dcbx_results *p_data, struct qed_hwfn *p_hwfn, bool enable, - bool update, u8 prio, u8 tc, enum dcbx_protocol_type type) { struct qed_hw_info *p_info = &p_hwfn->hw_info; @@ -231,7 +232,7 @@ qed_dcbx_update_app_info(struct qed_dcbx_results *p_data, personality = qed_dcbx_app_update[i].personality; name = qed_dcbx_app_update[i].name; - qed_dcbx_set_params(p_data, p_info, enable, update, + qed_dcbx_set_params(p_data, p_info, enable, prio, tc, type, personality); } } @@ -304,7 +305,7 @@ qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, */ enable = !(type == DCBX_PROTOCOL_ETH); - qed_dcbx_update_app_info(p_data, p_hwfn, enable, true, + qed_dcbx_update_app_info(p_data, p_hwfn, enable, priority, tc, type); } } @@ -316,7 +317,7 @@ qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, p_data->arr[DCBX_PROTOCOL_ROCE].update) { tc = p_data->arr[DCBX_PROTOCOL_ROCE].tc; priority = p_data->arr[DCBX_PROTOCOL_ROCE].priority; - qed_dcbx_update_app_info(p_data, p_hwfn, true, true, + qed_dcbx_update_app_info(p_data, p_hwfn, true, priority, tc, DCBX_PROTOCOL_ROCE_V2); } @@ -332,8 +333,8 @@ qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, if (p_data->arr[type].update) continue; - enable = !(type == DCBX_PROTOCOL_ETH); - qed_dcbx_update_app_info(p_data, p_hwfn, enable, true, + enable = (type == DCBX_PROTOCOL_ETH) ? false : !!dcbx_version; + qed_dcbx_update_app_info(p_data, p_hwfn, enable, priority, tc, type); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.h b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h index 414e26268f3a..5feb90e049e0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h @@ -52,7 +52,7 @@ enum qed_mib_read_type { struct qed_dcbx_app_data { bool enable; /* DCB enabled */ - bool update; /* Update indication */ + u8 update; /* Update indication */ u8 priority; /* Priority */ u8 tc; /* Traffic Class */ }; -- cgit v1.2.3 From 38b23e43ee6f0903de989913884a2142bf8b3d7c Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Mon, 29 May 2017 09:53:07 +0300 Subject: qed: Don't inherit RoCE DCBx for V2 Older firmware used by device didn't distinguish between RoCE and RoCE V2 from DCBx configuration perspective, and as a result we've used to take a the RoCE-related configuration and apply to it for both. Since we now support configuring each its own values, there's no reason to reflect [& configure] that both are using the same. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index 64c2e7cfa822..e2a62c091b80 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -310,17 +310,6 @@ qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, } } - /* If RoCE-V2 TLV is not detected, driver need to use RoCE app - * data for RoCE-v2 not the default app data. - */ - if (!p_data->arr[DCBX_PROTOCOL_ROCE_V2].update && - p_data->arr[DCBX_PROTOCOL_ROCE].update) { - tc = p_data->arr[DCBX_PROTOCOL_ROCE].tc; - priority = p_data->arr[DCBX_PROTOCOL_ROCE].priority; - qed_dcbx_update_app_info(p_data, p_hwfn, true, - priority, tc, DCBX_PROTOCOL_ROCE_V2); - } - /* Update ramrod protocol data and hw_info fields * with default info when corresponding APP TLV's are not detected. * The enabled field has a different logic for ethernet as only for -- cgit v1.2.3 From 88072fd4002a9976063d8f2babd3d030bd6ae0f9 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Mon, 29 May 2017 09:53:08 +0300 Subject: qed: QL41xxx VF MSI-x table The QL41xxx adapters' PCI allows a single configuration for the MSI-x table size of all child VFs of a given PF. The existing code wouldn't cause the management firmware to set that value, meaning the VFs would retain the default MSI-x table size. Introduce a new scheme so that whenever a VF is enabled, driver would set the number of MSI-x to be the maximum over the various VFs' needs. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 3 ++- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 35 +++++++++++++++++++++++++++-- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 32 +++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 802c162d8474..f610e52e201d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -11477,6 +11477,7 @@ struct public_drv_mb { #define DRV_MSG_CODE_INITIATE_PF_FLR 0x02010000 #define DRV_MSG_CODE_VF_DISABLED_DONE 0xc0000000 #define DRV_MSG_CODE_CFG_VF_MSIX 0xc0010000 +#define DRV_MSG_CODE_CFG_PF_VFS_MSIX 0xc0020000 #define DRV_MSG_CODE_NVM_GET_FILE_ATT 0x00030000 #define DRV_MSG_CODE_NVM_READ_NVRAM 0x00050000 #define DRV_MSG_CODE_MCP_RESET 0x00090000 @@ -11640,7 +11641,7 @@ struct public_drv_mb { #define FW_MSG_CODE_OS_WOL_SUPPORTED 0x00800000 #define FW_MSG_CODE_OS_WOL_NOT_SUPPORTED 0x00810000 - +#define FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE 0x00870000 #define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff u32 fw_mb_param; diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index fc49c75e6c4b..24c9b71cba4f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1801,8 +1801,9 @@ int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, return 0; } -int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u8 vf_id, u8 num) +static int +qed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 vf_id, u8 num) { u32 resp = 0, param = 0, rc_param = 0; int rc; @@ -1832,6 +1833,36 @@ int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, return rc; } +static int +qed_mcp_config_vf_msix_ah(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 num) +{ + u32 resp = 0, param = num, rc_param = 0; + int rc; + + rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_PF_VFS_MSIX, + param, &resp, &rc_param); + + if (resp != FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE) { + DP_NOTICE(p_hwfn, "MFW failed to set MSI-X for VFs\n"); + rc = -EINVAL; + } else { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "Requested 0x%02x MSI-x interrupts for VFs\n", num); + } + + return rc; +} + +int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 vf_id, u8 num) +{ + if (QED_IS_BB(p_hwfn->cdev)) + return qed_mcp_config_vf_msix_bb(p_hwfn, p_ptt, vf_id, num); + else + return qed_mcp_config_vf_msix_ah(p_hwfn, p_ptt, num); +} + int qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 71e392fe1d97..b6bda45d0489 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -747,6 +747,35 @@ static void qed_iov_vf_igu_set_int(struct qed_hwfn *p_hwfn, qed_fid_pretend(p_hwfn, p_ptt, (u16) p_hwfn->hw_info.concrete_fid); } +static int +qed_iov_enable_vf_access_msix(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 abs_vf_id, u8 num_sbs) +{ + u8 current_max = 0; + int i; + + /* For AH onward, configuration is per-PF. Find maximum of all + * the currently enabled child VFs, and set the number to be that. + */ + if (!QED_IS_BB(p_hwfn->cdev)) { + qed_for_each_vf(p_hwfn, i) { + struct qed_vf_info *p_vf; + + p_vf = qed_iov_get_vf_info(p_hwfn, (u16)i, true); + if (!p_vf) + continue; + + current_max = max_t(u8, current_max, p_vf->num_sbs); + } + } + + if (num_sbs > current_max) + return qed_mcp_config_vf_msix(p_hwfn, p_ptt, + abs_vf_id, num_sbs); + + return 0; +} + static int qed_iov_enable_vf_access(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *vf) @@ -771,7 +800,8 @@ static int qed_iov_enable_vf_access(struct qed_hwfn *p_hwfn, qed_iov_vf_igu_reset(p_hwfn, p_ptt, vf); - rc = qed_mcp_config_vf_msix(p_hwfn, p_ptt, vf->abs_vf_id, vf->num_sbs); + rc = qed_iov_enable_vf_access_msix(p_hwfn, p_ptt, + vf->abs_vf_id, vf->num_sbs); if (rc) return rc; -- cgit v1.2.3 From 2a351fd9b9ffe4168409e9f6519e048581ba6a41 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Mon, 29 May 2017 09:53:09 +0300 Subject: qed: Support dynamic s-tag change In case management firmware indicates a change in the used S-tag, propagate the configuration to HW and FW. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 4 +++- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 26 +++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 2 ++ drivers/net/ethernet/qlogic/qed/qed_sp.h | 9 ++++++++ drivers/net/ethernet/qlogic/qed/qed_sp_commands.c | 24 +++++++++++++++++++++ 5 files changed, 64 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index f610e52e201d..24b1458d7aa3 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -11474,6 +11474,7 @@ struct public_drv_mb { #define DRV_MSG_CODE_BW_UPDATE_ACK 0x32000000 #define DRV_MSG_CODE_NIG_DRAIN 0x30000000 +#define DRV_MSG_CODE_S_TAG_UPDATE_ACK 0x3b000000 #define DRV_MSG_CODE_INITIATE_PF_FLR 0x02010000 #define DRV_MSG_CODE_VF_DISABLED_DONE 0xc0000000 #define DRV_MSG_CODE_CFG_VF_MSIX 0xc0010000 @@ -11634,6 +11635,7 @@ struct public_drv_mb { #define FW_MSG_CODE_RESOURCE_ALLOC_OK 0x34000000 #define FW_MSG_CODE_RESOURCE_ALLOC_UNKNOWN 0x35000000 #define FW_MSG_CODE_RESOURCE_ALLOC_DEPRECATED 0x36000000 +#define FW_MSG_CODE_S_TAG_UPDATE_ACK_DONE 0x3b000000 #define FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE 0xb0010000 #define FW_MSG_CODE_NVM_OK 0x00010000 @@ -11681,7 +11683,7 @@ enum MFW_DRV_MSG_TYPE { MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED, MFW_DRV_MSG_RESERVED4, MFW_DRV_MSG_BW_UPDATE, - MFW_DRV_MSG_BW_UPDATE5, + MFW_DRV_MSG_S_TAG_UPDATE, MFW_DRV_MSG_GET_LAN_STATS, MFW_DRV_MSG_GET_FCOE_STATS, MFW_DRV_MSG_GET_ISCSI_STATS, diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 24c9b71cba4f..31c88e192cd0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1398,6 +1398,28 @@ static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) ¶m); } +static void qed_mcp_update_stag(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + struct public_func shmem_info; + u32 resp = 0, param = 0; + + qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); + + p_hwfn->mcp_info->func_info.ovlan = (u16)shmem_info.ovlan_stag & + FUNC_MF_CFG_OV_STAG_MASK; + p_hwfn->hw_info.ovlan = p_hwfn->mcp_info->func_info.ovlan; + if ((p_hwfn->hw_info.hw_mode & BIT(MODE_MF_SD)) && + (p_hwfn->hw_info.ovlan != QED_MCP_VLAN_UNSET)) { + qed_wr(p_hwfn, p_ptt, + NIG_REG_LLH_FUNC_TAG_VALUE, p_hwfn->hw_info.ovlan); + qed_sp_pf_update_stag(p_hwfn); + } + + /* Acknowledge the MFW */ + qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_S_TAG_UPDATE_ACK, 0, + &resp, ¶m); +} + int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { @@ -1453,6 +1475,10 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, case MFW_DRV_MSG_BW_UPDATE: qed_mcp_update_bw(p_hwfn, p_ptt); break; + case MFW_DRV_MSG_S_TAG_UPDATE: + qed_mcp_update_stag(p_hwfn, p_ptt); + break; + break; default: DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i); rc = -EINVAL; diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index f14772b9cda3..6abf91807265 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -242,6 +242,8 @@ 0x50196cUL #define NIG_REG_LLH_CLS_TYPE_DUALMODE \ 0x501964UL +#define NIG_REG_LLH_FUNC_TAG_EN 0x5019b0UL +#define NIG_REG_LLH_FUNC_TAG_VALUE 0x5019d0UL #define NIG_REG_LLH_FUNC_FILTER_VALUE \ 0x501a00UL #define NIG_REG_LLH_FUNC_FILTER_VALUE_SIZE \ diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index ef77de4de5f2..b9464f3ab0e2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -417,6 +417,15 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, int qed_sp_pf_update(struct qed_hwfn *p_hwfn); +/** + * @brief qed_sp_pf_update_stag - Update firmware of new outer tag + * + * @param p_hwfn + * + * @return int + */ +int qed_sp_pf_update_stag(struct qed_hwfn *p_hwfn); + /** * @brief qed_sp_pf_stop - PF Function Stop Ramrod * diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c index ab09975343cb..46d0c3cb83a5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c @@ -514,3 +514,27 @@ int qed_sp_heartbeat_ramrod(struct qed_hwfn *p_hwfn) return qed_spq_post(p_hwfn, p_ent, NULL); } + +int qed_sp_pf_update_stag(struct qed_hwfn *p_hwfn) +{ + struct qed_spq_entry *p_ent = NULL; + struct qed_sp_init_data init_data; + int rc = -EINVAL; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qed_spq_get_cid(p_hwfn); + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_CB; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + COMMON_RAMROD_PF_UPDATE, PROTOCOLID_COMMON, + &init_data); + if (rc) + return rc; + + p_ent->ramrod.pf_update.update_mf_vlan_flag = true; + p_ent->ramrod.pf_update.mf_vlan = cpu_to_le16(p_hwfn->hw_info.ovlan); + + return qed_spq_post(p_hwfn, p_ent, NULL); +} -- cgit v1.2.3 From 0ebbd1c8d9424a341a21eb18170f4eff1f1f0670 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Mon, 29 May 2017 09:53:10 +0300 Subject: qed: Get rid of the attention-arrays We have almost all the necessary information regarding attentions in the logic employed for taking register dumps. Add some more and get rid of the seperate implementation we have today for identifying & printing various attention sources. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_debug.c | 250 +++++ drivers/net/ethernet/qlogic/qed/qed_hsi.h | 37 + drivers/net/ethernet/qlogic/qed/qed_int.c | 1312 +-------------------------- 3 files changed, 312 insertions(+), 1287 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index 87a1389fb4a8..03c3cf77aaff 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -5352,8 +5352,85 @@ enum dbg_status qed_dbg_fw_asserts_dump(struct qed_hwfn *p_hwfn, return DBG_STATUS_OK; } +enum dbg_status qed_dbg_read_attn(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum block_id block_id, + enum dbg_attn_type attn_type, + bool clear_status, + struct dbg_attn_block_result *results) +{ + enum dbg_status status = qed_dbg_dev_init(p_hwfn, p_ptt); + u8 reg_idx, num_attn_regs, num_result_regs = 0; + const struct dbg_attn_reg *attn_reg_arr; + + if (status != DBG_STATUS_OK) + return status; + + if (!s_dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr || + !s_dbg_arrays[BIN_BUF_DBG_ATTN_BLOCKS].ptr || + !s_dbg_arrays[BIN_BUF_DBG_ATTN_REGS].ptr) + return DBG_STATUS_DBG_ARRAY_NOT_SET; + + attn_reg_arr = qed_get_block_attn_regs(block_id, + attn_type, &num_attn_regs); + + for (reg_idx = 0; reg_idx < num_attn_regs; reg_idx++) { + const struct dbg_attn_reg *reg_data = &attn_reg_arr[reg_idx]; + struct dbg_attn_reg_result *reg_result; + u32 sts_addr, sts_val; + u16 modes_buf_offset; + bool eval_mode; + + /* Check mode */ + eval_mode = GET_FIELD(reg_data->mode.data, + DBG_MODE_HDR_EVAL_MODE) > 0; + modes_buf_offset = GET_FIELD(reg_data->mode.data, + DBG_MODE_HDR_MODES_BUF_OFFSET); + if (eval_mode && !qed_is_mode_match(p_hwfn, &modes_buf_offset)) + continue; + + /* Mode match - read attention status register */ + sts_addr = DWORDS_TO_BYTES(clear_status ? + reg_data->sts_clr_address : + GET_FIELD(reg_data->data, + DBG_ATTN_REG_STS_ADDRESS)); + sts_val = qed_rd(p_hwfn, p_ptt, sts_addr); + if (!sts_val) + continue; + + /* Non-zero attention status - add to results */ + reg_result = &results->reg_results[num_result_regs]; + SET_FIELD(reg_result->data, + DBG_ATTN_REG_RESULT_STS_ADDRESS, sts_addr); + SET_FIELD(reg_result->data, + DBG_ATTN_REG_RESULT_NUM_REG_ATTN, + GET_FIELD(reg_data->data, DBG_ATTN_REG_NUM_REG_ATTN)); + reg_result->block_attn_offset = reg_data->block_attn_offset; + reg_result->sts_val = sts_val; + reg_result->mask_val = qed_rd(p_hwfn, + p_ptt, + DWORDS_TO_BYTES + (reg_data->mask_address)); + num_result_regs++; + } + + results->block_id = (u8)block_id; + results->names_offset = + qed_get_block_attn_data(block_id, attn_type)->names_offset; + SET_FIELD(results->data, DBG_ATTN_BLOCK_RESULT_ATTN_TYPE, attn_type); + SET_FIELD(results->data, + DBG_ATTN_BLOCK_RESULT_NUM_REGS, num_result_regs); + + return DBG_STATUS_OK; +} + /******************************* Data Types **********************************/ +struct block_info { + const char *name; + enum block_id id; +}; + struct mcp_trace_format { u32 data; #define MCP_TRACE_FORMAT_MODULE_MASK 0x0000ffff @@ -5534,6 +5611,97 @@ struct user_dbg_array { static struct user_dbg_array s_user_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {NULL} }; +/* Block names array */ +static struct block_info s_block_info_arr[] = { + {"grc", BLOCK_GRC}, + {"miscs", BLOCK_MISCS}, + {"misc", BLOCK_MISC}, + {"dbu", BLOCK_DBU}, + {"pglue_b", BLOCK_PGLUE_B}, + {"cnig", BLOCK_CNIG}, + {"cpmu", BLOCK_CPMU}, + {"ncsi", BLOCK_NCSI}, + {"opte", BLOCK_OPTE}, + {"bmb", BLOCK_BMB}, + {"pcie", BLOCK_PCIE}, + {"mcp", BLOCK_MCP}, + {"mcp2", BLOCK_MCP2}, + {"pswhst", BLOCK_PSWHST}, + {"pswhst2", BLOCK_PSWHST2}, + {"pswrd", BLOCK_PSWRD}, + {"pswrd2", BLOCK_PSWRD2}, + {"pswwr", BLOCK_PSWWR}, + {"pswwr2", BLOCK_PSWWR2}, + {"pswrq", BLOCK_PSWRQ}, + {"pswrq2", BLOCK_PSWRQ2}, + {"pglcs", BLOCK_PGLCS}, + {"ptu", BLOCK_PTU}, + {"dmae", BLOCK_DMAE}, + {"tcm", BLOCK_TCM}, + {"mcm", BLOCK_MCM}, + {"ucm", BLOCK_UCM}, + {"xcm", BLOCK_XCM}, + {"ycm", BLOCK_YCM}, + {"pcm", BLOCK_PCM}, + {"qm", BLOCK_QM}, + {"tm", BLOCK_TM}, + {"dorq", BLOCK_DORQ}, + {"brb", BLOCK_BRB}, + {"src", BLOCK_SRC}, + {"prs", BLOCK_PRS}, + {"tsdm", BLOCK_TSDM}, + {"msdm", BLOCK_MSDM}, + {"usdm", BLOCK_USDM}, + {"xsdm", BLOCK_XSDM}, + {"ysdm", BLOCK_YSDM}, + {"psdm", BLOCK_PSDM}, + {"tsem", BLOCK_TSEM}, + {"msem", BLOCK_MSEM}, + {"usem", BLOCK_USEM}, + {"xsem", BLOCK_XSEM}, + {"ysem", BLOCK_YSEM}, + {"psem", BLOCK_PSEM}, + {"rss", BLOCK_RSS}, + {"tmld", BLOCK_TMLD}, + {"muld", BLOCK_MULD}, + {"yuld", BLOCK_YULD}, + {"xyld", BLOCK_XYLD}, + {"ptld", BLOCK_PTLD}, + {"ypld", BLOCK_YPLD}, + {"prm", BLOCK_PRM}, + {"pbf_pb1", BLOCK_PBF_PB1}, + {"pbf_pb2", BLOCK_PBF_PB2}, + {"rpb", BLOCK_RPB}, + {"btb", BLOCK_BTB}, + {"pbf", BLOCK_PBF}, + {"rdif", BLOCK_RDIF}, + {"tdif", BLOCK_TDIF}, + {"cdu", BLOCK_CDU}, + {"ccfc", BLOCK_CCFC}, + {"tcfc", BLOCK_TCFC}, + {"igu", BLOCK_IGU}, + {"cau", BLOCK_CAU}, + {"rgfs", BLOCK_RGFS}, + {"rgsrc", BLOCK_RGSRC}, + {"tgfs", BLOCK_TGFS}, + {"tgsrc", BLOCK_TGSRC}, + {"umac", BLOCK_UMAC}, + {"xmac", BLOCK_XMAC}, + {"dbg", BLOCK_DBG}, + {"nig", BLOCK_NIG}, + {"wol", BLOCK_WOL}, + {"bmbn", BLOCK_BMBN}, + {"ipc", BLOCK_IPC}, + {"nwm", BLOCK_NWM}, + {"nws", BLOCK_NWS}, + {"ms", BLOCK_MS}, + {"phy_pcie", BLOCK_PHY_PCIE}, + {"led", BLOCK_LED}, + {"avs_wrap", BLOCK_AVS_WRAP}, + {"misc_aeu", BLOCK_MISC_AEU}, + {"bar0_map", BLOCK_BAR0_MAP} +}; + /* Status string array */ static const char * const s_status_str[] = { /* DBG_STATUS_OK */ @@ -7193,6 +7361,88 @@ enum dbg_status qed_print_fw_asserts_results(struct qed_hwfn *p_hwfn, results_buf, &parsed_buf_size); } +enum dbg_status qed_dbg_parse_attn(struct qed_hwfn *p_hwfn, + struct dbg_attn_block_result *results) +{ + struct user_dbg_array *block_attn, *pstrings; + const u32 *block_attn_name_offsets; + enum dbg_attn_type attn_type; + const char *block_name; + u8 num_regs, i, j; + + num_regs = GET_FIELD(results->data, DBG_ATTN_BLOCK_RESULT_NUM_REGS); + attn_type = (enum dbg_attn_type) + GET_FIELD(results->data, + DBG_ATTN_BLOCK_RESULT_ATTN_TYPE); + block_name = s_block_info_arr[results->block_id].name; + + if (!s_user_dbg_arrays[BIN_BUF_DBG_ATTN_INDEXES].ptr || + !s_user_dbg_arrays[BIN_BUF_DBG_ATTN_NAME_OFFSETS].ptr || + !s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr) + return DBG_STATUS_DBG_ARRAY_NOT_SET; + + block_attn = &s_user_dbg_arrays[BIN_BUF_DBG_ATTN_NAME_OFFSETS]; + block_attn_name_offsets = &block_attn->ptr[results->names_offset]; + + /* Go over registers with a non-zero attention status */ + for (i = 0; i < num_regs; i++) { + struct dbg_attn_reg_result *reg_result; + struct dbg_attn_bit_mapping *mapping; + u8 num_reg_attn, bit_idx = 0; + + reg_result = &results->reg_results[i]; + num_reg_attn = GET_FIELD(reg_result->data, + DBG_ATTN_REG_RESULT_NUM_REG_ATTN); + block_attn = &s_user_dbg_arrays[BIN_BUF_DBG_ATTN_INDEXES]; + mapping = &((struct dbg_attn_bit_mapping *) + block_attn->ptr)[reg_result->block_attn_offset]; + + pstrings = &s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS]; + + /* Go over attention status bits */ + for (j = 0; j < num_reg_attn; j++) { + u16 attn_idx_val = GET_FIELD(mapping[j].data, + DBG_ATTN_BIT_MAPPING_VAL); + const char *attn_name, *attn_type_str, *masked_str; + u32 name_offset, sts_addr; + + /* Check if bit mask should be advanced (due to unused + * bits). + */ + if (GET_FIELD(mapping[j].data, + DBG_ATTN_BIT_MAPPING_IS_UNUSED_BIT_CNT)) { + bit_idx += (u8)attn_idx_val; + continue; + } + + /* Check current bit index */ + if (!(reg_result->sts_val & BIT(bit_idx))) { + bit_idx++; + continue; + } + + /* Find attention name */ + name_offset = block_attn_name_offsets[attn_idx_val]; + attn_name = &((const char *) + pstrings->ptr)[name_offset]; + attn_type_str = attn_type == ATTN_TYPE_INTERRUPT ? + "Interrupt" : "Parity"; + masked_str = reg_result->mask_val & BIT(bit_idx) ? + " [masked]" : ""; + sts_addr = GET_FIELD(reg_result->data, + DBG_ATTN_REG_RESULT_STS_ADDRESS); + DP_NOTICE(p_hwfn, + "%s (%s) : %s [address 0x%08x, bit %d]%s\n", + block_name, attn_type_str, attn_name, + sts_addr, bit_idx, masked_str); + + bit_idx++; + } + } + + return DBG_STATUS_OK; +} + /* Wrapper for unifying the idle_chk and mcp_trace api */ static enum dbg_status qed_print_idle_chk_results_wrapper(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 24b1458d7aa3..3bf3614b3084 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -3076,6 +3076,29 @@ enum dbg_status qed_dbg_fw_asserts_dump(struct qed_hwfn *p_hwfn, u32 *dump_buf, u32 buf_size_in_dwords, u32 *num_dumped_dwords); + +/** + * @brief qed_dbg_read_attn - Reads the attention registers of the specified + * block and type, and writes the results into the specified buffer. + * + * @param p_hwfn - HW device data + * @param p_ptt - Ptt window used for writing the registers. + * @param block - Block ID. + * @param attn_type - Attention type. + * @param clear_status - Indicates if the attention status should be cleared. + * @param results - OUT: Pointer to write the read results into + * + * @return error if one of the following holds: + * - the version wasn't set + * Otherwise, returns ok. + */ +enum dbg_status qed_dbg_read_attn(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum block_id block, + enum dbg_attn_type attn_type, + bool clear_status, + struct dbg_attn_block_result *results); + /** * @brief qed_dbg_print_attn - Prints attention registers values in the * specified results struct. @@ -3309,6 +3332,20 @@ enum dbg_status qed_print_fw_asserts_results(struct qed_hwfn *p_hwfn, u32 num_dumped_dwords, char *results_buf); +/** + * @brief qed_dbg_parse_attn - Parses and prints attention registers values in + * the specified results struct. + * + * @param p_hwfn - HW device data + * @param results - Pointer to the attention read results + * + * @return error if one of the following holds: + * - the version wasn't set + * Otherwise, returns ok. + */ +enum dbg_status qed_dbg_parse_attn(struct qed_hwfn *p_hwfn, + struct dbg_attn_block_result *results); + /* Debug Bus blocks */ static const u32 dbg_bus_blocks[] = { 0x0000000f, /* grc, bb, 15 lines */ diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 661412c275f7..7f4f8e7d71d7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -105,1215 +105,6 @@ struct aeu_invert_reg { #define MAX_ATTN_GRPS (8) #define NUM_ATTN_REGS (9) -/* HW Attention register */ -struct attn_hw_reg { - u16 reg_idx; /* Index of this register in its block */ - u16 num_of_bits; /* number of valid attention bits */ - u32 sts_addr; /* Address of the STS register */ - u32 sts_clr_addr; /* Address of the STS_CLR register */ - u32 sts_wr_addr; /* Address of the STS_WR register */ - u32 mask_addr; /* Address of the MASK register */ -}; - -/* HW block attention registers */ -struct attn_hw_regs { - u16 num_of_int_regs; /* Number of interrupt regs */ - u16 num_of_prty_regs; /* Number of parity regs */ - struct attn_hw_reg **int_regs; /* interrupt regs */ - struct attn_hw_reg **prty_regs; /* parity regs */ -}; - -/* HW block attention registers */ -struct attn_hw_block { - const char *name; /* Block name */ - struct attn_hw_regs chip_regs[1]; -}; - -static struct attn_hw_reg grc_int0_bb_b0 = { - 0, 4, 0x50180, 0x5018c, 0x50188, 0x50184}; - -static struct attn_hw_reg *grc_int_bb_b0_regs[1] = { - &grc_int0_bb_b0}; - -static struct attn_hw_reg grc_prty1_bb_b0 = { - 0, 2, 0x50200, 0x5020c, 0x50208, 0x50204}; - -static struct attn_hw_reg *grc_prty_bb_b0_regs[1] = { - &grc_prty1_bb_b0}; - -static struct attn_hw_reg miscs_int0_bb_b0 = { - 0, 3, 0x9180, 0x918c, 0x9188, 0x9184}; - -static struct attn_hw_reg miscs_int1_bb_b0 = { - 1, 11, 0x9190, 0x919c, 0x9198, 0x9194}; - -static struct attn_hw_reg *miscs_int_bb_b0_regs[2] = { - &miscs_int0_bb_b0, &miscs_int1_bb_b0}; - -static struct attn_hw_reg miscs_prty0_bb_b0 = { - 0, 1, 0x91a0, 0x91ac, 0x91a8, 0x91a4}; - -static struct attn_hw_reg *miscs_prty_bb_b0_regs[1] = { - &miscs_prty0_bb_b0}; - -static struct attn_hw_reg misc_int0_bb_b0 = { - 0, 1, 0x8180, 0x818c, 0x8188, 0x8184}; - -static struct attn_hw_reg *misc_int_bb_b0_regs[1] = { - &misc_int0_bb_b0}; - -static struct attn_hw_reg pglue_b_int0_bb_b0 = { - 0, 23, 0x2a8180, 0x2a818c, 0x2a8188, 0x2a8184}; - -static struct attn_hw_reg *pglue_b_int_bb_b0_regs[1] = { - &pglue_b_int0_bb_b0}; - -static struct attn_hw_reg pglue_b_prty0_bb_b0 = { - 0, 1, 0x2a8190, 0x2a819c, 0x2a8198, 0x2a8194}; - -static struct attn_hw_reg pglue_b_prty1_bb_b0 = { - 1, 22, 0x2a8200, 0x2a820c, 0x2a8208, 0x2a8204}; - -static struct attn_hw_reg *pglue_b_prty_bb_b0_regs[2] = { - &pglue_b_prty0_bb_b0, &pglue_b_prty1_bb_b0}; - -static struct attn_hw_reg cnig_int0_bb_b0 = { - 0, 6, 0x2182e8, 0x2182f4, 0x2182f0, 0x2182ec}; - -static struct attn_hw_reg *cnig_int_bb_b0_regs[1] = { - &cnig_int0_bb_b0}; - -static struct attn_hw_reg cnig_prty0_bb_b0 = { - 0, 2, 0x218348, 0x218354, 0x218350, 0x21834c}; - -static struct attn_hw_reg *cnig_prty_bb_b0_regs[1] = { - &cnig_prty0_bb_b0}; - -static struct attn_hw_reg cpmu_int0_bb_b0 = { - 0, 1, 0x303e0, 0x303ec, 0x303e8, 0x303e4}; - -static struct attn_hw_reg *cpmu_int_bb_b0_regs[1] = { - &cpmu_int0_bb_b0}; - -static struct attn_hw_reg ncsi_int0_bb_b0 = { - 0, 1, 0x404cc, 0x404d8, 0x404d4, 0x404d0}; - -static struct attn_hw_reg *ncsi_int_bb_b0_regs[1] = { - &ncsi_int0_bb_b0}; - -static struct attn_hw_reg ncsi_prty1_bb_b0 = { - 0, 1, 0x40000, 0x4000c, 0x40008, 0x40004}; - -static struct attn_hw_reg *ncsi_prty_bb_b0_regs[1] = { - &ncsi_prty1_bb_b0}; - -static struct attn_hw_reg opte_prty1_bb_b0 = { - 0, 11, 0x53000, 0x5300c, 0x53008, 0x53004}; - -static struct attn_hw_reg opte_prty0_bb_b0 = { - 1, 1, 0x53208, 0x53214, 0x53210, 0x5320c}; - -static struct attn_hw_reg *opte_prty_bb_b0_regs[2] = { - &opte_prty1_bb_b0, &opte_prty0_bb_b0}; - -static struct attn_hw_reg bmb_int0_bb_b0 = { - 0, 16, 0x5400c0, 0x5400cc, 0x5400c8, 0x5400c4}; - -static struct attn_hw_reg bmb_int1_bb_b0 = { - 1, 28, 0x5400d8, 0x5400e4, 0x5400e0, 0x5400dc}; - -static struct attn_hw_reg bmb_int2_bb_b0 = { - 2, 26, 0x5400f0, 0x5400fc, 0x5400f8, 0x5400f4}; - -static struct attn_hw_reg bmb_int3_bb_b0 = { - 3, 31, 0x540108, 0x540114, 0x540110, 0x54010c}; - -static struct attn_hw_reg bmb_int4_bb_b0 = { - 4, 27, 0x540120, 0x54012c, 0x540128, 0x540124}; - -static struct attn_hw_reg bmb_int5_bb_b0 = { - 5, 29, 0x540138, 0x540144, 0x540140, 0x54013c}; - -static struct attn_hw_reg bmb_int6_bb_b0 = { - 6, 30, 0x540150, 0x54015c, 0x540158, 0x540154}; - -static struct attn_hw_reg bmb_int7_bb_b0 = { - 7, 32, 0x540168, 0x540174, 0x540170, 0x54016c}; - -static struct attn_hw_reg bmb_int8_bb_b0 = { - 8, 32, 0x540184, 0x540190, 0x54018c, 0x540188}; - -static struct attn_hw_reg bmb_int9_bb_b0 = { - 9, 32, 0x54019c, 0x5401a8, 0x5401a4, 0x5401a0}; - -static struct attn_hw_reg bmb_int10_bb_b0 = { - 10, 3, 0x5401b4, 0x5401c0, 0x5401bc, 0x5401b8}; - -static struct attn_hw_reg bmb_int11_bb_b0 = { - 11, 4, 0x5401cc, 0x5401d8, 0x5401d4, 0x5401d0}; - -static struct attn_hw_reg *bmb_int_bb_b0_regs[12] = { - &bmb_int0_bb_b0, &bmb_int1_bb_b0, &bmb_int2_bb_b0, &bmb_int3_bb_b0, - &bmb_int4_bb_b0, &bmb_int5_bb_b0, &bmb_int6_bb_b0, &bmb_int7_bb_b0, - &bmb_int8_bb_b0, &bmb_int9_bb_b0, &bmb_int10_bb_b0, &bmb_int11_bb_b0}; - -static struct attn_hw_reg bmb_prty0_bb_b0 = { - 0, 5, 0x5401dc, 0x5401e8, 0x5401e4, 0x5401e0}; - -static struct attn_hw_reg bmb_prty1_bb_b0 = { - 1, 31, 0x540400, 0x54040c, 0x540408, 0x540404}; - -static struct attn_hw_reg bmb_prty2_bb_b0 = { - 2, 15, 0x540410, 0x54041c, 0x540418, 0x540414}; - -static struct attn_hw_reg *bmb_prty_bb_b0_regs[3] = { - &bmb_prty0_bb_b0, &bmb_prty1_bb_b0, &bmb_prty2_bb_b0}; - -static struct attn_hw_reg pcie_prty1_bb_b0 = { - 0, 17, 0x54000, 0x5400c, 0x54008, 0x54004}; - -static struct attn_hw_reg *pcie_prty_bb_b0_regs[1] = { - &pcie_prty1_bb_b0}; - -static struct attn_hw_reg mcp2_prty0_bb_b0 = { - 0, 1, 0x52040, 0x5204c, 0x52048, 0x52044}; - -static struct attn_hw_reg mcp2_prty1_bb_b0 = { - 1, 12, 0x52204, 0x52210, 0x5220c, 0x52208}; - -static struct attn_hw_reg *mcp2_prty_bb_b0_regs[2] = { - &mcp2_prty0_bb_b0, &mcp2_prty1_bb_b0}; - -static struct attn_hw_reg pswhst_int0_bb_b0 = { - 0, 18, 0x2a0180, 0x2a018c, 0x2a0188, 0x2a0184}; - -static struct attn_hw_reg *pswhst_int_bb_b0_regs[1] = { - &pswhst_int0_bb_b0}; - -static struct attn_hw_reg pswhst_prty0_bb_b0 = { - 0, 1, 0x2a0190, 0x2a019c, 0x2a0198, 0x2a0194}; - -static struct attn_hw_reg pswhst_prty1_bb_b0 = { - 1, 17, 0x2a0200, 0x2a020c, 0x2a0208, 0x2a0204}; - -static struct attn_hw_reg *pswhst_prty_bb_b0_regs[2] = { - &pswhst_prty0_bb_b0, &pswhst_prty1_bb_b0}; - -static struct attn_hw_reg pswhst2_int0_bb_b0 = { - 0, 5, 0x29e180, 0x29e18c, 0x29e188, 0x29e184}; - -static struct attn_hw_reg *pswhst2_int_bb_b0_regs[1] = { - &pswhst2_int0_bb_b0}; - -static struct attn_hw_reg pswhst2_prty0_bb_b0 = { - 0, 1, 0x29e190, 0x29e19c, 0x29e198, 0x29e194}; - -static struct attn_hw_reg *pswhst2_prty_bb_b0_regs[1] = { - &pswhst2_prty0_bb_b0}; - -static struct attn_hw_reg pswrd_int0_bb_b0 = { - 0, 3, 0x29c180, 0x29c18c, 0x29c188, 0x29c184}; - -static struct attn_hw_reg *pswrd_int_bb_b0_regs[1] = { - &pswrd_int0_bb_b0}; - -static struct attn_hw_reg pswrd_prty0_bb_b0 = { - 0, 1, 0x29c190, 0x29c19c, 0x29c198, 0x29c194}; - -static struct attn_hw_reg *pswrd_prty_bb_b0_regs[1] = { - &pswrd_prty0_bb_b0}; - -static struct attn_hw_reg pswrd2_int0_bb_b0 = { - 0, 5, 0x29d180, 0x29d18c, 0x29d188, 0x29d184}; - -static struct attn_hw_reg *pswrd2_int_bb_b0_regs[1] = { - &pswrd2_int0_bb_b0}; - -static struct attn_hw_reg pswrd2_prty0_bb_b0 = { - 0, 1, 0x29d190, 0x29d19c, 0x29d198, 0x29d194}; - -static struct attn_hw_reg pswrd2_prty1_bb_b0 = { - 1, 31, 0x29d200, 0x29d20c, 0x29d208, 0x29d204}; - -static struct attn_hw_reg pswrd2_prty2_bb_b0 = { - 2, 3, 0x29d210, 0x29d21c, 0x29d218, 0x29d214}; - -static struct attn_hw_reg *pswrd2_prty_bb_b0_regs[3] = { - &pswrd2_prty0_bb_b0, &pswrd2_prty1_bb_b0, &pswrd2_prty2_bb_b0}; - -static struct attn_hw_reg pswwr_int0_bb_b0 = { - 0, 16, 0x29a180, 0x29a18c, 0x29a188, 0x29a184}; - -static struct attn_hw_reg *pswwr_int_bb_b0_regs[1] = { - &pswwr_int0_bb_b0}; - -static struct attn_hw_reg pswwr_prty0_bb_b0 = { - 0, 1, 0x29a190, 0x29a19c, 0x29a198, 0x29a194}; - -static struct attn_hw_reg *pswwr_prty_bb_b0_regs[1] = { - &pswwr_prty0_bb_b0}; - -static struct attn_hw_reg pswwr2_int0_bb_b0 = { - 0, 19, 0x29b180, 0x29b18c, 0x29b188, 0x29b184}; - -static struct attn_hw_reg *pswwr2_int_bb_b0_regs[1] = { - &pswwr2_int0_bb_b0}; - -static struct attn_hw_reg pswwr2_prty0_bb_b0 = { - 0, 1, 0x29b190, 0x29b19c, 0x29b198, 0x29b194}; - -static struct attn_hw_reg pswwr2_prty1_bb_b0 = { - 1, 31, 0x29b200, 0x29b20c, 0x29b208, 0x29b204}; - -static struct attn_hw_reg pswwr2_prty2_bb_b0 = { - 2, 31, 0x29b210, 0x29b21c, 0x29b218, 0x29b214}; - -static struct attn_hw_reg pswwr2_prty3_bb_b0 = { - 3, 31, 0x29b220, 0x29b22c, 0x29b228, 0x29b224}; - -static struct attn_hw_reg pswwr2_prty4_bb_b0 = { - 4, 20, 0x29b230, 0x29b23c, 0x29b238, 0x29b234}; - -static struct attn_hw_reg *pswwr2_prty_bb_b0_regs[5] = { - &pswwr2_prty0_bb_b0, &pswwr2_prty1_bb_b0, &pswwr2_prty2_bb_b0, - &pswwr2_prty3_bb_b0, &pswwr2_prty4_bb_b0}; - -static struct attn_hw_reg pswrq_int0_bb_b0 = { - 0, 21, 0x280180, 0x28018c, 0x280188, 0x280184}; - -static struct attn_hw_reg *pswrq_int_bb_b0_regs[1] = { - &pswrq_int0_bb_b0}; - -static struct attn_hw_reg pswrq_prty0_bb_b0 = { - 0, 1, 0x280190, 0x28019c, 0x280198, 0x280194}; - -static struct attn_hw_reg *pswrq_prty_bb_b0_regs[1] = { - &pswrq_prty0_bb_b0}; - -static struct attn_hw_reg pswrq2_int0_bb_b0 = { - 0, 15, 0x240180, 0x24018c, 0x240188, 0x240184}; - -static struct attn_hw_reg *pswrq2_int_bb_b0_regs[1] = { - &pswrq2_int0_bb_b0}; - -static struct attn_hw_reg pswrq2_prty1_bb_b0 = { - 0, 9, 0x240200, 0x24020c, 0x240208, 0x240204}; - -static struct attn_hw_reg *pswrq2_prty_bb_b0_regs[1] = { - &pswrq2_prty1_bb_b0}; - -static struct attn_hw_reg pglcs_int0_bb_b0 = { - 0, 1, 0x1d00, 0x1d0c, 0x1d08, 0x1d04}; - -static struct attn_hw_reg *pglcs_int_bb_b0_regs[1] = { - &pglcs_int0_bb_b0}; - -static struct attn_hw_reg dmae_int0_bb_b0 = { - 0, 2, 0xc180, 0xc18c, 0xc188, 0xc184}; - -static struct attn_hw_reg *dmae_int_bb_b0_regs[1] = { - &dmae_int0_bb_b0}; - -static struct attn_hw_reg dmae_prty1_bb_b0 = { - 0, 3, 0xc200, 0xc20c, 0xc208, 0xc204}; - -static struct attn_hw_reg *dmae_prty_bb_b0_regs[1] = { - &dmae_prty1_bb_b0}; - -static struct attn_hw_reg ptu_int0_bb_b0 = { - 0, 8, 0x560180, 0x56018c, 0x560188, 0x560184}; - -static struct attn_hw_reg *ptu_int_bb_b0_regs[1] = { - &ptu_int0_bb_b0}; - -static struct attn_hw_reg ptu_prty1_bb_b0 = { - 0, 18, 0x560200, 0x56020c, 0x560208, 0x560204}; - -static struct attn_hw_reg *ptu_prty_bb_b0_regs[1] = { - &ptu_prty1_bb_b0}; - -static struct attn_hw_reg tcm_int0_bb_b0 = { - 0, 8, 0x1180180, 0x118018c, 0x1180188, 0x1180184}; - -static struct attn_hw_reg tcm_int1_bb_b0 = { - 1, 32, 0x1180190, 0x118019c, 0x1180198, 0x1180194}; - -static struct attn_hw_reg tcm_int2_bb_b0 = { - 2, 1, 0x11801a0, 0x11801ac, 0x11801a8, 0x11801a4}; - -static struct attn_hw_reg *tcm_int_bb_b0_regs[3] = { - &tcm_int0_bb_b0, &tcm_int1_bb_b0, &tcm_int2_bb_b0}; - -static struct attn_hw_reg tcm_prty1_bb_b0 = { - 0, 31, 0x1180200, 0x118020c, 0x1180208, 0x1180204}; - -static struct attn_hw_reg tcm_prty2_bb_b0 = { - 1, 2, 0x1180210, 0x118021c, 0x1180218, 0x1180214}; - -static struct attn_hw_reg *tcm_prty_bb_b0_regs[2] = { - &tcm_prty1_bb_b0, &tcm_prty2_bb_b0}; - -static struct attn_hw_reg mcm_int0_bb_b0 = { - 0, 14, 0x1200180, 0x120018c, 0x1200188, 0x1200184}; - -static struct attn_hw_reg mcm_int1_bb_b0 = { - 1, 26, 0x1200190, 0x120019c, 0x1200198, 0x1200194}; - -static struct attn_hw_reg mcm_int2_bb_b0 = { - 2, 1, 0x12001a0, 0x12001ac, 0x12001a8, 0x12001a4}; - -static struct attn_hw_reg *mcm_int_bb_b0_regs[3] = { - &mcm_int0_bb_b0, &mcm_int1_bb_b0, &mcm_int2_bb_b0}; - -static struct attn_hw_reg mcm_prty1_bb_b0 = { - 0, 31, 0x1200200, 0x120020c, 0x1200208, 0x1200204}; - -static struct attn_hw_reg mcm_prty2_bb_b0 = { - 1, 4, 0x1200210, 0x120021c, 0x1200218, 0x1200214}; - -static struct attn_hw_reg *mcm_prty_bb_b0_regs[2] = { - &mcm_prty1_bb_b0, &mcm_prty2_bb_b0}; - -static struct attn_hw_reg ucm_int0_bb_b0 = { - 0, 17, 0x1280180, 0x128018c, 0x1280188, 0x1280184}; - -static struct attn_hw_reg ucm_int1_bb_b0 = { - 1, 29, 0x1280190, 0x128019c, 0x1280198, 0x1280194}; - -static struct attn_hw_reg ucm_int2_bb_b0 = { - 2, 1, 0x12801a0, 0x12801ac, 0x12801a8, 0x12801a4}; - -static struct attn_hw_reg *ucm_int_bb_b0_regs[3] = { - &ucm_int0_bb_b0, &ucm_int1_bb_b0, &ucm_int2_bb_b0}; - -static struct attn_hw_reg ucm_prty1_bb_b0 = { - 0, 31, 0x1280200, 0x128020c, 0x1280208, 0x1280204}; - -static struct attn_hw_reg ucm_prty2_bb_b0 = { - 1, 7, 0x1280210, 0x128021c, 0x1280218, 0x1280214}; - -static struct attn_hw_reg *ucm_prty_bb_b0_regs[2] = { - &ucm_prty1_bb_b0, &ucm_prty2_bb_b0}; - -static struct attn_hw_reg xcm_int0_bb_b0 = { - 0, 16, 0x1000180, 0x100018c, 0x1000188, 0x1000184}; - -static struct attn_hw_reg xcm_int1_bb_b0 = { - 1, 25, 0x1000190, 0x100019c, 0x1000198, 0x1000194}; - -static struct attn_hw_reg xcm_int2_bb_b0 = { - 2, 8, 0x10001a0, 0x10001ac, 0x10001a8, 0x10001a4}; - -static struct attn_hw_reg *xcm_int_bb_b0_regs[3] = { - &xcm_int0_bb_b0, &xcm_int1_bb_b0, &xcm_int2_bb_b0}; - -static struct attn_hw_reg xcm_prty1_bb_b0 = { - 0, 31, 0x1000200, 0x100020c, 0x1000208, 0x1000204}; - -static struct attn_hw_reg xcm_prty2_bb_b0 = { - 1, 11, 0x1000210, 0x100021c, 0x1000218, 0x1000214}; - -static struct attn_hw_reg *xcm_prty_bb_b0_regs[2] = { - &xcm_prty1_bb_b0, &xcm_prty2_bb_b0}; - -static struct attn_hw_reg ycm_int0_bb_b0 = { - 0, 13, 0x1080180, 0x108018c, 0x1080188, 0x1080184}; - -static struct attn_hw_reg ycm_int1_bb_b0 = { - 1, 23, 0x1080190, 0x108019c, 0x1080198, 0x1080194}; - -static struct attn_hw_reg ycm_int2_bb_b0 = { - 2, 1, 0x10801a0, 0x10801ac, 0x10801a8, 0x10801a4}; - -static struct attn_hw_reg *ycm_int_bb_b0_regs[3] = { - &ycm_int0_bb_b0, &ycm_int1_bb_b0, &ycm_int2_bb_b0}; - -static struct attn_hw_reg ycm_prty1_bb_b0 = { - 0, 31, 0x1080200, 0x108020c, 0x1080208, 0x1080204}; - -static struct attn_hw_reg ycm_prty2_bb_b0 = { - 1, 3, 0x1080210, 0x108021c, 0x1080218, 0x1080214}; - -static struct attn_hw_reg *ycm_prty_bb_b0_regs[2] = { - &ycm_prty1_bb_b0, &ycm_prty2_bb_b0}; - -static struct attn_hw_reg pcm_int0_bb_b0 = { - 0, 5, 0x1100180, 0x110018c, 0x1100188, 0x1100184}; - -static struct attn_hw_reg pcm_int1_bb_b0 = { - 1, 14, 0x1100190, 0x110019c, 0x1100198, 0x1100194}; - -static struct attn_hw_reg pcm_int2_bb_b0 = { - 2, 1, 0x11001a0, 0x11001ac, 0x11001a8, 0x11001a4}; - -static struct attn_hw_reg *pcm_int_bb_b0_regs[3] = { - &pcm_int0_bb_b0, &pcm_int1_bb_b0, &pcm_int2_bb_b0}; - -static struct attn_hw_reg pcm_prty1_bb_b0 = { - 0, 11, 0x1100200, 0x110020c, 0x1100208, 0x1100204}; - -static struct attn_hw_reg *pcm_prty_bb_b0_regs[1] = { - &pcm_prty1_bb_b0}; - -static struct attn_hw_reg qm_int0_bb_b0 = { - 0, 22, 0x2f0180, 0x2f018c, 0x2f0188, 0x2f0184}; - -static struct attn_hw_reg *qm_int_bb_b0_regs[1] = { - &qm_int0_bb_b0}; - -static struct attn_hw_reg qm_prty0_bb_b0 = { - 0, 11, 0x2f0190, 0x2f019c, 0x2f0198, 0x2f0194}; - -static struct attn_hw_reg qm_prty1_bb_b0 = { - 1, 31, 0x2f0200, 0x2f020c, 0x2f0208, 0x2f0204}; - -static struct attn_hw_reg qm_prty2_bb_b0 = { - 2, 31, 0x2f0210, 0x2f021c, 0x2f0218, 0x2f0214}; - -static struct attn_hw_reg qm_prty3_bb_b0 = { - 3, 11, 0x2f0220, 0x2f022c, 0x2f0228, 0x2f0224}; - -static struct attn_hw_reg *qm_prty_bb_b0_regs[4] = { - &qm_prty0_bb_b0, &qm_prty1_bb_b0, &qm_prty2_bb_b0, &qm_prty3_bb_b0}; - -static struct attn_hw_reg tm_int0_bb_b0 = { - 0, 32, 0x2c0180, 0x2c018c, 0x2c0188, 0x2c0184}; - -static struct attn_hw_reg tm_int1_bb_b0 = { - 1, 11, 0x2c0190, 0x2c019c, 0x2c0198, 0x2c0194}; - -static struct attn_hw_reg *tm_int_bb_b0_regs[2] = { - &tm_int0_bb_b0, &tm_int1_bb_b0}; - -static struct attn_hw_reg tm_prty1_bb_b0 = { - 0, 17, 0x2c0200, 0x2c020c, 0x2c0208, 0x2c0204}; - -static struct attn_hw_reg *tm_prty_bb_b0_regs[1] = { - &tm_prty1_bb_b0}; - -static struct attn_hw_reg dorq_int0_bb_b0 = { - 0, 9, 0x100180, 0x10018c, 0x100188, 0x100184}; - -static struct attn_hw_reg *dorq_int_bb_b0_regs[1] = { - &dorq_int0_bb_b0}; - -static struct attn_hw_reg dorq_prty0_bb_b0 = { - 0, 1, 0x100190, 0x10019c, 0x100198, 0x100194}; - -static struct attn_hw_reg dorq_prty1_bb_b0 = { - 1, 6, 0x100200, 0x10020c, 0x100208, 0x100204}; - -static struct attn_hw_reg *dorq_prty_bb_b0_regs[2] = { - &dorq_prty0_bb_b0, &dorq_prty1_bb_b0}; - -static struct attn_hw_reg brb_int0_bb_b0 = { - 0, 32, 0x3400c0, 0x3400cc, 0x3400c8, 0x3400c4}; - -static struct attn_hw_reg brb_int1_bb_b0 = { - 1, 30, 0x3400d8, 0x3400e4, 0x3400e0, 0x3400dc}; - -static struct attn_hw_reg brb_int2_bb_b0 = { - 2, 28, 0x3400f0, 0x3400fc, 0x3400f8, 0x3400f4}; - -static struct attn_hw_reg brb_int3_bb_b0 = { - 3, 31, 0x340108, 0x340114, 0x340110, 0x34010c}; - -static struct attn_hw_reg brb_int4_bb_b0 = { - 4, 27, 0x340120, 0x34012c, 0x340128, 0x340124}; - -static struct attn_hw_reg brb_int5_bb_b0 = { - 5, 1, 0x340138, 0x340144, 0x340140, 0x34013c}; - -static struct attn_hw_reg brb_int6_bb_b0 = { - 6, 8, 0x340150, 0x34015c, 0x340158, 0x340154}; - -static struct attn_hw_reg brb_int7_bb_b0 = { - 7, 32, 0x340168, 0x340174, 0x340170, 0x34016c}; - -static struct attn_hw_reg brb_int8_bb_b0 = { - 8, 17, 0x340184, 0x340190, 0x34018c, 0x340188}; - -static struct attn_hw_reg brb_int9_bb_b0 = { - 9, 1, 0x34019c, 0x3401a8, 0x3401a4, 0x3401a0}; - -static struct attn_hw_reg brb_int10_bb_b0 = { - 10, 14, 0x3401b4, 0x3401c0, 0x3401bc, 0x3401b8}; - -static struct attn_hw_reg brb_int11_bb_b0 = { - 11, 8, 0x3401cc, 0x3401d8, 0x3401d4, 0x3401d0}; - -static struct attn_hw_reg *brb_int_bb_b0_regs[12] = { - &brb_int0_bb_b0, &brb_int1_bb_b0, &brb_int2_bb_b0, &brb_int3_bb_b0, - &brb_int4_bb_b0, &brb_int5_bb_b0, &brb_int6_bb_b0, &brb_int7_bb_b0, - &brb_int8_bb_b0, &brb_int9_bb_b0, &brb_int10_bb_b0, &brb_int11_bb_b0}; - -static struct attn_hw_reg brb_prty0_bb_b0 = { - 0, 5, 0x3401dc, 0x3401e8, 0x3401e4, 0x3401e0}; - -static struct attn_hw_reg brb_prty1_bb_b0 = { - 1, 31, 0x340400, 0x34040c, 0x340408, 0x340404}; - -static struct attn_hw_reg brb_prty2_bb_b0 = { - 2, 14, 0x340410, 0x34041c, 0x340418, 0x340414}; - -static struct attn_hw_reg *brb_prty_bb_b0_regs[3] = { - &brb_prty0_bb_b0, &brb_prty1_bb_b0, &brb_prty2_bb_b0}; - -static struct attn_hw_reg src_int0_bb_b0 = { - 0, 1, 0x2381d8, 0x2381dc, 0x2381e0, 0x2381e4}; - -static struct attn_hw_reg *src_int_bb_b0_regs[1] = { - &src_int0_bb_b0}; - -static struct attn_hw_reg prs_int0_bb_b0 = { - 0, 2, 0x1f0040, 0x1f004c, 0x1f0048, 0x1f0044}; - -static struct attn_hw_reg *prs_int_bb_b0_regs[1] = { - &prs_int0_bb_b0}; - -static struct attn_hw_reg prs_prty0_bb_b0 = { - 0, 2, 0x1f0050, 0x1f005c, 0x1f0058, 0x1f0054}; - -static struct attn_hw_reg prs_prty1_bb_b0 = { - 1, 31, 0x1f0204, 0x1f0210, 0x1f020c, 0x1f0208}; - -static struct attn_hw_reg prs_prty2_bb_b0 = { - 2, 5, 0x1f0214, 0x1f0220, 0x1f021c, 0x1f0218}; - -static struct attn_hw_reg *prs_prty_bb_b0_regs[3] = { - &prs_prty0_bb_b0, &prs_prty1_bb_b0, &prs_prty2_bb_b0}; - -static struct attn_hw_reg tsdm_int0_bb_b0 = { - 0, 26, 0xfb0040, 0xfb004c, 0xfb0048, 0xfb0044}; - -static struct attn_hw_reg *tsdm_int_bb_b0_regs[1] = { - &tsdm_int0_bb_b0}; - -static struct attn_hw_reg tsdm_prty1_bb_b0 = { - 0, 10, 0xfb0200, 0xfb020c, 0xfb0208, 0xfb0204}; - -static struct attn_hw_reg *tsdm_prty_bb_b0_regs[1] = { - &tsdm_prty1_bb_b0}; - -static struct attn_hw_reg msdm_int0_bb_b0 = { - 0, 26, 0xfc0040, 0xfc004c, 0xfc0048, 0xfc0044}; - -static struct attn_hw_reg *msdm_int_bb_b0_regs[1] = { - &msdm_int0_bb_b0}; - -static struct attn_hw_reg msdm_prty1_bb_b0 = { - 0, 11, 0xfc0200, 0xfc020c, 0xfc0208, 0xfc0204}; - -static struct attn_hw_reg *msdm_prty_bb_b0_regs[1] = { - &msdm_prty1_bb_b0}; - -static struct attn_hw_reg usdm_int0_bb_b0 = { - 0, 26, 0xfd0040, 0xfd004c, 0xfd0048, 0xfd0044}; - -static struct attn_hw_reg *usdm_int_bb_b0_regs[1] = { - &usdm_int0_bb_b0}; - -static struct attn_hw_reg usdm_prty1_bb_b0 = { - 0, 10, 0xfd0200, 0xfd020c, 0xfd0208, 0xfd0204}; - -static struct attn_hw_reg *usdm_prty_bb_b0_regs[1] = { - &usdm_prty1_bb_b0}; - -static struct attn_hw_reg xsdm_int0_bb_b0 = { - 0, 26, 0xf80040, 0xf8004c, 0xf80048, 0xf80044}; - -static struct attn_hw_reg *xsdm_int_bb_b0_regs[1] = { - &xsdm_int0_bb_b0}; - -static struct attn_hw_reg xsdm_prty1_bb_b0 = { - 0, 10, 0xf80200, 0xf8020c, 0xf80208, 0xf80204}; - -static struct attn_hw_reg *xsdm_prty_bb_b0_regs[1] = { - &xsdm_prty1_bb_b0}; - -static struct attn_hw_reg ysdm_int0_bb_b0 = { - 0, 26, 0xf90040, 0xf9004c, 0xf90048, 0xf90044}; - -static struct attn_hw_reg *ysdm_int_bb_b0_regs[1] = { - &ysdm_int0_bb_b0}; - -static struct attn_hw_reg ysdm_prty1_bb_b0 = { - 0, 9, 0xf90200, 0xf9020c, 0xf90208, 0xf90204}; - -static struct attn_hw_reg *ysdm_prty_bb_b0_regs[1] = { - &ysdm_prty1_bb_b0}; - -static struct attn_hw_reg psdm_int0_bb_b0 = { - 0, 26, 0xfa0040, 0xfa004c, 0xfa0048, 0xfa0044}; - -static struct attn_hw_reg *psdm_int_bb_b0_regs[1] = { - &psdm_int0_bb_b0}; - -static struct attn_hw_reg psdm_prty1_bb_b0 = { - 0, 9, 0xfa0200, 0xfa020c, 0xfa0208, 0xfa0204}; - -static struct attn_hw_reg *psdm_prty_bb_b0_regs[1] = { - &psdm_prty1_bb_b0}; - -static struct attn_hw_reg tsem_int0_bb_b0 = { - 0, 32, 0x1700040, 0x170004c, 0x1700048, 0x1700044}; - -static struct attn_hw_reg tsem_int1_bb_b0 = { - 1, 13, 0x1700050, 0x170005c, 0x1700058, 0x1700054}; - -static struct attn_hw_reg tsem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1740040, 0x174004c, 0x1740048, 0x1740044}; - -static struct attn_hw_reg *tsem_int_bb_b0_regs[3] = { - &tsem_int0_bb_b0, &tsem_int1_bb_b0, &tsem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg tsem_prty0_bb_b0 = { - 0, 3, 0x17000c8, 0x17000d4, 0x17000d0, 0x17000cc}; - -static struct attn_hw_reg tsem_prty1_bb_b0 = { - 1, 6, 0x1700200, 0x170020c, 0x1700208, 0x1700204}; - -static struct attn_hw_reg tsem_fast_memory_vfc_config_prty1_bb_b0 = { - 2, 6, 0x174a200, 0x174a20c, 0x174a208, 0x174a204}; - -static struct attn_hw_reg *tsem_prty_bb_b0_regs[3] = { - &tsem_prty0_bb_b0, &tsem_prty1_bb_b0, - &tsem_fast_memory_vfc_config_prty1_bb_b0}; - -static struct attn_hw_reg msem_int0_bb_b0 = { - 0, 32, 0x1800040, 0x180004c, 0x1800048, 0x1800044}; - -static struct attn_hw_reg msem_int1_bb_b0 = { - 1, 13, 0x1800050, 0x180005c, 0x1800058, 0x1800054}; - -static struct attn_hw_reg msem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1840040, 0x184004c, 0x1840048, 0x1840044}; - -static struct attn_hw_reg *msem_int_bb_b0_regs[3] = { - &msem_int0_bb_b0, &msem_int1_bb_b0, &msem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg msem_prty0_bb_b0 = { - 0, 3, 0x18000c8, 0x18000d4, 0x18000d0, 0x18000cc}; - -static struct attn_hw_reg msem_prty1_bb_b0 = { - 1, 6, 0x1800200, 0x180020c, 0x1800208, 0x1800204}; - -static struct attn_hw_reg *msem_prty_bb_b0_regs[2] = { - &msem_prty0_bb_b0, &msem_prty1_bb_b0}; - -static struct attn_hw_reg usem_int0_bb_b0 = { - 0, 32, 0x1900040, 0x190004c, 0x1900048, 0x1900044}; - -static struct attn_hw_reg usem_int1_bb_b0 = { - 1, 13, 0x1900050, 0x190005c, 0x1900058, 0x1900054}; - -static struct attn_hw_reg usem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1940040, 0x194004c, 0x1940048, 0x1940044}; - -static struct attn_hw_reg *usem_int_bb_b0_regs[3] = { - &usem_int0_bb_b0, &usem_int1_bb_b0, &usem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg usem_prty0_bb_b0 = { - 0, 3, 0x19000c8, 0x19000d4, 0x19000d0, 0x19000cc}; - -static struct attn_hw_reg usem_prty1_bb_b0 = { - 1, 6, 0x1900200, 0x190020c, 0x1900208, 0x1900204}; - -static struct attn_hw_reg *usem_prty_bb_b0_regs[2] = { - &usem_prty0_bb_b0, &usem_prty1_bb_b0}; - -static struct attn_hw_reg xsem_int0_bb_b0 = { - 0, 32, 0x1400040, 0x140004c, 0x1400048, 0x1400044}; - -static struct attn_hw_reg xsem_int1_bb_b0 = { - 1, 13, 0x1400050, 0x140005c, 0x1400058, 0x1400054}; - -static struct attn_hw_reg xsem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1440040, 0x144004c, 0x1440048, 0x1440044}; - -static struct attn_hw_reg *xsem_int_bb_b0_regs[3] = { - &xsem_int0_bb_b0, &xsem_int1_bb_b0, &xsem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg xsem_prty0_bb_b0 = { - 0, 3, 0x14000c8, 0x14000d4, 0x14000d0, 0x14000cc}; - -static struct attn_hw_reg xsem_prty1_bb_b0 = { - 1, 7, 0x1400200, 0x140020c, 0x1400208, 0x1400204}; - -static struct attn_hw_reg *xsem_prty_bb_b0_regs[2] = { - &xsem_prty0_bb_b0, &xsem_prty1_bb_b0}; - -static struct attn_hw_reg ysem_int0_bb_b0 = { - 0, 32, 0x1500040, 0x150004c, 0x1500048, 0x1500044}; - -static struct attn_hw_reg ysem_int1_bb_b0 = { - 1, 13, 0x1500050, 0x150005c, 0x1500058, 0x1500054}; - -static struct attn_hw_reg ysem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1540040, 0x154004c, 0x1540048, 0x1540044}; - -static struct attn_hw_reg *ysem_int_bb_b0_regs[3] = { - &ysem_int0_bb_b0, &ysem_int1_bb_b0, &ysem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg ysem_prty0_bb_b0 = { - 0, 3, 0x15000c8, 0x15000d4, 0x15000d0, 0x15000cc}; - -static struct attn_hw_reg ysem_prty1_bb_b0 = { - 1, 7, 0x1500200, 0x150020c, 0x1500208, 0x1500204}; - -static struct attn_hw_reg *ysem_prty_bb_b0_regs[2] = { - &ysem_prty0_bb_b0, &ysem_prty1_bb_b0}; - -static struct attn_hw_reg psem_int0_bb_b0 = { - 0, 32, 0x1600040, 0x160004c, 0x1600048, 0x1600044}; - -static struct attn_hw_reg psem_int1_bb_b0 = { - 1, 13, 0x1600050, 0x160005c, 0x1600058, 0x1600054}; - -static struct attn_hw_reg psem_fast_memory_int0_bb_b0 = { - 2, 1, 0x1640040, 0x164004c, 0x1640048, 0x1640044}; - -static struct attn_hw_reg *psem_int_bb_b0_regs[3] = { - &psem_int0_bb_b0, &psem_int1_bb_b0, &psem_fast_memory_int0_bb_b0}; - -static struct attn_hw_reg psem_prty0_bb_b0 = { - 0, 3, 0x16000c8, 0x16000d4, 0x16000d0, 0x16000cc}; - -static struct attn_hw_reg psem_prty1_bb_b0 = { - 1, 6, 0x1600200, 0x160020c, 0x1600208, 0x1600204}; - -static struct attn_hw_reg psem_fast_memory_vfc_config_prty1_bb_b0 = { - 2, 6, 0x164a200, 0x164a20c, 0x164a208, 0x164a204}; - -static struct attn_hw_reg *psem_prty_bb_b0_regs[3] = { - &psem_prty0_bb_b0, &psem_prty1_bb_b0, - &psem_fast_memory_vfc_config_prty1_bb_b0}; - -static struct attn_hw_reg rss_int0_bb_b0 = { - 0, 12, 0x238980, 0x23898c, 0x238988, 0x238984}; - -static struct attn_hw_reg *rss_int_bb_b0_regs[1] = { - &rss_int0_bb_b0}; - -static struct attn_hw_reg rss_prty1_bb_b0 = { - 0, 4, 0x238a00, 0x238a0c, 0x238a08, 0x238a04}; - -static struct attn_hw_reg *rss_prty_bb_b0_regs[1] = { - &rss_prty1_bb_b0}; - -static struct attn_hw_reg tmld_int0_bb_b0 = { - 0, 6, 0x4d0180, 0x4d018c, 0x4d0188, 0x4d0184}; - -static struct attn_hw_reg *tmld_int_bb_b0_regs[1] = { - &tmld_int0_bb_b0}; - -static struct attn_hw_reg tmld_prty1_bb_b0 = { - 0, 8, 0x4d0200, 0x4d020c, 0x4d0208, 0x4d0204}; - -static struct attn_hw_reg *tmld_prty_bb_b0_regs[1] = { - &tmld_prty1_bb_b0}; - -static struct attn_hw_reg muld_int0_bb_b0 = { - 0, 6, 0x4e0180, 0x4e018c, 0x4e0188, 0x4e0184}; - -static struct attn_hw_reg *muld_int_bb_b0_regs[1] = { - &muld_int0_bb_b0}; - -static struct attn_hw_reg muld_prty1_bb_b0 = { - 0, 10, 0x4e0200, 0x4e020c, 0x4e0208, 0x4e0204}; - -static struct attn_hw_reg *muld_prty_bb_b0_regs[1] = { - &muld_prty1_bb_b0}; - -static struct attn_hw_reg yuld_int0_bb_b0 = { - 0, 6, 0x4c8180, 0x4c818c, 0x4c8188, 0x4c8184}; - -static struct attn_hw_reg *yuld_int_bb_b0_regs[1] = { - &yuld_int0_bb_b0}; - -static struct attn_hw_reg yuld_prty1_bb_b0 = { - 0, 6, 0x4c8200, 0x4c820c, 0x4c8208, 0x4c8204}; - -static struct attn_hw_reg *yuld_prty_bb_b0_regs[1] = { - &yuld_prty1_bb_b0}; - -static struct attn_hw_reg xyld_int0_bb_b0 = { - 0, 6, 0x4c0180, 0x4c018c, 0x4c0188, 0x4c0184}; - -static struct attn_hw_reg *xyld_int_bb_b0_regs[1] = { - &xyld_int0_bb_b0}; - -static struct attn_hw_reg xyld_prty1_bb_b0 = { - 0, 9, 0x4c0200, 0x4c020c, 0x4c0208, 0x4c0204}; - -static struct attn_hw_reg *xyld_prty_bb_b0_regs[1] = { - &xyld_prty1_bb_b0}; - -static struct attn_hw_reg prm_int0_bb_b0 = { - 0, 11, 0x230040, 0x23004c, 0x230048, 0x230044}; - -static struct attn_hw_reg *prm_int_bb_b0_regs[1] = { - &prm_int0_bb_b0}; - -static struct attn_hw_reg prm_prty0_bb_b0 = { - 0, 1, 0x230050, 0x23005c, 0x230058, 0x230054}; - -static struct attn_hw_reg prm_prty1_bb_b0 = { - 1, 24, 0x230200, 0x23020c, 0x230208, 0x230204}; - -static struct attn_hw_reg *prm_prty_bb_b0_regs[2] = { - &prm_prty0_bb_b0, &prm_prty1_bb_b0}; - -static struct attn_hw_reg pbf_pb1_int0_bb_b0 = { - 0, 9, 0xda0040, 0xda004c, 0xda0048, 0xda0044}; - -static struct attn_hw_reg *pbf_pb1_int_bb_b0_regs[1] = { - &pbf_pb1_int0_bb_b0}; - -static struct attn_hw_reg pbf_pb1_prty0_bb_b0 = { - 0, 1, 0xda0050, 0xda005c, 0xda0058, 0xda0054}; - -static struct attn_hw_reg *pbf_pb1_prty_bb_b0_regs[1] = { - &pbf_pb1_prty0_bb_b0}; - -static struct attn_hw_reg pbf_pb2_int0_bb_b0 = { - 0, 9, 0xda4040, 0xda404c, 0xda4048, 0xda4044}; - -static struct attn_hw_reg *pbf_pb2_int_bb_b0_regs[1] = { - &pbf_pb2_int0_bb_b0}; - -static struct attn_hw_reg pbf_pb2_prty0_bb_b0 = { - 0, 1, 0xda4050, 0xda405c, 0xda4058, 0xda4054}; - -static struct attn_hw_reg *pbf_pb2_prty_bb_b0_regs[1] = { - &pbf_pb2_prty0_bb_b0}; - -static struct attn_hw_reg rpb_int0_bb_b0 = { - 0, 9, 0x23c040, 0x23c04c, 0x23c048, 0x23c044}; - -static struct attn_hw_reg *rpb_int_bb_b0_regs[1] = { - &rpb_int0_bb_b0}; - -static struct attn_hw_reg rpb_prty0_bb_b0 = { - 0, 1, 0x23c050, 0x23c05c, 0x23c058, 0x23c054}; - -static struct attn_hw_reg *rpb_prty_bb_b0_regs[1] = { - &rpb_prty0_bb_b0}; - -static struct attn_hw_reg btb_int0_bb_b0 = { - 0, 16, 0xdb00c0, 0xdb00cc, 0xdb00c8, 0xdb00c4}; - -static struct attn_hw_reg btb_int1_bb_b0 = { - 1, 16, 0xdb00d8, 0xdb00e4, 0xdb00e0, 0xdb00dc}; - -static struct attn_hw_reg btb_int2_bb_b0 = { - 2, 4, 0xdb00f0, 0xdb00fc, 0xdb00f8, 0xdb00f4}; - -static struct attn_hw_reg btb_int3_bb_b0 = { - 3, 32, 0xdb0108, 0xdb0114, 0xdb0110, 0xdb010c}; - -static struct attn_hw_reg btb_int4_bb_b0 = { - 4, 23, 0xdb0120, 0xdb012c, 0xdb0128, 0xdb0124}; - -static struct attn_hw_reg btb_int5_bb_b0 = { - 5, 32, 0xdb0138, 0xdb0144, 0xdb0140, 0xdb013c}; - -static struct attn_hw_reg btb_int6_bb_b0 = { - 6, 1, 0xdb0150, 0xdb015c, 0xdb0158, 0xdb0154}; - -static struct attn_hw_reg btb_int8_bb_b0 = { - 7, 1, 0xdb0184, 0xdb0190, 0xdb018c, 0xdb0188}; - -static struct attn_hw_reg btb_int9_bb_b0 = { - 8, 1, 0xdb019c, 0xdb01a8, 0xdb01a4, 0xdb01a0}; - -static struct attn_hw_reg btb_int10_bb_b0 = { - 9, 1, 0xdb01b4, 0xdb01c0, 0xdb01bc, 0xdb01b8}; - -static struct attn_hw_reg btb_int11_bb_b0 = { - 10, 2, 0xdb01cc, 0xdb01d8, 0xdb01d4, 0xdb01d0}; - -static struct attn_hw_reg *btb_int_bb_b0_regs[11] = { - &btb_int0_bb_b0, &btb_int1_bb_b0, &btb_int2_bb_b0, &btb_int3_bb_b0, - &btb_int4_bb_b0, &btb_int5_bb_b0, &btb_int6_bb_b0, &btb_int8_bb_b0, - &btb_int9_bb_b0, &btb_int10_bb_b0, &btb_int11_bb_b0}; - -static struct attn_hw_reg btb_prty0_bb_b0 = { - 0, 5, 0xdb01dc, 0xdb01e8, 0xdb01e4, 0xdb01e0}; - -static struct attn_hw_reg btb_prty1_bb_b0 = { - 1, 23, 0xdb0400, 0xdb040c, 0xdb0408, 0xdb0404}; - -static struct attn_hw_reg *btb_prty_bb_b0_regs[2] = { - &btb_prty0_bb_b0, &btb_prty1_bb_b0}; - -static struct attn_hw_reg pbf_int0_bb_b0 = { - 0, 1, 0xd80180, 0xd8018c, 0xd80188, 0xd80184}; - -static struct attn_hw_reg *pbf_int_bb_b0_regs[1] = { - &pbf_int0_bb_b0}; - -static struct attn_hw_reg pbf_prty0_bb_b0 = { - 0, 1, 0xd80190, 0xd8019c, 0xd80198, 0xd80194}; - -static struct attn_hw_reg pbf_prty1_bb_b0 = { - 1, 31, 0xd80200, 0xd8020c, 0xd80208, 0xd80204}; - -static struct attn_hw_reg pbf_prty2_bb_b0 = { - 2, 27, 0xd80210, 0xd8021c, 0xd80218, 0xd80214}; - -static struct attn_hw_reg *pbf_prty_bb_b0_regs[3] = { - &pbf_prty0_bb_b0, &pbf_prty1_bb_b0, &pbf_prty2_bb_b0}; - -static struct attn_hw_reg rdif_int0_bb_b0 = { - 0, 8, 0x300180, 0x30018c, 0x300188, 0x300184}; - -static struct attn_hw_reg *rdif_int_bb_b0_regs[1] = { - &rdif_int0_bb_b0}; - -static struct attn_hw_reg rdif_prty0_bb_b0 = { - 0, 1, 0x300190, 0x30019c, 0x300198, 0x300194}; - -static struct attn_hw_reg *rdif_prty_bb_b0_regs[1] = { - &rdif_prty0_bb_b0}; - -static struct attn_hw_reg tdif_int0_bb_b0 = { - 0, 8, 0x310180, 0x31018c, 0x310188, 0x310184}; - -static struct attn_hw_reg *tdif_int_bb_b0_regs[1] = { - &tdif_int0_bb_b0}; - -static struct attn_hw_reg tdif_prty0_bb_b0 = { - 0, 1, 0x310190, 0x31019c, 0x310198, 0x310194}; - -static struct attn_hw_reg tdif_prty1_bb_b0 = { - 1, 11, 0x310200, 0x31020c, 0x310208, 0x310204}; - -static struct attn_hw_reg *tdif_prty_bb_b0_regs[2] = { - &tdif_prty0_bb_b0, &tdif_prty1_bb_b0}; - -static struct attn_hw_reg cdu_int0_bb_b0 = { - 0, 8, 0x5801c0, 0x5801c4, 0x5801c8, 0x5801cc}; - -static struct attn_hw_reg *cdu_int_bb_b0_regs[1] = { - &cdu_int0_bb_b0}; - -static struct attn_hw_reg cdu_prty1_bb_b0 = { - 0, 5, 0x580200, 0x58020c, 0x580208, 0x580204}; - -static struct attn_hw_reg *cdu_prty_bb_b0_regs[1] = { - &cdu_prty1_bb_b0}; - -static struct attn_hw_reg ccfc_int0_bb_b0 = { - 0, 2, 0x2e0180, 0x2e018c, 0x2e0188, 0x2e0184}; - -static struct attn_hw_reg *ccfc_int_bb_b0_regs[1] = { - &ccfc_int0_bb_b0}; - -static struct attn_hw_reg ccfc_prty1_bb_b0 = { - 0, 2, 0x2e0200, 0x2e020c, 0x2e0208, 0x2e0204}; - -static struct attn_hw_reg ccfc_prty0_bb_b0 = { - 1, 6, 0x2e05e4, 0x2e05f0, 0x2e05ec, 0x2e05e8}; - -static struct attn_hw_reg *ccfc_prty_bb_b0_regs[2] = { - &ccfc_prty1_bb_b0, &ccfc_prty0_bb_b0}; - -static struct attn_hw_reg tcfc_int0_bb_b0 = { - 0, 2, 0x2d0180, 0x2d018c, 0x2d0188, 0x2d0184}; - -static struct attn_hw_reg *tcfc_int_bb_b0_regs[1] = { - &tcfc_int0_bb_b0}; - -static struct attn_hw_reg tcfc_prty1_bb_b0 = { - 0, 2, 0x2d0200, 0x2d020c, 0x2d0208, 0x2d0204}; - -static struct attn_hw_reg tcfc_prty0_bb_b0 = { - 1, 6, 0x2d05e4, 0x2d05f0, 0x2d05ec, 0x2d05e8}; - -static struct attn_hw_reg *tcfc_prty_bb_b0_regs[2] = { - &tcfc_prty1_bb_b0, &tcfc_prty0_bb_b0}; - -static struct attn_hw_reg igu_int0_bb_b0 = { - 0, 11, 0x180180, 0x18018c, 0x180188, 0x180184}; - -static struct attn_hw_reg *igu_int_bb_b0_regs[1] = { - &igu_int0_bb_b0}; - -static struct attn_hw_reg igu_prty0_bb_b0 = { - 0, 1, 0x180190, 0x18019c, 0x180198, 0x180194}; - -static struct attn_hw_reg igu_prty1_bb_b0 = { - 1, 31, 0x180200, 0x18020c, 0x180208, 0x180204}; - -static struct attn_hw_reg igu_prty2_bb_b0 = { - 2, 1, 0x180210, 0x18021c, 0x180218, 0x180214}; - -static struct attn_hw_reg *igu_prty_bb_b0_regs[3] = { - &igu_prty0_bb_b0, &igu_prty1_bb_b0, &igu_prty2_bb_b0}; - -static struct attn_hw_reg cau_int0_bb_b0 = { - 0, 11, 0x1c00d4, 0x1c00d8, 0x1c00dc, 0x1c00e0}; - -static struct attn_hw_reg *cau_int_bb_b0_regs[1] = { - &cau_int0_bb_b0}; - -static struct attn_hw_reg cau_prty1_bb_b0 = { - 0, 13, 0x1c0200, 0x1c020c, 0x1c0208, 0x1c0204}; - -static struct attn_hw_reg *cau_prty_bb_b0_regs[1] = { - &cau_prty1_bb_b0}; - -static struct attn_hw_reg dbg_int0_bb_b0 = { - 0, 1, 0x10180, 0x1018c, 0x10188, 0x10184}; - -static struct attn_hw_reg *dbg_int_bb_b0_regs[1] = { - &dbg_int0_bb_b0}; - -static struct attn_hw_reg dbg_prty1_bb_b0 = { - 0, 1, 0x10200, 0x1020c, 0x10208, 0x10204}; - -static struct attn_hw_reg *dbg_prty_bb_b0_regs[1] = { - &dbg_prty1_bb_b0}; - -static struct attn_hw_reg nig_int0_bb_b0 = { - 0, 12, 0x500040, 0x50004c, 0x500048, 0x500044}; - -static struct attn_hw_reg nig_int1_bb_b0 = { - 1, 32, 0x500050, 0x50005c, 0x500058, 0x500054}; - -static struct attn_hw_reg nig_int2_bb_b0 = { - 2, 20, 0x500060, 0x50006c, 0x500068, 0x500064}; - -static struct attn_hw_reg nig_int3_bb_b0 = { - 3, 18, 0x500070, 0x50007c, 0x500078, 0x500074}; - -static struct attn_hw_reg nig_int4_bb_b0 = { - 4, 20, 0x500080, 0x50008c, 0x500088, 0x500084}; - -static struct attn_hw_reg nig_int5_bb_b0 = { - 5, 18, 0x500090, 0x50009c, 0x500098, 0x500094}; - -static struct attn_hw_reg *nig_int_bb_b0_regs[6] = { - &nig_int0_bb_b0, &nig_int1_bb_b0, &nig_int2_bb_b0, &nig_int3_bb_b0, - &nig_int4_bb_b0, &nig_int5_bb_b0}; - -static struct attn_hw_reg nig_prty0_bb_b0 = { - 0, 1, 0x5000a0, 0x5000ac, 0x5000a8, 0x5000a4}; - -static struct attn_hw_reg nig_prty1_bb_b0 = { - 1, 31, 0x500200, 0x50020c, 0x500208, 0x500204}; - -static struct attn_hw_reg nig_prty2_bb_b0 = { - 2, 31, 0x500210, 0x50021c, 0x500218, 0x500214}; - -static struct attn_hw_reg nig_prty3_bb_b0 = { - 3, 31, 0x500220, 0x50022c, 0x500228, 0x500224}; - -static struct attn_hw_reg nig_prty4_bb_b0 = { - 4, 17, 0x500230, 0x50023c, 0x500238, 0x500234}; - -static struct attn_hw_reg *nig_prty_bb_b0_regs[5] = { - &nig_prty0_bb_b0, &nig_prty1_bb_b0, &nig_prty2_bb_b0, - &nig_prty3_bb_b0, &nig_prty4_bb_b0}; - -static struct attn_hw_reg ipc_int0_bb_b0 = { - 0, 13, 0x2050c, 0x20518, 0x20514, 0x20510}; - -static struct attn_hw_reg *ipc_int_bb_b0_regs[1] = { - &ipc_int0_bb_b0}; - -static struct attn_hw_reg ipc_prty0_bb_b0 = { - 0, 1, 0x2051c, 0x20528, 0x20524, 0x20520}; - -static struct attn_hw_reg *ipc_prty_bb_b0_regs[1] = { - &ipc_prty0_bb_b0}; - -static struct attn_hw_block attn_blocks[] = { - {"grc", {{1, 1, grc_int_bb_b0_regs, grc_prty_bb_b0_regs} } }, - {"miscs", {{2, 1, miscs_int_bb_b0_regs, miscs_prty_bb_b0_regs} } }, - {"misc", {{1, 0, misc_int_bb_b0_regs, NULL} } }, - {"dbu", {{0, 0, NULL, NULL} } }, - {"pglue_b", {{1, 2, pglue_b_int_bb_b0_regs, - pglue_b_prty_bb_b0_regs} } }, - {"cnig", {{1, 1, cnig_int_bb_b0_regs, cnig_prty_bb_b0_regs} } }, - {"cpmu", {{1, 0, cpmu_int_bb_b0_regs, NULL} } }, - {"ncsi", {{1, 1, ncsi_int_bb_b0_regs, ncsi_prty_bb_b0_regs} } }, - {"opte", {{0, 2, NULL, opte_prty_bb_b0_regs} } }, - {"bmb", {{12, 3, bmb_int_bb_b0_regs, bmb_prty_bb_b0_regs} } }, - {"pcie", {{0, 1, NULL, pcie_prty_bb_b0_regs} } }, - {"mcp", {{0, 0, NULL, NULL} } }, - {"mcp2", {{0, 2, NULL, mcp2_prty_bb_b0_regs} } }, - {"pswhst", {{1, 2, pswhst_int_bb_b0_regs, pswhst_prty_bb_b0_regs} } }, - {"pswhst2", {{1, 1, pswhst2_int_bb_b0_regs, - pswhst2_prty_bb_b0_regs} } }, - {"pswrd", {{1, 1, pswrd_int_bb_b0_regs, pswrd_prty_bb_b0_regs} } }, - {"pswrd2", {{1, 3, pswrd2_int_bb_b0_regs, pswrd2_prty_bb_b0_regs} } }, - {"pswwr", {{1, 1, pswwr_int_bb_b0_regs, pswwr_prty_bb_b0_regs} } }, - {"pswwr2", {{1, 5, pswwr2_int_bb_b0_regs, pswwr2_prty_bb_b0_regs} } }, - {"pswrq", {{1, 1, pswrq_int_bb_b0_regs, pswrq_prty_bb_b0_regs} } }, - {"pswrq2", {{1, 1, pswrq2_int_bb_b0_regs, pswrq2_prty_bb_b0_regs} } }, - {"pglcs", {{1, 0, pglcs_int_bb_b0_regs, NULL} } }, - {"dmae", {{1, 1, dmae_int_bb_b0_regs, dmae_prty_bb_b0_regs} } }, - {"ptu", {{1, 1, ptu_int_bb_b0_regs, ptu_prty_bb_b0_regs} } }, - {"tcm", {{3, 2, tcm_int_bb_b0_regs, tcm_prty_bb_b0_regs} } }, - {"mcm", {{3, 2, mcm_int_bb_b0_regs, mcm_prty_bb_b0_regs} } }, - {"ucm", {{3, 2, ucm_int_bb_b0_regs, ucm_prty_bb_b0_regs} } }, - {"xcm", {{3, 2, xcm_int_bb_b0_regs, xcm_prty_bb_b0_regs} } }, - {"ycm", {{3, 2, ycm_int_bb_b0_regs, ycm_prty_bb_b0_regs} } }, - {"pcm", {{3, 1, pcm_int_bb_b0_regs, pcm_prty_bb_b0_regs} } }, - {"qm", {{1, 4, qm_int_bb_b0_regs, qm_prty_bb_b0_regs} } }, - {"tm", {{2, 1, tm_int_bb_b0_regs, tm_prty_bb_b0_regs} } }, - {"dorq", {{1, 2, dorq_int_bb_b0_regs, dorq_prty_bb_b0_regs} } }, - {"brb", {{12, 3, brb_int_bb_b0_regs, brb_prty_bb_b0_regs} } }, - {"src", {{1, 0, src_int_bb_b0_regs, NULL} } }, - {"prs", {{1, 3, prs_int_bb_b0_regs, prs_prty_bb_b0_regs} } }, - {"tsdm", {{1, 1, tsdm_int_bb_b0_regs, tsdm_prty_bb_b0_regs} } }, - {"msdm", {{1, 1, msdm_int_bb_b0_regs, msdm_prty_bb_b0_regs} } }, - {"usdm", {{1, 1, usdm_int_bb_b0_regs, usdm_prty_bb_b0_regs} } }, - {"xsdm", {{1, 1, xsdm_int_bb_b0_regs, xsdm_prty_bb_b0_regs} } }, - {"ysdm", {{1, 1, ysdm_int_bb_b0_regs, ysdm_prty_bb_b0_regs} } }, - {"psdm", {{1, 1, psdm_int_bb_b0_regs, psdm_prty_bb_b0_regs} } }, - {"tsem", {{3, 3, tsem_int_bb_b0_regs, tsem_prty_bb_b0_regs} } }, - {"msem", {{3, 2, msem_int_bb_b0_regs, msem_prty_bb_b0_regs} } }, - {"usem", {{3, 2, usem_int_bb_b0_regs, usem_prty_bb_b0_regs} } }, - {"xsem", {{3, 2, xsem_int_bb_b0_regs, xsem_prty_bb_b0_regs} } }, - {"ysem", {{3, 2, ysem_int_bb_b0_regs, ysem_prty_bb_b0_regs} } }, - {"psem", {{3, 3, psem_int_bb_b0_regs, psem_prty_bb_b0_regs} } }, - {"rss", {{1, 1, rss_int_bb_b0_regs, rss_prty_bb_b0_regs} } }, - {"tmld", {{1, 1, tmld_int_bb_b0_regs, tmld_prty_bb_b0_regs} } }, - {"muld", {{1, 1, muld_int_bb_b0_regs, muld_prty_bb_b0_regs} } }, - {"yuld", {{1, 1, yuld_int_bb_b0_regs, yuld_prty_bb_b0_regs} } }, - {"xyld", {{1, 1, xyld_int_bb_b0_regs, xyld_prty_bb_b0_regs} } }, - {"prm", {{1, 2, prm_int_bb_b0_regs, prm_prty_bb_b0_regs} } }, - {"pbf_pb1", {{1, 1, pbf_pb1_int_bb_b0_regs, - pbf_pb1_prty_bb_b0_regs} } }, - {"pbf_pb2", {{1, 1, pbf_pb2_int_bb_b0_regs, - pbf_pb2_prty_bb_b0_regs} } }, - {"rpb", { {1, 1, rpb_int_bb_b0_regs, rpb_prty_bb_b0_regs} } }, - {"btb", { {11, 2, btb_int_bb_b0_regs, btb_prty_bb_b0_regs} } }, - {"pbf", { {1, 3, pbf_int_bb_b0_regs, pbf_prty_bb_b0_regs} } }, - {"rdif", { {1, 1, rdif_int_bb_b0_regs, rdif_prty_bb_b0_regs} } }, - {"tdif", { {1, 2, tdif_int_bb_b0_regs, tdif_prty_bb_b0_regs} } }, - {"cdu", { {1, 1, cdu_int_bb_b0_regs, cdu_prty_bb_b0_regs} } }, - {"ccfc", { {1, 2, ccfc_int_bb_b0_regs, ccfc_prty_bb_b0_regs} } }, - {"tcfc", { {1, 2, tcfc_int_bb_b0_regs, tcfc_prty_bb_b0_regs} } }, - {"igu", { {1, 3, igu_int_bb_b0_regs, igu_prty_bb_b0_regs} } }, - {"cau", { {1, 1, cau_int_bb_b0_regs, cau_prty_bb_b0_regs} } }, - {"umac", { {0, 0, NULL, NULL} } }, - {"xmac", { {0, 0, NULL, NULL} } }, - {"dbg", { {1, 1, dbg_int_bb_b0_regs, dbg_prty_bb_b0_regs} } }, - {"nig", { {6, 5, nig_int_bb_b0_regs, nig_prty_bb_b0_regs} } }, - {"wol", { {0, 0, NULL, NULL} } }, - {"bmbn", { {0, 0, NULL, NULL} } }, - {"ipc", { {1, 1, ipc_int_bb_b0_regs, ipc_prty_bb_b0_regs} } }, - {"nwm", { {0, 0, NULL, NULL} } }, - {"nws", { {0, 0, NULL, NULL} } }, - {"ms", { {0, 0, NULL, NULL} } }, - {"phy_pcie", { {0, 0, NULL, NULL} } }, - {"misc_aeu", { {0, 0, NULL, NULL} } }, - {"bar0_map", { {0, 0, NULL, NULL} } },}; - /* Specific HW attention callbacks */ static int qed_mcp_attn_cb(struct qed_hwfn *p_hwfn) { @@ -1863,26 +654,23 @@ static int qed_int_assertion(struct qed_hwfn *p_hwfn, u16 asserted_bits) return 0; } -static void qed_int_deassertion_print_bit(struct qed_hwfn *p_hwfn, - struct attn_hw_reg *p_reg_desc, - struct attn_hw_block *p_block, - enum qed_attention_type type, - u32 val, u32 mask) +static void qed_int_attn_print(struct qed_hwfn *p_hwfn, + enum block_id id, + enum dbg_attn_type type, bool b_clear) { - int j; + struct dbg_attn_block_result attn_results; + enum dbg_status status; - for (j = 0; j < p_reg_desc->num_of_bits; j++) { - if (!(val & (1 << j))) - continue; + memset(&attn_results, 0, sizeof(attn_results)); + status = qed_dbg_read_attn(p_hwfn, p_hwfn->p_dpc_ptt, id, type, + b_clear, &attn_results); + if (status != DBG_STATUS_OK) DP_NOTICE(p_hwfn, - "%s (%s): reg %d [0x%08x], bit %d [%s]\n", - p_block->name, - type == QED_ATTN_TYPE_ATTN ? "Interrupt" : - "Parity", - p_reg_desc->reg_idx, p_reg_desc->sts_addr, - j, (mask & (1 << j)) ? " [MASKED]" : ""); - } + "Failed to parse attention information [status: %s]\n", + qed_dbg_get_status_str(status)); + else + qed_dbg_parse_attn(p_hwfn, &attn_results); } /** @@ -1903,6 +691,7 @@ qed_int_deassertion_aeu_bit(struct qed_hwfn *p_hwfn, u32 aeu_en_reg, u32 bitmask) { + bool b_fatal = false; int rc = -EINVAL; u32 val; @@ -1916,38 +705,14 @@ qed_int_deassertion_aeu_bit(struct qed_hwfn *p_hwfn, rc = p_aeu->cb(p_hwfn); } - /* Handle HW block interrupt registers */ - if (p_aeu->block_index != MAX_BLOCK_ID) { - struct attn_hw_block *p_block; - u32 mask; - int i; - - p_block = &attn_blocks[p_aeu->block_index]; + if (rc) + b_fatal = true; - /* Handle each interrupt register */ - for (i = 0; i < p_block->chip_regs[0].num_of_int_regs; i++) { - struct attn_hw_reg *p_reg_desc; - u32 sts_addr; + /* Print HW block interrupt registers */ + if (p_aeu->block_index != MAX_BLOCK_ID) + qed_int_attn_print(p_hwfn, p_aeu->block_index, + ATTN_TYPE_INTERRUPT, !b_fatal); - p_reg_desc = p_block->chip_regs[0].int_regs[i]; - - /* In case of fatal attention, don't clear the status - * so it would appear in following idle check. - */ - if (rc == 0) - sts_addr = p_reg_desc->sts_clr_addr; - else - sts_addr = p_reg_desc->sts_addr; - - val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, sts_addr); - mask = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - p_reg_desc->mask_addr); - qed_int_deassertion_print_bit(p_hwfn, p_reg_desc, - p_block, - QED_ATTN_TYPE_ATTN, - val, mask); - } - } /* If the attention is benign, no need to prevent it */ if (!rc) @@ -1963,30 +728,6 @@ out: return rc; } -static void qed_int_parity_print(struct qed_hwfn *p_hwfn, - struct aeu_invert_reg_bit *p_aeu, - struct attn_hw_block *p_block, - u8 bit_index) -{ - int i; - - for (i = 0; i < p_block->chip_regs[0].num_of_prty_regs; i++) { - struct attn_hw_reg *p_reg_desc; - u32 val, mask; - - p_reg_desc = p_block->chip_regs[0].prty_regs[i]; - - val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - p_reg_desc->sts_clr_addr); - mask = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - p_reg_desc->mask_addr); - qed_int_deassertion_print_bit(p_hwfn, p_reg_desc, - p_block, - QED_ATTN_TYPE_PARITY, - val, mask); - } -} - /** * @brief qed_int_deassertion_parity - handle a single parity AEU source * @@ -2004,17 +745,14 @@ static void qed_int_deassertion_parity(struct qed_hwfn *p_hwfn, p_aeu->bit_name, bit_index); if (block_id != MAX_BLOCK_ID) { - qed_int_parity_print(p_hwfn, p_aeu, &attn_blocks[block_id], - bit_index); + qed_int_attn_print(p_hwfn, block_id, ATTN_TYPE_PARITY, false); /* In BB, there's a single parity bit for several blocks */ if (block_id == BLOCK_BTB) { - qed_int_parity_print(p_hwfn, p_aeu, - &attn_blocks[BLOCK_OPTE], - bit_index); - qed_int_parity_print(p_hwfn, p_aeu, - &attn_blocks[BLOCK_MCP], - bit_index); + qed_int_attn_print(p_hwfn, BLOCK_OPTE, + ATTN_TYPE_PARITY, false); + qed_int_attn_print(p_hwfn, BLOCK_MCP, + ATTN_TYPE_PARITY, false); } } } -- cgit v1.2.3 From ba36f718c7fedbf0b083faec5e3606d98b846cb7 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Mon, 29 May 2017 09:53:11 +0300 Subject: qed: Diffrentiate adapter-specific attentions There are 4 attention bits in AEU that have different meaning for QL45xxx and QL41xxx adapters. Instead of doing a massive infrastructure change in favor of these bits, we implement a point fix where only those four would change meaning dependent on the adapter involved. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_int.c | 80 ++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 7f4f8e7d71d7..de6f60c6997a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -90,6 +90,12 @@ struct aeu_invert_reg_bit { /* Multiple bits start with this offset */ #define ATTENTION_OFFSET_MASK (0x000ff000) #define ATTENTION_OFFSET_SHIFT (12) + +#define ATTENTION_BB_MASK (0x00700000) +#define ATTENTION_BB_SHIFT (20) +#define ATTENTION_BB(value) (value << ATTENTION_BB_SHIFT) +#define ATTENTION_BB_DIFFERENT BIT(23) + unsigned int flags; /* Callback to call if attention will be triggered */ @@ -381,6 +387,25 @@ static int qed_dorq_attn_cb(struct qed_hwfn *p_hwfn) return -EINVAL; } +/* Instead of major changes to the data-structure, we have a some 'special' + * identifiers for sources that changed meaning between adapters. + */ +enum aeu_invert_reg_special_type { + AEU_INVERT_REG_SPECIAL_CNIG_0, + AEU_INVERT_REG_SPECIAL_CNIG_1, + AEU_INVERT_REG_SPECIAL_CNIG_2, + AEU_INVERT_REG_SPECIAL_CNIG_3, + AEU_INVERT_REG_SPECIAL_MAX, +}; + +static struct aeu_invert_reg_bit +aeu_descs_special[AEU_INVERT_REG_SPECIAL_MAX] = { + {"CNIG port 0", ATTENTION_SINGLE, NULL, BLOCK_CNIG}, + {"CNIG port 1", ATTENTION_SINGLE, NULL, BLOCK_CNIG}, + {"CNIG port 2", ATTENTION_SINGLE, NULL, BLOCK_CNIG}, + {"CNIG port 3", ATTENTION_SINGLE, NULL, BLOCK_CNIG}, +}; + /* Notice aeu_invert_reg must be defined in the same order of bits as HW; */ static struct aeu_invert_reg aeu_descs[NUM_ATTN_REGS] = { { @@ -427,8 +452,22 @@ static struct aeu_invert_reg aeu_descs[NUM_ATTN_REGS] = { (33 << ATTENTION_OFFSET_SHIFT), NULL, MAX_BLOCK_ID}, {"General Attention 35", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID}, - {"CNIG port %d", (4 << ATTENTION_LENGTH_SHIFT), - NULL, BLOCK_CNIG}, + {"NWS Parity", + ATTENTION_PAR | ATTENTION_BB_DIFFERENT | + ATTENTION_BB(AEU_INVERT_REG_SPECIAL_CNIG_0), + NULL, BLOCK_NWS}, + {"NWS Interrupt", + ATTENTION_SINGLE | ATTENTION_BB_DIFFERENT | + ATTENTION_BB(AEU_INVERT_REG_SPECIAL_CNIG_1), + NULL, BLOCK_NWS}, + {"NWM Parity", + ATTENTION_PAR | ATTENTION_BB_DIFFERENT | + ATTENTION_BB(AEU_INVERT_REG_SPECIAL_CNIG_2), + NULL, BLOCK_NWM}, + {"NWM Interrupt", + ATTENTION_SINGLE | ATTENTION_BB_DIFFERENT | + ATTENTION_BB(AEU_INVERT_REG_SPECIAL_CNIG_3), + NULL, BLOCK_NWM}, {"MCP CPU", ATTENTION_SINGLE, qed_mcp_attn_cb, MAX_BLOCK_ID}, {"MCP Watchdog timer", ATTENTION_SINGLE, @@ -566,6 +605,27 @@ static struct aeu_invert_reg aeu_descs[NUM_ATTN_REGS] = { }, }; +static struct aeu_invert_reg_bit * +qed_int_aeu_translate(struct qed_hwfn *p_hwfn, + struct aeu_invert_reg_bit *p_bit) +{ + if (!QED_IS_BB(p_hwfn->cdev)) + return p_bit; + + if (!(p_bit->flags & ATTENTION_BB_DIFFERENT)) + return p_bit; + + return &aeu_descs_special[(p_bit->flags & ATTENTION_BB_MASK) >> + ATTENTION_BB_SHIFT]; +} + +static bool qed_int_is_parity_flag(struct qed_hwfn *p_hwfn, + struct aeu_invert_reg_bit *p_bit) +{ + return !!(qed_int_aeu_translate(p_hwfn, p_bit)->flags & + ATTENTION_PARITY); +} + #define ATTN_STATE_BITS (0xfff) #define ATTN_BITS_MASKABLE (0x3ff) struct qed_sb_attn_info { @@ -799,7 +859,7 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, for (j = 0, bit_idx = 0; bit_idx < 32; j++) { struct aeu_invert_reg_bit *p_bit = &p_aeu->bits[j]; - if ((p_bit->flags & ATTENTION_PARITY) && + if (qed_int_is_parity_flag(p_hwfn, p_bit) && !!(parities & BIT(bit_idx))) qed_int_deassertion_parity(p_hwfn, p_bit, bit_idx); @@ -838,14 +898,11 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, u32 bitmask; p_aeu = &sb_attn_sw->p_aeu_desc[i].bits[j]; - - /* No need to handle parity-only bits */ - if (p_aeu->flags == ATTENTION_PAR) - continue; + p_aeu = qed_int_aeu_translate(p_hwfn, p_aeu); bit = bit_idx; bit_len = ATTENTION_LENGTH(p_aeu->flags); - if (p_aeu->flags & ATTENTION_PAR_INT) { + if (qed_int_is_parity_flag(p_hwfn, p_aeu)) { /* Skip Parity */ bit++; bit_len--; @@ -1104,12 +1161,13 @@ static void qed_int_sb_attn_init(struct qed_hwfn *p_hwfn, for (i = 0; i < NUM_ATTN_REGS; i++) { /* j is array index, k is bit index */ for (j = 0, k = 0; k < 32; j++) { - unsigned int flags = aeu_descs[i].bits[j].flags; + struct aeu_invert_reg_bit *p_aeu; - if (flags & ATTENTION_PARITY) + p_aeu = &aeu_descs[i].bits[j]; + if (qed_int_is_parity_flag(p_hwfn, p_aeu)) sb_info->parity_mask[i] |= 1 << k; - k += ATTENTION_LENGTH(flags); + k += ATTENTION_LENGTH(p_aeu->flags); } DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, "Attn Mask [Reg %d]: 0x%08x\n", -- cgit v1.2.3 From 6010179da3a27f4622eb40a731337fbdb8bbc713 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Mon, 29 May 2017 09:53:12 +0300 Subject: qed: Print multi-bit attentions properly In strucuture reflecting the AEU hw block some entries represent multiple HW bits, and the associated name is in fact a pattern. Today, whenever such an attention would be asserted the resulted prints would show the pattern string instead of indicating which of the possible bits was set. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_int.c | 38 +++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index de6f60c6997a..e19a00203f35 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -749,19 +749,19 @@ static int qed_int_deassertion_aeu_bit(struct qed_hwfn *p_hwfn, struct aeu_invert_reg_bit *p_aeu, u32 aeu_en_reg, - u32 bitmask) + const char *p_bit_name, u32 bitmask) { bool b_fatal = false; int rc = -EINVAL; u32 val; DP_INFO(p_hwfn, "Deasserted attention `%s'[%08x]\n", - p_aeu->bit_name, bitmask); + p_bit_name, bitmask); /* Call callback before clearing the interrupt status */ if (p_aeu->cb) { DP_INFO(p_hwfn, "`%s (attention)': Calling Callback function\n", - p_aeu->bit_name); + p_bit_name); rc = p_aeu->cb(p_hwfn); } @@ -782,7 +782,7 @@ qed_int_deassertion_aeu_bit(struct qed_hwfn *p_hwfn, val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg); qed_wr(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg, (val & ~bitmask)); DP_INFO(p_hwfn, "`%s' - Disabled future attentions\n", - p_aeu->bit_name); + p_bit_name); out: return rc; @@ -894,8 +894,8 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, * previous assertion. */ for (j = 0, bit_idx = 0; bit_idx < 32; j++) { + long unsigned int bitmask; u8 bit, bit_len; - u32 bitmask; p_aeu = &sb_attn_sw->p_aeu_desc[i].bits[j]; p_aeu = qed_int_aeu_translate(p_hwfn, p_aeu); @@ -909,11 +909,39 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, } bitmask = bits & (((1 << bit_len) - 1) << bit); + bitmask >>= bit; + if (bitmask) { + u32 flags = p_aeu->flags; + char bit_name[30]; + u8 num; + + num = (u8)find_first_bit(&bitmask, + bit_len); + + /* Some bits represent more than a + * a single interrupt. Correctly print + * their name. + */ + if (ATTENTION_LENGTH(flags) > 2 || + ((flags & ATTENTION_PAR_INT) && + ATTENTION_LENGTH(flags) > 1)) + snprintf(bit_name, 30, + p_aeu->bit_name, num); + else + strncpy(bit_name, + p_aeu->bit_name, 30); + + /* We now need to pass bitmask in its + * correct position. + */ + bitmask <<= bit; + /* Handle source of the attention */ qed_int_deassertion_aeu_bit(p_hwfn, p_aeu, aeu_en, + bit_name, bitmask); } -- cgit v1.2.3 From 9790c35e9682e0e158653108cc6950f2be196c80 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Mon, 29 May 2017 09:53:13 +0300 Subject: qed: Mask parities after occurance Parities might exhibit a flood behavior since we re-enable the attention line without preventing the parity from re-triggering the assertion. Mask the source in AEU until the parity would be handled. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_int.c | 36 ++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index e19a00203f35..6ac6d80311bb 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -793,16 +793,18 @@ out: * * @param p_hwfn * @param p_aeu - descriptor of an AEU bit which caused the parity + * @param aeu_en_reg - address of the AEU enable register * @param bit_index */ static void qed_int_deassertion_parity(struct qed_hwfn *p_hwfn, struct aeu_invert_reg_bit *p_aeu, - u8 bit_index) + u32 aeu_en_reg, u8 bit_index) { - u32 block_id = p_aeu->block_index; + u32 block_id = p_aeu->block_index, mask, val; - DP_INFO(p_hwfn->cdev, "%s[%d] parity attention is set\n", - p_aeu->bit_name, bit_index); + DP_NOTICE(p_hwfn->cdev, + "%s parity attention is set [address 0x%08x, bit %d]\n", + p_aeu->bit_name, aeu_en_reg, bit_index); if (block_id != MAX_BLOCK_ID) { qed_int_attn_print(p_hwfn, block_id, ATTN_TYPE_PARITY, false); @@ -815,6 +817,13 @@ static void qed_int_deassertion_parity(struct qed_hwfn *p_hwfn, ATTN_TYPE_PARITY, false); } } + + /* Prevent this parity error from being re-asserted */ + mask = ~BIT(bit_index); + val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg); + qed_wr(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg, val & mask); + DP_INFO(p_hwfn, "`%s' - Disabled future parity errors\n", + p_aeu->bit_name); } /** @@ -829,7 +838,7 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, u16 deasserted_bits) { struct qed_sb_attn_info *sb_attn_sw = p_hwfn->p_sb_attn; - u32 aeu_inv_arr[NUM_ATTN_REGS], aeu_mask; + u32 aeu_inv_arr[NUM_ATTN_REGS], aeu_mask, aeu_en, en; u8 i, j, k, bit_idx; int rc = 0; @@ -846,11 +855,11 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, /* Find parity attentions first */ for (i = 0; i < NUM_ATTN_REGS; i++) { struct aeu_invert_reg *p_aeu = &sb_attn_sw->p_aeu_desc[i]; - u32 en = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - MISC_REG_AEU_ENABLE1_IGU_OUT_0 + - i * sizeof(u32)); u32 parities; + aeu_en = MISC_REG_AEU_ENABLE1_IGU_OUT_0 + i * sizeof(u32); + en = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en); + /* Skip register in which no parity bit is currently set */ parities = sb_attn_sw->parity_mask[i] & aeu_inv_arr[i] & en; if (!parities) @@ -862,7 +871,7 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, if (qed_int_is_parity_flag(p_hwfn, p_bit) && !!(parities & BIT(bit_idx))) qed_int_deassertion_parity(p_hwfn, p_bit, - bit_idx); + aeu_en, bit_idx); bit_idx += ATTENTION_LENGTH(p_bit->flags); } @@ -877,10 +886,11 @@ static int qed_int_deassertion(struct qed_hwfn *p_hwfn, continue; for (i = 0; i < NUM_ATTN_REGS; i++) { - u32 aeu_en = MISC_REG_AEU_ENABLE1_IGU_OUT_0 + - i * sizeof(u32) + - k * sizeof(u32) * NUM_ATTN_REGS; - u32 en, bits; + u32 bits; + + aeu_en = MISC_REG_AEU_ENABLE1_IGU_OUT_0 + + i * sizeof(u32) + + k * sizeof(u32) * NUM_ATTN_REGS; en = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en); bits = aeu_inv_arr[i] & en; -- cgit v1.2.3 From fc6575bc498cb86e33a39a399355fd7e74ef2002 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Mon, 29 May 2017 09:53:14 +0300 Subject: qed: Cache alignemnt padding to match host Improve PCI performance by adjusting padding sizes to match those of the host machine's cacheline. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 15 +++++++++++++-- drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 072d950cd8ee..d73e3c265466 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1227,6 +1227,10 @@ static void qed_init_cache_line_size(struct qed_hwfn *p_hwfn, L1_CACHE_BYTES, wr_mbs); STORE_RT_REG(p_hwfn, PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET, val); + if (val > 0) { + STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET, val); + STORE_RT_REG(p_hwfn, PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET, val); + } } static int qed_hw_init_common(struct qed_hwfn *p_hwfn, @@ -1433,8 +1437,15 @@ qed_hw_init_pf_doorbell_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) static int qed_hw_init_port(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, int hw_mode) { - return qed_init_run(p_hwfn, p_ptt, PHASE_PORT, - p_hwfn->port_id, hw_mode); + int rc = 0; + + rc = qed_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, hw_mode); + if (rc) + return rc; + + qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_WRITE_PAD_ENABLE, 0); + + return 0; } static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 6abf91807265..67172d7a7868 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -1559,6 +1559,7 @@ #define PGLUE_B_REG_PGL_ADDR_EC_F0_K2 0x2aaf9cUL #define PGLUE_B_REG_PGL_ADDR_F0_F0_K2 0x2aafa0UL #define PGLUE_B_REG_PGL_ADDR_F4_F0_K2 0x2aafa4UL +#define PGLUE_B_REG_MASTER_WRITE_PAD_ENABLE 0x2aae30UL #define NIG_REG_TSGEN_FREECNT_UPDATE_K2 0x509008UL #define CNIG_REG_NIG_PORT0_CONF_K2 0x218200UL -- cgit v1.2.3 From 15b9e5330f94ccd8202a3eacc79b5d27da82e1c6 Mon Sep 17 00:00:00 2001 From: Bogdan Purcareata Date: Mon, 29 May 2017 09:11:30 +0000 Subject: net: phy: Add Cortina CS4340 driver Add basic support for Cortina PHY drivers. Support only CS4340 for now. The phys are not compatible with IEEE 802.3 clause 22/45 registers. Implement proper read_status support. The generic 10G phy driver causes bus register access errors. The driver should be described using the "ethernet-phy-id" device tree compatible. Signed-off-by: Bogdan Purcareata Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 5 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/cortina.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 drivers/net/phy/cortina.c (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index c360dd6ead22..0c516d3229d0 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -234,6 +234,11 @@ config CICADA_PHY ---help--- Currently supports the cis8204 +config CORTINA_PHY + tristate "Cortina EDC CDR 10G Ethernet PHY" + ---help--- + Currently supports the CS4340 phy. + config DAVICOM_PHY tristate "Davicom PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index e36db9a2ba38..e2fde094f63d 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_CICADA_PHY) += cicada.o +obj-$(CONFIG_CORTINA_PHY) += cortina.o obj-$(CONFIG_DAVICOM_PHY) += davicom.o obj-$(CONFIG_DP83640_PHY) += dp83640.o obj-$(CONFIG_DP83848_PHY) += dp83848.o diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c new file mode 100644 index 000000000000..72f4228a63bb --- /dev/null +++ b/drivers/net/phy/cortina.c @@ -0,0 +1,118 @@ +/* + * Copyright 2017 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * CORTINA is a registered trademark of Cortina Systems, Inc. + * + */ +#include +#include + +#define PHY_ID_CS4340 0x13e51002 + +#define VILLA_GLOBAL_CHIP_ID_LSB 0x0 +#define VILLA_GLOBAL_CHIP_ID_MSB 0x1 + +#define VILLA_GLOBAL_GPIO_1_INTS 0x017 + +static int cortina_read_reg(struct phy_device *phydev, u16 regnum) +{ + return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, + MII_ADDR_C45 | regnum); +} + +static int cortina_config_aneg(struct phy_device *phydev) +{ + phydev->supported = SUPPORTED_10000baseT_Full; + phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + +static int cortina_read_status(struct phy_device *phydev) +{ + int gpio_int_status, ret = 0; + + gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS); + if (gpio_int_status < 0) { + ret = gpio_int_status; + goto err; + } + + if (gpio_int_status & 0x8) { + /* up when edc_convergedS set */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + } else { + phydev->link = 0; + } + +err: + return ret; +} + +static int cortina_soft_reset(struct phy_device *phydev) +{ + return 0; +} + +static int cortina_probe(struct phy_device *phydev) +{ + u32 phy_id = 0; + int id_lsb = 0, id_msb = 0; + + /* Read device id from phy registers. */ + id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB); + if (id_lsb < 0) + return -ENXIO; + + phy_id = id_lsb << 16; + + id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB); + if (id_msb < 0) + return -ENXIO; + + phy_id |= id_msb; + + /* Make sure the device tree binding matched the driver with the + * right device. + */ + if (phy_id != phydev->drv->phy_id) { + phydev_err(phydev, "Error matching phy with %s driver\n", + phydev->drv->name); + return -ENODEV; + } + + return 0; +} + +static struct phy_driver cortina_driver[] = { +{ + .phy_id = PHY_ID_CS4340, + .phy_id_mask = 0xffffffff, + .name = "Cortina CS4340", + .config_aneg = cortina_config_aneg, + .read_status = cortina_read_status, + .soft_reset = cortina_soft_reset, + .probe = cortina_probe, +}, +}; + +module_phy_driver(cortina_driver); + +static struct mdio_device_id __maybe_unused cortina_tbl[] = { + { PHY_ID_CS4340, 0xffffffff}, + {}, +}; + +MODULE_DEVICE_TABLE(mdio, cortina_tbl); -- cgit v1.2.3 From ce68349a356d60d942ce5758d835e9cb00dcf61d Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:09 +0200 Subject: net: qualcomm: qca_7k: clean up header includes Currently the includes doesn't reflect the dependencies. So fix this up by removing all unnecessary entries and add the necessary ones explicit. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_7k.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c index f0066fbb44a6..e9162e1f0c7f 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.c +++ b/drivers/net/ethernet/qualcomm/qca_7k.c @@ -23,11 +23,9 @@ * kernel-based SPI device. */ -#include -#include -#include +#include +#include #include -#include #include "qca_7k.h" -- cgit v1.2.3 From e75977b4b88c3b226c7d3964a048fa8c75659b02 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:10 +0200 Subject: net: qca_framing: use u16 for frame offset It doesn't make sense to use a signed variable for offset here, so fix it up. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_framing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_framing.h b/drivers/net/ethernet/qualcomm/qca_framing.h index d5e795dcdf47..8b385e6f22c9 100644 --- a/drivers/net/ethernet/qualcomm/qca_framing.h +++ b/drivers/net/ethernet/qualcomm/qca_framing.h @@ -103,7 +103,7 @@ struct qcafrm_handle { enum qcafrm_state state; /* Offset in buffer (borrowed for length too) */ - s16 offset; + u16 offset; /* Frame length as kept by this module */ u16 len; -- cgit v1.2.3 From 661ec067b035029ee1c8d282636889a5fd2ddfb3 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:11 +0200 Subject: net: qca_7k: Use BIT macro Use the BIT macro for the CONFIG and INT register values. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_7k.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h index 1cad851ee507..4047f0aeb47a 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.h +++ b/drivers/net/ethernet/qualcomm/qca_7k.h @@ -54,15 +54,15 @@ #define SPI_REG_ACTION_CTRL 0x1B00 /* SPI_CONFIG register definition; */ -#define QCASPI_SLAVE_RESET_BIT (1 << 6) +#define QCASPI_SLAVE_RESET_BIT BIT(6) /* INTR_CAUSE/ENABLE register definition. */ -#define SPI_INT_WRBUF_BELOW_WM (1 << 10) -#define SPI_INT_CPU_ON (1 << 6) -#define SPI_INT_ADDR_ERR (1 << 3) -#define SPI_INT_WRBUF_ERR (1 << 2) -#define SPI_INT_RDBUF_ERR (1 << 1) -#define SPI_INT_PKT_AVLBL (1 << 0) +#define SPI_INT_WRBUF_BELOW_WM BIT(10) +#define SPI_INT_CPU_ON BIT(6) +#define SPI_INT_ADDR_ERR BIT(3) +#define SPI_INT_WRBUF_ERR BIT(2) +#define SPI_INT_RDBUF_ERR BIT(1) +#define SPI_INT_PKT_AVLBL BIT(0) void qcaspi_spi_error(struct qcaspi *qca); int qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result); -- cgit v1.2.3 From 00bc2e49e7bfd499ee925f552155c328d765bf8a Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:12 +0200 Subject: net: qca_spi: Use SET_NETDEV_DEV() Use SET_NETDEV_DEV() in qca_spi to create the "/sys/class/net//device" symlink. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 24ca7df15d07..0c3fdeee27ea 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -894,6 +894,7 @@ qca_spi_probe(struct spi_device *spi) return -ENOMEM; qcaspi_netdev_setup(qcaspi_devs); + SET_NETDEV_DEV(qcaspi_devs, &spi->dev); qca = netdev_priv(qcaspi_devs); if (!qca) { -- cgit v1.2.3 From 0324e75db24bb99c6b7e096d84f273429eb94163 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:13 +0200 Subject: net: qualcomm: use net_device_ops instead of direct call There is no need to export qcaspi_netdev_open and qcaspi_netdev_close because they are also accessible via the net_device_ops. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_debug.c | 5 +++-- drivers/net/ethernet/qualcomm/qca_spi.c | 4 ++-- drivers/net/ethernet/qualcomm/qca_spi.h | 3 --- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c index d145df98feff..92b6be9c4429 100644 --- a/drivers/net/ethernet/qualcomm/qca_debug.c +++ b/drivers/net/ethernet/qualcomm/qca_debug.c @@ -275,6 +275,7 @@ qcaspi_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) static int qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) { + const struct net_device_ops *ops = dev->netdev_ops; struct qcaspi *qca = netdev_priv(dev); if ((ring->rx_pending) || @@ -283,13 +284,13 @@ qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) return -EINVAL; if (netif_running(dev)) - qcaspi_netdev_close(dev); + ops->ndo_stop(dev); qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN); qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN); if (netif_running(dev)) - qcaspi_netdev_open(dev); + ops->ndo_open(dev); return 0; } diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 0c3fdeee27ea..7e039e37a3c7 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -603,7 +603,7 @@ qcaspi_intr_handler(int irq, void *data) return IRQ_HANDLED; } -int +static int qcaspi_netdev_open(struct net_device *dev) { struct qcaspi *qca = netdev_priv(dev); @@ -640,7 +640,7 @@ qcaspi_netdev_open(struct net_device *dev) return 0; } -int +static int qcaspi_netdev_close(struct net_device *dev) { struct qcaspi *qca = netdev_priv(dev); diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index 6e31a0e744a4..064853ddd678 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -108,7 +108,4 @@ struct qcaspi { u16 burst_len; }; -int qcaspi_netdev_open(struct net_device *dev); -int qcaspi_netdev_close(struct net_device *dev); - #endif /* _QCA_SPI_H */ -- cgit v1.2.3 From 2280e3cf1d7feb974d35b34863e9ed6e9c56b257 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:14 +0200 Subject: net: qualcomm: Improve readability of length defines In order to avoid mixing things up, make the MTU and frame length defines easier to read. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_framing.c | 2 +- drivers/net/ethernet/qualcomm/qca_framing.h | 8 ++++---- drivers/net/ethernet/qualcomm/qca_spi.c | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_framing.c b/drivers/net/ethernet/qualcomm/qca_framing.c index faa924c85e29..2341f2bf574d 100644 --- a/drivers/net/ethernet/qualcomm/qca_framing.c +++ b/drivers/net/ethernet/qualcomm/qca_framing.c @@ -117,7 +117,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by break; case QCAFRM_WAIT_RSVD_BYTE2: len = handle->offset; - if (len > buf_len || len < QCAFRM_ETHMINLEN) { + if (len > buf_len || len < QCAFRM_MIN_LEN) { ret = QCAFRM_INVLEN; handle->state = QCAFRM_HW_LEN0; } else { diff --git a/drivers/net/ethernet/qualcomm/qca_framing.h b/drivers/net/ethernet/qualcomm/qca_framing.h index 8b385e6f22c9..5df7c65d887c 100644 --- a/drivers/net/ethernet/qualcomm/qca_framing.h +++ b/drivers/net/ethernet/qualcomm/qca_framing.h @@ -44,12 +44,12 @@ #define QCAFRM_INVFRAME (QCAFRM_ERR_BASE - 4) /* Min/Max Ethernet MTU: 46/1500 */ -#define QCAFRM_ETHMINMTU (ETH_ZLEN - ETH_HLEN) -#define QCAFRM_ETHMAXMTU ETH_DATA_LEN +#define QCAFRM_MIN_MTU (ETH_ZLEN - ETH_HLEN) +#define QCAFRM_MAX_MTU ETH_DATA_LEN /* Min/Max frame lengths */ -#define QCAFRM_ETHMINLEN (QCAFRM_ETHMINMTU + ETH_HLEN) -#define QCAFRM_ETHMAXLEN (QCAFRM_ETHMAXMTU + VLAN_ETH_HLEN) +#define QCAFRM_MIN_LEN (QCAFRM_MIN_MTU + ETH_HLEN) +#define QCAFRM_MAX_LEN (QCAFRM_MAX_MTU + VLAN_ETH_HLEN) /* QCA7K header len */ #define QCAFRM_HEADER_LEN 8 diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 7e039e37a3c7..f15554867ef7 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -69,7 +69,7 @@ static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN; module_param(qcaspi_pluggable, int, 0); MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no)."); -#define QCASPI_MTU QCAFRM_ETHMAXMTU +#define QCASPI_MTU QCAFRM_MAX_MTU #define QCASPI_TX_TIMEOUT (1 * HZ) #define QCASPI_QCA7K_REBOOT_TIME_MS 1000 @@ -403,7 +403,7 @@ qcaspi_tx_ring_has_space(struct tx_ring *txr) if (txr->skb[txr->tail]) return 0; - return (txr->size + QCAFRM_ETHMAXLEN < QCASPI_HW_BUF_LEN) ? 1 : 0; + return (txr->size + QCAFRM_MAX_LEN < QCASPI_HW_BUF_LEN) ? 1 : 0; } /* Flush the tx ring. This function is only safe to @@ -667,8 +667,8 @@ qcaspi_netdev_xmit(struct sk_buff *skb, struct net_device *dev) struct sk_buff *tskb; u8 pad_len = 0; - if (skb->len < QCAFRM_ETHMINLEN) - pad_len = QCAFRM_ETHMINLEN - skb->len; + if (skb->len < QCAFRM_MIN_LEN) + pad_len = QCAFRM_MIN_LEN - skb->len; if (qca->txr.skb[qca->txr.tail]) { netdev_warn(qca->net_dev, "queue was unexpectedly full!\n"); @@ -805,8 +805,8 @@ qcaspi_netdev_setup(struct net_device *dev) dev->tx_queue_len = 100; /* MTU range: 46 - 1500 */ - dev->min_mtu = QCAFRM_ETHMINMTU; - dev->max_mtu = QCAFRM_ETHMAXMTU; + dev->min_mtu = QCAFRM_MIN_MTU; + dev->max_mtu = QCAFRM_MAX_MTU; qca = netdev_priv(dev); memset(qca, 0, sizeof(struct qcaspi)); -- cgit v1.2.3 From 96a2227c3ff006bf600f1c2ef08f470f3ccae90e Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:15 +0200 Subject: net: qca_spi: remove QCASPI_MTU There is no need for an additional MTU define. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index f15554867ef7..74646286fd0f 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -69,7 +69,6 @@ static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN; module_param(qcaspi_pluggable, int, 0); MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no)."); -#define QCASPI_MTU QCAFRM_MAX_MTU #define QCASPI_TX_TIMEOUT (1 * HZ) #define QCASPI_QCA7K_REBOOT_TIME_MS 1000 @@ -746,7 +745,7 @@ qcaspi_netdev_init(struct net_device *dev) { struct qcaspi *qca = netdev_priv(dev); - dev->mtu = QCASPI_MTU; + dev->mtu = QCAFRM_MAX_MTU; dev->type = ARPHRD_ETHER; qca->clkspeed = qcaspi_clkspeed; qca->burst_len = qcaspi_burst_len; -- cgit v1.2.3 From 55b7a770aef7beeb45e69c4833a22c94a074dcb3 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:16 +0200 Subject: net: qualcomm: move qcaspi_tx_cmd to qca_spi.c The function qcaspi_tx_cmd() is only called from qca_spi.c. So we better move it there. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_7k.c | 24 ------------------------ drivers/net/ethernet/qualcomm/qca_7k.h | 1 - drivers/net/ethernet/qualcomm/qca_spi.c | 24 ++++++++++++++++++++++++ 3 files changed, 24 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c index e9162e1f0c7f..ffe7a16bdfc8 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.c +++ b/drivers/net/ethernet/qualcomm/qca_7k.c @@ -121,27 +121,3 @@ qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value) return ret; } - -int -qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd) -{ - __be16 tx_data; - struct spi_message *msg = &qca->spi_msg1; - struct spi_transfer *transfer = &qca->spi_xfer1; - int ret; - - tx_data = cpu_to_be16(cmd); - transfer->len = sizeof(tx_data); - transfer->tx_buf = &tx_data; - transfer->rx_buf = NULL; - - ret = spi_sync(qca->spi_dev, msg); - - if (!ret) - ret = msg->status; - - if (ret) - qcaspi_spi_error(qca); - - return ret; -} diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h index 4047f0aeb47a..27124c2bb77a 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.h +++ b/drivers/net/ethernet/qualcomm/qca_7k.h @@ -67,6 +67,5 @@ void qcaspi_spi_error(struct qcaspi *qca); int qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result); int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value); -int qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd); #endif /* _QCA_7K_H */ diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 74646286fd0f..50adc4f626e3 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -191,6 +191,30 @@ qcaspi_read_legacy(struct qcaspi *qca, u8 *dst, u32 len) return len; } +static int +qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd) +{ + __be16 tx_data; + struct spi_message *msg = &qca->spi_msg1; + struct spi_transfer *transfer = &qca->spi_xfer1; + int ret; + + tx_data = cpu_to_be16(cmd); + transfer->len = sizeof(tx_data); + transfer->tx_buf = &tx_data; + transfer->rx_buf = NULL; + + ret = spi_sync(qca->spi_dev, msg); + + if (!ret) + ret = msg->status; + + if (ret) + qcaspi_spi_error(qca); + + return ret; +} + static int qcaspi_tx_frame(struct qcaspi *qca, struct sk_buff *skb) { -- cgit v1.2.3 From 0d78d5f73adb1f8a789ceaaa4aca58c52bd1d160 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:17 +0200 Subject: net: qca_spi: Clarify MODULE_DESCRIPTION Since this driver is specific to the QCA7000, we should make the module description more precisely. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 50adc4f626e3..ee90af31bd65 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -999,7 +999,7 @@ static struct spi_driver qca_spi_driver = { }; module_spi_driver(qca_spi_driver); -MODULE_DESCRIPTION("Qualcomm Atheros SPI Driver"); +MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 SPI Driver"); MODULE_AUTHOR("Qualcomm Atheros Communications"); MODULE_AUTHOR("Stefan Wahren "); MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From f1789286e0200f6a40fc20b05ee0e5e62d044a9e Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:18 +0200 Subject: net: qualcomm: rename qca_framing.c to qca_7k_common.c As preparation for the upcoming UART driver we need a module which contains common functions for both interfaces. The module qca_framing is a good candidate but renaming to qca_7k_common would make it clear. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/Makefile | 2 +- drivers/net/ethernet/qualcomm/qca_7k_common.c | 156 ++++++++++++++++++++++++++ drivers/net/ethernet/qualcomm/qca_7k_common.h | 134 ++++++++++++++++++++++ drivers/net/ethernet/qualcomm/qca_framing.c | 156 -------------------------- drivers/net/ethernet/qualcomm/qca_framing.h | 134 ---------------------- drivers/net/ethernet/qualcomm/qca_spi.c | 2 +- drivers/net/ethernet/qualcomm/qca_spi.h | 2 +- 7 files changed, 293 insertions(+), 293 deletions(-) create mode 100644 drivers/net/ethernet/qualcomm/qca_7k_common.c create mode 100644 drivers/net/ethernet/qualcomm/qca_7k_common.h delete mode 100644 drivers/net/ethernet/qualcomm/qca_framing.c delete mode 100644 drivers/net/ethernet/qualcomm/qca_framing.h (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile index aacb0a585c68..5e17bf116e75 100644 --- a/drivers/net/ethernet/qualcomm/Makefile +++ b/drivers/net/ethernet/qualcomm/Makefile @@ -3,6 +3,6 @@ # obj-$(CONFIG_QCA7000) += qcaspi.o -qcaspi-objs := qca_spi.o qca_framing.o qca_7k.o qca_debug.o +qcaspi-objs := qca_spi.o qca_7k_common.o qca_7k.o qca_debug.o obj-y += emac/ diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c new file mode 100644 index 000000000000..6d17fbd47c6a --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2011, 2012, Atheros Communications Inc. + * Copyright (c) 2014, I2SE GmbH + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Atheros ethernet framing. Every Ethernet frame is surrounded + * by an atheros frame while transmitted over a serial channel; + */ + +#include + +#include "qca_7k_common.h" + +u16 +qcafrm_create_header(u8 *buf, u16 length) +{ + __le16 len; + + if (!buf) + return 0; + + len = cpu_to_le16(length); + + buf[0] = 0xAA; + buf[1] = 0xAA; + buf[2] = 0xAA; + buf[3] = 0xAA; + buf[4] = len & 0xff; + buf[5] = (len >> 8) & 0xff; + buf[6] = 0; + buf[7] = 0; + + return QCAFRM_HEADER_LEN; +} + +u16 +qcafrm_create_footer(u8 *buf) +{ + if (!buf) + return 0; + + buf[0] = 0x55; + buf[1] = 0x55; + return QCAFRM_FOOTER_LEN; +} + +/* Gather received bytes and try to extract a full ethernet frame by + * following a simple state machine. + * + * Return: QCAFRM_GATHER No ethernet frame fully received yet. + * QCAFRM_NOHEAD Header expected but not found. + * QCAFRM_INVLEN Atheros frame length is invalid + * QCAFRM_NOTAIL Footer expected but not found. + * > 0 Number of byte in the fully received + * Ethernet frame + */ + +s32 +qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte) +{ + s32 ret = QCAFRM_GATHER; + u16 len; + + switch (handle->state) { + case QCAFRM_HW_LEN0: + case QCAFRM_HW_LEN1: + /* by default, just go to next state */ + handle->state--; + + if (recv_byte != 0x00) { + /* first two bytes of length must be 0 */ + handle->state = QCAFRM_HW_LEN0; + } + break; + case QCAFRM_HW_LEN2: + case QCAFRM_HW_LEN3: + handle->state--; + break; + /* 4 bytes header pattern */ + case QCAFRM_WAIT_AA1: + case QCAFRM_WAIT_AA2: + case QCAFRM_WAIT_AA3: + case QCAFRM_WAIT_AA4: + if (recv_byte != 0xAA) { + ret = QCAFRM_NOHEAD; + handle->state = QCAFRM_HW_LEN0; + } else { + handle->state--; + } + break; + /* 2 bytes length. */ + /* Borrow offset field to hold length for now. */ + case QCAFRM_WAIT_LEN_BYTE0: + handle->offset = recv_byte; + handle->state = QCAFRM_WAIT_LEN_BYTE1; + break; + case QCAFRM_WAIT_LEN_BYTE1: + handle->offset = handle->offset | (recv_byte << 8); + handle->state = QCAFRM_WAIT_RSVD_BYTE1; + break; + case QCAFRM_WAIT_RSVD_BYTE1: + handle->state = QCAFRM_WAIT_RSVD_BYTE2; + break; + case QCAFRM_WAIT_RSVD_BYTE2: + len = handle->offset; + if (len > buf_len || len < QCAFRM_MIN_LEN) { + ret = QCAFRM_INVLEN; + handle->state = QCAFRM_HW_LEN0; + } else { + handle->state = (enum qcafrm_state)(len + 1); + /* Remaining number of bytes. */ + handle->offset = 0; + } + break; + default: + /* Receiving Ethernet frame itself. */ + buf[handle->offset] = recv_byte; + handle->offset++; + handle->state--; + break; + case QCAFRM_WAIT_551: + if (recv_byte != 0x55) { + ret = QCAFRM_NOTAIL; + handle->state = QCAFRM_HW_LEN0; + } else { + handle->state = QCAFRM_WAIT_552; + } + break; + case QCAFRM_WAIT_552: + if (recv_byte != 0x55) { + ret = QCAFRM_NOTAIL; + handle->state = QCAFRM_HW_LEN0; + } else { + ret = handle->offset; + /* Frame is fully received. */ + handle->state = QCAFRM_HW_LEN0; + } + break; + } + + return ret; +} diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h new file mode 100644 index 000000000000..5df7c65d887c --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2011, 2012, Atheros Communications Inc. + * Copyright (c) 2014, I2SE GmbH + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Atheros Ethernet framing. Every Ethernet frame is surrounded by an atheros + * frame while transmitted over a serial channel. + */ + +#ifndef _QCA_FRAMING_H +#define _QCA_FRAMING_H + +#include +#include +#include + +/* Frame is currently being received */ +#define QCAFRM_GATHER 0 + +/* No header byte while expecting it */ +#define QCAFRM_NOHEAD (QCAFRM_ERR_BASE - 1) + +/* No tailer byte while expecting it */ +#define QCAFRM_NOTAIL (QCAFRM_ERR_BASE - 2) + +/* Frame length is invalid */ +#define QCAFRM_INVLEN (QCAFRM_ERR_BASE - 3) + +/* Frame length is invalid */ +#define QCAFRM_INVFRAME (QCAFRM_ERR_BASE - 4) + +/* Min/Max Ethernet MTU: 46/1500 */ +#define QCAFRM_MIN_MTU (ETH_ZLEN - ETH_HLEN) +#define QCAFRM_MAX_MTU ETH_DATA_LEN + +/* Min/Max frame lengths */ +#define QCAFRM_MIN_LEN (QCAFRM_MIN_MTU + ETH_HLEN) +#define QCAFRM_MAX_LEN (QCAFRM_MAX_MTU + VLAN_ETH_HLEN) + +/* QCA7K header len */ +#define QCAFRM_HEADER_LEN 8 + +/* QCA7K footer len */ +#define QCAFRM_FOOTER_LEN 2 + +/* QCA7K Framing. */ +#define QCAFRM_ERR_BASE -1000 + +enum qcafrm_state { + QCAFRM_HW_LEN0 = 0x8000, + QCAFRM_HW_LEN1 = QCAFRM_HW_LEN0 - 1, + QCAFRM_HW_LEN2 = QCAFRM_HW_LEN1 - 1, + QCAFRM_HW_LEN3 = QCAFRM_HW_LEN2 - 1, + + /* Waiting first 0xAA of header */ + QCAFRM_WAIT_AA1 = QCAFRM_HW_LEN3 - 1, + + /* Waiting second 0xAA of header */ + QCAFRM_WAIT_AA2 = QCAFRM_WAIT_AA1 - 1, + + /* Waiting third 0xAA of header */ + QCAFRM_WAIT_AA3 = QCAFRM_WAIT_AA2 - 1, + + /* Waiting fourth 0xAA of header */ + QCAFRM_WAIT_AA4 = QCAFRM_WAIT_AA3 - 1, + + /* Waiting Byte 0-1 of length (litte endian) */ + QCAFRM_WAIT_LEN_BYTE0 = QCAFRM_WAIT_AA4 - 1, + QCAFRM_WAIT_LEN_BYTE1 = QCAFRM_WAIT_AA4 - 2, + + /* Reserved bytes */ + QCAFRM_WAIT_RSVD_BYTE1 = QCAFRM_WAIT_AA4 - 3, + QCAFRM_WAIT_RSVD_BYTE2 = QCAFRM_WAIT_AA4 - 4, + + /* The frame length is used as the state until + * the end of the Ethernet frame + * Waiting for first 0x55 of footer + */ + QCAFRM_WAIT_551 = 1, + + /* Waiting for second 0x55 of footer */ + QCAFRM_WAIT_552 = QCAFRM_WAIT_551 - 1 +}; + +/* Structure to maintain the frame decoding during reception. */ + +struct qcafrm_handle { + /* Current decoding state */ + enum qcafrm_state state; + + /* Offset in buffer (borrowed for length too) */ + u16 offset; + + /* Frame length as kept by this module */ + u16 len; +}; + +u16 qcafrm_create_header(u8 *buf, u16 len); + +u16 qcafrm_create_footer(u8 *buf); + +static inline void qcafrm_fsm_init(struct qcafrm_handle *handle) +{ + handle->state = QCAFRM_HW_LEN0; +} + +/* Gather received bytes and try to extract a full Ethernet frame + * by following a simple state machine. + * + * Return: QCAFRM_GATHER No Ethernet frame fully received yet. + * QCAFRM_NOHEAD Header expected but not found. + * QCAFRM_INVLEN QCA7K frame length is invalid + * QCAFRM_NOTAIL Footer expected but not found. + * > 0 Number of byte in the fully received + * Ethernet frame + */ + +s32 qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte); + +#endif /* _QCA_FRAMING_H */ diff --git a/drivers/net/ethernet/qualcomm/qca_framing.c b/drivers/net/ethernet/qualcomm/qca_framing.c deleted file mode 100644 index 2341f2bf574d..000000000000 --- a/drivers/net/ethernet/qualcomm/qca_framing.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2011, 2012, Atheros Communications Inc. - * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* Atheros ethernet framing. Every Ethernet frame is surrounded - * by an atheros frame while transmitted over a serial channel; - */ - -#include - -#include "qca_framing.h" - -u16 -qcafrm_create_header(u8 *buf, u16 length) -{ - __le16 len; - - if (!buf) - return 0; - - len = cpu_to_le16(length); - - buf[0] = 0xAA; - buf[1] = 0xAA; - buf[2] = 0xAA; - buf[3] = 0xAA; - buf[4] = len & 0xff; - buf[5] = (len >> 8) & 0xff; - buf[6] = 0; - buf[7] = 0; - - return QCAFRM_HEADER_LEN; -} - -u16 -qcafrm_create_footer(u8 *buf) -{ - if (!buf) - return 0; - - buf[0] = 0x55; - buf[1] = 0x55; - return QCAFRM_FOOTER_LEN; -} - -/* Gather received bytes and try to extract a full ethernet frame by - * following a simple state machine. - * - * Return: QCAFRM_GATHER No ethernet frame fully received yet. - * QCAFRM_NOHEAD Header expected but not found. - * QCAFRM_INVLEN Atheros frame length is invalid - * QCAFRM_NOTAIL Footer expected but not found. - * > 0 Number of byte in the fully received - * Ethernet frame - */ - -s32 -qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte) -{ - s32 ret = QCAFRM_GATHER; - u16 len; - - switch (handle->state) { - case QCAFRM_HW_LEN0: - case QCAFRM_HW_LEN1: - /* by default, just go to next state */ - handle->state--; - - if (recv_byte != 0x00) { - /* first two bytes of length must be 0 */ - handle->state = QCAFRM_HW_LEN0; - } - break; - case QCAFRM_HW_LEN2: - case QCAFRM_HW_LEN3: - handle->state--; - break; - /* 4 bytes header pattern */ - case QCAFRM_WAIT_AA1: - case QCAFRM_WAIT_AA2: - case QCAFRM_WAIT_AA3: - case QCAFRM_WAIT_AA4: - if (recv_byte != 0xAA) { - ret = QCAFRM_NOHEAD; - handle->state = QCAFRM_HW_LEN0; - } else { - handle->state--; - } - break; - /* 2 bytes length. */ - /* Borrow offset field to hold length for now. */ - case QCAFRM_WAIT_LEN_BYTE0: - handle->offset = recv_byte; - handle->state = QCAFRM_WAIT_LEN_BYTE1; - break; - case QCAFRM_WAIT_LEN_BYTE1: - handle->offset = handle->offset | (recv_byte << 8); - handle->state = QCAFRM_WAIT_RSVD_BYTE1; - break; - case QCAFRM_WAIT_RSVD_BYTE1: - handle->state = QCAFRM_WAIT_RSVD_BYTE2; - break; - case QCAFRM_WAIT_RSVD_BYTE2: - len = handle->offset; - if (len > buf_len || len < QCAFRM_MIN_LEN) { - ret = QCAFRM_INVLEN; - handle->state = QCAFRM_HW_LEN0; - } else { - handle->state = (enum qcafrm_state)(len + 1); - /* Remaining number of bytes. */ - handle->offset = 0; - } - break; - default: - /* Receiving Ethernet frame itself. */ - buf[handle->offset] = recv_byte; - handle->offset++; - handle->state--; - break; - case QCAFRM_WAIT_551: - if (recv_byte != 0x55) { - ret = QCAFRM_NOTAIL; - handle->state = QCAFRM_HW_LEN0; - } else { - handle->state = QCAFRM_WAIT_552; - } - break; - case QCAFRM_WAIT_552: - if (recv_byte != 0x55) { - ret = QCAFRM_NOTAIL; - handle->state = QCAFRM_HW_LEN0; - } else { - ret = handle->offset; - /* Frame is fully received. */ - handle->state = QCAFRM_HW_LEN0; - } - break; - } - - return ret; -} diff --git a/drivers/net/ethernet/qualcomm/qca_framing.h b/drivers/net/ethernet/qualcomm/qca_framing.h deleted file mode 100644 index 5df7c65d887c..000000000000 --- a/drivers/net/ethernet/qualcomm/qca_framing.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2011, 2012, Atheros Communications Inc. - * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* Atheros Ethernet framing. Every Ethernet frame is surrounded by an atheros - * frame while transmitted over a serial channel. - */ - -#ifndef _QCA_FRAMING_H -#define _QCA_FRAMING_H - -#include -#include -#include - -/* Frame is currently being received */ -#define QCAFRM_GATHER 0 - -/* No header byte while expecting it */ -#define QCAFRM_NOHEAD (QCAFRM_ERR_BASE - 1) - -/* No tailer byte while expecting it */ -#define QCAFRM_NOTAIL (QCAFRM_ERR_BASE - 2) - -/* Frame length is invalid */ -#define QCAFRM_INVLEN (QCAFRM_ERR_BASE - 3) - -/* Frame length is invalid */ -#define QCAFRM_INVFRAME (QCAFRM_ERR_BASE - 4) - -/* Min/Max Ethernet MTU: 46/1500 */ -#define QCAFRM_MIN_MTU (ETH_ZLEN - ETH_HLEN) -#define QCAFRM_MAX_MTU ETH_DATA_LEN - -/* Min/Max frame lengths */ -#define QCAFRM_MIN_LEN (QCAFRM_MIN_MTU + ETH_HLEN) -#define QCAFRM_MAX_LEN (QCAFRM_MAX_MTU + VLAN_ETH_HLEN) - -/* QCA7K header len */ -#define QCAFRM_HEADER_LEN 8 - -/* QCA7K footer len */ -#define QCAFRM_FOOTER_LEN 2 - -/* QCA7K Framing. */ -#define QCAFRM_ERR_BASE -1000 - -enum qcafrm_state { - QCAFRM_HW_LEN0 = 0x8000, - QCAFRM_HW_LEN1 = QCAFRM_HW_LEN0 - 1, - QCAFRM_HW_LEN2 = QCAFRM_HW_LEN1 - 1, - QCAFRM_HW_LEN3 = QCAFRM_HW_LEN2 - 1, - - /* Waiting first 0xAA of header */ - QCAFRM_WAIT_AA1 = QCAFRM_HW_LEN3 - 1, - - /* Waiting second 0xAA of header */ - QCAFRM_WAIT_AA2 = QCAFRM_WAIT_AA1 - 1, - - /* Waiting third 0xAA of header */ - QCAFRM_WAIT_AA3 = QCAFRM_WAIT_AA2 - 1, - - /* Waiting fourth 0xAA of header */ - QCAFRM_WAIT_AA4 = QCAFRM_WAIT_AA3 - 1, - - /* Waiting Byte 0-1 of length (litte endian) */ - QCAFRM_WAIT_LEN_BYTE0 = QCAFRM_WAIT_AA4 - 1, - QCAFRM_WAIT_LEN_BYTE1 = QCAFRM_WAIT_AA4 - 2, - - /* Reserved bytes */ - QCAFRM_WAIT_RSVD_BYTE1 = QCAFRM_WAIT_AA4 - 3, - QCAFRM_WAIT_RSVD_BYTE2 = QCAFRM_WAIT_AA4 - 4, - - /* The frame length is used as the state until - * the end of the Ethernet frame - * Waiting for first 0x55 of footer - */ - QCAFRM_WAIT_551 = 1, - - /* Waiting for second 0x55 of footer */ - QCAFRM_WAIT_552 = QCAFRM_WAIT_551 - 1 -}; - -/* Structure to maintain the frame decoding during reception. */ - -struct qcafrm_handle { - /* Current decoding state */ - enum qcafrm_state state; - - /* Offset in buffer (borrowed for length too) */ - u16 offset; - - /* Frame length as kept by this module */ - u16 len; -}; - -u16 qcafrm_create_header(u8 *buf, u16 len); - -u16 qcafrm_create_footer(u8 *buf); - -static inline void qcafrm_fsm_init(struct qcafrm_handle *handle) -{ - handle->state = QCAFRM_HW_LEN0; -} - -/* Gather received bytes and try to extract a full Ethernet frame - * by following a simple state machine. - * - * Return: QCAFRM_GATHER No Ethernet frame fully received yet. - * QCAFRM_NOHEAD Header expected but not found. - * QCAFRM_INVLEN QCA7K frame length is invalid - * QCAFRM_NOTAIL Footer expected but not found. - * > 0 Number of byte in the fully received - * Ethernet frame - */ - -s32 qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte); - -#endif /* _QCA_FRAMING_H */ diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index ee90af31bd65..43cc7de0b395 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -43,8 +43,8 @@ #include #include "qca_7k.h" +#include "qca_7k_common.h" #include "qca_debug.h" -#include "qca_framing.h" #include "qca_spi.h" #define MAX_DMA_BURST_LEN 5000 diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index 064853ddd678..fc4beb1b32d1 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -32,7 +32,7 @@ #include #include -#include "qca_framing.h" +#include "qca_7k_common.h" #define QCASPI_DRV_VERSION "0.2.7-i" #define QCASPI_DRV_NAME "qcaspi" -- cgit v1.2.3 From 60d6702464b9d667312035eb3bd9d390af9626dd Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:19 +0200 Subject: net: qualcomm: prepare frame decoding for UART driver Unfortunately the frame format is not exactly identical between SPI and UART. In case of SPI there is an additional HW length at the beginning. So store the initial state to make the decoding state machine more flexible and easy to extend for UART support. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/qca_7k_common.c | 12 ++++++------ drivers/net/ethernet/qualcomm/qca_7k_common.h | 8 ++++++-- drivers/net/ethernet/qualcomm/qca_spi.c | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c index 6d17fbd47c6a..0d3daa95cc70 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.c +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c @@ -83,7 +83,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by if (recv_byte != 0x00) { /* first two bytes of length must be 0 */ - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } break; case QCAFRM_HW_LEN2: @@ -97,7 +97,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by case QCAFRM_WAIT_AA4: if (recv_byte != 0xAA) { ret = QCAFRM_NOHEAD; - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } else { handle->state--; } @@ -119,7 +119,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by len = handle->offset; if (len > buf_len || len < QCAFRM_MIN_LEN) { ret = QCAFRM_INVLEN; - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } else { handle->state = (enum qcafrm_state)(len + 1); /* Remaining number of bytes. */ @@ -135,7 +135,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by case QCAFRM_WAIT_551: if (recv_byte != 0x55) { ret = QCAFRM_NOTAIL; - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } else { handle->state = QCAFRM_WAIT_552; } @@ -143,11 +143,11 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by case QCAFRM_WAIT_552: if (recv_byte != 0x55) { ret = QCAFRM_NOTAIL; - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } else { ret = handle->offset; /* Frame is fully received. */ - handle->state = QCAFRM_HW_LEN0; + handle->state = handle->init; } break; } diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h index 5df7c65d887c..07bdd6c4f728 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.h +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h @@ -61,6 +61,7 @@ #define QCAFRM_ERR_BASE -1000 enum qcafrm_state { + /* HW length is only available on SPI */ QCAFRM_HW_LEN0 = 0x8000, QCAFRM_HW_LEN1 = QCAFRM_HW_LEN0 - 1, QCAFRM_HW_LEN2 = QCAFRM_HW_LEN1 - 1, @@ -101,6 +102,8 @@ enum qcafrm_state { struct qcafrm_handle { /* Current decoding state */ enum qcafrm_state state; + /* Initial state depends on connection type */ + enum qcafrm_state init; /* Offset in buffer (borrowed for length too) */ u16 offset; @@ -113,9 +116,10 @@ u16 qcafrm_create_header(u8 *buf, u16 len); u16 qcafrm_create_footer(u8 *buf); -static inline void qcafrm_fsm_init(struct qcafrm_handle *handle) +static inline void qcafrm_fsm_init_spi(struct qcafrm_handle *handle) { - handle->state = QCAFRM_HW_LEN0; + handle->init = QCAFRM_HW_LEN0; + handle->state = handle->init; } /* Gather received bytes and try to extract a full Ethernet frame diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 43cc7de0b395..de78f60309a0 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -638,7 +638,7 @@ qcaspi_netdev_open(struct net_device *dev) qca->intr_req = 1; qca->intr_svc = 0; qca->sync = QCASPI_SYNC_UNKNOWN; - qcafrm_fsm_init(&qca->frm_handle); + qcafrm_fsm_init_spi(&qca->frm_handle); qca->spi_thread = kthread_run((void *)qcaspi_spi_thread, qca, "%s", dev->name); -- cgit v1.2.3 From b2f98200c73cf4bd7c26438490b5a137210e9c7d Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:20 +0200 Subject: net: qualcomm: make qca_7k_common a separate kernel module In order to share common functions between QCA7000 SPI and UART protocol driver the qca_7k_common needs to be a separate kernel module. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/Kconfig | 8 +++++++- drivers/net/ethernet/qualcomm/Makefile | 5 +++-- drivers/net/ethernet/qualcomm/qca_7k_common.c | 10 ++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig index d7720bf92d49..b4c369dccde7 100644 --- a/drivers/net/ethernet/qualcomm/Kconfig +++ b/drivers/net/ethernet/qualcomm/Kconfig @@ -16,7 +16,13 @@ config NET_VENDOR_QUALCOMM if NET_VENDOR_QUALCOMM config QCA7000 - tristate "Qualcomm Atheros QCA7000 support" + tristate + help + This enables support for the Qualcomm Atheros QCA7000. + +config QCA7000_SPI + tristate "Qualcomm Atheros QCA7000 SPI support" + select QCA7000 depends on SPI_MASTER && OF ---help--- This SPI protocol driver supports the Qualcomm Atheros QCA7000. diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile index 5e17bf116e75..65556ca185a6 100644 --- a/drivers/net/ethernet/qualcomm/Makefile +++ b/drivers/net/ethernet/qualcomm/Makefile @@ -2,7 +2,8 @@ # Makefile for the Qualcomm network device drivers. # -obj-$(CONFIG_QCA7000) += qcaspi.o -qcaspi-objs := qca_spi.o qca_7k_common.o qca_7k.o qca_debug.o +obj-$(CONFIG_QCA7000) += qca_7k_common.o +obj-$(CONFIG_QCA7000_SPI) += qcaspi.o +qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o obj-y += emac/ diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c index 0d3daa95cc70..6b511f05df61 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.c +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c @@ -21,7 +21,9 @@ * by an atheros frame while transmitted over a serial channel; */ +#include #include +#include #include "qca_7k_common.h" @@ -46,6 +48,7 @@ qcafrm_create_header(u8 *buf, u16 length) return QCAFRM_HEADER_LEN; } +EXPORT_SYMBOL_GPL(qcafrm_create_header); u16 qcafrm_create_footer(u8 *buf) @@ -57,6 +60,7 @@ qcafrm_create_footer(u8 *buf) buf[1] = 0x55; return QCAFRM_FOOTER_LEN; } +EXPORT_SYMBOL_GPL(qcafrm_create_footer); /* Gather received bytes and try to extract a full ethernet frame by * following a simple state machine. @@ -154,3 +158,9 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by return ret; } +EXPORT_SYMBOL_GPL(qcafrm_fsm_decode); + +MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 common"); +MODULE_AUTHOR("Qualcomm Atheros Communications"); +MODULE_AUTHOR("Stefan Wahren "); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From dfc768fbe618d97d0dde88c8e8e586201b0a7587 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 29 May 2017 13:57:25 +0200 Subject: net: qualcomm: add QCA7000 UART driver This patch adds the Ethernet over UART driver for the Qualcomm QCA7000 HomePlug GreenPHY. Signed-off-by: Stefan Wahren Reviewed-by: Lino Sanfilippo Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/Kconfig | 16 + drivers/net/ethernet/qualcomm/Makefile | 2 + drivers/net/ethernet/qualcomm/qca_7k_common.h | 6 + drivers/net/ethernet/qualcomm/qca_uart.c | 423 ++++++++++++++++++++++++++ 4 files changed, 447 insertions(+) create mode 100644 drivers/net/ethernet/qualcomm/qca_uart.c (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig index b4c369dccde7..877675a27b9f 100644 --- a/drivers/net/ethernet/qualcomm/Kconfig +++ b/drivers/net/ethernet/qualcomm/Kconfig @@ -30,6 +30,22 @@ config QCA7000_SPI To compile this driver as a module, choose M here. The module will be called qcaspi. +config QCA7000_UART + tristate "Qualcomm Atheros QCA7000 UART support" + select QCA7000 + depends on SERIAL_DEV_BUS && OF + ---help--- + This UART protocol driver supports the Qualcomm Atheros QCA7000. + + Currently the driver assumes these device UART settings: + Data bits: 8 + Parity: None + Stop bits: 1 + Flow control: None + + To compile this driver as a module, choose M here. The module + will be called qcauart. + config QCOM_EMAC tristate "Qualcomm Technologies, Inc. EMAC Gigabit Ethernet support" depends on HAS_DMA && HAS_IOMEM diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile index 65556ca185a6..92fa7c4da90a 100644 --- a/drivers/net/ethernet/qualcomm/Makefile +++ b/drivers/net/ethernet/qualcomm/Makefile @@ -5,5 +5,7 @@ obj-$(CONFIG_QCA7000) += qca_7k_common.o obj-$(CONFIG_QCA7000_SPI) += qcaspi.o qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o +obj-$(CONFIG_QCA7000_UART) += qcauart.o +qcauart-objs := qca_uart.o obj-y += emac/ diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h index 07bdd6c4f728..928554f11e35 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.h +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h @@ -122,6 +122,12 @@ static inline void qcafrm_fsm_init_spi(struct qcafrm_handle *handle) handle->state = handle->init; } +static inline void qcafrm_fsm_init_uart(struct qcafrm_handle *handle) +{ + handle->init = QCAFRM_WAIT_AA1; + handle->state = handle->init; +} + /* Gather received bytes and try to extract a full Ethernet frame * by following a simple state machine. * diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c new file mode 100644 index 000000000000..db6068cd7a1f --- /dev/null +++ b/drivers/net/ethernet/qualcomm/qca_uart.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. + * Copyright (c) 2017, I2SE GmbH + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* This module implements the Qualcomm Atheros UART protocol for + * kernel-based UART device; it is essentially an Ethernet-to-UART + * serial converter; + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qca_7k_common.h" + +#define QCAUART_DRV_VERSION "0.1.0" +#define QCAUART_DRV_NAME "qcauart" +#define QCAUART_TX_TIMEOUT (1 * HZ) + +struct qcauart { + struct net_device *net_dev; + spinlock_t lock; /* transmit lock */ + struct work_struct tx_work; /* Flushes transmit buffer */ + + struct serdev_device *serdev; + struct qcafrm_handle frm_handle; + struct sk_buff *rx_skb; + + unsigned char *tx_head; /* pointer to next XMIT byte */ + int tx_left; /* bytes left in XMIT queue */ + unsigned char *tx_buffer; +}; + +static int +qca_tty_receive(struct serdev_device *serdev, const unsigned char *data, + size_t count) +{ + struct qcauart *qca = serdev_device_get_drvdata(serdev); + struct net_device *netdev = qca->net_dev; + struct net_device_stats *n_stats = &netdev->stats; + size_t i; + + if (!qca->rx_skb) { + qca->rx_skb = netdev_alloc_skb_ip_align(netdev, + netdev->mtu + + VLAN_ETH_HLEN); + if (!qca->rx_skb) { + n_stats->rx_errors++; + n_stats->rx_dropped++; + return 0; + } + } + + for (i = 0; i < count; i++) { + s32 retcode; + + retcode = qcafrm_fsm_decode(&qca->frm_handle, + qca->rx_skb->data, + skb_tailroom(qca->rx_skb), + data[i]); + + switch (retcode) { + case QCAFRM_GATHER: + case QCAFRM_NOHEAD: + break; + case QCAFRM_NOTAIL: + netdev_dbg(netdev, "recv: no RX tail\n"); + n_stats->rx_errors++; + n_stats->rx_dropped++; + break; + case QCAFRM_INVLEN: + netdev_dbg(netdev, "recv: invalid RX length\n"); + n_stats->rx_errors++; + n_stats->rx_dropped++; + break; + default: + n_stats->rx_packets++; + n_stats->rx_bytes += retcode; + skb_put(qca->rx_skb, retcode); + qca->rx_skb->protocol = eth_type_trans( + qca->rx_skb, qca->rx_skb->dev); + qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY; + netif_rx_ni(qca->rx_skb); + qca->rx_skb = netdev_alloc_skb_ip_align(netdev, + netdev->mtu + + VLAN_ETH_HLEN); + if (!qca->rx_skb) { + netdev_dbg(netdev, "recv: out of RX resources\n"); + n_stats->rx_errors++; + return i; + } + } + } + + return i; +} + +/* Write out any remaining transmit buffer. Scheduled when tty is writable */ +static void qcauart_transmit(struct work_struct *work) +{ + struct qcauart *qca = container_of(work, struct qcauart, tx_work); + struct net_device_stats *n_stats = &qca->net_dev->stats; + int written; + + spin_lock_bh(&qca->lock); + + /* First make sure we're connected. */ + if (!netif_running(qca->net_dev)) { + spin_unlock_bh(&qca->lock); + return; + } + + if (qca->tx_left <= 0) { + /* Now serial buffer is almost free & we can start + * transmission of another packet + */ + n_stats->tx_packets++; + spin_unlock_bh(&qca->lock); + netif_wake_queue(qca->net_dev); + return; + } + + written = serdev_device_write_buf(qca->serdev, qca->tx_head, + qca->tx_left); + if (written > 0) { + qca->tx_left -= written; + qca->tx_head += written; + } + spin_unlock_bh(&qca->lock); +} + +/* Called by the driver when there's room for more data. + * Schedule the transmit. + */ +static void qca_tty_wakeup(struct serdev_device *serdev) +{ + struct qcauart *qca = serdev_device_get_drvdata(serdev); + + schedule_work(&qca->tx_work); +} + +static struct serdev_device_ops qca_serdev_ops = { + .receive_buf = qca_tty_receive, + .write_wakeup = qca_tty_wakeup, +}; + +static int qcauart_netdev_open(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + + netif_start_queue(qca->net_dev); + + return 0; +} + +static int qcauart_netdev_close(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + + netif_stop_queue(dev); + flush_work(&qca->tx_work); + + spin_lock_bh(&qca->lock); + qca->tx_left = 0; + spin_unlock_bh(&qca->lock); + + return 0; +} + +static netdev_tx_t +qcauart_netdev_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device_stats *n_stats = &dev->stats; + struct qcauart *qca = netdev_priv(dev); + u8 pad_len = 0; + int written; + u8 *pos; + + spin_lock(&qca->lock); + + WARN_ON(qca->tx_left); + + if (!netif_running(dev)) { + spin_unlock(&qca->lock); + netdev_warn(qca->net_dev, "xmit: iface is down\n"); + goto out; + } + + pos = qca->tx_buffer; + + if (skb->len < QCAFRM_MIN_LEN) + pad_len = QCAFRM_MIN_LEN - skb->len; + + pos += qcafrm_create_header(pos, skb->len + pad_len); + + memcpy(pos, skb->data, skb->len); + pos += skb->len; + + if (pad_len) { + memset(pos, 0, pad_len); + pos += pad_len; + } + + pos += qcafrm_create_footer(pos); + + netif_stop_queue(qca->net_dev); + + written = serdev_device_write_buf(qca->serdev, qca->tx_buffer, + pos - qca->tx_buffer); + if (written > 0) { + qca->tx_left = (pos - qca->tx_buffer) - written; + qca->tx_head = qca->tx_buffer + written; + n_stats->tx_bytes += written; + } + spin_unlock(&qca->lock); + + netif_trans_update(dev); +out: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +static void qcauart_netdev_tx_timeout(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + + netdev_info(qca->net_dev, "Transmit timeout at %ld, latency %ld\n", + jiffies, dev_trans_start(dev)); + dev->stats.tx_errors++; + dev->stats.tx_dropped++; +} + +static int qcauart_netdev_init(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + size_t len; + + /* Finish setting up the device info. */ + dev->mtu = QCAFRM_MAX_MTU; + dev->type = ARPHRD_ETHER; + + len = QCAFRM_HEADER_LEN + QCAFRM_MAX_LEN + QCAFRM_FOOTER_LEN; + qca->tx_buffer = devm_kmalloc(&qca->serdev->dev, len, GFP_KERNEL); + if (!qca->tx_buffer) + return -ENOMEM; + + qca->rx_skb = netdev_alloc_skb_ip_align(qca->net_dev, + qca->net_dev->mtu + + VLAN_ETH_HLEN); + if (!qca->rx_skb) + return -ENOBUFS; + + return 0; +} + +static void qcauart_netdev_uninit(struct net_device *dev) +{ + struct qcauart *qca = netdev_priv(dev); + + if (qca->rx_skb) + dev_kfree_skb(qca->rx_skb); +} + +static const struct net_device_ops qcauart_netdev_ops = { + .ndo_init = qcauart_netdev_init, + .ndo_uninit = qcauart_netdev_uninit, + .ndo_open = qcauart_netdev_open, + .ndo_stop = qcauart_netdev_close, + .ndo_start_xmit = qcauart_netdev_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_tx_timeout = qcauart_netdev_tx_timeout, + .ndo_validate_addr = eth_validate_addr, +}; + +static void qcauart_netdev_setup(struct net_device *dev) +{ + dev->netdev_ops = &qcauart_netdev_ops; + dev->watchdog_timeo = QCAUART_TX_TIMEOUT; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->tx_queue_len = 100; + + /* MTU range: 46 - 1500 */ + dev->min_mtu = QCAFRM_MIN_MTU; + dev->max_mtu = QCAFRM_MAX_MTU; +} + +static const struct of_device_id qca_uart_of_match[] = { + { + .compatible = "qca,qca7000", + }, + {} +}; +MODULE_DEVICE_TABLE(of, qca_uart_of_match); + +static int qca_uart_probe(struct serdev_device *serdev) +{ + struct net_device *qcauart_dev = alloc_etherdev(sizeof(struct qcauart)); + struct qcauart *qca; + const char *mac; + u32 speed = 115200; + int ret; + + if (!qcauart_dev) + return -ENOMEM; + + qcauart_netdev_setup(qcauart_dev); + SET_NETDEV_DEV(qcauart_dev, &serdev->dev); + + qca = netdev_priv(qcauart_dev); + if (!qca) { + pr_err("qca_uart: Fail to retrieve private structure\n"); + ret = -ENOMEM; + goto free; + } + qca->net_dev = qcauart_dev; + qca->serdev = serdev; + qcafrm_fsm_init_uart(&qca->frm_handle); + + spin_lock_init(&qca->lock); + INIT_WORK(&qca->tx_work, qcauart_transmit); + + of_property_read_u32(serdev->dev.of_node, "current-speed", &speed); + + mac = of_get_mac_address(serdev->dev.of_node); + + if (mac) + ether_addr_copy(qca->net_dev->dev_addr, mac); + + if (!is_valid_ether_addr(qca->net_dev->dev_addr)) { + eth_hw_addr_random(qca->net_dev); + dev_info(&serdev->dev, "Using random MAC address: %pM\n", + qca->net_dev->dev_addr); + } + + netif_carrier_on(qca->net_dev); + serdev_device_set_drvdata(serdev, qca); + serdev_device_set_client_ops(serdev, &qca_serdev_ops); + + ret = serdev_device_open(serdev); + if (ret) { + dev_err(&serdev->dev, "Unable to open device %s\n", + qcauart_dev->name); + goto free; + } + + speed = serdev_device_set_baudrate(serdev, speed); + dev_info(&serdev->dev, "Using baudrate: %u\n", speed); + + serdev_device_set_flow_control(serdev, false); + + ret = register_netdev(qcauart_dev); + if (ret) { + dev_err(&serdev->dev, "Unable to register net device %s\n", + qcauart_dev->name); + serdev_device_close(serdev); + cancel_work_sync(&qca->tx_work); + goto free; + } + + return 0; + +free: + free_netdev(qcauart_dev); + return ret; +} + +static void qca_uart_remove(struct serdev_device *serdev) +{ + struct qcauart *qca = serdev_device_get_drvdata(serdev); + + unregister_netdev(qca->net_dev); + + /* Flush any pending characters in the driver. */ + serdev_device_close(serdev); + cancel_work_sync(&qca->tx_work); + + free_netdev(qca->net_dev); +} + +static struct serdev_device_driver qca_uart_driver = { + .probe = qca_uart_probe, + .remove = qca_uart_remove, + .driver = { + .name = QCAUART_DRV_NAME, + .of_match_table = of_match_ptr(qca_uart_of_match), + }, +}; + +module_serdev_device_driver(qca_uart_driver); + +MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 UART Driver"); +MODULE_AUTHOR("Qualcomm Atheros Communications"); +MODULE_AUTHOR("Stefan Wahren "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(QCAUART_DRV_VERSION); -- cgit v1.2.3 From b1a73af910e4e77c2eef9953f673d4c74ba07ad7 Mon Sep 17 00:00:00 2001 From: Surendra Mobiya Date: Tue, 30 May 2017 11:32:06 +0530 Subject: cxgb4: keep carrier off before registering netdev Mark carrier off before registering netdev to ensure that vlan device picks up the correct state of the carrier Signed-off-by: Surendra Mobiya Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 2ae54d54aea8..06c3414c93b1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4956,6 +4956,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets); netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets); + netif_carrier_off(adapter->port[i]); + err = register_netdev(adapter->port[i]); if (err) break; -- cgit v1.2.3 From 12eb070babbcab4b003e060933971089864a6a54 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Tue, 30 May 2017 11:50:40 +0530 Subject: cxgb4: add new T5 pci device id Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index 9232becc965d..be7041f6cf71 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -173,6 +173,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x509f), /* Custom T540-CR */ CH_PCI_ID_TABLE_FENTRY(0x50a0), /* Custom T540-CR */ CH_PCI_ID_TABLE_FENTRY(0x50a1), /* Custom T540-CR */ + CH_PCI_ID_TABLE_FENTRY(0x50a2), /* Custom T540-KR4 */ /* T6 adapters: */ -- cgit v1.2.3 From 26747211486c5bc7dd014c3caab206576e00c0d0 Mon Sep 17 00:00:00 2001 From: Arjun Vynipadath Date: Tue, 30 May 2017 18:06:06 +0530 Subject: cxgb4: FW upgrade fixes Disable FW_OK flag while flashing Firmware. This will help to fix any potential mailbox timeouts during Firmware flash. Grab new devlog parameters after Firmware restart. When we FLASH new Firmware onto an adapter, the new Firmware may have the Firmware Device Log located at a different memory address or have a different size for it. Signed-off-by: Arjun Vynipadath Signed-off-by: Casey Leedom Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index b97ce4a15ae0..9160c882fbfc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -6288,13 +6288,18 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, if (!t4_fw_matches_chip(adap, fw_hdr)) return -EINVAL; + /* Disable FW_OK flag so that mbox commands with FW_OK flag set + * wont be sent when we are flashing FW. + */ + adap->flags &= ~FW_OK; + ret = t4_fw_halt(adap, mbox, force); if (ret < 0 && !force) - return ret; + goto out; ret = t4_load_fw(adap, fw_data, size); if (ret < 0) - return ret; + goto out; /* * Older versions of the firmware don't understand the new @@ -6305,7 +6310,17 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, * its header flags to see if it advertises the capability. */ reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); - return t4_fw_restart(adap, mbox, reset); + ret = t4_fw_restart(adap, mbox, reset); + + /* Grab potentially new Firmware Device Log parameters so we can see + * how healthy the new Firmware is. It's okay to contact the new + * Firmware for these parameters even though, as far as it's + * concerned, we've never said "HELLO" to it ... + */ + (void)t4_init_devlog_params(adap); +out: + adap->flags |= FW_OK; + return ret; } /** -- cgit v1.2.3 From 90592b9a35836bacd34d92a3aba7958756b6a7c0 Mon Sep 17 00:00:00 2001 From: Arjun Vynipadath Date: Tue, 30 May 2017 13:30:24 +0530 Subject: cxgb4: Fix netdev_features flag GRO is not supported by Chelsio HW when rx_csum is disabled. Update the netdev features flag when rx_csum is modified. Signed-off-by: Arjun Vynipadath Signed-off-by: Steve Wise Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 06c3414c93b1..8c69046be025 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2727,6 +2727,16 @@ static int cxgb_setup_tc(struct net_device *dev, u32 handle, __be16 proto, return -EOPNOTSUPP; } +static netdev_features_t cxgb_fix_features(struct net_device *dev, + netdev_features_t features) +{ + /* Disable GRO, if RX_CSUM is disabled */ + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_GRO; + + return features; +} + static const struct net_device_ops cxgb4_netdev_ops = { .ndo_open = cxgb_open, .ndo_stop = cxgb_close, @@ -2748,6 +2758,7 @@ static const struct net_device_ops cxgb4_netdev_ops = { #endif /* CONFIG_CHELSIO_T4_FCOE */ .ndo_set_tx_maxrate = cxgb_set_tx_maxrate, .ndo_setup_tc = cxgb_setup_tc, + .ndo_fix_features = cxgb_fix_features, }; #ifdef CONFIG_PCI_IOV -- cgit v1.2.3 From e6cbef0ced13a3ef9a49d895c635b4e0ed4e47a0 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 26 May 2017 18:07:37 -0400 Subject: net: dsa: b53: remove unused dev argument The port net device passed to b53_fdb_copy is not used. Remove it. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index fa099ed41652..6a5648a9cb09 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1281,8 +1281,7 @@ static void b53_arl_search_rd(struct b53_device *dev, u8 idx, b53_arl_to_entry(ent, mac_vid, fwd_entry); } -static int b53_fdb_copy(struct net_device *dev, int port, - const struct b53_arl_entry *ent, +static int b53_fdb_copy(int port, const struct b53_arl_entry *ent, struct switchdev_obj_port_fdb *fdb, switchdev_obj_dump_cb_t *cb) { @@ -1304,7 +1303,6 @@ int b53_fdb_dump(struct dsa_switch *ds, int port, switchdev_obj_dump_cb_t *cb) { struct b53_device *priv = ds->priv; - struct net_device *dev = ds->ports[port].netdev; struct b53_arl_entry results[2]; unsigned int count = 0; int ret; @@ -1320,13 +1318,13 @@ int b53_fdb_dump(struct dsa_switch *ds, int port, return ret; b53_arl_search_rd(priv, 0, &results[0]); - ret = b53_fdb_copy(dev, port, &results[0], fdb, cb); + ret = b53_fdb_copy(port, &results[0], fdb, cb); if (ret) return ret; if (priv->num_arl_entries > 2) { b53_arl_search_rd(priv, 1, &results[1]); - ret = b53_fdb_copy(dev, port, &results[1], fdb, cb); + ret = b53_fdb_copy(port, &results[1], fdb, cb); if (ret) return ret; -- cgit v1.2.3 From e605db801bdeb9d94cccbd4a2f641030067ef008 Mon Sep 17 00:00:00 2001 From: Deepak Khungar Date: Mon, 29 May 2017 19:06:04 -0400 Subject: bnxt_en: Support for Short Firmware Message The new short message format is used on the new BCM57454 VFs. Each firmware message is a fixed 16-byte message sent using the standard firmware communication channel. The short message has a DMA address pointing to the legacy long firmware message. Signed-off-by: Deepak Khungar Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 66 ++++++++++++++++++++++++++++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 ++ 2 files changed, 69 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 69b6829ef1d0..47bc4f3e5808 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2868,6 +2868,32 @@ static int bnxt_alloc_hwrm_resources(struct bnxt *bp) return 0; } +static void bnxt_free_hwrm_short_cmd_req(struct bnxt *bp) +{ + if (bp->hwrm_short_cmd_req_addr) { + struct pci_dev *pdev = bp->pdev; + + dma_free_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN, + bp->hwrm_short_cmd_req_addr, + bp->hwrm_short_cmd_req_dma_addr); + bp->hwrm_short_cmd_req_addr = NULL; + } +} + +static int bnxt_alloc_hwrm_short_cmd_req(struct bnxt *bp) +{ + struct pci_dev *pdev = bp->pdev; + + bp->hwrm_short_cmd_req_addr = + dma_alloc_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN, + &bp->hwrm_short_cmd_req_dma_addr, + GFP_KERNEL); + if (!bp->hwrm_short_cmd_req_addr) + return -ENOMEM; + + return 0; +} + static void bnxt_free_stats(struct bnxt *bp) { u32 size, i; @@ -3215,16 +3241,41 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len, __le32 *resp_len, *valid; u16 cp_ring_id, len = 0; struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr; + u16 max_req_len = BNXT_HWRM_MAX_REQ_LEN; req->seq_id = cpu_to_le16(bp->hwrm_cmd_seq++); memset(resp, 0, PAGE_SIZE); cp_ring_id = le16_to_cpu(req->cmpl_ring); intr_process = (cp_ring_id == INVALID_HW_RING_ID) ? 0 : 1; + if (bp->flags & BNXT_FLAG_SHORT_CMD) { + void *short_cmd_req = bp->hwrm_short_cmd_req_addr; + struct hwrm_short_input short_input = {0}; + + memcpy(short_cmd_req, req, msg_len); + memset(short_cmd_req + msg_len, 0, BNXT_HWRM_MAX_REQ_LEN - + msg_len); + + short_input.req_type = req->req_type; + short_input.signature = + cpu_to_le16(SHORT_REQ_SIGNATURE_SHORT_CMD); + short_input.size = cpu_to_le16(msg_len); + short_input.req_addr = + cpu_to_le64(bp->hwrm_short_cmd_req_dma_addr); + + data = (u32 *)&short_input; + msg_len = sizeof(short_input); + + /* Sync memory write before updating doorbell */ + wmb(); + + max_req_len = BNXT_HWRM_SHORT_REQ_LEN; + } + /* Write request msg to hwrm channel */ __iowrite32_copy(bp->bar0, data, msg_len / 4); - for (i = msg_len; i < BNXT_HWRM_MAX_REQ_LEN; i += 4) + for (i = msg_len; i < max_req_len; i += 4) writel(0, bp->bar0 + i); /* currently supports only one outstanding message */ @@ -4662,6 +4713,7 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp) int rc; struct hwrm_ver_get_input req = {0}; struct hwrm_ver_get_output *resp = bp->hwrm_cmd_resp_addr; + u32 dev_caps_cfg; bp->hwrm_max_req_len = HWRM_MAX_REQ_LEN; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VER_GET, -1, -1); @@ -4699,6 +4751,11 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp) !resp->chip_metal) bp->flags |= BNXT_FLAG_CHIP_NITRO_A0; + dev_caps_cfg = le32_to_cpu(resp->dev_caps_cfg); + if ((dev_caps_cfg & VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED) && + (dev_caps_cfg & VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_REQUIRED)) + bp->flags |= BNXT_FLAG_SHORT_CMD; + hwrm_ver_get_exit: mutex_unlock(&bp->hwrm_cmd_lock); return rc; @@ -7357,6 +7414,7 @@ static void bnxt_remove_one(struct pci_dev *pdev) bnxt_clear_int_mode(bp); bnxt_hwrm_func_drv_unrgtr(bp); bnxt_free_hwrm_resources(bp); + bnxt_free_hwrm_short_cmd_req(bp); bnxt_ethtool_free(bp); bnxt_dcb_free(bp); kfree(bp->edev); @@ -7607,6 +7665,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto init_err_pci_clean; + if (bp->flags & BNXT_FLAG_SHORT_CMD) { + rc = bnxt_alloc_hwrm_short_cmd_req(bp); + if (rc) + goto init_err_pci_clean; + } + rc = bnxt_hwrm_func_reset(bp); if (rc) goto init_err_pci_clean; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 3ef42dbc6327..cb566783dadb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -500,6 +500,7 @@ struct rx_tpa_end_cmp_ext { #define NEXT_CMP(idx) RING_CMP(ADV_RAW_CMP(idx, 1)) #define BNXT_HWRM_MAX_REQ_LEN (bp->hwrm_max_req_len) +#define BNXT_HWRM_SHORT_REQ_LEN sizeof(struct hwrm_short_input) #define DFLT_HWRM_CMD_TIMEOUT 500 #define HWRM_CMD_TIMEOUT (bp->hwrm_cmd_timeout) #define HWRM_RESET_TIMEOUT ((HWRM_CMD_TIMEOUT) * 4) @@ -1006,6 +1007,7 @@ struct bnxt { #define BNXT_FLAG_RX_PAGE_MODE 0x40000 #define BNXT_FLAG_FW_LLDP_AGENT 0x80000 #define BNXT_FLAG_MULTI_HOST 0x100000 + #define BNXT_FLAG_SHORT_CMD 0x200000 #define BNXT_FLAG_CHIP_NITRO_A0 0x1000000 #define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA | \ @@ -1106,6 +1108,8 @@ struct bnxt { u32 hwrm_spec_code; u16 hwrm_cmd_seq; u32 hwrm_intr_seq_id; + void *hwrm_short_cmd_req_addr; + dma_addr_t hwrm_short_cmd_req_dma_addr; void *hwrm_cmd_resp_addr; dma_addr_t hwrm_cmd_resp_dma_addr; void *hwrm_dbg_resp_addr; -- cgit v1.2.3 From c7ef35eb0c8d0b58d2d5ae5be599e6aa730361b2 Mon Sep 17 00:00:00 2001 From: Deepak Khungar Date: Mon, 29 May 2017 19:06:05 -0400 Subject: bnxt_en: Add PCI IDs for BCM57454 VF devices. Signed-off-by: Deepak Khungar Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 47bc4f3e5808..dc10a9a2af1b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -175,6 +175,8 @@ static const struct pci_device_id bnxt_pci_tbl[] = { { PCI_VDEVICE(BROADCOM, 0x16f1), .driver_data = BCM57452 }, { PCI_VDEVICE(BROADCOM, 0x1614), .driver_data = BCM57454 }, #ifdef CONFIG_BNXT_SRIOV + { PCI_VDEVICE(BROADCOM, 0x1606), .driver_data = NETXTREME_E_VF }, + { PCI_VDEVICE(BROADCOM, 0x1609), .driver_data = NETXTREME_E_VF }, { PCI_VDEVICE(BROADCOM, 0x16c1), .driver_data = NETXTREME_E_VF }, { PCI_VDEVICE(BROADCOM, 0x16cb), .driver_data = NETXTREME_C_VF }, { PCI_VDEVICE(BROADCOM, 0x16d3), .driver_data = NETXTREME_E_VF }, -- cgit v1.2.3 From 0efd2fc65c922dff207ff10a776a7a33e0e3c7c5 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 29 May 2017 19:06:06 -0400 Subject: bnxt_en: Add a callback to inform RDMA driver during PCI shutdown. When bnxt_en gets a PCI shutdown call, we need to have a new callback to inform the RDMA driver to do proper shutdown and removal. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 19 +++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h | 2 ++ 3 files changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index dc10a9a2af1b..63d23b657d28 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7837,6 +7837,7 @@ static void bnxt_shutdown(struct pci_dev *pdev) dev_close(dev); if (system_state == SYSTEM_POWER_OFF) { + bnxt_ulp_shutdown(bp); bnxt_clear_int_mode(bp); pci_wake_from_d3(pdev, bp->wol); pci_set_power_state(pdev, PCI_D3hot); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index 8b7464b76501..77da75a55c02 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -266,6 +266,25 @@ void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs) } } +void bnxt_ulp_shutdown(struct bnxt *bp) +{ + struct bnxt_en_dev *edev = bp->edev; + struct bnxt_ulp_ops *ops; + int i; + + if (!edev) + return; + + for (i = 0; i < BNXT_MAX_ULP; i++) { + struct bnxt_ulp *ulp = &edev->ulp_tbl[i]; + + ops = rtnl_dereference(ulp->ulp_ops); + if (!ops || !ops->ulp_shutdown) + continue; + ops->ulp_shutdown(ulp->handle); + } +} + void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl) { u16 event_id = le16_to_cpu(cmpl->event_id); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h index 74f816e46a33..d2471067dc37 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h @@ -26,6 +26,7 @@ struct bnxt_ulp_ops { void (*ulp_stop)(void *); void (*ulp_start)(void *); void (*ulp_sriov_config)(void *, int); + void (*ulp_shutdown)(void *); }; struct bnxt_msix_entry { @@ -87,6 +88,7 @@ void bnxt_subtract_ulp_resources(struct bnxt *bp, int ulp_id); void bnxt_ulp_stop(struct bnxt *bp); void bnxt_ulp_start(struct bnxt *bp); void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs); +void bnxt_ulp_shutdown(struct bnxt *bp); void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl); struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev); -- cgit v1.2.3 From 3284f9e1ab505b41fa604c81e4b3271c6b88cdcb Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 29 May 2017 19:06:07 -0400 Subject: bnxt_en: Add additional chip ID definitions. Add additional chip definitions and macros for all supported chips. Add a new macro BNXT_CHIP_P4_PLUS for the newer generation of chips and use the macro to properly determine the features supported by these newer chips. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 ++---- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 29 +++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 63d23b657d28..427db49b8161 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7712,7 +7712,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) init_waitqueue_head(&bp->sriov_cfg_wait); #endif bp->gro_func = bnxt_gro_func_5730x; - if (BNXT_CHIP_NUM_57X1X(bp->chip_num)) + if (BNXT_CHIP_P4_PLUS(bp)) bp->gro_func = bnxt_gro_func_5731x; rc = bnxt_hwrm_func_drv_rgtr(bp); @@ -7763,9 +7763,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 | VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 | VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6; - if (!BNXT_CHIP_NUM_57X0X(bp->chip_num) && - !BNXT_CHIP_TYPE_NITRO_A0(bp) && - bp->hwrm_spec_code >= 0x10501) { + if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) { bp->flags |= BNXT_FLAG_UDP_RSS_CAP; bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 | VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index cb566783dadb..c59b2cdbce2c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -938,31 +938,45 @@ struct bnxt { #define CHIP_NUM_57402 0x16d0 #define CHIP_NUM_57404 0x16d1 #define CHIP_NUM_57406 0x16d2 +#define CHIP_NUM_57407 0x16d5 #define CHIP_NUM_57311 0x16ce #define CHIP_NUM_57312 0x16cf #define CHIP_NUM_57314 0x16df +#define CHIP_NUM_57317 0x16e0 #define CHIP_NUM_57412 0x16d6 #define CHIP_NUM_57414 0x16d7 #define CHIP_NUM_57416 0x16d8 #define CHIP_NUM_57417 0x16d9 +#define CHIP_NUM_57412L 0x16da +#define CHIP_NUM_57414L 0x16db + +#define CHIP_NUM_5745X 0xd730 #define BNXT_CHIP_NUM_5730X(chip_num) \ ((chip_num) >= CHIP_NUM_57301 && \ (chip_num) <= CHIP_NUM_57304) #define BNXT_CHIP_NUM_5740X(chip_num) \ - ((chip_num) >= CHIP_NUM_57402 && \ - (chip_num) <= CHIP_NUM_57406) + (((chip_num) >= CHIP_NUM_57402 && \ + (chip_num) <= CHIP_NUM_57406) || \ + (chip_num) == CHIP_NUM_57407) #define BNXT_CHIP_NUM_5731X(chip_num) \ ((chip_num) == CHIP_NUM_57311 || \ (chip_num) == CHIP_NUM_57312 || \ - (chip_num) == CHIP_NUM_57314) + (chip_num) == CHIP_NUM_57314 || \ + (chip_num) == CHIP_NUM_57317) #define BNXT_CHIP_NUM_5741X(chip_num) \ ((chip_num) >= CHIP_NUM_57412 && \ - (chip_num) <= CHIP_NUM_57417) + (chip_num) <= CHIP_NUM_57414L) + +#define BNXT_CHIP_NUM_58700(chip_num) \ + ((chip_num) == CHIP_NUM_58700) + +#define BNXT_CHIP_NUM_5745X(chip_num) \ + ((chip_num) == CHIP_NUM_5745X) #define BNXT_CHIP_NUM_57X0X(chip_num) \ (BNXT_CHIP_NUM_5730X(chip_num) || BNXT_CHIP_NUM_5740X(chip_num)) @@ -1022,6 +1036,13 @@ struct bnxt { #define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0) #define BNXT_RX_PAGE_MODE(bp) ((bp)->flags & BNXT_FLAG_RX_PAGE_MODE) +/* Chip class phase 4 and later */ +#define BNXT_CHIP_P4_PLUS(bp) \ + (BNXT_CHIP_NUM_57X1X((bp)->chip_num) || \ + BNXT_CHIP_NUM_5745X((bp)->chip_num) || \ + (BNXT_CHIP_NUM_58700((bp)->chip_num) && \ + !BNXT_CHIP_TYPE_NITRO_A0(bp))) + struct bnxt_en_dev *edev; struct bnxt_en_dev * (*ulp_probe)(struct net_device *); -- cgit v1.2.3 From 434c975a8fe2f70b70ac09ea5ddd008e0528adfa Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 29 May 2017 19:06:08 -0400 Subject: bnxt_en: Optimize doorbell write operations for newer chips. Older chips require the doorbells to be written twice, but newer chips do not. Add a new common function bnxt_db_write() to write all doorbells appropriately depending on the chip. Eliminating the extra doorbell on newer chips has a significant performance improvement on pktgen. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 30 +++++++++-------------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 9 +++++++ drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 3 +-- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 2 +- 4 files changed, 23 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 427db49b8161..d7c1295c16cf 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -463,8 +463,7 @@ normal_tx: prod = NEXT_TX(prod); txr->tx_prod = prod; - writel(DB_KEY_TX | prod, txr->tx_doorbell); - writel(DB_KEY_TX | prod, txr->tx_doorbell); + bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod); tx_done: @@ -1779,8 +1778,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) /* Sync BD data before updating doorbell */ wmb(); - writel(DB_KEY_TX | prod, db); - writel(DB_KEY_TX | prod, db); + bnxt_db_write(bp, db, DB_KEY_TX | prod); } cpr->cp_raw_cons = raw_cons; @@ -1796,14 +1794,10 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) if (event & BNXT_RX_EVENT) { struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; - writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell); - writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell); - if (event & BNXT_AGG_EVENT) { - writel(DB_KEY_RX | rxr->rx_agg_prod, - rxr->rx_agg_doorbell); - writel(DB_KEY_RX | rxr->rx_agg_prod, - rxr->rx_agg_doorbell); - } + bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod); + if (event & BNXT_AGG_EVENT) + bnxt_db_write(bp, rxr->rx_agg_doorbell, + DB_KEY_RX | rxr->rx_agg_prod); } return rx_pkts; } @@ -1863,13 +1857,11 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget) cpr->cp_raw_cons = raw_cons; BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons); - writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell); - writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell); + bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod); - if (event & BNXT_AGG_EVENT) { - writel(DB_KEY_RX | rxr->rx_agg_prod, rxr->rx_agg_doorbell); - writel(DB_KEY_RX | rxr->rx_agg_prod, rxr->rx_agg_doorbell); - } + if (event & BNXT_AGG_EVENT) + bnxt_db_write(bp, rxr->rx_agg_doorbell, + DB_KEY_RX | rxr->rx_agg_prod); if (!bnxt_has_work(bp, cpr) && rx_pkts < budget) { napi_complete_done(napi, rx_pkts); @@ -7714,6 +7706,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bp->gro_func = bnxt_gro_func_5730x; if (BNXT_CHIP_P4_PLUS(bp)) bp->gro_func = bnxt_gro_func_5731x; + else + bp->flags |= BNXT_FLAG_DOUBLE_DB; rc = bnxt_hwrm_func_drv_rgtr(bp); if (rc) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index c59b2cdbce2c..5984423499e6 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1022,6 +1022,7 @@ struct bnxt { #define BNXT_FLAG_FW_LLDP_AGENT 0x80000 #define BNXT_FLAG_MULTI_HOST 0x100000 #define BNXT_FLAG_SHORT_CMD 0x200000 + #define BNXT_FLAG_DOUBLE_DB 0x400000 #define BNXT_FLAG_CHIP_NITRO_A0 0x1000000 #define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA | \ @@ -1254,6 +1255,14 @@ static inline u32 bnxt_tx_avail(struct bnxt *bp, struct bnxt_tx_ring_info *txr) ((txr->tx_prod - txr->tx_cons) & bp->tx_ring_mask); } +/* For TX and RX ring doorbells */ +static inline void bnxt_db_write(struct bnxt *bp, void __iomem *db, u32 val) +{ + writel(val, db); + if (bp->flags & BNXT_FLAG_DOUBLE_DB) + writel(val, db); +} + extern const u16 bnxt_lhint_arr[]; int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 11ddf0adc6e1..fd1181510b65 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2376,8 +2376,7 @@ static int bnxt_run_loopback(struct bnxt *bp) /* Sync BD data before updating doorbell */ wmb(); - writel(DB_KEY_TX | txr->tx_prod, txr->tx_doorbell); - writel(DB_KEY_TX | txr->tx_prod, txr->tx_doorbell); + bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | txr->tx_prod); rc = bnxt_poll_loopback(bp, pkt_size); dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 9dae32756767..8ce793a0d030 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -63,7 +63,7 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts) tx_buf = &txr->tx_buf_ring[last_tx_cons]; rx_prod = tx_buf->rx_prod; } - writel(DB_KEY_RX | rx_prod, rxr->rx_doorbell); + bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rx_prod); } /* returns the following: -- cgit v1.2.3 From 4d172f21cefe896df8477940269b8d52129f8c87 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 29 May 2017 19:06:09 -0400 Subject: bnxt_en: Implement xmit_more. Do not write the TX doorbell if skb->xmit_more is set unless the TX queue is full. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d7c1295c16cf..2c6af316d2de 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -463,13 +463,17 @@ normal_tx: prod = NEXT_TX(prod); txr->tx_prod = prod; - bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod); + if (!skb->xmit_more) + bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod); tx_done: mmiowb(); if (unlikely(bnxt_tx_avail(bp, txr) <= MAX_SKB_FRAGS + 1)) { + if (skb->xmit_more && !tx_buf->is_push) + bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod); + netif_tx_stop_queue(txq); /* netif_tx_stop_queue() must be done before checking -- cgit v1.2.3 From 702c221ca64060b81af4461553be19cba275da8b Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 29 May 2017 19:06:10 -0400 Subject: bnxt_en: Pass in sh parameter to bnxt_set_dflt_rings(). In the existing code, the local variable sh is hardcoded to true to calculate default rings for shared ring configuration. It is better to have the caller determine the value of sh. Reported-by: Gustavo A. R. Silva Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 2c6af316d2de..954758f9a177 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7567,10 +7567,9 @@ static int bnxt_get_dflt_rings(struct bnxt *bp, int *max_rx, int *max_tx, return rc; } -static int bnxt_set_dflt_rings(struct bnxt *bp) +static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh) { int dflt_rings, max_rx_rings, max_tx_rings, rc; - bool sh = true; if (sh) bp->flags |= BNXT_FLAG_SHARED_RINGS; @@ -7749,7 +7748,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bnxt_set_tpa_flags(bp); bnxt_set_ring_params(bp); bnxt_set_max_func_irqs(bp, max_irqs); - rc = bnxt_set_dflt_rings(bp); + rc = bnxt_set_dflt_rings(bp, true); if (rc) { netdev_err(bp->dev, "Not enough rings available.\n"); rc = -ENOMEM; -- cgit v1.2.3 From ffe406457753a7ca2061ecc8c4d3971623066911 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 30 May 2017 20:03:00 -0400 Subject: bnxt_en: Fix xmit_more with BQL. We need to write the doorbell if BQL has stopped the queue and skb->xmit_more is set. Otherwise it is possible for the tx queue to rot and cause tx timeout. Fixes: 4d172f21cefe ("bnxt_en: Implement xmit_more.") Suggested-by: Yuval Mintz Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 954758f9a177..c1cd72a5eccf 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -463,7 +463,7 @@ normal_tx: prod = NEXT_TX(prod); txr->tx_prod = prod; - if (!skb->xmit_more) + if (!skb->xmit_more || netif_xmit_stopped(txq)) bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod); tx_done: -- cgit v1.2.3 From eb873fe4d31b92c455659bf2c54b203d5d46b9a1 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 28 Apr 2017 16:53:15 -0700 Subject: i40evf: fix duplicate lines This removes two duplicate lines that snuck into the code somehow. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index deb2cb8dac6b..3cdac246d357 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -152,8 +152,6 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) { u32 caps; - adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES; - adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ | I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | -- cgit v1.2.3 From 155b0f690051345deefc653774b739c786067d61 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 28 Apr 2017 16:53:16 -0700 Subject: i40evf: fix merge error in older patch This patch fixes a missing line that was missed while merging, which results in a driver feature in the VF not working to enable RSS as a negotiated feature. Fixes: 43a3d9ba34c9c ("i40evf: Allow PF driver to configure RSS") Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 3cdac246d357..91b21f26f8d4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -153,6 +153,7 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) u32 caps; caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF | I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ | I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | I40E_VIRTCHNL_VF_OFFLOAD_VLAN | -- cgit v1.2.3 From 9d68322e53e683e332c032def9854501f9cbf4e8 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 28 Apr 2017 16:53:17 -0700 Subject: i40evf: disable unused flags The i40evf hardware doesn't have any way to ever report FCoE enabled so just force the code to always report FCoE is disabled, remove the unused defines, and mark the OP as reserved. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40e_common.c | 3 +-- drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 43f10761f4ba..6729624fda5b 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -1105,8 +1105,7 @@ void i40e_vf_parse_hw_config(struct i40e_hw *hw, hw->dev_caps.num_msix_vectors_vf = msg->max_vectors; hw->dev_caps.dcb = msg->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_L2; - hw->dev_caps.fcoe = (msg->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_FCOE) ? 1 : 0; + hw->dev_caps.fcoe = 0; for (i = 0; i < msg->num_vsis; i++) { if (vsi_res->vsi_type == I40E_VSI_SRIOV) { ether_addr_copy(hw->mac.perm_addr, diff --git a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h index c5ad0388c3d5..b0b8de5d6f57 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h @@ -79,7 +79,7 @@ enum i40e_virtchnl_ops { I40E_VIRTCHNL_OP_DEL_VLAN = 13, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE = 14, I40E_VIRTCHNL_OP_GET_STATS = 15, - I40E_VIRTCHNL_OP_FCOE = 16, + I40E_VIRTCHNL_OP_RSVD = 16, I40E_VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */ I40E_VIRTCHNL_OP_IWARP = 20, I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21, @@ -155,7 +155,6 @@ struct i40e_virtchnl_vsi_resource { /* VF offload flags */ #define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 #define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002 -#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 #define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 #define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 #define I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR 0x00000020 -- cgit v1.2.3 From bbc4e7d273b594debbcccdf588085b3521365c50 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:51 -0700 Subject: i40e: fix race condition with PTP_TX_IN_PROGRESS bits Hardware related to the i40e driver has a limitation on Tx PTP packets. This requires us to limit the driver to timestamping a single packet at once. This is done using a state bitlock which enforces that only one timestamp request is honored at a time. Unfortunately this suffers from a race condition. The bit lock is not cleared until after skb_tstamp_tx() is called notifying applications of a new Tx timestamp. Even a well behaved application sending only one packet at a time and waiting for a response can wake up and send a new timestamped packet request before the bit lock is cleared. This results in needlessly dropping some Tx timestamp requests. We can fix this by unlocking the state bit as soon as we read the Timestamp register, as this is the first point at which it is safe to timestamp another packet. To avoid issues with the skb pointer, we'll use a copy of the pointer and set the global variable in the driver structure to NULL first. This ensures that the next timestamp request does not modify our local copy of the skb pointer. Now, a well behaved application which has at most one outstanding timestamp request will not accidentally race with the driver unlock bit. Obviously an application attempting to timestamp faster than one request at a time will have some timestamp requests skipped. Unfortunately there is nothing we can do about that. Reported-by: David Mirabito Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 0efff18ee336..aead71a92a60 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -338,6 +338,7 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi) void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) { struct skb_shared_hwtstamps shhwtstamps; + struct sk_buff *skb = pf->ptp_tx_skb; struct i40e_hw *hw = &pf->hw; u32 hi, lo; u64 ns; @@ -353,12 +354,19 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) hi = rd32(hw, I40E_PRTTSYN_TXTIME_H); ns = (((u64)hi) << 32) | lo; - i40e_ptp_convert_to_hwtstamp(&shhwtstamps, ns); - skb_tstamp_tx(pf->ptp_tx_skb, &shhwtstamps); - dev_kfree_skb_any(pf->ptp_tx_skb); + + /* Clear the bit lock as soon as possible after reading the register, + * and prior to notifying the stack via skb_tstamp_tx(). Otherwise + * applications might wake up and attempt to request another transmit + * timestamp prior to the bit lock being cleared. + */ pf->ptp_tx_skb = NULL; clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state); + + /* Notify the stack and free the skb after we've unlocked */ + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } /** -- cgit v1.2.3 From 69077577af5054da8c8adfb6c1ebb565c2f1f158 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:54 -0700 Subject: i40e: avoid permanent lock of *_PTP_TX_IN_PROGRESS The i40e driver uses a bit lock to indicate when a Tx timestamp is in progress to avoid attempting to timestamp multiple packets at once. This is required because hardware only has registers to handle one request at a time. There is a corner case where we failed to cleanup the bit lock after a failed transmit. This can potentially result in a state bit being locked forever. Add some cleanup code to i40e_xmit_frame_ring to check and make sure we cleanup incase of these failures. We also modify i40e_tx_map to return an error code indication DMA failure. Reported-by: Reported-by: David Mirabito Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 29321a6167a6..19984be0f70c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2932,10 +2932,12 @@ bool __i40e_chk_linearize(struct sk_buff *skb) * @hdr_len: size of the packet header * @td_cmd: the command field in the descriptor * @td_offset: offset for checksum or crc + * + * Returns 0 on success, -1 on failure to DMA **/ -static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, - struct i40e_tx_buffer *first, u32 tx_flags, - const u8 hdr_len, u32 td_cmd, u32 td_offset) +static inline int i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, + struct i40e_tx_buffer *first, u32 tx_flags, + const u8 hdr_len, u32 td_cmd, u32 td_offset) { unsigned int data_len = skb->data_len; unsigned int size = skb_headlen(skb); @@ -3093,7 +3095,7 @@ do_rs: mmiowb(); } - return; + return 0; dma_error: dev_info(tx_ring->dev, "TX DMA map failed\n"); @@ -3110,6 +3112,8 @@ dma_error: } tx_ring->next_to_use = i; + + return -1; } /** @@ -3210,8 +3214,9 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, */ i40e_atr(tx_ring, skb, tx_flags); - i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len, - td_cmd, td_offset); + if (i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len, + td_cmd, td_offset)) + goto cleanup_tx_tstamp; return NETDEV_TX_OK; @@ -3219,6 +3224,15 @@ out_drop: i40e_trace(xmit_frame_ring_drop, first->skb, tx_ring); dev_kfree_skb_any(first->skb); first->skb = NULL; +cleanup_tx_tstamp: + if (unlikely(tx_flags & I40E_TX_FLAGS_TSYN)) { + struct i40e_pf *pf = i40e_netdev_to_pf(tx_ring->netdev); + + dev_kfree_skb_any(pf->ptp_tx_skb); + pf->ptp_tx_skb = NULL; + clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state); + } + return NETDEV_TX_OK; } -- cgit v1.2.3 From 2955faca0403a4f6029d589f60ff44be09f24859 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:58 -0700 Subject: i40e: add statistic indicating number of skipped Tx timestamps The i40e driver can only handle one Tx timestamp request at a time. This means it is possible for an application timestamp request to be ignored. There is no easy way for an administrator to determine if this occurred. Add a new statistic which tracks this, tx_hwtstamp_skipped. Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 1 + drivers/net/ethernet/intel/i40e/i40e_txrx.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index cdde3cc28fb5..aa46ae016539 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -506,6 +506,7 @@ struct i40e_pf { struct mutex tmreg_lock; /* Used to protect the SYSTIME registers. */ u64 ptp_base_adj; u32 tx_hwtstamp_timeouts; + u32 tx_hwtstamp_skipped; u32 rx_hwtstamp_cleared; u32 latch_event_flags; spinlock_t ptp_rx_lock; /* Used to protect Rx timestamp registers. */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 7a8eb486b9ea..35a246f05520 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -147,6 +147,7 @@ static const struct i40e_stats i40e_gstrings_stats[] = { I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests), I40E_PF_STAT("arq_overflows", arq_overflows), I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), + I40E_PF_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt), I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match), I40E_PF_STAT("fdir_atr_tunnel_match", stats.fd_atr_tunnel_match), diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 19984be0f70c..c69ee4b0cfe2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2630,6 +2630,7 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; pf->ptp_tx_skb = skb_get(skb); } else { + pf->tx_hwtstamp_skipped++; return 0; } -- cgit v1.2.3 From 61189556692e8e58c97e764d6b3f24db5cd243de Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:29:01 -0700 Subject: i40e: use pf data structure directly in i40e_ptp_rx_hang There's no reason to pass a *vsi pointer if we already have the *pf pointer in the only location where we call this function. Lets update the signature and directly pass the *pf data structure pointer. Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 2 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index aa46ae016539..f4465afe1fe1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -956,7 +956,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf, struct i40e_dcbx_config *old_cfg, struct i40e_dcbx_config *new_cfg); #endif /* CONFIG_I40E_DCB */ -void i40e_ptp_rx_hang(struct i40e_vsi *vsi); +void i40e_ptp_rx_hang(struct i40e_pf *pf); void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf); void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index); void i40e_ptp_set_increment(struct i40e_pf *pf); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d5c9c9e06ff5..c019dec988e3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6372,7 +6372,7 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) i40e_update_veb_stats(pf->veb[i]); } - i40e_ptp_rx_hang(pf->vsi[pf->lan_vsi]); + i40e_ptp_rx_hang(pf); } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index aead71a92a60..cb81e16d0874 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -269,6 +269,7 @@ static u32 i40e_ptp_get_rx_events(struct i40e_pf *pf) /** * i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung + * @pf: The PF private data structure * @vsi: The VSI with the rings relevant to 1588 * * This watchdog task is scheduled to detect error case where hardware has @@ -276,9 +277,8 @@ static u32 i40e_ptp_get_rx_events(struct i40e_pf *pf) * particular error is rare but leaves the device in a state unable to timestamp * any future packets. **/ -void i40e_ptp_rx_hang(struct i40e_vsi *vsi) +void i40e_ptp_rx_hang(struct i40e_pf *pf) { - struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; unsigned int i, cleared = 0; -- cgit v1.2.3 From 0bc0706b46cd345537f9bd3cdf5d84c33f5484e4 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:29:02 -0700 Subject: i40e: check for Tx timestamp timeouts during watchdog The i40e driver has logic to handle only one Tx timestamp at a time, using a state bit lock to avoid multiple requests at once. It may be possible, if incredibly unlikely, that a Tx timestamp event is requested but never completes. Since we use an interrupt scheme to determine when the Tx timestamp occurred we would never clear the state bit in this case. Add an i40e_ptp_tx_hang() function similar to the already existing i40e_ptp_rx_hang() function. This function runs in the watchdog routine and makes sure we eventually recover from this case instead of permanently disabling Tx timestamps. Note: there is no currently known way to cause this without hacking the driver code to force it. Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 2 ++ drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + drivers/net/ethernet/intel/i40e/i40e_ptp.c | 30 +++++++++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_txrx.c | 1 + 4 files changed, 34 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index f4465afe1fe1..25bf336c5f38 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -502,6 +502,7 @@ struct i40e_pf { struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_caps; struct sk_buff *ptp_tx_skb; + unsigned long ptp_tx_start; struct hwtstamp_config tstamp_config; struct mutex tmreg_lock; /* Used to protect the SYSTIME registers. */ u64 ptp_base_adj; @@ -957,6 +958,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf, struct i40e_dcbx_config *new_cfg); #endif /* CONFIG_I40E_DCB */ void i40e_ptp_rx_hang(struct i40e_pf *pf); +void i40e_ptp_tx_hang(struct i40e_pf *pf); void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf); void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index); void i40e_ptp_set_increment(struct i40e_pf *pf); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c019dec988e3..e4eb97832413 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6373,6 +6373,7 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) } i40e_ptp_rx_hang(pf); + i40e_ptp_tx_hang(pf); } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index cb81e16d0874..1a0be835fa06 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -327,6 +327,36 @@ void i40e_ptp_rx_hang(struct i40e_pf *pf) pf->rx_hwtstamp_cleared += cleared; } +/** + * i40e_ptp_tx_hang - Detect error case when Tx timestamp register is hung + * @pf: The PF private data structure + * + * This watchdog task is run periodically to make sure that we clear the Tx + * timestamp logic if we don't obtain a timestamp in a reasonable amount of + * time. It is unexpected in the normal case but if it occurs it results in + * permanently prevent timestamps of future packets + **/ +void i40e_ptp_tx_hang(struct i40e_pf *pf) +{ + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) + return; + + /* Nothing to do if we're not already waiting for a timestamp */ + if (!test_bit(__I40E_PTP_TX_IN_PROGRESS, pf->state)) + return; + + /* We already have a handler routine which is run when we are notified + * of a Tx timestamp in the hardware. If we don't get an interrupt + * within a second it is reasonable to assume that we never will. + */ + if (time_is_before_jiffies(pf->ptp_tx_start + HZ)) { + dev_kfree_skb_any(pf->ptp_tx_skb); + pf->ptp_tx_skb = NULL; + clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state); + pf->tx_hwtstamp_timeouts++; + } +} + /** * i40e_ptp_tx_hwtstamp - Utility function which returns the Tx timestamp * @pf: Board private structure diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index c69ee4b0cfe2..c2e9013d05eb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2628,6 +2628,7 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, if (pf->ptp_tx && !test_and_set_bit_lock(__I40E_PTP_TX_IN_PROGRESS, pf->state)) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + pf->ptp_tx_start = jiffies; pf->ptp_tx_skb = skb_get(skb); } else { pf->tx_hwtstamp_skipped++; -- cgit v1.2.3 From 0a4ecc2c5e0479f269e6ca5f9588b23d649aa948 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Fri, 5 May 2017 21:29:13 +0200 Subject: i40e: Check for memory allocation failure If 'kzalloc' fails, a NULL pointer will be dereferenced. Return -ENOMEM instead. Signed-off-by: Christophe JAILLET Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_client.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_client.c b/drivers/net/ethernet/intel/i40e/i40e_client.c index c3b81a97558e..088b4a43bd2a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_client.c +++ b/drivers/net/ethernet/intel/i40e/i40e_client.c @@ -595,6 +595,8 @@ static int i40e_client_setup_qvlist(struct i40e_info *ldev, size = sizeof(struct i40e_qvlist_info) + (sizeof(struct i40e_qv_info) * (qvlist_info->num_vectors - 1)); ldev->qvlist_info = kzalloc(size, GFP_KERNEL); + if (!ldev->qvlist_info) + return -ENOMEM; ldev->qvlist_info->num_vectors = qvlist_info->num_vectors; for (i = 0; i < qvlist_info->num_vectors; i++) { -- cgit v1.2.3 From 79e68821582d08e369094e7ea45dbfb8fdb37d7e Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Tue, 23 May 2017 18:49:35 +0300 Subject: ath10k: go back to using dma_alloc_coherent() for firmware scratch memory This reverts commit b057886524be ("ath10k: do not use coherent memory for allocated device memory chunks") in 2015 which converted this allocation from dma_map_coherent() to kzalloc() / dma_map_single(). The current problem manifests when using later model NICs with larger (>700KiB) scratch spaces in memory. Although the kzalloc call succeeds, the software IOMMU TLB code (via dma_map_single()) panics because it can't find 700KiB of linear physmem bounce buffers for DMA. Now, this is a bit of a silly failure mode for the dma map API, but it's what we currently have to play with. In these cases, doing kzalloc() works fine, but the dma_map_single() call fails. After chatting with Linus briefly about this, it indeed should be using dma_alloc_coherent() for doing larger device memory allocation that requires some kind of physical address mapping. You're not supposed to be using kzalloc and dma_map_* calls for large memory regions, and I'm guessing not for long-held mappings either. Typically dma mappings should be temporary for DMA, not long held like these. Now, since hopefully the major annoying underlying problem has also been addressed (ie, ath10k is no longer tears down all of these allocations and reallocates them every time the vdevs are brought down) fragmentation should stop being such a touchy issue. If it is though, using dma_alloc_coherent() use gets us access to the CMB APIs too relatively easily and ideally we would be allocating memory early in boot for exactly these reasons. Signed-off-by: Adrian Chadd Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0dbcc79d718e..472b42bff7bf 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4482,31 +4482,17 @@ static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id, u32 num_units, u32 unit_len) { dma_addr_t paddr; - u32 pool_size = 0; + u32 pool_size; int idx = ar->wmi.num_mem_chunks; - void *vaddr = NULL; - - if (ar->wmi.num_mem_chunks == ARRAY_SIZE(ar->wmi.mem_chunks)) - return -ENOMEM; + void *vaddr; - while (!vaddr && num_units) { - pool_size = num_units * round_up(unit_len, 4); - if (!pool_size) - return -EINVAL; + pool_size = num_units * round_up(unit_len, 4); + vaddr = dma_alloc_coherent(ar->dev, pool_size, &paddr, GFP_KERNEL); - vaddr = kzalloc(pool_size, GFP_KERNEL | __GFP_NOWARN); - if (!vaddr) - num_units /= 2; - } - - if (!num_units) + if (!vaddr) return -ENOMEM; - paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_BIDIRECTIONAL); - if (dma_mapping_error(ar->dev, paddr)) { - kfree(vaddr); - return -ENOMEM; - } + memset(vaddr, 0, pool_size); ar->wmi.mem_chunks[idx].vaddr = vaddr; ar->wmi.mem_chunks[idx].paddr = paddr; @@ -8281,11 +8267,10 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar) /* free the host memory chunks requested by firmware */ for (i = 0; i < ar->wmi.num_mem_chunks; i++) { - dma_unmap_single(ar->dev, - ar->wmi.mem_chunks[i].paddr, - ar->wmi.mem_chunks[i].len, - DMA_BIDIRECTIONAL); - kfree(ar->wmi.mem_chunks[i].vaddr); + dma_free_coherent(ar->dev, + ar->wmi.mem_chunks[i].len, + ar->wmi.mem_chunks[i].vaddr, + ar->wmi.mem_chunks[i].paddr); } ar->wmi.num_mem_chunks = 0; -- cgit v1.2.3 From 2a20525b26475528dc5a664478db2fea23c57d42 Mon Sep 17 00:00:00 2001 From: Scott Peterson Date: Fri, 18 Nov 2016 11:25:42 -0800 Subject: ixgbe/ixgbevf: Enables TSO for MPLS encapsulated packets This patch advertises TSO & GSO features in netdev->mpls_features. In ixgbe(vf)_tso() where we set up segmentation offload, the IP header will be the inner network header when eth_p_mpls() indicates the Ethernet protocol is MPLS (UC or MC). Suggested-by: Alexander Duyck Signed-off-by: Scott Peterson Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 12 ++++++++++-- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index d39cba214320..c263e2293661 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "ixgbe.h" #include "ixgbe_common.h" @@ -7667,7 +7668,10 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring, if (err < 0) return err; - ip.hdr = skb_network_header(skb); + if (eth_p_mpls(first->protocol)) + ip.hdr = skb_inner_network_header(skb); + else + ip.hdr = skb_network_header(skb); l4.hdr = skb_checksum_start(skb); /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ @@ -10191,7 +10195,11 @@ skip_sriov: netdev->vlan_features |= netdev->features | NETIF_F_TSO_MANGLEID; netdev->hw_enc_features |= netdev->vlan_features; - netdev->mpls_features |= NETIF_F_HW_CSUM; + netdev->mpls_features |= NETIF_F_SG | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_HW_CSUM; + netdev->mpls_features |= IXGBE_GSO_PARTIAL_FEATURES; /* set this bit last since it cannot be part of vlan_features */ netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index eee29bddddc1..706d868a778d 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "ixgbevf.h" @@ -3321,7 +3322,10 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring, if (err < 0) return err; - ip.hdr = skb_network_header(skb); + if (eth_p_mpls(first->protocol)) + ip.hdr = skb_inner_network_header(skb); + else + ip.hdr = skb_network_header(skb); l4.hdr = skb_checksum_start(skb); /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ @@ -4075,7 +4079,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->features |= NETIF_F_HIGHDMA; netdev->vlan_features |= netdev->features | NETIF_F_TSO_MANGLEID; - netdev->mpls_features |= NETIF_F_HW_CSUM; + netdev->mpls_features |= NETIF_F_SG | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_HW_CSUM; + netdev->mpls_features |= IXGBEVF_GSO_PARTIAL_FEATURES; netdev->hw_enc_features |= netdev->vlan_features; /* set this bit last since it cannot be part of vlan_features */ -- cgit v1.2.3 From b09457e7a1d6e8d311b5342475d267087c4970a6 Mon Sep 17 00:00:00 2001 From: Liwei Song Date: Sun, 4 Dec 2016 22:40:44 -0500 Subject: ixgbe: initialize u64_stats_sync structures early at ixgbe_probe Fix the following CallTrace: INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 71 PID: 1 Comm: swapper/0 Not tainted 4.8.8-WR9.0.0.1_standard #11 Hardware name: Intel Corporation S2600WTT/S2600WTT, BIOS GRNDSDP1.86B.0036.R05.1407140519 07/14/2014 00200086 00200086 eb5e1ab8 c144dd70 00000000 00000000 eb5e1af8 c10af89a c1d23de4 eb5e1af8 00000009 eb5d8600 eb5d8638 eb5e1af8 c10b14d8 00000009 0000000a c1d32911 00000000 00000000 e44c826c eb5d8000 eb5e1b74 c10b214e Call Trace: [] dump_stack+0x5f/0x8f [] register_lock_class+0x25a/0x4c0 [] ? check_irq_usage+0x88/0xc0 [] __lock_acquire+0x5e/0x17a0 [] ? _raw_spin_unlock_irqrestore+0x3b/0x70 [] ? rcu_read_lock_sched_held+0x8a/0x90 [] lock_acquire+0x9f/0x1f0 [] ? dev_get_stats+0x5f/0x110 [] ixgbe_get_stats64+0x113/0x320 [] ? dev_get_stats+0x5f/0x110 [] dev_get_stats+0x5f/0x110 [] rtnl_fill_stats+0x40/0x105 [] rtnl_fill_ifinfo+0x4c5/0xd20 [] ? __kmalloc_node_track_caller+0x1a5/0x410 [] ? __kmalloc_reserve.isra.42+0x27/0x80 [] ? __alloc_skb+0x6f/0x270 [] rtmsg_ifinfo_build_skb+0x71/0xd0 [] rtmsg_ifinfo.part.23+0x1a/0x50 [] ? call_netdevice_notifiers_info+0x2d/0x60 [] rtmsg_ifinfo+0x2b/0x40 [] register_netdevice+0x3d7/0x4d0 [] register_netdev+0x17/0x30 [] ixgbe_probe+0x118d/0x1610 [] local_pci_probe+0x32/0x80 [] ? pci_match_device+0xd2/0x100 [] pci_device_probe+0xc0/0x110 [] driver_probe_device+0x1c5/0x280 [] ? pci_match_device+0xd2/0x100 [] __driver_attach+0x89/0x90 [] ? driver_probe_device+0x280/0x280 [] bus_for_each_dev+0x4f/0x80 [] driver_attach+0x1e/0x20 [] ? driver_probe_device+0x280/0x280 [] bus_add_driver+0x1a7/0x220 [] driver_register+0x59/0xe0 [] ? igb_init_module+0x49/0x49 [] __pci_register_driver+0x4a/0x50 [] ixgbe_init_module+0xa5/0xc4 [] do_one_initcall+0x35/0x150 [] ? parameq+0x18/0x70 [] ? repair_env_string+0x12/0x51 [] ? parse_args+0x260/0x3b0 [] ? __usermodehelper_set_disable_depth+0x43/0x50 [] kernel_init_freeable+0x19b/0x267 [] ? set_debug_rodata+0xf/0xf [] ? trace_hardirqs_on+0xb/0x10 [] ? _raw_spin_unlock_irq+0x32/0x50 [] ? finish_task_switch+0xab/0x1f0 [] ? finish_task_switch+0x69/0x1f0 [] kernel_init+0x10/0x110 [] ? schedule_tail+0x25/0x80 [] ret_from_kernel_thread+0xe/0x24 [] ? rest_init+0x130/0x130 This CallTrace occurred on 32-bit kernel with CONFIG_PROVE_LOCKING enabled. This happens at ixgbe driver probe hardware stage, when comes to ixgbe_get_stats64, the seqcount/seqlock still not initialize, although this was initialize in TX/RX resources setup routin, but it was too late, then lockdep give this Warning. To fix this, move the u64_stats_init function to driver probe stage, which before we get the status of seqcount and after the RX/TX ring was finished init. Signed-off-by: Liwei Song Tested-by: Krishneil Singh --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index c263e2293661..4f9679494b6c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6184,8 +6184,6 @@ int ixgbe_setup_tx_resources(struct ixgbe_ring *tx_ring) if (!tx_ring->tx_buffer_info) goto err; - u64_stats_init(&tx_ring->syncp); - /* round up to nearest 4K */ tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc); tx_ring->size = ALIGN(tx_ring->size, 4096); @@ -6279,8 +6277,6 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, if (!rx_ring->rx_buffer_info) goto err; - u64_stats_init(&rx_ring->syncp); - /* Round up to nearest 4K */ rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc); rx_ring->size = ALIGN(rx_ring->size, 4096); @@ -10283,6 +10279,10 @@ skip_sriov: if (err) goto err_sw_init; + for (i = 0; i < adapter->num_rx_queues; i++) + u64_stats_init(&adapter->rx_ring[i]->syncp); + for (i = 0; i < adapter->num_tx_queues; i++) + u64_stats_init(&adapter->tx_ring[i]->syncp); for (i = 0; i < adapter->num_xdp_queues; i++) u64_stats_init(&adapter->xdp_ring[i]->syncp); -- cgit v1.2.3 From 5e999fb43ebb5a64554890cda57edc1edd68a2ab Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Fri, 21 Apr 2017 05:37:13 -0400 Subject: ixgbe: Remove MAC X550EM_X 1Gbase-t led_[on|off] support Since FW configures the PHY and MAC X550EM_X has no PHY access, led_[on|off] is not supported with the 1Gbase-t design. Removed MAC X550EM_X 1Gbase-t led_[on|off] support by setting function pointers to NULL and added NULL pointer checks. Also set init_led_link_act to NULL and added NULL pointer check. Signed-off-by: Paul Greenwalt Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 3 ++- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 3 +++ drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 25 +++++++++++++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index c38d50c1fcf7..3af6127f0d44 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -395,7 +395,8 @@ s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) } /* Initialize the LED link active for LED blink support */ - hw->mac.ops.init_led_link_act(hw); + if (hw->mac.ops.init_led_link_act) + hw->mac.ops.init_led_link_act(hw); return status; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 7e5e336d7dcc..cced74dd5a63 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2254,6 +2254,9 @@ static int ixgbe_set_phys_id(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + if (!hw->mac.ops.led_on || !hw->mac.ops.led_off) + return -EOPNOTSUPP; + switch (state) { case ETHTOOL_ID_ACTIVE: adapter->led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 2ba024b575ea..50aaa2bd3c81 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -3206,6 +3206,7 @@ static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) phy->ops.setup_link = NULL; phy->ops.read_reg = NULL; phy->ops.write_reg = NULL; + phy->ops.reset = NULL; break; default: break; @@ -3819,6 +3820,28 @@ static const struct ixgbe_mac_operations mac_ops_X550EM_x = { .write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550, }; +static const struct ixgbe_mac_operations mac_ops_X550EM_x_fw = { + X550_COMMON_MAC + .led_on = NULL, + .led_off = NULL, + .init_led_link_act = NULL, + .reset_hw = &ixgbe_reset_hw_X550em, + .get_media_type = &ixgbe_get_media_type_X550em, + .get_san_mac_addr = NULL, + .get_wwn_prefix = NULL, + .setup_link = &ixgbe_setup_mac_link_X540, + .get_link_capabilities = &ixgbe_get_link_capabilities_X550em, + .get_bus_info = &ixgbe_get_bus_info_X550em, + .setup_sfp = ixgbe_setup_sfp_modules_X550em, + .acquire_swfw_sync = &ixgbe_acquire_swfw_sync_X550em, + .release_swfw_sync = &ixgbe_release_swfw_sync_X550em, + .init_swfw_sync = &ixgbe_init_swfw_sync_X540, + .setup_fc = NULL, + .fc_autoneg = ixgbe_fc_autoneg, + .read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550, + .write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550, +}; + static struct ixgbe_mac_operations mac_ops_x550em_a = { X550_COMMON_MAC .led_on = ixgbe_led_on_t_x550em, @@ -3986,7 +4009,7 @@ const struct ixgbe_info ixgbe_X550EM_x_info = { const struct ixgbe_info ixgbe_x550em_x_fw_info = { .mac = ixgbe_mac_X550EM_x, .get_invariants = ixgbe_get_invariants_X550_x_fw, - .mac_ops = &mac_ops_X550EM_x, + .mac_ops = &mac_ops_X550EM_x_fw, .eeprom_ops = &eeprom_ops_X550EM_x, .phy_ops = &phy_ops_x550em_x_fw, .mbx_ops = &mbx_ops_generic, -- cgit v1.2.3 From e6b41c888154b5c529ba4d65b6fc55f2a7ae4d75 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Tue, 25 Apr 2017 11:31:06 -0700 Subject: ixgbe: enable L3/L4 filtering for Tx switched packets This will ensure that VF-to-VF traffic on the same PF is filtered to allow RSS operation. Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 4f9679494b6c..7baca05c4a51 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3803,6 +3803,9 @@ static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter) mrqc = IXGBE_MRQC_VMDQRSS32EN; else mrqc = IXGBE_MRQC_VMDQRSS64EN; + + /* Enable L3/L4 for Tx Switched packets */ + mrqc |= IXGBE_MRQC_L3L4TXSWEN; } else { if (tcs > 4) mrqc = IXGBE_MRQC_RTRSS8TCEN; -- cgit v1.2.3 From 22cb4fff3d9756229f1e67987f4fabb57a8c68ca Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 25 Apr 2017 13:55:25 -0700 Subject: ixgbe: Correct thermal sensor event check The thermal sensor event logic is messed up, because it can execute the code when there is no thermal event. The current logic is that it will exit when !capable && !event whereas it really should exit when !capable || !event. For one thing, it means that the service task is doing too much work. It probably has some other symptoms as well. So, correct the logic, simplifying to only execute when there is a thermal event. The capable check is redundant. Signed-off-by: Mark Rustad Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 7baca05c4a51..5c671b7401cd 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -2639,8 +2639,7 @@ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter) if (test_bit(__IXGBE_DOWN, &adapter->state)) return; - if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && - !(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT)) + if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT)) return; adapter->flags2 &= ~IXGBE_FLAG2_TEMP_SENSOR_EVENT; -- cgit v1.2.3 From 6af3d0faede8b8c2ccd93f31d9f146ffd0b463d6 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Fri, 28 Apr 2017 12:42:03 -0700 Subject: ixgbe: Add error checking to setting VF MAC Currently, when setting a VF MAC address there are no error checks to ensure that the MAC filter was successfully added. This patch adds additional error checks, reporting, and propagation of errors. It also will not set the MAC address unless adding the MAC filter was successful. With these changes, setting the mac address to zeros can no longer call ixgbe_set_vf_mac() as adding a zero MAC address filter is not valid. Instead directly delete the filter and, if successful, clear the MAC address. Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 54 +++++++++++++++++++------- 1 file changed, 41 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 8baf298a8516..13c96a13841e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -778,11 +778,17 @@ static inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, int vf, unsigned char *mac_addr) { + s32 retval; + ixgbe_del_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf); - memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, ETH_ALEN); - ixgbe_add_mac_filter(adapter, adapter->vfinfo[vf].vf_mac_addresses, vf); + retval = ixgbe_add_mac_filter(adapter, mac_addr, vf); + if (retval >= 0) + memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, + ETH_ALEN); + else + memset(adapter->vfinfo[vf].vf_mac_addresses, 0, ETH_ALEN); - return 0; + return retval; } int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask) @@ -1347,27 +1353,49 @@ void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter) int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + s32 retval; if (vf >= adapter->num_vfs) return -EINVAL; - if (is_zero_ether_addr(mac)) { - adapter->vfinfo[vf].pf_set_mac = false; - dev_info(&adapter->pdev->dev, "removing MAC on VF %d\n", vf); - } else if (is_valid_ether_addr(mac)) { - adapter->vfinfo[vf].pf_set_mac = true; + if (is_valid_ether_addr(mac)) { dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf); dev_info(&adapter->pdev->dev, "Reload the VF driver to make this change effective."); - if (test_bit(__IXGBE_DOWN, &adapter->state)) { - dev_warn(&adapter->pdev->dev, "The VF MAC address has been set, but the PF device is not up.\n"); - dev_warn(&adapter->pdev->dev, "Bring the PF device up before attempting to use the VF device.\n"); + + retval = ixgbe_set_vf_mac(adapter, vf, mac); + if (retval >= 0) { + adapter->vfinfo[vf].pf_set_mac = true; + + if (test_bit(__IXGBE_DOWN, &adapter->state)) { + dev_warn(&adapter->pdev->dev, "The VF MAC address has been set, but the PF device is not up.\n"); + dev_warn(&adapter->pdev->dev, "Bring the PF device up before attempting to use the VF device.\n"); + } + } else { + dev_warn(&adapter->pdev->dev, "The VF MAC address was NOT set due to invalid or duplicate MAC address.\n"); + } + } else if (is_zero_ether_addr(mac)) { + unsigned char *vf_mac_addr = + adapter->vfinfo[vf].vf_mac_addresses; + + /* nothing to do */ + if (is_zero_ether_addr(vf_mac_addr)) + return 0; + + dev_info(&adapter->pdev->dev, "removing MAC on VF %d\n", vf); + + retval = ixgbe_del_mac_filter(adapter, vf_mac_addr, vf); + if (retval >= 0) { + adapter->vfinfo[vf].pf_set_mac = false; + memcpy(vf_mac_addr, mac, ETH_ALEN); + } else { + dev_warn(&adapter->pdev->dev, "Could NOT remove the VF MAC address.\n"); } } else { - return -EINVAL; + retval = -EINVAL; } - return ixgbe_set_vf_mac(adapter, vf, mac); + return retval; } static int ixgbe_enable_port_vlan(struct ixgbe_adapter *adapter, int vf, -- cgit v1.2.3 From e61e4c8b905b995a5334acf5fb9c7bcaec7417da Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Fri, 12 May 2017 11:38:07 -0700 Subject: ixgbe: Resolve truncation warning for q_vector->name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following warning is now shown as a result of new checks added for gcc 7: drivers/net/ethernet/intel/ixgbe/ixgbe_main.c: In function ‘ixgbe_open’: drivers/net/ethernet/intel/ixgbe/ixgbe_main.c:3118:13: warning: ‘%d’ directive output may be truncated writing between 1 and 10 bytes into a region of size between 3 and 18 [-Wformat-truncation=] "%s-%s-%d", netdev->name, "TxRx", ri++); ^~ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c:3118:6: note: directive argument in the range [0, 2147483647] "%s-%s-%d", netdev->name, "TxRx", ri++); ^~~~~~~~~~ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c:3117:4: note: ‘snprintf’ output between 8 and 32 bytes into a destination of size 24 snprintf(q_vector->name, sizeof(q_vector->name) - 1, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "%s-%s-%d", netdev->name, "TxRx", ri++); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Resolve this warning by making a couple of changes. - Don't reserve space for the null terminator. Since snprintf adds the null terminator automatically, there is no need for us to reserve a byte for it. - Change a couple variables that can never be negative from int to unsigned int. While we're making changes to the format string, move the constant strings into the format string instead of providing them as specifiers. Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 5c671b7401cd..0d2c54693cf3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3105,23 +3105,23 @@ int ixgbe_poll(struct napi_struct *napi, int budget) static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) { struct net_device *netdev = adapter->netdev; + unsigned int ri = 0, ti = 0; int vector, err; - int ri = 0, ti = 0; for (vector = 0; vector < adapter->num_q_vectors; vector++) { struct ixgbe_q_vector *q_vector = adapter->q_vector[vector]; struct msix_entry *entry = &adapter->msix_entries[vector]; if (q_vector->tx.ring && q_vector->rx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "TxRx", ri++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-TxRx-%u", netdev->name, ri++); ti++; } else if (q_vector->rx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "rx", ri++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-rx-%u", netdev->name, ri++); } else if (q_vector->tx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "tx", ti++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-tx-%u", netdev->name, ti++); } else { /* skip this unused q_vector */ continue; -- cgit v1.2.3 From 93df9465c93e634c49f18271218076ab0b9aaf75 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Wed, 31 May 2017 04:43:47 -0700 Subject: ixgbe: Resolve warnings for -Wimplicit-fallthrough This patch adds/changes fall through comments to address new warnings produced by gcc 7. Fixed formatting on a couple of comments in the function. Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 9 ++++++--- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 4 ++-- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 ++++++-- drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 7 +++---- 5 files changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index c8ac46049f34..d602637ccc40 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -1589,15 +1589,17 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, switch (ntohs(input_mask->formatted.vlan_id) & 0xEFFF) { case 0x0000: - /* mask VLAN ID, fall through to mask VLAN priority */ + /* mask VLAN ID */ fdirm |= IXGBE_FDIRM_VLANID; + /* fall through */ case 0x0FFF: /* mask VLAN priority */ fdirm |= IXGBE_FDIRM_VLANP; break; case 0xE000: - /* mask VLAN ID only, fall through */ + /* mask VLAN ID only */ fdirm |= IXGBE_FDIRM_VLANID; + /* fall through */ case 0xEFFF: /* no VLAN fields masked */ break; @@ -1608,8 +1610,9 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, switch (input_mask->formatted.flex_bytes & 0xFFFF) { case 0x0000: - /* Mask Flex Bytes, fall through */ + /* Mask Flex Bytes */ fdirm |= IXGBE_FDIRM_FLEX; + /* fall through */ case 0xFFFF: break; default: diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 3af6127f0d44..76ad0e0bd542 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -155,7 +155,7 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw) if (ret_val) return ret_val; - /* only backplane uses autoc so fall though */ + /* fall through - only backplane uses autoc */ case ixgbe_media_type_fiber: reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); @@ -3549,7 +3549,7 @@ void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, rxpktsize <<= IXGBE_RXPBSIZE_SHIFT; for (; i < (num_pb / 2); i++) IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); - /* Fall through to configure remaining packet buffers */ + /* fall through - configure remaining packet buffers */ case (PBA_STRATEGY_EQUAL): /* Divide the remaining Rx packet buffer evenly among the TCs */ rxpktsize = (pbsize / (num_pb - i)) << IXGBE_RXPBSIZE_SHIFT; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index cced74dd5a63..9113e8099b03 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2668,6 +2668,7 @@ static int ixgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp, *flow_type = IXGBE_ATR_FLOW_TYPE_IPV4; break; } + /* fall through */ default: return 0; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 0d2c54693cf3..54463f03b3db 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1452,7 +1452,7 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) IXGBE_DCA_CTRL_DCA_MODE_CB2); break; } - /* Fall Through since DCA is disabled. */ + /* fall through - DCA is disabled. */ case DCA_PROVIDER_REMOVE: if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { dca_remove_requester(dev); @@ -2233,6 +2233,7 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter, break; default: bpf_warn_invalid_xdp_action(act); + /* fallthrough */ case XDP_ABORTED: trace_xdp_exception(rx_ring->netdev, xdp_prog, act); /* fallthrough -- handle aborts by dropping packet */ @@ -4177,7 +4178,7 @@ static void ixgbe_setup_rdrxctl(struct ixgbe_adapter *adapter) case ixgbe_mac_x550em_a: if (adapter->num_vfs) rdrxctl |= IXGBE_RDRXCTL_PSP; - /* fall through for older HW */ + /* fall through */ case ixgbe_mac_82599EB: case ixgbe_mac_X540: /* Disable RSC for ACK packets */ @@ -6885,6 +6886,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC); hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC); hwstats->b2ogprc += IXGBE_READ_REG(hw, IXGBE_B2OGPRC); + /* fall through */ case ixgbe_mac_82599EB: for (i = 0; i < 16; i++) adapter->hw_rx_no_dma_resources += @@ -8207,6 +8209,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb, if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) break; + /* fall through */ default: return fallback(dev, skb); } @@ -9931,6 +9934,7 @@ bool ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id, /* only support first port */ if (hw->bus.func != 0) break; + /* fall through */ case IXGBE_SUBDEV_ID_82599_SP_560FLR: case IXGBE_SUBDEV_ID_82599_SFP: case IXGBE_SUBDEV_ID_82599_RNDC: diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 13c96a13841e..e2766da5fe02 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -540,16 +540,15 @@ static s32 ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf, u32 vf) case ixgbe_mbox_api_11: case ixgbe_mbox_api_12: case ixgbe_mbox_api_13: - /* - * Version 1.1 supports jumbo frames on VFs if PF has + /* Version 1.1 supports jumbo frames on VFs if PF has * jumbo frames enabled which means legacy VFs are * disabled */ if (pf_max_frame > ETH_FRAME_LEN) break; + /* fall through */ default: - /* - * If the PF or VF are running w/ jumbo frames enabled + /* If the PF or VF are running w/ jumbo frames enabled * we need to shut down the VF Rx path as we cannot * support jumbo frames on legacy VFs */ -- cgit v1.2.3 From 31f5d9b1e890d52c807093fac7ee7f00eb369897 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Fri, 12 May 2017 11:38:09 -0700 Subject: ixgbevf: Resolve truncation warning for q_vector->name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following warning is now shown as a result of new checks added for gcc 7: drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c: In function ‘ixgbevf_open’: drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c:1363:13: warning: ‘%d’ directive output may be truncated writing between 1 and 10 bytes into a region of size between 3 and 18 [-Wformat-truncation=] "%s-%s-%d", netdev->name, "TxRx", ri++); ^~ drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c:1363:6: note: directive argument in the range [0, 2147483647] "%s-%s-%d", netdev->name, "TxRx", ri++); ^~~~~~~~~~ drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c:1362:4: note: ‘snprintf’ output between 8 and 32 bytes into a destination of size 24 snprintf(q_vector->name, sizeof(q_vector->name) - 1, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "%s-%s-%d", netdev->name, "TxRx", ri++); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Resolve this warning by making a couple of changes. - Don't reserve space for the null terminator. Since snprintf adds the null terminator automatically, there is no need for us to reserve a byte for it. - Change a couple variables that can never be negative from int to unsigned int. While we're making changes to the format string, move the constant strings into the format string instead of providing them as specifiers. Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 706d868a778d..aced91c9c034 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -1351,23 +1351,23 @@ static int ixgbevf_request_msix_irqs(struct ixgbevf_adapter *adapter) { struct net_device *netdev = adapter->netdev; int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; + unsigned int ri = 0, ti = 0; int vector, err; - int ri = 0, ti = 0; for (vector = 0; vector < q_vectors; vector++) { struct ixgbevf_q_vector *q_vector = adapter->q_vector[vector]; struct msix_entry *entry = &adapter->msix_entries[vector]; if (q_vector->tx.ring && q_vector->rx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "TxRx", ri++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-TxRx-%u", netdev->name, ri++); ti++; } else if (q_vector->rx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "rx", ri++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-rx-%u", netdev->name, ri++); } else if (q_vector->tx.ring) { - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-%s-%d", netdev->name, "tx", ti++); + snprintf(q_vector->name, sizeof(q_vector->name), + "%s-tx-%u", netdev->name, ti++); } else { /* skip this unused q_vector */ continue; -- cgit v1.2.3 From 80666035c70bc8def691b4cb98fa39da3d6fdee1 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Fri, 12 May 2017 11:38:10 -0700 Subject: ixgbevf: Resolve warnings for -Wimplicit-fallthrough MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Additions to gcc 7 now warn whenever a switch statement falls through implicitly. This patch adds explicit fall through comments to address the following warnings: drivers/net/ethernet/intel/ixgbevf/vf.c: In function ‘ixgbevf_get_reta_locked’: drivers/net/ethernet/intel/ixgbevf/vf.c:336:6: warning: this statement may fall through [-Wimplicit-fallthrough=] if (hw->mac.type < ixgbe_mac_X550_vf) ^ drivers/net/ethernet/intel/ixgbevf/vf.c:338:2: note: here default: ^~~~~~~ drivers/net/ethernet/intel/ixgbevf/vf.c: In function ‘ixgbevf_get_rss_key_locked’: drivers/net/ethernet/intel/ixgbevf/vf.c:402:6: warning: this statement may fall through [-Wimplicit-fallthrough=] if (hw->mac.type < ixgbe_mac_X550_vf) ^ drivers/net/ethernet/intel/ixgbevf/vf.c:404:2: note: here default: ^~~~~~~ Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/vf.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c index b6d0c01eab10..0c25006ce9af 100644 --- a/drivers/net/ethernet/intel/ixgbevf/vf.c +++ b/drivers/net/ethernet/intel/ixgbevf/vf.c @@ -335,6 +335,7 @@ int ixgbevf_get_reta_locked(struct ixgbe_hw *hw, u32 *reta, int num_rx_queues) case ixgbe_mbox_api_12: if (hw->mac.type < ixgbe_mac_X550_vf) break; + /* fall through */ default: return -EOPNOTSUPP; } @@ -401,6 +402,7 @@ int ixgbevf_get_rss_key_locked(struct ixgbe_hw *hw, u8 *rss_key) case ixgbe_mbox_api_12: if (hw->mac.type < ixgbe_mac_X550_vf) break; + /* fall through */ default: return -EOPNOTSUPP; } -- cgit v1.2.3 From cc1de78c2a3d936d733bc9bd3f6e0655d03c2fb7 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 17 May 2017 15:17:41 -0700 Subject: ixgbe: correct CS4223/7 PHY identification Previous method was unreliable. Use a different register to differentiate between the SKUs. Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h | 5 +++-- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h index 5aa2c3cf7aec..b0cac961df3b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h @@ -84,8 +84,9 @@ #define IXGBE_CS4227_GLOBAL_ID_LSB 0 #define IXGBE_CS4227_GLOBAL_ID_MSB 1 #define IXGBE_CS4227_SCRATCH 2 -#define IXGBE_CS4223_PHY_ID 0x7003 /* Quad port */ -#define IXGBE_CS4227_PHY_ID 0x3003 /* Dual port */ +#define IXGBE_CS4227_EFUSE_PDF_SKU 0x19F +#define IXGBE_CS4223_SKU_ID 0x0010 /* Quad port */ +#define IXGBE_CS4227_SKU_ID 0x0014 /* Dual port */ #define IXGBE_CS4227_RESET_PENDING 0x1357 #define IXGBE_CS4227_RESET_COMPLETE 0x5AA5 #define IXGBE_CS4227_RETRIES 15 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 50aaa2bd3c81..32b35efde2df 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1807,16 +1807,16 @@ ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed, if (hw->phy.mdio.prtad == MDIO_PRTAD_NONE) return IXGBE_ERR_PHY_ADDR_INVALID; - /* Get external PHY device id */ - ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_GLOBAL_ID_MSB, - IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); + /* Get external PHY SKU id */ + ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_EFUSE_PDF_SKU, + IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); if (ret_val) return ret_val; /* When configuring quad port CS4223, the MAC instance is part * of the slice offset. */ - if (reg_phy_ext == IXGBE_CS4223_PHY_ID) + if (reg_phy_ext == IXGBE_CS4223_SKU_ID) slice_offset = (hw->bus.lan_id + (hw->bus.instance_id << 1)) << 12; else -- cgit v1.2.3 From 410a494902777c11f95031d9ed757d7f8f09c5c6 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 17 May 2017 15:17:46 -0700 Subject: ixgbe: add write flush when configuring CS4223/7 Make sure the writes are processed immediately. Without the flush it is possible for operations on one port to spill over the other as the resource is shared. Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 32b35efde2df..80824fec15d2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1824,12 +1824,28 @@ ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed, /* Configure CS4227/CS4223 LINE side to proper mode. */ reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + slice_offset; + + ret_val = hw->phy.ops.read_reg(hw, reg_slice, + IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); + if (ret_val) + return ret_val; + + reg_phy_ext &= ~((IXGBE_CS4227_EDC_MODE_CX1 << 1) | + (IXGBE_CS4227_EDC_MODE_SR << 1)); + if (setup_linear) reg_phy_ext = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 1; else reg_phy_ext = (IXGBE_CS4227_EDC_MODE_SR << 1) | 1; - return hw->phy.ops.write_reg(hw, reg_slice, IXGBE_MDIO_ZERO_DEV_TYPE, - reg_phy_ext); + + ret_val = hw->phy.ops.write_reg(hw, reg_slice, + IXGBE_MDIO_ZERO_DEV_TYPE, reg_phy_ext); + if (ret_val) + return ret_val; + + /* Flush previous write with a read */ + return hw->phy.ops.read_reg(hw, reg_slice, + IXGBE_MDIO_ZERO_DEV_TYPE, ®_phy_ext); } /** -- cgit v1.2.3 From 08ed48e182ef870517a84d2331c4c5da8f1c3b3a Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 17 May 2017 15:17:51 -0700 Subject: ixgbe: always call setup_mac_link for multispeed fiber Remove the logic which would previously skip the link configuration in the case where we are already at the requested speed in ixgbe_setup_mac_link_multispeed_fiber(). By exiting early we are skipping the link configuration and as such the driver may not always configure the PHY correctly for SFP+. Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 76ad0e0bd542..7af85f505bad 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -4121,15 +4121,6 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, speedcnt++; highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL; - /* If we already have link at this speed, just jump out */ - status = hw->mac.ops.check_link(hw, &link_speed, &link_up, - false); - if (status) - return status; - - if (link_speed == IXGBE_LINK_SPEED_10GB_FULL && link_up) - goto out; - /* Set the module link speed */ switch (hw->phy.media_type) { case ixgbe_media_type_fiber: @@ -4181,15 +4172,6 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN) highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL; - /* If we already have link at this speed, just jump out */ - status = hw->mac.ops.check_link(hw, &link_speed, &link_up, - false); - if (status) - return status; - - if (link_speed == IXGBE_LINK_SPEED_1GB_FULL && link_up) - goto out; - /* Set the module link speed */ switch (hw->phy.media_type) { case ixgbe_media_type_fiber: -- cgit v1.2.3 From 3ce5cb75f39378e3b77628352735632ccc98b489 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 17 May 2017 15:17:56 -0700 Subject: ixgbe: add missing configuration for rate select 1 Add RS1 configuration to ixgbe_set_soft_rate_select_speed() Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 7af85f505bad..4e35e7017f3d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -4278,4 +4278,23 @@ void ixgbe_set_soft_rate_select_speed(struct ixgbe_hw *hw, hw_dbg(hw, "Failed to write Rx Rate Select RS0\n"); return; } + + /* Set RS1 */ + status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB, + IXGBE_I2C_EEPROM_DEV_ADDR2, + &eeprom_data); + if (status) { + hw_dbg(hw, "Failed to read Rx Rate Select RS1\n"); + return; + } + + eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) | rs; + + status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB, + IXGBE_I2C_EEPROM_DEV_ADDR2, + eeprom_data); + if (status) { + hw_dbg(hw, "Failed to write Rx Rate Select RS1\n"); + return; + } } -- cgit v1.2.3 From d9c23ff80b9fdc1f2e8efeb5368adfd93493d7b4 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 18 May 2017 16:45:06 -0700 Subject: ixgbe: fix incorrect status check Check for ret_val instead of !ret_val to allow the rest of the code to execute and configure the speed properly. Signed-off-by: Emil Tantilov Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 80824fec15d2..72d84a065e34 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1750,14 +1750,14 @@ ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed, if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT) return 0; - if (!ret_val) + if (ret_val) return ret_val; /* Configure internal PHY for native SFI based on module type */ ret_val = hw->mac.ops.read_iosf_sb_reg(hw, IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, ®_phy_int); - if (!ret_val) + if (ret_val) return ret_val; reg_phy_int &= IXGBE_KRM_PMD_FLX_MASK_ST20_SFI_10G_DA; @@ -1767,7 +1767,7 @@ ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed, ret_val = hw->mac.ops.write_iosf_sb_reg(hw, IXGBE_KRM_PMD_FLX_MASK_ST20(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, reg_phy_int); - if (!ret_val) + if (ret_val) return ret_val; /* Setup SFI internal link. */ @@ -1798,7 +1798,7 @@ ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed, if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT) return 0; - if (!ret_val) + if (ret_val) return ret_val; /* Configure internal PHY for KR/KX. */ -- cgit v1.2.3 From f4c5d5991590c4f640d5de245047444bf11f69d2 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 May 2017 07:12:30 +0000 Subject: mwifiex: use variable interface header length Usb tx aggregation feature will utilize 4-bytes bus interface header, otherwise it will be set to zero in default case. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 2 +- drivers/net/wireless/marvell/mwifiex/cmdevt.c | 8 ++++---- drivers/net/wireless/marvell/mwifiex/init.c | 5 +++++ drivers/net/wireless/marvell/mwifiex/main.h | 1 + drivers/net/wireless/marvell/mwifiex/pcie.c | 19 ++++++++++--------- drivers/net/wireless/marvell/mwifiex/sdio.c | 12 ++++++------ drivers/net/wireless/marvell/mwifiex/sta_tx.c | 12 ++++++------ drivers/net/wireless/marvell/mwifiex/txrx.c | 11 +++-------- drivers/net/wireless/marvell/mwifiex/uap_txrx.c | 5 ++--- 9 files changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c index a75013ac84d7..e8ffb26eb912 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c @@ -164,7 +164,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, int pad = 0, aggr_num = 0, ret; struct mwifiex_tx_param tx_param; struct txpd *ptx_pd = NULL; - int headroom = adapter->iface_type == MWIFIEX_USB ? 0 : INTF_HEADER_LEN; + int headroom = adapter->intf_hdr_len; skb_src = skb_peek(&pra_list->skb_head); if (!skb_src) { diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 95221306a4e5..40c3fe5ab8ca 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -258,10 +258,10 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, if (ret == -EBUSY) cmd_node->cmd_skb = NULL; } else { - skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); + skb_push(cmd_node->cmd_skb, adapter->intf_hdr_len); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, cmd_node->cmd_skb, NULL); - skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); + skb_pull(cmd_node->cmd_skb, adapter->intf_hdr_len); } if (ret == -1) { @@ -351,10 +351,10 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) if (ret != -EBUSY) dev_kfree_skb_any(sleep_cfm_tmp); } else { - skb_push(adapter->sleep_cfm, INTF_HEADER_LEN); + skb_push(adapter->sleep_cfm, adapter->intf_hdr_len); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, adapter->sleep_cfm, NULL); - skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); + skb_pull(adapter->sleep_cfm, adapter->intf_hdr_len); } if (ret == -1) { diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 80bdf1c5f77f..3ecb59f7405b 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -217,6 +217,11 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) else adapter->data_sent = false; + if (adapter->iface_type == MWIFIEX_USB) + adapter->intf_hdr_len = 0; + else + adapter->intf_hdr_len = INTF_HEADER_LEN; + adapter->cmd_resp_received = false; adapter->event_received = false; adapter->data_received = false; diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index c1d96c64af74..a4a014366d79 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -849,6 +849,7 @@ struct mwifiex_adapter { u8 perm_addr[ETH_ALEN]; bool surprise_removed; u32 fw_release_number; + u8 intf_hdr_len; u16 init_wait_q_woken; wait_queue_head_t init_wait_q; void *card; diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 394224d6c219..b53ecf1eddda 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1389,7 +1389,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) * first 2 bytes for len, next 2 bytes is for type */ rx_len = get_unaligned_le16(skb_data->data); - if (WARN_ON(rx_len <= INTF_HEADER_LEN || + if (WARN_ON(rx_len <= adapter->intf_hdr_len || rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) { mwifiex_dbg(adapter, ERROR, "Invalid RX len %d, Rd=%#x, Wr=%#x\n", @@ -1400,7 +1400,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) mwifiex_dbg(adapter, DATA, "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", card->rxbd_rdptr, wrptr, rx_len); - skb_pull(skb_data, INTF_HEADER_LEN); + skb_pull(skb_data, adapter->intf_hdr_len); if (adapter->rx_work_enabled) { skb_queue_tail(&adapter->rx_data_q, skb_data); adapter->data_received = true; @@ -1734,7 +1734,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) MWIFIEX_MAX_DELAY_COUNT); mwifiex_unmap_pci_memory(adapter, skb, PCI_DMA_FROMDEVICE); - skb_pull(skb, INTF_HEADER_LEN); + skb_pull(skb, adapter->intf_hdr_len); while (reg->sleep_cookie && (count++ < 10) && mwifiex_pcie_ok_to_access_hw(adapter)) usleep_range(50, 60); @@ -1747,12 +1747,12 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) } memcpy(adapter->upld_buf, skb->data, min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); - skb_push(skb, INTF_HEADER_LEN); + skb_push(skb, adapter->intf_hdr_len); if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, PCI_DMA_FROMDEVICE)) return -1; } else if (mwifiex_pcie_ok_to_access_hw(adapter)) { - skb_pull(skb, INTF_HEADER_LEN); + skb_pull(skb, adapter->intf_hdr_len); adapter->curr_cmd->resp_skb = skb; adapter->cmd_resp_received = true; /* Take the pointer and set it to CMD node and will @@ -1789,7 +1789,7 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, if (skb) { card->cmdrsp_buf = skb; - skb_push(card->cmdrsp_buf, INTF_HEADER_LEN); + skb_push(card->cmdrsp_buf, adapter->intf_hdr_len); if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, PCI_DMA_FROMDEVICE)) return -1; @@ -1854,14 +1854,15 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) desc = card->evtbd_ring[rdptr]; memset(desc, 0, sizeof(*desc)); - event = get_unaligned_le32(&skb_cmd->data[INTF_HEADER_LEN]); + event = get_unaligned_le32( + &skb_cmd->data[adapter->intf_hdr_len]); adapter->event_cause = event; /* The first 4bytes will be the event transfer header len is 2 bytes followed by type which is 2 bytes */ memcpy(&data_len, skb_cmd->data, sizeof(__le16)); evt_len = le16_to_cpu(data_len); skb_trim(skb_cmd, evt_len); - skb_pull(skb_cmd, INTF_HEADER_LEN); + skb_pull(skb_cmd, adapter->intf_hdr_len); mwifiex_dbg(adapter, EVENT, "info: Event length: %d\n", evt_len); @@ -1920,7 +1921,7 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, } if (!card->evt_buf_list[rdptr]) { - skb_push(skb, INTF_HEADER_LEN); + skb_push(skb, adapter->intf_hdr_len); skb_put(skb, MAX_EVENT_SIZE - skb->len); if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index d38d31bb9b79..f81a006668f3 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -1125,7 +1125,7 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, data = skb->data; total_pkt_len = skb->len; - while (total_pkt_len >= (SDIO_HEADER_OFFSET + INTF_HEADER_LEN)) { + while (total_pkt_len >= (SDIO_HEADER_OFFSET + adapter->intf_hdr_len)) { if (total_pkt_len < adapter->sdio_rx_block_size) break; blk_num = *(data + BLOCK_NUMBER_OFFSET); @@ -1152,7 +1152,7 @@ static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, break; skb_put(skb_deaggr, pkt_len); memcpy(skb_deaggr->data, data + SDIO_HEADER_OFFSET, pkt_len); - skb_pull(skb_deaggr, INTF_HEADER_LEN); + skb_pull(skb_deaggr, adapter->intf_hdr_len); mwifiex_handle_rx_packet(adapter, skb_deaggr); data += blk_size; @@ -1178,7 +1178,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, if (upld_typ != MWIFIEX_TYPE_AGGR_DATA) { skb_trim(skb, pkt_len); - skb_pull(skb, INTF_HEADER_LEN); + skb_pull(skb, adapter->intf_hdr_len); } switch (upld_typ) { @@ -1537,7 +1537,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) rx_len = card->mp_regs[reg->cmd_rd_len_1] << 8; rx_len |= (u16)card->mp_regs[reg->cmd_rd_len_0]; rx_blocks = DIV_ROUND_UP(rx_len, MWIFIEX_SDIO_BLOCK_SIZE); - if (rx_len <= INTF_HEADER_LEN || + if (rx_len <= adapter->intf_hdr_len || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > MWIFIEX_RX_DATA_BUF_SIZE) return -1; @@ -1635,7 +1635,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) rx_blocks = (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - 1) / MWIFIEX_SDIO_BLOCK_SIZE; - if (rx_len <= INTF_HEADER_LEN || + if (rx_len <= adapter->intf_hdr_len || (card->mpa_rx.enabled && ((rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > card->mpa_rx.buf_size))) { @@ -1896,7 +1896,7 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, adapter->cmd_sent = true; /* Type must be MWIFIEX_TYPE_CMD */ - if (pkt_len <= INTF_HEADER_LEN || + if (pkt_len <= adapter->intf_hdr_len || pkt_len > MWIFIEX_UPLD_SIZE) mwifiex_dbg(adapter, ERROR, "%s: payload=%p, nb=%d\n", diff --git a/drivers/net/wireless/marvell/mwifiex/sta_tx.c b/drivers/net/wireless/marvell/mwifiex/sta_tx.c index f6683ea6bd5d..620f8650a742 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_tx.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_tx.c @@ -49,8 +49,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); unsigned int pad; u16 pkt_type, pkt_offset; - int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 : - INTF_HEADER_LEN; + int hroom = adapter->intf_hdr_len; if (!skb->len) { mwifiex_dbg(adapter, ERROR, @@ -116,7 +115,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset); - /* make space for INTF_HEADER_LEN */ + /* make space for adapter->intf_hdr_len */ skb_push(skb, hroom); if (!local_tx_pd->tx_control) @@ -165,8 +164,9 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) memset(tx_info, 0, sizeof(*tx_info)); tx_info->bss_num = priv->bss_num; tx_info->bss_type = priv->bss_type; - tx_info->pkt_len = data_len - (sizeof(struct txpd) + INTF_HEADER_LEN); - skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN); + tx_info->pkt_len = data_len - + (sizeof(struct txpd) + adapter->intf_hdr_len); + skb_reserve(skb, sizeof(struct txpd) + adapter->intf_hdr_len); skb_push(skb, sizeof(struct txpd)); local_tx_pd = (struct txpd *) skb->data; @@ -177,11 +177,11 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; + skb_push(skb, adapter->intf_hdr_len); if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, skb, NULL); } else { - skb_push(skb, INTF_HEADER_LEN); tx_param.next_pkt_len = 0; ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb, &tx_param); diff --git a/drivers/net/wireless/marvell/mwifiex/txrx.c b/drivers/net/wireless/marvell/mwifiex/txrx.c index fac28bd8fbee..15e92afdd1c8 100644 --- a/drivers/net/wireless/marvell/mwifiex/txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/txrx.c @@ -91,7 +91,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, struct mwifiex_sta_node *dest_node; struct ethhdr *hdr = (void *)skb->data; - hroom = (adapter->iface_type == MWIFIEX_USB) ? 0 : INTF_HEADER_LEN; + hroom = adapter->intf_hdr_len; if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) { dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest); @@ -179,13 +179,8 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter, mwifiex_write_data_complete(adapter, skb, 0, 0); return ret; } - if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { - if (adapter->iface_type == MWIFIEX_USB) - local_tx_pd = (struct txpd *)head_ptr; - else - local_tx_pd = (struct txpd *) (head_ptr + - INTF_HEADER_LEN); - } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + local_tx_pd = (struct txpd *)(head_ptr + adapter->intf_hdr_len); if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c index bf5660eb27d3..1e6a62c69ac5 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c @@ -468,8 +468,7 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); int pad; u16 pkt_type, pkt_offset; - int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 : - INTF_HEADER_LEN; + int hroom = adapter->intf_hdr_len; if (!skb->len) { mwifiex_dbg(adapter, ERROR, @@ -521,7 +520,7 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, txpd->tx_pkt_offset = cpu_to_le16(pkt_offset); - /* make space for INTF_HEADER_LEN */ + /* make space for adapter->intf_hdr_len */ skb_push(skb, hroom); if (!txpd->tx_control) -- cgit v1.2.3 From 42d1abb50ffc51c65e9cec735c8a9711296a05f7 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 May 2017 07:12:31 +0000 Subject: mwifiex: usb: kill urb before free its memory we have observed host system hang when device firmware crash, stack trace show it was an use-after-free case: previous submitted urb will be holding in usbcore, and given back to device driver when device disconnected, while the urb have been freed in usb device disconnect handler. This patch kill the holding urb before free its memory. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index debd6216366a..9c3d654ae009 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -363,6 +363,7 @@ static void mwifiex_usb_free(struct usb_card_rec *card) for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { port = &card->port[i]; for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { + usb_kill_urb(port->tx_data_list[j].urb); usb_free_urb(port->tx_data_list[j].urb); port->tx_data_list[j].urb = NULL; } -- cgit v1.2.3 From c59942938c6ab37f69658cafec6869eeb77e2e79 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 May 2017 07:12:32 +0000 Subject: mwifiex: usb: transmit aggregation packets Instead of using 4KB packet buffer for data transfer, new chipset have more device memory. This patch try to aggregation packets in an 16KB buffer. In this way, totally usb transaction cost will be reduced. Thoughput test on usb 2.0 show both TCP TX and UPD TX promote ~40M, from ~240M to ~280M. This feature is default disabled, and can be enabled by module parameter, like: insmod mwifiex.ko aggr_ctrl=1 Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/fw.h | 10 + drivers/net/wireless/marvell/mwifiex/main.c | 4 + drivers/net/wireless/marvell/mwifiex/main.h | 15 + drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 18 ++ drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c | 24 ++ drivers/net/wireless/marvell/mwifiex/usb.c | 355 ++++++++++++++++++--- drivers/net/wireless/marvell/mwifiex/usb.h | 9 + 7 files changed, 382 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 6cf9ab9133ea..b4d915b9232c 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -405,6 +405,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_TDLS_OPER 0x0122 #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 #define HostCmd_CMD_CHAN_REGION_CFG 0x0242 +#define HostCmd_CMD_PACKET_AGGR_CTRL 0x0251 #define PROTOCOL_NO_SECURITY 0x01 #define PROTOCOL_STATIC_WEP 0x02 @@ -2268,6 +2269,14 @@ struct host_cmd_ds_chan_region_cfg { __le16 action; } __packed; +struct host_cmd_ds_pkt_aggr_ctrl { + __le16 action; + __le16 enable; + __le16 tx_aggr_max_size; + __le16 tx_aggr_max_num; + __le16 tx_aggr_align; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -2343,6 +2352,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_wakeup_reason hs_wakeup_reason; struct host_cmd_ds_gtk_rekey_params rekey; struct host_cmd_ds_chan_region_cfg reg_cfg; + struct host_cmd_ds_pkt_aggr_ctrl pkt_aggr_ctrl; } params; } __packed; diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index dd87b9ff64c3..2c42191293c3 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -44,6 +44,10 @@ bool mfg_mode; module_param(mfg_mode, bool, 0); MODULE_PARM_DESC(mfg_mode, "manufacturing mode enable:1, disable:0"); +bool aggr_ctrl; +module_param(aggr_ctrl, bool, 0000); +MODULE_PARM_DESC(aggr_ctrl, "usb tx aggreataon enable:1, disable:0"); + /* * This function registers the device and performs all the necessary * initializations. diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index a4a014366d79..c37fb2606502 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -60,6 +60,7 @@ extern const char driver_version[]; extern bool mfg_mode; +extern bool aggr_ctrl; struct mwifiex_adapter; struct mwifiex_private; @@ -798,6 +799,18 @@ struct mwifiex_auto_tdls_peer { u8 do_setup; }; +#define MWIFIEX_TYPE_AGGR_DATA_V2 11 +#define MWIFIEX_BUS_AGGR_MODE_LEN_V2 (2) +#define MWIFIEX_BUS_AGGR_MAX_LEN 16000 +#define MWIFIEX_BUS_AGGR_MAX_NUM 10 +struct bus_aggr_params { + u16 enable; + u16 mode; + u16 tx_aggr_max_size; + u16 tx_aggr_max_num; + u16 tx_aggr_align; +}; + struct mwifiex_if_ops { int (*init_if) (struct mwifiex_adapter *); void (*cleanup_if) (struct mwifiex_adapter *); @@ -1016,6 +1029,8 @@ struct mwifiex_adapter { /* Wake-on-WLAN (WoWLAN) */ int irq_wakeup; bool wake_by_wifi; + /* Aggregation parameters*/ + struct bus_aggr_params bus_aggr; }; void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 83916c1439af..534d94a206a5 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -2064,6 +2064,15 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_11AC_CFG: ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf); break; + case HostCmd_CMD_PACKET_AGGR_CTRL: + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->params.pkt_aggr_ctrl.action = cpu_to_le16(cmd_action); + cmd_ptr->params.pkt_aggr_ctrl.enable = + cpu_to_le16(*(u16 *)data_buf); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_pkt_aggr_ctrl) + + S_DS_GEN); + break; case HostCmd_CMD_P2P_MODE_CFG: cmd_ptr->command = cpu_to_le16(cmd_no); cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action); @@ -2241,6 +2250,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) enum state_11d_t state_11d; struct mwifiex_ds_11n_tx_cfg tx_cfg; u8 sdio_sp_rx_aggr_enable; + u16 packet_aggr_enable; int data; if (first_sta) { @@ -2387,6 +2397,14 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) "11D: failed to enable 11D\n"); } + /* Pacekt aggregation handshake with firmware */ + if (aggr_ctrl) { + packet_aggr_enable = true; + mwifiex_send_cmd(priv, HostCmd_CMD_PACKET_AGGR_CTRL, + HostCmd_ACT_GEN_SET, 0, + &packet_aggr_enable, true); + } + /* Send cmd to FW to configure 11n specific configuration * (Short GI, Channel BW, Green field support etc.) for transmit */ diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index f1d1f56fc23f..3348fb3a7514 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -1154,6 +1154,27 @@ static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv, return 0; } +int mwifiex_ret_pkt_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_pkt_aggr_ctrl *pkt_aggr_ctrl = + &resp->params.pkt_aggr_ctrl; + struct mwifiex_adapter *adapter = priv->adapter; + + adapter->bus_aggr.enable = le16_to_cpu(pkt_aggr_ctrl->enable); + if (adapter->bus_aggr.enable) + adapter->intf_hdr_len = INTF_HEADER_LEN; + adapter->bus_aggr.mode = MWIFIEX_BUS_AGGR_MODE_LEN_V2; + adapter->bus_aggr.tx_aggr_max_size = + le16_to_cpu(pkt_aggr_ctrl->tx_aggr_max_size); + adapter->bus_aggr.tx_aggr_max_num = + le16_to_cpu(pkt_aggr_ctrl->tx_aggr_max_num); + adapter->bus_aggr.tx_aggr_align = + le16_to_cpu(pkt_aggr_ctrl->tx_aggr_align); + + return 0; +} + /* * This function handles the command responses. * @@ -1255,6 +1276,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_11AC_CFG: break; + case HostCmd_CMD_PACKET_AGGR_CTRL: + ret = mwifiex_ret_pkt_aggr_ctrl(priv, resp); + break; case HostCmd_CMD_P2P_MODE_CFG: ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf); break; diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 9c3d654ae009..0ab455b03cdc 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -681,6 +681,7 @@ static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) if (!port->tx_data_ep) continue; port->tx_data_ix = 0; + skb_queue_head_init(&port->tx_aggr.aggr_list); if (port->tx_data_ep == MWIFIEX_USB_EP_DATA) port->block_status = false; else @@ -847,73 +848,31 @@ static inline u8 mwifiex_usb_data_sent(struct mwifiex_adapter *adapter) return true; } -/* This function write a command/data packet to card. */ -static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, - struct sk_buff *skb, - struct mwifiex_tx_param *tx_param) +static int mwifiex_usb_construct_send_urb(struct mwifiex_adapter *adapter, + struct usb_tx_data_port *port, u8 ep, + struct urb_context *context, + struct sk_buff *skb_send) { struct usb_card_rec *card = adapter->card; - struct urb_context *context = NULL; - struct usb_tx_data_port *port = NULL; - u8 *data = (u8 *)skb->data; + int ret = -EINPROGRESS; struct urb *tx_urb; - int idx, ret = -EINPROGRESS; - - if (adapter->is_suspended) { - mwifiex_dbg(adapter, ERROR, - "%s: not allowed while suspended\n", __func__); - return -1; - } - - if (adapter->surprise_removed) { - mwifiex_dbg(adapter, ERROR, "%s: device removed\n", __func__); - return -1; - } - - mwifiex_dbg(adapter, INFO, "%s: ep=%d\n", __func__, ep); - - if (ep == card->tx_cmd_ep) { - context = &card->tx_cmd; - } else { - for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) { - if (ep == card->port[idx].tx_data_ep) { - port = &card->port[idx]; - if (atomic_read(&port->tx_data_urb_pending) - >= MWIFIEX_TX_DATA_URB) { - port->block_status = true; - adapter->data_sent = - mwifiex_usb_data_sent(adapter); - return -EBUSY; - } - if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB) - port->tx_data_ix = 0; - context = - &port->tx_data_list[port->tx_data_ix++]; - break; - } - } - if (!port) { - mwifiex_dbg(adapter, ERROR, "Wrong usb tx data port\n"); - return -1; - } - } context->adapter = adapter; context->ep = ep; - context->skb = skb; + context->skb = skb_send; tx_urb = context->urb; if (ep == card->tx_cmd_ep && card->tx_cmd_ep_type == USB_ENDPOINT_XFER_INT) usb_fill_int_urb(tx_urb, card->udev, - usb_sndintpipe(card->udev, ep), data, - skb->len, mwifiex_usb_tx_complete, + usb_sndintpipe(card->udev, ep), skb_send->data, + skb_send->len, mwifiex_usb_tx_complete, (void *)context, card->tx_cmd_interval); else usb_fill_bulk_urb(tx_urb, card->udev, - usb_sndbulkpipe(card->udev, ep), data, - skb->len, mwifiex_usb_tx_complete, - (void *)context); + usb_sndbulkpipe(card->udev, ep), + skb_send->data, skb_send->len, + mwifiex_usb_tx_complete, (void *)context); tx_urb->transfer_flags |= URB_ZERO_PACKET; @@ -950,6 +909,275 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, return ret; } +static int mwifiex_usb_prepare_tx_aggr_skb(struct mwifiex_adapter *adapter, + struct usb_tx_data_port *port, + struct sk_buff **skb_send) +{ + struct sk_buff *skb_aggr, *skb_tmp; + u8 *payload, pad; + u16 align = adapter->bus_aggr.tx_aggr_align; + struct mwifiex_txinfo *tx_info = NULL; + bool is_txinfo_set = false; + + skb_aggr = mwifiex_alloc_dma_align_buf(port->tx_aggr.aggr_len, + GFP_ATOMIC); + if (!skb_aggr) { + mwifiex_dbg(adapter, ERROR, + "%s: alloc skb_aggr failed\n", __func__); + + while ((skb_tmp = skb_dequeue(&port->tx_aggr.aggr_list))) + mwifiex_write_data_complete(adapter, skb_tmp, 0, -1); + + port->tx_aggr.aggr_num = 0; + port->tx_aggr.aggr_len = 0; + return -EBUSY; + } + + tx_info = MWIFIEX_SKB_TXCB(skb_aggr); + memset(tx_info, 0, sizeof(*tx_info)); + + while ((skb_tmp = skb_dequeue(&port->tx_aggr.aggr_list))) { + /* padding for aligning next packet header*/ + pad = (align - (skb_tmp->len & (align - 1))) % align; + payload = skb_put(skb_aggr, skb_tmp->len + pad); + memcpy(payload, skb_tmp->data, skb_tmp->len); + if (skb_queue_empty(&port->tx_aggr.aggr_list)) { + /* do not padding for last packet*/ + *(u16 *)payload = cpu_to_le16(skb_tmp->len); + *(u16 *)&payload[2] = + cpu_to_le16(MWIFIEX_TYPE_AGGR_DATA_V2 | 0x80); + skb_trim(skb_aggr, skb_aggr->len - pad); + } else { + /* add aggregation interface header */ + *(u16 *)payload = cpu_to_le16(skb_tmp->len + pad); + *(u16 *)&payload[2] = + cpu_to_le16(MWIFIEX_TYPE_AGGR_DATA_V2); + } + + if (!is_txinfo_set) { + tx_info->bss_num = MWIFIEX_SKB_TXCB(skb_tmp)->bss_num; + tx_info->bss_type = MWIFIEX_SKB_TXCB(skb_tmp)->bss_type; + is_txinfo_set = true; + } + + port->tx_aggr.aggr_num--; + port->tx_aggr.aggr_len -= (skb_tmp->len + pad); + mwifiex_write_data_complete(adapter, skb_tmp, 0, 0); + } + + tx_info->pkt_len = skb_aggr->len - + (sizeof(struct txpd) + adapter->intf_hdr_len); + tx_info->flags |= MWIFIEX_BUF_FLAG_AGGR_PKT; + + port->tx_aggr.aggr_num = 0; + port->tx_aggr.aggr_len = 0; + *skb_send = skb_aggr; + + return 0; +} + +/* This function prepare data packet to be send under usb tx aggregation + * protocol, check current usb aggregation status, link packet to aggrgation + * list if possible, work flow as below: + * (1) if only 1 packet available, add usb tx aggregation header and send. + * (2) if packet is able to aggregated, link it to current aggregation list. + * (3) if packet is not able to aggregated, aggregate and send exist packets + * in aggrgation list. Then, link packet in the list if there is more + * packet in transmit queue, otherwise try to transmit single packet. + */ +static int mwifiex_usb_aggr_tx_data(struct mwifiex_adapter *adapter, u8 ep, + struct sk_buff *skb, + struct mwifiex_tx_param *tx_param, + struct usb_tx_data_port *port) +{ + u8 *payload, pad; + u16 align = adapter->bus_aggr.tx_aggr_align; + struct sk_buff *skb_send = NULL; + struct urb_context *context = NULL; + struct txpd *local_tx_pd = + (struct txpd *)((u8 *)skb->data + adapter->intf_hdr_len); + u8 f_send_aggr_buf = 0; + u8 f_send_cur_buf = 0; + u8 f_precopy_cur_buf = 0; + u8 f_postcopy_cur_buf = 0; + int ret; + + /* padding to ensure each packet alginment */ + pad = (align - (skb->len & (align - 1))) % align; + + if (tx_param && tx_param->next_pkt_len) { + /* next packet available in tx queue*/ + if (port->tx_aggr.aggr_len + skb->len + pad > + adapter->bus_aggr.tx_aggr_max_size) { + f_send_aggr_buf = 1; + f_postcopy_cur_buf = 1; + } else { + /* current packet could be aggregated*/ + f_precopy_cur_buf = 1; + + if (port->tx_aggr.aggr_len + skb->len + pad + + tx_param->next_pkt_len > + adapter->bus_aggr.tx_aggr_max_size || + port->tx_aggr.aggr_num + 2 > + adapter->bus_aggr.tx_aggr_max_num) { + /* next packet could not be aggregated + * send current aggregation buffer + */ + f_send_aggr_buf = 1; + } + } + } else { + /* last packet in tx queue */ + if (port->tx_aggr.aggr_num > 0) { + /* pending packets in aggregation buffer*/ + if (port->tx_aggr.aggr_len + skb->len + pad > + adapter->bus_aggr.tx_aggr_max_size) { + /* current packet not be able to aggregated, + * send aggr buffer first, then send packet. + */ + f_send_cur_buf = 1; + } else { + /* last packet, Aggregation and send */ + f_precopy_cur_buf = 1; + } + + f_send_aggr_buf = 1; + } else { + /* no pending packets in aggregation buffer, + * send current packet immediately + */ + f_send_cur_buf = 1; + } + } + + if (local_tx_pd->flags & MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET) { + /* Send NULL packet immediately*/ + if (f_precopy_cur_buf) { + if (skb_queue_empty(&port->tx_aggr.aggr_list)) { + f_precopy_cur_buf = 0; + f_send_aggr_buf = 0; + f_send_cur_buf = 1; + } else { + f_send_aggr_buf = 1; + } + } else if (f_postcopy_cur_buf) { + f_send_cur_buf = 1; + f_postcopy_cur_buf = 0; + } + } + + if (f_precopy_cur_buf) { + skb_queue_tail(&port->tx_aggr.aggr_list, skb); + port->tx_aggr.aggr_len += (skb->len + pad); + port->tx_aggr.aggr_num++; + } + + if (f_send_aggr_buf) { + ret = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send); + if (!ret) { + context = &port->tx_data_list[port->tx_data_ix++]; + ret = mwifiex_usb_construct_send_urb(adapter, port, ep, + context, skb_send); + if (ret == -1) + mwifiex_write_data_complete(adapter, skb_send, + 0, -1); + } + } + + if (f_send_cur_buf) { + if (f_send_aggr_buf) { + if (atomic_read(&port->tx_data_urb_pending) >= + MWIFIEX_TX_DATA_URB) { + port->block_status = true; + adapter->data_sent = + mwifiex_usb_data_sent(adapter); + /* no available urb, postcopy packet*/ + f_postcopy_cur_buf = 1; + goto postcopy_cur_buf; + } + + if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB) + port->tx_data_ix = 0; + } + + payload = skb->data; + *(u16 *)&payload[2] = + cpu_to_le16(MWIFIEX_TYPE_AGGR_DATA_V2 | 0x80); + *(u16 *)payload = cpu_to_le16(skb->len); + skb_send = skb; + context = &port->tx_data_list[port->tx_data_ix++]; + return mwifiex_usb_construct_send_urb(adapter, port, ep, + context, skb_send); + } + +postcopy_cur_buf: + if (f_postcopy_cur_buf) { + skb_queue_tail(&port->tx_aggr.aggr_list, skb); + port->tx_aggr.aggr_len += (skb->len + pad); + port->tx_aggr.aggr_num++; + } + + return -EINPROGRESS; +} + +/* This function write a command/data packet to card. */ +static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, + struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + struct usb_card_rec *card = adapter->card; + struct urb_context *context = NULL; + struct usb_tx_data_port *port = NULL; + int idx; + + if (adapter->is_suspended) { + mwifiex_dbg(adapter, ERROR, + "%s: not allowed while suspended\n", __func__); + return -1; + } + + if (adapter->surprise_removed) { + mwifiex_dbg(adapter, ERROR, "%s: device removed\n", __func__); + return -1; + } + + mwifiex_dbg(adapter, INFO, "%s: ep=%d\n", __func__, ep); + + if (ep == card->tx_cmd_ep) { + context = &card->tx_cmd; + } else { + /* get the data port structure for endpoint */ + for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) { + if (ep == card->port[idx].tx_data_ep) { + port = &card->port[idx]; + if (atomic_read(&port->tx_data_urb_pending) + >= MWIFIEX_TX_DATA_URB) { + port->block_status = true; + adapter->data_sent = + mwifiex_usb_data_sent(adapter); + return -EBUSY; + } + if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB) + port->tx_data_ix = 0; + break; + } + } + + if (!port) { + mwifiex_dbg(adapter, ERROR, "Wrong usb tx data port\n"); + return -1; + } + + if (adapter->bus_aggr.enable) + return mwifiex_usb_aggr_tx_data(adapter, ep, skb, + tx_param, port); + + context = &port->tx_data_list[port->tx_data_ix++]; + } + + return mwifiex_usb_construct_send_urb(adapter, port, ep, context, skb); +} + /* This function register usb device and initialize parameter. */ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) { @@ -990,10 +1218,31 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) return 0; } +static void mwifiex_usb_cleanup_tx_aggr(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + struct usb_tx_data_port *port; + struct sk_buff *skb_tmp; + int idx; + + if (adapter->bus_aggr.enable) { + for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) { + port = &card->port[idx]; + while ((skb_tmp = + skb_dequeue(&port->tx_aggr.aggr_list))) + mwifiex_write_data_complete(adapter, skb_tmp, + 0, -1); + } + } +} + static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) { struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + if (adapter->bus_aggr.enable) + mwifiex_usb_cleanup_tx_aggr(adapter); + card->adapter = NULL; } diff --git a/drivers/net/wireless/marvell/mwifiex/usb.h b/drivers/net/wireless/marvell/mwifiex/usb.h index e36bd63172ff..b89b840e0142 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.h +++ b/drivers/net/wireless/marvell/mwifiex/usb.h @@ -64,12 +64,21 @@ struct urb_context { u8 ep; }; +struct usb_tx_aggr { + struct sk_buff_head aggr_list; + int aggr_len; + int aggr_num; +}; + struct usb_tx_data_port { u8 tx_data_ep; u8 block_status; atomic_t tx_data_urb_pending; int tx_data_ix; struct urb_context tx_data_list[MWIFIEX_TX_DATA_URB]; + /* usb tx aggregation*/ + struct usb_tx_aggr tx_aggr; + struct sk_buff *skb_aggr[MWIFIEX_TX_DATA_URB]; }; struct usb_card_rec { -- cgit v1.2.3 From a2ca85ad721de50b90d50f3a11b67c4776a1236d Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 May 2017 07:12:33 +0000 Subject: mwifiex: usb: add timer to flush aggregation packets Aggregation will wait for next packet until limit aggr size/number reach. Packet might be drop and also packet dequeue will be stop in some cases. This patch add timer to flush packets in aggregation list to avoid long time waiting. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/usb.c | 258 ++++++++++++++++++++--------- drivers/net/wireless/marvell/mwifiex/usb.h | 14 ++ 2 files changed, 193 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 0ab455b03cdc..cb1753e43ef4 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -663,76 +663,6 @@ static struct usb_driver mwifiex_usb_driver = { .soft_unbind = 1, }; -static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) -{ - struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; - struct usb_tx_data_port *port; - int i, j; - - card->tx_cmd.adapter = adapter; - card->tx_cmd.ep = card->tx_cmd_ep; - - card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); - if (!card->tx_cmd.urb) - return -ENOMEM; - - for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { - port = &card->port[i]; - if (!port->tx_data_ep) - continue; - port->tx_data_ix = 0; - skb_queue_head_init(&port->tx_aggr.aggr_list); - if (port->tx_data_ep == MWIFIEX_USB_EP_DATA) - port->block_status = false; - else - port->block_status = true; - for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { - port->tx_data_list[j].adapter = adapter; - port->tx_data_list[j].ep = port->tx_data_ep; - port->tx_data_list[j].urb = - usb_alloc_urb(0, GFP_KERNEL); - if (!port->tx_data_list[j].urb) - return -ENOMEM; - } - } - - return 0; -} - -static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter) -{ - struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; - int i; - - card->rx_cmd.adapter = adapter; - card->rx_cmd.ep = card->rx_cmd_ep; - - card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); - if (!card->rx_cmd.urb) - return -ENOMEM; - - card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); - if (!card->rx_cmd.skb) - return -ENOMEM; - - if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE)) - return -1; - - for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { - card->rx_data_list[i].adapter = adapter; - card->rx_data_list[i].ep = card->rx_data_ep; - - card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); - if (!card->rx_data_list[i].urb) - return -1; - if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], - MWIFIEX_RX_DATA_BUF_SIZE)) - return -1; - } - - return 0; -} - static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, u32 *len, u8 ep, u32 timeout) { @@ -919,6 +849,15 @@ static int mwifiex_usb_prepare_tx_aggr_skb(struct mwifiex_adapter *adapter, struct mwifiex_txinfo *tx_info = NULL; bool is_txinfo_set = false; + /* Packets in aggr_list will be send in either skb_aggr or + * write complete, delete the tx_aggr timer + */ + if (port->tx_aggr.timer_cnxt.is_hold_timer_set) { + del_timer(&port->tx_aggr.timer_cnxt.hold_timer); + port->tx_aggr.timer_cnxt.is_hold_timer_set = false; + port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0; + } + skb_aggr = mwifiex_alloc_dma_align_buf(port->tx_aggr.aggr_len, GFP_ATOMIC); if (!skb_aggr) { @@ -1000,6 +939,7 @@ static int mwifiex_usb_aggr_tx_data(struct mwifiex_adapter *adapter, u8 ep, u8 f_send_cur_buf = 0; u8 f_precopy_cur_buf = 0; u8 f_postcopy_cur_buf = 0; + u32 timeout; int ret; /* padding to ensure each packet alginment */ @@ -1070,8 +1010,35 @@ static int mwifiex_usb_aggr_tx_data(struct mwifiex_adapter *adapter, u8 ep, skb_queue_tail(&port->tx_aggr.aggr_list, skb); port->tx_aggr.aggr_len += (skb->len + pad); port->tx_aggr.aggr_num++; + if (f_send_aggr_buf) + goto send_aggr_buf; + + /* packet will not been send immediately, + * set a timer to make sure it will be sent under + * strict time limit. Dynamically fit the timeout + * value, according to packets number in aggr_list + */ + if (!port->tx_aggr.timer_cnxt.is_hold_timer_set) { + port->tx_aggr.timer_cnxt.hold_tmo_msecs = + MWIFIEX_USB_TX_AGGR_TMO_MIN; + timeout = + port->tx_aggr.timer_cnxt.hold_tmo_msecs; + mod_timer(&port->tx_aggr.timer_cnxt.hold_timer, + jiffies + msecs_to_jiffies(timeout)); + port->tx_aggr.timer_cnxt.is_hold_timer_set = true; + } else { + if (port->tx_aggr.timer_cnxt.hold_tmo_msecs < + MWIFIEX_USB_TX_AGGR_TMO_MAX) { + /* Dyanmic fit timeout */ + timeout = + ++port->tx_aggr.timer_cnxt.hold_tmo_msecs; + mod_timer(&port->tx_aggr.timer_cnxt.hold_timer, + jiffies + msecs_to_jiffies(timeout)); + } + } } +send_aggr_buf: if (f_send_aggr_buf) { ret = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send); if (!ret) { @@ -1115,11 +1082,60 @@ postcopy_cur_buf: skb_queue_tail(&port->tx_aggr.aggr_list, skb); port->tx_aggr.aggr_len += (skb->len + pad); port->tx_aggr.aggr_num++; + /* New aggregation begin, start timer */ + if (!port->tx_aggr.timer_cnxt.is_hold_timer_set) { + port->tx_aggr.timer_cnxt.hold_tmo_msecs = + MWIFIEX_USB_TX_AGGR_TMO_MIN; + timeout = port->tx_aggr.timer_cnxt.hold_tmo_msecs; + mod_timer(&port->tx_aggr.timer_cnxt.hold_timer, + jiffies + msecs_to_jiffies(timeout)); + port->tx_aggr.timer_cnxt.is_hold_timer_set = true; + } } return -EINPROGRESS; } +static void mwifiex_usb_tx_aggr_tmo(unsigned long context) +{ + struct urb_context *urb_cnxt = NULL; + struct sk_buff *skb_send = NULL; + struct tx_aggr_tmr_cnxt *timer_context = + (struct tx_aggr_tmr_cnxt *)context; + struct mwifiex_adapter *adapter = timer_context->adapter; + struct usb_tx_data_port *port = timer_context->port; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&port->tx_aggr_lock, flags); + err = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send); + if (err) { + mwifiex_dbg(adapter, ERROR, + "prepare tx aggr skb failed, err=%d\n", err); + return; + } + + if (atomic_read(&port->tx_data_urb_pending) >= + MWIFIEX_TX_DATA_URB) { + port->block_status = true; + adapter->data_sent = + mwifiex_usb_data_sent(adapter); + err = -1; + goto done; + } + + if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB) + port->tx_data_ix = 0; + + urb_cnxt = &port->tx_data_list[port->tx_data_ix++]; + err = mwifiex_usb_construct_send_urb(adapter, port, port->tx_data_ep, + urb_cnxt, skb_send); +done: + if (err == -1) + mwifiex_write_data_complete(adapter, skb_send, 0, -1); + spin_unlock_irqrestore(&port->tx_aggr_lock, flags); +} + /* This function write a command/data packet to card. */ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, struct sk_buff *skb, @@ -1128,7 +1144,8 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, struct usb_card_rec *card = adapter->card; struct urb_context *context = NULL; struct usb_tx_data_port *port = NULL; - int idx; + unsigned long flags; + int idx, ret; if (adapter->is_suspended) { mwifiex_dbg(adapter, ERROR, @@ -1168,9 +1185,13 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, return -1; } - if (adapter->bus_aggr.enable) - return mwifiex_usb_aggr_tx_data(adapter, ep, skb, + if (adapter->bus_aggr.enable) { + spin_lock_irqsave(&port->tx_aggr_lock, flags); + ret = mwifiex_usb_aggr_tx_data(adapter, ep, skb, tx_param, port); + spin_unlock_irqrestore(&port->tx_aggr_lock, flags); + return ret; + } context = &port->tx_data_list[port->tx_data_ix++]; } @@ -1178,6 +1199,84 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, return mwifiex_usb_construct_send_urb(adapter, port, ep, context, skb); } +static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + struct usb_tx_data_port *port; + int i, j; + + card->tx_cmd.adapter = adapter; + card->tx_cmd.ep = card->tx_cmd_ep; + + card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->tx_cmd.urb) + return -ENOMEM; + + for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { + port = &card->port[i]; + if (!port->tx_data_ep) + continue; + port->tx_data_ix = 0; + skb_queue_head_init(&port->tx_aggr.aggr_list); + if (port->tx_data_ep == MWIFIEX_USB_EP_DATA) + port->block_status = false; + else + port->block_status = true; + for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { + port->tx_data_list[j].adapter = adapter; + port->tx_data_list[j].ep = port->tx_data_ep; + port->tx_data_list[j].urb = + usb_alloc_urb(0, GFP_KERNEL); + if (!port->tx_data_list[j].urb) + return -ENOMEM; + } + + port->tx_aggr.timer_cnxt.adapter = adapter; + port->tx_aggr.timer_cnxt.port = port; + port->tx_aggr.timer_cnxt.is_hold_timer_set = false; + port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0; + setup_timer(&port->tx_aggr.timer_cnxt.hold_timer, + mwifiex_usb_tx_aggr_tmo, + (unsigned long)&port->tx_aggr.timer_cnxt); + } + + return 0; +} + +static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + int i; + + card->rx_cmd.adapter = adapter; + card->rx_cmd.ep = card->rx_cmd_ep; + + card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->rx_cmd.urb) + return -ENOMEM; + + card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); + if (!card->rx_cmd.skb) + return -ENOMEM; + + if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE)) + return -1; + + for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { + card->rx_data_list[i].adapter = adapter; + card->rx_data_list[i].ep = card->rx_data_ep; + + card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->rx_data_list[i].urb) + return -1; + if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], + MWIFIEX_RX_DATA_BUF_SIZE)) + return -1; + } + + return 0; +} + /* This function register usb device and initialize parameter. */ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) { @@ -1225,14 +1324,16 @@ static void mwifiex_usb_cleanup_tx_aggr(struct mwifiex_adapter *adapter) struct sk_buff *skb_tmp; int idx; - if (adapter->bus_aggr.enable) { - for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) { - port = &card->port[idx]; + for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) { + port = &card->port[idx]; + if (adapter->bus_aggr.enable) while ((skb_tmp = skb_dequeue(&port->tx_aggr.aggr_list))) mwifiex_write_data_complete(adapter, skb_tmp, 0, -1); - } + del_timer_sync(&port->tx_aggr.timer_cnxt.hold_timer); + port->tx_aggr.timer_cnxt.is_hold_timer_set = false; + port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0; } } @@ -1240,8 +1341,7 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) { struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; - if (adapter->bus_aggr.enable) - mwifiex_usb_cleanup_tx_aggr(adapter); + mwifiex_usb_cleanup_tx_aggr(adapter); card->adapter = NULL; } diff --git a/drivers/net/wireless/marvell/mwifiex/usb.h b/drivers/net/wireless/marvell/mwifiex/usb.h index b89b840e0142..37abd228a84f 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.h +++ b/drivers/net/wireless/marvell/mwifiex/usb.h @@ -64,10 +64,22 @@ struct urb_context { u8 ep; }; +#define MWIFIEX_USB_TX_AGGR_TMO_MIN 1 +#define MWIFIEX_USB_TX_AGGR_TMO_MAX 4 + +struct tx_aggr_tmr_cnxt { + struct mwifiex_adapter *adapter; + struct usb_tx_data_port *port; + struct timer_list hold_timer; + bool is_hold_timer_set; + u32 hold_tmo_msecs; +}; + struct usb_tx_aggr { struct sk_buff_head aggr_list; int aggr_len; int aggr_num; + struct tx_aggr_tmr_cnxt timer_cnxt; }; struct usb_tx_data_port { @@ -79,6 +91,8 @@ struct usb_tx_data_port { /* usb tx aggregation*/ struct usb_tx_aggr tx_aggr; struct sk_buff *skb_aggr[MWIFIEX_TX_DATA_URB]; + /* lock for protect tx aggregation data path*/ + spinlock_t tx_aggr_lock; }; struct usb_card_rec { -- cgit v1.2.3 From 822446d4ff2b1924f8fe16ebb60675f8c3c7b34f Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 23 May 2017 07:12:34 +0000 Subject: mwifiex: check next packet length for usb tx aggregation The next packet length will be used by interface driver, to check if the next packet still could be aggregated. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 12 ++++++------ drivers/net/wireless/marvell/mwifiex/txrx.c | 4 ++-- drivers/net/wireless/marvell/mwifiex/wmm.c | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c index e8ffb26eb912..53e67526f40d 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c @@ -250,15 +250,15 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, return 0; } + if (skb_src) + tx_param.next_pkt_len = skb_src->len + sizeof(struct txpd); + else + tx_param.next_pkt_len = 0; + if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, - skb_aggr, NULL); + skb_aggr, &tx_param); } else { - if (skb_src) - tx_param.next_pkt_len = - skb_src->len + sizeof(struct txpd); - else - tx_param.next_pkt_len = 0; ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb_aggr, &tx_param); diff --git a/drivers/net/wireless/marvell/mwifiex/txrx.c b/drivers/net/wireless/marvell/mwifiex/txrx.c index 15e92afdd1c8..d848933466d9 100644 --- a/drivers/net/wireless/marvell/mwifiex/txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/txrx.c @@ -117,7 +117,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, - skb, NULL); + skb, tx_param); } else { ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, @@ -185,7 +185,7 @@ static int mwifiex_host_to_card(struct mwifiex_adapter *adapter, if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, - skb, NULL); + skb, tx_param); } else { ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index e4ff3b973850..75cdd55d1046 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -1363,13 +1363,13 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); + tx_param.next_pkt_len = + ((skb_next) ? skb_next->len + + sizeof(struct txpd) : 0); if (adapter->iface_type == MWIFIEX_USB) { ret = adapter->if_ops.host_to_card(adapter, priv->usb_port, - skb, NULL); + skb, &tx_param); } else { - tx_param.next_pkt_len = - ((skb_next) ? skb_next->len + - sizeof(struct txpd) : 0); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb, &tx_param); } -- cgit v1.2.3 From 1b17aedffb079fa5c05c2118b7f23a1e72e4dd2f Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 26 May 2017 18:03:05 -0400 Subject: net: dsa: mv88e6xxx: provide a PHY setup helper Similarly to the VTU, PVT and ATU setup, provide a mv88e6xxx_phy_setup helper which wraps mv88e6xxx_ppu_enable, so that no more PPU-related functions are exposed outside of phy.c. Thus make mv88e6xxx_ppu_enable static. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 11 ++++------- drivers/net/dsa/mv88e6xxx/phy.c | 7 ++++++- drivers/net/dsa/mv88e6xxx/phy.h | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 742c0eae7fa3..7f5f44f89389 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2034,13 +2034,6 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) u32 upstream_port = dsa_upstream_port(ds); int err; - /* Enable the PHY Polling Unit if present, don't discard any packets, - * and mask all interrupt sources. - */ - err = mv88e6xxx_ppu_enable(chip); - if (err) - return err; - if (chip->info->ops->g1_set_cpu_port) { err = chip->info->ops->g1_set_cpu_port(chip, upstream_port); if (err) @@ -2140,6 +2133,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) goto unlock; } + err = mv88e6xxx_phy_setup(chip); + if (err) + goto unlock; + err = mv88e6xxx_vtu_setup(chip); if (err) goto unlock; diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c index 0d3e8aaedf50..b865b1e2b103 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.c +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -124,7 +124,7 @@ static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip) return chip->info->ops->ppu_disable(chip); } -int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip) +static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip) { if (!chip->info->ops->ppu_enable) return 0; @@ -241,3 +241,8 @@ void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip) if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) mv88e6xxx_ppu_state_destroy(chip); } + +int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip) +{ + return mv88e6xxx_ppu_enable(chip); +} diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h index 0961d781b726..dfa98549dfcd 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.h +++ b/drivers/net/dsa/mv88e6xxx/phy.h @@ -30,8 +30,8 @@ int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 *val); int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 val); -int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip); void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip); void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip); +int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip); #endif /*_MV88E6XXX_PHY_H */ -- cgit v1.2.3 From 7e20cfb50496c0549d11eab521feb5bc565c63a6 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 26 May 2017 18:03:06 -0400 Subject: net: dsa: mv88e6xxx: rename PHY PPU accessors Make it clear that mv88e6xxx_phy_ppu_{read,write} are an implementation of the .phy_{read,write} operations, by renaming them with the mv88e6185 prefix, since 88E6185 it is the reference switch model supported in an upstream board (ZII Dev Rev B), which makes use of them. Distinguish the signatures of implementation specific and generic PHY functions in the phy.h header. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 16 ++++++++-------- drivers/net/dsa/mv88e6xxx/phy.c | 4 ++-- drivers/net/dsa/mv88e6xxx/phy.h | 11 +++++++---- 3 files changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 7f5f44f89389..070e82ac6132 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2371,8 +2371,8 @@ static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, static const struct mv88e6xxx_ops mv88e6085_ops = { /* MV88E6XXX_FAMILY_6097 */ .set_switch_mac = mv88e6xxx_g1_set_switch_mac, - .phy_read = mv88e6xxx_phy_ppu_read, - .phy_write = mv88e6xxx_phy_ppu_write, + .phy_read = mv88e6185_phy_ppu_read, + .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -2402,8 +2402,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { static const struct mv88e6xxx_ops mv88e6095_ops = { /* MV88E6XXX_FAMILY_6095 */ .set_switch_mac = mv88e6xxx_g1_set_switch_mac, - .phy_read = mv88e6xxx_phy_ppu_read, - .phy_write = mv88e6xxx_phy_ppu_write, + .phy_read = mv88e6185_phy_ppu_read, + .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -2480,8 +2480,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { static const struct mv88e6xxx_ops mv88e6131_ops = { /* MV88E6XXX_FAMILY_6185 */ .set_switch_mac = mv88e6xxx_g1_set_switch_mac, - .phy_read = mv88e6xxx_phy_ppu_read, - .phy_write = mv88e6xxx_phy_ppu_write, + .phy_read = mv88e6185_phy_ppu_read, + .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -2727,8 +2727,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { static const struct mv88e6xxx_ops mv88e6185_ops = { /* MV88E6XXX_FAMILY_6185 */ .set_switch_mac = mv88e6xxx_g1_set_switch_mac, - .phy_read = mv88e6xxx_phy_ppu_read, - .phy_write = mv88e6xxx_phy_ppu_write, + .phy_read = mv88e6185_phy_ppu_read, + .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c index b865b1e2b103..19e0128257e5 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.c +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -202,7 +202,7 @@ static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip) del_timer_sync(&chip->ppu_timer); } -int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, +int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 *val) { int err; @@ -216,7 +216,7 @@ int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, return err; } -int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, +int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 val) { int err; diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h index dfa98549dfcd..91fe3c3e9aea 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.h +++ b/drivers/net/dsa/mv88e6xxx/phy.h @@ -14,10 +14,17 @@ #ifndef _MV88E6XXX_PHY_H #define _MV88E6XXX_PHY_H +/* PHY Registers accesses implementations */ int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 *val); int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 val); +int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val); +int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 val); + +/* Generic PHY operations */ int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, int reg, u16 *val); int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, @@ -26,10 +33,6 @@ int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy, u8 page, int reg, u16 *val); int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, u8 page, int reg, u16 val); -int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, - int addr, int reg, u16 *val); -int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, - int addr, int reg, u16 val); void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip); void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip); int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip); -- cgit v1.2.3 From b15a7c039d30db0b38dfbced900f65b65c06bff9 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 26 May 2017 18:03:07 -0400 Subject: net: dsa: mv88e6xxx: rename PHY PPU functions Respect the implicit naming convention used in all register sets specific files, by renaming the mv88e6xxx_ppu_* functions with the mv88e6xxx_phy_* prefix. This is simply a s/xxx_ppu/xxx_phy_ppu/ substitution. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/phy.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c index 19e0128257e5..d47a6e08d88c 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.c +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -116,7 +116,7 @@ int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, return err; } -static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip) +static int mv88e6xxx_phy_ppu_disable(struct mv88e6xxx_chip *chip) { if (!chip->info->ops->ppu_disable) return 0; @@ -124,7 +124,7 @@ static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip) return chip->info->ops->ppu_disable(chip); } -static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip) +static int mv88e6xxx_phy_ppu_enable(struct mv88e6xxx_chip *chip) { if (!chip->info->ops->ppu_enable) return 0; @@ -132,7 +132,7 @@ static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip) return chip->info->ops->ppu_enable(chip); } -static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly) +static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly) { struct mv88e6xxx_chip *chip; @@ -141,7 +141,7 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly) mutex_lock(&chip->reg_lock); if (mutex_trylock(&chip->ppu_mutex)) { - if (mv88e6xxx_ppu_enable(chip) == 0) + if (mv88e6xxx_phy_ppu_enable(chip) == 0) chip->ppu_disabled = 0; mutex_unlock(&chip->ppu_mutex); } @@ -149,14 +149,14 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly) mutex_unlock(&chip->reg_lock); } -static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps) +static void mv88e6xxx_phy_ppu_reenable_timer(unsigned long _ps) { struct mv88e6xxx_chip *chip = (void *)_ps; schedule_work(&chip->ppu_work); } -static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip) +static int mv88e6xxx_phy_ppu_access_get(struct mv88e6xxx_chip *chip) { int ret; @@ -168,7 +168,7 @@ static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip) * it. */ if (!chip->ppu_disabled) { - ret = mv88e6xxx_ppu_disable(chip); + ret = mv88e6xxx_phy_ppu_disable(chip); if (ret < 0) { mutex_unlock(&chip->ppu_mutex); return ret; @@ -182,22 +182,22 @@ static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip) return ret; } -static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip) +static void mv88e6xxx_phy_ppu_access_put(struct mv88e6xxx_chip *chip) { /* Schedule a timer to re-enable the PHY polling unit. */ mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10)); mutex_unlock(&chip->ppu_mutex); } -static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip) +static void mv88e6xxx_phy_ppu_state_init(struct mv88e6xxx_chip *chip) { mutex_init(&chip->ppu_mutex); - INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work); - setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer, + INIT_WORK(&chip->ppu_work, mv88e6xxx_phy_ppu_reenable_work); + setup_timer(&chip->ppu_timer, mv88e6xxx_phy_ppu_reenable_timer, (unsigned long)chip); } -static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip) +static void mv88e6xxx_phy_ppu_state_destroy(struct mv88e6xxx_chip *chip) { del_timer_sync(&chip->ppu_timer); } @@ -207,10 +207,10 @@ int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, { int err; - err = mv88e6xxx_ppu_access_get(chip); + err = mv88e6xxx_phy_ppu_access_get(chip); if (!err) { err = mv88e6xxx_read(chip, addr, reg, val); - mv88e6xxx_ppu_access_put(chip); + mv88e6xxx_phy_ppu_access_put(chip); } return err; @@ -221,10 +221,10 @@ int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, { int err; - err = mv88e6xxx_ppu_access_get(chip); + err = mv88e6xxx_phy_ppu_access_get(chip); if (!err) { err = mv88e6xxx_write(chip, addr, reg, val); - mv88e6xxx_ppu_access_put(chip); + mv88e6xxx_phy_ppu_access_put(chip); } return err; @@ -233,16 +233,16 @@ int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip) { if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) - mv88e6xxx_ppu_state_init(chip); + mv88e6xxx_phy_ppu_state_init(chip); } void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip) { if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable) - mv88e6xxx_ppu_state_destroy(chip); + mv88e6xxx_phy_ppu_state_destroy(chip); } int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip) { - return mv88e6xxx_ppu_enable(chip); + return mv88e6xxx_phy_ppu_enable(chip); } -- cgit v1.2.3 From 23c9ee4934e7a79b49151d0f05c24117d69c73fe Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 26 May 2017 18:12:51 -0400 Subject: net: dsa: remove dev arg of dsa_register_switch The current dsa_register_switch function takes a useless struct device pointer argument, which always equals ds->dev. Drivers either call it with ds->dev, or with the same device pointer passed to dsa_switch_alloc, which ends up being assigned to ds->dev. This patch removes the second argument of the dsa_register_switch and _dsa_register_switch functions. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 2 +- drivers/net/dsa/dsa_loop.c | 2 +- drivers/net/dsa/lan9303-core.c | 2 +- drivers/net/dsa/mt7530.c | 2 +- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- drivers/net/dsa/qca8k.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 6a5648a9cb09..e68d368e20ac 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1989,7 +1989,7 @@ int b53_switch_register(struct b53_device *dev) pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev); - return dsa_register_switch(dev->ds, dev->ds->dev); + return dsa_register_switch(dev->ds); } EXPORT_SYMBOL(b53_switch_register); diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 5edf07beb9d2..79e62593ff4e 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -271,7 +271,7 @@ static int dsa_loop_drv_probe(struct mdio_device *mdiodev) dev_set_drvdata(&mdiodev->dev, ds); - return dsa_register_switch(ds, ds->dev); + return dsa_register_switch(ds); } static void dsa_loop_drv_remove(struct mdio_device *mdiodev) diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index c8b2423c8ef7..cd76e61f1fca 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -802,7 +802,7 @@ static int lan9303_register_switch(struct lan9303 *chip) chip->ds->ops = &lan9303_switch_ops; chip->ds->phys_mii_mask = chip->phy_addr_sel_strap ? 0xe : 0x7; - return dsa_register_switch(chip->ds, chip->dev); + return dsa_register_switch(chip->ds); } static void lan9303_probe_reset_gpio(struct lan9303 *chip, diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 4d2f45153ede..25e00d5e0eec 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1080,7 +1080,7 @@ mt7530_probe(struct mdio_device *mdiodev) mutex_init(&priv->reg_mutex); dev_set_drvdata(&mdiodev->dev, priv); - return dsa_register_switch(priv->ds, &mdiodev->dev); + return dsa_register_switch(priv->ds); } static void diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 070e82ac6132..7cf470c3e662 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3884,7 +3884,7 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) dev_set_drvdata(dev, ds); - return dsa_register_switch(ds, dev); + return dsa_register_switch(ds); } static void mv88e6xxx_unregister_switch(struct mv88e6xxx_chip *chip) diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 0f6a011d8ed1..b3bee7eab45f 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -958,7 +958,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev) mutex_init(&priv->reg_mutex); dev_set_drvdata(&mdiodev->dev, priv); - return dsa_register_switch(priv->ds, &mdiodev->dev); + return dsa_register_switch(priv->ds); } static void -- cgit v1.2.3 From 9831724a08f06f9560fcc3f1132cbd290e5f9149 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 30 May 2017 11:26:14 +0200 Subject: net/mlxfw: select CONFIG_XZ_DEC The new mlxfw code fails to build without the xz library: drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.o: In function `mlxfw_mfa2_xz_dec_run': :(.text.mlxfw_mfa2_xz_dec_run+0x8): undefined reference to `xz_dec_run' drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.o: In function `mlxfw_mfa2_file_component_get': :(.text.mlxfw_mfa2_file_component_get+0x218): undefined reference to `xz_dec_init' :(.text.mlxfw_mfa2_file_component_get+0x2c0): undefined reference to `xz_dec_end' This adds a Kconfig 'select' statement for it, which is also what the other user of that library has. Fixes: 410ed13cae39 ("Add the mlxfw module for Mellanox firmware flash process") Signed-off-by: Arnd Bergmann Acked-by: Yotam Gigi Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxfw/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxfw/Kconfig b/drivers/net/ethernet/mellanox/mlxfw/Kconfig index 56b60ac7bc34..2b21af8a2b1d 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxfw/Kconfig @@ -4,3 +4,4 @@ config MLXFW tristate "mlxfw" if COMPILE_TEST + select XZ_DEC -- cgit v1.2.3 From 8eb1b3c336b36421bd6673ec02222cb57e52372d Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Tue, 30 May 2017 11:36:56 -0700 Subject: netvsc: Add #include's for csum_* function declarations Add direct #include statements for declarations of csum_tcpudp_magic() and csum_ipv6_magic(). While the needed #include's are picked up indirectly for the x86 architecture, they aren't on other architectures, resulting in compile errors. Signed-off-by: Michael Kelley Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 4421a6d00375..2564ac83eb64 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include "hyperv_net.h" -- cgit v1.2.3 From d897a638e98c476c56118d0dcc1bc55450504866 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2017 08:06:43 -0700 Subject: sched: add helper for updating statistics on all actions Forgetting to disable preemption around tcf_action_stats_update() seems to be a common mistake. Add a helper function for updating stats on all actions of a filter. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 10 +--------- drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c | 10 +--------- drivers/net/ethernet/netronome/nfp/nfp_net_offload.c | 11 ++--------- 3 files changed, 4 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index d2f90ba2dbc4..7914a32a3036 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1863,9 +1863,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv, { struct mlx5e_tc_table *tc = &priv->fs.tc; struct mlx5e_tc_flow *flow; - struct tc_action *a; struct mlx5_fc *counter; - LIST_HEAD(actions); u64 bytes; u64 packets; u64 lastuse; @@ -1884,13 +1882,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv, mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); - preempt_disable(); - - tcf_exts_to_list(f->exts, &actions); - list_for_each_entry(a, &actions, list) - tcf_action_stats_update(a, bytes, packets, lastuse); - - preempt_enable(); + tcf_exts_stats_update(f->exts, bytes, packets, lastuse); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index ed75c6a85bc3..13af8e358847 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -397,8 +397,6 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_acl_ruleset *ruleset; struct mlxsw_sp_acl_rule *rule; - struct tc_action *a; - LIST_HEAD(actions); u64 packets; u64 lastuse; u64 bytes; @@ -419,13 +417,7 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, if (err) goto err_rule_get_stats; - preempt_disable(); - - tcf_exts_to_list(f->exts, &actions); - list_for_each_entry(a, &actions, list) - tcf_action_stats_update(a, bytes, packets, lastuse); - - preempt_enable(); + tcf_exts_stats_update(f->exts, bytes, packets, lastuse); mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset); return 0; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c b/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c index cc823df12c8a..2fa7b67d0c6f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c @@ -84,8 +84,6 @@ static void nfp_net_bpf_stats_reset(struct nfp_net *nn) static int nfp_net_bpf_stats_update(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) { - struct tc_action *a; - LIST_HEAD(actions); u64 bytes, pkts; pkts = nn->rx_filter.pkts - nn->rx_filter_prev.pkts; @@ -94,13 +92,8 @@ nfp_net_bpf_stats_update(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) nn->rx_filter_prev = nn->rx_filter; - preempt_disable(); - - tcf_exts_to_list(cls_bpf->exts, &actions); - list_for_each_entry(a, &actions, list) - tcf_action_stats_update(a, bytes, pkts, nn->rx_filter_change); - - preempt_enable(); + tcf_exts_stats_update(cls_bpf->exts, + bytes, pkts, nn->rx_filter_change); return 0; } -- cgit v1.2.3 From 5c9143598ea1a5f7a92761966f0c65a459eef7b4 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2017 08:06:44 -0700 Subject: nfp: add missing fall through statements GCC 7 checks for fall through comments, add the two missing ones. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index c9a140376621..2bcf3e8330ea 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1687,8 +1687,10 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) continue; default: bpf_warn_invalid_xdp_action(act); + /* fall through */ case XDP_ABORTED: trace_xdp_exception(dp->netdev, xdp_prog, act); + /* fall through */ case XDP_DROP: nfp_net_rx_give_one(dp, rx_ring, rxbuf->frag, rxbuf->dma_addr); -- cgit v1.2.3 From 69394af5de15493fa7bb42ed123d51e713a88b3c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2017 08:06:45 -0700 Subject: nfp: turn reading PCIe RTsym parameters into a helper Turn the function to read number of ports into a generic helper. While at it make sure we propagate all errors other than -ENOENT. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 24 ++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 388759e047d8..55a4a334cf6b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -191,26 +191,32 @@ nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id) return NULL; } -static unsigned int nfp_net_pf_get_num_ports(struct nfp_pf *pf) +static int +nfp_net_pf_rtsym_read_optional(struct nfp_pf *pf, const char *format, + unsigned int default_val) { char name[256]; int err = 0; u64 val; - snprintf(name, sizeof(name), "nfd_cfg_pf%u_num_ports", - nfp_cppcore_pcie_unit(pf->cpp)); + snprintf(name, sizeof(name), format, nfp_cppcore_pcie_unit(pf->cpp)); val = nfp_rtsym_read_le(pf->cpp, name, &err); - /* Default to one port/vNIC */ if (err) { - if (err != -ENOENT) - nfp_err(pf->cpp, "Unable to read adapter vNIC count\n"); - val = 1; + if (err == -ENOENT) + return default_val; + nfp_err(pf->cpp, "Unable to read symbol %s\n", name); + return err; } return val; } +static int nfp_net_pf_get_num_ports(struct nfp_pf *pf) +{ + return nfp_net_pf_rtsym_read_optional(pf, "nfd_cfg_pf%u_num_ports", 1); +} + static unsigned int nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar, unsigned int stride, u32 start_off, u32 num_off) @@ -675,6 +681,10 @@ int nfp_net_pci_probe(struct nfp_pf *pf) mutex_lock(&pf->lock); pf->max_data_vnics = nfp_net_pf_get_num_ports(pf); + if ((int)pf->max_data_vnics < 0) { + err = pf->max_data_vnics; + goto err_unlock; + } ctrl_bar = nfp_net_pf_map_ctrl_bar(pf); if (!ctrl_bar) { -- cgit v1.2.3 From 8aa0cb00743a1767013a5ee0a581db62620aabd7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2017 08:06:46 -0700 Subject: nfp: move port init to apps Start fleshing out the apps by turning the vNIC init code to a per-app callback. The two initial apps we have are NIC and eBPF. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 5 +- drivers/net/ethernet/netronome/nfp/bpf/main.c | 58 +++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_app.c | 21 +++++- drivers/net/ethernet/netronome/nfp/nfp_app.h | 50 ++++++++++++- drivers/net/ethernet/netronome/nfp/nfp_app_nic.c | 86 +++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_main.h | 6 ++ drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 61 ++++++++-------- drivers/net/ethernet/netronome/nfp/nic/main.c | 57 +++++++++++++++ 8 files changed, 309 insertions(+), 35 deletions(-) create mode 100644 drivers/net/ethernet/netronome/nfp/bpf/main.c create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_app_nic.c create mode 100644 drivers/net/ethernet/netronome/nfp/nic/main.c (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 83039c65e061..bbbfc19e5887 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -15,6 +15,7 @@ nfp-objs := \ nfpcore/nfp_rtsym.o \ nfpcore/nfp_target.o \ nfp_app.o \ + nfp_app_nic.o \ nfp_devlink.o \ nfp_hwmon.o \ nfp_main.o \ @@ -23,7 +24,9 @@ nfp-objs := \ nfp_net_offload.o \ nfp_net_main.o \ nfp_netvf_main.o \ - nfp_port.o + nfp_port.o \ + bpf/main.o \ + nic/main.o ifeq ($(CONFIG_BPF_SYSCALL),y) nfp-objs += \ diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c new file mode 100644 index 000000000000..63b4769c58c2 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../nfpcore/nfp_cpp.h" +#include "../nfp_app.h" +#include "../nfp_main.h" +#include "../nfp_net.h" +#include "../nfp_port.h" + +static int +nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) +{ + /* Limit to single port, otherwise it's just a NIC */ + if (id > 0) { + nfp_warn(app->cpp, + "BPF NIC doesn't support more than one port right now\n"); + nn->port = nfp_port_alloc(app, NFP_PORT_INVALID, nn->dp.netdev); + return PTR_ERR_OR_ZERO(nn->port); + } + + return nfp_app_nic_vnic_init(app, nn, id); +} + +const struct nfp_app_type app_bpf = { + .id = NFP_APP_BPF_NIC, + + .vnic_init = nfp_bpf_vnic_init, +}; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index 59be638bb60e..30687d87ae51 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -33,12 +33,30 @@ #include +#include "nfpcore/nfp_cpp.h" #include "nfp_app.h" #include "nfp_main.h" -struct nfp_app *nfp_app_alloc(struct nfp_pf *pf) +static const struct nfp_app_type *apps[] = { + &app_nic, + &app_bpf, +}; + +struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id) { struct nfp_app *app; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(apps); i++) + if (apps[i]->id == id) + break; + if (i == ARRAY_SIZE(apps)) { + nfp_err(pf->cpp, "failed to find app with ID 0x%02hhx\n", id); + return ERR_PTR(-EINVAL); + } + + if (WARN_ON(!apps[i]->vnic_init)) + return ERR_PTR(-EINVAL); app = kzalloc(sizeof(*app), GFP_KERNEL); if (!app) @@ -47,6 +65,7 @@ struct nfp_app *nfp_app_alloc(struct nfp_pf *pf) app->pf = pf; app->cpp = pf->cpp; app->pdev = pf->pdev; + app->type = apps[i]; return app; } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index e63425c02c8d..98dd5773e7cc 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -35,22 +35,70 @@ #define _NFP_APP_H 1 struct pci_dev; +struct nfp_app; struct nfp_cpp; struct nfp_pf; +struct nfp_net; + +enum nfp_app_id { + NFP_APP_CORE_NIC = 0x1, + NFP_APP_BPF_NIC = 0x2, +}; + +extern const struct nfp_app_type app_nic; +extern const struct nfp_app_type app_bpf; + +/** + * struct nfp_app_type - application definition + * @id: application ID + * + * Callbacks + * @init: perform basic app checks + * @vnic_init: init vNICs (assign port types, etc.) + */ +struct nfp_app_type { + enum nfp_app_id id; + + int (*init)(struct nfp_app *app); + + int (*vnic_init)(struct nfp_app *app, struct nfp_net *nn, + unsigned int id); +}; /** * struct nfp_app - NFP application container * @pdev: backpointer to PCI device * @pf: backpointer to NFP PF structure * @cpp: pointer to the CPP handle + * @type: pointer to const application ops and info */ struct nfp_app { struct pci_dev *pdev; struct nfp_pf *pf; struct nfp_cpp *cpp; + + const struct nfp_app_type *type; }; -struct nfp_app *nfp_app_alloc(struct nfp_pf *pf); +static inline int nfp_app_init(struct nfp_app *app) +{ + if (!app->type->init) + return 0; + return app->type->init(app); +} + +static inline int nfp_app_vnic_init(struct nfp_app *app, struct nfp_net *nn, + unsigned int id) +{ + return app->type->vnic_init(app, nn, id); +} + +struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id); void nfp_app_free(struct nfp_app *app); +/* Callbacks shared between apps */ + +int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn, + unsigned int id); + #endif diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c new file mode 100644 index 000000000000..1a33ad9f4170 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "nfpcore/nfp_cpp.h" +#include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" +#include "nfp_main.h" +#include "nfp_net.h" +#include "nfp_port.h" + +static int +nfp_app_nic_vnic_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, + struct nfp_net *nn, unsigned int id) +{ + if (!pf->eth_tbl) + return 0; + + nn->port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, nn->dp.netdev); + if (IS_ERR(nn->port)) + return PTR_ERR(nn->port); + + nn->port->eth_id = id; + nn->port->eth_port = nfp_net_find_port(pf->eth_tbl, id); + + /* Check if vNIC has external port associated and cfg is OK */ + if (!nn->port->eth_port) { + nfp_err(app->cpp, + "NSP port entries don't match vNICs (no entry for port #%d)\n", + id); + nfp_port_free(nn->port); + return -EINVAL; + } + if (nn->port->eth_port->override_changed) { + nfp_warn(app->cpp, + "Config changed for port #%d, reboot required before port will be operational\n", + id); + nn->port->type = NFP_PORT_INVALID; + return 1; + } + + return 0; +} + +int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn, + unsigned int id) +{ + int err; + + err = nfp_app_nic_vnic_init_phy_port(app->pf, app, nn, id); + if (err) + return err < 0 ? err : 0; + + nfp_net_get_mac_addr(nn, app->cpp, id); + + return 0; +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 20fad76da5aa..c46d00bbf19d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -54,6 +54,7 @@ struct pci_dev; struct nfp_cpp; struct nfp_cpp_area; struct nfp_eth_table; +struct nfp_net; struct nfp_nsp_identify; /** @@ -123,4 +124,9 @@ void nfp_net_pci_remove(struct nfp_pf *pf); int nfp_hwmon_register(struct nfp_pf *pf); void nfp_hwmon_unregister(struct nfp_pf *pf); +struct nfp_eth_table_port * +nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id); +void +nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id); + #endif /* NFP_MAIN_H */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 55a4a334cf6b..28782bf3ce68 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -141,7 +141,7 @@ err_area: * First try to get the MAC address from NSP ETH table. If that * fails try HWInfo. As a last resort generate a random address. */ -static void +void nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id) { struct nfp_eth_table_port *eth_port; @@ -179,7 +179,7 @@ nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id) ether_addr_copy(dp->netdev->perm_addr, mac_addr); } -static struct nfp_eth_table_port * +struct nfp_eth_table_port * nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id) { int i; @@ -217,6 +217,12 @@ static int nfp_net_pf_get_num_ports(struct nfp_pf *pf) return nfp_net_pf_rtsym_read_optional(pf, "nfd_cfg_pf%u_num_ports", 1); } +static int nfp_net_pf_get_app_id(struct nfp_pf *pf) +{ + return nfp_net_pf_rtsym_read_optional(pf, "_pf%u_net_app_id", + NFP_APP_CORE_NIC); +} + static unsigned int nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar, unsigned int stride, u32 start_off, u32 num_off) @@ -302,9 +308,9 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, int stride, struct nfp_net_fw_version *fw_ver, unsigned int eth_id) { - struct nfp_eth_table_port *eth_port; u32 n_tx_rings, n_rx_rings; struct nfp_net *nn; + int err; n_tx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_TXRINGS); n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS); @@ -323,16 +329,10 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, nn->stride_rx = stride; nn->stride_tx = stride; - eth_port = nfp_net_find_port(pf->eth_tbl, eth_id); - if (eth_port) { - nn->port = nfp_port_alloc(pf->app, NFP_PORT_PHYS_PORT, - nn->dp.netdev); - if (IS_ERR(nn->port)) { - nfp_net_free(nn); - return ERR_CAST(nn->port); - } - nn->port->eth_id = eth_id; - nn->port->eth_port = eth_port; + err = nfp_app_vnic_init(pf->app, nn, eth_id); + if (err) { + nfp_net_free(nn); + return ERR_PTR(err); } pf->num_vnics++; @@ -346,9 +346,6 @@ nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id) { int err; - /* Get MAC address */ - nfp_net_get_mac_addr(nn, pf->cpp, id); - /* Get ME clock frequency from ctrl BAR * XXX for now frequency is hardcoded until we figure out how * to get the value from nfp-hwinfo into ctrl bar @@ -387,12 +384,6 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, unsigned int i; int err; - if (pf->eth_tbl && pf->max_data_vnics != pf->eth_tbl->count) { - nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n", - pf->max_data_vnics, pf->eth_tbl->count); - return -EINVAL; - } - prev_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); prev_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); @@ -413,14 +404,8 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, ctrl_bar += NFP_PF_CSR_SLICE_SIZE; - /* Check if vNIC has external port associated and cfg is OK */ - if (pf->eth_tbl && !nn->port) { - nfp_err(pf->cpp, "NSP port entries don't match vNICs (no entry for port #%d)\n", i); - err = -EINVAL; - goto err_free_prev; - } - if (nn->port && nn->port->eth_port->override_changed) { - nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i); + /* Kill the vNIC if app init marked it as invalid */ + if (nn->port && nn->port->type == NFP_PORT_INVALID) { nfp_net_pf_free_vnic(pf, nn); continue; } @@ -518,9 +503,21 @@ err_nn_free: static int nfp_net_pf_app_init(struct nfp_pf *pf) { - pf->app = nfp_app_alloc(pf); + int err; + + pf->app = nfp_app_alloc(pf, nfp_net_pf_get_app_id(pf)); + if (IS_ERR(pf->app)) + return PTR_ERR(pf->app); - return PTR_ERR_OR_ZERO(pf->app); + err = nfp_app_init(pf->app); + if (err) + goto err_free; + + return 0; + +err_free: + nfp_app_free(pf->app); + return err; } static void nfp_net_pf_app_clean(struct nfp_pf *pf) diff --git a/drivers/net/ethernet/netronome/nfp/nic/main.c b/drivers/net/ethernet/netronome/nfp/nic/main.c new file mode 100644 index 000000000000..6a5b30667248 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nic/main.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../nfpcore/nfp_cpp.h" +#include "../nfpcore/nfp_nsp.h" +#include "../nfp_app.h" +#include "../nfp_main.h" + +static int nfp_nic_init(struct nfp_app *app) +{ + struct nfp_pf *pf = app->pf; + + if (pf->eth_tbl && pf->max_data_vnics != pf->eth_tbl->count) { + nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n", + pf->max_data_vnics, pf->eth_tbl->count); + return -EINVAL; + } + + return 0; +} + +const struct nfp_app_type app_nic = { + .id = NFP_APP_CORE_NIC, + + .init = nfp_nic_init, + .vnic_init = nfp_app_nic_vnic_init, +}; -- cgit v1.2.3 From 2707d6f18baa8a8ff2cabddfb324d0be7f512fe5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2017 08:06:47 -0700 Subject: nfp: report app name in ethtool -i Let the app print its name in ethtool -i output. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/bpf/main.c | 1 + drivers/net/ethernet/netronome/nfp/nfp_app.c | 2 +- drivers/net/ethernet/netronome/nfp/nfp_app.h | 9 +++++++++ drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 5 +++-- drivers/net/ethernet/netronome/nfp/nic/main.c | 1 + 5 files changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index 63b4769c58c2..d91d72e22dc8 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -53,6 +53,7 @@ nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) const struct nfp_app_type app_bpf = { .id = NFP_APP_BPF_NIC, + .name = "ebpf", .vnic_init = nfp_bpf_vnic_init, }; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index 30687d87ae51..cea2090cf063 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -55,7 +55,7 @@ struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id) return ERR_PTR(-EINVAL); } - if (WARN_ON(!apps[i]->vnic_init)) + if (WARN_ON(!apps[i]->name || !apps[i]->vnic_init)) return ERR_PTR(-EINVAL); app = kzalloc(sizeof(*app), GFP_KERNEL); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index 98dd5773e7cc..b5426398f29e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -51,6 +51,7 @@ extern const struct nfp_app_type app_bpf; /** * struct nfp_app_type - application definition * @id: application ID + * @name: application name * * Callbacks * @init: perform basic app checks @@ -58,6 +59,7 @@ extern const struct nfp_app_type app_bpf; */ struct nfp_app_type { enum nfp_app_id id; + const char *name; int (*init)(struct nfp_app *app); @@ -93,6 +95,13 @@ static inline int nfp_app_vnic_init(struct nfp_app *app, struct nfp_net *nn, return app->type->vnic_init(app, nn, id); } +static inline const char *nfp_app_name(struct nfp_app *app) +{ + if (!app) + return ""; + return app->type->name; +} + struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id); void nfp_app_free(struct nfp_app *app); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 84fdbc4b835b..83664ca25213 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -166,9 +166,10 @@ static void nfp_net_get_drvinfo(struct net_device *netdev, nfp_net_get_nspinfo(nn->app, nsp_version); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), - "%d.%d.%d.%d %s", + "%d.%d.%d.%d %s %s", nn->fw_ver.resv, nn->fw_ver.class, - nn->fw_ver.major, nn->fw_ver.minor, nsp_version); + nn->fw_ver.major, nn->fw_ver.minor, nsp_version, + nfp_app_name(nn->app)); strlcpy(drvinfo->bus_info, pci_name(nn->pdev), sizeof(drvinfo->bus_info)); diff --git a/drivers/net/ethernet/netronome/nfp/nic/main.c b/drivers/net/ethernet/netronome/nfp/nic/main.c index 6a5b30667248..520684242b7d 100644 --- a/drivers/net/ethernet/netronome/nfp/nic/main.c +++ b/drivers/net/ethernet/netronome/nfp/nic/main.c @@ -51,6 +51,7 @@ static int nfp_nic_init(struct nfp_app *app) const struct nfp_app_type app_nic = { .id = NFP_APP_CORE_NIC, + .name = "nic", .init = nfp_nic_init, .vnic_init = nfp_app_nic_vnic_init, -- cgit v1.2.3 From d9ae7f2bfead4600e85459be93082ca8b1c884f9 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2017 08:06:48 -0700 Subject: nfp: move eBPF offload files to BPF app directory Pure move of eBPF offload files to BPF app directory, only change the names and relative header location. nfp_asm.h stays in the main dir and it doesn't really have to include nfp_bpf.h. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 6 +- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 1899 ++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/bpf/main.h | 201 +++ drivers/net/ethernet/netronome/nfp/bpf/offload.c | 287 +++ drivers/net/ethernet/netronome/nfp/bpf/verifier.c | 174 ++ drivers/net/ethernet/netronome/nfp/nfp_asm.h | 2 +- drivers/net/ethernet/netronome/nfp/nfp_bpf.h | 201 --- drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c | 1899 -------------------- .../net/ethernet/netronome/nfp/nfp_bpf_verifier.c | 174 -- .../net/ethernet/netronome/nfp/nfp_net_offload.c | 287 --- 10 files changed, 2565 insertions(+), 2565 deletions(-) create mode 100644 drivers/net/ethernet/netronome/nfp/bpf/jit.c create mode 100644 drivers/net/ethernet/netronome/nfp/bpf/main.h create mode 100644 drivers/net/ethernet/netronome/nfp/bpf/offload.c create mode 100644 drivers/net/ethernet/netronome/nfp/bpf/verifier.c delete mode 100644 drivers/net/ethernet/netronome/nfp/nfp_bpf.h delete mode 100644 drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c delete mode 100644 drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c delete mode 100644 drivers/net/ethernet/netronome/nfp/nfp_net_offload.c (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index bbbfc19e5887..5ad9a557f06a 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -21,17 +21,17 @@ nfp-objs := \ nfp_main.o \ nfp_net_common.o \ nfp_net_ethtool.o \ - nfp_net_offload.o \ nfp_net_main.o \ nfp_netvf_main.o \ nfp_port.o \ bpf/main.o \ + bpf/offload.o \ nic/main.o ifeq ($(CONFIG_BPF_SYSCALL),y) nfp-objs += \ - nfp_bpf_verifier.o \ - nfp_bpf_jit.o + bpf/verifier.o \ + bpf/jit.o endif nfp-$(CONFIG_NFP_DEBUG) += nfp_net_debugfs.o diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c new file mode 100644 index 000000000000..8e57fda6b8b5 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -0,0 +1,1899 @@ +/* + * Copyright (C) 2016 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define pr_fmt(fmt) "NFP net bpf: " fmt + +#include +#include +#include +#include +#include + +#include "main.h" +#include "../nfp_asm.h" + +/* --- NFP prog --- */ +/* Foreach "multiple" entries macros provide pos and next pointers. + * It's safe to modify the next pointers (but not pos). + */ +#define nfp_for_each_insn_walk2(nfp_prog, pos, next) \ + for (pos = list_first_entry(&(nfp_prog)->insns, typeof(*pos), l), \ + next = list_next_entry(pos, l); \ + &(nfp_prog)->insns != &pos->l && \ + &(nfp_prog)->insns != &next->l; \ + pos = nfp_meta_next(pos), \ + next = nfp_meta_next(pos)) + +#define nfp_for_each_insn_walk3(nfp_prog, pos, next, next2) \ + for (pos = list_first_entry(&(nfp_prog)->insns, typeof(*pos), l), \ + next = list_next_entry(pos, l), \ + next2 = list_next_entry(next, l); \ + &(nfp_prog)->insns != &pos->l && \ + &(nfp_prog)->insns != &next->l && \ + &(nfp_prog)->insns != &next2->l; \ + pos = nfp_meta_next(pos), \ + next = nfp_meta_next(pos), \ + next2 = nfp_meta_next(next)) + +static bool +nfp_meta_has_next(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return meta->l.next != &nfp_prog->insns; +} + +static bool +nfp_meta_has_prev(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return meta->l.prev != &nfp_prog->insns; +} + +static void nfp_prog_free(struct nfp_prog *nfp_prog) +{ + struct nfp_insn_meta *meta, *tmp; + + list_for_each_entry_safe(meta, tmp, &nfp_prog->insns, l) { + list_del(&meta->l); + kfree(meta); + } + kfree(nfp_prog); +} + +static void nfp_prog_push(struct nfp_prog *nfp_prog, u64 insn) +{ + if (nfp_prog->__prog_alloc_len == nfp_prog->prog_len) { + nfp_prog->error = -ENOSPC; + return; + } + + nfp_prog->prog[nfp_prog->prog_len] = insn; + nfp_prog->prog_len++; +} + +static unsigned int nfp_prog_current_offset(struct nfp_prog *nfp_prog) +{ + return nfp_prog->start_off + nfp_prog->prog_len; +} + +static unsigned int +nfp_prog_offset_to_index(struct nfp_prog *nfp_prog, unsigned int offset) +{ + return offset - nfp_prog->start_off; +} + +/* --- SW reg --- */ +struct nfp_insn_ur_regs { + enum alu_dst_ab dst_ab; + u16 dst; + u16 areg, breg; + bool swap; + bool wr_both; +}; + +struct nfp_insn_re_regs { + enum alu_dst_ab dst_ab; + u8 dst; + u8 areg, breg; + bool swap; + bool wr_both; + bool i8; +}; + +static u16 nfp_swreg_to_unreg(u32 swreg, bool is_dst) +{ + u16 val = FIELD_GET(NN_REG_VAL, swreg); + + switch (FIELD_GET(NN_REG_TYPE, swreg)) { + case NN_REG_GPR_A: + case NN_REG_GPR_B: + case NN_REG_GPR_BOTH: + return val; + case NN_REG_NNR: + return UR_REG_NN | val; + case NN_REG_XFER: + return UR_REG_XFR | val; + case NN_REG_IMM: + if (val & ~0xff) { + pr_err("immediate too large\n"); + return 0; + } + return UR_REG_IMM_encode(val); + case NN_REG_NONE: + return is_dst ? UR_REG_NO_DST : REG_NONE; + default: + pr_err("unrecognized reg encoding %08x\n", swreg); + return 0; + } +} + +static int +swreg_to_unrestricted(u32 dst, u32 lreg, u32 rreg, struct nfp_insn_ur_regs *reg) +{ + memset(reg, 0, sizeof(*reg)); + + /* Decode destination */ + if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_IMM) + return -EFAULT; + + if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_GPR_B) + reg->dst_ab = ALU_DST_B; + if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_GPR_BOTH) + reg->wr_both = true; + reg->dst = nfp_swreg_to_unreg(dst, true); + + /* Decode source operands */ + if (FIELD_GET(NN_REG_TYPE, lreg) == FIELD_GET(NN_REG_TYPE, rreg)) + return -EFAULT; + + if (FIELD_GET(NN_REG_TYPE, lreg) == NN_REG_GPR_B || + FIELD_GET(NN_REG_TYPE, rreg) == NN_REG_GPR_A) { + reg->areg = nfp_swreg_to_unreg(rreg, false); + reg->breg = nfp_swreg_to_unreg(lreg, false); + reg->swap = true; + } else { + reg->areg = nfp_swreg_to_unreg(lreg, false); + reg->breg = nfp_swreg_to_unreg(rreg, false); + } + + return 0; +} + +static u16 nfp_swreg_to_rereg(u32 swreg, bool is_dst, bool has_imm8, bool *i8) +{ + u16 val = FIELD_GET(NN_REG_VAL, swreg); + + switch (FIELD_GET(NN_REG_TYPE, swreg)) { + case NN_REG_GPR_A: + case NN_REG_GPR_B: + case NN_REG_GPR_BOTH: + return val; + case NN_REG_XFER: + return RE_REG_XFR | val; + case NN_REG_IMM: + if (val & ~(0x7f | has_imm8 << 7)) { + pr_err("immediate too large\n"); + return 0; + } + *i8 = val & 0x80; + return RE_REG_IMM_encode(val & 0x7f); + case NN_REG_NONE: + return is_dst ? RE_REG_NO_DST : REG_NONE; + default: + pr_err("unrecognized reg encoding\n"); + return 0; + } +} + +static int +swreg_to_restricted(u32 dst, u32 lreg, u32 rreg, struct nfp_insn_re_regs *reg, + bool has_imm8) +{ + memset(reg, 0, sizeof(*reg)); + + /* Decode destination */ + if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_IMM) + return -EFAULT; + + if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_GPR_B) + reg->dst_ab = ALU_DST_B; + if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_GPR_BOTH) + reg->wr_both = true; + reg->dst = nfp_swreg_to_rereg(dst, true, false, NULL); + + /* Decode source operands */ + if (FIELD_GET(NN_REG_TYPE, lreg) == FIELD_GET(NN_REG_TYPE, rreg)) + return -EFAULT; + + if (FIELD_GET(NN_REG_TYPE, lreg) == NN_REG_GPR_B || + FIELD_GET(NN_REG_TYPE, rreg) == NN_REG_GPR_A) { + reg->areg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); + reg->breg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); + reg->swap = true; + } else { + reg->areg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); + reg->breg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); + } + + return 0; +} + +/* --- Emitters --- */ +static const struct cmd_tgt_act cmd_tgt_act[__CMD_TGT_MAP_SIZE] = { + [CMD_TGT_WRITE8] = { 0x00, 0x42 }, + [CMD_TGT_READ8] = { 0x01, 0x43 }, + [CMD_TGT_READ_LE] = { 0x01, 0x40 }, + [CMD_TGT_READ_SWAP_LE] = { 0x03, 0x40 }, +}; + +static void +__emit_cmd(struct nfp_prog *nfp_prog, enum cmd_tgt_map op, + u8 mode, u8 xfer, u8 areg, u8 breg, u8 size, bool sync) +{ + enum cmd_ctx_swap ctx; + u64 insn; + + if (sync) + ctx = CMD_CTX_SWAP; + else + ctx = CMD_CTX_NO_SWAP; + + insn = FIELD_PREP(OP_CMD_A_SRC, areg) | + FIELD_PREP(OP_CMD_CTX, ctx) | + FIELD_PREP(OP_CMD_B_SRC, breg) | + FIELD_PREP(OP_CMD_TOKEN, cmd_tgt_act[op].token) | + FIELD_PREP(OP_CMD_XFER, xfer) | + FIELD_PREP(OP_CMD_CNT, size) | + FIELD_PREP(OP_CMD_SIG, sync) | + FIELD_PREP(OP_CMD_TGT_CMD, cmd_tgt_act[op].tgt_cmd) | + FIELD_PREP(OP_CMD_MODE, mode); + + nfp_prog_push(nfp_prog, insn); +} + +static void +emit_cmd(struct nfp_prog *nfp_prog, enum cmd_tgt_map op, + u8 mode, u8 xfer, u32 lreg, u32 rreg, u8 size, bool sync) +{ + struct nfp_insn_re_regs reg; + int err; + + err = swreg_to_restricted(reg_none(), lreg, rreg, ®, false); + if (err) { + nfp_prog->error = err; + return; + } + if (reg.swap) { + pr_err("cmd can't swap arguments\n"); + nfp_prog->error = -EFAULT; + return; + } + + __emit_cmd(nfp_prog, op, mode, xfer, reg.areg, reg.breg, size, sync); +} + +static void +__emit_br(struct nfp_prog *nfp_prog, enum br_mask mask, enum br_ev_pip ev_pip, + enum br_ctx_signal_state css, u16 addr, u8 defer) +{ + u16 addr_lo, addr_hi; + u64 insn; + + addr_lo = addr & (OP_BR_ADDR_LO >> __bf_shf(OP_BR_ADDR_LO)); + addr_hi = addr != addr_lo; + + insn = OP_BR_BASE | + FIELD_PREP(OP_BR_MASK, mask) | + FIELD_PREP(OP_BR_EV_PIP, ev_pip) | + FIELD_PREP(OP_BR_CSS, css) | + FIELD_PREP(OP_BR_DEFBR, defer) | + FIELD_PREP(OP_BR_ADDR_LO, addr_lo) | + FIELD_PREP(OP_BR_ADDR_HI, addr_hi); + + nfp_prog_push(nfp_prog, insn); +} + +static void emit_br_def(struct nfp_prog *nfp_prog, u16 addr, u8 defer) +{ + if (defer > 2) { + pr_err("BUG: branch defer out of bounds %d\n", defer); + nfp_prog->error = -EFAULT; + return; + } + __emit_br(nfp_prog, BR_UNC, BR_EV_PIP_UNCOND, BR_CSS_NONE, addr, defer); +} + +static void +emit_br(struct nfp_prog *nfp_prog, enum br_mask mask, u16 addr, u8 defer) +{ + __emit_br(nfp_prog, mask, + mask != BR_UNC ? BR_EV_PIP_COND : BR_EV_PIP_UNCOND, + BR_CSS_NONE, addr, defer); +} + +static void +__emit_br_byte(struct nfp_prog *nfp_prog, u8 areg, u8 breg, bool imm8, + u8 byte, bool equal, u16 addr, u8 defer) +{ + u16 addr_lo, addr_hi; + u64 insn; + + addr_lo = addr & (OP_BB_ADDR_LO >> __bf_shf(OP_BB_ADDR_LO)); + addr_hi = addr != addr_lo; + + insn = OP_BBYTE_BASE | + FIELD_PREP(OP_BB_A_SRC, areg) | + FIELD_PREP(OP_BB_BYTE, byte) | + FIELD_PREP(OP_BB_B_SRC, breg) | + FIELD_PREP(OP_BB_I8, imm8) | + FIELD_PREP(OP_BB_EQ, equal) | + FIELD_PREP(OP_BB_DEFBR, defer) | + FIELD_PREP(OP_BB_ADDR_LO, addr_lo) | + FIELD_PREP(OP_BB_ADDR_HI, addr_hi); + + nfp_prog_push(nfp_prog, insn); +} + +static void +emit_br_byte_neq(struct nfp_prog *nfp_prog, + u32 dst, u8 imm, u8 byte, u16 addr, u8 defer) +{ + struct nfp_insn_re_regs reg; + int err; + + err = swreg_to_restricted(reg_none(), dst, reg_imm(imm), ®, true); + if (err) { + nfp_prog->error = err; + return; + } + + __emit_br_byte(nfp_prog, reg.areg, reg.breg, reg.i8, byte, false, addr, + defer); +} + +static void +__emit_immed(struct nfp_prog *nfp_prog, u16 areg, u16 breg, u16 imm_hi, + enum immed_width width, bool invert, + enum immed_shift shift, bool wr_both) +{ + u64 insn; + + insn = OP_IMMED_BASE | + FIELD_PREP(OP_IMMED_A_SRC, areg) | + FIELD_PREP(OP_IMMED_B_SRC, breg) | + FIELD_PREP(OP_IMMED_IMM, imm_hi) | + FIELD_PREP(OP_IMMED_WIDTH, width) | + FIELD_PREP(OP_IMMED_INV, invert) | + FIELD_PREP(OP_IMMED_SHIFT, shift) | + FIELD_PREP(OP_IMMED_WR_AB, wr_both); + + nfp_prog_push(nfp_prog, insn); +} + +static void +emit_immed(struct nfp_prog *nfp_prog, u32 dst, u16 imm, + enum immed_width width, bool invert, enum immed_shift shift) +{ + struct nfp_insn_ur_regs reg; + int err; + + if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_IMM) { + nfp_prog->error = -EFAULT; + return; + } + + err = swreg_to_unrestricted(dst, dst, reg_imm(imm & 0xff), ®); + if (err) { + nfp_prog->error = err; + return; + } + + __emit_immed(nfp_prog, reg.areg, reg.breg, imm >> 8, width, + invert, shift, reg.wr_both); +} + +static void +__emit_shf(struct nfp_prog *nfp_prog, u16 dst, enum alu_dst_ab dst_ab, + enum shf_sc sc, u8 shift, + u16 areg, enum shf_op op, u16 breg, bool i8, bool sw, bool wr_both) +{ + u64 insn; + + if (!FIELD_FIT(OP_SHF_SHIFT, shift)) { + nfp_prog->error = -EFAULT; + return; + } + + if (sc == SHF_SC_L_SHF) + shift = 32 - shift; + + insn = OP_SHF_BASE | + FIELD_PREP(OP_SHF_A_SRC, areg) | + FIELD_PREP(OP_SHF_SC, sc) | + FIELD_PREP(OP_SHF_B_SRC, breg) | + FIELD_PREP(OP_SHF_I8, i8) | + FIELD_PREP(OP_SHF_SW, sw) | + FIELD_PREP(OP_SHF_DST, dst) | + FIELD_PREP(OP_SHF_SHIFT, shift) | + FIELD_PREP(OP_SHF_OP, op) | + FIELD_PREP(OP_SHF_DST_AB, dst_ab) | + FIELD_PREP(OP_SHF_WR_AB, wr_both); + + nfp_prog_push(nfp_prog, insn); +} + +static void +emit_shf(struct nfp_prog *nfp_prog, u32 dst, u32 lreg, enum shf_op op, u32 rreg, + enum shf_sc sc, u8 shift) +{ + struct nfp_insn_re_regs reg; + int err; + + err = swreg_to_restricted(dst, lreg, rreg, ®, true); + if (err) { + nfp_prog->error = err; + return; + } + + __emit_shf(nfp_prog, reg.dst, reg.dst_ab, sc, shift, + reg.areg, op, reg.breg, reg.i8, reg.swap, reg.wr_both); +} + +static void +__emit_alu(struct nfp_prog *nfp_prog, u16 dst, enum alu_dst_ab dst_ab, + u16 areg, enum alu_op op, u16 breg, bool swap, bool wr_both) +{ + u64 insn; + + insn = OP_ALU_BASE | + FIELD_PREP(OP_ALU_A_SRC, areg) | + FIELD_PREP(OP_ALU_B_SRC, breg) | + FIELD_PREP(OP_ALU_DST, dst) | + FIELD_PREP(OP_ALU_SW, swap) | + FIELD_PREP(OP_ALU_OP, op) | + FIELD_PREP(OP_ALU_DST_AB, dst_ab) | + FIELD_PREP(OP_ALU_WR_AB, wr_both); + + nfp_prog_push(nfp_prog, insn); +} + +static void +emit_alu(struct nfp_prog *nfp_prog, u32 dst, u32 lreg, enum alu_op op, u32 rreg) +{ + struct nfp_insn_ur_regs reg; + int err; + + err = swreg_to_unrestricted(dst, lreg, rreg, ®); + if (err) { + nfp_prog->error = err; + return; + } + + __emit_alu(nfp_prog, reg.dst, reg.dst_ab, + reg.areg, op, reg.breg, reg.swap, reg.wr_both); +} + +static void +__emit_ld_field(struct nfp_prog *nfp_prog, enum shf_sc sc, + u8 areg, u8 bmask, u8 breg, u8 shift, bool imm8, + bool zero, bool swap, bool wr_both) +{ + u64 insn; + + insn = OP_LDF_BASE | + FIELD_PREP(OP_LDF_A_SRC, areg) | + FIELD_PREP(OP_LDF_SC, sc) | + FIELD_PREP(OP_LDF_B_SRC, breg) | + FIELD_PREP(OP_LDF_I8, imm8) | + FIELD_PREP(OP_LDF_SW, swap) | + FIELD_PREP(OP_LDF_ZF, zero) | + FIELD_PREP(OP_LDF_BMASK, bmask) | + FIELD_PREP(OP_LDF_SHF, shift) | + FIELD_PREP(OP_LDF_WR_AB, wr_both); + + nfp_prog_push(nfp_prog, insn); +} + +static void +emit_ld_field_any(struct nfp_prog *nfp_prog, enum shf_sc sc, u8 shift, + u32 dst, u8 bmask, u32 src, bool zero) +{ + struct nfp_insn_re_regs reg; + int err; + + err = swreg_to_restricted(reg_none(), dst, src, ®, true); + if (err) { + nfp_prog->error = err; + return; + } + + __emit_ld_field(nfp_prog, sc, reg.areg, bmask, reg.breg, shift, + reg.i8, zero, reg.swap, reg.wr_both); +} + +static void +emit_ld_field(struct nfp_prog *nfp_prog, u32 dst, u8 bmask, u32 src, + enum shf_sc sc, u8 shift) +{ + emit_ld_field_any(nfp_prog, sc, shift, dst, bmask, src, false); +} + +/* --- Wrappers --- */ +static bool pack_immed(u32 imm, u16 *val, enum immed_shift *shift) +{ + if (!(imm & 0xffff0000)) { + *val = imm; + *shift = IMMED_SHIFT_0B; + } else if (!(imm & 0xff0000ff)) { + *val = imm >> 8; + *shift = IMMED_SHIFT_1B; + } else if (!(imm & 0x0000ffff)) { + *val = imm >> 16; + *shift = IMMED_SHIFT_2B; + } else { + return false; + } + + return true; +} + +static void wrp_immed(struct nfp_prog *nfp_prog, u32 dst, u32 imm) +{ + enum immed_shift shift; + u16 val; + + if (pack_immed(imm, &val, &shift)) { + emit_immed(nfp_prog, dst, val, IMMED_WIDTH_ALL, false, shift); + } else if (pack_immed(~imm, &val, &shift)) { + emit_immed(nfp_prog, dst, val, IMMED_WIDTH_ALL, true, shift); + } else { + emit_immed(nfp_prog, dst, imm & 0xffff, IMMED_WIDTH_ALL, + false, IMMED_SHIFT_0B); + emit_immed(nfp_prog, dst, imm >> 16, IMMED_WIDTH_WORD, + false, IMMED_SHIFT_2B); + } +} + +/* ur_load_imm_any() - encode immediate or use tmp register (unrestricted) + * If the @imm is small enough encode it directly in operand and return + * otherwise load @imm to a spare register and return its encoding. + */ +static u32 ur_load_imm_any(struct nfp_prog *nfp_prog, u32 imm, u32 tmp_reg) +{ + if (FIELD_FIT(UR_REG_IMM_MAX, imm)) + return reg_imm(imm); + + wrp_immed(nfp_prog, tmp_reg, imm); + return tmp_reg; +} + +/* re_load_imm_any() - encode immediate or use tmp register (restricted) + * If the @imm is small enough encode it directly in operand and return + * otherwise load @imm to a spare register and return its encoding. + */ +static u32 re_load_imm_any(struct nfp_prog *nfp_prog, u32 imm, u32 tmp_reg) +{ + if (FIELD_FIT(RE_REG_IMM_MAX, imm)) + return reg_imm(imm); + + wrp_immed(nfp_prog, tmp_reg, imm); + return tmp_reg; +} + +static void +wrp_br_special(struct nfp_prog *nfp_prog, enum br_mask mask, + enum br_special special) +{ + emit_br(nfp_prog, mask, 0, 0); + + nfp_prog->prog[nfp_prog->prog_len - 1] |= + FIELD_PREP(OP_BR_SPECIAL, special); +} + +static void wrp_reg_mov(struct nfp_prog *nfp_prog, u16 dst, u16 src) +{ + emit_alu(nfp_prog, reg_both(dst), reg_none(), ALU_OP_NONE, reg_b(src)); +} + +static int +construct_data_ind_ld(struct nfp_prog *nfp_prog, u16 offset, + u16 src, bool src_valid, u8 size) +{ + unsigned int i; + u16 shift, sz; + u32 tmp_reg; + + /* We load the value from the address indicated in @offset and then + * shift out the data we don't need. Note: this is big endian! + */ + sz = size < 4 ? 4 : size; + shift = size < 4 ? 4 - size : 0; + + if (src_valid) { + /* Calculate the true offset (src_reg + imm) */ + tmp_reg = ur_load_imm_any(nfp_prog, offset, imm_b(nfp_prog)); + emit_alu(nfp_prog, imm_both(nfp_prog), + reg_a(src), ALU_OP_ADD, tmp_reg); + /* Check packet length (size guaranteed to fit b/c it's u8) */ + emit_alu(nfp_prog, imm_a(nfp_prog), + imm_a(nfp_prog), ALU_OP_ADD, reg_imm(size)); + emit_alu(nfp_prog, reg_none(), + NFP_BPF_ABI_LEN, ALU_OP_SUB, imm_a(nfp_prog)); + wrp_br_special(nfp_prog, BR_BLO, OP_BR_GO_ABORT); + /* Load data */ + emit_cmd(nfp_prog, CMD_TGT_READ8, CMD_MODE_32b, 0, + pkt_reg(nfp_prog), imm_b(nfp_prog), sz - 1, true); + } else { + /* Check packet length */ + tmp_reg = ur_load_imm_any(nfp_prog, offset + size, + imm_a(nfp_prog)); + emit_alu(nfp_prog, reg_none(), + NFP_BPF_ABI_LEN, ALU_OP_SUB, tmp_reg); + wrp_br_special(nfp_prog, BR_BLO, OP_BR_GO_ABORT); + /* Load data */ + tmp_reg = re_load_imm_any(nfp_prog, offset, imm_b(nfp_prog)); + emit_cmd(nfp_prog, CMD_TGT_READ8, CMD_MODE_32b, 0, + pkt_reg(nfp_prog), tmp_reg, sz - 1, true); + } + + i = 0; + if (shift) + emit_shf(nfp_prog, reg_both(0), reg_none(), SHF_OP_NONE, + reg_xfer(0), SHF_SC_R_SHF, shift * 8); + else + for (; i * 4 < size; i++) + emit_alu(nfp_prog, reg_both(i), + reg_none(), ALU_OP_NONE, reg_xfer(i)); + + if (i < 2) + wrp_immed(nfp_prog, reg_both(1), 0); + + return 0; +} + +static int construct_data_ld(struct nfp_prog *nfp_prog, u16 offset, u8 size) +{ + return construct_data_ind_ld(nfp_prog, offset, 0, false, size); +} + +static int wrp_set_mark(struct nfp_prog *nfp_prog, u8 src) +{ + emit_alu(nfp_prog, NFP_BPF_ABI_MARK, + reg_none(), ALU_OP_NONE, reg_b(src)); + emit_alu(nfp_prog, NFP_BPF_ABI_FLAGS, + NFP_BPF_ABI_FLAGS, ALU_OP_OR, reg_imm(NFP_BPF_ABI_FLAG_MARK)); + + return 0; +} + +static void +wrp_alu_imm(struct nfp_prog *nfp_prog, u8 dst, enum alu_op alu_op, u32 imm) +{ + u32 tmp_reg; + + if (alu_op == ALU_OP_AND) { + if (!imm) + wrp_immed(nfp_prog, reg_both(dst), 0); + if (!imm || !~imm) + return; + } + if (alu_op == ALU_OP_OR) { + if (!~imm) + wrp_immed(nfp_prog, reg_both(dst), ~0U); + if (!imm || !~imm) + return; + } + if (alu_op == ALU_OP_XOR) { + if (!~imm) + emit_alu(nfp_prog, reg_both(dst), reg_none(), + ALU_OP_NEG, reg_b(dst)); + if (!imm || !~imm) + return; + } + + tmp_reg = ur_load_imm_any(nfp_prog, imm, imm_b(nfp_prog)); + emit_alu(nfp_prog, reg_both(dst), reg_a(dst), alu_op, tmp_reg); +} + +static int +wrp_alu64_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, + enum alu_op alu_op, bool skip) +{ + const struct bpf_insn *insn = &meta->insn; + u64 imm = insn->imm; /* sign extend */ + + if (skip) { + meta->skip = true; + return 0; + } + + wrp_alu_imm(nfp_prog, insn->dst_reg * 2, alu_op, imm & ~0U); + wrp_alu_imm(nfp_prog, insn->dst_reg * 2 + 1, alu_op, imm >> 32); + + return 0; +} + +static int +wrp_alu64_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, + enum alu_op alu_op) +{ + u8 dst = meta->insn.dst_reg * 2, src = meta->insn.src_reg * 2; + + emit_alu(nfp_prog, reg_both(dst), reg_a(dst), alu_op, reg_b(src)); + emit_alu(nfp_prog, reg_both(dst + 1), + reg_a(dst + 1), alu_op, reg_b(src + 1)); + + return 0; +} + +static int +wrp_alu32_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, + enum alu_op alu_op, bool skip) +{ + const struct bpf_insn *insn = &meta->insn; + + if (skip) { + meta->skip = true; + return 0; + } + + wrp_alu_imm(nfp_prog, insn->dst_reg * 2, alu_op, insn->imm); + wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); + + return 0; +} + +static int +wrp_alu32_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, + enum alu_op alu_op) +{ + u8 dst = meta->insn.dst_reg * 2, src = meta->insn.src_reg * 2; + + emit_alu(nfp_prog, reg_both(dst), reg_a(dst), alu_op, reg_b(src)); + wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2 + 1), 0); + + return 0; +} + +static void +wrp_test_reg_one(struct nfp_prog *nfp_prog, u8 dst, enum alu_op alu_op, u8 src, + enum br_mask br_mask, u16 off) +{ + emit_alu(nfp_prog, reg_none(), reg_a(dst), alu_op, reg_b(src)); + emit_br(nfp_prog, br_mask, off, 0); +} + +static int +wrp_test_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, + enum alu_op alu_op, enum br_mask br_mask) +{ + const struct bpf_insn *insn = &meta->insn; + + if (insn->off < 0) /* TODO */ + return -EOPNOTSUPP; + + wrp_test_reg_one(nfp_prog, insn->dst_reg * 2, alu_op, + insn->src_reg * 2, br_mask, insn->off); + wrp_test_reg_one(nfp_prog, insn->dst_reg * 2 + 1, alu_op, + insn->src_reg * 2 + 1, br_mask, insn->off); + + return 0; +} + +static int +wrp_cmp_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, + enum br_mask br_mask, bool swap) +{ + const struct bpf_insn *insn = &meta->insn; + u64 imm = insn->imm; /* sign extend */ + u8 reg = insn->dst_reg * 2; + u32 tmp_reg; + + if (insn->off < 0) /* TODO */ + return -EOPNOTSUPP; + + tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); + if (!swap) + emit_alu(nfp_prog, reg_none(), reg_a(reg), ALU_OP_SUB, tmp_reg); + else + emit_alu(nfp_prog, reg_none(), tmp_reg, ALU_OP_SUB, reg_a(reg)); + + tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); + if (!swap) + emit_alu(nfp_prog, reg_none(), + reg_a(reg + 1), ALU_OP_SUB_C, tmp_reg); + else + emit_alu(nfp_prog, reg_none(), + tmp_reg, ALU_OP_SUB_C, reg_a(reg + 1)); + + emit_br(nfp_prog, br_mask, insn->off, 0); + + return 0; +} + +static int +wrp_cmp_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, + enum br_mask br_mask, bool swap) +{ + const struct bpf_insn *insn = &meta->insn; + u8 areg = insn->src_reg * 2, breg = insn->dst_reg * 2; + + if (insn->off < 0) /* TODO */ + return -EOPNOTSUPP; + + if (swap) { + areg ^= breg; + breg ^= areg; + areg ^= breg; + } + + emit_alu(nfp_prog, reg_none(), reg_a(areg), ALU_OP_SUB, reg_b(breg)); + emit_alu(nfp_prog, reg_none(), + reg_a(areg + 1), ALU_OP_SUB_C, reg_b(breg + 1)); + emit_br(nfp_prog, br_mask, insn->off, 0); + + return 0; +} + +/* --- Callbacks --- */ +static int mov_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + wrp_reg_mov(nfp_prog, insn->dst_reg * 2, insn->src_reg * 2); + wrp_reg_mov(nfp_prog, insn->dst_reg * 2 + 1, insn->src_reg * 2 + 1); + + return 0; +} + +static int mov_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + u64 imm = meta->insn.imm; /* sign extend */ + + wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2), imm & ~0U); + wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2 + 1), imm >> 32); + + return 0; +} + +static int xor_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu64_reg(nfp_prog, meta, ALU_OP_XOR); +} + +static int xor_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu64_imm(nfp_prog, meta, ALU_OP_XOR, !meta->insn.imm); +} + +static int and_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu64_reg(nfp_prog, meta, ALU_OP_AND); +} + +static int and_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu64_imm(nfp_prog, meta, ALU_OP_AND, !~meta->insn.imm); +} + +static int or_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu64_reg(nfp_prog, meta, ALU_OP_OR); +} + +static int or_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu64_imm(nfp_prog, meta, ALU_OP_OR, !meta->insn.imm); +} + +static int add_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + emit_alu(nfp_prog, reg_both(insn->dst_reg * 2), + reg_a(insn->dst_reg * 2), ALU_OP_ADD, + reg_b(insn->src_reg * 2)); + emit_alu(nfp_prog, reg_both(insn->dst_reg * 2 + 1), + reg_a(insn->dst_reg * 2 + 1), ALU_OP_ADD_C, + reg_b(insn->src_reg * 2 + 1)); + + return 0; +} + +static int add_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + u64 imm = insn->imm; /* sign extend */ + + wrp_alu_imm(nfp_prog, insn->dst_reg * 2, ALU_OP_ADD, imm & ~0U); + wrp_alu_imm(nfp_prog, insn->dst_reg * 2 + 1, ALU_OP_ADD_C, imm >> 32); + + return 0; +} + +static int sub_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + emit_alu(nfp_prog, reg_both(insn->dst_reg * 2), + reg_a(insn->dst_reg * 2), ALU_OP_SUB, + reg_b(insn->src_reg * 2)); + emit_alu(nfp_prog, reg_both(insn->dst_reg * 2 + 1), + reg_a(insn->dst_reg * 2 + 1), ALU_OP_SUB_C, + reg_b(insn->src_reg * 2 + 1)); + + return 0; +} + +static int sub_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + u64 imm = insn->imm; /* sign extend */ + + wrp_alu_imm(nfp_prog, insn->dst_reg * 2, ALU_OP_SUB, imm & ~0U); + wrp_alu_imm(nfp_prog, insn->dst_reg * 2 + 1, ALU_OP_SUB_C, imm >> 32); + + return 0; +} + +static int shl_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + if (insn->imm != 32) + return 1; /* TODO */ + + wrp_reg_mov(nfp_prog, insn->dst_reg * 2 + 1, insn->dst_reg * 2); + wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2), 0); + + return 0; +} + +static int shr_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + if (insn->imm != 32) + return 1; /* TODO */ + + wrp_reg_mov(nfp_prog, insn->dst_reg * 2, insn->dst_reg * 2 + 1); + wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); + + return 0; +} + +static int mov_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + wrp_reg_mov(nfp_prog, insn->dst_reg * 2, insn->src_reg * 2); + wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); + + return 0; +} + +static int mov_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2), insn->imm); + wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); + + return 0; +} + +static int xor_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_reg(nfp_prog, meta, ALU_OP_XOR); +} + +static int xor_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_imm(nfp_prog, meta, ALU_OP_XOR, !~meta->insn.imm); +} + +static int and_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_reg(nfp_prog, meta, ALU_OP_AND); +} + +static int and_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_imm(nfp_prog, meta, ALU_OP_AND, !~meta->insn.imm); +} + +static int or_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_reg(nfp_prog, meta, ALU_OP_OR); +} + +static int or_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_imm(nfp_prog, meta, ALU_OP_OR, !meta->insn.imm); +} + +static int add_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_reg(nfp_prog, meta, ALU_OP_ADD); +} + +static int add_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_imm(nfp_prog, meta, ALU_OP_ADD, !meta->insn.imm); +} + +static int sub_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_reg(nfp_prog, meta, ALU_OP_SUB); +} + +static int sub_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_alu32_imm(nfp_prog, meta, ALU_OP_SUB, !meta->insn.imm); +} + +static int shl_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + if (!insn->imm) + return 1; /* TODO: zero shift means indirect */ + + emit_shf(nfp_prog, reg_both(insn->dst_reg * 2), + reg_none(), SHF_OP_NONE, reg_b(insn->dst_reg * 2), + SHF_SC_L_SHF, insn->imm); + wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); + + return 0; +} + +static int imm_ld8_part2(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + wrp_immed(nfp_prog, reg_both(nfp_meta_prev(meta)->insn.dst_reg * 2 + 1), + meta->insn.imm); + + return 0; +} + +static int imm_ld8(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + meta->double_cb = imm_ld8_part2; + wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2), insn->imm); + + return 0; +} + +static int data_ld1(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return construct_data_ld(nfp_prog, meta->insn.imm, 1); +} + +static int data_ld2(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return construct_data_ld(nfp_prog, meta->insn.imm, 2); +} + +static int data_ld4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return construct_data_ld(nfp_prog, meta->insn.imm, 4); +} + +static int data_ind_ld1(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return construct_data_ind_ld(nfp_prog, meta->insn.imm, + meta->insn.src_reg * 2, true, 1); +} + +static int data_ind_ld2(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return construct_data_ind_ld(nfp_prog, meta->insn.imm, + meta->insn.src_reg * 2, true, 2); +} + +static int data_ind_ld4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return construct_data_ind_ld(nfp_prog, meta->insn.imm, + meta->insn.src_reg * 2, true, 4); +} + +static int mem_ldx4_skb(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + if (meta->insn.off == offsetof(struct sk_buff, len)) + emit_alu(nfp_prog, reg_both(meta->insn.dst_reg * 2), + reg_none(), ALU_OP_NONE, NFP_BPF_ABI_LEN); + else + return -EOPNOTSUPP; + + return 0; +} + +static int mem_ldx4_xdp(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + u32 dst = reg_both(meta->insn.dst_reg * 2); + + if (meta->insn.off != offsetof(struct xdp_md, data) && + meta->insn.off != offsetof(struct xdp_md, data_end)) + return -EOPNOTSUPP; + + emit_alu(nfp_prog, dst, reg_none(), ALU_OP_NONE, NFP_BPF_ABI_PKT); + + if (meta->insn.off == offsetof(struct xdp_md, data)) + return 0; + + emit_alu(nfp_prog, dst, dst, ALU_OP_ADD, NFP_BPF_ABI_LEN); + + return 0; +} + +static int mem_ldx4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + int ret; + + if (nfp_prog->act == NN_ACT_XDP) + ret = mem_ldx4_xdp(nfp_prog, meta); + else + ret = mem_ldx4_skb(nfp_prog, meta); + + wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2 + 1), 0); + + return ret; +} + +static int mem_stx4_skb(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + if (meta->insn.off == offsetof(struct sk_buff, mark)) + return wrp_set_mark(nfp_prog, meta->insn.src_reg * 2); + + return -EOPNOTSUPP; +} + +static int mem_stx4_xdp(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return -EOPNOTSUPP; +} + +static int mem_stx4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + if (nfp_prog->act == NN_ACT_XDP) + return mem_stx4_xdp(nfp_prog, meta); + return mem_stx4_skb(nfp_prog, meta); +} + +static int jump(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + if (meta->insn.off < 0) /* TODO */ + return -EOPNOTSUPP; + emit_br(nfp_prog, BR_UNC, meta->insn.off, 0); + + return 0; +} + +static int jeq_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + u64 imm = insn->imm; /* sign extend */ + u32 or1 = reg_a(insn->dst_reg * 2), or2 = reg_b(insn->dst_reg * 2 + 1); + u32 tmp_reg; + + if (insn->off < 0) /* TODO */ + return -EOPNOTSUPP; + + if (imm & ~0U) { + tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); + emit_alu(nfp_prog, imm_a(nfp_prog), + reg_a(insn->dst_reg * 2), ALU_OP_XOR, tmp_reg); + or1 = imm_a(nfp_prog); + } + + if (imm >> 32) { + tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); + emit_alu(nfp_prog, imm_b(nfp_prog), + reg_a(insn->dst_reg * 2 + 1), ALU_OP_XOR, tmp_reg); + or2 = imm_b(nfp_prog); + } + + emit_alu(nfp_prog, reg_none(), or1, ALU_OP_OR, or2); + emit_br(nfp_prog, BR_BEQ, insn->off, 0); + + return 0; +} + +static int jgt_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_cmp_imm(nfp_prog, meta, BR_BLO, false); +} + +static int jge_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_cmp_imm(nfp_prog, meta, BR_BHS, true); +} + +static int jset_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + u64 imm = insn->imm; /* sign extend */ + u32 tmp_reg; + + if (insn->off < 0) /* TODO */ + return -EOPNOTSUPP; + + if (!imm) { + meta->skip = true; + return 0; + } + + if (imm & ~0U) { + tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); + emit_alu(nfp_prog, reg_none(), + reg_a(insn->dst_reg * 2), ALU_OP_AND, tmp_reg); + emit_br(nfp_prog, BR_BNE, insn->off, 0); + } + + if (imm >> 32) { + tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); + emit_alu(nfp_prog, reg_none(), + reg_a(insn->dst_reg * 2 + 1), ALU_OP_AND, tmp_reg); + emit_br(nfp_prog, BR_BNE, insn->off, 0); + } + + return 0; +} + +static int jne_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + u64 imm = insn->imm; /* sign extend */ + u32 tmp_reg; + + if (insn->off < 0) /* TODO */ + return -EOPNOTSUPP; + + if (!imm) { + emit_alu(nfp_prog, reg_none(), reg_a(insn->dst_reg * 2), + ALU_OP_OR, reg_b(insn->dst_reg * 2 + 1)); + emit_br(nfp_prog, BR_BNE, insn->off, 0); + } + + tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); + emit_alu(nfp_prog, reg_none(), + reg_a(insn->dst_reg * 2), ALU_OP_XOR, tmp_reg); + emit_br(nfp_prog, BR_BNE, insn->off, 0); + + tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); + emit_alu(nfp_prog, reg_none(), + reg_a(insn->dst_reg * 2 + 1), ALU_OP_XOR, tmp_reg); + emit_br(nfp_prog, BR_BNE, insn->off, 0); + + return 0; +} + +static int jeq_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + const struct bpf_insn *insn = &meta->insn; + + if (insn->off < 0) /* TODO */ + return -EOPNOTSUPP; + + emit_alu(nfp_prog, imm_a(nfp_prog), reg_a(insn->dst_reg * 2), + ALU_OP_XOR, reg_b(insn->src_reg * 2)); + emit_alu(nfp_prog, imm_b(nfp_prog), reg_a(insn->dst_reg * 2 + 1), + ALU_OP_XOR, reg_b(insn->src_reg * 2 + 1)); + emit_alu(nfp_prog, reg_none(), + imm_a(nfp_prog), ALU_OP_OR, imm_b(nfp_prog)); + emit_br(nfp_prog, BR_BEQ, insn->off, 0); + + return 0; +} + +static int jgt_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_cmp_reg(nfp_prog, meta, BR_BLO, false); +} + +static int jge_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_cmp_reg(nfp_prog, meta, BR_BHS, true); +} + +static int jset_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_test_reg(nfp_prog, meta, ALU_OP_AND, BR_BNE); +} + +static int jne_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + return wrp_test_reg(nfp_prog, meta, ALU_OP_XOR, BR_BNE); +} + +static int goto_out(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +{ + wrp_br_special(nfp_prog, BR_UNC, OP_BR_GO_OUT); + + return 0; +} + +static const instr_cb_t instr_cb[256] = { + [BPF_ALU64 | BPF_MOV | BPF_X] = mov_reg64, + [BPF_ALU64 | BPF_MOV | BPF_K] = mov_imm64, + [BPF_ALU64 | BPF_XOR | BPF_X] = xor_reg64, + [BPF_ALU64 | BPF_XOR | BPF_K] = xor_imm64, + [BPF_ALU64 | BPF_AND | BPF_X] = and_reg64, + [BPF_ALU64 | BPF_AND | BPF_K] = and_imm64, + [BPF_ALU64 | BPF_OR | BPF_X] = or_reg64, + [BPF_ALU64 | BPF_OR | BPF_K] = or_imm64, + [BPF_ALU64 | BPF_ADD | BPF_X] = add_reg64, + [BPF_ALU64 | BPF_ADD | BPF_K] = add_imm64, + [BPF_ALU64 | BPF_SUB | BPF_X] = sub_reg64, + [BPF_ALU64 | BPF_SUB | BPF_K] = sub_imm64, + [BPF_ALU64 | BPF_LSH | BPF_K] = shl_imm64, + [BPF_ALU64 | BPF_RSH | BPF_K] = shr_imm64, + [BPF_ALU | BPF_MOV | BPF_X] = mov_reg, + [BPF_ALU | BPF_MOV | BPF_K] = mov_imm, + [BPF_ALU | BPF_XOR | BPF_X] = xor_reg, + [BPF_ALU | BPF_XOR | BPF_K] = xor_imm, + [BPF_ALU | BPF_AND | BPF_X] = and_reg, + [BPF_ALU | BPF_AND | BPF_K] = and_imm, + [BPF_ALU | BPF_OR | BPF_X] = or_reg, + [BPF_ALU | BPF_OR | BPF_K] = or_imm, + [BPF_ALU | BPF_ADD | BPF_X] = add_reg, + [BPF_ALU | BPF_ADD | BPF_K] = add_imm, + [BPF_ALU | BPF_SUB | BPF_X] = sub_reg, + [BPF_ALU | BPF_SUB | BPF_K] = sub_imm, + [BPF_ALU | BPF_LSH | BPF_K] = shl_imm, + [BPF_LD | BPF_IMM | BPF_DW] = imm_ld8, + [BPF_LD | BPF_ABS | BPF_B] = data_ld1, + [BPF_LD | BPF_ABS | BPF_H] = data_ld2, + [BPF_LD | BPF_ABS | BPF_W] = data_ld4, + [BPF_LD | BPF_IND | BPF_B] = data_ind_ld1, + [BPF_LD | BPF_IND | BPF_H] = data_ind_ld2, + [BPF_LD | BPF_IND | BPF_W] = data_ind_ld4, + [BPF_LDX | BPF_MEM | BPF_W] = mem_ldx4, + [BPF_STX | BPF_MEM | BPF_W] = mem_stx4, + [BPF_JMP | BPF_JA | BPF_K] = jump, + [BPF_JMP | BPF_JEQ | BPF_K] = jeq_imm, + [BPF_JMP | BPF_JGT | BPF_K] = jgt_imm, + [BPF_JMP | BPF_JGE | BPF_K] = jge_imm, + [BPF_JMP | BPF_JSET | BPF_K] = jset_imm, + [BPF_JMP | BPF_JNE | BPF_K] = jne_imm, + [BPF_JMP | BPF_JEQ | BPF_X] = jeq_reg, + [BPF_JMP | BPF_JGT | BPF_X] = jgt_reg, + [BPF_JMP | BPF_JGE | BPF_X] = jge_reg, + [BPF_JMP | BPF_JSET | BPF_X] = jset_reg, + [BPF_JMP | BPF_JNE | BPF_X] = jne_reg, + [BPF_JMP | BPF_EXIT] = goto_out, +}; + +/* --- Misc code --- */ +static void br_set_offset(u64 *instr, u16 offset) +{ + u16 addr_lo, addr_hi; + + addr_lo = offset & (OP_BR_ADDR_LO >> __bf_shf(OP_BR_ADDR_LO)); + addr_hi = offset != addr_lo; + *instr &= ~(OP_BR_ADDR_HI | OP_BR_ADDR_LO); + *instr |= FIELD_PREP(OP_BR_ADDR_HI, addr_hi); + *instr |= FIELD_PREP(OP_BR_ADDR_LO, addr_lo); +} + +/* --- Assembler logic --- */ +static int nfp_fixup_branches(struct nfp_prog *nfp_prog) +{ + struct nfp_insn_meta *meta, *next; + u32 off, br_idx; + u32 idx; + + nfp_for_each_insn_walk2(nfp_prog, meta, next) { + if (meta->skip) + continue; + if (BPF_CLASS(meta->insn.code) != BPF_JMP) + continue; + + br_idx = nfp_prog_offset_to_index(nfp_prog, next->off) - 1; + if (!nfp_is_br(nfp_prog->prog[br_idx])) { + pr_err("Fixup found block not ending in branch %d %02x %016llx!!\n", + br_idx, meta->insn.code, nfp_prog->prog[br_idx]); + return -ELOOP; + } + /* Leave special branches for later */ + if (FIELD_GET(OP_BR_SPECIAL, nfp_prog->prog[br_idx])) + continue; + + /* Find the target offset in assembler realm */ + off = meta->insn.off; + if (!off) { + pr_err("Fixup found zero offset!!\n"); + return -ELOOP; + } + + while (off && nfp_meta_has_next(nfp_prog, next)) { + next = nfp_meta_next(next); + off--; + } + if (off) { + pr_err("Fixup found too large jump!! %d\n", off); + return -ELOOP; + } + + if (next->skip) { + pr_err("Branch landing on removed instruction!!\n"); + return -ELOOP; + } + + for (idx = nfp_prog_offset_to_index(nfp_prog, meta->off); + idx <= br_idx; idx++) { + if (!nfp_is_br(nfp_prog->prog[idx])) + continue; + br_set_offset(&nfp_prog->prog[idx], next->off); + } + } + + /* Fixup 'goto out's separately, they can be scattered around */ + for (br_idx = 0; br_idx < nfp_prog->prog_len; br_idx++) { + enum br_special special; + + if ((nfp_prog->prog[br_idx] & OP_BR_BASE_MASK) != OP_BR_BASE) + continue; + + special = FIELD_GET(OP_BR_SPECIAL, nfp_prog->prog[br_idx]); + switch (special) { + case OP_BR_NORMAL: + break; + case OP_BR_GO_OUT: + br_set_offset(&nfp_prog->prog[br_idx], + nfp_prog->tgt_out); + break; + case OP_BR_GO_ABORT: + br_set_offset(&nfp_prog->prog[br_idx], + nfp_prog->tgt_abort); + break; + } + + nfp_prog->prog[br_idx] &= ~OP_BR_SPECIAL; + } + + return 0; +} + +static void nfp_intro(struct nfp_prog *nfp_prog) +{ + emit_alu(nfp_prog, pkt_reg(nfp_prog), + reg_none(), ALU_OP_NONE, NFP_BPF_ABI_PKT); +} + +static void nfp_outro_tc_legacy(struct nfp_prog *nfp_prog) +{ + const u8 act2code[] = { + [NN_ACT_TC_DROP] = 0x22, + [NN_ACT_TC_REDIR] = 0x24 + }; + /* Target for aborts */ + nfp_prog->tgt_abort = nfp_prog_current_offset(nfp_prog); + wrp_immed(nfp_prog, reg_both(0), 0); + + /* Target for normal exits */ + nfp_prog->tgt_out = nfp_prog_current_offset(nfp_prog); + /* Legacy TC mode: + * 0 0x11 -> pass, count as stat0 + * -1 drop 0x22 -> drop, count as stat1 + * redir 0x24 -> redir, count as stat1 + * ife mark 0x21 -> pass, count as stat1 + * ife + tx 0x24 -> redir, count as stat1 + */ + emit_br_byte_neq(nfp_prog, reg_b(0), 0xff, 0, nfp_prog->tgt_done, 2); + emit_alu(nfp_prog, reg_a(0), + reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); + emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_imm(0x11), SHF_SC_L_SHF, 16); + + emit_br(nfp_prog, BR_UNC, nfp_prog->tgt_done, 1); + emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_imm(act2code[nfp_prog->act]), + SHF_SC_L_SHF, 16); +} + +static void nfp_outro_tc_da(struct nfp_prog *nfp_prog) +{ + /* TC direct-action mode: + * 0,1 ok NOT SUPPORTED[1] + * 2 drop 0x22 -> drop, count as stat1 + * 4,5 nuke 0x02 -> drop + * 7 redir 0x44 -> redir, count as stat2 + * * unspec 0x11 -> pass, count as stat0 + * + * [1] We can't support OK and RECLASSIFY because we can't tell TC + * the exact decision made. We are forced to support UNSPEC + * to handle aborts so that's the only one we handle for passing + * packets up the stack. + */ + /* Target for aborts */ + nfp_prog->tgt_abort = nfp_prog_current_offset(nfp_prog); + + emit_br_def(nfp_prog, nfp_prog->tgt_done, 2); + + emit_alu(nfp_prog, reg_a(0), + reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); + emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_imm(0x11), SHF_SC_L_SHF, 16); + + /* Target for normal exits */ + nfp_prog->tgt_out = nfp_prog_current_offset(nfp_prog); + + /* if R0 > 7 jump to abort */ + emit_alu(nfp_prog, reg_none(), reg_imm(7), ALU_OP_SUB, reg_b(0)); + emit_br(nfp_prog, BR_BLO, nfp_prog->tgt_abort, 0); + emit_alu(nfp_prog, reg_a(0), + reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); + + wrp_immed(nfp_prog, reg_b(2), 0x41221211); + wrp_immed(nfp_prog, reg_b(3), 0x41001211); + + emit_shf(nfp_prog, reg_a(1), + reg_none(), SHF_OP_NONE, reg_b(0), SHF_SC_L_SHF, 2); + + emit_alu(nfp_prog, reg_none(), reg_a(1), ALU_OP_OR, reg_imm(0)); + emit_shf(nfp_prog, reg_a(2), + reg_imm(0xf), SHF_OP_AND, reg_b(2), SHF_SC_R_SHF, 0); + + emit_alu(nfp_prog, reg_none(), reg_a(1), ALU_OP_OR, reg_imm(0)); + emit_shf(nfp_prog, reg_b(2), + reg_imm(0xf), SHF_OP_AND, reg_b(3), SHF_SC_R_SHF, 0); + + emit_br_def(nfp_prog, nfp_prog->tgt_done, 2); + + emit_shf(nfp_prog, reg_b(2), + reg_a(2), SHF_OP_OR, reg_b(2), SHF_SC_L_SHF, 4); + emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_b(2), SHF_SC_L_SHF, 16); +} + +static void nfp_outro_xdp(struct nfp_prog *nfp_prog) +{ + /* XDP return codes: + * 0 aborted 0x82 -> drop, count as stat3 + * 1 drop 0x22 -> drop, count as stat1 + * 2 pass 0x11 -> pass, count as stat0 + * 3 tx 0x44 -> redir, count as stat2 + * * unknown 0x82 -> drop, count as stat3 + */ + /* Target for aborts */ + nfp_prog->tgt_abort = nfp_prog_current_offset(nfp_prog); + + emit_br_def(nfp_prog, nfp_prog->tgt_done, 2); + + emit_alu(nfp_prog, reg_a(0), + reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); + emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_imm(0x82), SHF_SC_L_SHF, 16); + + /* Target for normal exits */ + nfp_prog->tgt_out = nfp_prog_current_offset(nfp_prog); + + /* if R0 > 3 jump to abort */ + emit_alu(nfp_prog, reg_none(), reg_imm(3), ALU_OP_SUB, reg_b(0)); + emit_br(nfp_prog, BR_BLO, nfp_prog->tgt_abort, 0); + + wrp_immed(nfp_prog, reg_b(2), 0x44112282); + + emit_shf(nfp_prog, reg_a(1), + reg_none(), SHF_OP_NONE, reg_b(0), SHF_SC_L_SHF, 3); + + emit_alu(nfp_prog, reg_none(), reg_a(1), ALU_OP_OR, reg_imm(0)); + emit_shf(nfp_prog, reg_b(2), + reg_imm(0xff), SHF_OP_AND, reg_b(2), SHF_SC_R_SHF, 0); + + emit_br_def(nfp_prog, nfp_prog->tgt_done, 2); + + emit_alu(nfp_prog, reg_a(0), + reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); + emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_b(2), SHF_SC_L_SHF, 16); +} + +static void nfp_outro(struct nfp_prog *nfp_prog) +{ + switch (nfp_prog->act) { + case NN_ACT_DIRECT: + nfp_outro_tc_da(nfp_prog); + break; + case NN_ACT_TC_DROP: + case NN_ACT_TC_REDIR: + nfp_outro_tc_legacy(nfp_prog); + break; + case NN_ACT_XDP: + nfp_outro_xdp(nfp_prog); + break; + } +} + +static int nfp_translate(struct nfp_prog *nfp_prog) +{ + struct nfp_insn_meta *meta; + int err; + + nfp_intro(nfp_prog); + if (nfp_prog->error) + return nfp_prog->error; + + list_for_each_entry(meta, &nfp_prog->insns, l) { + instr_cb_t cb = instr_cb[meta->insn.code]; + + meta->off = nfp_prog_current_offset(nfp_prog); + + if (meta->skip) { + nfp_prog->n_translated++; + continue; + } + + if (nfp_meta_has_prev(nfp_prog, meta) && + nfp_meta_prev(meta)->double_cb) + cb = nfp_meta_prev(meta)->double_cb; + if (!cb) + return -ENOENT; + err = cb(nfp_prog, meta); + if (err) + return err; + + nfp_prog->n_translated++; + } + + nfp_outro(nfp_prog); + if (nfp_prog->error) + return nfp_prog->error; + + return nfp_fixup_branches(nfp_prog); +} + +static int +nfp_prog_prepare(struct nfp_prog *nfp_prog, const struct bpf_insn *prog, + unsigned int cnt) +{ + unsigned int i; + + for (i = 0; i < cnt; i++) { + struct nfp_insn_meta *meta; + + meta = kzalloc(sizeof(*meta), GFP_KERNEL); + if (!meta) + return -ENOMEM; + + meta->insn = prog[i]; + meta->n = i; + + list_add_tail(&meta->l, &nfp_prog->insns); + } + + return 0; +} + +/* --- Optimizations --- */ +static void nfp_bpf_opt_reg_init(struct nfp_prog *nfp_prog) +{ + struct nfp_insn_meta *meta; + + list_for_each_entry(meta, &nfp_prog->insns, l) { + struct bpf_insn insn = meta->insn; + + /* Programs converted from cBPF start with register xoring */ + if (insn.code == (BPF_ALU64 | BPF_XOR | BPF_X) && + insn.src_reg == insn.dst_reg) + continue; + + /* Programs start with R6 = R1 but we ignore the skb pointer */ + if (insn.code == (BPF_ALU64 | BPF_MOV | BPF_X) && + insn.src_reg == 1 && insn.dst_reg == 6) + meta->skip = true; + + /* Return as soon as something doesn't match */ + if (!meta->skip) + return; + } +} + +/* Try to rename registers so that program uses only low ones */ +static int nfp_bpf_opt_reg_rename(struct nfp_prog *nfp_prog) +{ + bool reg_used[MAX_BPF_REG] = {}; + u8 tgt_reg[MAX_BPF_REG] = {}; + struct nfp_insn_meta *meta; + unsigned int i, j; + + list_for_each_entry(meta, &nfp_prog->insns, l) { + if (meta->skip) + continue; + + reg_used[meta->insn.src_reg] = true; + reg_used[meta->insn.dst_reg] = true; + } + + for (i = 0, j = 0; i < ARRAY_SIZE(tgt_reg); i++) { + if (!reg_used[i]) + continue; + + tgt_reg[i] = j++; + } + nfp_prog->num_regs = j; + + list_for_each_entry(meta, &nfp_prog->insns, l) { + meta->insn.src_reg = tgt_reg[meta->insn.src_reg]; + meta->insn.dst_reg = tgt_reg[meta->insn.dst_reg]; + } + + return 0; +} + +/* Remove masking after load since our load guarantees this is not needed */ +static void nfp_bpf_opt_ld_mask(struct nfp_prog *nfp_prog) +{ + struct nfp_insn_meta *meta1, *meta2; + const s32 exp_mask[] = { + [BPF_B] = 0x000000ffU, + [BPF_H] = 0x0000ffffU, + [BPF_W] = 0xffffffffU, + }; + + nfp_for_each_insn_walk2(nfp_prog, meta1, meta2) { + struct bpf_insn insn, next; + + insn = meta1->insn; + next = meta2->insn; + + if (BPF_CLASS(insn.code) != BPF_LD) + continue; + if (BPF_MODE(insn.code) != BPF_ABS && + BPF_MODE(insn.code) != BPF_IND) + continue; + + if (next.code != (BPF_ALU64 | BPF_AND | BPF_K)) + continue; + + if (!exp_mask[BPF_SIZE(insn.code)]) + continue; + if (exp_mask[BPF_SIZE(insn.code)] != next.imm) + continue; + + if (next.src_reg || next.dst_reg) + continue; + + meta2->skip = true; + } +} + +static void nfp_bpf_opt_ld_shift(struct nfp_prog *nfp_prog) +{ + struct nfp_insn_meta *meta1, *meta2, *meta3; + + nfp_for_each_insn_walk3(nfp_prog, meta1, meta2, meta3) { + struct bpf_insn insn, next1, next2; + + insn = meta1->insn; + next1 = meta2->insn; + next2 = meta3->insn; + + if (BPF_CLASS(insn.code) != BPF_LD) + continue; + if (BPF_MODE(insn.code) != BPF_ABS && + BPF_MODE(insn.code) != BPF_IND) + continue; + if (BPF_SIZE(insn.code) != BPF_W) + continue; + + if (!(next1.code == (BPF_LSH | BPF_K | BPF_ALU64) && + next2.code == (BPF_RSH | BPF_K | BPF_ALU64)) && + !(next1.code == (BPF_RSH | BPF_K | BPF_ALU64) && + next2.code == (BPF_LSH | BPF_K | BPF_ALU64))) + continue; + + if (next1.src_reg || next1.dst_reg || + next2.src_reg || next2.dst_reg) + continue; + + if (next1.imm != 0x20 || next2.imm != 0x20) + continue; + + meta2->skip = true; + meta3->skip = true; + } +} + +static int nfp_bpf_optimize(struct nfp_prog *nfp_prog) +{ + int ret; + + nfp_bpf_opt_reg_init(nfp_prog); + + ret = nfp_bpf_opt_reg_rename(nfp_prog); + if (ret) + return ret; + + nfp_bpf_opt_ld_mask(nfp_prog); + nfp_bpf_opt_ld_shift(nfp_prog); + + return 0; +} + +/** + * nfp_bpf_jit() - translate BPF code into NFP assembly + * @filter: kernel BPF filter struct + * @prog_mem: memory to store assembler instructions + * @act: action attached to this eBPF program + * @prog_start: offset of the first instruction when loaded + * @prog_done: where to jump on exit + * @prog_sz: size of @prog_mem in instructions + * @res: achieved parameters of translation results + */ +int +nfp_bpf_jit(struct bpf_prog *filter, void *prog_mem, + enum nfp_bpf_action_type act, + unsigned int prog_start, unsigned int prog_done, + unsigned int prog_sz, struct nfp_bpf_result *res) +{ + struct nfp_prog *nfp_prog; + int ret; + + nfp_prog = kzalloc(sizeof(*nfp_prog), GFP_KERNEL); + if (!nfp_prog) + return -ENOMEM; + + INIT_LIST_HEAD(&nfp_prog->insns); + nfp_prog->act = act; + nfp_prog->start_off = prog_start; + nfp_prog->tgt_done = prog_done; + + ret = nfp_prog_prepare(nfp_prog, filter->insnsi, filter->len); + if (ret) + goto out; + + ret = nfp_prog_verify(nfp_prog, filter); + if (ret) + goto out; + + ret = nfp_bpf_optimize(nfp_prog); + if (ret) + goto out; + + if (nfp_prog->num_regs <= 7) + nfp_prog->regs_per_thread = 16; + else + nfp_prog->regs_per_thread = 32; + + nfp_prog->prog = prog_mem; + nfp_prog->__prog_alloc_len = prog_sz; + + ret = nfp_translate(nfp_prog); + if (ret) { + pr_err("Translation failed with error %d (translated: %u)\n", + ret, nfp_prog->n_translated); + ret = -EINVAL; + } + + res->n_instr = nfp_prog->prog_len; + res->dense_mode = nfp_prog->num_regs <= 7; +out: + nfp_prog_free(nfp_prog); + + return ret; +} diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h new file mode 100644 index 000000000000..9513c80f7be5 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2016 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __NFP_BPF_H__ +#define __NFP_BPF_H__ 1 + +#include +#include +#include +#include + +/* For branch fixup logic use up-most byte of branch instruction as scratch + * area. Remember to clear this before sending instructions to HW! + */ +#define OP_BR_SPECIAL 0xff00000000000000ULL + +enum br_special { + OP_BR_NORMAL = 0, + OP_BR_GO_OUT, + OP_BR_GO_ABORT, +}; + +enum static_regs { + STATIC_REG_PKT = 1, +#define REG_PKT_BANK ALU_DST_A + STATIC_REG_IMM = 2, /* Bank AB */ +}; + +enum nfp_bpf_action_type { + NN_ACT_TC_DROP, + NN_ACT_TC_REDIR, + NN_ACT_DIRECT, + NN_ACT_XDP, +}; + +/* Software register representation, hardware encoding in asm.h */ +#define NN_REG_TYPE GENMASK(31, 24) +#define NN_REG_VAL GENMASK(7, 0) + +enum nfp_bpf_reg_type { + NN_REG_GPR_A = BIT(0), + NN_REG_GPR_B = BIT(1), + NN_REG_NNR = BIT(2), + NN_REG_XFER = BIT(3), + NN_REG_IMM = BIT(4), + NN_REG_NONE = BIT(5), +}; + +#define NN_REG_GPR_BOTH (NN_REG_GPR_A | NN_REG_GPR_B) + +#define reg_both(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_GPR_BOTH)) +#define reg_a(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_GPR_A)) +#define reg_b(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_GPR_B)) +#define reg_nnr(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_NNR)) +#define reg_xfer(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_XFER)) +#define reg_imm(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_IMM)) +#define reg_none() (FIELD_PREP(NN_REG_TYPE, NN_REG_NONE)) + +#define pkt_reg(np) reg_a((np)->regs_per_thread - STATIC_REG_PKT) +#define imm_a(np) reg_a((np)->regs_per_thread - STATIC_REG_IMM) +#define imm_b(np) reg_b((np)->regs_per_thread - STATIC_REG_IMM) +#define imm_both(np) reg_both((np)->regs_per_thread - STATIC_REG_IMM) + +#define NFP_BPF_ABI_FLAGS reg_nnr(0) +#define NFP_BPF_ABI_FLAG_MARK 1 +#define NFP_BPF_ABI_MARK reg_nnr(1) +#define NFP_BPF_ABI_PKT reg_nnr(2) +#define NFP_BPF_ABI_LEN reg_nnr(3) + +struct nfp_prog; +struct nfp_insn_meta; +typedef int (*instr_cb_t)(struct nfp_prog *, struct nfp_insn_meta *); + +#define nfp_prog_first_meta(nfp_prog) \ + list_first_entry(&(nfp_prog)->insns, struct nfp_insn_meta, l) +#define nfp_prog_last_meta(nfp_prog) \ + list_last_entry(&(nfp_prog)->insns, struct nfp_insn_meta, l) +#define nfp_meta_next(meta) list_next_entry(meta, l) +#define nfp_meta_prev(meta) list_prev_entry(meta, l) + +/** + * struct nfp_insn_meta - BPF instruction wrapper + * @insn: BPF instruction + * @off: index of first generated machine instruction (in nfp_prog.prog) + * @n: eBPF instruction number + * @skip: skip this instruction (optimized out) + * @double_cb: callback for second part of the instruction + * @l: link on nfp_prog->insns list + */ +struct nfp_insn_meta { + struct bpf_insn insn; + unsigned int off; + unsigned short n; + bool skip; + instr_cb_t double_cb; + + struct list_head l; +}; + +#define BPF_SIZE_MASK 0x18 + +static inline u8 mbpf_class(const struct nfp_insn_meta *meta) +{ + return BPF_CLASS(meta->insn.code); +} + +static inline u8 mbpf_src(const struct nfp_insn_meta *meta) +{ + return BPF_SRC(meta->insn.code); +} + +static inline u8 mbpf_op(const struct nfp_insn_meta *meta) +{ + return BPF_OP(meta->insn.code); +} + +static inline u8 mbpf_mode(const struct nfp_insn_meta *meta) +{ + return BPF_MODE(meta->insn.code); +} + +/** + * struct nfp_prog - nfp BPF program + * @prog: machine code + * @prog_len: number of valid instructions in @prog array + * @__prog_alloc_len: alloc size of @prog array + * @act: BPF program/action type (TC DA, TC with action, XDP etc.) + * @num_regs: number of registers used by this program + * @regs_per_thread: number of basic registers allocated per thread + * @start_off: address of the first instruction in the memory + * @tgt_out: jump target for normal exit + * @tgt_abort: jump target for abort (e.g. access outside of packet buffer) + * @tgt_done: jump target to get the next packet + * @n_translated: number of successfully translated instructions (for errors) + * @error: error code if something went wrong + * @insns: list of BPF instruction wrappers (struct nfp_insn_meta) + */ +struct nfp_prog { + u64 *prog; + unsigned int prog_len; + unsigned int __prog_alloc_len; + + enum nfp_bpf_action_type act; + + unsigned int num_regs; + unsigned int regs_per_thread; + + unsigned int start_off; + unsigned int tgt_out; + unsigned int tgt_abort; + unsigned int tgt_done; + + unsigned int n_translated; + int error; + + struct list_head insns; +}; + +struct nfp_bpf_result { + unsigned int n_instr; + bool dense_mode; +}; + +int +nfp_bpf_jit(struct bpf_prog *filter, void *prog, enum nfp_bpf_action_type act, + unsigned int prog_start, unsigned int prog_done, + unsigned int prog_sz, struct nfp_bpf_result *res); + +int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog); + +#endif diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c new file mode 100644 index 000000000000..30372dc99517 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2016 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * nfp_net_offload.c + * Netronome network device driver: TC offload functions for PF and VF + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "main.h" +#include "../nfp_net_ctrl.h" +#include "../nfp_net.h" + +void nfp_net_filter_stats_timer(unsigned long data) +{ + struct nfp_net *nn = (void *)data; + struct nfp_stat_pair latest; + + spin_lock_bh(&nn->rx_filter_lock); + + if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) + mod_timer(&nn->rx_filter_stats_timer, + jiffies + NFP_NET_STAT_POLL_IVL); + + spin_unlock_bh(&nn->rx_filter_lock); + + latest.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); + latest.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); + + if (latest.pkts != nn->rx_filter.pkts) + nn->rx_filter_change = jiffies; + + nn->rx_filter = latest; +} + +static void nfp_net_bpf_stats_reset(struct nfp_net *nn) +{ + nn->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); + nn->rx_filter.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); + nn->rx_filter_prev = nn->rx_filter; + nn->rx_filter_change = jiffies; +} + +static int +nfp_net_bpf_stats_update(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) +{ + u64 bytes, pkts; + + pkts = nn->rx_filter.pkts - nn->rx_filter_prev.pkts; + bytes = nn->rx_filter.bytes - nn->rx_filter_prev.bytes; + bytes -= pkts * ETH_HLEN; + + nn->rx_filter_prev = nn->rx_filter; + + tcf_exts_stats_update(cls_bpf->exts, + bytes, pkts, nn->rx_filter_change); + + return 0; +} + +static int +nfp_net_bpf_get_act(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) +{ + const struct tc_action *a; + LIST_HEAD(actions); + + if (!cls_bpf->exts) + return NN_ACT_XDP; + + /* TC direct action */ + if (cls_bpf->exts_integrated) { + if (tc_no_actions(cls_bpf->exts)) + return NN_ACT_DIRECT; + + return -EOPNOTSUPP; + } + + /* TC legacy mode */ + if (!tc_single_action(cls_bpf->exts)) + return -EOPNOTSUPP; + + tcf_exts_to_list(cls_bpf->exts, &actions); + list_for_each_entry(a, &actions, list) { + if (is_tcf_gact_shot(a)) + return NN_ACT_TC_DROP; + + if (is_tcf_mirred_egress_redirect(a) && + tcf_mirred_ifindex(a) == nn->dp.netdev->ifindex) + return NN_ACT_TC_REDIR; + } + + return -EOPNOTSUPP; +} + +static int +nfp_net_bpf_offload_prepare(struct nfp_net *nn, + struct tc_cls_bpf_offload *cls_bpf, + struct nfp_bpf_result *res, + void **code, dma_addr_t *dma_addr, u16 max_instr) +{ + unsigned int code_sz = max_instr * sizeof(u64); + enum nfp_bpf_action_type act; + u16 start_off, done_off; + unsigned int max_mtu; + int ret; + + if (!IS_ENABLED(CONFIG_BPF_SYSCALL)) + return -EOPNOTSUPP; + + ret = nfp_net_bpf_get_act(nn, cls_bpf); + if (ret < 0) + return ret; + act = ret; + + max_mtu = nn_readb(nn, NFP_NET_CFG_BPF_INL_MTU) * 64 - 32; + if (max_mtu < nn->dp.netdev->mtu) { + nn_info(nn, "BPF offload not supported with MTU larger than HW packet split boundary\n"); + return -EOPNOTSUPP; + } + + start_off = nn_readw(nn, NFP_NET_CFG_BPF_START); + done_off = nn_readw(nn, NFP_NET_CFG_BPF_DONE); + + *code = dma_zalloc_coherent(nn->dp.dev, code_sz, dma_addr, GFP_KERNEL); + if (!*code) + return -ENOMEM; + + ret = nfp_bpf_jit(cls_bpf->prog, *code, act, start_off, done_off, + max_instr, res); + if (ret) + goto out; + + return 0; + +out: + dma_free_coherent(nn->dp.dev, code_sz, *code, *dma_addr); + return ret; +} + +static void +nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags, + void *code, dma_addr_t dma_addr, + unsigned int code_sz, unsigned int n_instr, + bool dense_mode) +{ + u64 bpf_addr = dma_addr; + int err; + + nn->dp.bpf_offload_skip_sw = !!(tc_flags & TCA_CLS_FLAGS_SKIP_SW); + + if (dense_mode) + bpf_addr |= NFP_NET_CFG_BPF_CFG_8CTX; + + nn_writew(nn, NFP_NET_CFG_BPF_SIZE, n_instr); + nn_writeq(nn, NFP_NET_CFG_BPF_ADDR, bpf_addr); + + /* Load up the JITed code */ + err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_BPF); + if (err) + nn_err(nn, "FW command error while loading BPF: %d\n", err); + + /* Enable passing packets through BPF function */ + nn->dp.ctrl |= NFP_NET_CFG_CTRL_BPF; + nn_writel(nn, NFP_NET_CFG_CTRL, nn->dp.ctrl); + err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); + if (err) + nn_err(nn, "FW command error while enabling BPF: %d\n", err); + + dma_free_coherent(nn->dp.dev, code_sz, code, dma_addr); + + nfp_net_bpf_stats_reset(nn); + mod_timer(&nn->rx_filter_stats_timer, jiffies + NFP_NET_STAT_POLL_IVL); +} + +static int nfp_net_bpf_stop(struct nfp_net *nn) +{ + if (!(nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF)) + return 0; + + spin_lock_bh(&nn->rx_filter_lock); + nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_BPF; + spin_unlock_bh(&nn->rx_filter_lock); + nn_writel(nn, NFP_NET_CFG_CTRL, nn->dp.ctrl); + + del_timer_sync(&nn->rx_filter_stats_timer); + nn->dp.bpf_offload_skip_sw = 0; + + return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); +} + +int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) +{ + struct nfp_bpf_result res; + dma_addr_t dma_addr; + u16 max_instr; + void *code; + int err; + + max_instr = nn_readw(nn, NFP_NET_CFG_BPF_MAX_LEN); + + switch (cls_bpf->command) { + case TC_CLSBPF_REPLACE: + /* There is nothing stopping us from implementing seamless + * replace but the simple method of loading I adopted in + * the firmware does not handle atomic replace (i.e. we have to + * stop the BPF offload and re-enable it). Leaking-in a few + * frames which didn't have BPF applied in the hardware should + * be fine if software fallback is available, though. + */ + if (nn->dp.bpf_offload_skip_sw) + return -EBUSY; + + err = nfp_net_bpf_offload_prepare(nn, cls_bpf, &res, &code, + &dma_addr, max_instr); + if (err) + return err; + + nfp_net_bpf_stop(nn); + nfp_net_bpf_load_and_start(nn, cls_bpf->gen_flags, code, + dma_addr, max_instr * sizeof(u64), + res.n_instr, res.dense_mode); + return 0; + + case TC_CLSBPF_ADD: + if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) + return -EBUSY; + + err = nfp_net_bpf_offload_prepare(nn, cls_bpf, &res, &code, + &dma_addr, max_instr); + if (err) + return err; + + nfp_net_bpf_load_and_start(nn, cls_bpf->gen_flags, code, + dma_addr, max_instr * sizeof(u64), + res.n_instr, res.dense_mode); + return 0; + + case TC_CLSBPF_DESTROY: + return nfp_net_bpf_stop(nn); + + case TC_CLSBPF_STATS: + return nfp_net_bpf_stats_update(nn, cls_bpf); + + default: + return -EOPNOTSUPP; + } +} diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c new file mode 100644 index 000000000000..d696ba46f70a --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2016 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define pr_fmt(fmt) "NFP net bpf: " fmt + +#include +#include +#include +#include + +#include "main.h" + +/* Analyzer/verifier definitions */ +struct nfp_bpf_analyzer_priv { + struct nfp_prog *prog; + struct nfp_insn_meta *meta; +}; + +static struct nfp_insn_meta * +nfp_bpf_goto_meta(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, + unsigned int insn_idx, unsigned int n_insns) +{ + unsigned int forward, backward, i; + + backward = meta->n - insn_idx; + forward = insn_idx - meta->n; + + if (min(forward, backward) > n_insns - insn_idx - 1) { + backward = n_insns - insn_idx - 1; + meta = nfp_prog_last_meta(nfp_prog); + } + if (min(forward, backward) > insn_idx && backward > insn_idx) { + forward = insn_idx; + meta = nfp_prog_first_meta(nfp_prog); + } + + if (forward < backward) + for (i = 0; i < forward; i++) + meta = nfp_meta_next(meta); + else + for (i = 0; i < backward; i++) + meta = nfp_meta_prev(meta); + + return meta; +} + +static int +nfp_bpf_check_exit(struct nfp_prog *nfp_prog, + const struct bpf_verifier_env *env) +{ + const struct bpf_reg_state *reg0 = &env->cur_state.regs[0]; + + if (nfp_prog->act == NN_ACT_XDP) + return 0; + + if (reg0->type != CONST_IMM) { + pr_info("unsupported exit state: %d, imm: %llx\n", + reg0->type, reg0->imm); + return -EINVAL; + } + + if (nfp_prog->act != NN_ACT_DIRECT && + reg0->imm != 0 && (reg0->imm & ~0U) != ~0U) { + pr_info("unsupported exit state: %d, imm: %llx\n", + reg0->type, reg0->imm); + return -EINVAL; + } + + if (nfp_prog->act == NN_ACT_DIRECT && reg0->imm <= TC_ACT_REDIRECT && + reg0->imm != TC_ACT_SHOT && reg0->imm != TC_ACT_STOLEN && + reg0->imm != TC_ACT_QUEUED) { + pr_info("unsupported exit state: %d, imm: %llx\n", + reg0->type, reg0->imm); + return -EINVAL; + } + + return 0; +} + +static int +nfp_bpf_check_ctx_ptr(struct nfp_prog *nfp_prog, + const struct bpf_verifier_env *env, u8 reg) +{ + if (env->cur_state.regs[reg].type != PTR_TO_CTX) + return -EINVAL; + + return 0; +} + +static int +nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) +{ + struct nfp_bpf_analyzer_priv *priv = env->analyzer_priv; + struct nfp_insn_meta *meta = priv->meta; + + meta = nfp_bpf_goto_meta(priv->prog, meta, insn_idx, env->prog->len); + priv->meta = meta; + + if (meta->insn.src_reg == BPF_REG_10 || + meta->insn.dst_reg == BPF_REG_10) { + pr_err("stack not yet supported\n"); + return -EINVAL; + } + if (meta->insn.src_reg >= MAX_BPF_REG || + meta->insn.dst_reg >= MAX_BPF_REG) { + pr_err("program uses extended registers - jit hardening?\n"); + return -EINVAL; + } + + if (meta->insn.code == (BPF_JMP | BPF_EXIT)) + return nfp_bpf_check_exit(priv->prog, env); + + if ((meta->insn.code & ~BPF_SIZE_MASK) == (BPF_LDX | BPF_MEM)) + return nfp_bpf_check_ctx_ptr(priv->prog, env, + meta->insn.src_reg); + if ((meta->insn.code & ~BPF_SIZE_MASK) == (BPF_STX | BPF_MEM)) + return nfp_bpf_check_ctx_ptr(priv->prog, env, + meta->insn.dst_reg); + + return 0; +} + +static const struct bpf_ext_analyzer_ops nfp_bpf_analyzer_ops = { + .insn_hook = nfp_verify_insn, +}; + +int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog) +{ + struct nfp_bpf_analyzer_priv *priv; + int ret; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->prog = nfp_prog; + priv->meta = nfp_prog_first_meta(nfp_prog); + + ret = bpf_analyzer(prog, &nfp_bpf_analyzer_ops, priv); + + kfree(priv); + + return ret; +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_asm.h b/drivers/net/ethernet/netronome/nfp/nfp_asm.h index 22484b6fd3e8..d2b535739d2b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_asm.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_asm.h @@ -34,7 +34,7 @@ #ifndef __NFP_ASM_H__ #define __NFP_ASM_H__ 1 -#include "nfp_bpf.h" +#include #define REG_NONE 0 diff --git a/drivers/net/ethernet/netronome/nfp/nfp_bpf.h b/drivers/net/ethernet/netronome/nfp/nfp_bpf.h deleted file mode 100644 index 9513c80f7be5..000000000000 --- a/drivers/net/ethernet/netronome/nfp/nfp_bpf.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2016 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __NFP_BPF_H__ -#define __NFP_BPF_H__ 1 - -#include -#include -#include -#include - -/* For branch fixup logic use up-most byte of branch instruction as scratch - * area. Remember to clear this before sending instructions to HW! - */ -#define OP_BR_SPECIAL 0xff00000000000000ULL - -enum br_special { - OP_BR_NORMAL = 0, - OP_BR_GO_OUT, - OP_BR_GO_ABORT, -}; - -enum static_regs { - STATIC_REG_PKT = 1, -#define REG_PKT_BANK ALU_DST_A - STATIC_REG_IMM = 2, /* Bank AB */ -}; - -enum nfp_bpf_action_type { - NN_ACT_TC_DROP, - NN_ACT_TC_REDIR, - NN_ACT_DIRECT, - NN_ACT_XDP, -}; - -/* Software register representation, hardware encoding in asm.h */ -#define NN_REG_TYPE GENMASK(31, 24) -#define NN_REG_VAL GENMASK(7, 0) - -enum nfp_bpf_reg_type { - NN_REG_GPR_A = BIT(0), - NN_REG_GPR_B = BIT(1), - NN_REG_NNR = BIT(2), - NN_REG_XFER = BIT(3), - NN_REG_IMM = BIT(4), - NN_REG_NONE = BIT(5), -}; - -#define NN_REG_GPR_BOTH (NN_REG_GPR_A | NN_REG_GPR_B) - -#define reg_both(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_GPR_BOTH)) -#define reg_a(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_GPR_A)) -#define reg_b(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_GPR_B)) -#define reg_nnr(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_NNR)) -#define reg_xfer(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_XFER)) -#define reg_imm(x) ((x) | FIELD_PREP(NN_REG_TYPE, NN_REG_IMM)) -#define reg_none() (FIELD_PREP(NN_REG_TYPE, NN_REG_NONE)) - -#define pkt_reg(np) reg_a((np)->regs_per_thread - STATIC_REG_PKT) -#define imm_a(np) reg_a((np)->regs_per_thread - STATIC_REG_IMM) -#define imm_b(np) reg_b((np)->regs_per_thread - STATIC_REG_IMM) -#define imm_both(np) reg_both((np)->regs_per_thread - STATIC_REG_IMM) - -#define NFP_BPF_ABI_FLAGS reg_nnr(0) -#define NFP_BPF_ABI_FLAG_MARK 1 -#define NFP_BPF_ABI_MARK reg_nnr(1) -#define NFP_BPF_ABI_PKT reg_nnr(2) -#define NFP_BPF_ABI_LEN reg_nnr(3) - -struct nfp_prog; -struct nfp_insn_meta; -typedef int (*instr_cb_t)(struct nfp_prog *, struct nfp_insn_meta *); - -#define nfp_prog_first_meta(nfp_prog) \ - list_first_entry(&(nfp_prog)->insns, struct nfp_insn_meta, l) -#define nfp_prog_last_meta(nfp_prog) \ - list_last_entry(&(nfp_prog)->insns, struct nfp_insn_meta, l) -#define nfp_meta_next(meta) list_next_entry(meta, l) -#define nfp_meta_prev(meta) list_prev_entry(meta, l) - -/** - * struct nfp_insn_meta - BPF instruction wrapper - * @insn: BPF instruction - * @off: index of first generated machine instruction (in nfp_prog.prog) - * @n: eBPF instruction number - * @skip: skip this instruction (optimized out) - * @double_cb: callback for second part of the instruction - * @l: link on nfp_prog->insns list - */ -struct nfp_insn_meta { - struct bpf_insn insn; - unsigned int off; - unsigned short n; - bool skip; - instr_cb_t double_cb; - - struct list_head l; -}; - -#define BPF_SIZE_MASK 0x18 - -static inline u8 mbpf_class(const struct nfp_insn_meta *meta) -{ - return BPF_CLASS(meta->insn.code); -} - -static inline u8 mbpf_src(const struct nfp_insn_meta *meta) -{ - return BPF_SRC(meta->insn.code); -} - -static inline u8 mbpf_op(const struct nfp_insn_meta *meta) -{ - return BPF_OP(meta->insn.code); -} - -static inline u8 mbpf_mode(const struct nfp_insn_meta *meta) -{ - return BPF_MODE(meta->insn.code); -} - -/** - * struct nfp_prog - nfp BPF program - * @prog: machine code - * @prog_len: number of valid instructions in @prog array - * @__prog_alloc_len: alloc size of @prog array - * @act: BPF program/action type (TC DA, TC with action, XDP etc.) - * @num_regs: number of registers used by this program - * @regs_per_thread: number of basic registers allocated per thread - * @start_off: address of the first instruction in the memory - * @tgt_out: jump target for normal exit - * @tgt_abort: jump target for abort (e.g. access outside of packet buffer) - * @tgt_done: jump target to get the next packet - * @n_translated: number of successfully translated instructions (for errors) - * @error: error code if something went wrong - * @insns: list of BPF instruction wrappers (struct nfp_insn_meta) - */ -struct nfp_prog { - u64 *prog; - unsigned int prog_len; - unsigned int __prog_alloc_len; - - enum nfp_bpf_action_type act; - - unsigned int num_regs; - unsigned int regs_per_thread; - - unsigned int start_off; - unsigned int tgt_out; - unsigned int tgt_abort; - unsigned int tgt_done; - - unsigned int n_translated; - int error; - - struct list_head insns; -}; - -struct nfp_bpf_result { - unsigned int n_instr; - bool dense_mode; -}; - -int -nfp_bpf_jit(struct bpf_prog *filter, void *prog, enum nfp_bpf_action_type act, - unsigned int prog_start, unsigned int prog_done, - unsigned int prog_sz, struct nfp_bpf_result *res); - -int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog); - -#endif diff --git a/drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c b/drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c deleted file mode 100644 index 97a8f00674d0..000000000000 --- a/drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c +++ /dev/null @@ -1,1899 +0,0 @@ -/* - * Copyright (C) 2016 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define pr_fmt(fmt) "NFP net bpf: " fmt - -#include -#include -#include -#include -#include - -#include "nfp_asm.h" -#include "nfp_bpf.h" - -/* --- NFP prog --- */ -/* Foreach "multiple" entries macros provide pos and next pointers. - * It's safe to modify the next pointers (but not pos). - */ -#define nfp_for_each_insn_walk2(nfp_prog, pos, next) \ - for (pos = list_first_entry(&(nfp_prog)->insns, typeof(*pos), l), \ - next = list_next_entry(pos, l); \ - &(nfp_prog)->insns != &pos->l && \ - &(nfp_prog)->insns != &next->l; \ - pos = nfp_meta_next(pos), \ - next = nfp_meta_next(pos)) - -#define nfp_for_each_insn_walk3(nfp_prog, pos, next, next2) \ - for (pos = list_first_entry(&(nfp_prog)->insns, typeof(*pos), l), \ - next = list_next_entry(pos, l), \ - next2 = list_next_entry(next, l); \ - &(nfp_prog)->insns != &pos->l && \ - &(nfp_prog)->insns != &next->l && \ - &(nfp_prog)->insns != &next2->l; \ - pos = nfp_meta_next(pos), \ - next = nfp_meta_next(pos), \ - next2 = nfp_meta_next(next)) - -static bool -nfp_meta_has_next(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return meta->l.next != &nfp_prog->insns; -} - -static bool -nfp_meta_has_prev(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return meta->l.prev != &nfp_prog->insns; -} - -static void nfp_prog_free(struct nfp_prog *nfp_prog) -{ - struct nfp_insn_meta *meta, *tmp; - - list_for_each_entry_safe(meta, tmp, &nfp_prog->insns, l) { - list_del(&meta->l); - kfree(meta); - } - kfree(nfp_prog); -} - -static void nfp_prog_push(struct nfp_prog *nfp_prog, u64 insn) -{ - if (nfp_prog->__prog_alloc_len == nfp_prog->prog_len) { - nfp_prog->error = -ENOSPC; - return; - } - - nfp_prog->prog[nfp_prog->prog_len] = insn; - nfp_prog->prog_len++; -} - -static unsigned int nfp_prog_current_offset(struct nfp_prog *nfp_prog) -{ - return nfp_prog->start_off + nfp_prog->prog_len; -} - -static unsigned int -nfp_prog_offset_to_index(struct nfp_prog *nfp_prog, unsigned int offset) -{ - return offset - nfp_prog->start_off; -} - -/* --- SW reg --- */ -struct nfp_insn_ur_regs { - enum alu_dst_ab dst_ab; - u16 dst; - u16 areg, breg; - bool swap; - bool wr_both; -}; - -struct nfp_insn_re_regs { - enum alu_dst_ab dst_ab; - u8 dst; - u8 areg, breg; - bool swap; - bool wr_both; - bool i8; -}; - -static u16 nfp_swreg_to_unreg(u32 swreg, bool is_dst) -{ - u16 val = FIELD_GET(NN_REG_VAL, swreg); - - switch (FIELD_GET(NN_REG_TYPE, swreg)) { - case NN_REG_GPR_A: - case NN_REG_GPR_B: - case NN_REG_GPR_BOTH: - return val; - case NN_REG_NNR: - return UR_REG_NN | val; - case NN_REG_XFER: - return UR_REG_XFR | val; - case NN_REG_IMM: - if (val & ~0xff) { - pr_err("immediate too large\n"); - return 0; - } - return UR_REG_IMM_encode(val); - case NN_REG_NONE: - return is_dst ? UR_REG_NO_DST : REG_NONE; - default: - pr_err("unrecognized reg encoding %08x\n", swreg); - return 0; - } -} - -static int -swreg_to_unrestricted(u32 dst, u32 lreg, u32 rreg, struct nfp_insn_ur_regs *reg) -{ - memset(reg, 0, sizeof(*reg)); - - /* Decode destination */ - if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_IMM) - return -EFAULT; - - if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_GPR_B) - reg->dst_ab = ALU_DST_B; - if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_GPR_BOTH) - reg->wr_both = true; - reg->dst = nfp_swreg_to_unreg(dst, true); - - /* Decode source operands */ - if (FIELD_GET(NN_REG_TYPE, lreg) == FIELD_GET(NN_REG_TYPE, rreg)) - return -EFAULT; - - if (FIELD_GET(NN_REG_TYPE, lreg) == NN_REG_GPR_B || - FIELD_GET(NN_REG_TYPE, rreg) == NN_REG_GPR_A) { - reg->areg = nfp_swreg_to_unreg(rreg, false); - reg->breg = nfp_swreg_to_unreg(lreg, false); - reg->swap = true; - } else { - reg->areg = nfp_swreg_to_unreg(lreg, false); - reg->breg = nfp_swreg_to_unreg(rreg, false); - } - - return 0; -} - -static u16 nfp_swreg_to_rereg(u32 swreg, bool is_dst, bool has_imm8, bool *i8) -{ - u16 val = FIELD_GET(NN_REG_VAL, swreg); - - switch (FIELD_GET(NN_REG_TYPE, swreg)) { - case NN_REG_GPR_A: - case NN_REG_GPR_B: - case NN_REG_GPR_BOTH: - return val; - case NN_REG_XFER: - return RE_REG_XFR | val; - case NN_REG_IMM: - if (val & ~(0x7f | has_imm8 << 7)) { - pr_err("immediate too large\n"); - return 0; - } - *i8 = val & 0x80; - return RE_REG_IMM_encode(val & 0x7f); - case NN_REG_NONE: - return is_dst ? RE_REG_NO_DST : REG_NONE; - default: - pr_err("unrecognized reg encoding\n"); - return 0; - } -} - -static int -swreg_to_restricted(u32 dst, u32 lreg, u32 rreg, struct nfp_insn_re_regs *reg, - bool has_imm8) -{ - memset(reg, 0, sizeof(*reg)); - - /* Decode destination */ - if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_IMM) - return -EFAULT; - - if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_GPR_B) - reg->dst_ab = ALU_DST_B; - if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_GPR_BOTH) - reg->wr_both = true; - reg->dst = nfp_swreg_to_rereg(dst, true, false, NULL); - - /* Decode source operands */ - if (FIELD_GET(NN_REG_TYPE, lreg) == FIELD_GET(NN_REG_TYPE, rreg)) - return -EFAULT; - - if (FIELD_GET(NN_REG_TYPE, lreg) == NN_REG_GPR_B || - FIELD_GET(NN_REG_TYPE, rreg) == NN_REG_GPR_A) { - reg->areg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); - reg->breg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); - reg->swap = true; - } else { - reg->areg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); - reg->breg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); - } - - return 0; -} - -/* --- Emitters --- */ -static const struct cmd_tgt_act cmd_tgt_act[__CMD_TGT_MAP_SIZE] = { - [CMD_TGT_WRITE8] = { 0x00, 0x42 }, - [CMD_TGT_READ8] = { 0x01, 0x43 }, - [CMD_TGT_READ_LE] = { 0x01, 0x40 }, - [CMD_TGT_READ_SWAP_LE] = { 0x03, 0x40 }, -}; - -static void -__emit_cmd(struct nfp_prog *nfp_prog, enum cmd_tgt_map op, - u8 mode, u8 xfer, u8 areg, u8 breg, u8 size, bool sync) -{ - enum cmd_ctx_swap ctx; - u64 insn; - - if (sync) - ctx = CMD_CTX_SWAP; - else - ctx = CMD_CTX_NO_SWAP; - - insn = FIELD_PREP(OP_CMD_A_SRC, areg) | - FIELD_PREP(OP_CMD_CTX, ctx) | - FIELD_PREP(OP_CMD_B_SRC, breg) | - FIELD_PREP(OP_CMD_TOKEN, cmd_tgt_act[op].token) | - FIELD_PREP(OP_CMD_XFER, xfer) | - FIELD_PREP(OP_CMD_CNT, size) | - FIELD_PREP(OP_CMD_SIG, sync) | - FIELD_PREP(OP_CMD_TGT_CMD, cmd_tgt_act[op].tgt_cmd) | - FIELD_PREP(OP_CMD_MODE, mode); - - nfp_prog_push(nfp_prog, insn); -} - -static void -emit_cmd(struct nfp_prog *nfp_prog, enum cmd_tgt_map op, - u8 mode, u8 xfer, u32 lreg, u32 rreg, u8 size, bool sync) -{ - struct nfp_insn_re_regs reg; - int err; - - err = swreg_to_restricted(reg_none(), lreg, rreg, ®, false); - if (err) { - nfp_prog->error = err; - return; - } - if (reg.swap) { - pr_err("cmd can't swap arguments\n"); - nfp_prog->error = -EFAULT; - return; - } - - __emit_cmd(nfp_prog, op, mode, xfer, reg.areg, reg.breg, size, sync); -} - -static void -__emit_br(struct nfp_prog *nfp_prog, enum br_mask mask, enum br_ev_pip ev_pip, - enum br_ctx_signal_state css, u16 addr, u8 defer) -{ - u16 addr_lo, addr_hi; - u64 insn; - - addr_lo = addr & (OP_BR_ADDR_LO >> __bf_shf(OP_BR_ADDR_LO)); - addr_hi = addr != addr_lo; - - insn = OP_BR_BASE | - FIELD_PREP(OP_BR_MASK, mask) | - FIELD_PREP(OP_BR_EV_PIP, ev_pip) | - FIELD_PREP(OP_BR_CSS, css) | - FIELD_PREP(OP_BR_DEFBR, defer) | - FIELD_PREP(OP_BR_ADDR_LO, addr_lo) | - FIELD_PREP(OP_BR_ADDR_HI, addr_hi); - - nfp_prog_push(nfp_prog, insn); -} - -static void emit_br_def(struct nfp_prog *nfp_prog, u16 addr, u8 defer) -{ - if (defer > 2) { - pr_err("BUG: branch defer out of bounds %d\n", defer); - nfp_prog->error = -EFAULT; - return; - } - __emit_br(nfp_prog, BR_UNC, BR_EV_PIP_UNCOND, BR_CSS_NONE, addr, defer); -} - -static void -emit_br(struct nfp_prog *nfp_prog, enum br_mask mask, u16 addr, u8 defer) -{ - __emit_br(nfp_prog, mask, - mask != BR_UNC ? BR_EV_PIP_COND : BR_EV_PIP_UNCOND, - BR_CSS_NONE, addr, defer); -} - -static void -__emit_br_byte(struct nfp_prog *nfp_prog, u8 areg, u8 breg, bool imm8, - u8 byte, bool equal, u16 addr, u8 defer) -{ - u16 addr_lo, addr_hi; - u64 insn; - - addr_lo = addr & (OP_BB_ADDR_LO >> __bf_shf(OP_BB_ADDR_LO)); - addr_hi = addr != addr_lo; - - insn = OP_BBYTE_BASE | - FIELD_PREP(OP_BB_A_SRC, areg) | - FIELD_PREP(OP_BB_BYTE, byte) | - FIELD_PREP(OP_BB_B_SRC, breg) | - FIELD_PREP(OP_BB_I8, imm8) | - FIELD_PREP(OP_BB_EQ, equal) | - FIELD_PREP(OP_BB_DEFBR, defer) | - FIELD_PREP(OP_BB_ADDR_LO, addr_lo) | - FIELD_PREP(OP_BB_ADDR_HI, addr_hi); - - nfp_prog_push(nfp_prog, insn); -} - -static void -emit_br_byte_neq(struct nfp_prog *nfp_prog, - u32 dst, u8 imm, u8 byte, u16 addr, u8 defer) -{ - struct nfp_insn_re_regs reg; - int err; - - err = swreg_to_restricted(reg_none(), dst, reg_imm(imm), ®, true); - if (err) { - nfp_prog->error = err; - return; - } - - __emit_br_byte(nfp_prog, reg.areg, reg.breg, reg.i8, byte, false, addr, - defer); -} - -static void -__emit_immed(struct nfp_prog *nfp_prog, u16 areg, u16 breg, u16 imm_hi, - enum immed_width width, bool invert, - enum immed_shift shift, bool wr_both) -{ - u64 insn; - - insn = OP_IMMED_BASE | - FIELD_PREP(OP_IMMED_A_SRC, areg) | - FIELD_PREP(OP_IMMED_B_SRC, breg) | - FIELD_PREP(OP_IMMED_IMM, imm_hi) | - FIELD_PREP(OP_IMMED_WIDTH, width) | - FIELD_PREP(OP_IMMED_INV, invert) | - FIELD_PREP(OP_IMMED_SHIFT, shift) | - FIELD_PREP(OP_IMMED_WR_AB, wr_both); - - nfp_prog_push(nfp_prog, insn); -} - -static void -emit_immed(struct nfp_prog *nfp_prog, u32 dst, u16 imm, - enum immed_width width, bool invert, enum immed_shift shift) -{ - struct nfp_insn_ur_regs reg; - int err; - - if (FIELD_GET(NN_REG_TYPE, dst) == NN_REG_IMM) { - nfp_prog->error = -EFAULT; - return; - } - - err = swreg_to_unrestricted(dst, dst, reg_imm(imm & 0xff), ®); - if (err) { - nfp_prog->error = err; - return; - } - - __emit_immed(nfp_prog, reg.areg, reg.breg, imm >> 8, width, - invert, shift, reg.wr_both); -} - -static void -__emit_shf(struct nfp_prog *nfp_prog, u16 dst, enum alu_dst_ab dst_ab, - enum shf_sc sc, u8 shift, - u16 areg, enum shf_op op, u16 breg, bool i8, bool sw, bool wr_both) -{ - u64 insn; - - if (!FIELD_FIT(OP_SHF_SHIFT, shift)) { - nfp_prog->error = -EFAULT; - return; - } - - if (sc == SHF_SC_L_SHF) - shift = 32 - shift; - - insn = OP_SHF_BASE | - FIELD_PREP(OP_SHF_A_SRC, areg) | - FIELD_PREP(OP_SHF_SC, sc) | - FIELD_PREP(OP_SHF_B_SRC, breg) | - FIELD_PREP(OP_SHF_I8, i8) | - FIELD_PREP(OP_SHF_SW, sw) | - FIELD_PREP(OP_SHF_DST, dst) | - FIELD_PREP(OP_SHF_SHIFT, shift) | - FIELD_PREP(OP_SHF_OP, op) | - FIELD_PREP(OP_SHF_DST_AB, dst_ab) | - FIELD_PREP(OP_SHF_WR_AB, wr_both); - - nfp_prog_push(nfp_prog, insn); -} - -static void -emit_shf(struct nfp_prog *nfp_prog, u32 dst, u32 lreg, enum shf_op op, u32 rreg, - enum shf_sc sc, u8 shift) -{ - struct nfp_insn_re_regs reg; - int err; - - err = swreg_to_restricted(dst, lreg, rreg, ®, true); - if (err) { - nfp_prog->error = err; - return; - } - - __emit_shf(nfp_prog, reg.dst, reg.dst_ab, sc, shift, - reg.areg, op, reg.breg, reg.i8, reg.swap, reg.wr_both); -} - -static void -__emit_alu(struct nfp_prog *nfp_prog, u16 dst, enum alu_dst_ab dst_ab, - u16 areg, enum alu_op op, u16 breg, bool swap, bool wr_both) -{ - u64 insn; - - insn = OP_ALU_BASE | - FIELD_PREP(OP_ALU_A_SRC, areg) | - FIELD_PREP(OP_ALU_B_SRC, breg) | - FIELD_PREP(OP_ALU_DST, dst) | - FIELD_PREP(OP_ALU_SW, swap) | - FIELD_PREP(OP_ALU_OP, op) | - FIELD_PREP(OP_ALU_DST_AB, dst_ab) | - FIELD_PREP(OP_ALU_WR_AB, wr_both); - - nfp_prog_push(nfp_prog, insn); -} - -static void -emit_alu(struct nfp_prog *nfp_prog, u32 dst, u32 lreg, enum alu_op op, u32 rreg) -{ - struct nfp_insn_ur_regs reg; - int err; - - err = swreg_to_unrestricted(dst, lreg, rreg, ®); - if (err) { - nfp_prog->error = err; - return; - } - - __emit_alu(nfp_prog, reg.dst, reg.dst_ab, - reg.areg, op, reg.breg, reg.swap, reg.wr_both); -} - -static void -__emit_ld_field(struct nfp_prog *nfp_prog, enum shf_sc sc, - u8 areg, u8 bmask, u8 breg, u8 shift, bool imm8, - bool zero, bool swap, bool wr_both) -{ - u64 insn; - - insn = OP_LDF_BASE | - FIELD_PREP(OP_LDF_A_SRC, areg) | - FIELD_PREP(OP_LDF_SC, sc) | - FIELD_PREP(OP_LDF_B_SRC, breg) | - FIELD_PREP(OP_LDF_I8, imm8) | - FIELD_PREP(OP_LDF_SW, swap) | - FIELD_PREP(OP_LDF_ZF, zero) | - FIELD_PREP(OP_LDF_BMASK, bmask) | - FIELD_PREP(OP_LDF_SHF, shift) | - FIELD_PREP(OP_LDF_WR_AB, wr_both); - - nfp_prog_push(nfp_prog, insn); -} - -static void -emit_ld_field_any(struct nfp_prog *nfp_prog, enum shf_sc sc, u8 shift, - u32 dst, u8 bmask, u32 src, bool zero) -{ - struct nfp_insn_re_regs reg; - int err; - - err = swreg_to_restricted(reg_none(), dst, src, ®, true); - if (err) { - nfp_prog->error = err; - return; - } - - __emit_ld_field(nfp_prog, sc, reg.areg, bmask, reg.breg, shift, - reg.i8, zero, reg.swap, reg.wr_both); -} - -static void -emit_ld_field(struct nfp_prog *nfp_prog, u32 dst, u8 bmask, u32 src, - enum shf_sc sc, u8 shift) -{ - emit_ld_field_any(nfp_prog, sc, shift, dst, bmask, src, false); -} - -/* --- Wrappers --- */ -static bool pack_immed(u32 imm, u16 *val, enum immed_shift *shift) -{ - if (!(imm & 0xffff0000)) { - *val = imm; - *shift = IMMED_SHIFT_0B; - } else if (!(imm & 0xff0000ff)) { - *val = imm >> 8; - *shift = IMMED_SHIFT_1B; - } else if (!(imm & 0x0000ffff)) { - *val = imm >> 16; - *shift = IMMED_SHIFT_2B; - } else { - return false; - } - - return true; -} - -static void wrp_immed(struct nfp_prog *nfp_prog, u32 dst, u32 imm) -{ - enum immed_shift shift; - u16 val; - - if (pack_immed(imm, &val, &shift)) { - emit_immed(nfp_prog, dst, val, IMMED_WIDTH_ALL, false, shift); - } else if (pack_immed(~imm, &val, &shift)) { - emit_immed(nfp_prog, dst, val, IMMED_WIDTH_ALL, true, shift); - } else { - emit_immed(nfp_prog, dst, imm & 0xffff, IMMED_WIDTH_ALL, - false, IMMED_SHIFT_0B); - emit_immed(nfp_prog, dst, imm >> 16, IMMED_WIDTH_WORD, - false, IMMED_SHIFT_2B); - } -} - -/* ur_load_imm_any() - encode immediate or use tmp register (unrestricted) - * If the @imm is small enough encode it directly in operand and return - * otherwise load @imm to a spare register and return its encoding. - */ -static u32 ur_load_imm_any(struct nfp_prog *nfp_prog, u32 imm, u32 tmp_reg) -{ - if (FIELD_FIT(UR_REG_IMM_MAX, imm)) - return reg_imm(imm); - - wrp_immed(nfp_prog, tmp_reg, imm); - return tmp_reg; -} - -/* re_load_imm_any() - encode immediate or use tmp register (restricted) - * If the @imm is small enough encode it directly in operand and return - * otherwise load @imm to a spare register and return its encoding. - */ -static u32 re_load_imm_any(struct nfp_prog *nfp_prog, u32 imm, u32 tmp_reg) -{ - if (FIELD_FIT(RE_REG_IMM_MAX, imm)) - return reg_imm(imm); - - wrp_immed(nfp_prog, tmp_reg, imm); - return tmp_reg; -} - -static void -wrp_br_special(struct nfp_prog *nfp_prog, enum br_mask mask, - enum br_special special) -{ - emit_br(nfp_prog, mask, 0, 0); - - nfp_prog->prog[nfp_prog->prog_len - 1] |= - FIELD_PREP(OP_BR_SPECIAL, special); -} - -static void wrp_reg_mov(struct nfp_prog *nfp_prog, u16 dst, u16 src) -{ - emit_alu(nfp_prog, reg_both(dst), reg_none(), ALU_OP_NONE, reg_b(src)); -} - -static int -construct_data_ind_ld(struct nfp_prog *nfp_prog, u16 offset, - u16 src, bool src_valid, u8 size) -{ - unsigned int i; - u16 shift, sz; - u32 tmp_reg; - - /* We load the value from the address indicated in @offset and then - * shift out the data we don't need. Note: this is big endian! - */ - sz = size < 4 ? 4 : size; - shift = size < 4 ? 4 - size : 0; - - if (src_valid) { - /* Calculate the true offset (src_reg + imm) */ - tmp_reg = ur_load_imm_any(nfp_prog, offset, imm_b(nfp_prog)); - emit_alu(nfp_prog, imm_both(nfp_prog), - reg_a(src), ALU_OP_ADD, tmp_reg); - /* Check packet length (size guaranteed to fit b/c it's u8) */ - emit_alu(nfp_prog, imm_a(nfp_prog), - imm_a(nfp_prog), ALU_OP_ADD, reg_imm(size)); - emit_alu(nfp_prog, reg_none(), - NFP_BPF_ABI_LEN, ALU_OP_SUB, imm_a(nfp_prog)); - wrp_br_special(nfp_prog, BR_BLO, OP_BR_GO_ABORT); - /* Load data */ - emit_cmd(nfp_prog, CMD_TGT_READ8, CMD_MODE_32b, 0, - pkt_reg(nfp_prog), imm_b(nfp_prog), sz - 1, true); - } else { - /* Check packet length */ - tmp_reg = ur_load_imm_any(nfp_prog, offset + size, - imm_a(nfp_prog)); - emit_alu(nfp_prog, reg_none(), - NFP_BPF_ABI_LEN, ALU_OP_SUB, tmp_reg); - wrp_br_special(nfp_prog, BR_BLO, OP_BR_GO_ABORT); - /* Load data */ - tmp_reg = re_load_imm_any(nfp_prog, offset, imm_b(nfp_prog)); - emit_cmd(nfp_prog, CMD_TGT_READ8, CMD_MODE_32b, 0, - pkt_reg(nfp_prog), tmp_reg, sz - 1, true); - } - - i = 0; - if (shift) - emit_shf(nfp_prog, reg_both(0), reg_none(), SHF_OP_NONE, - reg_xfer(0), SHF_SC_R_SHF, shift * 8); - else - for (; i * 4 < size; i++) - emit_alu(nfp_prog, reg_both(i), - reg_none(), ALU_OP_NONE, reg_xfer(i)); - - if (i < 2) - wrp_immed(nfp_prog, reg_both(1), 0); - - return 0; -} - -static int construct_data_ld(struct nfp_prog *nfp_prog, u16 offset, u8 size) -{ - return construct_data_ind_ld(nfp_prog, offset, 0, false, size); -} - -static int wrp_set_mark(struct nfp_prog *nfp_prog, u8 src) -{ - emit_alu(nfp_prog, NFP_BPF_ABI_MARK, - reg_none(), ALU_OP_NONE, reg_b(src)); - emit_alu(nfp_prog, NFP_BPF_ABI_FLAGS, - NFP_BPF_ABI_FLAGS, ALU_OP_OR, reg_imm(NFP_BPF_ABI_FLAG_MARK)); - - return 0; -} - -static void -wrp_alu_imm(struct nfp_prog *nfp_prog, u8 dst, enum alu_op alu_op, u32 imm) -{ - u32 tmp_reg; - - if (alu_op == ALU_OP_AND) { - if (!imm) - wrp_immed(nfp_prog, reg_both(dst), 0); - if (!imm || !~imm) - return; - } - if (alu_op == ALU_OP_OR) { - if (!~imm) - wrp_immed(nfp_prog, reg_both(dst), ~0U); - if (!imm || !~imm) - return; - } - if (alu_op == ALU_OP_XOR) { - if (!~imm) - emit_alu(nfp_prog, reg_both(dst), reg_none(), - ALU_OP_NEG, reg_b(dst)); - if (!imm || !~imm) - return; - } - - tmp_reg = ur_load_imm_any(nfp_prog, imm, imm_b(nfp_prog)); - emit_alu(nfp_prog, reg_both(dst), reg_a(dst), alu_op, tmp_reg); -} - -static int -wrp_alu64_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, - enum alu_op alu_op, bool skip) -{ - const struct bpf_insn *insn = &meta->insn; - u64 imm = insn->imm; /* sign extend */ - - if (skip) { - meta->skip = true; - return 0; - } - - wrp_alu_imm(nfp_prog, insn->dst_reg * 2, alu_op, imm & ~0U); - wrp_alu_imm(nfp_prog, insn->dst_reg * 2 + 1, alu_op, imm >> 32); - - return 0; -} - -static int -wrp_alu64_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, - enum alu_op alu_op) -{ - u8 dst = meta->insn.dst_reg * 2, src = meta->insn.src_reg * 2; - - emit_alu(nfp_prog, reg_both(dst), reg_a(dst), alu_op, reg_b(src)); - emit_alu(nfp_prog, reg_both(dst + 1), - reg_a(dst + 1), alu_op, reg_b(src + 1)); - - return 0; -} - -static int -wrp_alu32_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, - enum alu_op alu_op, bool skip) -{ - const struct bpf_insn *insn = &meta->insn; - - if (skip) { - meta->skip = true; - return 0; - } - - wrp_alu_imm(nfp_prog, insn->dst_reg * 2, alu_op, insn->imm); - wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); - - return 0; -} - -static int -wrp_alu32_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, - enum alu_op alu_op) -{ - u8 dst = meta->insn.dst_reg * 2, src = meta->insn.src_reg * 2; - - emit_alu(nfp_prog, reg_both(dst), reg_a(dst), alu_op, reg_b(src)); - wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2 + 1), 0); - - return 0; -} - -static void -wrp_test_reg_one(struct nfp_prog *nfp_prog, u8 dst, enum alu_op alu_op, u8 src, - enum br_mask br_mask, u16 off) -{ - emit_alu(nfp_prog, reg_none(), reg_a(dst), alu_op, reg_b(src)); - emit_br(nfp_prog, br_mask, off, 0); -} - -static int -wrp_test_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, - enum alu_op alu_op, enum br_mask br_mask) -{ - const struct bpf_insn *insn = &meta->insn; - - if (insn->off < 0) /* TODO */ - return -EOPNOTSUPP; - - wrp_test_reg_one(nfp_prog, insn->dst_reg * 2, alu_op, - insn->src_reg * 2, br_mask, insn->off); - wrp_test_reg_one(nfp_prog, insn->dst_reg * 2 + 1, alu_op, - insn->src_reg * 2 + 1, br_mask, insn->off); - - return 0; -} - -static int -wrp_cmp_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, - enum br_mask br_mask, bool swap) -{ - const struct bpf_insn *insn = &meta->insn; - u64 imm = insn->imm; /* sign extend */ - u8 reg = insn->dst_reg * 2; - u32 tmp_reg; - - if (insn->off < 0) /* TODO */ - return -EOPNOTSUPP; - - tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); - if (!swap) - emit_alu(nfp_prog, reg_none(), reg_a(reg), ALU_OP_SUB, tmp_reg); - else - emit_alu(nfp_prog, reg_none(), tmp_reg, ALU_OP_SUB, reg_a(reg)); - - tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); - if (!swap) - emit_alu(nfp_prog, reg_none(), - reg_a(reg + 1), ALU_OP_SUB_C, tmp_reg); - else - emit_alu(nfp_prog, reg_none(), - tmp_reg, ALU_OP_SUB_C, reg_a(reg + 1)); - - emit_br(nfp_prog, br_mask, insn->off, 0); - - return 0; -} - -static int -wrp_cmp_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, - enum br_mask br_mask, bool swap) -{ - const struct bpf_insn *insn = &meta->insn; - u8 areg = insn->src_reg * 2, breg = insn->dst_reg * 2; - - if (insn->off < 0) /* TODO */ - return -EOPNOTSUPP; - - if (swap) { - areg ^= breg; - breg ^= areg; - areg ^= breg; - } - - emit_alu(nfp_prog, reg_none(), reg_a(areg), ALU_OP_SUB, reg_b(breg)); - emit_alu(nfp_prog, reg_none(), - reg_a(areg + 1), ALU_OP_SUB_C, reg_b(breg + 1)); - emit_br(nfp_prog, br_mask, insn->off, 0); - - return 0; -} - -/* --- Callbacks --- */ -static int mov_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - wrp_reg_mov(nfp_prog, insn->dst_reg * 2, insn->src_reg * 2); - wrp_reg_mov(nfp_prog, insn->dst_reg * 2 + 1, insn->src_reg * 2 + 1); - - return 0; -} - -static int mov_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - u64 imm = meta->insn.imm; /* sign extend */ - - wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2), imm & ~0U); - wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2 + 1), imm >> 32); - - return 0; -} - -static int xor_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu64_reg(nfp_prog, meta, ALU_OP_XOR); -} - -static int xor_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu64_imm(nfp_prog, meta, ALU_OP_XOR, !meta->insn.imm); -} - -static int and_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu64_reg(nfp_prog, meta, ALU_OP_AND); -} - -static int and_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu64_imm(nfp_prog, meta, ALU_OP_AND, !~meta->insn.imm); -} - -static int or_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu64_reg(nfp_prog, meta, ALU_OP_OR); -} - -static int or_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu64_imm(nfp_prog, meta, ALU_OP_OR, !meta->insn.imm); -} - -static int add_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - emit_alu(nfp_prog, reg_both(insn->dst_reg * 2), - reg_a(insn->dst_reg * 2), ALU_OP_ADD, - reg_b(insn->src_reg * 2)); - emit_alu(nfp_prog, reg_both(insn->dst_reg * 2 + 1), - reg_a(insn->dst_reg * 2 + 1), ALU_OP_ADD_C, - reg_b(insn->src_reg * 2 + 1)); - - return 0; -} - -static int add_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - u64 imm = insn->imm; /* sign extend */ - - wrp_alu_imm(nfp_prog, insn->dst_reg * 2, ALU_OP_ADD, imm & ~0U); - wrp_alu_imm(nfp_prog, insn->dst_reg * 2 + 1, ALU_OP_ADD_C, imm >> 32); - - return 0; -} - -static int sub_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - emit_alu(nfp_prog, reg_both(insn->dst_reg * 2), - reg_a(insn->dst_reg * 2), ALU_OP_SUB, - reg_b(insn->src_reg * 2)); - emit_alu(nfp_prog, reg_both(insn->dst_reg * 2 + 1), - reg_a(insn->dst_reg * 2 + 1), ALU_OP_SUB_C, - reg_b(insn->src_reg * 2 + 1)); - - return 0; -} - -static int sub_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - u64 imm = insn->imm; /* sign extend */ - - wrp_alu_imm(nfp_prog, insn->dst_reg * 2, ALU_OP_SUB, imm & ~0U); - wrp_alu_imm(nfp_prog, insn->dst_reg * 2 + 1, ALU_OP_SUB_C, imm >> 32); - - return 0; -} - -static int shl_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - if (insn->imm != 32) - return 1; /* TODO */ - - wrp_reg_mov(nfp_prog, insn->dst_reg * 2 + 1, insn->dst_reg * 2); - wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2), 0); - - return 0; -} - -static int shr_imm64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - if (insn->imm != 32) - return 1; /* TODO */ - - wrp_reg_mov(nfp_prog, insn->dst_reg * 2, insn->dst_reg * 2 + 1); - wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); - - return 0; -} - -static int mov_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - wrp_reg_mov(nfp_prog, insn->dst_reg * 2, insn->src_reg * 2); - wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); - - return 0; -} - -static int mov_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2), insn->imm); - wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); - - return 0; -} - -static int xor_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_reg(nfp_prog, meta, ALU_OP_XOR); -} - -static int xor_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_imm(nfp_prog, meta, ALU_OP_XOR, !~meta->insn.imm); -} - -static int and_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_reg(nfp_prog, meta, ALU_OP_AND); -} - -static int and_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_imm(nfp_prog, meta, ALU_OP_AND, !~meta->insn.imm); -} - -static int or_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_reg(nfp_prog, meta, ALU_OP_OR); -} - -static int or_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_imm(nfp_prog, meta, ALU_OP_OR, !meta->insn.imm); -} - -static int add_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_reg(nfp_prog, meta, ALU_OP_ADD); -} - -static int add_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_imm(nfp_prog, meta, ALU_OP_ADD, !meta->insn.imm); -} - -static int sub_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_reg(nfp_prog, meta, ALU_OP_SUB); -} - -static int sub_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_alu32_imm(nfp_prog, meta, ALU_OP_SUB, !meta->insn.imm); -} - -static int shl_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - if (!insn->imm) - return 1; /* TODO: zero shift means indirect */ - - emit_shf(nfp_prog, reg_both(insn->dst_reg * 2), - reg_none(), SHF_OP_NONE, reg_b(insn->dst_reg * 2), - SHF_SC_L_SHF, insn->imm); - wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2 + 1), 0); - - return 0; -} - -static int imm_ld8_part2(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - wrp_immed(nfp_prog, reg_both(nfp_meta_prev(meta)->insn.dst_reg * 2 + 1), - meta->insn.imm); - - return 0; -} - -static int imm_ld8(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - meta->double_cb = imm_ld8_part2; - wrp_immed(nfp_prog, reg_both(insn->dst_reg * 2), insn->imm); - - return 0; -} - -static int data_ld1(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return construct_data_ld(nfp_prog, meta->insn.imm, 1); -} - -static int data_ld2(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return construct_data_ld(nfp_prog, meta->insn.imm, 2); -} - -static int data_ld4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return construct_data_ld(nfp_prog, meta->insn.imm, 4); -} - -static int data_ind_ld1(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return construct_data_ind_ld(nfp_prog, meta->insn.imm, - meta->insn.src_reg * 2, true, 1); -} - -static int data_ind_ld2(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return construct_data_ind_ld(nfp_prog, meta->insn.imm, - meta->insn.src_reg * 2, true, 2); -} - -static int data_ind_ld4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return construct_data_ind_ld(nfp_prog, meta->insn.imm, - meta->insn.src_reg * 2, true, 4); -} - -static int mem_ldx4_skb(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - if (meta->insn.off == offsetof(struct sk_buff, len)) - emit_alu(nfp_prog, reg_both(meta->insn.dst_reg * 2), - reg_none(), ALU_OP_NONE, NFP_BPF_ABI_LEN); - else - return -EOPNOTSUPP; - - return 0; -} - -static int mem_ldx4_xdp(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - u32 dst = reg_both(meta->insn.dst_reg * 2); - - if (meta->insn.off != offsetof(struct xdp_md, data) && - meta->insn.off != offsetof(struct xdp_md, data_end)) - return -EOPNOTSUPP; - - emit_alu(nfp_prog, dst, reg_none(), ALU_OP_NONE, NFP_BPF_ABI_PKT); - - if (meta->insn.off == offsetof(struct xdp_md, data)) - return 0; - - emit_alu(nfp_prog, dst, dst, ALU_OP_ADD, NFP_BPF_ABI_LEN); - - return 0; -} - -static int mem_ldx4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - int ret; - - if (nfp_prog->act == NN_ACT_XDP) - ret = mem_ldx4_xdp(nfp_prog, meta); - else - ret = mem_ldx4_skb(nfp_prog, meta); - - wrp_immed(nfp_prog, reg_both(meta->insn.dst_reg * 2 + 1), 0); - - return ret; -} - -static int mem_stx4_skb(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - if (meta->insn.off == offsetof(struct sk_buff, mark)) - return wrp_set_mark(nfp_prog, meta->insn.src_reg * 2); - - return -EOPNOTSUPP; -} - -static int mem_stx4_xdp(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return -EOPNOTSUPP; -} - -static int mem_stx4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - if (nfp_prog->act == NN_ACT_XDP) - return mem_stx4_xdp(nfp_prog, meta); - return mem_stx4_skb(nfp_prog, meta); -} - -static int jump(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - if (meta->insn.off < 0) /* TODO */ - return -EOPNOTSUPP; - emit_br(nfp_prog, BR_UNC, meta->insn.off, 0); - - return 0; -} - -static int jeq_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - u64 imm = insn->imm; /* sign extend */ - u32 or1 = reg_a(insn->dst_reg * 2), or2 = reg_b(insn->dst_reg * 2 + 1); - u32 tmp_reg; - - if (insn->off < 0) /* TODO */ - return -EOPNOTSUPP; - - if (imm & ~0U) { - tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); - emit_alu(nfp_prog, imm_a(nfp_prog), - reg_a(insn->dst_reg * 2), ALU_OP_XOR, tmp_reg); - or1 = imm_a(nfp_prog); - } - - if (imm >> 32) { - tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); - emit_alu(nfp_prog, imm_b(nfp_prog), - reg_a(insn->dst_reg * 2 + 1), ALU_OP_XOR, tmp_reg); - or2 = imm_b(nfp_prog); - } - - emit_alu(nfp_prog, reg_none(), or1, ALU_OP_OR, or2); - emit_br(nfp_prog, BR_BEQ, insn->off, 0); - - return 0; -} - -static int jgt_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_cmp_imm(nfp_prog, meta, BR_BLO, false); -} - -static int jge_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_cmp_imm(nfp_prog, meta, BR_BHS, true); -} - -static int jset_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - u64 imm = insn->imm; /* sign extend */ - u32 tmp_reg; - - if (insn->off < 0) /* TODO */ - return -EOPNOTSUPP; - - if (!imm) { - meta->skip = true; - return 0; - } - - if (imm & ~0U) { - tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); - emit_alu(nfp_prog, reg_none(), - reg_a(insn->dst_reg * 2), ALU_OP_AND, tmp_reg); - emit_br(nfp_prog, BR_BNE, insn->off, 0); - } - - if (imm >> 32) { - tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); - emit_alu(nfp_prog, reg_none(), - reg_a(insn->dst_reg * 2 + 1), ALU_OP_AND, tmp_reg); - emit_br(nfp_prog, BR_BNE, insn->off, 0); - } - - return 0; -} - -static int jne_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - u64 imm = insn->imm; /* sign extend */ - u32 tmp_reg; - - if (insn->off < 0) /* TODO */ - return -EOPNOTSUPP; - - if (!imm) { - emit_alu(nfp_prog, reg_none(), reg_a(insn->dst_reg * 2), - ALU_OP_OR, reg_b(insn->dst_reg * 2 + 1)); - emit_br(nfp_prog, BR_BNE, insn->off, 0); - } - - tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); - emit_alu(nfp_prog, reg_none(), - reg_a(insn->dst_reg * 2), ALU_OP_XOR, tmp_reg); - emit_br(nfp_prog, BR_BNE, insn->off, 0); - - tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); - emit_alu(nfp_prog, reg_none(), - reg_a(insn->dst_reg * 2 + 1), ALU_OP_XOR, tmp_reg); - emit_br(nfp_prog, BR_BNE, insn->off, 0); - - return 0; -} - -static int jeq_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - const struct bpf_insn *insn = &meta->insn; - - if (insn->off < 0) /* TODO */ - return -EOPNOTSUPP; - - emit_alu(nfp_prog, imm_a(nfp_prog), reg_a(insn->dst_reg * 2), - ALU_OP_XOR, reg_b(insn->src_reg * 2)); - emit_alu(nfp_prog, imm_b(nfp_prog), reg_a(insn->dst_reg * 2 + 1), - ALU_OP_XOR, reg_b(insn->src_reg * 2 + 1)); - emit_alu(nfp_prog, reg_none(), - imm_a(nfp_prog), ALU_OP_OR, imm_b(nfp_prog)); - emit_br(nfp_prog, BR_BEQ, insn->off, 0); - - return 0; -} - -static int jgt_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_cmp_reg(nfp_prog, meta, BR_BLO, false); -} - -static int jge_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_cmp_reg(nfp_prog, meta, BR_BHS, true); -} - -static int jset_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_test_reg(nfp_prog, meta, ALU_OP_AND, BR_BNE); -} - -static int jne_reg(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - return wrp_test_reg(nfp_prog, meta, ALU_OP_XOR, BR_BNE); -} - -static int goto_out(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) -{ - wrp_br_special(nfp_prog, BR_UNC, OP_BR_GO_OUT); - - return 0; -} - -static const instr_cb_t instr_cb[256] = { - [BPF_ALU64 | BPF_MOV | BPF_X] = mov_reg64, - [BPF_ALU64 | BPF_MOV | BPF_K] = mov_imm64, - [BPF_ALU64 | BPF_XOR | BPF_X] = xor_reg64, - [BPF_ALU64 | BPF_XOR | BPF_K] = xor_imm64, - [BPF_ALU64 | BPF_AND | BPF_X] = and_reg64, - [BPF_ALU64 | BPF_AND | BPF_K] = and_imm64, - [BPF_ALU64 | BPF_OR | BPF_X] = or_reg64, - [BPF_ALU64 | BPF_OR | BPF_K] = or_imm64, - [BPF_ALU64 | BPF_ADD | BPF_X] = add_reg64, - [BPF_ALU64 | BPF_ADD | BPF_K] = add_imm64, - [BPF_ALU64 | BPF_SUB | BPF_X] = sub_reg64, - [BPF_ALU64 | BPF_SUB | BPF_K] = sub_imm64, - [BPF_ALU64 | BPF_LSH | BPF_K] = shl_imm64, - [BPF_ALU64 | BPF_RSH | BPF_K] = shr_imm64, - [BPF_ALU | BPF_MOV | BPF_X] = mov_reg, - [BPF_ALU | BPF_MOV | BPF_K] = mov_imm, - [BPF_ALU | BPF_XOR | BPF_X] = xor_reg, - [BPF_ALU | BPF_XOR | BPF_K] = xor_imm, - [BPF_ALU | BPF_AND | BPF_X] = and_reg, - [BPF_ALU | BPF_AND | BPF_K] = and_imm, - [BPF_ALU | BPF_OR | BPF_X] = or_reg, - [BPF_ALU | BPF_OR | BPF_K] = or_imm, - [BPF_ALU | BPF_ADD | BPF_X] = add_reg, - [BPF_ALU | BPF_ADD | BPF_K] = add_imm, - [BPF_ALU | BPF_SUB | BPF_X] = sub_reg, - [BPF_ALU | BPF_SUB | BPF_K] = sub_imm, - [BPF_ALU | BPF_LSH | BPF_K] = shl_imm, - [BPF_LD | BPF_IMM | BPF_DW] = imm_ld8, - [BPF_LD | BPF_ABS | BPF_B] = data_ld1, - [BPF_LD | BPF_ABS | BPF_H] = data_ld2, - [BPF_LD | BPF_ABS | BPF_W] = data_ld4, - [BPF_LD | BPF_IND | BPF_B] = data_ind_ld1, - [BPF_LD | BPF_IND | BPF_H] = data_ind_ld2, - [BPF_LD | BPF_IND | BPF_W] = data_ind_ld4, - [BPF_LDX | BPF_MEM | BPF_W] = mem_ldx4, - [BPF_STX | BPF_MEM | BPF_W] = mem_stx4, - [BPF_JMP | BPF_JA | BPF_K] = jump, - [BPF_JMP | BPF_JEQ | BPF_K] = jeq_imm, - [BPF_JMP | BPF_JGT | BPF_K] = jgt_imm, - [BPF_JMP | BPF_JGE | BPF_K] = jge_imm, - [BPF_JMP | BPF_JSET | BPF_K] = jset_imm, - [BPF_JMP | BPF_JNE | BPF_K] = jne_imm, - [BPF_JMP | BPF_JEQ | BPF_X] = jeq_reg, - [BPF_JMP | BPF_JGT | BPF_X] = jgt_reg, - [BPF_JMP | BPF_JGE | BPF_X] = jge_reg, - [BPF_JMP | BPF_JSET | BPF_X] = jset_reg, - [BPF_JMP | BPF_JNE | BPF_X] = jne_reg, - [BPF_JMP | BPF_EXIT] = goto_out, -}; - -/* --- Misc code --- */ -static void br_set_offset(u64 *instr, u16 offset) -{ - u16 addr_lo, addr_hi; - - addr_lo = offset & (OP_BR_ADDR_LO >> __bf_shf(OP_BR_ADDR_LO)); - addr_hi = offset != addr_lo; - *instr &= ~(OP_BR_ADDR_HI | OP_BR_ADDR_LO); - *instr |= FIELD_PREP(OP_BR_ADDR_HI, addr_hi); - *instr |= FIELD_PREP(OP_BR_ADDR_LO, addr_lo); -} - -/* --- Assembler logic --- */ -static int nfp_fixup_branches(struct nfp_prog *nfp_prog) -{ - struct nfp_insn_meta *meta, *next; - u32 off, br_idx; - u32 idx; - - nfp_for_each_insn_walk2(nfp_prog, meta, next) { - if (meta->skip) - continue; - if (BPF_CLASS(meta->insn.code) != BPF_JMP) - continue; - - br_idx = nfp_prog_offset_to_index(nfp_prog, next->off) - 1; - if (!nfp_is_br(nfp_prog->prog[br_idx])) { - pr_err("Fixup found block not ending in branch %d %02x %016llx!!\n", - br_idx, meta->insn.code, nfp_prog->prog[br_idx]); - return -ELOOP; - } - /* Leave special branches for later */ - if (FIELD_GET(OP_BR_SPECIAL, nfp_prog->prog[br_idx])) - continue; - - /* Find the target offset in assembler realm */ - off = meta->insn.off; - if (!off) { - pr_err("Fixup found zero offset!!\n"); - return -ELOOP; - } - - while (off && nfp_meta_has_next(nfp_prog, next)) { - next = nfp_meta_next(next); - off--; - } - if (off) { - pr_err("Fixup found too large jump!! %d\n", off); - return -ELOOP; - } - - if (next->skip) { - pr_err("Branch landing on removed instruction!!\n"); - return -ELOOP; - } - - for (idx = nfp_prog_offset_to_index(nfp_prog, meta->off); - idx <= br_idx; idx++) { - if (!nfp_is_br(nfp_prog->prog[idx])) - continue; - br_set_offset(&nfp_prog->prog[idx], next->off); - } - } - - /* Fixup 'goto out's separately, they can be scattered around */ - for (br_idx = 0; br_idx < nfp_prog->prog_len; br_idx++) { - enum br_special special; - - if ((nfp_prog->prog[br_idx] & OP_BR_BASE_MASK) != OP_BR_BASE) - continue; - - special = FIELD_GET(OP_BR_SPECIAL, nfp_prog->prog[br_idx]); - switch (special) { - case OP_BR_NORMAL: - break; - case OP_BR_GO_OUT: - br_set_offset(&nfp_prog->prog[br_idx], - nfp_prog->tgt_out); - break; - case OP_BR_GO_ABORT: - br_set_offset(&nfp_prog->prog[br_idx], - nfp_prog->tgt_abort); - break; - } - - nfp_prog->prog[br_idx] &= ~OP_BR_SPECIAL; - } - - return 0; -} - -static void nfp_intro(struct nfp_prog *nfp_prog) -{ - emit_alu(nfp_prog, pkt_reg(nfp_prog), - reg_none(), ALU_OP_NONE, NFP_BPF_ABI_PKT); -} - -static void nfp_outro_tc_legacy(struct nfp_prog *nfp_prog) -{ - const u8 act2code[] = { - [NN_ACT_TC_DROP] = 0x22, - [NN_ACT_TC_REDIR] = 0x24 - }; - /* Target for aborts */ - nfp_prog->tgt_abort = nfp_prog_current_offset(nfp_prog); - wrp_immed(nfp_prog, reg_both(0), 0); - - /* Target for normal exits */ - nfp_prog->tgt_out = nfp_prog_current_offset(nfp_prog); - /* Legacy TC mode: - * 0 0x11 -> pass, count as stat0 - * -1 drop 0x22 -> drop, count as stat1 - * redir 0x24 -> redir, count as stat1 - * ife mark 0x21 -> pass, count as stat1 - * ife + tx 0x24 -> redir, count as stat1 - */ - emit_br_byte_neq(nfp_prog, reg_b(0), 0xff, 0, nfp_prog->tgt_done, 2); - emit_alu(nfp_prog, reg_a(0), - reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); - emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_imm(0x11), SHF_SC_L_SHF, 16); - - emit_br(nfp_prog, BR_UNC, nfp_prog->tgt_done, 1); - emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_imm(act2code[nfp_prog->act]), - SHF_SC_L_SHF, 16); -} - -static void nfp_outro_tc_da(struct nfp_prog *nfp_prog) -{ - /* TC direct-action mode: - * 0,1 ok NOT SUPPORTED[1] - * 2 drop 0x22 -> drop, count as stat1 - * 4,5 nuke 0x02 -> drop - * 7 redir 0x44 -> redir, count as stat2 - * * unspec 0x11 -> pass, count as stat0 - * - * [1] We can't support OK and RECLASSIFY because we can't tell TC - * the exact decision made. We are forced to support UNSPEC - * to handle aborts so that's the only one we handle for passing - * packets up the stack. - */ - /* Target for aborts */ - nfp_prog->tgt_abort = nfp_prog_current_offset(nfp_prog); - - emit_br_def(nfp_prog, nfp_prog->tgt_done, 2); - - emit_alu(nfp_prog, reg_a(0), - reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); - emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_imm(0x11), SHF_SC_L_SHF, 16); - - /* Target for normal exits */ - nfp_prog->tgt_out = nfp_prog_current_offset(nfp_prog); - - /* if R0 > 7 jump to abort */ - emit_alu(nfp_prog, reg_none(), reg_imm(7), ALU_OP_SUB, reg_b(0)); - emit_br(nfp_prog, BR_BLO, nfp_prog->tgt_abort, 0); - emit_alu(nfp_prog, reg_a(0), - reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); - - wrp_immed(nfp_prog, reg_b(2), 0x41221211); - wrp_immed(nfp_prog, reg_b(3), 0x41001211); - - emit_shf(nfp_prog, reg_a(1), - reg_none(), SHF_OP_NONE, reg_b(0), SHF_SC_L_SHF, 2); - - emit_alu(nfp_prog, reg_none(), reg_a(1), ALU_OP_OR, reg_imm(0)); - emit_shf(nfp_prog, reg_a(2), - reg_imm(0xf), SHF_OP_AND, reg_b(2), SHF_SC_R_SHF, 0); - - emit_alu(nfp_prog, reg_none(), reg_a(1), ALU_OP_OR, reg_imm(0)); - emit_shf(nfp_prog, reg_b(2), - reg_imm(0xf), SHF_OP_AND, reg_b(3), SHF_SC_R_SHF, 0); - - emit_br_def(nfp_prog, nfp_prog->tgt_done, 2); - - emit_shf(nfp_prog, reg_b(2), - reg_a(2), SHF_OP_OR, reg_b(2), SHF_SC_L_SHF, 4); - emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_b(2), SHF_SC_L_SHF, 16); -} - -static void nfp_outro_xdp(struct nfp_prog *nfp_prog) -{ - /* XDP return codes: - * 0 aborted 0x82 -> drop, count as stat3 - * 1 drop 0x22 -> drop, count as stat1 - * 2 pass 0x11 -> pass, count as stat0 - * 3 tx 0x44 -> redir, count as stat2 - * * unknown 0x82 -> drop, count as stat3 - */ - /* Target for aborts */ - nfp_prog->tgt_abort = nfp_prog_current_offset(nfp_prog); - - emit_br_def(nfp_prog, nfp_prog->tgt_done, 2); - - emit_alu(nfp_prog, reg_a(0), - reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); - emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_imm(0x82), SHF_SC_L_SHF, 16); - - /* Target for normal exits */ - nfp_prog->tgt_out = nfp_prog_current_offset(nfp_prog); - - /* if R0 > 3 jump to abort */ - emit_alu(nfp_prog, reg_none(), reg_imm(3), ALU_OP_SUB, reg_b(0)); - emit_br(nfp_prog, BR_BLO, nfp_prog->tgt_abort, 0); - - wrp_immed(nfp_prog, reg_b(2), 0x44112282); - - emit_shf(nfp_prog, reg_a(1), - reg_none(), SHF_OP_NONE, reg_b(0), SHF_SC_L_SHF, 3); - - emit_alu(nfp_prog, reg_none(), reg_a(1), ALU_OP_OR, reg_imm(0)); - emit_shf(nfp_prog, reg_b(2), - reg_imm(0xff), SHF_OP_AND, reg_b(2), SHF_SC_R_SHF, 0); - - emit_br_def(nfp_prog, nfp_prog->tgt_done, 2); - - emit_alu(nfp_prog, reg_a(0), - reg_none(), ALU_OP_NONE, NFP_BPF_ABI_FLAGS); - emit_ld_field(nfp_prog, reg_a(0), 0xc, reg_b(2), SHF_SC_L_SHF, 16); -} - -static void nfp_outro(struct nfp_prog *nfp_prog) -{ - switch (nfp_prog->act) { - case NN_ACT_DIRECT: - nfp_outro_tc_da(nfp_prog); - break; - case NN_ACT_TC_DROP: - case NN_ACT_TC_REDIR: - nfp_outro_tc_legacy(nfp_prog); - break; - case NN_ACT_XDP: - nfp_outro_xdp(nfp_prog); - break; - } -} - -static int nfp_translate(struct nfp_prog *nfp_prog) -{ - struct nfp_insn_meta *meta; - int err; - - nfp_intro(nfp_prog); - if (nfp_prog->error) - return nfp_prog->error; - - list_for_each_entry(meta, &nfp_prog->insns, l) { - instr_cb_t cb = instr_cb[meta->insn.code]; - - meta->off = nfp_prog_current_offset(nfp_prog); - - if (meta->skip) { - nfp_prog->n_translated++; - continue; - } - - if (nfp_meta_has_prev(nfp_prog, meta) && - nfp_meta_prev(meta)->double_cb) - cb = nfp_meta_prev(meta)->double_cb; - if (!cb) - return -ENOENT; - err = cb(nfp_prog, meta); - if (err) - return err; - - nfp_prog->n_translated++; - } - - nfp_outro(nfp_prog); - if (nfp_prog->error) - return nfp_prog->error; - - return nfp_fixup_branches(nfp_prog); -} - -static int -nfp_prog_prepare(struct nfp_prog *nfp_prog, const struct bpf_insn *prog, - unsigned int cnt) -{ - unsigned int i; - - for (i = 0; i < cnt; i++) { - struct nfp_insn_meta *meta; - - meta = kzalloc(sizeof(*meta), GFP_KERNEL); - if (!meta) - return -ENOMEM; - - meta->insn = prog[i]; - meta->n = i; - - list_add_tail(&meta->l, &nfp_prog->insns); - } - - return 0; -} - -/* --- Optimizations --- */ -static void nfp_bpf_opt_reg_init(struct nfp_prog *nfp_prog) -{ - struct nfp_insn_meta *meta; - - list_for_each_entry(meta, &nfp_prog->insns, l) { - struct bpf_insn insn = meta->insn; - - /* Programs converted from cBPF start with register xoring */ - if (insn.code == (BPF_ALU64 | BPF_XOR | BPF_X) && - insn.src_reg == insn.dst_reg) - continue; - - /* Programs start with R6 = R1 but we ignore the skb pointer */ - if (insn.code == (BPF_ALU64 | BPF_MOV | BPF_X) && - insn.src_reg == 1 && insn.dst_reg == 6) - meta->skip = true; - - /* Return as soon as something doesn't match */ - if (!meta->skip) - return; - } -} - -/* Try to rename registers so that program uses only low ones */ -static int nfp_bpf_opt_reg_rename(struct nfp_prog *nfp_prog) -{ - bool reg_used[MAX_BPF_REG] = {}; - u8 tgt_reg[MAX_BPF_REG] = {}; - struct nfp_insn_meta *meta; - unsigned int i, j; - - list_for_each_entry(meta, &nfp_prog->insns, l) { - if (meta->skip) - continue; - - reg_used[meta->insn.src_reg] = true; - reg_used[meta->insn.dst_reg] = true; - } - - for (i = 0, j = 0; i < ARRAY_SIZE(tgt_reg); i++) { - if (!reg_used[i]) - continue; - - tgt_reg[i] = j++; - } - nfp_prog->num_regs = j; - - list_for_each_entry(meta, &nfp_prog->insns, l) { - meta->insn.src_reg = tgt_reg[meta->insn.src_reg]; - meta->insn.dst_reg = tgt_reg[meta->insn.dst_reg]; - } - - return 0; -} - -/* Remove masking after load since our load guarantees this is not needed */ -static void nfp_bpf_opt_ld_mask(struct nfp_prog *nfp_prog) -{ - struct nfp_insn_meta *meta1, *meta2; - const s32 exp_mask[] = { - [BPF_B] = 0x000000ffU, - [BPF_H] = 0x0000ffffU, - [BPF_W] = 0xffffffffU, - }; - - nfp_for_each_insn_walk2(nfp_prog, meta1, meta2) { - struct bpf_insn insn, next; - - insn = meta1->insn; - next = meta2->insn; - - if (BPF_CLASS(insn.code) != BPF_LD) - continue; - if (BPF_MODE(insn.code) != BPF_ABS && - BPF_MODE(insn.code) != BPF_IND) - continue; - - if (next.code != (BPF_ALU64 | BPF_AND | BPF_K)) - continue; - - if (!exp_mask[BPF_SIZE(insn.code)]) - continue; - if (exp_mask[BPF_SIZE(insn.code)] != next.imm) - continue; - - if (next.src_reg || next.dst_reg) - continue; - - meta2->skip = true; - } -} - -static void nfp_bpf_opt_ld_shift(struct nfp_prog *nfp_prog) -{ - struct nfp_insn_meta *meta1, *meta2, *meta3; - - nfp_for_each_insn_walk3(nfp_prog, meta1, meta2, meta3) { - struct bpf_insn insn, next1, next2; - - insn = meta1->insn; - next1 = meta2->insn; - next2 = meta3->insn; - - if (BPF_CLASS(insn.code) != BPF_LD) - continue; - if (BPF_MODE(insn.code) != BPF_ABS && - BPF_MODE(insn.code) != BPF_IND) - continue; - if (BPF_SIZE(insn.code) != BPF_W) - continue; - - if (!(next1.code == (BPF_LSH | BPF_K | BPF_ALU64) && - next2.code == (BPF_RSH | BPF_K | BPF_ALU64)) && - !(next1.code == (BPF_RSH | BPF_K | BPF_ALU64) && - next2.code == (BPF_LSH | BPF_K | BPF_ALU64))) - continue; - - if (next1.src_reg || next1.dst_reg || - next2.src_reg || next2.dst_reg) - continue; - - if (next1.imm != 0x20 || next2.imm != 0x20) - continue; - - meta2->skip = true; - meta3->skip = true; - } -} - -static int nfp_bpf_optimize(struct nfp_prog *nfp_prog) -{ - int ret; - - nfp_bpf_opt_reg_init(nfp_prog); - - ret = nfp_bpf_opt_reg_rename(nfp_prog); - if (ret) - return ret; - - nfp_bpf_opt_ld_mask(nfp_prog); - nfp_bpf_opt_ld_shift(nfp_prog); - - return 0; -} - -/** - * nfp_bpf_jit() - translate BPF code into NFP assembly - * @filter: kernel BPF filter struct - * @prog_mem: memory to store assembler instructions - * @act: action attached to this eBPF program - * @prog_start: offset of the first instruction when loaded - * @prog_done: where to jump on exit - * @prog_sz: size of @prog_mem in instructions - * @res: achieved parameters of translation results - */ -int -nfp_bpf_jit(struct bpf_prog *filter, void *prog_mem, - enum nfp_bpf_action_type act, - unsigned int prog_start, unsigned int prog_done, - unsigned int prog_sz, struct nfp_bpf_result *res) -{ - struct nfp_prog *nfp_prog; - int ret; - - nfp_prog = kzalloc(sizeof(*nfp_prog), GFP_KERNEL); - if (!nfp_prog) - return -ENOMEM; - - INIT_LIST_HEAD(&nfp_prog->insns); - nfp_prog->act = act; - nfp_prog->start_off = prog_start; - nfp_prog->tgt_done = prog_done; - - ret = nfp_prog_prepare(nfp_prog, filter->insnsi, filter->len); - if (ret) - goto out; - - ret = nfp_prog_verify(nfp_prog, filter); - if (ret) - goto out; - - ret = nfp_bpf_optimize(nfp_prog); - if (ret) - goto out; - - if (nfp_prog->num_regs <= 7) - nfp_prog->regs_per_thread = 16; - else - nfp_prog->regs_per_thread = 32; - - nfp_prog->prog = prog_mem; - nfp_prog->__prog_alloc_len = prog_sz; - - ret = nfp_translate(nfp_prog); - if (ret) { - pr_err("Translation failed with error %d (translated: %u)\n", - ret, nfp_prog->n_translated); - ret = -EINVAL; - } - - res->n_instr = nfp_prog->prog_len; - res->dense_mode = nfp_prog->num_regs <= 7; -out: - nfp_prog_free(nfp_prog); - - return ret; -} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c b/drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c deleted file mode 100644 index b3361f9b8e5c..000000000000 --- a/drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2016 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define pr_fmt(fmt) "NFP net bpf: " fmt - -#include -#include -#include -#include - -#include "nfp_bpf.h" - -/* Analyzer/verifier definitions */ -struct nfp_bpf_analyzer_priv { - struct nfp_prog *prog; - struct nfp_insn_meta *meta; -}; - -static struct nfp_insn_meta * -nfp_bpf_goto_meta(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, - unsigned int insn_idx, unsigned int n_insns) -{ - unsigned int forward, backward, i; - - backward = meta->n - insn_idx; - forward = insn_idx - meta->n; - - if (min(forward, backward) > n_insns - insn_idx - 1) { - backward = n_insns - insn_idx - 1; - meta = nfp_prog_last_meta(nfp_prog); - } - if (min(forward, backward) > insn_idx && backward > insn_idx) { - forward = insn_idx; - meta = nfp_prog_first_meta(nfp_prog); - } - - if (forward < backward) - for (i = 0; i < forward; i++) - meta = nfp_meta_next(meta); - else - for (i = 0; i < backward; i++) - meta = nfp_meta_prev(meta); - - return meta; -} - -static int -nfp_bpf_check_exit(struct nfp_prog *nfp_prog, - const struct bpf_verifier_env *env) -{ - const struct bpf_reg_state *reg0 = &env->cur_state.regs[0]; - - if (nfp_prog->act == NN_ACT_XDP) - return 0; - - if (reg0->type != CONST_IMM) { - pr_info("unsupported exit state: %d, imm: %llx\n", - reg0->type, reg0->imm); - return -EINVAL; - } - - if (nfp_prog->act != NN_ACT_DIRECT && - reg0->imm != 0 && (reg0->imm & ~0U) != ~0U) { - pr_info("unsupported exit state: %d, imm: %llx\n", - reg0->type, reg0->imm); - return -EINVAL; - } - - if (nfp_prog->act == NN_ACT_DIRECT && reg0->imm <= TC_ACT_REDIRECT && - reg0->imm != TC_ACT_SHOT && reg0->imm != TC_ACT_STOLEN && - reg0->imm != TC_ACT_QUEUED) { - pr_info("unsupported exit state: %d, imm: %llx\n", - reg0->type, reg0->imm); - return -EINVAL; - } - - return 0; -} - -static int -nfp_bpf_check_ctx_ptr(struct nfp_prog *nfp_prog, - const struct bpf_verifier_env *env, u8 reg) -{ - if (env->cur_state.regs[reg].type != PTR_TO_CTX) - return -EINVAL; - - return 0; -} - -static int -nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) -{ - struct nfp_bpf_analyzer_priv *priv = env->analyzer_priv; - struct nfp_insn_meta *meta = priv->meta; - - meta = nfp_bpf_goto_meta(priv->prog, meta, insn_idx, env->prog->len); - priv->meta = meta; - - if (meta->insn.src_reg == BPF_REG_10 || - meta->insn.dst_reg == BPF_REG_10) { - pr_err("stack not yet supported\n"); - return -EINVAL; - } - if (meta->insn.src_reg >= MAX_BPF_REG || - meta->insn.dst_reg >= MAX_BPF_REG) { - pr_err("program uses extended registers - jit hardening?\n"); - return -EINVAL; - } - - if (meta->insn.code == (BPF_JMP | BPF_EXIT)) - return nfp_bpf_check_exit(priv->prog, env); - - if ((meta->insn.code & ~BPF_SIZE_MASK) == (BPF_LDX | BPF_MEM)) - return nfp_bpf_check_ctx_ptr(priv->prog, env, - meta->insn.src_reg); - if ((meta->insn.code & ~BPF_SIZE_MASK) == (BPF_STX | BPF_MEM)) - return nfp_bpf_check_ctx_ptr(priv->prog, env, - meta->insn.dst_reg); - - return 0; -} - -static const struct bpf_ext_analyzer_ops nfp_bpf_analyzer_ops = { - .insn_hook = nfp_verify_insn, -}; - -int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog) -{ - struct nfp_bpf_analyzer_priv *priv; - int ret; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->prog = nfp_prog; - priv->meta = nfp_prog_first_meta(nfp_prog); - - ret = bpf_analyzer(prog, &nfp_bpf_analyzer_ops, priv); - - kfree(priv); - - return ret; -} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c b/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c deleted file mode 100644 index 2fa7b67d0c6f..000000000000 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2016 Netronome Systems, Inc. - * - * This software is dual licensed under the GNU General License Version 2, - * June 1991 as shown in the file COPYING in the top-level directory of this - * source tree or the BSD 2-Clause License provided below. You have the - * option to license this software under the complete terms of either license. - * - * The BSD 2-Clause License: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * nfp_net_offload.c - * Netronome network device driver: TC offload functions for PF and VF - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "nfp_bpf.h" -#include "nfp_net_ctrl.h" -#include "nfp_net.h" - -void nfp_net_filter_stats_timer(unsigned long data) -{ - struct nfp_net *nn = (void *)data; - struct nfp_stat_pair latest; - - spin_lock_bh(&nn->rx_filter_lock); - - if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) - mod_timer(&nn->rx_filter_stats_timer, - jiffies + NFP_NET_STAT_POLL_IVL); - - spin_unlock_bh(&nn->rx_filter_lock); - - latest.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); - latest.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); - - if (latest.pkts != nn->rx_filter.pkts) - nn->rx_filter_change = jiffies; - - nn->rx_filter = latest; -} - -static void nfp_net_bpf_stats_reset(struct nfp_net *nn) -{ - nn->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); - nn->rx_filter.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); - nn->rx_filter_prev = nn->rx_filter; - nn->rx_filter_change = jiffies; -} - -static int -nfp_net_bpf_stats_update(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) -{ - u64 bytes, pkts; - - pkts = nn->rx_filter.pkts - nn->rx_filter_prev.pkts; - bytes = nn->rx_filter.bytes - nn->rx_filter_prev.bytes; - bytes -= pkts * ETH_HLEN; - - nn->rx_filter_prev = nn->rx_filter; - - tcf_exts_stats_update(cls_bpf->exts, - bytes, pkts, nn->rx_filter_change); - - return 0; -} - -static int -nfp_net_bpf_get_act(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) -{ - const struct tc_action *a; - LIST_HEAD(actions); - - if (!cls_bpf->exts) - return NN_ACT_XDP; - - /* TC direct action */ - if (cls_bpf->exts_integrated) { - if (tc_no_actions(cls_bpf->exts)) - return NN_ACT_DIRECT; - - return -EOPNOTSUPP; - } - - /* TC legacy mode */ - if (!tc_single_action(cls_bpf->exts)) - return -EOPNOTSUPP; - - tcf_exts_to_list(cls_bpf->exts, &actions); - list_for_each_entry(a, &actions, list) { - if (is_tcf_gact_shot(a)) - return NN_ACT_TC_DROP; - - if (is_tcf_mirred_egress_redirect(a) && - tcf_mirred_ifindex(a) == nn->dp.netdev->ifindex) - return NN_ACT_TC_REDIR; - } - - return -EOPNOTSUPP; -} - -static int -nfp_net_bpf_offload_prepare(struct nfp_net *nn, - struct tc_cls_bpf_offload *cls_bpf, - struct nfp_bpf_result *res, - void **code, dma_addr_t *dma_addr, u16 max_instr) -{ - unsigned int code_sz = max_instr * sizeof(u64); - enum nfp_bpf_action_type act; - u16 start_off, done_off; - unsigned int max_mtu; - int ret; - - if (!IS_ENABLED(CONFIG_BPF_SYSCALL)) - return -EOPNOTSUPP; - - ret = nfp_net_bpf_get_act(nn, cls_bpf); - if (ret < 0) - return ret; - act = ret; - - max_mtu = nn_readb(nn, NFP_NET_CFG_BPF_INL_MTU) * 64 - 32; - if (max_mtu < nn->dp.netdev->mtu) { - nn_info(nn, "BPF offload not supported with MTU larger than HW packet split boundary\n"); - return -EOPNOTSUPP; - } - - start_off = nn_readw(nn, NFP_NET_CFG_BPF_START); - done_off = nn_readw(nn, NFP_NET_CFG_BPF_DONE); - - *code = dma_zalloc_coherent(nn->dp.dev, code_sz, dma_addr, GFP_KERNEL); - if (!*code) - return -ENOMEM; - - ret = nfp_bpf_jit(cls_bpf->prog, *code, act, start_off, done_off, - max_instr, res); - if (ret) - goto out; - - return 0; - -out: - dma_free_coherent(nn->dp.dev, code_sz, *code, *dma_addr); - return ret; -} - -static void -nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags, - void *code, dma_addr_t dma_addr, - unsigned int code_sz, unsigned int n_instr, - bool dense_mode) -{ - u64 bpf_addr = dma_addr; - int err; - - nn->dp.bpf_offload_skip_sw = !!(tc_flags & TCA_CLS_FLAGS_SKIP_SW); - - if (dense_mode) - bpf_addr |= NFP_NET_CFG_BPF_CFG_8CTX; - - nn_writew(nn, NFP_NET_CFG_BPF_SIZE, n_instr); - nn_writeq(nn, NFP_NET_CFG_BPF_ADDR, bpf_addr); - - /* Load up the JITed code */ - err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_BPF); - if (err) - nn_err(nn, "FW command error while loading BPF: %d\n", err); - - /* Enable passing packets through BPF function */ - nn->dp.ctrl |= NFP_NET_CFG_CTRL_BPF; - nn_writel(nn, NFP_NET_CFG_CTRL, nn->dp.ctrl); - err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); - if (err) - nn_err(nn, "FW command error while enabling BPF: %d\n", err); - - dma_free_coherent(nn->dp.dev, code_sz, code, dma_addr); - - nfp_net_bpf_stats_reset(nn); - mod_timer(&nn->rx_filter_stats_timer, jiffies + NFP_NET_STAT_POLL_IVL); -} - -static int nfp_net_bpf_stop(struct nfp_net *nn) -{ - if (!(nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF)) - return 0; - - spin_lock_bh(&nn->rx_filter_lock); - nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_BPF; - spin_unlock_bh(&nn->rx_filter_lock); - nn_writel(nn, NFP_NET_CFG_CTRL, nn->dp.ctrl); - - del_timer_sync(&nn->rx_filter_stats_timer); - nn->dp.bpf_offload_skip_sw = 0; - - return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); -} - -int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) -{ - struct nfp_bpf_result res; - dma_addr_t dma_addr; - u16 max_instr; - void *code; - int err; - - max_instr = nn_readw(nn, NFP_NET_CFG_BPF_MAX_LEN); - - switch (cls_bpf->command) { - case TC_CLSBPF_REPLACE: - /* There is nothing stopping us from implementing seamless - * replace but the simple method of loading I adopted in - * the firmware does not handle atomic replace (i.e. we have to - * stop the BPF offload and re-enable it). Leaking-in a few - * frames which didn't have BPF applied in the hardware should - * be fine if software fallback is available, though. - */ - if (nn->dp.bpf_offload_skip_sw) - return -EBUSY; - - err = nfp_net_bpf_offload_prepare(nn, cls_bpf, &res, &code, - &dma_addr, max_instr); - if (err) - return err; - - nfp_net_bpf_stop(nn); - nfp_net_bpf_load_and_start(nn, cls_bpf->gen_flags, code, - dma_addr, max_instr * sizeof(u64), - res.n_instr, res.dense_mode); - return 0; - - case TC_CLSBPF_ADD: - if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) - return -EBUSY; - - err = nfp_net_bpf_offload_prepare(nn, cls_bpf, &res, &code, - &dma_addr, max_instr); - if (err) - return err; - - nfp_net_bpf_load_and_start(nn, cls_bpf->gen_flags, code, - dma_addr, max_instr * sizeof(u64), - res.n_instr, res.dense_mode); - return 0; - - case TC_CLSBPF_DESTROY: - return nfp_net_bpf_stop(nn); - - case TC_CLSBPF_STATS: - return nfp_net_bpf_stats_update(nn, cls_bpf); - - default: - return -EOPNOTSUPP; - } -} -- cgit v1.2.3 From bb45e51cb0f8fea496eb2d6a9ef2ffb5da564048 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2017 08:06:49 -0700 Subject: nfp: move bpf offload code to the BPF app Move bulk of the eBPF offload code out of common vNIC code into app-specific callbacks. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/bpf/main.c | 84 ++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/bpf/main.h | 5 ++ drivers/net/ethernet/netronome/nfp/nfp_app.h | 61 ++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_net.h | 1 - .../net/ethernet/netronome/nfp/nfp_net_common.c | 66 +++-------------- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 1 + 6 files changed, 159 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index d91d72e22dc8..a7478b5d1854 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -31,11 +31,57 @@ * SOFTWARE. */ +#include + #include "../nfpcore/nfp_cpp.h" #include "../nfp_app.h" #include "../nfp_main.h" #include "../nfp_net.h" #include "../nfp_port.h" +#include "main.h" + +static bool nfp_net_ebpf_capable(struct nfp_net *nn) +{ + if (nn->cap & NFP_NET_CFG_CTRL_BPF && + nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI) + return true; + return false; +} + +static int +nfp_bpf_xdp_offload(struct nfp_app *app, struct nfp_net *nn, + struct bpf_prog *prog) +{ + struct tc_cls_bpf_offload cmd = { + .prog = prog, + }; + int ret; + + if (!nfp_net_ebpf_capable(nn)) + return -EINVAL; + + if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) { + if (!nn->dp.bpf_offload_xdp) + return prog ? -EBUSY : 0; + cmd.command = prog ? TC_CLSBPF_REPLACE : TC_CLSBPF_DESTROY; + } else { + if (!prog) + return 0; + cmd.command = TC_CLSBPF_ADD; + } + + ret = nfp_net_bpf_offload(nn, &cmd); + /* Stop offload if replace not possible */ + if (ret && cmd.command == TC_CLSBPF_REPLACE) + nfp_bpf_xdp_offload(app, nn, NULL); + nn->dp.bpf_offload_xdp = prog && !ret; + return ret; +} + +static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn) +{ + return nfp_net_ebpf_capable(nn) ? "BPF" : ""; +} static int nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) @@ -51,9 +97,47 @@ nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) return nfp_app_nic_vnic_init(app, nn, id); } +static void nfp_bpf_vnic_clean(struct nfp_app *app, struct nfp_net *nn) +{ + if (nn->dp.bpf_offload_xdp) + nfp_bpf_xdp_offload(app, nn, NULL); +} + +static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev, + u32 handle, __be16 proto, struct tc_to_netdev *tc) +{ + struct nfp_net *nn = netdev_priv(netdev); + + if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS)) + return -EOPNOTSUPP; + if (proto != htons(ETH_P_ALL)) + return -EOPNOTSUPP; + + if (tc->type == TC_SETUP_CLSBPF && nfp_net_ebpf_capable(nn)) { + if (!nn->dp.bpf_offload_xdp) + return nfp_net_bpf_offload(nn, tc->cls_bpf); + else + return -EBUSY; + } + + return -EINVAL; +} + +static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn) +{ + return nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF; +} + const struct nfp_app_type app_bpf = { .id = NFP_APP_BPF_NIC, .name = "ebpf", + .extra_cap = nfp_bpf_extra_cap, + .vnic_init = nfp_bpf_vnic_init, + .vnic_clean = nfp_bpf_vnic_clean, + + .setup_tc = nfp_bpf_setup_tc, + .tc_busy = nfp_bpf_tc_busy, + .xdp_offload = nfp_bpf_xdp_offload, }; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 9513c80f7be5..9b526698e47d 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -198,4 +198,9 @@ nfp_bpf_jit(struct bpf_prog *filter, void *prog, enum nfp_bpf_action_type act, int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog); +struct nfp_net; +struct tc_cls_bpf_offload; + +int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf); + #endif diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index b5426398f29e..13efdefffa1a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -34,7 +34,10 @@ #ifndef _NFP_APP_H #define _NFP_APP_H 1 +struct bpf_prog; +struct net_device; struct pci_dev; +struct tc_to_netdev; struct nfp_app; struct nfp_cpp; struct nfp_pf; @@ -55,7 +58,12 @@ extern const struct nfp_app_type app_bpf; * * Callbacks * @init: perform basic app checks + * @extra_cap: extra capabilities string * @vnic_init: init vNICs (assign port types, etc.) + * @vnic_clean: clean up app's vNIC state + * @setup_tc: setup TC ndo + * @tc_busy: TC HW offload busy (rules loaded) + * @xdp_offload: offload an XDP program */ struct nfp_app_type { enum nfp_app_id id; @@ -63,8 +71,17 @@ struct nfp_app_type { int (*init)(struct nfp_app *app); + const char *(*extra_cap)(struct nfp_app *app, struct nfp_net *nn); + int (*vnic_init)(struct nfp_app *app, struct nfp_net *nn, unsigned int id); + void (*vnic_clean)(struct nfp_app *app, struct nfp_net *nn); + + int (*setup_tc)(struct nfp_app *app, struct net_device *netdev, + u32 handle, __be16 proto, struct tc_to_netdev *tc); + bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn); + int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn, + struct bpf_prog *prog); }; /** @@ -95,6 +112,12 @@ static inline int nfp_app_vnic_init(struct nfp_app *app, struct nfp_net *nn, return app->type->vnic_init(app, nn, id); } +static inline void nfp_app_vnic_clean(struct nfp_app *app, struct nfp_net *nn) +{ + if (app->type->vnic_clean) + app->type->vnic_clean(app, nn); +} + static inline const char *nfp_app_name(struct nfp_app *app) { if (!app) @@ -102,6 +125,44 @@ static inline const char *nfp_app_name(struct nfp_app *app) return app->type->name; } +static inline const char *nfp_app_extra_cap(struct nfp_app *app, + struct nfp_net *nn) +{ + if (!app || !app->type->extra_cap) + return ""; + return app->type->extra_cap(app, nn); +} + +static inline bool nfp_app_has_tc(struct nfp_app *app) +{ + return app && app->type->setup_tc; +} + +static inline bool nfp_app_tc_busy(struct nfp_app *app, struct nfp_net *nn) +{ + if (!app || !app->type->tc_busy) + return false; + return app->type->tc_busy(app, nn); +} + +static inline int nfp_app_setup_tc(struct nfp_app *app, + struct net_device *netdev, + u32 handle, __be16 proto, + struct tc_to_netdev *tc) +{ + if (!app || !app->type->setup_tc) + return -EOPNOTSUPP; + return app->type->setup_tc(app, netdev, handle, proto, tc); +} + +static inline int nfp_app_xdp_offload(struct nfp_app *app, struct nfp_net *nn, + struct bpf_prog *prog) +{ + if (!app || !app->type->xdp_offload) + return -EOPNOTSUPP; + return app->type->xdp_offload(app, nn, prog); +} + struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id); void nfp_app_free(struct nfp_app *app); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index cb7114309656..883cc6be02c1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -868,6 +868,5 @@ static inline void nfp_net_debugfs_dir_clean(struct dentry **dir) #endif /* CONFIG_NFP_DEBUG */ void nfp_net_filter_stats_timer(unsigned long data); -int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf); #endif /* _NFP_NET_H_ */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 2bcf3e8330ea..e0ece2de5841 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -64,10 +64,10 @@ #include -#include #include #include "nfpcore/nfp_nsp.h" +#include "nfp_app.h" #include "nfp_net_ctrl.h" #include "nfp_net.h" #include "nfp_port.h" @@ -2681,33 +2681,13 @@ static void nfp_net_stat64(struct net_device *netdev, } } -static bool nfp_net_ebpf_capable(struct nfp_net *nn) -{ - if (nn->cap & NFP_NET_CFG_CTRL_BPF && - nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI) - return true; - return false; -} - static int nfp_net_setup_tc(struct net_device *netdev, u32 handle, __be16 proto, struct tc_to_netdev *tc) { struct nfp_net *nn = netdev_priv(netdev); - if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS)) - return -EOPNOTSUPP; - if (proto != htons(ETH_P_ALL)) - return -EOPNOTSUPP; - - if (tc->type == TC_SETUP_CLSBPF && nfp_net_ebpf_capable(nn)) { - if (!nn->dp.bpf_offload_xdp) - return nfp_net_bpf_offload(nn, tc->cls_bpf); - else - return -EBUSY; - } - - return -EINVAL; + return nfp_app_setup_tc(nn->app, netdev, handle, proto, tc); } static int nfp_net_set_features(struct net_device *netdev, @@ -2765,7 +2745,7 @@ static int nfp_net_set_features(struct net_device *netdev, new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER; } - if (changed & NETIF_F_HW_TC && nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) { + if (changed & NETIF_F_HW_TC && nfp_app_tc_busy(nn->app, nn)) { nn_err(nn, "Cannot disable HW TC offload while in use\n"); return -EBUSY; } @@ -2914,34 +2894,6 @@ static void nfp_net_del_vxlan_port(struct net_device *netdev, nfp_net_set_vxlan_port(nn, idx, 0); } -static int nfp_net_xdp_offload(struct nfp_net *nn, struct bpf_prog *prog) -{ - struct tc_cls_bpf_offload cmd = { - .prog = prog, - }; - int ret; - - if (!nfp_net_ebpf_capable(nn)) - return -EINVAL; - - if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) { - if (!nn->dp.bpf_offload_xdp) - return prog ? -EBUSY : 0; - cmd.command = prog ? TC_CLSBPF_REPLACE : TC_CLSBPF_DESTROY; - } else { - if (!prog) - return 0; - cmd.command = TC_CLSBPF_ADD; - } - - ret = nfp_net_bpf_offload(nn, &cmd); - /* Stop offload if replace not possible */ - if (ret && cmd.command == TC_CLSBPF_REPLACE) - nfp_net_xdp_offload(nn, NULL); - nn->dp.bpf_offload_xdp = prog && !ret; - return ret; -} - static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) { struct bpf_prog *old_prog = nn->dp.xdp_prog; @@ -2954,7 +2906,7 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) if (prog && nn->dp.xdp_prog) { prog = xchg(&nn->dp.xdp_prog, prog); bpf_prog_put(prog); - nfp_net_xdp_offload(nn, nn->dp.xdp_prog); + nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); return 0; } @@ -2975,7 +2927,7 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) if (old_prog) bpf_prog_put(old_prog); - nfp_net_xdp_offload(nn, nn->dp.xdp_prog); + nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); return 0; } @@ -3068,10 +3020,10 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_IRQMOD ? "IRQMOD " : "", nn->cap & NFP_NET_CFG_CTRL_VXLAN ? "VXLAN " : "", nn->cap & NFP_NET_CFG_CTRL_NVGRE ? "NVGRE " : "", - nfp_net_ebpf_capable(nn) ? "BPF " : "", nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ? "RXCSUM_COMPLETE " : "", - nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR ? "LIVE_ADDR " : ""); + nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR ? "LIVE_ADDR " : "", + nfp_app_extra_cap(nn->app, nn)); } /** @@ -3316,7 +3268,7 @@ int nfp_net_init(struct nfp_net *nn) netdev->features = netdev->hw_features; - if (nfp_net_ebpf_capable(nn)) + if (nfp_app_has_tc(nn->app)) netdev->hw_features |= NETIF_F_HW_TC; /* Advertise but disable TSO by default. */ @@ -3373,6 +3325,4 @@ void nfp_net_clean(struct nfp_net *nn) if (nn->dp.xdp_prog) bpf_prog_put(nn->dp.xdp_prog); - if (nn->dp.bpf_offload_xdp) - nfp_net_xdp_offload(nn, NULL); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 28782bf3ce68..7dd310911d9f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -427,6 +427,7 @@ static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn) nfp_devlink_port_unregister(nn->port); nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_clean(nn); + nfp_app_vnic_clean(pf->app, nn); } static int -- cgit v1.2.3 From c66a9cf408037781fc1984bc60785049b453d8a4 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2017 08:06:50 -0700 Subject: nfp: move basic eBPF stats to app-specific code Allow apps to associate private data with vNICs and move BPF-specific fields of nfp_net to such structure. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/bpf/main.c | 19 ++++++++- drivers/net/ethernet/netronome/nfp/bpf/main.h | 18 +++++++++ drivers/net/ethernet/netronome/nfp/bpf/offload.c | 46 +++++++++++++--------- drivers/net/ethernet/netronome/nfp/nfp_net.h | 15 ++----- .../net/ethernet/netronome/nfp/nfp_net_common.c | 3 -- 5 files changed, 67 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index a7478b5d1854..afbdf5fd4e4f 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -86,6 +86,9 @@ static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn) static int nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) { + struct nfp_net_bpf_priv *priv; + int ret; + /* Limit to single port, otherwise it's just a NIC */ if (id > 0) { nfp_warn(app->cpp, @@ -94,13 +97,27 @@ nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) return PTR_ERR_OR_ZERO(nn->port); } - return nfp_app_nic_vnic_init(app, nn, id); + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + nn->app_priv = priv; + spin_lock_init(&priv->rx_filter_lock); + setup_timer(&priv->rx_filter_stats_timer, + nfp_net_filter_stats_timer, (unsigned long)nn); + + ret = nfp_app_nic_vnic_init(app, nn, id); + if (ret) + kfree(priv); + + return ret; } static void nfp_bpf_vnic_clean(struct nfp_app *app, struct nfp_net *nn) { if (nn->dp.bpf_offload_xdp) nfp_bpf_xdp_offload(app, nn, NULL); + kfree(nn->app_priv); } static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev, diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 9b526698e47d..4051e943f363 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -39,6 +39,8 @@ #include #include +#include "../nfp_net.h" + /* For branch fixup logic use up-most byte of branch instruction as scratch * area. Remember to clear this before sending instructions to HW! */ @@ -201,6 +203,22 @@ int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog); struct nfp_net; struct tc_cls_bpf_offload; +/** + * struct nfp_net_bpf_priv - per-vNIC BPF private data + * @rx_filter: Filter offload statistics - dropped packets/bytes + * @rx_filter_prev: Filter offload statistics - values from previous update + * @rx_filter_change: Jiffies when statistics last changed + * @rx_filter_stats_timer: Timer for polling filter offload statistics + * @rx_filter_lock: Lock protecting timer state changes (teardown) + */ +struct nfp_net_bpf_priv { + struct nfp_stat_pair rx_filter, rx_filter_prev; + unsigned long rx_filter_change; + struct timer_list rx_filter_stats_timer; + spinlock_t rx_filter_lock; +}; + int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf); +void nfp_net_filter_stats_timer(unsigned long data); #endif diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 30372dc99517..78d80a364edb 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -54,46 +54,52 @@ void nfp_net_filter_stats_timer(unsigned long data) { struct nfp_net *nn = (void *)data; + struct nfp_net_bpf_priv *priv; struct nfp_stat_pair latest; - spin_lock_bh(&nn->rx_filter_lock); + priv = nn->app_priv; + + spin_lock_bh(&priv->rx_filter_lock); if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) - mod_timer(&nn->rx_filter_stats_timer, + mod_timer(&priv->rx_filter_stats_timer, jiffies + NFP_NET_STAT_POLL_IVL); - spin_unlock_bh(&nn->rx_filter_lock); + spin_unlock_bh(&priv->rx_filter_lock); latest.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); latest.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); - if (latest.pkts != nn->rx_filter.pkts) - nn->rx_filter_change = jiffies; + if (latest.pkts != priv->rx_filter.pkts) + priv->rx_filter_change = jiffies; - nn->rx_filter = latest; + priv->rx_filter = latest; } static void nfp_net_bpf_stats_reset(struct nfp_net *nn) { - nn->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); - nn->rx_filter.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); - nn->rx_filter_prev = nn->rx_filter; - nn->rx_filter_change = jiffies; + struct nfp_net_bpf_priv *priv = nn->app_priv; + + priv->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); + priv->rx_filter.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); + priv->rx_filter_prev = priv->rx_filter; + priv->rx_filter_change = jiffies; } static int nfp_net_bpf_stats_update(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) { + struct nfp_net_bpf_priv *priv = nn->app_priv; u64 bytes, pkts; - pkts = nn->rx_filter.pkts - nn->rx_filter_prev.pkts; - bytes = nn->rx_filter.bytes - nn->rx_filter_prev.bytes; + pkts = priv->rx_filter.pkts - priv->rx_filter_prev.pkts; + bytes = priv->rx_filter.bytes - priv->rx_filter_prev.bytes; bytes -= pkts * ETH_HLEN; - nn->rx_filter_prev = nn->rx_filter; + priv->rx_filter_prev = priv->rx_filter; tcf_exts_stats_update(cls_bpf->exts, - bytes, pkts, nn->rx_filter_change); + bytes, pkts, priv->rx_filter_change); return 0; } @@ -183,6 +189,7 @@ nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags, unsigned int code_sz, unsigned int n_instr, bool dense_mode) { + struct nfp_net_bpf_priv *priv = nn->app_priv; u64 bpf_addr = dma_addr; int err; @@ -209,20 +216,23 @@ nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags, dma_free_coherent(nn->dp.dev, code_sz, code, dma_addr); nfp_net_bpf_stats_reset(nn); - mod_timer(&nn->rx_filter_stats_timer, jiffies + NFP_NET_STAT_POLL_IVL); + mod_timer(&priv->rx_filter_stats_timer, + jiffies + NFP_NET_STAT_POLL_IVL); } static int nfp_net_bpf_stop(struct nfp_net *nn) { + struct nfp_net_bpf_priv *priv = nn->app_priv; + if (!(nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF)) return 0; - spin_lock_bh(&nn->rx_filter_lock); + spin_lock_bh(&priv->rx_filter_lock); nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_BPF; - spin_unlock_bh(&nn->rx_filter_lock); + spin_unlock_bh(&priv->rx_filter_lock); nn_writel(nn, NFP_NET_CFG_CTRL, nn->dp.ctrl); - del_timer_sync(&nn->rx_filter_stats_timer); + del_timer_sync(&priv->rx_filter_stats_timer); nn->dp.bpf_offload_skip_sw = 0; return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 883cc6be02c1..2e526338f678 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -517,11 +517,6 @@ struct nfp_net_dp { * @rss_cfg: RSS configuration * @rss_key: RSS secret key * @rss_itbl: RSS indirection table - * @rx_filter: Filter offload statistics - dropped packets/bytes - * @rx_filter_prev: Filter offload statistics - values from previous update - * @rx_filter_change: Jiffies when statistics last changed - * @rx_filter_stats_timer: Timer for polling filter offload statistics - * @rx_filter_lock: Lock protecting timer state changes (teardown) * @max_r_vecs: Number of allocated interrupt vectors for RX/TX * @max_tx_rings: Maximum number of TX rings supported by the Firmware * @max_rx_rings: Maximum number of RX rings supported by the Firmware @@ -556,6 +551,7 @@ struct nfp_net_dp { * @pdev: Backpointer to PCI device * @app: APP handle if available * @port: Pointer to nfp_port structure if vNIC is a port + * @app_priv: APP private data for this vNIC */ struct nfp_net { struct nfp_net_dp dp; @@ -570,11 +566,6 @@ struct nfp_net { u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ]; u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ]; - struct nfp_stat_pair rx_filter, rx_filter_prev; - unsigned long rx_filter_change; - struct timer_list rx_filter_stats_timer; - spinlock_t rx_filter_lock; - unsigned int max_tx_rings; unsigned int max_rx_rings; @@ -627,6 +618,8 @@ struct nfp_net { struct nfp_app *app; struct nfp_port *port; + + void *app_priv; }; /* Functions to read/write from/to a BAR @@ -867,6 +860,4 @@ static inline void nfp_net_debugfs_dir_clean(struct dentry **dir) } #endif /* CONFIG_NFP_DEBUG */ -void nfp_net_filter_stats_timer(unsigned long data); - #endif /* _NFP_NET_H_ */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index e0ece2de5841..c3235d03b8eb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3072,13 +3072,10 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, nn->dp.rxd_cnt = NFP_NET_RX_DESCS_DEFAULT; spin_lock_init(&nn->reconfig_lock); - spin_lock_init(&nn->rx_filter_lock); spin_lock_init(&nn->link_status_lock); setup_timer(&nn->reconfig_timer, nfp_net_reconfig_timer, (unsigned long)nn); - setup_timer(&nn->rx_filter_stats_timer, - nfp_net_filter_stats_timer, (unsigned long)nn); return nn; } -- cgit v1.2.3 From 47eaa23b4c27d735cb797be71c711a99f99e9ff6 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2017 08:06:51 -0700 Subject: nfp: fix memory leak on FW load error Free management FW info when app FW load failed. Fixes: eefbde7e1002 ("nfp: add hwmon support") Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 68cd34d5a9fb..0c2e64d217b5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -279,6 +279,7 @@ static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf) err = nfp_fw_load(pdev, pf, nsp); if (err < 0) { + kfree(pf->nspi); kfree(pf->eth_tbl); dev_err(&pdev->dev, "Failed to load FW\n"); goto exit_close_nsp; -- cgit v1.2.3 From fc3973a1fa090d5f5437621a9ae1f2232a04ee5b Mon Sep 17 00:00:00 2001 From: Woojung Huh Date: Wed, 31 May 2017 20:19:13 +0000 Subject: phy: micrel: add Microchip KSZ 9477 Switch PHY support Adding Microchip 9477 Phy included in KSZ9477 Switch. Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Woojung Huh Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 4cfd54182da2..46e80bcc7a8a 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -20,6 +20,7 @@ * ksz8081, ksz8091, * ksz8061, * Switch : ksz8873, ksz886x + * ksz9477 */ #include @@ -996,6 +997,16 @@ static struct phy_driver ksphy_driver[] = { .read_status = ksz8873mll_read_status, .suspend = genphy_suspend, .resume = genphy_resume, +}, { + .phy_id = PHY_ID_KSZ9477, + .phy_id_mask = MICREL_PHY_ID_MASK, + .name = "Microchip KSZ9477", + .features = PHY_GBIT_FEATURES, + .config_init = kszphy_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, } }; module_phy_driver(ksphy_driver); -- cgit v1.2.3 From b987e98e50ab90e5291581204ef7a1c649313a70 Mon Sep 17 00:00:00 2001 From: Woojung Huh Date: Wed, 31 May 2017 20:19:19 +0000 Subject: dsa: add DSA switch driver for Microchip KSZ9477 The KSZ9477 is a fully integrated layer 2, managed, 7 ports GigE switch with numerous advanced features. 5 ports incorporate 10/100/1000 Mbps PHYs. The other 2 ports have interfaces that can be configured as SGMII, RGMII, MII or RMII. Either of these may connect directly to a host processor or to an external PHY. The SGMII port may interface to a fiber optic transceiver. This driver currently supports vlan, fdb, mdb & mirror dsa switch operations. Reviewed-by: Florian Fainelli Signed-off-by: Woojung Huh Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/Kconfig | 2 + drivers/net/dsa/Makefile | 1 + drivers/net/dsa/microchip/Kconfig | 12 + drivers/net/dsa/microchip/Makefile | 2 + drivers/net/dsa/microchip/ksz_9477_reg.h | 1676 ++++++++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz_common.c | 1279 +++++++++++++++++++++++ drivers/net/dsa/microchip/ksz_priv.h | 210 ++++ drivers/net/dsa/microchip/ksz_spi.c | 216 ++++ 8 files changed, 3398 insertions(+) create mode 100644 drivers/net/dsa/microchip/Kconfig create mode 100644 drivers/net/dsa/microchip/Makefile create mode 100644 drivers/net/dsa/microchip/ksz_9477_reg.h create mode 100644 drivers/net/dsa/microchip/ksz_common.c create mode 100644 drivers/net/dsa/microchip/ksz_priv.h create mode 100644 drivers/net/dsa/microchip/ksz_spi.c (limited to 'drivers') diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 68131a45ac5e..83a9bc892a3b 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -39,6 +39,8 @@ config NET_DSA_MV88E6060 This enables support for the Marvell 88E6060 ethernet switch chip. +source "drivers/net/dsa/microchip/Kconfig" + source "drivers/net/dsa/mv88e6xxx/Kconfig" config NET_DSA_QCA8K diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index 9613f36083a6..4a5b5bd297ee 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o obj-y += b53/ +obj-y += microchip/ obj-y += mv88e6xxx/ diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig new file mode 100644 index 000000000000..a8b8f59099ce --- /dev/null +++ b/drivers/net/dsa/microchip/Kconfig @@ -0,0 +1,12 @@ +menuconfig MICROCHIP_KSZ + tristate "Microchip KSZ series switch support" + depends on NET_DSA + select NET_DSA_TAG_KSZ + help + This driver adds support for Microchip KSZ switch chips. + +config MICROCHIP_KSZ_SPI_DRIVER + tristate "KSZ series SPI connected switch driver" + depends on MICROCHIP_KSZ && SPI + help + Select to enable support for registering switches configured through SPI. diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile new file mode 100644 index 000000000000..ed335e29fae8 --- /dev/null +++ b/drivers/net/dsa/microchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MICROCHIP_KSZ) += ksz_common.o +obj-$(CONFIG_MICROCHIP_KSZ_SPI_DRIVER) += ksz_spi.o diff --git a/drivers/net/dsa/microchip/ksz_9477_reg.h b/drivers/net/dsa/microchip/ksz_9477_reg.h new file mode 100644 index 000000000000..6aa6752035a1 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_9477_reg.h @@ -0,0 +1,1676 @@ +/* + * Microchip KSZ9477 register definitions + * + * Copyright (C) 2017 + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __KSZ9477_REGS_H +#define __KSZ9477_REGS_H + +#define KS_PRIO_M 0x7 +#define KS_PRIO_S 4 + +/* 0 - Operation */ +#define REG_CHIP_ID0__1 0x0000 + +#define REG_CHIP_ID1__1 0x0001 + +#define FAMILY_ID 0x95 +#define FAMILY_ID_94 0x94 +#define FAMILY_ID_95 0x95 +#define FAMILY_ID_85 0x85 +#define FAMILY_ID_98 0x98 +#define FAMILY_ID_88 0x88 + +#define REG_CHIP_ID2__1 0x0002 + +#define CHIP_ID_63 0x63 +#define CHIP_ID_66 0x66 +#define CHIP_ID_67 0x67 +#define CHIP_ID_77 0x77 +#define CHIP_ID_93 0x93 +#define CHIP_ID_96 0x96 +#define CHIP_ID_97 0x97 + +#define REG_CHIP_ID3__1 0x0003 + +#define SWITCH_REVISION_M 0x0F +#define SWITCH_REVISION_S 4 +#define SWITCH_RESET 0x01 + +#define REG_SW_PME_CTRL 0x0006 + +#define PME_ENABLE BIT(1) +#define PME_POLARITY BIT(0) + +#define REG_GLOBAL_OPTIONS 0x000F + +#define SW_GIGABIT_ABLE BIT(6) +#define SW_REDUNDANCY_ABLE BIT(5) +#define SW_AVB_ABLE BIT(4) +#define SW_9567_RL_5_2 0xC +#define SW_9477_SL_5_2 0xD + +#define SW_9896_GL_5_1 0xB +#define SW_9896_RL_5_1 0x8 +#define SW_9896_SL_5_1 0x9 + +#define SW_9895_GL_4_1 0x7 +#define SW_9895_RL_4_1 0x4 +#define SW_9895_SL_4_1 0x5 + +#define SW_9896_RL_4_2 0x6 + +#define SW_9893_RL_2_1 0x0 +#define SW_9893_SL_2_1 0x1 +#define SW_9893_GL_2_1 0x3 + +#define SW_QW_ABLE BIT(5) +#define SW_9893_RN_2_1 0xC + +#define REG_SW_INT_STATUS__4 0x0010 +#define REG_SW_INT_MASK__4 0x0014 + +#define LUE_INT BIT(31) +#define TRIG_TS_INT BIT(30) +#define APB_TIMEOUT_INT BIT(29) + +#define SWITCH_INT_MASK (TRIG_TS_INT | APB_TIMEOUT_INT) + +#define REG_SW_PORT_INT_STATUS__4 0x0018 +#define REG_SW_PORT_INT_MASK__4 0x001C +#define REG_SW_PHY_INT_STATUS 0x0020 +#define REG_SW_PHY_INT_ENABLE 0x0024 + +/* 1 - Global */ +#define REG_SW_GLOBAL_SERIAL_CTRL_0 0x0100 +#define SW_SPARE_REG_2 BIT(7) +#define SW_SPARE_REG_1 BIT(6) +#define SW_SPARE_REG_0 BIT(5) +#define SW_BIG_ENDIAN BIT(4) +#define SPI_AUTO_EDGE_DETECTION BIT(1) +#define SPI_CLOCK_OUT_RISING_EDGE BIT(0) + +#define REG_SW_GLOBAL_OUTPUT_CTRL__1 0x0103 +#define SW_ENABLE_REFCLKO BIT(1) +#define SW_REFCLKO_IS_125MHZ BIT(0) + +#define REG_SW_IBA__4 0x0104 + +#define SW_IBA_ENABLE BIT(31) +#define SW_IBA_DA_MATCH BIT(30) +#define SW_IBA_INIT BIT(29) +#define SW_IBA_QID_M 0xF +#define SW_IBA_QID_S 22 +#define SW_IBA_PORT_M 0x2F +#define SW_IBA_PORT_S 16 +#define SW_IBA_FRAME_TPID_M 0xFFFF + +#define REG_SW_APB_TIMEOUT_ADDR__4 0x0108 + +#define APB_TIMEOUT_ACKNOWLEDGE BIT(31) + +#define REG_SW_IBA_SYNC__1 0x010C + +#define REG_SW_IO_STRENGTH__1 0x010D +#define SW_DRIVE_STRENGTH_M 0x7 +#define SW_DRIVE_STRENGTH_2MA 0 +#define SW_DRIVE_STRENGTH_4MA 1 +#define SW_DRIVE_STRENGTH_8MA 2 +#define SW_DRIVE_STRENGTH_12MA 3 +#define SW_DRIVE_STRENGTH_16MA 4 +#define SW_DRIVE_STRENGTH_20MA 5 +#define SW_DRIVE_STRENGTH_24MA 6 +#define SW_DRIVE_STRENGTH_28MA 7 +#define SW_HI_SPEED_DRIVE_STRENGTH_S 4 +#define SW_LO_SPEED_DRIVE_STRENGTH_S 0 + +#define REG_SW_IBA_STATUS__4 0x0110 + +#define SW_IBA_REQ BIT(31) +#define SW_IBA_RESP BIT(30) +#define SW_IBA_DA_MISMATCH BIT(14) +#define SW_IBA_FMT_MISMATCH BIT(13) +#define SW_IBA_CODE_ERROR BIT(12) +#define SW_IBA_CMD_ERROR BIT(11) +#define SW_IBA_CMD_LOC_M (BIT(6) - 1) + +#define REG_SW_IBA_STATES__4 0x0114 + +#define SW_IBA_BUF_STATE_S 30 +#define SW_IBA_CMD_STATE_S 28 +#define SW_IBA_RESP_STATE_S 26 +#define SW_IBA_STATE_M 0x3 +#define SW_IBA_PACKET_SIZE_M 0x7F +#define SW_IBA_PACKET_SIZE_S 16 +#define SW_IBA_FMT_ID_M 0xFFFF + +#define REG_SW_IBA_RESULT__4 0x0118 + +#define SW_IBA_SIZE_S 24 + +#define SW_IBA_RETRY_CNT_M (BIT(5) - 1) + +/* 2 - PHY */ +#define REG_SW_POWER_MANAGEMENT_CTRL 0x0201 + +#define SW_PLL_POWER_DOWN BIT(5) +#define SW_POWER_DOWN_MODE 0x3 +#define SW_ENERGY_DETECTION 1 +#define SW_SOFT_POWER_DOWN 2 +#define SW_POWER_SAVING 3 + +/* 3 - Operation Control */ +#define REG_SW_OPERATION 0x0300 + +#define SW_DOUBLE_TAG BIT(7) +#define SW_RESET BIT(1) +#define SW_START BIT(0) + +#define REG_SW_MAC_ADDR_0 0x0302 +#define REG_SW_MAC_ADDR_1 0x0303 +#define REG_SW_MAC_ADDR_2 0x0304 +#define REG_SW_MAC_ADDR_3 0x0305 +#define REG_SW_MAC_ADDR_4 0x0306 +#define REG_SW_MAC_ADDR_5 0x0307 + +#define REG_SW_MTU__2 0x0308 + +#define REG_SW_ISP_TPID__2 0x030A + +#define REG_SW_HSR_TPID__2 0x030C + +#define REG_AVB_STRATEGY__2 0x030E + +#define SW_SHAPING_CREDIT_ACCT BIT(1) +#define SW_POLICING_CREDIT_ACCT BIT(0) + +#define REG_SW_LUE_CTRL_0 0x0310 + +#define SW_VLAN_ENABLE BIT(7) +#define SW_DROP_INVALID_VID BIT(6) +#define SW_AGE_CNT_M 0x7 +#define SW_AGE_CNT_S 3 +#define SW_RESV_MCAST_ENABLE BIT(2) +#define SW_HASH_OPTION_M 0x03 +#define SW_HASH_OPTION_CRC 1 +#define SW_HASH_OPTION_XOR 2 +#define SW_HASH_OPTION_DIRECT 3 + +#define REG_SW_LUE_CTRL_1 0x0311 + +#define UNICAST_LEARN_DISABLE BIT(7) +#define SW_SRC_ADDR_FILTER BIT(6) +#define SW_FLUSH_STP_TABLE BIT(5) +#define SW_FLUSH_MSTP_TABLE BIT(4) +#define SW_FWD_MCAST_SRC_ADDR BIT(3) +#define SW_AGING_ENABLE BIT(2) +#define SW_FAST_AGING BIT(1) +#define SW_LINK_AUTO_AGING BIT(0) + +#define REG_SW_LUE_CTRL_2 0x0312 + +#define SW_TRAP_DOUBLE_TAG BIT(6) +#define SW_EGRESS_VLAN_FILTER_DYN BIT(5) +#define SW_EGRESS_VLAN_FILTER_STA BIT(4) +#define SW_FLUSH_OPTION_M 0x3 +#define SW_FLUSH_OPTION_S 2 +#define SW_FLUSH_OPTION_DYN_MAC 1 +#define SW_FLUSH_OPTION_STA_MAC 2 +#define SW_FLUSH_OPTION_BOTH 3 +#define SW_PRIO_M 0x3 +#define SW_PRIO_DA 0 +#define SW_PRIO_SA 1 +#define SW_PRIO_HIGHEST_DA_SA 2 +#define SW_PRIO_LOWEST_DA_SA 3 + +#define REG_SW_LUE_CTRL_3 0x0313 + +#define REG_SW_LUE_INT_STATUS 0x0314 +#define REG_SW_LUE_INT_ENABLE 0x0315 + +#define LEARN_FAIL_INT BIT(2) +#define ALMOST_FULL_INT BIT(1) +#define WRITE_FAIL_INT BIT(0) + +#define REG_SW_LUE_INDEX_0__2 0x0316 + +#define ENTRY_INDEX_M 0x0FFF + +#define REG_SW_LUE_INDEX_1__2 0x0318 + +#define FAIL_INDEX_M 0x03FF + +#define REG_SW_LUE_INDEX_2__2 0x031A + +#define REG_SW_LUE_UNK_UCAST_CTRL__4 0x0320 + +#define SW_UNK_UCAST_ENABLE BIT(31) + +#define REG_SW_LUE_UNK_MCAST_CTRL__4 0x0324 + +#define SW_UNK_MCAST_ENABLE BIT(31) + +#define REG_SW_LUE_UNK_VID_CTRL__4 0x0328 + +#define SW_UNK_VID_ENABLE BIT(31) + +#define REG_SW_MAC_CTRL_0 0x0330 + +#define SW_NEW_BACKOFF BIT(7) +#define SW_CHECK_LENGTH BIT(3) +#define SW_PAUSE_UNH_MODE BIT(1) +#define SW_AGGR_BACKOFF BIT(0) + +#define REG_SW_MAC_CTRL_1 0x0331 + +#define MULTICAST_STORM_DISABLE BIT(6) +#define SW_BACK_PRESSURE BIT(5) +#define FAIR_FLOW_CTRL BIT(4) +#define NO_EXC_COLLISION_DROP BIT(3) +#define SW_JUMBO_PACKET BIT(2) +#define SW_LEGAL_PACKET_DISABLE BIT(1) +#define SW_PASS_SHORT_FRAME BIT(0) + +#define REG_SW_MAC_CTRL_2 0x0332 + +#define SW_REPLACE_VID BIT(3) +#define BROADCAST_STORM_RATE_HI 0x07 + +#define REG_SW_MAC_CTRL_3 0x0333 + +#define BROADCAST_STORM_RATE_LO 0xFF +#define BROADCAST_STORM_RATE 0x07FF + +#define REG_SW_MAC_CTRL_4 0x0334 + +#define SW_PASS_PAUSE BIT(3) + +#define REG_SW_MAC_CTRL_5 0x0335 + +#define SW_OUT_RATE_LIMIT_QUEUE_BASED BIT(3) + +#define REG_SW_MAC_CTRL_6 0x0336 + +#define SW_MIB_COUNTER_FLUSH BIT(7) +#define SW_MIB_COUNTER_FREEZE BIT(6) + +#define REG_SW_MAC_802_1P_MAP_0 0x0338 +#define REG_SW_MAC_802_1P_MAP_1 0x0339 +#define REG_SW_MAC_802_1P_MAP_2 0x033A +#define REG_SW_MAC_802_1P_MAP_3 0x033B + +#define SW_802_1P_MAP_M KS_PRIO_M +#define SW_802_1P_MAP_S KS_PRIO_S + +#define REG_SW_MAC_ISP_CTRL 0x033C + +#define REG_SW_MAC_TOS_CTRL 0x033E + +#define SW_TOS_DSCP_REMARK BIT(1) +#define SW_TOS_DSCP_REMAP BIT(0) + +#define REG_SW_MAC_TOS_PRIO_0 0x0340 +#define REG_SW_MAC_TOS_PRIO_1 0x0341 +#define REG_SW_MAC_TOS_PRIO_2 0x0342 +#define REG_SW_MAC_TOS_PRIO_3 0x0343 +#define REG_SW_MAC_TOS_PRIO_4 0x0344 +#define REG_SW_MAC_TOS_PRIO_5 0x0345 +#define REG_SW_MAC_TOS_PRIO_6 0x0346 +#define REG_SW_MAC_TOS_PRIO_7 0x0347 +#define REG_SW_MAC_TOS_PRIO_8 0x0348 +#define REG_SW_MAC_TOS_PRIO_9 0x0349 +#define REG_SW_MAC_TOS_PRIO_10 0x034A +#define REG_SW_MAC_TOS_PRIO_11 0x034B +#define REG_SW_MAC_TOS_PRIO_12 0x034C +#define REG_SW_MAC_TOS_PRIO_13 0x034D +#define REG_SW_MAC_TOS_PRIO_14 0x034E +#define REG_SW_MAC_TOS_PRIO_15 0x034F +#define REG_SW_MAC_TOS_PRIO_16 0x0350 +#define REG_SW_MAC_TOS_PRIO_17 0x0351 +#define REG_SW_MAC_TOS_PRIO_18 0x0352 +#define REG_SW_MAC_TOS_PRIO_19 0x0353 +#define REG_SW_MAC_TOS_PRIO_20 0x0354 +#define REG_SW_MAC_TOS_PRIO_21 0x0355 +#define REG_SW_MAC_TOS_PRIO_22 0x0356 +#define REG_SW_MAC_TOS_PRIO_23 0x0357 +#define REG_SW_MAC_TOS_PRIO_24 0x0358 +#define REG_SW_MAC_TOS_PRIO_25 0x0359 +#define REG_SW_MAC_TOS_PRIO_26 0x035A +#define REG_SW_MAC_TOS_PRIO_27 0x035B +#define REG_SW_MAC_TOS_PRIO_28 0x035C +#define REG_SW_MAC_TOS_PRIO_29 0x035D +#define REG_SW_MAC_TOS_PRIO_30 0x035E +#define REG_SW_MAC_TOS_PRIO_31 0x035F + +#define REG_SW_MRI_CTRL_0 0x0370 + +#define SW_IGMP_SNOOP BIT(6) +#define SW_IPV6_MLD_OPTION BIT(3) +#define SW_IPV6_MLD_SNOOP BIT(2) +#define SW_MIRROR_RX_TX BIT(0) + +#define REG_SW_CLASS_D_IP_CTRL__4 0x0374 + +#define SW_CLASS_D_IP_ENABLE BIT(31) + +#define REG_SW_MRI_CTRL_8 0x0378 + +#define SW_NO_COLOR_S 6 +#define SW_RED_COLOR_S 4 +#define SW_YELLOW_COLOR_S 2 +#define SW_GREEN_COLOR_S 0 +#define SW_COLOR_M 0x3 + +#define REG_SW_QM_CTRL__4 0x0390 + +#define PRIO_SCHEME_SELECT_M KS_PRIO_M +#define PRIO_SCHEME_SELECT_S 6 +#define PRIO_MAP_3_HI 0 +#define PRIO_MAP_2_HI 2 +#define PRIO_MAP_0_LO 3 +#define UNICAST_VLAN_BOUNDARY BIT(1) + +#define REG_SW_EEE_QM_CTRL__2 0x03C0 + +#define REG_SW_EEE_TXQ_WAIT_TIME__2 0x03C2 + +/* 4 - */ +#define REG_SW_VLAN_ENTRY__4 0x0400 + +#define VLAN_VALID BIT(31) +#define VLAN_FORWARD_OPTION BIT(27) +#define VLAN_PRIO_M KS_PRIO_M +#define VLAN_PRIO_S 24 +#define VLAN_MSTP_M 0x7 +#define VLAN_MSTP_S 12 +#define VLAN_FID_M 0x7F + +#define REG_SW_VLAN_ENTRY_UNTAG__4 0x0404 +#define REG_SW_VLAN_ENTRY_PORTS__4 0x0408 + +#define REG_SW_VLAN_ENTRY_INDEX__2 0x040C + +#define VLAN_INDEX_M 0x0FFF + +#define REG_SW_VLAN_CTRL 0x040E + +#define VLAN_START BIT(7) +#define VLAN_ACTION 0x3 +#define VLAN_WRITE 1 +#define VLAN_READ 2 +#define VLAN_CLEAR 3 + +#define REG_SW_ALU_INDEX_0 0x0410 + +#define ALU_FID_INDEX_S 16 +#define ALU_MAC_ADDR_HI 0xFFFF + +#define REG_SW_ALU_INDEX_1 0x0414 + +#define ALU_DIRECT_INDEX_M (BIT(12) - 1) + +#define REG_SW_ALU_CTRL__4 0x0418 + +#define ALU_VALID_CNT_M (BIT(14) - 1) +#define ALU_VALID_CNT_S 16 +#define ALU_START BIT(7) +#define ALU_VALID BIT(6) +#define ALU_DIRECT BIT(2) +#define ALU_ACTION 0x3 +#define ALU_WRITE 1 +#define ALU_READ 2 +#define ALU_SEARCH 3 + +#define REG_SW_ALU_STAT_CTRL__4 0x041C + +#define ALU_STAT_INDEX_M (BIT(4) - 1) +#define ALU_STAT_INDEX_S 16 +#define ALU_RESV_MCAST_INDEX_M (BIT(6) - 1) +#define ALU_STAT_START BIT(7) +#define ALU_RESV_MCAST_ADDR BIT(1) +#define ALU_STAT_READ BIT(0) + +#define REG_SW_ALU_VAL_A 0x0420 + +#define ALU_V_STATIC_VALID BIT(31) +#define ALU_V_SRC_FILTER BIT(30) +#define ALU_V_DST_FILTER BIT(29) +#define ALU_V_PRIO_AGE_CNT_M (BIT(3) - 1) +#define ALU_V_PRIO_AGE_CNT_S 26 +#define ALU_V_MSTP_M 0x7 + +#define REG_SW_ALU_VAL_B 0x0424 + +#define ALU_V_OVERRIDE BIT(31) +#define ALU_V_USE_FID BIT(30) +#define ALU_V_PORT_MAP (BIT(24) - 1) + +#define REG_SW_ALU_VAL_C 0x0428 + +#define ALU_V_FID_M (BIT(16) - 1) +#define ALU_V_FID_S 16 +#define ALU_V_MAC_ADDR_HI 0xFFFF + +#define REG_SW_ALU_VAL_D 0x042C + +#define REG_HSR_ALU_INDEX_0 0x0440 + +#define REG_HSR_ALU_INDEX_1 0x0444 + +#define HSR_DST_MAC_INDEX_LO_S 16 +#define HSR_SRC_MAC_INDEX_HI 0xFFFF + +#define REG_HSR_ALU_INDEX_2 0x0448 + +#define HSR_INDEX_MAX BIT(9) +#define HSR_DIRECT_INDEX_M (HSR_INDEX_MAX - 1) + +#define REG_HSR_ALU_INDEX_3 0x044C + +#define HSR_PATH_INDEX_M (BIT(4) - 1) + +#define REG_HSR_ALU_CTRL__4 0x0450 + +#define HSR_VALID_CNT_M (BIT(14) - 1) +#define HSR_VALID_CNT_S 16 +#define HSR_START BIT(7) +#define HSR_VALID BIT(6) +#define HSR_SEARCH_END BIT(5) +#define HSR_DIRECT BIT(2) +#define HSR_ACTION 0x3 +#define HSR_WRITE 1 +#define HSR_READ 2 +#define HSR_SEARCH 3 + +#define REG_HSR_ALU_VAL_A 0x0454 + +#define HSR_V_STATIC_VALID BIT(31) +#define HSR_V_AGE_CNT_M (BIT(3) - 1) +#define HSR_V_AGE_CNT_S 26 +#define HSR_V_PATH_ID_M (BIT(4) - 1) + +#define REG_HSR_ALU_VAL_B 0x0458 + +#define REG_HSR_ALU_VAL_C 0x045C + +#define HSR_V_DST_MAC_ADDR_LO_S 16 +#define HSR_V_SRC_MAC_ADDR_HI 0xFFFF + +#define REG_HSR_ALU_VAL_D 0x0460 + +#define REG_HSR_ALU_VAL_E 0x0464 + +#define HSR_V_START_SEQ_1_S 16 +#define HSR_V_START_SEQ_2_S 0 + +#define REG_HSR_ALU_VAL_F 0x0468 + +#define HSR_V_EXP_SEQ_1_S 16 +#define HSR_V_EXP_SEQ_2_S 0 + +#define REG_HSR_ALU_VAL_G 0x046C + +#define HSR_V_SEQ_CNT_1_S 16 +#define HSR_V_SEQ_CNT_2_S 0 + +#define HSR_V_SEQ_M (BIT(16) - 1) + +/* 5 - PTP Clock */ +#define REG_PTP_CLK_CTRL 0x0500 + +#define PTP_STEP_ADJ BIT(6) +#define PTP_STEP_DIR BIT(5) +#define PTP_READ_TIME BIT(4) +#define PTP_LOAD_TIME BIT(3) +#define PTP_CLK_ADJ_ENABLE BIT(2) +#define PTP_CLK_ENABLE BIT(1) +#define PTP_CLK_RESET BIT(0) + +#define REG_PTP_RTC_SUB_NANOSEC__2 0x0502 + +#define PTP_RTC_SUB_NANOSEC_M 0x0007 + +#define REG_PTP_RTC_NANOSEC 0x0504 +#define REG_PTP_RTC_NANOSEC_H 0x0504 +#define REG_PTP_RTC_NANOSEC_L 0x0506 + +#define REG_PTP_RTC_SEC 0x0508 +#define REG_PTP_RTC_SEC_H 0x0508 +#define REG_PTP_RTC_SEC_L 0x050A + +#define REG_PTP_SUBNANOSEC_RATE 0x050C +#define REG_PTP_SUBNANOSEC_RATE_H 0x050C + +#define PTP_RATE_DIR BIT(31) +#define PTP_TMP_RATE_ENABLE BIT(30) + +#define REG_PTP_SUBNANOSEC_RATE_L 0x050E + +#define REG_PTP_RATE_DURATION 0x0510 +#define REG_PTP_RATE_DURATION_H 0x0510 +#define REG_PTP_RATE_DURATION_L 0x0512 + +#define REG_PTP_MSG_CONF1 0x0514 + +#define PTP_802_1AS BIT(7) +#define PTP_ENABLE BIT(6) +#define PTP_ETH_ENABLE BIT(5) +#define PTP_IPV4_UDP_ENABLE BIT(4) +#define PTP_IPV6_UDP_ENABLE BIT(3) +#define PTP_TC_P2P BIT(2) +#define PTP_MASTER BIT(1) +#define PTP_1STEP BIT(0) + +#define REG_PTP_MSG_CONF2 0x0516 + +#define PTP_UNICAST_ENABLE BIT(12) +#define PTP_ALTERNATE_MASTER BIT(11) +#define PTP_ALL_HIGH_PRIO BIT(10) +#define PTP_SYNC_CHECK BIT(9) +#define PTP_DELAY_CHECK BIT(8) +#define PTP_PDELAY_CHECK BIT(7) +#define PTP_DROP_SYNC_DELAY_REQ BIT(5) +#define PTP_DOMAIN_CHECK BIT(4) +#define PTP_UDP_CHECKSUM BIT(2) + +#define REG_PTP_DOMAIN_VERSION 0x0518 +#define PTP_VERSION_M 0xFF00 +#define PTP_DOMAIN_M 0x00FF + +#define REG_PTP_UNIT_INDEX__4 0x0520 + +#define PTP_UNIT_M 0xF + +#define PTP_GPIO_INDEX_S 16 +#define PTP_TSI_INDEX_S 8 +#define PTP_TOU_INDEX_S 0 + +#define REG_PTP_TRIG_STATUS__4 0x0524 + +#define TRIG_ERROR_S 16 +#define TRIG_DONE_S 0 + +#define REG_PTP_INT_STATUS__4 0x0528 + +#define TRIG_INT_S 16 +#define TS_INT_S 0 + +#define TRIG_UNIT_M 0x7 +#define TS_UNIT_M 0x3 + +#define REG_PTP_CTRL_STAT__4 0x052C + +#define GPIO_IN BIT(7) +#define GPIO_OUT BIT(6) +#define TS_INT_ENABLE BIT(5) +#define TRIG_ACTIVE BIT(4) +#define TRIG_ENABLE BIT(3) +#define TRIG_RESET BIT(2) +#define TS_ENABLE BIT(1) +#define TS_RESET BIT(0) + +#define GPIO_CTRL_M (GPIO_IN | GPIO_OUT) + +#define TRIG_CTRL_M \ + (TRIG_ACTIVE | TRIG_ENABLE | TRIG_RESET) + +#define TS_CTRL_M \ + (TS_INT_ENABLE | TS_ENABLE | TS_RESET) + +#define REG_TRIG_TARGET_NANOSEC 0x0530 +#define REG_TRIG_TARGET_SEC 0x0534 + +#define REG_TRIG_CTRL__4 0x0538 + +#define TRIG_CASCADE_ENABLE BIT(31) +#define TRIG_CASCADE_TAIL BIT(30) +#define TRIG_CASCADE_UPS_M 0xF +#define TRIG_CASCADE_UPS_S 26 +#define TRIG_NOW BIT(25) +#define TRIG_NOTIFY BIT(24) +#define TRIG_EDGE BIT(23) +#define TRIG_PATTERN_S 20 +#define TRIG_PATTERN_M 0x7 +#define TRIG_NEG_EDGE 0 +#define TRIG_POS_EDGE 1 +#define TRIG_NEG_PULSE 2 +#define TRIG_POS_PULSE 3 +#define TRIG_NEG_PERIOD 4 +#define TRIG_POS_PERIOD 5 +#define TRIG_REG_OUTPUT 6 +#define TRIG_GPO_S 16 +#define TRIG_GPO_M 0xF +#define TRIG_CASCADE_ITERATE_CNT_M 0xFFFF + +#define REG_TRIG_CYCLE_WIDTH 0x053C + +#define REG_TRIG_CYCLE_CNT 0x0540 + +#define TRIG_CYCLE_CNT_M 0xFFFF +#define TRIG_CYCLE_CNT_S 16 +#define TRIG_BIT_PATTERN_M 0xFFFF + +#define REG_TRIG_ITERATE_TIME 0x0544 + +#define REG_TRIG_PULSE_WIDTH__4 0x0548 + +#define TRIG_PULSE_WIDTH_M 0x00FFFFFF + +#define REG_TS_CTRL_STAT__4 0x0550 + +#define TS_EVENT_DETECT_M 0xF +#define TS_EVENT_DETECT_S 17 +#define TS_EVENT_OVERFLOW BIT(16) +#define TS_GPI_M 0xF +#define TS_GPI_S 8 +#define TS_DETECT_RISE BIT(7) +#define TS_DETECT_FALL BIT(6) +#define TS_DETECT_S 6 +#define TS_CASCADE_TAIL BIT(5) +#define TS_CASCADE_UPS_M 0xF +#define TS_CASCADE_UPS_S 1 +#define TS_CASCADE_ENABLE BIT(0) + +#define DETECT_RISE (TS_DETECT_RISE >> TS_DETECT_S) +#define DETECT_FALL (TS_DETECT_FALL >> TS_DETECT_S) + +#define REG_TS_EVENT_0_NANOSEC 0x0554 +#define REG_TS_EVENT_0_SEC 0x0558 +#define REG_TS_EVENT_0_SUB_NANOSEC 0x055C + +#define REG_TS_EVENT_1_NANOSEC 0x0560 +#define REG_TS_EVENT_1_SEC 0x0564 +#define REG_TS_EVENT_1_SUB_NANOSEC 0x0568 + +#define REG_TS_EVENT_2_NANOSEC 0x056C +#define REG_TS_EVENT_2_SEC 0x0570 +#define REG_TS_EVENT_2_SUB_NANOSEC 0x0574 + +#define REG_TS_EVENT_3_NANOSEC 0x0578 +#define REG_TS_EVENT_3_SEC 0x057C +#define REG_TS_EVENT_3_SUB_NANOSEC 0x0580 + +#define REG_TS_EVENT_4_NANOSEC 0x0584 +#define REG_TS_EVENT_4_SEC 0x0588 +#define REG_TS_EVENT_4_SUB_NANOSEC 0x058C + +#define REG_TS_EVENT_5_NANOSEC 0x0590 +#define REG_TS_EVENT_5_SEC 0x0594 +#define REG_TS_EVENT_5_SUB_NANOSEC 0x0598 + +#define REG_TS_EVENT_6_NANOSEC 0x059C +#define REG_TS_EVENT_6_SEC 0x05A0 +#define REG_TS_EVENT_6_SUB_NANOSEC 0x05A4 + +#define REG_TS_EVENT_7_NANOSEC 0x05A8 +#define REG_TS_EVENT_7_SEC 0x05AC +#define REG_TS_EVENT_7_SUB_NANOSEC 0x05B0 + +#define TS_EVENT_EDGE_M 0x1 +#define TS_EVENT_EDGE_S 30 +#define TS_EVENT_NANOSEC_M (BIT(30) - 1) + +#define TS_EVENT_SUB_NANOSEC_M 0x7 + +#define TS_EVENT_SAMPLE \ + (REG_TS_EVENT_1_NANOSEC - REG_TS_EVENT_0_NANOSEC) + +#define PORT_CTRL_ADDR(port, addr) ((addr) | (((port) + 1) << 12)) + +#define REG_GLOBAL_RR_INDEX__1 0x0600 + +/* DLR */ +#define REG_DLR_SRC_PORT__4 0x0604 + +#define DLR_SRC_PORT_UNICAST BIT(31) +#define DLR_SRC_PORT_M 0x3 +#define DLR_SRC_PORT_BOTH 0 +#define DLR_SRC_PORT_EACH 1 + +#define REG_DLR_IP_ADDR__4 0x0608 + +#define REG_DLR_CTRL__1 0x0610 + +#define DLR_RESET_SEQ_ID BIT(3) +#define DLR_BACKUP_AUTO_ON BIT(2) +#define DLR_BEACON_TX_ENABLE BIT(1) +#define DLR_ASSIST_ENABLE BIT(0) + +#define REG_DLR_STATE__1 0x0611 + +#define DLR_NODE_STATE_M 0x3 +#define DLR_NODE_STATE_S 1 +#define DLR_NODE_STATE_IDLE 0 +#define DLR_NODE_STATE_FAULT 1 +#define DLR_NODE_STATE_NORMAL 2 +#define DLR_RING_STATE_FAULT 0 +#define DLR_RING_STATE_NORMAL 1 + +#define REG_DLR_PRECEDENCE__1 0x0612 + +#define REG_DLR_BEACON_INTERVAL__4 0x0614 + +#define REG_DLR_BEACON_TIMEOUT__4 0x0618 + +#define REG_DLR_TIMEOUT_WINDOW__4 0x061C + +#define DLR_TIMEOUT_WINDOW_M (BIT(22) - 1) + +#define REG_DLR_VLAN_ID__2 0x0620 + +#define DLR_VLAN_ID_M (BIT(12) - 1) + +#define REG_DLR_DEST_ADDR_0 0x0622 +#define REG_DLR_DEST_ADDR_1 0x0623 +#define REG_DLR_DEST_ADDR_2 0x0624 +#define REG_DLR_DEST_ADDR_3 0x0625 +#define REG_DLR_DEST_ADDR_4 0x0626 +#define REG_DLR_DEST_ADDR_5 0x0627 + +#define REG_DLR_PORT_MAP__4 0x0628 + +#define REG_DLR_CLASS__1 0x062C + +#define DLR_FRAME_QID_M 0x3 + +/* HSR */ +#define REG_HSR_PORT_MAP__4 0x0640 + +#define REG_HSR_ALU_CTRL_0__1 0x0644 + +#define HSR_DUPLICATE_DISCARD BIT(7) +#define HSR_NODE_UNICAST BIT(6) +#define HSR_AGE_CNT_DEFAULT_M 0x7 +#define HSR_AGE_CNT_DEFAULT_S 3 +#define HSR_LEARN_MCAST_DISABLE BIT(2) +#define HSR_HASH_OPTION_M 0x3 +#define HSR_HASH_DISABLE 0 +#define HSR_HASH_UPPER_BITS 1 +#define HSR_HASH_LOWER_BITS 2 +#define HSR_HASH_XOR_BOTH_BITS 3 + +#define REG_HSR_ALU_CTRL_1__1 0x0645 + +#define HSR_LEARN_UCAST_DISABLE BIT(7) +#define HSR_FLUSH_TABLE BIT(5) +#define HSR_PROC_MCAST_SRC BIT(3) +#define HSR_AGING_ENABLE BIT(2) + +#define REG_HSR_ALU_CTRL_2__2 0x0646 + +#define REG_HSR_ALU_AGE_PERIOD__4 0x0648 + +#define REG_HSR_ALU_INT_STATUS__1 0x064C +#define REG_HSR_ALU_INT_MASK__1 0x064D + +#define HSR_WINDOW_OVERFLOW_INT BIT(3) +#define HSR_LEARN_FAIL_INT BIT(2) +#define HSR_ALMOST_FULL_INT BIT(1) +#define HSR_WRITE_FAIL_INT BIT(0) + +#define REG_HSR_ALU_ENTRY_0__2 0x0650 + +#define HSR_ENTRY_INDEX_M (BIT(10) - 1) +#define HSR_FAIL_INDEX_M (BIT(8) - 1) + +#define REG_HSR_ALU_ENTRY_1__2 0x0652 + +#define HSR_FAIL_LEARN_INDEX_M (BIT(8) - 1) + +#define REG_HSR_ALU_ENTRY_3__2 0x0654 + +#define HSR_CPU_ACCESS_ENTRY_INDEX_M (BIT(8) - 1) + +/* 0 - Operation */ +#define REG_PORT_DEFAULT_VID 0x0000 + +#define REG_PORT_CUSTOM_VID 0x0002 +#define REG_PORT_AVB_SR_1_VID 0x0004 +#define REG_PORT_AVB_SR_2_VID 0x0006 + +#define REG_PORT_AVB_SR_1_TYPE 0x0008 +#define REG_PORT_AVB_SR_2_TYPE 0x000A + +#define REG_PORT_PME_STATUS 0x0013 +#define REG_PORT_PME_CTRL 0x0017 + +#define PME_WOL_MAGICPKT BIT(2) +#define PME_WOL_LINKUP BIT(1) +#define PME_WOL_ENERGY BIT(0) + +#define REG_PORT_INT_STATUS 0x001B +#define REG_PORT_INT_MASK 0x001F + +#define PORT_SGMII_INT BIT(3) +#define PORT_PTP_INT BIT(2) +#define PORT_PHY_INT BIT(1) +#define PORT_ACL_INT BIT(0) + +#define PORT_INT_MASK \ + (PORT_SGMII_INT | PORT_PTP_INT | PORT_PHY_INT | PORT_ACL_INT) + +#define REG_PORT_CTRL_0 0x0020 + +#define PORT_MAC_LOOPBACK BIT(7) +#define PORT_FORCE_TX_FLOW_CTRL BIT(4) +#define PORT_FORCE_RX_FLOW_CTRL BIT(3) +#define PORT_TAIL_TAG_ENABLE BIT(2) +#define PORT_QUEUE_SPLIT_ENABLE 0x3 + +#define REG_PORT_CTRL_1 0x0021 + +#define PORT_SRP_ENABLE 0x3 + +#define REG_PORT_STATUS_0 0x0030 + +#define PORT_INTF_SPEED_M 0x3 +#define PORT_INTF_SPEED_S 3 +#define PORT_INTF_FULL_DUPLEX BIT(2) +#define PORT_TX_FLOW_CTRL BIT(1) +#define PORT_RX_FLOW_CTRL BIT(0) + +#define REG_PORT_STATUS_1 0x0034 + +/* 1 - PHY */ +#define REG_PORT_PHY_CTRL 0x0100 + +#define PORT_PHY_RESET BIT(15) +#define PORT_PHY_LOOPBACK BIT(14) +#define PORT_SPEED_100MBIT BIT(13) +#define PORT_AUTO_NEG_ENABLE BIT(12) +#define PORT_POWER_DOWN BIT(11) +#define PORT_ISOLATE BIT(10) +#define PORT_AUTO_NEG_RESTART BIT(9) +#define PORT_FULL_DUPLEX BIT(8) +#define PORT_COLLISION_TEST BIT(7) +#define PORT_SPEED_1000MBIT BIT(6) + +#define REG_PORT_PHY_STATUS 0x0102 + +#define PORT_100BT4_CAPABLE BIT(15) +#define PORT_100BTX_FD_CAPABLE BIT(14) +#define PORT_100BTX_CAPABLE BIT(13) +#define PORT_10BT_FD_CAPABLE BIT(12) +#define PORT_10BT_CAPABLE BIT(11) +#define PORT_EXTENDED_STATUS BIT(8) +#define PORT_MII_SUPPRESS_CAPABLE BIT(6) +#define PORT_AUTO_NEG_ACKNOWLEDGE BIT(5) +#define PORT_REMOTE_FAULT BIT(4) +#define PORT_AUTO_NEG_CAPABLE BIT(3) +#define PORT_LINK_STATUS BIT(2) +#define PORT_JABBER_DETECT BIT(1) +#define PORT_EXTENDED_CAPABILITY BIT(0) + +#define REG_PORT_PHY_ID_HI 0x0104 +#define REG_PORT_PHY_ID_LO 0x0106 + +#define KSZ9477_ID_HI 0x0022 +#define KSZ9477_ID_LO 0x1622 + +#define REG_PORT_PHY_AUTO_NEGOTIATION 0x0108 + +#define PORT_AUTO_NEG_NEXT_PAGE BIT(15) +#define PORT_AUTO_NEG_REMOTE_FAULT BIT(13) +#define PORT_AUTO_NEG_ASYM_PAUSE BIT(11) +#define PORT_AUTO_NEG_SYM_PAUSE BIT(10) +#define PORT_AUTO_NEG_100BT4 BIT(9) +#define PORT_AUTO_NEG_100BTX_FD BIT(8) +#define PORT_AUTO_NEG_100BTX BIT(7) +#define PORT_AUTO_NEG_10BT_FD BIT(6) +#define PORT_AUTO_NEG_10BT BIT(5) +#define PORT_AUTO_NEG_SELECTOR 0x001F +#define PORT_AUTO_NEG_802_3 0x0001 + +#define PORT_AUTO_NEG_PAUSE \ + (PORT_AUTO_NEG_ASYM_PAUSE | PORT_AUTO_NEG_SYM_PAUSE) + +#define REG_PORT_PHY_REMOTE_CAPABILITY 0x010A + +#define PORT_REMOTE_NEXT_PAGE BIT(15) +#define PORT_REMOTE_ACKNOWLEDGE BIT(14) +#define PORT_REMOTE_REMOTE_FAULT BIT(13) +#define PORT_REMOTE_ASYM_PAUSE BIT(11) +#define PORT_REMOTE_SYM_PAUSE BIT(10) +#define PORT_REMOTE_100BTX_FD BIT(8) +#define PORT_REMOTE_100BTX BIT(7) +#define PORT_REMOTE_10BT_FD BIT(6) +#define PORT_REMOTE_10BT BIT(5) + +#define REG_PORT_PHY_1000_CTRL 0x0112 + +#define PORT_AUTO_NEG_MANUAL BIT(12) +#define PORT_AUTO_NEG_MASTER BIT(11) +#define PORT_AUTO_NEG_MASTER_PREFERRED BIT(10) +#define PORT_AUTO_NEG_1000BT_FD BIT(9) +#define PORT_AUTO_NEG_1000BT BIT(8) + +#define REG_PORT_PHY_1000_STATUS 0x0114 + +#define PORT_MASTER_FAULT BIT(15) +#define PORT_LOCAL_MASTER BIT(14) +#define PORT_LOCAL_RX_OK BIT(13) +#define PORT_REMOTE_RX_OK BIT(12) +#define PORT_REMOTE_1000BT_FD BIT(11) +#define PORT_REMOTE_1000BT BIT(10) +#define PORT_REMOTE_IDLE_CNT_M 0x0F + +#define PORT_PHY_1000_STATIC_STATUS \ + (PORT_LOCAL_RX_OK | \ + PORT_REMOTE_RX_OK | \ + PORT_REMOTE_1000BT_FD | \ + PORT_REMOTE_1000BT) + +#define REG_PORT_PHY_MMD_SETUP 0x011A + +#define PORT_MMD_OP_MODE_M 0x3 +#define PORT_MMD_OP_MODE_S 14 +#define PORT_MMD_OP_INDEX 0 +#define PORT_MMD_OP_DATA_NO_INCR 1 +#define PORT_MMD_OP_DATA_INCR_RW 2 +#define PORT_MMD_OP_DATA_INCR_W 3 +#define PORT_MMD_DEVICE_ID_M 0x1F + +#define MMD_SETUP(mode, dev) \ + (((u16)(mode) << PORT_MMD_OP_MODE_S) | (dev)) + +#define REG_PORT_PHY_MMD_INDEX_DATA 0x011C + +#define MMD_DEVICE_ID_DSP 1 + +#define MMD_DSP_SQI_CHAN_A 0xAC +#define MMD_DSP_SQI_CHAN_B 0xAD +#define MMD_DSP_SQI_CHAN_C 0xAE +#define MMD_DSP_SQI_CHAN_D 0xAF + +#define DSP_SQI_ERR_DETECTED BIT(15) +#define DSP_SQI_AVG_ERR 0x7FFF + +#define MMD_DEVICE_ID_COMMON 2 + +#define MMD_DEVICE_ID_EEE_ADV 7 + +#define MMD_EEE_ADV 0x3C +#define EEE_ADV_100MBIT BIT(1) +#define EEE_ADV_1GBIT BIT(2) + +#define MMD_EEE_LP_ADV 0x3D +#define MMD_EEE_MSG_CODE 0x3F + +#define MMD_DEVICE_ID_AFED 0x1C + +#define REG_PORT_PHY_EXTENDED_STATUS 0x011E + +#define PORT_100BTX_FD_ABLE BIT(15) +#define PORT_100BTX_ABLE BIT(14) +#define PORT_10BT_FD_ABLE BIT(13) +#define PORT_10BT_ABLE BIT(12) + +#define REG_PORT_SGMII_ADDR__4 0x0200 +#define PORT_SGMII_AUTO_INCR BIT(23) +#define PORT_SGMII_DEVICE_ID_M 0x1F +#define PORT_SGMII_DEVICE_ID_S 16 +#define PORT_SGMII_ADDR_M (BIT(21) - 1) + +#define REG_PORT_SGMII_DATA__4 0x0204 +#define PORT_SGMII_DATA_M (BIT(16) - 1) + +#define MMD_DEVICE_ID_PMA 0x01 +#define MMD_DEVICE_ID_PCS 0x03 +#define MMD_DEVICE_ID_PHY_XS 0x04 +#define MMD_DEVICE_ID_DTE_XS 0x05 +#define MMD_DEVICE_ID_AN 0x07 +#define MMD_DEVICE_ID_VENDOR_CTRL 0x1E +#define MMD_DEVICE_ID_VENDOR_MII 0x1F + +#define SR_MII MMD_DEVICE_ID_VENDOR_MII + +#define MMD_SR_MII_CTRL 0x0000 + +#define SR_MII_RESET BIT(15) +#define SR_MII_LOOPBACK BIT(14) +#define SR_MII_SPEED_100MBIT BIT(13) +#define SR_MII_AUTO_NEG_ENABLE BIT(12) +#define SR_MII_POWER_DOWN BIT(11) +#define SR_MII_AUTO_NEG_RESTART BIT(9) +#define SR_MII_FULL_DUPLEX BIT(8) +#define SR_MII_SPEED_1000MBIT BIT(6) + +#define MMD_SR_MII_STATUS 0x0001 +#define MMD_SR_MII_ID_1 0x0002 +#define MMD_SR_MII_ID_2 0x0003 +#define MMD_SR_MII_AUTO_NEGOTIATION 0x0004 + +#define SR_MII_AUTO_NEG_NEXT_PAGE BIT(15) +#define SR_MII_AUTO_NEG_REMOTE_FAULT_M 0x3 +#define SR_MII_AUTO_NEG_REMOTE_FAULT_S 12 +#define SR_MII_AUTO_NEG_NO_ERROR 0 +#define SR_MII_AUTO_NEG_OFFLINE 1 +#define SR_MII_AUTO_NEG_LINK_FAILURE 2 +#define SR_MII_AUTO_NEG_ERROR 3 +#define SR_MII_AUTO_NEG_PAUSE_M 0x3 +#define SR_MII_AUTO_NEG_PAUSE_S 7 +#define SR_MII_AUTO_NEG_NO_PAUSE 0 +#define SR_MII_AUTO_NEG_ASYM_PAUSE_TX 1 +#define SR_MII_AUTO_NEG_SYM_PAUSE 2 +#define SR_MII_AUTO_NEG_ASYM_PAUSE_RX 3 +#define SR_MII_AUTO_NEG_HALF_DUPLEX BIT(6) +#define SR_MII_AUTO_NEG_FULL_DUPLEX BIT(5) + +#define MMD_SR_MII_REMOTE_CAPABILITY 0x0005 +#define MMD_SR_MII_AUTO_NEG_EXP 0x0006 +#define MMD_SR_MII_AUTO_NEG_EXT 0x000F + +#define MMD_SR_MII_DIGITAL_CTRL_1 0x8000 + +#define MMD_SR_MII_AUTO_NEG_CTRL 0x8001 + +#define SR_MII_8_BIT BIT(8) +#define SR_MII_SGMII_LINK_UP BIT(4) +#define SR_MII_TX_CFG_PHY_MASTER BIT(3) +#define SR_MII_PCS_MODE_M 0x3 +#define SR_MII_PCS_MODE_S 1 +#define SR_MII_PCS_SGMII 2 +#define SR_MII_AUTO_NEG_COMPLETE_INTR BIT(0) + +#define MMD_SR_MII_AUTO_NEG_STATUS 0x8002 + +#define SR_MII_STAT_LINK_UP BIT(4) +#define SR_MII_STAT_M 0x3 +#define SR_MII_STAT_S 2 +#define SR_MII_STAT_10_MBPS 0 +#define SR_MII_STAT_100_MBPS 1 +#define SR_MII_STAT_1000_MBPS 2 +#define SR_MII_STAT_FULL_DUPLEX BIT(1) + +#define MMD_SR_MII_PHY_CTRL 0x80A0 + +#define SR_MII_PHY_LANE_SEL_M 0xF +#define SR_MII_PHY_LANE_SEL_S 8 +#define SR_MII_PHY_WRITE BIT(1) +#define SR_MII_PHY_START_BUSY BIT(0) + +#define MMD_SR_MII_PHY_ADDR 0x80A1 + +#define SR_MII_PHY_ADDR_M (BIT(16) - 1) + +#define MMD_SR_MII_PHY_DATA 0x80A2 + +#define SR_MII_PHY_DATA_M (BIT(16) - 1) + +#define SR_MII_PHY_JTAG_CHIP_ID_HI 0x000C +#define SR_MII_PHY_JTAG_CHIP_ID_LO 0x000D + +#define REG_PORT_PHY_REMOTE_LB_LED 0x0122 + +#define PORT_REMOTE_LOOPBACK BIT(8) +#define PORT_LED_SELECT (3 << 6) +#define PORT_LED_CTRL (3 << 4) +#define PORT_LED_CTRL_TEST BIT(3) +#define PORT_10BT_PREAMBLE BIT(2) +#define PORT_LINK_MD_10BT_ENABLE BIT(1) +#define PORT_LINK_MD_PASS BIT(0) + +#define REG_PORT_PHY_LINK_MD 0x0124 + +#define PORT_START_CABLE_DIAG BIT(15) +#define PORT_TX_DISABLE BIT(14) +#define PORT_CABLE_DIAG_PAIR_M 0x3 +#define PORT_CABLE_DIAG_PAIR_S 12 +#define PORT_CABLE_DIAG_SELECT_M 0x3 +#define PORT_CABLE_DIAG_SELECT_S 10 +#define PORT_CABLE_DIAG_RESULT_M 0x3 +#define PORT_CABLE_DIAG_RESULT_S 8 +#define PORT_CABLE_STAT_NORMAL 0 +#define PORT_CABLE_STAT_OPEN 1 +#define PORT_CABLE_STAT_SHORT 2 +#define PORT_CABLE_STAT_FAILED 3 +#define PORT_CABLE_FAULT_COUNTER 0x00FF + +#define REG_PORT_PHY_PMA_STATUS 0x0126 + +#define PORT_1000_LINK_GOOD BIT(1) +#define PORT_100_LINK_GOOD BIT(0) + +#define REG_PORT_PHY_DIGITAL_STATUS 0x0128 + +#define PORT_LINK_DETECT BIT(14) +#define PORT_SIGNAL_DETECT BIT(13) +#define PORT_PHY_STAT_MDI BIT(12) +#define PORT_PHY_STAT_MASTER BIT(11) + +#define REG_PORT_PHY_RXER_COUNTER 0x012A + +#define REG_PORT_PHY_INT_ENABLE 0x0136 +#define REG_PORT_PHY_INT_STATUS 0x0137 + +#define JABBER_INT BIT(7) +#define RX_ERR_INT BIT(6) +#define PAGE_RX_INT BIT(5) +#define PARALLEL_DETECT_FAULT_INT BIT(4) +#define LINK_PARTNER_ACK_INT BIT(3) +#define LINK_DOWN_INT BIT(2) +#define REMOTE_FAULT_INT BIT(1) +#define LINK_UP_INT BIT(0) + +#define REG_PORT_PHY_DIGITAL_DEBUG_1 0x0138 + +#define PORT_REG_CLK_SPEED_25_MHZ BIT(14) +#define PORT_PHY_FORCE_MDI BIT(7) +#define PORT_PHY_AUTO_MDIX_DISABLE BIT(6) + +/* Same as PORT_PHY_LOOPBACK */ +#define PORT_PHY_PCS_LOOPBACK BIT(0) + +#define REG_PORT_PHY_DIGITAL_DEBUG_2 0x013A + +#define REG_PORT_PHY_DIGITAL_DEBUG_3 0x013C + +#define PORT_100BT_FIXED_LATENCY BIT(15) + +#define REG_PORT_PHY_PHY_CTRL 0x013E + +#define PORT_INT_PIN_HIGH BIT(14) +#define PORT_ENABLE_JABBER BIT(9) +#define PORT_STAT_SPEED_1000MBIT BIT(6) +#define PORT_STAT_SPEED_100MBIT BIT(5) +#define PORT_STAT_SPEED_10MBIT BIT(4) +#define PORT_STAT_FULL_DUPLEX BIT(3) + +/* Same as PORT_PHY_STAT_MASTER */ +#define PORT_STAT_MASTER BIT(2) +#define PORT_RESET BIT(1) +#define PORT_LINK_STATUS_FAIL BIT(0) + +/* 3 - xMII */ +#define REG_PORT_XMII_CTRL_0 0x0300 + +#define PORT_SGMII_SEL BIT(7) +#define PORT_MII_FULL_DUPLEX BIT(6) +#define PORT_MII_100MBIT BIT(4) +#define PORT_GRXC_ENABLE BIT(0) + +#define REG_PORT_XMII_CTRL_1 0x0301 + +#define PORT_RMII_CLK_SEL BIT(7) +/* S1 */ +#define PORT_MII_1000MBIT_S1 BIT(6) +/* S2 */ +#define PORT_MII_NOT_1GBIT BIT(6) +#define PORT_MII_SEL_EDGE BIT(5) +#define PORT_RGMII_ID_IG_ENABLE BIT(4) +#define PORT_RGMII_ID_EG_ENABLE BIT(3) +#define PORT_MII_MAC_MODE BIT(2) +#define PORT_MII_SEL_M 0x3 +/* S1 */ +#define PORT_MII_SEL_S1 0x0 +#define PORT_RMII_SEL_S1 0x1 +#define PORT_GMII_SEL_S1 0x2 +#define PORT_RGMII_SEL_S1 0x3 +/* S2 */ +#define PORT_RGMII_SEL 0x0 +#define PORT_RMII_SEL 0x1 +#define PORT_GMII_SEL 0x2 +#define PORT_MII_SEL 0x3 + +/* 4 - MAC */ +#define REG_PORT_MAC_CTRL_0 0x0400 + +#define PORT_BROADCAST_STORM BIT(1) +#define PORT_JUMBO_FRAME BIT(0) + +#define REG_PORT_MAC_CTRL_1 0x0401 + +#define PORT_BACK_PRESSURE BIT(3) +#define PORT_PASS_ALL BIT(0) + +#define REG_PORT_MAC_CTRL_2 0x0402 + +#define PORT_100BT_EEE_DISABLE BIT(7) +#define PORT_1000BT_EEE_DISABLE BIT(6) + +#define REG_PORT_MAC_IN_RATE_LIMIT 0x0403 + +#define PORT_IN_PORT_BASED_S 6 +#define PORT_RATE_PACKET_BASED_S 5 +#define PORT_IN_FLOW_CTRL_S 4 +#define PORT_COUNT_IFG_S 1 +#define PORT_COUNT_PREAMBLE_S 0 +#define PORT_IN_PORT_BASED BIT(6) +#define PORT_IN_PACKET_BASED BIT(5) +#define PORT_IN_FLOW_CTRL BIT(4) +#define PORT_IN_LIMIT_MODE_M 0x3 +#define PORT_IN_LIMIT_MODE_S 2 +#define PORT_IN_ALL 0 +#define PORT_IN_UNICAST 1 +#define PORT_IN_MULTICAST 2 +#define PORT_IN_BROADCAST 3 +#define PORT_COUNT_IFG BIT(1) +#define PORT_COUNT_PREAMBLE BIT(0) + +#define REG_PORT_IN_RATE_0 0x0410 +#define REG_PORT_IN_RATE_1 0x0411 +#define REG_PORT_IN_RATE_2 0x0412 +#define REG_PORT_IN_RATE_3 0x0413 +#define REG_PORT_IN_RATE_4 0x0414 +#define REG_PORT_IN_RATE_5 0x0415 +#define REG_PORT_IN_RATE_6 0x0416 +#define REG_PORT_IN_RATE_7 0x0417 + +#define REG_PORT_OUT_RATE_0 0x0420 +#define REG_PORT_OUT_RATE_1 0x0421 +#define REG_PORT_OUT_RATE_2 0x0422 +#define REG_PORT_OUT_RATE_3 0x0423 + +#define PORT_RATE_LIMIT_M (BIT(7) - 1) + +/* 5 - MIB Counters */ +#define REG_PORT_MIB_CTRL_STAT__4 0x0500 + +#define MIB_COUNTER_OVERFLOW BIT(31) +#define MIB_COUNTER_VALID BIT(30) +#define MIB_COUNTER_READ BIT(25) +#define MIB_COUNTER_FLUSH_FREEZE BIT(24) +#define MIB_COUNTER_INDEX_M (BIT(8) - 1) +#define MIB_COUNTER_INDEX_S 16 +#define MIB_COUNTER_DATA_HI_M 0xF + +#define REG_PORT_MIB_DATA 0x0504 + +/* 6 - ACL */ +#define REG_PORT_ACL_0 0x0600 + +#define ACL_FIRST_RULE_M 0xF + +#define REG_PORT_ACL_1 0x0601 + +#define ACL_MODE_M 0x3 +#define ACL_MODE_S 4 +#define ACL_MODE_DISABLE 0 +#define ACL_MODE_LAYER_2 1 +#define ACL_MODE_LAYER_3 2 +#define ACL_MODE_LAYER_4 3 +#define ACL_ENABLE_M 0x3 +#define ACL_ENABLE_S 2 +#define ACL_ENABLE_2_COUNT 0 +#define ACL_ENABLE_2_TYPE 1 +#define ACL_ENABLE_2_MAC 2 +#define ACL_ENABLE_2_BOTH 3 +#define ACL_ENABLE_3_IP 1 +#define ACL_ENABLE_3_SRC_DST_COMP 2 +#define ACL_ENABLE_4_PROTOCOL 0 +#define ACL_ENABLE_4_TCP_PORT_COMP 1 +#define ACL_ENABLE_4_UDP_PORT_COMP 2 +#define ACL_ENABLE_4_TCP_SEQN_COMP 3 +#define ACL_SRC BIT(1) +#define ACL_EQUAL BIT(0) + +#define REG_PORT_ACL_2 0x0602 +#define REG_PORT_ACL_3 0x0603 + +#define ACL_MAX_PORT 0xFFFF + +#define REG_PORT_ACL_4 0x0604 +#define REG_PORT_ACL_5 0x0605 + +#define ACL_MIN_PORT 0xFFFF +#define ACL_IP_ADDR 0xFFFFFFFF +#define ACL_TCP_SEQNUM 0xFFFFFFFF + +#define REG_PORT_ACL_6 0x0606 + +#define ACL_RESERVED 0xF8 +#define ACL_PORT_MODE_M 0x3 +#define ACL_PORT_MODE_S 1 +#define ACL_PORT_MODE_DISABLE 0 +#define ACL_PORT_MODE_EITHER 1 +#define ACL_PORT_MODE_IN_RANGE 2 +#define ACL_PORT_MODE_OUT_OF_RANGE 3 + +#define REG_PORT_ACL_7 0x0607 + +#define ACL_TCP_FLAG_ENABLE BIT(0) + +#define REG_PORT_ACL_8 0x0608 + +#define ACL_TCP_FLAG_M 0xFF + +#define REG_PORT_ACL_9 0x0609 + +#define ACL_TCP_FLAG 0xFF +#define ACL_ETH_TYPE 0xFFFF +#define ACL_IP_M 0xFFFFFFFF + +#define REG_PORT_ACL_A 0x060A + +#define ACL_PRIO_MODE_M 0x3 +#define ACL_PRIO_MODE_S 6 +#define ACL_PRIO_MODE_DISABLE 0 +#define ACL_PRIO_MODE_HIGHER 1 +#define ACL_PRIO_MODE_LOWER 2 +#define ACL_PRIO_MODE_REPLACE 3 +#define ACL_PRIO_M KS_PRIO_M +#define ACL_PRIO_S 3 +#define ACL_VLAN_PRIO_REPLACE BIT(2) +#define ACL_VLAN_PRIO_M KS_PRIO_M +#define ACL_VLAN_PRIO_HI_M 0x3 + +#define REG_PORT_ACL_B 0x060B + +#define ACL_VLAN_PRIO_LO_M 0x8 +#define ACL_VLAN_PRIO_S 7 +#define ACL_MAP_MODE_M 0x3 +#define ACL_MAP_MODE_S 5 +#define ACL_MAP_MODE_DISABLE 0 +#define ACL_MAP_MODE_OR 1 +#define ACL_MAP_MODE_AND 2 +#define ACL_MAP_MODE_REPLACE 3 + +#define ACL_CNT_M (BIT(11) - 1) +#define ACL_CNT_S 5 + +#define REG_PORT_ACL_C 0x060C + +#define REG_PORT_ACL_D 0x060D +#define ACL_MSEC_UNIT BIT(6) +#define ACL_INTR_MODE BIT(5) +#define ACL_PORT_MAP 0x7F + +#define REG_PORT_ACL_E 0x060E +#define REG_PORT_ACL_F 0x060F + +#define REG_PORT_ACL_BYTE_EN_MSB 0x0610 +#define REG_PORT_ACL_BYTE_EN_LSB 0x0611 + +#define ACL_ACTION_START 0xA +#define ACL_ACTION_LEN 4 +#define ACL_INTR_CNT_START 0xD +#define ACL_RULESET_START 0xE +#define ACL_RULESET_LEN 2 +#define ACL_TABLE_LEN 16 + +#define ACL_ACTION_ENABLE 0x003C +#define ACL_MATCH_ENABLE 0x7FC3 +#define ACL_RULESET_ENABLE 0x8003 +#define ACL_BYTE_ENABLE 0xFFFF + +#define REG_PORT_ACL_CTRL_0 0x0612 + +#define PORT_ACL_WRITE_DONE BIT(6) +#define PORT_ACL_READ_DONE BIT(5) +#define PORT_ACL_WRITE BIT(4) +#define PORT_ACL_INDEX_M 0xF + +#define REG_PORT_ACL_CTRL_1 0x0613 + +/* 8 - Classification and Policing */ +#define REG_PORT_MRI_MIRROR_CTRL 0x0800 + +#define PORT_MIRROR_RX BIT(6) +#define PORT_MIRROR_TX BIT(5) +#define PORT_MIRROR_SNIFFER BIT(1) + +#define REG_PORT_MRI_PRIO_CTRL 0x0801 + +#define PORT_HIGHEST_PRIO BIT(7) +#define PORT_OR_PRIO BIT(6) +#define PORT_MAC_PRIO_ENABLE BIT(4) +#define PORT_VLAN_PRIO_ENABLE BIT(3) +#define PORT_802_1P_PRIO_ENABLE BIT(2) +#define PORT_DIFFSERV_PRIO_ENABLE BIT(1) +#define PORT_ACL_PRIO_ENABLE BIT(0) + +#define REG_PORT_MRI_MAC_CTRL 0x0802 + +#define PORT_USER_PRIO_CEILING BIT(7) +#define PORT_DROP_NON_VLAN BIT(4) +#define PORT_DROP_TAG BIT(3) +#define PORT_BASED_PRIO_M KS_PRIO_M +#define PORT_BASED_PRIO_S 0 + +#define REG_PORT_MRI_AUTHEN_CTRL 0x0803 + +#define PORT_ACL_ENABLE BIT(2) +#define PORT_AUTHEN_MODE 0x3 +#define PORT_AUTHEN_PASS 0 +#define PORT_AUTHEN_BLOCK 1 +#define PORT_AUTHEN_TRAP 2 + +#define REG_PORT_MRI_INDEX__4 0x0804 + +#define MRI_INDEX_P_M 0x7 +#define MRI_INDEX_P_S 16 +#define MRI_INDEX_Q_M 0x3 +#define MRI_INDEX_Q_S 0 + +#define REG_PORT_MRI_TC_MAP__4 0x0808 + +#define PORT_TC_MAP_M 0xf +#define PORT_TC_MAP_S 4 + +#define REG_PORT_MRI_POLICE_CTRL__4 0x080C + +#define POLICE_DROP_ALL BIT(10) +#define POLICE_PACKET_TYPE_M 0x3 +#define POLICE_PACKET_TYPE_S 8 +#define POLICE_PACKET_DROPPED 0 +#define POLICE_PACKET_GREEN 1 +#define POLICE_PACKET_YELLOW 2 +#define POLICE_PACKET_RED 3 +#define PORT_BASED_POLICING BIT(7) +#define NON_DSCP_COLOR_M 0x3 +#define NON_DSCP_COLOR_S 5 +#define COLOR_MARK_ENABLE BIT(4) +#define COLOR_REMAP_ENABLE BIT(3) +#define POLICE_DROP_SRP BIT(2) +#define POLICE_COLOR_NOT_AWARE BIT(1) +#define POLICE_ENABLE BIT(0) + +#define REG_PORT_POLICE_COLOR_0__4 0x0810 +#define REG_PORT_POLICE_COLOR_1__4 0x0814 +#define REG_PORT_POLICE_COLOR_2__4 0x0818 +#define REG_PORT_POLICE_COLOR_3__4 0x081C + +#define POLICE_COLOR_MAP_S 2 +#define POLICE_COLOR_MAP_M (BIT(POLICE_COLOR_MAP_S) - 1) + +#define REG_PORT_POLICE_RATE__4 0x0820 + +#define POLICE_CIR_S 16 +#define POLICE_PIR_S 0 + +#define REG_PORT_POLICE_BURST_SIZE__4 0x0824 + +#define POLICE_BURST_SIZE_M 0x3FFF +#define POLICE_CBS_S 16 +#define POLICE_PBS_S 0 + +#define REG_PORT_WRED_PM_CTRL_0__4 0x0830 + +#define WRED_PM_CTRL_M (BIT(11) - 1) + +#define WRED_PM_MAX_THRESHOLD_S 16 +#define WRED_PM_MIN_THRESHOLD_S 0 + +#define REG_PORT_WRED_PM_CTRL_1__4 0x0834 + +#define WRED_PM_MULTIPLIER_S 16 +#define WRED_PM_AVG_QUEUE_SIZE_S 0 + +#define REG_PORT_WRED_QUEUE_CTRL_0__4 0x0840 +#define REG_PORT_WRED_QUEUE_CTRL_1__4 0x0844 + +#define REG_PORT_WRED_QUEUE_PMON__4 0x0848 + +#define WRED_RANDOM_DROP_ENABLE BIT(31) +#define WRED_PMON_FLUSH BIT(30) +#define WRED_DROP_GYR_DISABLE BIT(29) +#define WRED_DROP_YR_DISABLE BIT(28) +#define WRED_DROP_R_DISABLE BIT(27) +#define WRED_DROP_ALL BIT(26) +#define WRED_PMON_M (BIT(24) - 1) + +/* 9 - Shaping */ + +#define REG_PORT_MTI_QUEUE_INDEX__4 0x0900 + +#define REG_PORT_MTI_QUEUE_CTRL_0__4 0x0904 + +#define MTI_PVID_REPLACE BIT(0) + +#define REG_PORT_MTI_QUEUE_CTRL_0 0x0914 + +#define MTI_SCHEDULE_MODE_M 0x3 +#define MTI_SCHEDULE_MODE_S 6 +#define MTI_SCHEDULE_STRICT_PRIO 0 +#define MTI_SCHEDULE_WRR 2 +#define MTI_SHAPING_M 0x3 +#define MTI_SHAPING_S 4 +#define MTI_SHAPING_OFF 0 +#define MTI_SHAPING_SRP 1 +#define MTI_SHAPING_TIME_AWARE 2 + +#define REG_PORT_MTI_QUEUE_CTRL_1 0x0915 + +#define MTI_TX_RATIO_M (BIT(7) - 1) + +#define REG_PORT_MTI_QUEUE_CTRL_2__2 0x0916 +#define REG_PORT_MTI_HI_WATER_MARK 0x0916 +#define REG_PORT_MTI_QUEUE_CTRL_3__2 0x0918 +#define REG_PORT_MTI_LO_WATER_MARK 0x0918 +#define REG_PORT_MTI_QUEUE_CTRL_4__2 0x091A +#define REG_PORT_MTI_CREDIT_INCREMENT 0x091A + +/* A - QM */ + +#define REG_PORT_QM_CTRL__4 0x0A00 + +#define PORT_QM_DROP_PRIO_M 0x3 + +#define REG_PORT_VLAN_MEMBERSHIP__4 0x0A04 + +#define REG_PORT_QM_QUEUE_INDEX__4 0x0A08 + +#define PORT_QM_QUEUE_INDEX_S 24 +#define PORT_QM_BURST_SIZE_S 16 +#define PORT_QM_MIN_RESV_SPACE_M (BIT(11) - 1) + +#define REG_PORT_QM_WATER_MARK__4 0x0A0C + +#define PORT_QM_HI_WATER_MARK_S 16 +#define PORT_QM_LO_WATER_MARK_S 0 +#define PORT_QM_WATER_MARK_M (BIT(11) - 1) + +#define REG_PORT_QM_TX_CNT_0__4 0x0A10 + +#define PORT_QM_TX_CNT_USED_S 0 +#define PORT_QM_TX_CNT_M (BIT(11) - 1) + +#define REG_PORT_QM_TX_CNT_1__4 0x0A14 + +#define PORT_QM_TX_CNT_CALCULATED_S 16 +#define PORT_QM_TX_CNT_AVAIL_S 0 + +/* B - LUE */ +#define REG_PORT_LUE_CTRL 0x0B00 + +#define PORT_VLAN_LOOKUP_VID_0 BIT(7) +#define PORT_INGRESS_FILTER BIT(6) +#define PORT_DISCARD_NON_VID BIT(5) +#define PORT_MAC_BASED_802_1X BIT(4) +#define PORT_SRC_ADDR_FILTER BIT(3) + +#define REG_PORT_LUE_MSTP_INDEX 0x0B01 + +#define REG_PORT_LUE_MSTP_STATE 0x0B04 + +#define PORT_TX_ENABLE BIT(2) +#define PORT_RX_ENABLE BIT(1) +#define PORT_LEARN_DISABLE BIT(0) + +/* C - PTP */ + +#define REG_PTP_PORT_RX_DELAY__2 0x0C00 +#define REG_PTP_PORT_TX_DELAY__2 0x0C02 +#define REG_PTP_PORT_ASYM_DELAY__2 0x0C04 + +#define REG_PTP_PORT_XDELAY_TS 0x0C08 +#define REG_PTP_PORT_XDELAY_TS_H 0x0C08 +#define REG_PTP_PORT_XDELAY_TS_L 0x0C0A + +#define REG_PTP_PORT_SYNC_TS 0x0C0C +#define REG_PTP_PORT_SYNC_TS_H 0x0C0C +#define REG_PTP_PORT_SYNC_TS_L 0x0C0E + +#define REG_PTP_PORT_PDRESP_TS 0x0C10 +#define REG_PTP_PORT_PDRESP_TS_H 0x0C10 +#define REG_PTP_PORT_PDRESP_TS_L 0x0C12 + +#define REG_PTP_PORT_TX_INT_STATUS__2 0x0C14 +#define REG_PTP_PORT_TX_INT_ENABLE__2 0x0C16 + +#define PTP_PORT_SYNC_INT BIT(15) +#define PTP_PORT_XDELAY_REQ_INT BIT(14) +#define PTP_PORT_PDELAY_RESP_INT BIT(13) + +#define REG_PTP_PORT_LINK_DELAY__4 0x0C18 + +#define PRIO_QUEUES 4 +#define RX_PRIO_QUEUES 8 + +#define KS_PRIO_IN_REG 2 + +#define TOTAL_PORT_NUM 7 + +#define KSZ9477_COUNTER_NUM 0x20 +#define TOTAL_KSZ9477_COUNTER_NUM (KSZ9477_COUNTER_NUM + 2 + 2) + +#define SWITCH_COUNTER_NUM KSZ9477_COUNTER_NUM +#define TOTAL_SWITCH_COUNTER_NUM TOTAL_KSZ9477_COUNTER_NUM + +#define P_BCAST_STORM_CTRL REG_PORT_MAC_CTRL_0 +#define P_PRIO_CTRL REG_PORT_MRI_PRIO_CTRL +#define P_MIRROR_CTRL REG_PORT_MRI_MIRROR_CTRL +#define P_STP_CTRL REG_PORT_LUE_MSTP_STATE +#define P_PHY_CTRL REG_PORT_PHY_CTRL +#define P_NEG_RESTART_CTRL REG_PORT_PHY_CTRL +#define P_LINK_STATUS REG_PORT_PHY_STATUS +#define P_SPEED_STATUS REG_PORT_PHY_PHY_CTRL +#define P_RATE_LIMIT_CTRL REG_PORT_MAC_IN_RATE_LIMIT + +#define S_LINK_AGING_CTRL REG_SW_LUE_CTRL_1 +#define S_MIRROR_CTRL REG_SW_MRI_CTRL_0 +#define S_REPLACE_VID_CTRL REG_SW_MAC_CTRL_2 +#define S_802_1P_PRIO_CTRL REG_SW_MAC_802_1P_MAP_0 +#define S_TOS_PRIO_CTRL REG_SW_MAC_TOS_PRIO_0 +#define S_FLUSH_TABLE_CTRL REG_SW_LUE_CTRL_1 + +#define SW_FLUSH_DYN_MAC_TABLE SW_FLUSH_MSTP_TABLE + +#define MAX_TIMESTAMP_UNIT 2 +#define MAX_TRIG_UNIT 3 +#define MAX_TIMESTAMP_EVENT_UNIT 8 +#define MAX_GPIO 4 + +#define PTP_TRIG_UNIT_M (BIT(MAX_TRIG_UNIT) - 1) +#define PTP_TS_UNIT_M (BIT(MAX_TIMESTAMP_UNIT) - 1) + +/* Driver set switch broadcast storm protection at 10% rate. */ +#define BROADCAST_STORM_PROT_RATE 10 + +/* 148,800 frames * 67 ms / 100 */ +#define BROADCAST_STORM_VALUE 9969 + +#endif /* KSZ9477_REGS_H */ diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c new file mode 100644 index 000000000000..b313ecdf2919 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -0,0 +1,1279 @@ +/* + * Microchip switch driver main logic + * + * Copyright (C) 2017 + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ksz_priv.h" + +static const struct { + int index; + char string[ETH_GSTRING_LEN]; +} mib_names[TOTAL_SWITCH_COUNTER_NUM] = { + { 0x00, "rx_hi" }, + { 0x01, "rx_undersize" }, + { 0x02, "rx_fragments" }, + { 0x03, "rx_oversize" }, + { 0x04, "rx_jabbers" }, + { 0x05, "rx_symbol_err" }, + { 0x06, "rx_crc_err" }, + { 0x07, "rx_align_err" }, + { 0x08, "rx_mac_ctrl" }, + { 0x09, "rx_pause" }, + { 0x0A, "rx_bcast" }, + { 0x0B, "rx_mcast" }, + { 0x0C, "rx_ucast" }, + { 0x0D, "rx_64_or_less" }, + { 0x0E, "rx_65_127" }, + { 0x0F, "rx_128_255" }, + { 0x10, "rx_256_511" }, + { 0x11, "rx_512_1023" }, + { 0x12, "rx_1024_1522" }, + { 0x13, "rx_1523_2000" }, + { 0x14, "rx_2001" }, + { 0x15, "tx_hi" }, + { 0x16, "tx_late_col" }, + { 0x17, "tx_pause" }, + { 0x18, "tx_bcast" }, + { 0x19, "tx_mcast" }, + { 0x1A, "tx_ucast" }, + { 0x1B, "tx_deferred" }, + { 0x1C, "tx_total_col" }, + { 0x1D, "tx_exc_col" }, + { 0x1E, "tx_single_col" }, + { 0x1F, "tx_mult_col" }, + { 0x80, "rx_total" }, + { 0x81, "tx_total" }, + { 0x82, "rx_discards" }, + { 0x83, "tx_discards" }, +}; + +static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) +{ + u8 data; + + ksz_read8(dev, addr, &data); + if (set) + data |= bits; + else + data &= ~bits; + ksz_write8(dev, addr, data); +} + +static void ksz_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) +{ + u32 data; + + ksz_read32(dev, addr, &data); + if (set) + data |= bits; + else + data &= ~bits; + ksz_write32(dev, addr, data); +} + +static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, + bool set) +{ + u32 addr; + u8 data; + + addr = PORT_CTRL_ADDR(port, offset); + ksz_read8(dev, addr, &data); + + if (set) + data |= bits; + else + data &= ~bits; + + ksz_write8(dev, addr, data); +} + +static void ksz_port_cfg32(struct ksz_device *dev, int port, int offset, + u32 bits, bool set) +{ + u32 addr; + u32 data; + + addr = PORT_CTRL_ADDR(port, offset); + ksz_read32(dev, addr, &data); + + if (set) + data |= bits; + else + data &= ~bits; + + ksz_write32(dev, addr, data); +} + +static int wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton, int timeout) +{ + u8 data; + + do { + ksz_read8(dev, REG_SW_VLAN_CTRL, &data); + if (!(data & waiton)) + break; + usleep_range(1, 10); + } while (timeout-- > 0); + + if (timeout <= 0) + return -ETIMEDOUT; + + return 0; +} + +static int get_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table) +{ + struct ksz_device *dev = ds->priv; + int ret; + + mutex_lock(&dev->vlan_mutex); + + ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START); + + /* wait to be cleared */ + ret = wait_vlan_ctrl_ready(dev, VLAN_START, 1000); + if (ret < 0) { + dev_dbg(dev->dev, "Failed to read vlan table\n"); + goto exit; + } + + ksz_read32(dev, REG_SW_VLAN_ENTRY__4, &vlan_table[0]); + ksz_read32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, &vlan_table[1]); + ksz_read32(dev, REG_SW_VLAN_ENTRY_PORTS__4, &vlan_table[2]); + + ksz_write8(dev, REG_SW_VLAN_CTRL, 0); + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + +static int set_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table) +{ + struct ksz_device *dev = ds->priv; + int ret; + + mutex_lock(&dev->vlan_mutex); + + ksz_write32(dev, REG_SW_VLAN_ENTRY__4, vlan_table[0]); + ksz_write32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, vlan_table[1]); + ksz_write32(dev, REG_SW_VLAN_ENTRY_PORTS__4, vlan_table[2]); + + ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); + ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE); + + /* wait to be cleared */ + ret = wait_vlan_ctrl_ready(dev, VLAN_START, 1000); + if (ret < 0) { + dev_dbg(dev->dev, "Failed to write vlan table\n"); + goto exit; + } + + ksz_write8(dev, REG_SW_VLAN_CTRL, 0); + + /* update vlan cache table */ + dev->vlan_cache[vid].table[0] = vlan_table[0]; + dev->vlan_cache[vid].table[1] = vlan_table[1]; + dev->vlan_cache[vid].table[2] = vlan_table[2]; + +exit: + mutex_unlock(&dev->vlan_mutex); + + return ret; +} + +static void read_table(struct dsa_switch *ds, u32 *table) +{ + struct ksz_device *dev = ds->priv; + + ksz_read32(dev, REG_SW_ALU_VAL_A, &table[0]); + ksz_read32(dev, REG_SW_ALU_VAL_B, &table[1]); + ksz_read32(dev, REG_SW_ALU_VAL_C, &table[2]); + ksz_read32(dev, REG_SW_ALU_VAL_D, &table[3]); +} + +static void write_table(struct dsa_switch *ds, u32 *table) +{ + struct ksz_device *dev = ds->priv; + + ksz_write32(dev, REG_SW_ALU_VAL_A, table[0]); + ksz_write32(dev, REG_SW_ALU_VAL_B, table[1]); + ksz_write32(dev, REG_SW_ALU_VAL_C, table[2]); + ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]); +} + +static int wait_alu_ready(struct ksz_device *dev, u32 waiton, int timeout) +{ + u32 data; + + do { + ksz_read32(dev, REG_SW_ALU_CTRL__4, &data); + if (!(data & waiton)) + break; + usleep_range(1, 10); + } while (timeout-- > 0); + + if (timeout <= 0) + return -ETIMEDOUT; + + return 0; +} + +static int wait_alu_sta_ready(struct ksz_device *dev, u32 waiton, int timeout) +{ + u32 data; + + do { + ksz_read32(dev, REG_SW_ALU_STAT_CTRL__4, &data); + if (!(data & waiton)) + break; + usleep_range(1, 10); + } while (timeout-- > 0); + + if (timeout <= 0) + return -ETIMEDOUT; + + return 0; +} + +static int ksz_reset_switch(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + u8 data8; + u16 data16; + u32 data32; + + /* reset switch */ + ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true); + + /* turn off SPI DO Edge select */ + ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8); + data8 &= ~SPI_AUTO_EDGE_DETECTION; + ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8); + + /* default configuration */ + ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); + data8 = SW_AGING_ENABLE | SW_LINK_AUTO_AGING | + SW_SRC_ADDR_FILTER | SW_FLUSH_STP_TABLE | SW_FLUSH_MSTP_TABLE; + ksz_write8(dev, REG_SW_LUE_CTRL_1, data8); + + /* disable interrupts */ + ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK); + ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F); + ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); + + /* set broadcast storm protection 10% rate */ + ksz_read16(dev, REG_SW_MAC_CTRL_2, &data16); + data16 &= ~BROADCAST_STORM_RATE; + data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100; + ksz_write16(dev, REG_SW_MAC_CTRL_2, data16); + + return 0; +} + +static void port_setup(struct ksz_device *dev, int port, bool cpu_port) +{ + u8 data8; + u16 data16; + + /* enable tag tail for host port */ + if (cpu_port) + ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_TAIL_TAG_ENABLE, + true); + + ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false); + + /* set back pressure */ + ksz_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, true); + + /* set flow control */ + ksz_port_cfg(dev, port, REG_PORT_CTRL_0, + PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, true); + + /* enable broadcast storm limit */ + ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); + + /* disable DiffServ priority */ + ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_PRIO_ENABLE, false); + + /* replace priority */ + ksz_port_cfg(dev, port, REG_PORT_MRI_MAC_CTRL, PORT_USER_PRIO_CEILING, + false); + ksz_port_cfg32(dev, port, REG_PORT_MTI_QUEUE_CTRL_0__4, + MTI_PVID_REPLACE, false); + + /* enable 802.1p priority */ + ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); + + /* configure MAC to 1G & RGMII mode */ + ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); + data8 |= PORT_RGMII_ID_EG_ENABLE; + data8 &= ~PORT_MII_NOT_1GBIT; + data8 &= ~PORT_MII_SEL_M; + data8 |= PORT_RGMII_SEL; + ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8); + + /* clear pending interrupts */ + ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16); +} + +static void ksz_config_cpu_port(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + int i; + + ds->num_ports = dev->port_cnt; + + for (i = 0; i < ds->num_ports; i++) { + if (dsa_is_cpu_port(ds, i) && (dev->cpu_ports & (1 << i))) { + dev->cpu_port = i; + + /* enable cpu port */ + port_setup(dev, i, true); + } + } +} + +static int ksz_setup(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + int ret = 0; + + dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), + dev->num_vlans, GFP_KERNEL); + if (!dev->vlan_cache) + return -ENOMEM; + + ret = ksz_reset_switch(ds); + if (ret) { + dev_err(ds->dev, "failed to reset switch\n"); + return ret; + } + + /* accept packet up to 2000bytes */ + ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_LEGAL_PACKET_DISABLE, true); + + ksz_config_cpu_port(ds); + + ksz_cfg(dev, REG_SW_MAC_CTRL_1, MULTICAST_STORM_DISABLE, true); + + /* queue based egress rate limit */ + ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true); + + /* start switch */ + ksz_cfg(dev, REG_SW_OPERATION, SW_START, true); + + return 0; +} + +static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds) +{ + return DSA_TAG_PROTO_KSZ; +} + +static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) +{ + struct ksz_device *dev = ds->priv; + u16 val = 0; + + ksz_pread16(dev, addr, 0x100 + (reg << 1), &val); + + return val; +} + +static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) +{ + struct ksz_device *dev = ds->priv; + + ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); + + return 0; +} + +static int ksz_enable_port(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct ksz_device *dev = ds->priv; + + /* setup slave port */ + port_setup(dev, port, false); + + return 0; +} + +static void ksz_disable_port(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct ksz_device *dev = ds->priv; + + /* there is no port disable */ + ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, true); +} + +static int ksz_sset_count(struct dsa_switch *ds) +{ + return TOTAL_SWITCH_COUNTER_NUM; +} + +static void ksz_get_strings(struct dsa_switch *ds, int port, uint8_t *buf) +{ + int i; + + for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) { + memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string, + ETH_GSTRING_LEN); + } +} + +static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, + uint64_t *buf) +{ + struct ksz_device *dev = ds->priv; + int i; + u32 data; + int timeout; + + mutex_lock(&dev->stats_mutex); + + for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) { + data = MIB_COUNTER_READ; + data |= ((mib_names[i].index & 0xFF) << MIB_COUNTER_INDEX_S); + ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data); + + timeout = 1000; + do { + ksz_pread32(dev, port, REG_PORT_MIB_CTRL_STAT__4, + &data); + usleep_range(1, 10); + if (!(data & MIB_COUNTER_READ)) + break; + } while (timeout-- > 0); + + /* failed to read MIB. get out of loop */ + if (!timeout) { + dev_dbg(dev->dev, "Failed to get MIB\n"); + break; + } + + /* count resets upon read */ + ksz_pread32(dev, port, REG_PORT_MIB_DATA, &data); + + dev->mib_value[i] += (uint64_t)data; + buf[i] = dev->mib_value[i]; + } + + mutex_unlock(&dev->stats_mutex); +} + +static void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +{ + struct ksz_device *dev = ds->priv; + u8 data; + + ksz_pread8(dev, port, P_STP_CTRL, &data); + data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE); + + switch (state) { + case BR_STATE_DISABLED: + data |= PORT_LEARN_DISABLE; + break; + case BR_STATE_LISTENING: + data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE); + break; + case BR_STATE_LEARNING: + data |= PORT_RX_ENABLE; + break; + case BR_STATE_FORWARDING: + data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); + break; + case BR_STATE_BLOCKING: + data |= PORT_LEARN_DISABLE; + break; + default: + dev_err(ds->dev, "invalid STP state: %d\n", state); + return; + } + + ksz_pwrite8(dev, port, P_STP_CTRL, data); +} + +static void ksz_port_fast_age(struct dsa_switch *ds, int port) +{ + struct ksz_device *dev = ds->priv; + u8 data8; + + ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); + data8 |= SW_FAST_AGING; + ksz_write8(dev, REG_SW_LUE_CTRL_1, data8); + + data8 &= ~SW_FAST_AGING; + ksz_write8(dev, REG_SW_LUE_CTRL_1, data8); +} + +static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag) +{ + struct ksz_device *dev = ds->priv; + + if (flag) { + ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, + PORT_VLAN_LOOKUP_VID_0, true); + ksz_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, true); + ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, true); + } else { + ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, false); + ksz_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, false); + ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, + PORT_VLAN_LOOKUP_VID_0, false); + } + + return 0; +} + +static int ksz_port_vlan_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) +{ + /* nothing needed */ + + return 0; +} + +static void ksz_port_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) +{ + struct ksz_device *dev = ds->priv; + u32 vlan_table[3]; + u16 vid; + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + if (get_vlan_table(ds, vid, vlan_table)) { + dev_dbg(dev->dev, "Failed to get vlan table\n"); + return; + } + + vlan_table[0] = VLAN_VALID | (vid & VLAN_FID_M); + if (untagged) + vlan_table[1] |= BIT(port); + else + vlan_table[1] &= ~BIT(port); + vlan_table[1] &= ~(BIT(dev->cpu_port)); + + vlan_table[2] |= BIT(port) | BIT(dev->cpu_port); + + if (set_vlan_table(ds, vid, vlan_table)) { + dev_dbg(dev->dev, "Failed to set vlan table\n"); + return; + } + + /* change PVID */ + if (vlan->flags & BRIDGE_VLAN_INFO_PVID) + ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vid); + } +} + +static int ksz_port_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + struct ksz_device *dev = ds->priv; + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + u32 vlan_table[3]; + u16 vid; + u16 pvid; + + ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &pvid); + pvid = pvid & 0xFFF; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + if (get_vlan_table(ds, vid, vlan_table)) { + dev_dbg(dev->dev, "Failed to get vlan table\n"); + return -ETIMEDOUT; + } + + vlan_table[2] &= ~BIT(port); + + if (pvid == vid) + pvid = 1; + + if (untagged) + vlan_table[1] &= ~BIT(port); + + if (set_vlan_table(ds, vid, vlan_table)) { + dev_dbg(dev->dev, "Failed to set vlan table\n"); + return -ETIMEDOUT; + } + } + + ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid); + + return 0; +} + +static int ksz_port_vlan_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_vlan *vlan, + switchdev_obj_dump_cb_t *cb) +{ + struct ksz_device *dev = ds->priv; + u16 vid; + u16 data; + struct vlan_table *vlan_cache; + int err = 0; + + mutex_lock(&dev->vlan_mutex); + + /* use dev->vlan_cache due to lack of searching valid vlan entry */ + for (vid = vlan->vid_begin; vid < dev->num_vlans; vid++) { + vlan_cache = &dev->vlan_cache[vid]; + + if (!(vlan_cache->table[0] & VLAN_VALID)) + continue; + + vlan->vid_begin = vid; + vlan->vid_end = vid; + vlan->flags = 0; + if (vlan_cache->table[2] & BIT(port)) { + if (vlan_cache->table[1] & BIT(port)) + vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; + ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &data); + if (vid == (data & 0xFFFFF)) + vlan->flags |= BRIDGE_VLAN_INFO_PVID; + + err = cb(&vlan->obj); + if (err) + break; + } + } + + mutex_unlock(&dev->vlan_mutex); + + return err; +} + +static int ksz_port_fdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) +{ + /* nothing needed */ + + return 0; +} + +struct alu_struct { + /* entry 1 */ + u8 is_static:1; + u8 is_src_filter:1; + u8 is_dst_filter:1; + u8 prio_age:3; + u32 _reserv_0_1:23; + u8 mstp:3; + /* entry 2 */ + u8 is_override:1; + u8 is_use_fid:1; + u32 _reserv_1_1:23; + u8 port_forward:7; + /* entry 3 & 4*/ + u32 _reserv_2_1:9; + u8 fid:7; + u8 mac[ETH_ALEN]; +}; + +static void ksz_port_fdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) +{ + struct ksz_device *dev = ds->priv; + u32 alu_table[4]; + u32 data; + + mutex_lock(&dev->alu_mutex); + + /* find any entry with mac & vid */ + data = fdb->vid << ALU_FID_INDEX_S; + data |= ((fdb->addr[0] << 8) | fdb->addr[1]); + ksz_write32(dev, REG_SW_ALU_INDEX_0, data); + + data = ((fdb->addr[2] << 24) | (fdb->addr[3] << 16)); + data |= ((fdb->addr[4] << 8) | fdb->addr[5]); + ksz_write32(dev, REG_SW_ALU_INDEX_1, data); + + /* start read operation */ + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); + + /* wait to be finished */ + if (wait_alu_ready(dev, ALU_START, 1000) < 0) { + dev_dbg(dev->dev, "Failed to read ALU\n"); + goto exit; + } + + /* read ALU entry */ + read_table(ds, alu_table); + + /* update ALU entry */ + alu_table[0] = ALU_V_STATIC_VALID; + alu_table[1] |= BIT(port); + if (fdb->vid) + alu_table[1] |= ALU_V_USE_FID; + alu_table[2] = (fdb->vid << ALU_V_FID_S); + alu_table[2] |= ((fdb->addr[0] << 8) | fdb->addr[1]); + alu_table[3] = ((fdb->addr[2] << 24) | (fdb->addr[3] << 16)); + alu_table[3] |= ((fdb->addr[4] << 8) | fdb->addr[5]); + + write_table(ds, alu_table); + + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); + + /* wait to be finished */ + if (wait_alu_ready(dev, ALU_START, 1000) < 0) + dev_dbg(dev->dev, "Failed to read ALU\n"); + +exit: + mutex_unlock(&dev->alu_mutex); +} + +static int ksz_port_fdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_fdb *fdb) +{ + struct ksz_device *dev = ds->priv; + u32 alu_table[4]; + u32 data; + int ret = 0; + + mutex_lock(&dev->alu_mutex); + + /* read any entry with mac & vid */ + data = fdb->vid << ALU_FID_INDEX_S; + data |= ((fdb->addr[0] << 8) | fdb->addr[1]); + ksz_write32(dev, REG_SW_ALU_INDEX_0, data); + + data = ((fdb->addr[2] << 24) | (fdb->addr[3] << 16)); + data |= ((fdb->addr[4] << 8) | fdb->addr[5]); + ksz_write32(dev, REG_SW_ALU_INDEX_1, data); + + /* start read operation */ + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); + + /* wait to be finished */ + ret = wait_alu_ready(dev, ALU_START, 1000); + if (ret < 0) { + dev_dbg(dev->dev, "Failed to read ALU\n"); + goto exit; + } + + ksz_read32(dev, REG_SW_ALU_VAL_A, &alu_table[0]); + if (alu_table[0] & ALU_V_STATIC_VALID) { + ksz_read32(dev, REG_SW_ALU_VAL_B, &alu_table[1]); + ksz_read32(dev, REG_SW_ALU_VAL_C, &alu_table[2]); + ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]); + + /* clear forwarding port */ + alu_table[2] &= ~BIT(port); + + /* if there is no port to forward, clear table */ + if ((alu_table[2] & ALU_V_PORT_MAP) == 0) { + alu_table[0] = 0; + alu_table[1] = 0; + alu_table[2] = 0; + alu_table[3] = 0; + } + } else { + alu_table[0] = 0; + alu_table[1] = 0; + alu_table[2] = 0; + alu_table[3] = 0; + } + + write_table(ds, alu_table); + + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); + + /* wait to be finished */ + ret = wait_alu_ready(dev, ALU_START, 1000); + if (ret < 0) + dev_dbg(dev->dev, "Failed to write ALU\n"); + +exit: + mutex_unlock(&dev->alu_mutex); + + return ret; +} + +static void convert_alu(struct alu_struct *alu, u32 *alu_table) +{ + alu->is_static = !!(alu_table[0] & ALU_V_STATIC_VALID); + alu->is_src_filter = !!(alu_table[0] & ALU_V_SRC_FILTER); + alu->is_dst_filter = !!(alu_table[0] & ALU_V_DST_FILTER); + alu->prio_age = (alu_table[0] >> ALU_V_PRIO_AGE_CNT_S) & + ALU_V_PRIO_AGE_CNT_M; + alu->mstp = alu_table[0] & ALU_V_MSTP_M; + + alu->is_override = !!(alu_table[1] & ALU_V_OVERRIDE); + alu->is_use_fid = !!(alu_table[1] & ALU_V_USE_FID); + alu->port_forward = alu_table[1] & ALU_V_PORT_MAP; + + alu->fid = (alu_table[2] >> ALU_V_FID_S) & ALU_V_FID_M; + + alu->mac[0] = (alu_table[2] >> 8) & 0xFF; + alu->mac[1] = alu_table[2] & 0xFF; + alu->mac[2] = (alu_table[3] >> 24) & 0xFF; + alu->mac[3] = (alu_table[3] >> 16) & 0xFF; + alu->mac[4] = (alu_table[3] >> 8) & 0xFF; + alu->mac[5] = alu_table[3] & 0xFF; +} + +static int ksz_port_fdb_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_fdb *fdb, + switchdev_obj_dump_cb_t *cb) +{ + struct ksz_device *dev = ds->priv; + int ret = 0; + u32 data; + u32 alu_table[4]; + struct alu_struct alu; + int timeout; + + mutex_lock(&dev->alu_mutex); + + /* start ALU search */ + ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_START | ALU_SEARCH); + + do { + timeout = 1000; + do { + ksz_read32(dev, REG_SW_ALU_CTRL__4, &data); + if ((data & ALU_VALID) || !(data & ALU_START)) + break; + usleep_range(1, 10); + } while (timeout-- > 0); + + if (!timeout) { + dev_dbg(dev->dev, "Failed to search ALU\n"); + ret = -ETIMEDOUT; + goto exit; + } + + /* read ALU table */ + read_table(ds, alu_table); + + convert_alu(&alu, alu_table); + + if (alu.port_forward & BIT(port)) { + fdb->vid = alu.fid; + if (alu.is_static) + fdb->ndm_state = NUD_NOARP; + else + fdb->ndm_state = NUD_REACHABLE; + ether_addr_copy(fdb->addr, alu.mac); + + ret = cb(&fdb->obj); + if (ret) + goto exit; + } + } while (data & ALU_START); + +exit: + + /* stop ALU search */ + ksz_write32(dev, REG_SW_ALU_CTRL__4, 0); + + mutex_unlock(&dev->alu_mutex); + + return ret; +} + +static int ksz_port_mdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans) +{ + /* nothing to do */ + return 0; +} + +static void ksz_port_mdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans) +{ + struct ksz_device *dev = ds->priv; + u32 static_table[4]; + u32 data; + int index; + u32 mac_hi, mac_lo; + + mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); + mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); + mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); + + mutex_lock(&dev->alu_mutex); + + for (index = 0; index < dev->num_statics; index++) { + /* find empty slot first */ + data = (index << ALU_STAT_INDEX_S) | + ALU_STAT_READ | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + if (wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0) { + dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); + goto exit; + } + + /* read ALU static table */ + read_table(ds, static_table); + + if (static_table[0] & ALU_V_STATIC_VALID) { + /* check this has same vid & mac address */ + if (((static_table[2] >> ALU_V_FID_S) == (mdb->vid)) && + ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && + (static_table[3] == mac_lo)) { + /* found matching one */ + break; + } + } else { + /* found empty one */ + break; + } + } + + /* no available entry */ + if (index == dev->num_statics) + goto exit; + + /* add entry */ + static_table[0] = ALU_V_STATIC_VALID; + static_table[1] |= BIT(port); + if (mdb->vid) + static_table[1] |= ALU_V_USE_FID; + static_table[2] = (mdb->vid << ALU_V_FID_S); + static_table[2] |= mac_hi; + static_table[3] = mac_lo; + + write_table(ds, static_table); + + data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + if (wait_alu_sta_ready(dev, ALU_STAT_START, 1000) < 0) + dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); + +exit: + mutex_unlock(&dev->alu_mutex); +} + +static int ksz_port_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct ksz_device *dev = ds->priv; + u32 static_table[4]; + u32 data; + int index; + int ret = 0; + u32 mac_hi, mac_lo; + + mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); + mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); + mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); + + mutex_lock(&dev->alu_mutex); + + for (index = 0; index < dev->num_statics; index++) { + /* find empty slot first */ + data = (index << ALU_STAT_INDEX_S) | + ALU_STAT_READ | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + ret = wait_alu_sta_ready(dev, ALU_STAT_START, 1000); + if (ret < 0) { + dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); + goto exit; + } + + /* read ALU static table */ + read_table(ds, static_table); + + if (static_table[0] & ALU_V_STATIC_VALID) { + /* check this has same vid & mac address */ + + if (((static_table[2] >> ALU_V_FID_S) == (mdb->vid)) && + ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && + (static_table[3] == mac_lo)) { + /* found matching one */ + break; + } + } + } + + /* no available entry */ + if (index == dev->num_statics) { + ret = -EINVAL; + goto exit; + } + + /* clear port */ + static_table[1] &= ~BIT(port); + + if ((static_table[1] & ALU_V_PORT_MAP) == 0) { + /* delete entry */ + static_table[0] = 0; + static_table[1] = 0; + static_table[2] = 0; + static_table[3] = 0; + } + + write_table(ds, static_table); + + data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; + ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); + + /* wait to be finished */ + ret = wait_alu_sta_ready(dev, ALU_STAT_START, 1000); + if (ret < 0) + dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); + +exit: + mutex_unlock(&dev->alu_mutex); + + return ret; +} + +static int ksz_port_mdb_dump(struct dsa_switch *ds, int port, + struct switchdev_obj_port_mdb *mdb, + switchdev_obj_dump_cb_t *cb) +{ + /* this is not called by switch layer */ + return 0; +} + +static int ksz_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress) +{ + struct ksz_device *dev = ds->priv; + + if (ingress) + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true); + else + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true); + + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false); + + /* configure mirror port */ + ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, true); + + ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); + + return 0; +} + +static void ksz_port_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + struct ksz_device *dev = ds->priv; + u8 data; + + if (mirror->ingress) + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false); + else + ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false); + + ksz_pread8(dev, port, P_MIRROR_CTRL, &data); + + if (!(data & (PORT_MIRROR_RX | PORT_MIRROR_TX))) + ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, + PORT_MIRROR_SNIFFER, false); +} + +static const struct dsa_switch_ops ksz_switch_ops = { + .get_tag_protocol = ksz_get_tag_protocol, + .setup = ksz_setup, + .phy_read = ksz_phy_read16, + .phy_write = ksz_phy_write16, + .port_enable = ksz_enable_port, + .port_disable = ksz_disable_port, + .get_strings = ksz_get_strings, + .get_ethtool_stats = ksz_get_ethtool_stats, + .get_sset_count = ksz_sset_count, + .port_stp_state_set = ksz_port_stp_state_set, + .port_fast_age = ksz_port_fast_age, + .port_vlan_filtering = ksz_port_vlan_filtering, + .port_vlan_prepare = ksz_port_vlan_prepare, + .port_vlan_add = ksz_port_vlan_add, + .port_vlan_del = ksz_port_vlan_del, + .port_vlan_dump = ksz_port_vlan_dump, + .port_fdb_prepare = ksz_port_fdb_prepare, + .port_fdb_dump = ksz_port_fdb_dump, + .port_fdb_add = ksz_port_fdb_add, + .port_fdb_del = ksz_port_fdb_del, + .port_mdb_prepare = ksz_port_mdb_prepare, + .port_mdb_add = ksz_port_mdb_add, + .port_mdb_del = ksz_port_mdb_del, + .port_mdb_dump = ksz_port_mdb_dump, + .port_mirror_add = ksz_port_mirror_add, + .port_mirror_del = ksz_port_mirror_del, +}; + +struct ksz_chip_data { + u32 chip_id; + const char *dev_name; + int num_vlans; + int num_alus; + int num_statics; + int cpu_ports; + int port_cnt; +}; + +static const struct ksz_chip_data ksz_switch_chips[] = { + { + .chip_id = 0x00947700, + .dev_name = "KSZ9477", + .num_vlans = 4096, + .num_alus = 4096, + .num_statics = 16, + .cpu_ports = 0x7F, /* can be configured as cpu port */ + .port_cnt = 7, /* total physical port count */ + }, +}; + +static int ksz_switch_init(struct ksz_device *dev) +{ + int i; + + mutex_init(&dev->reg_mutex); + mutex_init(&dev->stats_mutex); + mutex_init(&dev->alu_mutex); + mutex_init(&dev->vlan_mutex); + + dev->ds->ops = &ksz_switch_ops; + + for (i = 0; i < ARRAY_SIZE(ksz_switch_chips); i++) { + const struct ksz_chip_data *chip = &ksz_switch_chips[i]; + + if (dev->chip_id == chip->chip_id) { + dev->name = chip->dev_name; + dev->num_vlans = chip->num_vlans; + dev->num_alus = chip->num_alus; + dev->num_statics = chip->num_statics; + dev->port_cnt = chip->port_cnt; + dev->cpu_ports = chip->cpu_ports; + + break; + } + } + + /* no switch found */ + if (!dev->port_cnt) + return -ENODEV; + + return 0; +} + +struct ksz_device *ksz_switch_alloc(struct device *base, + const struct ksz_io_ops *ops, + void *priv) +{ + struct dsa_switch *ds; + struct ksz_device *swdev; + + ds = dsa_switch_alloc(base, DSA_MAX_PORTS); + if (!ds) + return NULL; + + swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL); + if (!swdev) + return NULL; + + ds->priv = swdev; + swdev->dev = base; + + swdev->ds = ds; + swdev->priv = priv; + swdev->ops = ops; + + return swdev; +} +EXPORT_SYMBOL(ksz_switch_alloc); + +int ksz_switch_detect(struct ksz_device *dev) +{ + u8 data8; + u32 id32; + int ret; + + /* turn off SPI DO Edge select */ + ret = ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8); + if (ret) + return ret; + + data8 &= ~SPI_AUTO_EDGE_DETECTION; + ret = ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8); + if (ret) + return ret; + + /* read chip id */ + ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32); + if (ret) + return ret; + + dev->chip_id = id32; + + return 0; +} +EXPORT_SYMBOL(ksz_switch_detect); + +int ksz_switch_register(struct ksz_device *dev) +{ + int ret; + + if (dev->pdata) + dev->chip_id = dev->pdata->chip_id; + + if (ksz_switch_detect(dev)) + return -EINVAL; + + ret = ksz_switch_init(dev); + if (ret) + return ret; + + return dsa_register_switch(dev->ds); +} +EXPORT_SYMBOL(ksz_switch_register); + +void ksz_switch_remove(struct ksz_device *dev) +{ + dsa_unregister_switch(dev->ds); +} +EXPORT_SYMBOL(ksz_switch_remove); + +MODULE_AUTHOR("Woojung Huh "); +MODULE_DESCRIPTION("Microchip KSZ Series Switch DSA Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h new file mode 100644 index 000000000000..2a98dbd51456 --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_priv.h @@ -0,0 +1,210 @@ +/* + * Microchip KSZ series switch common definitions + * + * Copyright (C) 2017 + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __KSZ_PRIV_H +#define __KSZ_PRIV_H + +#include +#include +#include +#include +#include + +#include "ksz_9477_reg.h" + +struct ksz_io_ops; + +struct vlan_table { + u32 table[3]; +}; + +struct ksz_device { + struct dsa_switch *ds; + struct ksz_platform_data *pdata; + const char *name; + + struct mutex reg_mutex; /* register access */ + struct mutex stats_mutex; /* status access */ + struct mutex alu_mutex; /* ALU access */ + struct mutex vlan_mutex; /* vlan access */ + const struct ksz_io_ops *ops; + + struct device *dev; + + void *priv; + + /* chip specific data */ + u32 chip_id; + int num_vlans; + int num_alus; + int num_statics; + int cpu_port; /* port connected to CPU */ + int cpu_ports; /* port bitmap can be cpu port */ + int port_cnt; + + struct vlan_table *vlan_cache; + + u64 mib_value[TOTAL_SWITCH_COUNTER_NUM]; +}; + +struct ksz_io_ops { + int (*read8)(struct ksz_device *dev, u32 reg, u8 *value); + int (*read16)(struct ksz_device *dev, u32 reg, u16 *value); + int (*read24)(struct ksz_device *dev, u32 reg, u32 *value); + int (*read32)(struct ksz_device *dev, u32 reg, u32 *value); + int (*write8)(struct ksz_device *dev, u32 reg, u8 value); + int (*write16)(struct ksz_device *dev, u32 reg, u16 value); + int (*write24)(struct ksz_device *dev, u32 reg, u32 value); + int (*write32)(struct ksz_device *dev, u32 reg, u32 value); + int (*phy_read16)(struct ksz_device *dev, int addr, int reg, + u16 *value); + int (*phy_write16)(struct ksz_device *dev, int addr, int reg, + u16 value); +}; + +struct ksz_device *ksz_switch_alloc(struct device *base, + const struct ksz_io_ops *ops, void *priv); +int ksz_switch_detect(struct ksz_device *dev); +int ksz_switch_register(struct ksz_device *dev); +void ksz_switch_remove(struct ksz_device *dev); + +static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read8(dev, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read16(dev, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_read24(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read24(dev, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read32(dev, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_write8(struct ksz_device *dev, u32 reg, u8 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write8(dev, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write16(dev, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_write24(struct ksz_device *dev, u32 reg, u32 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write24(dev, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write32(dev, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline void ksz_pread8(struct ksz_device *dev, int port, int offset, + u8 *data) +{ + ksz_read8(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pread16(struct ksz_device *dev, int port, int offset, + u16 *data) +{ + ksz_read16(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pread32(struct ksz_device *dev, int port, int offset, + u32 *data) +{ + ksz_read32(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pwrite8(struct ksz_device *dev, int port, int offset, + u8 data) +{ + ksz_write8(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pwrite16(struct ksz_device *dev, int port, int offset, + u16 data) +{ + ksz_write16(dev, PORT_CTRL_ADDR(port, offset), data); +} + +static inline void ksz_pwrite32(struct ksz_device *dev, int port, int offset, + u32 data) +{ + ksz_write32(dev, PORT_CTRL_ADDR(port, offset), data); +} + +#endif diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c new file mode 100644 index 000000000000..c51946983bed --- /dev/null +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -0,0 +1,216 @@ +/* + * Microchip KSZ series register access through SPI + * + * Copyright (C) 2017 + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include + +#include "ksz_priv.h" + +/* SPI frame opcodes */ +#define KS_SPIOP_RD 3 +#define KS_SPIOP_WR 2 + +#define SPI_ADDR_SHIFT 24 +#define SPI_ADDR_MASK (BIT(SPI_ADDR_SHIFT) - 1) +#define SPI_TURNAROUND_SHIFT 5 + +static int ksz_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val, + unsigned int len) +{ + u32 txbuf; + int ret; + + txbuf = reg & SPI_ADDR_MASK; + txbuf |= KS_SPIOP_RD << SPI_ADDR_SHIFT; + txbuf <<= SPI_TURNAROUND_SHIFT; + txbuf = cpu_to_be32(txbuf); + + ret = spi_write_then_read(spi, &txbuf, 4, val, len); + return ret; +} + +static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data, + unsigned int len) +{ + struct spi_device *spi = dev->priv; + + return ksz_spi_read_reg(spi, reg, data, len); +} + +static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val) +{ + return ksz_spi_read(dev, reg, val, 1); +} + +static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val) +{ + int ret = ksz_spi_read(dev, reg, (u8 *)val, 2); + + if (!ret) + *val = be16_to_cpu(*val); + + return ret; +} + +static int ksz_spi_read24(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret; + + *val = 0; + ret = ksz_spi_read(dev, reg, (u8 *)val, 3); + if (!ret) { + *val = be32_to_cpu(*val); + /* convert to 24bit */ + *val >>= 8; + } + + return ret; +} + +static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val) +{ + int ret = ksz_spi_read(dev, reg, (u8 *)val, 4); + + if (!ret) + *val = be32_to_cpu(*val); + + return ret; +} + +static int ksz_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val, + unsigned int len) +{ + u32 txbuf; + u8 data[12]; + int i; + + txbuf = reg & SPI_ADDR_MASK; + txbuf |= (KS_SPIOP_WR << SPI_ADDR_SHIFT); + txbuf <<= SPI_TURNAROUND_SHIFT; + txbuf = cpu_to_be32(txbuf); + + data[0] = txbuf & 0xFF; + data[1] = (txbuf & 0xFF00) >> 8; + data[2] = (txbuf & 0xFF0000) >> 16; + data[3] = (txbuf & 0xFF000000) >> 24; + for (i = 0; i < len; i++) + data[i + 4] = val[i]; + + return spi_write(spi, &data, 4 + len); +} + +static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value) +{ + struct spi_device *spi = dev->priv; + + return ksz_spi_write_reg(spi, reg, &value, 1); +} + +static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value) +{ + struct spi_device *spi = dev->priv; + + value = cpu_to_be16(value); + return ksz_spi_write_reg(spi, reg, (u8 *)&value, 2); +} + +static int ksz_spi_write24(struct ksz_device *dev, u32 reg, u32 value) +{ + struct spi_device *spi = dev->priv; + + /* make it to big endian 24bit from MSB */ + value <<= 8; + value = cpu_to_be32(value); + return ksz_spi_write_reg(spi, reg, (u8 *)&value, 3); +} + +static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value) +{ + struct spi_device *spi = dev->priv; + + value = cpu_to_be32(value); + return ksz_spi_write_reg(spi, reg, (u8 *)&value, 4); +} + +static const struct ksz_io_ops ksz_spi_ops = { + .read8 = ksz_spi_read8, + .read16 = ksz_spi_read16, + .read24 = ksz_spi_read24, + .read32 = ksz_spi_read32, + .write8 = ksz_spi_write8, + .write16 = ksz_spi_write16, + .write24 = ksz_spi_write24, + .write32 = ksz_spi_write32, +}; + +static int ksz_spi_probe(struct spi_device *spi) +{ + struct ksz_device *dev; + int ret; + + dev = ksz_switch_alloc(&spi->dev, &ksz_spi_ops, spi); + if (!dev) + return -ENOMEM; + + if (spi->dev.platform_data) + dev->pdata = spi->dev.platform_data; + + ret = ksz_switch_register(dev); + if (ret) + return ret; + + spi_set_drvdata(spi, dev); + + return 0; +} + +static int ksz_spi_remove(struct spi_device *spi) +{ + struct ksz_device *dev = spi_get_drvdata(spi); + + if (dev) + ksz_switch_remove(dev); + + return 0; +} + +static const struct of_device_id ksz_dt_ids[] = { + { .compatible = "microchip,ksz9477" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ksz_dt_ids); + +static struct spi_driver ksz_spi_driver = { + .driver = { + .name = "ksz9477-switch", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ksz_dt_ids), + }, + .probe = ksz_spi_probe, + .remove = ksz_spi_remove, +}; + +module_spi_driver(ksz_spi_driver); + +MODULE_AUTHOR("Woojung Huh "); +MODULE_DESCRIPTION("Microchip KSZ Series Switch SPI access Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4f8e25458cb6efc9e4497bb5cecb3a667d4963ab Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 25 May 2017 14:45:03 +0100 Subject: qtnfmac: remove duplicated assignment to mac mac is being assigned twice, remove redundant 2nd assignment. Detected by CoverityScan, CID#1437554 ("Incorrect expression") Signed-off-by: Colin Ian King Acked-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index fc0ce2c09097..e3c090008125 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -922,7 +922,7 @@ void qtnf_netdev_updown(struct net_device *ndev, bool up) void qtnf_virtual_intf_cleanup(struct net_device *ndev) { struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); - struct qtnf_wmac *mac = mac = wiphy_priv(vif->wdev.wiphy); + struct qtnf_wmac *mac = wiphy_priv(vif->wdev.wiphy); if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { switch (vif->sta_state) { -- cgit v1.2.3 From 01926202b34b252514350a60ab20ec63ad1c5fad Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 26 May 2017 09:41:49 +0800 Subject: mwifiex: simplify the code around ra_list We don't need to check if the list is empty separately as we could use list_first_entry_or_null to cover it. Signed-off-by: Shawn Lin Reviewed-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/tdls.c | 7 ++----- drivers/net/wireless/marvell/mwifiex/wmm.c | 8 ++------ 2 files changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index 7d0d3ff3dd4c..d76ce8797de1 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -55,11 +55,8 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv, tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; } else { tid_list = &priv->wmm.tid_tbl_ptr[tid_down].ra_list; - if (!list_empty(tid_list)) - ra_list = list_first_entry(tid_list, - struct mwifiex_ra_list_tbl, list); - else - ra_list = NULL; + ra_list = list_first_entry_or_null(tid_list, + struct mwifiex_ra_list_tbl, list); tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT; } diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index 75cdd55d1046..0edd26881321 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -868,12 +868,8 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, return; default: list_head = priv->wmm.tid_tbl_ptr[tid_down].ra_list; - if (!list_empty(&list_head)) - ra_list = list_first_entry( - &list_head, struct mwifiex_ra_list_tbl, - list); - else - ra_list = NULL; + ra_list = list_first_entry_or_null(&list_head, + struct mwifiex_ra_list_tbl, list); break; } } else { -- cgit v1.2.3 From 1f71719951420da588bc707939c64c72112b1f0e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Fri, 26 May 2017 06:57:13 +0000 Subject: mwifiex: uap: process remain on channel expired event AP interface need process remain-on-channel firmware event and notify cfg80211, this will be used in the listen-stage of p2p find procedure. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/uap_event.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/uap_event.c b/drivers/net/wireless/marvell/mwifiex/uap_event.c index e10b2a52e78f..e8c8728db15a 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_event.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_event.c @@ -312,6 +312,17 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) adapter->event_skb->len - sizeof(eventcause)); break; + + case EVENT_REMAIN_ON_CHAN_EXPIRED: + mwifiex_dbg(adapter, EVENT, + "event: uap: Remain on channel expired\n"); + cfg80211_remain_on_channel_expired(&priv->wdev, + priv->roc_cfg.cookie, + &priv->roc_cfg.chan, + GFP_ATOMIC); + memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg)); + break; + default: mwifiex_dbg(adapter, EVENT, "event: unknown event id: %#x\n", eventcause); -- cgit v1.2.3 From 219569ad0c41df7a7f999a2cad688c6b6ce173e2 Mon Sep 17 00:00:00 2001 From: amit karwar Date: Fri, 26 May 2017 20:31:31 +0530 Subject: rsi: use subdirectory for firmware file linux-firmware maintainers prefer to have a subdirectory for firmware files. Code is changed here to pick firmware file from a subdirectory. Firmware file with a new loading mechanism will be submitted inside rsi directory. Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index d49dbaa14079..3d24e8ed74df 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -22,7 +22,7 @@ /* FLASH Firmware */ static struct ta_metadata metadata_flash_content[] = { {"flash_content", 0x00010000}, - {"rs9113_wlan_qspi.rps", 0x00010000}, + {"rsi/rs9113_wlan_qspi.rps", 0x00010000}, }; /** -- cgit v1.2.3 From 13c3b26a71dfed57152ccfdb8fb5fb29584ded7c Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 31 May 2017 14:21:19 +0300 Subject: ath10k: increase BMI timeout When testing a 9888 chipset NIC, I notice it often takes almost 2 seconds, and then many times OTP fails, probably due to the two-second timeout. [ 2269.841842] ath10k_pci 0000:05:00.0: bmi cmd took: 1984 jiffies (HZ: 1000), rv: 0 [ 2273.608185] ath10k_pci 0000:05:00.0: bmi cmd took: 1986 jiffies (HZ: 1000), rv: 0 [ 2277.294732] ath10k_pci 0000:05:00.0: bmi cmd took: 1989 jiffies (HZ: 1000), rv: 0 So, increase the BMI timeout to 3 seconds. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 0342073ed397..ff97e0e73c4e 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -188,8 +188,8 @@ struct bmi_target_info { u32 type; }; -/* in msec */ -#define BMI_COMMUNICATION_TIMEOUT_HZ (2 * HZ) +/* in jiffies */ +#define BMI_COMMUNICATION_TIMEOUT_HZ (3 * HZ) #define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_HOST 1 -- cgit v1.2.3 From 6bb099b088c70f76b5f34672a83d4452b1e3af36 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 31 May 2017 14:21:21 +0300 Subject: ath10k: log when longer bmi cmds happen This lets one have a clue that maybe timeouts are happening when we just aren't waiting long enough. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1e9806f57ee4..4f3f513dac4f 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -101,7 +101,8 @@ static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); static int ath10k_pci_request_irq(struct ath10k *ar); static void ath10k_pci_free_irq(struct ath10k *ar); -static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, +static int ath10k_pci_bmi_wait(struct ath10k *ar, + struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer); static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar); @@ -1846,7 +1847,7 @@ int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, if (ret) goto err_resp; - ret = ath10k_pci_bmi_wait(ce_tx, ce_rx, &xfer); + ret = ath10k_pci_bmi_wait(ar, ce_tx, ce_rx, &xfer); if (ret) { u32 unused_buffer; unsigned int unused_nbytes; @@ -1913,23 +1914,37 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) xfer->rx_done = true; } -static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, +static int ath10k_pci_bmi_wait(struct ath10k *ar, + struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer) { unsigned long timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ; + unsigned long started = jiffies; + unsigned long dur; + int ret; while (time_before_eq(jiffies, timeout)) { ath10k_pci_bmi_send_done(tx_pipe); ath10k_pci_bmi_recv_data(rx_pipe); - if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp)) - return 0; + if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp)) { + ret = 0; + goto out; + } schedule(); } - return -ETIMEDOUT; + ret = -ETIMEDOUT; + +out: + dur = jiffies - started; + if (dur > HZ) + ath10k_dbg(ar, ATH10K_DBG_BMI, + "bmi cmd took %lu jiffies hz %d ret %d\n", + dur, HZ, ret); + return ret; } /* -- cgit v1.2.3 From 4f40b423339b8121fbd5d6735bf6942020355c98 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 31 May 2017 14:21:26 +0300 Subject: ath10k: initialize nbytes to 0 ath10k firmware checks nbytes == 0 as part of determining if DMA has completed successfully. To help make this work more often, have the driver initialize nbytes to zero when freeing the descriptor slot. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index ee1090ca2eac..51309563990f 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -594,6 +594,7 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, unsigned int nentries_mask = src_ring->nentries_mask; unsigned int sw_index = src_ring->sw_index; unsigned int read_index; + struct ce_desc *desc; if (src_ring->hw_index == sw_index) { /* @@ -623,6 +624,9 @@ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, /* sanity */ src_ring->per_transfer_context[sw_index] = NULL; + desc = CE_SRC_RING_TO_DESC(src_ring->base_addr_owner_space, + sw_index); + desc->nbytes = 0; /* Update sw_index */ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); -- cgit v1.2.3 From a9f5f287fa1d47d61dfa8b60f94831174b2ea4d0 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Wed, 31 May 2017 14:21:27 +0300 Subject: ath10k: add BMI parameters to fix calibration from DT/pre-cal QCA99X0, QCA9888, QCA9984 supports calibration data in either OTP or DT/pre-cal file. Current ath10k supports Calibration data from OTP only. If caldata is loaded from DT/pre-cal file, fetching board id and applying calibration parameters like tx power gets failed. error log: [ 15.733663] ath10k_pci 0000:01:00.0: failed to fetch board file: -2 [ 15.741474] ath10k_pci 0000:01:00.0: could not probe fw (-2) This patch adds calibration data support from DT/pre-cal file. Below parameters are used to get board id and applying calibration parameters from cal data. EEPROM[OTP] FLASH[DT/pre-cal file] Cal param 0x700 0x10000 Board id 0x10 0x8000 Tested on QCA9888 with pre-cal file. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.h | 2 ++ drivers/net/wireless/ath/ath10k/core.c | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index ff97e0e73c4e..9c0839b2ca8f 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -83,6 +83,8 @@ enum bmi_cmd_id { #define BMI_NVRAM_SEG_NAME_SZ 16 #define BMI_PARAM_GET_EEPROM_BOARD_ID 0x10 +#define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000 +#define BMI_PARAM_FLASH_SECTION_ALL 0x10000 #define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00 #define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10 diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index eea111d704c5..ce79a2e070bd 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -691,7 +691,7 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) { u32 result, address; u8 board_id, chip_id; - int ret; + int ret, bmi_board_id_param; address = ar->hw_params.patch_load_addr; @@ -715,8 +715,13 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) return ret; } - ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EEPROM_BOARD_ID, - &result); + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID; + else + bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID; + + ret = ath10k_bmi_execute(ar, address, bmi_board_id_param, &result); if (ret) { ath10k_err(ar, "could not execute otp for board id check: %d\n", ret); @@ -845,6 +850,11 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) return ret; } + /* As of now pre-cal is valid for 10_4 variants */ + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); if (ret) { ath10k_err(ar, "could not execute otp (%d)\n", ret); -- cgit v1.2.3 From 9a993cc1ea952b0018f393f7f58fa04f531543ed Mon Sep 17 00:00:00 2001 From: Ryan Hsu Date: Wed, 31 May 2017 14:21:28 +0300 Subject: ath10k: fix the logic of limiting tdls peer counts The original idea is to limit the maximum TDLS peer link, but the logic is always false, and never be able to restrict the number of TDLS peer creation. Fix the logic here and also move the checking earlier, so that it could avoid to handle the failure case, e.g disable the tdls peer, delete the peer and also vdev count cleanup. Signed-off-by: Ryan Hsu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 49 +++++++++++++++-------------------- 1 file changed, 21 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4674ff33d320..48418f91396c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6073,6 +6073,20 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ar->num_stations + 1, ar->max_num_stations, ar->num_peers + 1, ar->max_num_peers); + num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif); + num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw); + + if (sta->tdls) { + if (num_tdls_stations >= ar->max_num_tdls_vdevs) { + ath10k_warn(ar, "vdev %i exceeded maximum number of tdls vdevs %i\n", + arvif->vdev_id, + ar->max_num_tdls_vdevs); + ret = -ELNRNG; + goto exit; + } + peer_type = WMI_PEER_TYPE_TDLS; + } + ret = ath10k_mac_inc_num_stations(arvif, sta); if (ret) { ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n", @@ -6080,9 +6094,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, goto exit; } - if (sta->tdls) - peer_type = WMI_PEER_TYPE_TDLS; - ret = ath10k_peer_create(ar, vif, sta, arvif->vdev_id, sta->addr, peer_type); if (ret) { @@ -6113,35 +6124,17 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, if (!sta->tdls) goto exit; - num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif); - num_tdls_vifs = ath10k_mac_tdls_vifs_count(hw); - - if (num_tdls_vifs >= ar->max_num_tdls_vdevs && - num_tdls_stations == 0) { - ath10k_warn(ar, "vdev %i exceeded maximum number of tdls vdevs %i\n", - arvif->vdev_id, ar->max_num_tdls_vdevs); - ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); + ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, + WMI_TDLS_ENABLE_ACTIVE); + if (ret) { + ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n", + arvif->vdev_id, ret); + ath10k_peer_delete(ar, arvif->vdev_id, + sta->addr); ath10k_mac_dec_num_stations(arvif, sta); - ret = -ENOBUFS; goto exit; } - if (num_tdls_stations == 0) { - /* This is the first tdls peer in current vif */ - enum wmi_tdls_state state = WMI_TDLS_ENABLE_ACTIVE; - - ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, - state); - if (ret) { - ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n", - arvif->vdev_id, ret); - ath10k_peer_delete(ar, arvif->vdev_id, - sta->addr); - ath10k_mac_dec_num_stations(arvif, sta); - goto exit; - } - } - ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta, WMI_TDLS_PEER_STATE_PEERING); if (ret) { -- cgit v1.2.3 From 97fcc193f67e584dc6564767c6e186fe1ecd71d2 Mon Sep 17 00:00:00 2001 From: Gao Feng Date: Thu, 1 Jun 2017 17:58:39 +0800 Subject: ppp: remove unnecessary bh disable in xmit path Since the commit 55454a565836 ("ppp: avoid dealock on recursive xmit"), the PPP xmit path is protected by wrapper functions which disable the bh already. So it is unnecessary to disable the bh again in the real xmit path. Signed-off-by: Gao Feng Acked-by: Guillaume Nault Signed-off-by: David S. Miller --- drivers/net/ppp/ppp_generic.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index f9c0e62716ea..bbded33120fe 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1618,7 +1618,7 @@ ppp_push(struct ppp *ppp) list = list->next; pch = list_entry(list, struct channel, clist); - spin_lock_bh(&pch->downl); + spin_lock(&pch->downl); if (pch->chan) { if (pch->chan->ops->start_xmit(pch->chan, skb)) ppp->xmit_pending = NULL; @@ -1627,7 +1627,7 @@ ppp_push(struct ppp *ppp) kfree_skb(skb); ppp->xmit_pending = NULL; } - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); return; } @@ -1757,7 +1757,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) } /* check the channel's mtu and whether it is still attached. */ - spin_lock_bh(&pch->downl); + spin_lock(&pch->downl); if (pch->chan == NULL) { /* can't use this channel, it's being deregistered */ if (pch->speed == 0) @@ -1765,7 +1765,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) else totspeed -= pch->speed; - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); pch->avail = 0; totlen = len; totfree--; @@ -1816,7 +1816,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) */ if (flen <= 0) { pch->avail = 2; - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); continue; } @@ -1861,14 +1861,14 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) len -= flen; ++ppp->nxseq; bits = 0; - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); } ppp->nxchan = i; return 1; noskb: - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); if (ppp->debug & 1) netdev_err(ppp->dev, "PPP: no memory (fragment)\n"); ++ppp->dev->stats.tx_errors; @@ -1883,7 +1883,7 @@ static void __ppp_channel_push(struct channel *pch) struct sk_buff *skb; struct ppp *ppp; - spin_lock_bh(&pch->downl); + spin_lock(&pch->downl); if (pch->chan) { while (!skb_queue_empty(&pch->file.xq)) { skb = skb_dequeue(&pch->file.xq); @@ -1897,14 +1897,14 @@ static void __ppp_channel_push(struct channel *pch) /* channel got deregistered */ skb_queue_purge(&pch->file.xq); } - spin_unlock_bh(&pch->downl); + spin_unlock(&pch->downl); /* see if there is anything from the attached unit to be sent */ if (skb_queue_empty(&pch->file.xq)) { - read_lock_bh(&pch->upl); + read_lock(&pch->upl); ppp = pch->ppp; if (ppp) __ppp_xmit_process(ppp); - read_unlock_bh(&pch->upl); + read_unlock(&pch->upl); } } -- cgit v1.2.3 From 8befd73c23c929c038dd85027ed60eb1a6e4c1e9 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:01 +0300 Subject: qed: Make qed_int_cau_conf_pi() static Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_int.c | 68 +++++++++++++++---------------- drivers/net/ethernet/qlogic/qed/qed_int.h | 18 -------- 2 files changed, 34 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 6ac6d80311bb..9b655faf5720 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1300,6 +1300,40 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn, SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE1, cau_state); } +static void qed_int_cau_conf_pi(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 igu_sb_id, + u32 pi_index, + enum qed_coalescing_fsm coalescing_fsm, + u8 timeset) +{ + struct cau_pi_entry pi_entry; + u32 sb_offset, pi_offset; + + if (IS_VF(p_hwfn->cdev)) + return; + + sb_offset = igu_sb_id * PIS_PER_SB; + memset(&pi_entry, 0, sizeof(struct cau_pi_entry)); + + SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_PI_TIMESET, timeset); + if (coalescing_fsm == QED_COAL_RX_STATE_MACHINE) + SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 0); + else + SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 1); + + pi_offset = sb_offset + pi_index; + if (p_hwfn->hw_init_done) { + qed_wr(p_hwfn, p_ptt, + CAU_REG_PI_MEMORY + pi_offset * sizeof(u32), + *((u32 *)&(pi_entry))); + } else { + STORE_RT_REG(p_hwfn, + CAU_REG_PI_MEMORY_RT_OFFSET + pi_offset, + *((u32 *)&(pi_entry))); + } +} + void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, dma_addr_t sb_phys, @@ -1366,40 +1400,6 @@ void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn, } } -void qed_int_cau_conf_pi(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u16 igu_sb_id, - u32 pi_index, - enum qed_coalescing_fsm coalescing_fsm, - u8 timeset) -{ - struct cau_pi_entry pi_entry; - u32 sb_offset, pi_offset; - - if (IS_VF(p_hwfn->cdev)) - return; - - sb_offset = igu_sb_id * PIS_PER_SB; - memset(&pi_entry, 0, sizeof(struct cau_pi_entry)); - - SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_PI_TIMESET, timeset); - if (coalescing_fsm == QED_COAL_RX_STATE_MACHINE) - SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 0); - else - SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 1); - - pi_offset = sb_offset + pi_index; - if (p_hwfn->hw_init_done) { - qed_wr(p_hwfn, p_ptt, - CAU_REG_PI_MEMORY + pi_offset * sizeof(u32), - *((u32 *)&(pi_entry))); - } else { - STORE_RT_REG(p_hwfn, - CAU_REG_PI_MEMORY_RT_OFFSET + pi_offset, - *((u32 *)&(pi_entry))); - } -} - void qed_int_sb_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_sb_info *sb_info) { diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index 0ae0bb4593ef..a8e48e14efef 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -78,24 +78,6 @@ enum qed_coalescing_fsm { QED_COAL_TX_STATE_MACHINE }; -/** - * @brief qed_int_cau_conf_pi - configure cau for a given - * status block - * - * @param p_hwfn - * @param p_ptt - * @param igu_sb_id - * @param pi_index - * @param state - * @param timeset - */ -void qed_int_cau_conf_pi(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u16 igu_sb_id, - u32 pi_index, - enum qed_coalescing_fsm coalescing_fsm, - u8 timeset); - /** * @brief qed_int_igu_enable_int - enable device interrupts * -- cgit v1.2.3 From 979cead3deb9f938cd91aa9775744fe7275151c0 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:02 +0300 Subject: qed: Minor refactoring in interrupt code Separate the portions controlling interrupt enablement form those controlling the ability of HW to generate attentions. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_int.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 9b655faf5720..7ecebb66cebd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1616,10 +1616,9 @@ void qed_int_igu_enable_int(struct qed_hwfn *p_hwfn, qed_wr(p_hwfn, p_ptt, IGU_REG_PF_CONFIGURATION, igu_pf_conf); } -int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - enum qed_int_mode int_mode) +static void qed_int_igu_enable_attn(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) { - int rc = 0; /* Configure AEU signal change to produce attentions */ qed_wr(p_hwfn, p_ptt, IGU_REG_ATTENTION_ENABLE, 0); @@ -1632,6 +1631,16 @@ int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, /* Unmask AEU signals toward IGU */ qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_MASK_ATTN_IGU, 0xff); +} + +int +qed_int_igu_enable(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, enum qed_int_mode int_mode) +{ + int rc = 0; + + qed_int_igu_enable_attn(p_hwfn, p_ptt); + if ((int_mode != QED_INT_MODE_INTA) || IS_LEAD_HWFN(p_hwfn)) { rc = qed_slowpath_irq_req(p_hwfn); if (rc) { -- cgit v1.2.3 From d749dd0dc117e7b02fa3a169c431476d59d18950 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:03 +0300 Subject: qed: IGU read revised As a first step for relaxing various assumptions done by driver about the IGU mapping, the driver is now going to read the entire IGU into a shadow copy, and mark in its database each status block that's relevant for it. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_int.c | 203 ++++++++++------------------ drivers/net/ethernet/qlogic/qed/qed_int.h | 11 +- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 7 +- 4 files changed, 83 insertions(+), 140 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index d73e3c265466..0b8e139e057b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1167,7 +1167,7 @@ static void qed_init_cau_rt_data(struct qed_dev *cdev) for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(cdev); sb_id++) { - p_block = &p_igu_info->igu_map.igu_blocks[sb_id]; + p_block = &p_igu_info->entry[sb_id]; if (!p_block->is_pf) continue; diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 7ecebb66cebd..2e280c498cd3 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1783,44 +1783,27 @@ void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, p_hwfn->hw_info.opaque_fid, b_set); } -static u32 qed_int_igu_read_cam_block(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u16 sb_id) +static void qed_int_igu_read_cam_block(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u16 igu_sb_id) { u32 val = qed_rd(p_hwfn, p_ptt, - IGU_REG_MAPPING_MEMORY + sizeof(u32) * sb_id); + IGU_REG_MAPPING_MEMORY + sizeof(u32) * igu_sb_id); struct qed_igu_block *p_block; - p_block = &p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks[sb_id]; - - /* stop scanning when hit first invalid PF entry */ - if (!GET_FIELD(val, IGU_MAPPING_LINE_VALID) && - GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID)) - goto out; + p_block = &p_hwfn->hw_info.p_igu_info->entry[igu_sb_id]; /* Fill the block information */ - p_block->status = QED_IGU_STATUS_VALID; - p_block->function_id = GET_FIELD(val, - IGU_MAPPING_LINE_FUNCTION_NUMBER); - p_block->is_pf = GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID); - p_block->vector_number = GET_FIELD(val, - IGU_MAPPING_LINE_VECTOR_NUMBER); - - DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, - "IGU_BLOCK: [SB 0x%04x, Value in CAM 0x%08x] func_id = %d is_pf = %d vector_num = 0x%x\n", - sb_id, val, p_block->function_id, - p_block->is_pf, p_block->vector_number); - -out: - return val; + p_block->function_id = GET_FIELD(val, IGU_MAPPING_LINE_FUNCTION_NUMBER); + p_block->is_pf = GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID); + p_block->vector_number = GET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER); } int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_igu_info *p_igu_info; - u32 val, min_vf = 0, max_vf = 0; - u16 sb_id, last_iov_sb_id = 0; - struct qed_igu_block *blk; - u16 prev_sb_id = 0xFF; + struct qed_igu_block *p_block; + u32 min_vf = 0, max_vf = 0; + u16 igu_sb_id; p_hwfn->hw_info.p_igu_info = kzalloc(sizeof(*p_igu_info), GFP_KERNEL); if (!p_hwfn->hw_info.p_igu_info) @@ -1828,12 +1811,15 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) p_igu_info = p_hwfn->hw_info.p_igu_info; - /* Initialize base sb / sb cnt for PFs and VFs */ - p_igu_info->igu_base_sb = 0xffff; - p_igu_info->igu_sb_cnt = 0; - p_igu_info->igu_dsb_id = 0xffff; - p_igu_info->igu_base_sb_iov = 0xffff; + /* Initialize base sb / sb cnt for PFs and VFs */ + p_igu_info->igu_base_sb = 0xffff; + p_igu_info->igu_sb_cnt = 0; + p_igu_info->igu_base_sb_iov = 0xffff; + + /* Distinguish between existent and non-existent default SB */ + p_igu_info->igu_dsb_id = QED_SB_INVALID_IDX; + /* Find the range of VF ids whose SB belong to this PF */ if (p_hwfn->cdev->p_iov_info) { struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; @@ -1841,113 +1827,72 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) max_vf = p_iov->first_vf_in_pf + p_iov->total_vfs; } - for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); - sb_id++) { - blk = &p_igu_info->igu_map.igu_blocks[sb_id]; - - val = qed_int_igu_read_cam_block(p_hwfn, p_ptt, sb_id); - - /* stop scanning when hit first invalid PF entry */ - if (!GET_FIELD(val, IGU_MAPPING_LINE_VALID) && - GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID)) - break; - - if (blk->is_pf) { - if (blk->function_id == p_hwfn->rel_pf_id) { - blk->status |= QED_IGU_STATUS_PF; - - if (blk->vector_number == 0) { - if (p_igu_info->igu_dsb_id == 0xffff) - p_igu_info->igu_dsb_id = sb_id; - } else { - if (p_igu_info->igu_base_sb == - 0xffff) { - p_igu_info->igu_base_sb = sb_id; - } else if (prev_sb_id != sb_id - 1) { - DP_NOTICE(p_hwfn->cdev, - "consecutive igu vectors for HWFN %x broken", - p_hwfn->rel_pf_id); - break; - } - prev_sb_id = sb_id; - /* we don't count the default */ - (p_igu_info->igu_sb_cnt)++; - } - } - } else { - if ((blk->function_id >= min_vf) && - (blk->function_id < max_vf)) { - /* Available for VFs of this PF */ - if (p_igu_info->igu_base_sb_iov == 0xffff) { - p_igu_info->igu_base_sb_iov = sb_id; - } else if (last_iov_sb_id != sb_id - 1) { - if (!val) { - DP_VERBOSE(p_hwfn->cdev, - NETIF_MSG_INTR, - "First uninitialized IGU CAM entry at index 0x%04x\n", - sb_id); - } else { - DP_NOTICE(p_hwfn->cdev, - "Consecutive igu vectors for HWFN %x vfs is broken [jumps from %04x to %04x]\n", - p_hwfn->rel_pf_id, - last_iov_sb_id, - sb_id); } - break; - } - blk->status |= QED_IGU_STATUS_FREE; - p_hwfn->hw_info.p_igu_info->free_blks++; - last_iov_sb_id = sb_id; + for (igu_sb_id = 0; + igu_sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); igu_sb_id++) { + /* Read current entry; Notice it might not belong to this PF */ + qed_int_igu_read_cam_block(p_hwfn, p_ptt, igu_sb_id); + p_block = &p_igu_info->entry[igu_sb_id]; + + if ((p_block->is_pf) && + (p_block->function_id == p_hwfn->rel_pf_id)) { + p_block->status = QED_IGU_STATUS_PF | + QED_IGU_STATUS_VALID | + QED_IGU_STATUS_FREE; + + if (p_igu_info->igu_dsb_id != QED_SB_INVALID_IDX) { + if (p_igu_info->igu_base_sb == 0xffff) + p_igu_info->igu_base_sb = igu_sb_id; + p_igu_info->igu_sb_cnt++; } + } else if (!(p_block->is_pf) && + (p_block->function_id >= min_vf) && + (p_block->function_id < max_vf)) { + /* Available for VFs of this PF */ + p_block->status = QED_IGU_STATUS_VALID | + QED_IGU_STATUS_FREE; + + if (p_igu_info->igu_base_sb_iov == 0xffff) + p_igu_info->igu_base_sb_iov = igu_sb_id; + p_igu_info->free_blks++; } - } - /* There's a possibility the igu_sb_cnt_iov doesn't properly reflect - * the number of VF SBs [especially for first VF on engine, as we can't - * differentiate between empty entries and its entries]. - * Since we don't really support more SBs than VFs today, prevent any - * such configuration by sanitizing the number of SBs to equal the - * number of VFs. - */ - if (IS_PF_SRIOV(p_hwfn)) { - u16 total_vfs = p_hwfn->cdev->p_iov_info->total_vfs; - - if (total_vfs < p_igu_info->free_blks) { - DP_VERBOSE(p_hwfn, - (NETIF_MSG_INTR | QED_MSG_IOV), - "Limiting number of SBs for IOV - %04x --> %04x\n", - p_igu_info->free_blks, - p_hwfn->cdev->p_iov_info->total_vfs); - p_igu_info->free_blks = total_vfs; - } else if (total_vfs > p_igu_info->free_blks) { - DP_NOTICE(p_hwfn, - "IGU has only %04x SBs for VFs while the device has %04x VFs\n", - p_igu_info->free_blks, total_vfs); - return -EINVAL; + /* Mark the First entry belonging to the PF or its VFs + * as the default SB. + */ + if ((p_block->status & QED_IGU_STATUS_VALID) && + (p_igu_info->igu_dsb_id == QED_SB_INVALID_IDX)) { + p_igu_info->igu_dsb_id = igu_sb_id; + p_block->status |= QED_IGU_STATUS_DSB; + } + + /* limit number of prints by having each PF print only its + * entries with the exception of PF0 which would print + * everything. + */ + if ((p_block->status & QED_IGU_STATUS_VALID) || + (p_hwfn->abs_pf_id == 0)) { + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "IGU_BLOCK: [SB 0x%04x] func_id = %d is_pf = %d vector_num = 0x%x\n", + igu_sb_id, p_block->function_id, + p_block->is_pf, p_block->vector_number); } } - p_igu_info->igu_sb_cnt_iov = p_igu_info->free_blks; - DP_VERBOSE( - p_hwfn, - NETIF_MSG_INTR, - "IGU igu_base_sb=0x%x [IOV 0x%x] igu_sb_cnt=%d [IOV 0x%x] igu_dsb_id=0x%x\n", - p_igu_info->igu_base_sb, - p_igu_info->igu_base_sb_iov, - p_igu_info->igu_sb_cnt, - p_igu_info->igu_sb_cnt_iov, - p_igu_info->igu_dsb_id); - - if (p_igu_info->igu_base_sb == 0xffff || - p_igu_info->igu_dsb_id == 0xffff || - p_igu_info->igu_sb_cnt == 0) { + if (p_igu_info->igu_dsb_id == QED_SB_INVALID_IDX) { DP_NOTICE(p_hwfn, - "IGU CAM returned invalid values igu_base_sb=0x%x igu_sb_cnt=%d igu_dsb_id=0x%x\n", - p_igu_info->igu_base_sb, - p_igu_info->igu_sb_cnt, - p_igu_info->igu_dsb_id); + "IGU CAM returned invalid values igu_dsb_id=0x%x\n", + p_igu_info->igu_dsb_id); return -EINVAL; } + /* All non default SB are considered free at this point */ + p_igu_info->igu_sb_cnt_iov = p_igu_info->free_blks; + + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "igu_dsb_id=0x%x, num Free SBs - PF: %04x VF: %04x\n", + p_igu_info->igu_dsb_id, + p_igu_info->igu_sb_cnt, p_igu_info->igu_sb_cnt_iov); + return 0; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index a8e48e14efef..91424cf79f67 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -199,24 +199,23 @@ void qed_int_disable_post_isr_release(struct qed_dev *cdev); #define SB_ALIGNED_SIZE(p_hwfn) \ ALIGNED_TYPE_SIZE(struct status_block, p_hwfn) +#define QED_SB_INVALID_IDX 0xffff + struct qed_igu_block { u8 status; #define QED_IGU_STATUS_FREE 0x01 #define QED_IGU_STATUS_VALID 0x02 #define QED_IGU_STATUS_PF 0x04 +#define QED_IGU_STATUS_DSB 0x08 u8 vector_number; u8 function_id; u8 is_pf; }; -struct qed_igu_map { - struct qed_igu_block igu_blocks[MAX_TOT_SB_PER_PATH]; -}; - struct qed_igu_info { - struct qed_igu_map igu_map; - u16 igu_dsb_id; + struct qed_igu_block entry[MAX_TOT_SB_PER_PATH]; + u16 igu_dsb_id; u16 igu_base_sb; u16 igu_base_sb_iov; u16 igu_sb_cnt; diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index b6bda45d0489..0827a4187dc7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -393,7 +393,7 @@ static void qed_iov_clear_vf_igu_blocks(struct qed_hwfn *p_hwfn, for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); sb_id++) { - p_sb = &p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks[sb_id]; + p_sb = &p_hwfn->hw_info.p_igu_info->entry[sb_id]; if ((p_sb->status & QED_IGU_STATUS_FREE) && !(p_sb->status & QED_IGU_STATUS_PF)) { val = qed_rd(p_hwfn, p_ptt, @@ -872,7 +872,7 @@ static u8 qed_iov_alloc_vf_igu_sbs(struct qed_hwfn *p_hwfn, int qid = 0, igu_id = 0; u32 val = 0; - igu_blocks = p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks; + igu_blocks = p_hwfn->hw_info.p_igu_info->entry; if (num_rx_queues > p_hwfn->hw_info.p_igu_info->free_blks) num_rx_queues = p_hwfn->hw_info.p_igu_info->free_blks; @@ -931,8 +931,7 @@ static void qed_iov_free_vf_igu_sbs(struct qed_hwfn *p_hwfn, SET_FIELD(val, IGU_MAPPING_LINE_VALID, 0); qed_wr(p_hwfn, p_ptt, addr, val); - p_info->igu_map.igu_blocks[igu_id].status |= - QED_IGU_STATUS_FREE; + p_info->entry[igu_id].status |= QED_IGU_STATUS_FREE; p_hwfn->hw_info.p_igu_info->free_blks++; } -- cgit v1.2.3 From d031548e9194714dc2e8cb928d9f671432c8a342 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:04 +0300 Subject: qed: Distinguish between sb_id and igu_sb_id In qed code, sb_id means 2 different things: - An interrupt vector [usually when received as a parameter from a protocol driver, but not only] that's associated with a status block. - An index to a status block entity existing in HW. This patch renames the references to the HW entity, adding an 'igu_' prefix to allow an easier distinction. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 12 ++++++---- drivers/net/ethernet/qlogic/qed/qed_int.c | 39 +++++++++++++++++-------------- drivers/net/ethernet/qlogic/qed/qed_int.h | 4 ++-- 3 files changed, 30 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 0b8e139e057b..3b6114d4461a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1155,7 +1155,7 @@ static int qed_calc_hw_mode(struct qed_hwfn *p_hwfn) static void qed_init_cau_rt_data(struct qed_dev *cdev) { u32 offset = CAU_REG_SB_VAR_MEMORY_RT_OFFSET; - int i, sb_id; + int i, igu_sb_id; for_each_hwfn(cdev, i) { struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; @@ -1165,15 +1165,17 @@ static void qed_init_cau_rt_data(struct qed_dev *cdev) p_igu_info = p_hwfn->hw_info.p_igu_info; - for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(cdev); - sb_id++) { - p_block = &p_igu_info->entry[sb_id]; + for (igu_sb_id = 0; + igu_sb_id < QED_MAPPING_MEMORY_SIZE(cdev); igu_sb_id++) { + p_block = &p_igu_info->entry[igu_sb_id]; + if (!p_block->is_pf) continue; qed_init_cau_sb_entry(p_hwfn, &sb_entry, p_block->function_id, 0, 0); - STORE_RT_REG_AGG(p_hwfn, offset + sb_id * 2, sb_entry); + STORE_RT_REG_AGG(p_hwfn, offset + igu_sb_id * 2, + sb_entry); } } } diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 2e280c498cd3..92744cfb57f4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1669,10 +1669,11 @@ void qed_int_igu_disable_int(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) #define IGU_CLEANUP_SLEEP_LENGTH (1000) static void qed_int_igu_cleanup_sb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u32 sb_id, bool cleanup_set, u16 opaque_fid) + u16 igu_sb_id, + bool cleanup_set, u16 opaque_fid) { u32 cmd_ctrl = 0, val = 0, sb_bit = 0, sb_bit_addr = 0, data = 0; - u32 pxp_addr = IGU_CMD_INT_ACK_BASE + sb_id; + u32 pxp_addr = IGU_CMD_INT_ACK_BASE + igu_sb_id; u32 sleep_cnt = IGU_CLEANUP_SLEEP_LENGTH; /* Set the data field */ @@ -1695,8 +1696,8 @@ static void qed_int_igu_cleanup_sb(struct qed_hwfn *p_hwfn, mmiowb(); /* calculate where to read the status bit from */ - sb_bit = 1 << (sb_id % 32); - sb_bit_addr = sb_id / 32 * sizeof(u32); + sb_bit = 1 << (igu_sb_id % 32); + sb_bit_addr = igu_sb_id / 32 * sizeof(u32); sb_bit_addr += IGU_REG_CLEANUP_STATUS_0; @@ -1713,29 +1714,30 @@ static void qed_int_igu_cleanup_sb(struct qed_hwfn *p_hwfn, if (!sleep_cnt) DP_NOTICE(p_hwfn, "Timeout waiting for clear status 0x%08x [for sb %d]\n", - val, sb_id); + val, igu_sb_id); } void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u32 sb_id, u16 opaque, bool b_set) + u16 igu_sb_id, u16 opaque, bool b_set) { int pi, i; /* Set */ if (b_set) - qed_int_igu_cleanup_sb(p_hwfn, p_ptt, sb_id, 1, opaque); + qed_int_igu_cleanup_sb(p_hwfn, p_ptt, igu_sb_id, 1, opaque); /* Clear */ - qed_int_igu_cleanup_sb(p_hwfn, p_ptt, sb_id, 0, opaque); + qed_int_igu_cleanup_sb(p_hwfn, p_ptt, igu_sb_id, 0, opaque); /* Wait for the IGU SB to cleanup */ for (i = 0; i < IGU_CLEANUP_SLEEP_LENGTH; i++) { u32 val; val = qed_rd(p_hwfn, p_ptt, - IGU_REG_WRITE_DONE_PENDING + ((sb_id / 32) * 4)); - if (val & (1 << (sb_id % 32))) + IGU_REG_WRITE_DONE_PENDING + + ((igu_sb_id / 32) * 4)); + if (val & BIT((igu_sb_id % 32))) usleep_range(10, 20); else break; @@ -1743,12 +1745,12 @@ void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn, if (i == IGU_CLEANUP_SLEEP_LENGTH) DP_NOTICE(p_hwfn, "Failed SB[0x%08x] still appearing in WRITE_DONE_PENDING\n", - sb_id); + igu_sb_id); /* Clear the CAU for the SB */ for (pi = 0; pi < 12; pi++) qed_wr(p_hwfn, p_ptt, - CAU_REG_PI_MEMORY + (sb_id * 12 + pi) * 4, 0); + CAU_REG_PI_MEMORY + (igu_sb_id * 12 + pi) * 4, 0); } void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, @@ -1757,7 +1759,7 @@ void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, { u32 igu_base_sb = p_hwfn->hw_info.p_igu_info->igu_base_sb; u32 igu_sb_cnt = p_hwfn->hw_info.p_igu_info->igu_sb_cnt; - u32 sb_id = 0, val = 0; + u32 igu_sb_id = 0, val = 0; val = qed_rd(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION); val |= IGU_REG_BLOCK_CONFIGURATION_VF_CLEANUP_EN; @@ -1768,18 +1770,19 @@ void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, "IGU cleaning SBs [%d,...,%d]\n", igu_base_sb, igu_base_sb + igu_sb_cnt - 1); - for (sb_id = igu_base_sb; sb_id < igu_base_sb + igu_sb_cnt; sb_id++) - qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, sb_id, + for (igu_sb_id = igu_base_sb; igu_sb_id < igu_base_sb + igu_sb_cnt; + igu_sb_id++) + qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, igu_sb_id, p_hwfn->hw_info.opaque_fid, b_set); if (!b_slowpath) return; - sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id; + igu_sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id; DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, - "IGU cleaning slowpath SB [%d]\n", sb_id); - qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, sb_id, + "IGU cleaning slowpath SB [%d]\n", igu_sb_id); + qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, igu_sb_id, p_hwfn->hw_info.opaque_fid, b_set); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index 91424cf79f67..60aaf9f9bb78 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -302,13 +302,13 @@ u16 qed_int_get_sp_sb_id(struct qed_hwfn *p_hwfn); * * @param p_hwfn * @param p_ptt - * @param sb_id - igu status block id + * @param igu_sb_id - igu status block id * @param opaque - opaque fid of the sb owner. * @param b_set - set(1) / clear(0) */ void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u32 sb_id, + u16 igu_sb_id, u16 opaque, bool b_set); -- cgit v1.2.3 From a333f7f3fd327d736a23c52aafcfe17c75f2610c Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:05 +0300 Subject: qed: Add aux. function translating sb_id -> igu_sb_id An additional step for relaxing the IGU order assumption, we now add an auxiliary function that can be used for finding the HW status block that's associated with a given MSI-x vector. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_int.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 92744cfb57f4..3307978f6eeb 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1412,15 +1412,26 @@ void qed_int_sb_setup(struct qed_hwfn *p_hwfn, sb_info->igu_sb_id, 0, 0); } -/** - * @brief qed_get_igu_sb_id - given a sw sb_id return the - * igu_sb_id - * - * @param p_hwfn - * @param sb_id - * - * @return u16 - */ +static u16 qed_get_pf_igu_sb_id(struct qed_hwfn *p_hwfn, u16 vector_id) +{ + struct qed_igu_block *p_block; + u16 igu_id; + + for (igu_id = 0; igu_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); + igu_id++) { + p_block = &p_hwfn->hw_info.p_igu_info->entry[igu_id]; + + if (!(p_block->status & QED_IGU_STATUS_VALID) || + !p_block->is_pf || + p_block->vector_number != vector_id) + continue; + + return igu_id; + } + + return QED_SB_INVALID_IDX; +} + static u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) { u16 igu_sb_id; @@ -1429,7 +1440,7 @@ static u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) if (sb_id == QED_SP_SB_ID) igu_sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id; else if (IS_PF(p_hwfn->cdev)) - igu_sb_id = sb_id + p_hwfn->hw_info.p_igu_info->igu_base_sb; + igu_sb_id = qed_get_pf_igu_sb_id(p_hwfn, sb_id + 1); else igu_sb_id = qed_vf_get_igu_sb_id(p_hwfn, sb_id); -- cgit v1.2.3 From 726fdbe9fa7ebccda1579716f68f8bae6fa9c87a Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:06 +0300 Subject: qed: Encapsulate interrupt counters in struct We already have an API struct that contains interrupt-related numbers. Use it to encapsulate all information relating to the status of SBs as (used|free). Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 4 ++-- drivers/net/ethernet/qlogic/qed/qed_int.c | 20 +++++++++----------- drivers/net/ethernet/qlogic/qed/qed_int.h | 10 +++++----- drivers/net/ethernet/qlogic/qed/qed_main.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 9 ++++----- 5 files changed, 21 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 3b6114d4461a..1fff0473ddbb 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -2061,7 +2061,7 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) qed_int_get_num_sbs(p_hwfn, &sb_cnt_info); feat_num[QED_VF_L2_QUE] = min_t(u32, RESC_NUM(p_hwfn, QED_L2_QUEUE), - sb_cnt_info.sb_iov_cnt); + sb_cnt_info.iov_cnt); feat_num[QED_PF_L2_QUE] = min_t(u32, RESC_NUM(p_hwfn, QED_SB) - non_l2_sbs, @@ -2255,7 +2255,7 @@ int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn, case QED_SB: memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); qed_int_get_num_sbs(p_hwfn, &sb_cnt_info); - *p_resc_num = sb_cnt_info.sb_cnt; + *p_resc_num = sb_cnt_info.cnt; break; default: return -EINVAL; diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 3307978f6eeb..c9164e27a1b2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1769,7 +1769,7 @@ void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, bool b_set, bool b_slowpath) { u32 igu_base_sb = p_hwfn->hw_info.p_igu_info->igu_base_sb; - u32 igu_sb_cnt = p_hwfn->hw_info.p_igu_info->igu_sb_cnt; + u32 igu_sb_cnt = p_hwfn->hw_info.p_igu_info->usage.cnt; u32 igu_sb_id = 0, val = 0; val = qed_rd(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION); @@ -1827,7 +1827,6 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) /* Initialize base sb / sb cnt for PFs and VFs */ p_igu_info->igu_base_sb = 0xffff; - p_igu_info->igu_sb_cnt = 0; p_igu_info->igu_base_sb_iov = 0xffff; /* Distinguish between existent and non-existent default SB */ @@ -1856,7 +1855,7 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) if (p_igu_info->igu_dsb_id != QED_SB_INVALID_IDX) { if (p_igu_info->igu_base_sb == 0xffff) p_igu_info->igu_base_sb = igu_sb_id; - p_igu_info->igu_sb_cnt++; + p_igu_info->usage.cnt++; } } else if (!(p_block->is_pf) && (p_block->function_id >= min_vf) && @@ -1867,7 +1866,7 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) if (p_igu_info->igu_base_sb_iov == 0xffff) p_igu_info->igu_base_sb_iov = igu_sb_id; - p_igu_info->free_blks++; + p_igu_info->usage.iov_cnt++; } /* Mark the First entry belonging to the PF or its VFs @@ -1900,12 +1899,13 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) } /* All non default SB are considered free at this point */ - p_igu_info->igu_sb_cnt_iov = p_igu_info->free_blks; + p_igu_info->usage.free_cnt = p_igu_info->usage.cnt; + p_igu_info->usage.free_cnt_iov = p_igu_info->usage.iov_cnt; DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, "igu_dsb_id=0x%x, num Free SBs - PF: %04x VF: %04x\n", p_igu_info->igu_dsb_id, - p_igu_info->igu_sb_cnt, p_igu_info->igu_sb_cnt_iov); + p_igu_info->usage.cnt, p_igu_info->usage.iov_cnt); return 0; } @@ -2003,9 +2003,7 @@ void qed_int_get_num_sbs(struct qed_hwfn *p_hwfn, if (!info || !p_sb_cnt_info) return; - p_sb_cnt_info->sb_cnt = info->igu_sb_cnt; - p_sb_cnt_info->sb_iov_cnt = info->igu_sb_cnt_iov; - p_sb_cnt_info->sb_free_blk = info->free_blks; + memcpy(p_sb_cnt_info, &info->usage, sizeof(*p_sb_cnt_info)); } u16 qed_int_queue_id_from_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) @@ -2014,10 +2012,10 @@ u16 qed_int_queue_id_from_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) /* Determine origin of SB id */ if ((sb_id >= p_info->igu_base_sb) && - (sb_id < p_info->igu_base_sb + p_info->igu_sb_cnt)) { + (sb_id < p_info->igu_base_sb + p_info->usage.cnt)) { return sb_id - p_info->igu_base_sb; } else if ((sb_id >= p_info->igu_base_sb_iov) && - (sb_id < p_info->igu_base_sb_iov + p_info->igu_sb_cnt_iov)) { + (sb_id < p_info->igu_base_sb_iov + p_info->usage.iov_cnt)) { /* We want the first VF queue to be adjacent to the * last PF queue. Since L2 queues can be partial to * SBs, we'll use the feature instead. diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index 60aaf9f9bb78..5a0e8f02c969 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -216,11 +216,11 @@ struct qed_igu_block { struct qed_igu_info { struct qed_igu_block entry[MAX_TOT_SB_PER_PATH]; u16 igu_dsb_id; - u16 igu_base_sb; - u16 igu_base_sb_iov; - u16 igu_sb_cnt; - u16 igu_sb_cnt_iov; - u16 free_blks; + + u16 igu_base_sb; + u16 igu_base_sb_iov; + struct qed_sb_cnt_info usage; + }; /* TODO Names of function may change... */ diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index c5bb80b9afc1..ac3bdcd9f0b6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -762,7 +762,7 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev, for_each_hwfn(cdev, i) { memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info); - cdev->int_params.in.num_vectors += sb_cnt_info.sb_cnt; + cdev->int_params.in.num_vectors += sb_cnt_info.cnt; cdev->int_params.in.num_vectors++; /* slowpath */ } diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 0827a4187dc7..62b207a80a03 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -874,9 +874,9 @@ static u8 qed_iov_alloc_vf_igu_sbs(struct qed_hwfn *p_hwfn, igu_blocks = p_hwfn->hw_info.p_igu_info->entry; - if (num_rx_queues > p_hwfn->hw_info.p_igu_info->free_blks) - num_rx_queues = p_hwfn->hw_info.p_igu_info->free_blks; - p_hwfn->hw_info.p_igu_info->free_blks -= num_rx_queues; + if (num_rx_queues > p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov) + num_rx_queues = p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov; + p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov -= num_rx_queues; SET_FIELD(val, IGU_MAPPING_LINE_FUNCTION_NUMBER, vf->abs_vf_id); SET_FIELD(val, IGU_MAPPING_LINE_VALID, 1); @@ -932,8 +932,7 @@ static void qed_iov_free_vf_igu_sbs(struct qed_hwfn *p_hwfn, qed_wr(p_hwfn, p_ptt, addr, val); p_info->entry[igu_id].status |= QED_IGU_STATUS_FREE; - - p_hwfn->hw_info.p_igu_info->free_blks++; + p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov++; } vf->num_sbs = 0; -- cgit v1.2.3 From 1ac72433c565c8db38fd1f9db80a73193369e5fc Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:07 +0300 Subject: qed: Remove assumption on SB order in IGU Current code assumes there's a known layout for SBs in the IGU, where all the SBs of a single entity would be laid in consecutive order of vectors. While the assumption is still kept by management firmware, we already have the necessary information to eliminate it, so no reason to keep it in code. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_int.c | 79 ++++++++++++------------------- drivers/net/ethernet/qlogic/qed/qed_int.h | 15 ++---- 2 files changed, 33 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index c9164e27a1b2..a49484a8726c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1732,8 +1732,16 @@ void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 igu_sb_id, u16 opaque, bool b_set) { + struct qed_igu_block *p_block; int pi, i; + p_block = &p_hwfn->hw_info.p_igu_info->entry[igu_sb_id]; + DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, + "Cleaning SB [%04x]: func_id= %d is_pf = %d vector_num = 0x%0x\n", + igu_sb_id, + p_block->function_id, + p_block->is_pf, p_block->vector_number); + /* Set */ if (b_set) qed_int_igu_cleanup_sb(p_hwfn, p_ptt, igu_sb_id, 1, opaque); @@ -1768,33 +1776,35 @@ void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_set, bool b_slowpath) { - u32 igu_base_sb = p_hwfn->hw_info.p_igu_info->igu_base_sb; - u32 igu_sb_cnt = p_hwfn->hw_info.p_igu_info->usage.cnt; - u32 igu_sb_id = 0, val = 0; + struct qed_igu_info *p_info = p_hwfn->hw_info.p_igu_info; + struct qed_igu_block *p_block; + u16 igu_sb_id = 0; + u32 val = 0; val = qed_rd(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION); val |= IGU_REG_BLOCK_CONFIGURATION_VF_CLEANUP_EN; val &= ~IGU_REG_BLOCK_CONFIGURATION_PXP_TPH_INTERFACE_EN; qed_wr(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION, val); - DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, - "IGU cleaning SBs [%d,...,%d]\n", - igu_base_sb, igu_base_sb + igu_sb_cnt - 1); + for (igu_sb_id = 0; + igu_sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); igu_sb_id++) { + p_block = &p_info->entry[igu_sb_id]; + + if (!(p_block->status & QED_IGU_STATUS_VALID) || + !p_block->is_pf || + (p_block->status & QED_IGU_STATUS_DSB)) + continue; - for (igu_sb_id = igu_base_sb; igu_sb_id < igu_base_sb + igu_sb_cnt; - igu_sb_id++) qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, igu_sb_id, p_hwfn->hw_info.opaque_fid, b_set); + } - if (!b_slowpath) - return; - - igu_sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id; - DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, - "IGU cleaning slowpath SB [%d]\n", igu_sb_id); - qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, igu_sb_id, - p_hwfn->hw_info.opaque_fid, b_set); + if (b_slowpath) + qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, + p_info->igu_dsb_id, + p_hwfn->hw_info.opaque_fid, + b_set); } static void qed_int_igu_read_cam_block(struct qed_hwfn *p_hwfn, @@ -1810,6 +1820,7 @@ static void qed_int_igu_read_cam_block(struct qed_hwfn *p_hwfn, p_block->function_id = GET_FIELD(val, IGU_MAPPING_LINE_FUNCTION_NUMBER); p_block->is_pf = GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID); p_block->vector_number = GET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER); + p_block->igu_sb_id = igu_sb_id; } int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) @@ -1825,10 +1836,6 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) p_igu_info = p_hwfn->hw_info.p_igu_info; - /* Initialize base sb / sb cnt for PFs and VFs */ - p_igu_info->igu_base_sb = 0xffff; - p_igu_info->igu_base_sb_iov = 0xffff; - /* Distinguish between existent and non-existent default SB */ p_igu_info->igu_dsb_id = QED_SB_INVALID_IDX; @@ -1852,11 +1859,8 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) QED_IGU_STATUS_VALID | QED_IGU_STATUS_FREE; - if (p_igu_info->igu_dsb_id != QED_SB_INVALID_IDX) { - if (p_igu_info->igu_base_sb == 0xffff) - p_igu_info->igu_base_sb = igu_sb_id; + if (p_igu_info->igu_dsb_id != QED_SB_INVALID_IDX) p_igu_info->usage.cnt++; - } } else if (!(p_block->is_pf) && (p_block->function_id >= min_vf) && (p_block->function_id < max_vf)) { @@ -1864,9 +1868,8 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) p_block->status = QED_IGU_STATUS_VALID | QED_IGU_STATUS_FREE; - if (p_igu_info->igu_base_sb_iov == 0xffff) - p_igu_info->igu_base_sb_iov = igu_sb_id; - p_igu_info->usage.iov_cnt++; + if (p_igu_info->igu_dsb_id != QED_SB_INVALID_IDX) + p_igu_info->usage.iov_cnt++; } /* Mark the First entry belonging to the PF or its VFs @@ -2006,28 +2009,6 @@ void qed_int_get_num_sbs(struct qed_hwfn *p_hwfn, memcpy(p_sb_cnt_info, &info->usage, sizeof(*p_sb_cnt_info)); } -u16 qed_int_queue_id_from_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) -{ - struct qed_igu_info *p_info = p_hwfn->hw_info.p_igu_info; - - /* Determine origin of SB id */ - if ((sb_id >= p_info->igu_base_sb) && - (sb_id < p_info->igu_base_sb + p_info->usage.cnt)) { - return sb_id - p_info->igu_base_sb; - } else if ((sb_id >= p_info->igu_base_sb_iov) && - (sb_id < p_info->igu_base_sb_iov + p_info->usage.iov_cnt)) { - /* We want the first VF queue to be adjacent to the - * last PF queue. Since L2 queues can be partial to - * SBs, we'll use the feature instead. - */ - return sb_id - p_info->igu_base_sb_iov + - FEAT_NUM(p_hwfn, QED_PF_L2_QUE); - } else { - DP_NOTICE(p_hwfn, "SB %d not in range for function\n", sb_id); - return 0; - } -} - void qed_int_disable_post_isr_release(struct qed_dev *cdev) { int i; diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index 5a0e8f02c969..b55334ff76a2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -211,14 +211,15 @@ struct qed_igu_block { u8 vector_number; u8 function_id; u8 is_pf; + + /* Index inside IGU [meant for back reference] */ + u16 igu_sb_id; }; struct qed_igu_info { struct qed_igu_block entry[MAX_TOT_SB_PER_PATH]; u16 igu_dsb_id; - u16 igu_base_sb; - u16 igu_base_sb_iov; struct qed_sb_cnt_info usage; }; @@ -357,16 +358,6 @@ void qed_int_free(struct qed_hwfn *p_hwfn); void qed_int_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); -/** - * @brief - Returns an Rx queue index appropriate for usage with given SB. - * - * @param p_hwfn - * @param sb_id - absolute index of SB - * - * @return index of Rx queue - */ -u16 qed_int_queue_id_from_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id); - /** * @brief - Enable Interrupt & Attention for hw function * -- cgit v1.2.3 From 09b6b14749523e3660b72be2ed91b3c0b852f58f Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:08 +0300 Subject: qed: Provide auxiliary for getting free VF SB IOV code is very intrusive in its manipulation of the status block database. Add a new auxiliary function to allow the PF to find an available unused status block to configure for a specific VF's MSI-x vector. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_int.c | 20 ++++++++++++ drivers/net/ethernet/qlogic/qed/qed_int.h | 11 +++++++ drivers/net/ethernet/qlogic/qed/qed_sriov.c | 49 ++++++++++++----------------- 3 files changed, 51 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index a49484a8726c..96eee1ede8ab 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1412,6 +1412,26 @@ void qed_int_sb_setup(struct qed_hwfn *p_hwfn, sb_info->igu_sb_id, 0, 0); } +struct qed_igu_block *qed_get_igu_free_sb(struct qed_hwfn *p_hwfn, bool b_is_pf) +{ + struct qed_igu_block *p_block; + u16 igu_id; + + for (igu_id = 0; igu_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); + igu_id++) { + p_block = &p_hwfn->hw_info.p_igu_info->entry[igu_id]; + + if (!(p_block->status & QED_IGU_STATUS_VALID) || + !(p_block->status & QED_IGU_STATUS_FREE)) + continue; + + if (!!(p_block->status & QED_IGU_STATUS_PF) == b_is_pf) + return p_block; + } + + return NULL; +} + static u16 qed_get_pf_igu_sb_id(struct qed_hwfn *p_hwfn, u16 vector_id) { struct qed_igu_block *p_block; diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index b55334ff76a2..273e73a1f850 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -225,6 +225,17 @@ struct qed_igu_info { }; /* TODO Names of function may change... */ +/** + * @brief return a pointer to an unused valid SB + * + * @param p_hwfn + * @param b_is_pf - true iff we want a SB belonging to a PF + * + * @return point to an igu_block, NULL if none is available + */ +struct qed_igu_block *qed_get_igu_free_sb(struct qed_hwfn *p_hwfn, + bool b_is_pf); + void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_set, diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 62b207a80a03..cb9123b8c8fc 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -868,12 +868,11 @@ static u8 qed_iov_alloc_vf_igu_sbs(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *vf, u16 num_rx_queues) { - struct qed_igu_block *igu_blocks; - int qid = 0, igu_id = 0; + struct qed_igu_block *p_block; + struct cau_sb_entry sb_entry; + int qid = 0; u32 val = 0; - igu_blocks = p_hwfn->hw_info.p_igu_info->entry; - if (num_rx_queues > p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov) num_rx_queues = p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov; p_hwfn->hw_info.p_igu_info->usage.free_cnt_iov -= num_rx_queues; @@ -882,31 +881,23 @@ static u8 qed_iov_alloc_vf_igu_sbs(struct qed_hwfn *p_hwfn, SET_FIELD(val, IGU_MAPPING_LINE_VALID, 1); SET_FIELD(val, IGU_MAPPING_LINE_PF_VALID, 0); - while ((qid < num_rx_queues) && - (igu_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev))) { - if (igu_blocks[igu_id].status & QED_IGU_STATUS_FREE) { - struct cau_sb_entry sb_entry; - - vf->igu_sbs[qid] = (u16)igu_id; - igu_blocks[igu_id].status &= ~QED_IGU_STATUS_FREE; - - SET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER, qid); - - qed_wr(p_hwfn, p_ptt, - IGU_REG_MAPPING_MEMORY + sizeof(u32) * igu_id, - val); - - /* Configure igu sb in CAU which were marked valid */ - qed_init_cau_sb_entry(p_hwfn, &sb_entry, - p_hwfn->rel_pf_id, - vf->abs_vf_id, 1); - qed_dmae_host2grc(p_hwfn, p_ptt, - (u64)(uintptr_t)&sb_entry, - CAU_REG_SB_VAR_MEMORY + - igu_id * sizeof(u64), 2, 0); - qid++; - } - igu_id++; + for (qid = 0; qid < num_rx_queues; qid++) { + p_block = qed_get_igu_free_sb(p_hwfn, false); + vf->igu_sbs[qid] = p_block->igu_sb_id; + p_block->status &= ~QED_IGU_STATUS_FREE; + SET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER, qid); + + qed_wr(p_hwfn, p_ptt, + IGU_REG_MAPPING_MEMORY + + sizeof(u32) * p_block->igu_sb_id, val); + + /* Configure igu sb in CAU which were marked valid */ + qed_init_cau_sb_entry(p_hwfn, &sb_entry, + p_hwfn->rel_pf_id, vf->abs_vf_id, 1); + qed_dmae_host2grc(p_hwfn, p_ptt, + (u64)(uintptr_t)&sb_entry, + CAU_REG_SB_VAR_MEMORY + + p_block->igu_sb_id * sizeof(u64), 2, 0); } vf->num_sbs = (u8) num_rx_queues; -- cgit v1.2.3 From 50a207147fceb64ad24c1e08e4a2a75535922e81 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:09 +0300 Subject: qed: Hold a single array for SBs A PF today holds 2 different arrays - one holding information about the HW configuration and one holding information about the SBs that are used by the protocol drivers. These arrays aren't really connected - e.g., protocol driver initializing a given SB would not mark the same SB as occupied in the HW shadow array. Move into a single array [at least for PFs] - hold the mapping of the driver-protocol SBs on the HW entry which they configure. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 4 --- drivers/net/ethernet/qlogic/qed/qed_fcoe.c | 5 +++- drivers/net/ethernet/qlogic/qed/qed_int.c | 46 ++++++++++++++++++++++------- drivers/net/ethernet/qlogic/qed/qed_int.h | 23 +++++++++++---- drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_roce.c | 5 ++-- drivers/net/ethernet/qlogic/qed/qed_vf.c | 27 +++++++++++++++-- drivers/net/ethernet/qlogic/qed/qed_vf.h | 18 +++++++++++ 8 files changed, 103 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index e0becec17b09..ffc080795be7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -495,10 +495,6 @@ struct qed_hwfn { bool b_rdma_enabled_in_prs; u32 rdma_prs_search_reg; - /* Array of sb_info of all status blocks */ - struct qed_sb_info *sbs_info[MAX_SB_PER_PF_MIMD]; - u16 num_sbs; - struct qed_cxt_mngr *p_cxt_mngr; /* Flag indicating whether interrupts are enabled or not*/ diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c index cb342f16c137..3fc4ff22960e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c @@ -183,7 +183,10 @@ qed_sp_fcoe_func_start(struct qed_hwfn *p_hwfn, p_data->q_params.queue_relative_offset = (u8)tmp; for (i = 0; i < fcoe_pf_params->num_cqs; i++) { - tmp = cpu_to_le16(p_hwfn->sbs_info[i]->igu_sb_id); + u16 igu_sb_id; + + igu_sb_id = qed_get_igu_sb_id(p_hwfn, i); + tmp = cpu_to_le16(igu_sb_id); p_data->q_params.cq_cmdq_sb_num_arr[i] = tmp; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 96eee1ede8ab..c9cad2e25dd8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1452,7 +1452,7 @@ static u16 qed_get_pf_igu_sb_id(struct qed_hwfn *p_hwfn, u16 vector_id) return QED_SB_INVALID_IDX; } -static u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) +u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) { u16 igu_sb_id; @@ -1485,8 +1485,19 @@ int qed_int_sb_init(struct qed_hwfn *p_hwfn, sb_info->igu_sb_id = qed_get_igu_sb_id(p_hwfn, sb_id); if (sb_id != QED_SP_SB_ID) { - p_hwfn->sbs_info[sb_id] = sb_info; - p_hwfn->num_sbs++; + if (IS_PF(p_hwfn->cdev)) { + struct qed_igu_info *p_info; + struct qed_igu_block *p_block; + + p_info = p_hwfn->hw_info.p_igu_info; + p_block = &p_info->entry[sb_info->igu_sb_id]; + + p_block->sb_info = sb_info; + p_block->status &= ~QED_IGU_STATUS_FREE; + p_info->usage.free_cnt--; + } else { + qed_vf_set_sb_info(p_hwfn, sb_id, sb_info); + } } sb_info->cdev = p_hwfn->cdev; @@ -1515,20 +1526,35 @@ int qed_int_sb_init(struct qed_hwfn *p_hwfn, int qed_int_sb_release(struct qed_hwfn *p_hwfn, struct qed_sb_info *sb_info, u16 sb_id) { - if (sb_id == QED_SP_SB_ID) { - DP_ERR(p_hwfn, "Do Not free sp sb using this function"); - return -EINVAL; - } + struct qed_igu_block *p_block; + struct qed_igu_info *p_info; + + if (!sb_info) + return 0; /* zero status block and ack counter */ sb_info->sb_ack = 0; memset(sb_info->sb_virt, 0, sizeof(*sb_info->sb_virt)); - if (p_hwfn->sbs_info[sb_id] != NULL) { - p_hwfn->sbs_info[sb_id] = NULL; - p_hwfn->num_sbs--; + if (IS_VF(p_hwfn->cdev)) { + qed_vf_set_sb_info(p_hwfn, sb_id, NULL); + return 0; } + p_info = p_hwfn->hw_info.p_igu_info; + p_block = &p_info->entry[sb_info->igu_sb_id]; + + /* Vector 0 is reserved to Default SB */ + if (!p_block->vector_number) { + DP_ERR(p_hwfn, "Do Not free sp sb using this function"); + return -EINVAL; + } + + /* Lose reference to client's SB info, and fix counters */ + p_block->sb_info = NULL; + p_block->status |= QED_IGU_STATUS_FREE; + p_info->usage.free_cnt++; + return 0; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index 273e73a1f850..bc61c5013b6e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -202,18 +202,20 @@ void qed_int_disable_post_isr_release(struct qed_dev *cdev); #define QED_SB_INVALID_IDX 0xffff struct qed_igu_block { - u8 status; + u8 status; #define QED_IGU_STATUS_FREE 0x01 #define QED_IGU_STATUS_VALID 0x02 #define QED_IGU_STATUS_PF 0x04 #define QED_IGU_STATUS_DSB 0x08 - u8 vector_number; - u8 function_id; - u8 is_pf; + u8 vector_number; + u8 function_id; + u8 is_pf; /* Index inside IGU [meant for back reference] */ - u16 igu_sb_id; + u16 igu_sb_id; + + struct qed_sb_info *sb_info; }; struct qed_igu_info { @@ -224,7 +226,16 @@ struct qed_igu_info { }; -/* TODO Names of function may change... */ +/** + * @brief Translate the weakly-defined client sb-id into an IGU sb-id + * + * @param p_hwfn + * @param sb_id - user provided sb_id + * + * @return an index inside IGU CAM where the SB resides + */ +u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id); + /** * @brief return a pointer to an unused valid SB * diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index 43a20a6fd1b6..bc8ce09d390f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -220,7 +220,7 @@ qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn, p_queue->cmdq_sb_pi = p_params->gl_cmd_pi; for (i = 0; i < p_params->num_queues; i++) { - val = p_hwfn->sbs_info[i]->igu_sb_id; + val = qed_get_igu_sb_id(p_hwfn, i); p_queue->cq_cmdq_sb_num_arr[i] = cpu_to_le16(val); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index eb1a5cfc49c0..b9434b707b08 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -581,6 +581,7 @@ static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn, struct qed_sp_init_data init_data; struct qed_spq_entry *p_ent; u32 cnq_id, sb_id; + u16 igu_sb_id; int rc; DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Starting FW\n"); @@ -612,10 +613,10 @@ static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn, for (cnq_id = 0; cnq_id < params->desired_cnq; cnq_id++) { sb_id = qed_rdma_get_sb_id(p_hwfn, cnq_id); + igu_sb_id = qed_get_igu_sb_id(p_hwfn, sb_id); + p_ramrod->cnq_params[cnq_id].sb_num = cpu_to_le16(igu_sb_id); p_cnq_params = &p_ramrod->cnq_params[cnq_id]; p_cnq_pbl_list = ¶ms->cnq_pbl_list[cnq_id]; - p_cnq_params->sb_num = - cpu_to_le16(p_hwfn->sbs_info[sb_id]->igu_sb_id); p_cnq_params->sb_index = p_hwfn->pf_params.rdma_pf_params.gl_pi; p_cnq_params->num_pbl_pages = p_cnq_pbl_list->num_pbl_pages; diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index 11d71e5eea14..3703b22a3973 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -792,9 +792,12 @@ int qed_vf_pf_vport_start(struct qed_hwfn *p_hwfn, req->only_untagged = only_untagged; /* status blocks */ - for (i = 0; i < p_hwfn->vf_iov_info->acquire_resp.resc.num_sbs; i++) - if (p_hwfn->sbs_info[i]) - req->sb_addr[i] = p_hwfn->sbs_info[i]->sb_phys; + for (i = 0; i < p_hwfn->vf_iov_info->acquire_resp.resc.num_sbs; i++) { + struct qed_sb_info *p_sb = p_hwfn->vf_iov_info->sbs_info[i]; + + if (p_sb) + req->sb_addr[i] = p_sb->sb_phys; + } /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, @@ -1240,6 +1243,24 @@ u16 qed_vf_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) return p_iov->acquire_resp.resc.hw_sbs[sb_id].hw_sb_id; } +void qed_vf_set_sb_info(struct qed_hwfn *p_hwfn, + u16 sb_id, struct qed_sb_info *p_sb) +{ + struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; + + if (!p_iov) { + DP_NOTICE(p_hwfn, "vf_sriov_info isn't initialized\n"); + return; + } + + if (sb_id >= PFVF_MAX_SBS_PER_VF) { + DP_NOTICE(p_hwfn, "Can't configure SB %04x\n", sb_id); + return; + } + + p_iov->sbs_info[sb_id] = p_sb; +} + int qed_vf_read_bulletin(struct qed_hwfn *p_hwfn, u8 *p_change) { struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index 34ac70b0e5fe..67862085f032 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h @@ -627,6 +627,14 @@ struct qed_vf_iov { * this has to be propagated as it affects the fastpath. */ bool b_pre_fp_hsi; + + /* Current day VFs are passing the SBs physical address on vport + * start, and as they lack an IGU mapping they need to store the + * addresses of previously registered SBs. + * Even if we were to change configuration flow, due to backward + * compatibility [with older PFs] we'd still need to store these. + */ + struct qed_sb_info *sbs_info[PFVF_MAX_SBS_PER_VF]; }; #ifdef CONFIG_QED_SRIOV @@ -836,6 +844,16 @@ int qed_vf_pf_release(struct qed_hwfn *p_hwfn); */ u16 qed_vf_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id); +/** + * @brief Stores [or removes] a configured sb_info. + * + * @param p_hwfn + * @param sb_id - zero-based SB index [for fastpath] + * @param sb_info - may be NULL [during removal]. + */ +void qed_vf_set_sb_info(struct qed_hwfn *p_hwfn, + u16 sb_id, struct qed_sb_info *p_sb); + /** * @brief qed_vf_pf_vport_start - perform vport start for VF. * -- cgit v1.2.3 From ebbdcc669c7f9d8632d358a739d814485f8917dc Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:10 +0300 Subject: qed: Reset IGU CAM to default on init The IGU CAM contains an assocaition between hardware SBs and interrupt lines, and it can be dynamically configured to allow more interrupts in one entity over another, specifically for Re-distibution of SBs between a PF and its child VFs. While we don't yet use this functionality, there are other clients that do and as such its possible the information passed from management firmware during initialization in regard to the possible number of SBs doesn't accurately reflect the current HW configuration. The following changes are going to apply to the driver init sequence: a. PF is going to re-configure all entries belonging to itself and its child VFs in IGU CAM based on the management firmware info regarding the number of SBs that are supposed to exist there. b. PF is going to stop using the SB resource [management firmware provided information] for anything but the initialization. Instead, it would use the live-time counters it maintains for the numbers. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 35 ++++---- drivers/net/ethernet/qlogic/qed/qed_int.c | 138 +++++++++++++++++++++++++++++- drivers/net/ethernet/qlogic/qed/qed_int.h | 9 ++ 3 files changed, 162 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 1fff0473ddbb..939e85cc63a0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -2038,9 +2038,12 @@ static void get_function_id(struct qed_hwfn *p_hwfn) static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) { u32 *feat_num = p_hwfn->hw_info.feat_num; - struct qed_sb_cnt_info sb_cnt_info; + struct qed_sb_cnt_info sb_cnt; u32 non_l2_sbs = 0; + memset(&sb_cnt, 0, sizeof(sb_cnt)); + qed_int_get_num_sbs(p_hwfn, &sb_cnt); + if (IS_ENABLED(CONFIG_QED_RDMA) && p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) { /* Roce CNQ each requires: 1 status block + 1 CNQ. We divide @@ -2048,7 +2051,7 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) * consideration as to how many l2 queues / cnqs we have. */ feat_num[QED_RDMA_CNQ] = - min_t(u32, RESC_NUM(p_hwfn, QED_SB) / 2, + min_t(u32, sb_cnt.cnt / 2, RESC_NUM(p_hwfn, QED_RDMA_CNQ_RAM)); non_l2_sbs = feat_num[QED_RDMA_CNQ]; @@ -2057,14 +2060,11 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE || p_hwfn->hw_info.personality == QED_PCI_ETH) { /* Start by allocating VF queues, then PF's */ - memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); - qed_int_get_num_sbs(p_hwfn, &sb_cnt_info); feat_num[QED_VF_L2_QUE] = min_t(u32, RESC_NUM(p_hwfn, QED_L2_QUEUE), - sb_cnt_info.iov_cnt); + sb_cnt.iov_cnt); feat_num[QED_PF_L2_QUE] = min_t(u32, - RESC_NUM(p_hwfn, QED_SB) - - non_l2_sbs, + sb_cnt.cnt - non_l2_sbs, RESC_NUM(p_hwfn, QED_L2_QUEUE) - FEAT_NUM(p_hwfn, @@ -2072,7 +2072,7 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) } if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) - feat_num[QED_ISCSI_CQ] = min_t(u32, RESC_NUM(p_hwfn, QED_SB), + feat_num[QED_ISCSI_CQ] = min_t(u32, sb_cnt.cnt, RESC_NUM(p_hwfn, QED_CMDQS_CQS)); DP_VERBOSE(p_hwfn, @@ -2082,7 +2082,7 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) (int)FEAT_NUM(p_hwfn, QED_VF_L2_QUE), (int)FEAT_NUM(p_hwfn, QED_RDMA_CNQ), (int)FEAT_NUM(p_hwfn, QED_ISCSI_CQ), - RESC_NUM(p_hwfn, QED_SB)); + (int)sb_cnt.cnt); } const char *qed_hw_get_resc_name(enum qed_resources res_id) @@ -2201,7 +2201,6 @@ int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn, { u8 num_funcs = p_hwfn->num_funcs_on_engine; bool b_ah = QED_IS_AH(p_hwfn->cdev); - struct qed_sb_cnt_info sb_cnt_info; switch (res_id) { case QED_L2_QUEUE: @@ -2253,9 +2252,10 @@ int qed_hw_get_dflt_resc(struct qed_hwfn *p_hwfn, *p_resc_num = 1; break; case QED_SB: - memset(&sb_cnt_info, 0, sizeof(sb_cnt_info)); - qed_int_get_num_sbs(p_hwfn, &sb_cnt_info); - *p_resc_num = sb_cnt_info.cnt; + /* Since we want its value to reflect whether MFW supports + * the new scheme, have a default of 0. + */ + *p_resc_num = 0; break; default: return -EINVAL; @@ -2324,11 +2324,6 @@ static int __qed_hw_set_resc_info(struct qed_hwfn *p_hwfn, goto out; } - /* Special handling for status blocks; Would be revised in future */ - if (res_id == QED_SB) { - *p_resc_num -= 1; - *p_resc_start -= p_hwfn->enabled_func_idx; - } out: /* PQs have to divide by 8 [that's the HW granularity]. * Reduce number so it would fit. @@ -2426,6 +2421,10 @@ static int qed_hw_get_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) return -EINVAL; } + /* This will also learn the number of SBs from MFW */ + if (qed_int_igu_reset_cam(p_hwfn, p_ptt)) + return -EINVAL; + qed_hw_set_feat(p_hwfn); for (res_id = 0; res_id < QED_MAX_RESC; res_id++) diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index c9cad2e25dd8..719cdbfe1695 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1853,6 +1853,140 @@ void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn, b_set); } +int qed_int_igu_reset_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + struct qed_igu_info *p_info = p_hwfn->hw_info.p_igu_info; + struct qed_igu_block *p_block; + int pf_sbs, vf_sbs; + u16 igu_sb_id; + u32 val, rval; + + if (!RESC_NUM(p_hwfn, QED_SB)) { + p_info->b_allow_pf_vf_change = false; + } else { + /* Use the numbers the MFW have provided - + * don't forget MFW accounts for the default SB as well. + */ + p_info->b_allow_pf_vf_change = true; + + if (p_info->usage.cnt != RESC_NUM(p_hwfn, QED_SB) - 1) { + DP_INFO(p_hwfn, + "MFW notifies of 0x%04x PF SBs; IGU indicates of only 0x%04x\n", + RESC_NUM(p_hwfn, QED_SB) - 1, + p_info->usage.cnt); + p_info->usage.cnt = RESC_NUM(p_hwfn, QED_SB) - 1; + } + + if (IS_PF_SRIOV(p_hwfn)) { + u16 vfs = p_hwfn->cdev->p_iov_info->total_vfs; + + if (vfs != p_info->usage.iov_cnt) + DP_VERBOSE(p_hwfn, + NETIF_MSG_INTR, + "0x%04x VF SBs in IGU CAM != PCI configuration 0x%04x\n", + p_info->usage.iov_cnt, vfs); + + /* At this point we know how many SBs we have totally + * in IGU + number of PF SBs. So we can validate that + * we'd have sufficient for VF. + */ + if (vfs > p_info->usage.free_cnt + + p_info->usage.free_cnt_iov - p_info->usage.cnt) { + DP_NOTICE(p_hwfn, + "Not enough SBs for VFs - 0x%04x SBs, from which %04x PFs and %04x are required\n", + p_info->usage.free_cnt + + p_info->usage.free_cnt_iov, + p_info->usage.cnt, vfs); + return -EINVAL; + } + + /* Currently cap the number of VFs SBs by the + * number of VFs. + */ + p_info->usage.iov_cnt = vfs; + } + } + + /* Mark all SBs as free, now in the right PF/VFs division */ + p_info->usage.free_cnt = p_info->usage.cnt; + p_info->usage.free_cnt_iov = p_info->usage.iov_cnt; + p_info->usage.orig = p_info->usage.cnt; + p_info->usage.iov_orig = p_info->usage.iov_cnt; + + /* We now proceed to re-configure the IGU cam to reflect the initial + * configuration. We can start with the Default SB. + */ + pf_sbs = p_info->usage.cnt; + vf_sbs = p_info->usage.iov_cnt; + + for (igu_sb_id = p_info->igu_dsb_id; + igu_sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); igu_sb_id++) { + p_block = &p_info->entry[igu_sb_id]; + val = 0; + + if (!(p_block->status & QED_IGU_STATUS_VALID)) + continue; + + if (p_block->status & QED_IGU_STATUS_DSB) { + p_block->function_id = p_hwfn->rel_pf_id; + p_block->is_pf = 1; + p_block->vector_number = 0; + p_block->status = QED_IGU_STATUS_VALID | + QED_IGU_STATUS_PF | + QED_IGU_STATUS_DSB; + } else if (pf_sbs) { + pf_sbs--; + p_block->function_id = p_hwfn->rel_pf_id; + p_block->is_pf = 1; + p_block->vector_number = p_info->usage.cnt - pf_sbs; + p_block->status = QED_IGU_STATUS_VALID | + QED_IGU_STATUS_PF | + QED_IGU_STATUS_FREE; + } else if (vf_sbs) { + p_block->function_id = + p_hwfn->cdev->p_iov_info->first_vf_in_pf + + p_info->usage.iov_cnt - vf_sbs; + p_block->is_pf = 0; + p_block->vector_number = 0; + p_block->status = QED_IGU_STATUS_VALID | + QED_IGU_STATUS_FREE; + vf_sbs--; + } else { + p_block->function_id = 0; + p_block->is_pf = 0; + p_block->vector_number = 0; + } + + SET_FIELD(val, IGU_MAPPING_LINE_FUNCTION_NUMBER, + p_block->function_id); + SET_FIELD(val, IGU_MAPPING_LINE_PF_VALID, p_block->is_pf); + SET_FIELD(val, IGU_MAPPING_LINE_VECTOR_NUMBER, + p_block->vector_number); + + /* VF entries would be enabled when VF is initializaed */ + SET_FIELD(val, IGU_MAPPING_LINE_VALID, p_block->is_pf); + + rval = qed_rd(p_hwfn, p_ptt, + IGU_REG_MAPPING_MEMORY + sizeof(u32) * igu_sb_id); + + if (rval != val) { + qed_wr(p_hwfn, p_ptt, + IGU_REG_MAPPING_MEMORY + + sizeof(u32) * igu_sb_id, val); + + DP_VERBOSE(p_hwfn, + NETIF_MSG_INTR, + "IGU reset: [SB 0x%04x] func_id = %d is_pf = %d vector_num = 0x%x [%08x -> %08x]\n", + igu_sb_id, + p_block->function_id, + p_block->is_pf, + p_block->vector_number, rval, val); + } + } + + return 0; +} + static void qed_int_igu_read_cam_block(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 igu_sb_id) { @@ -1919,7 +2053,7 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) } /* Mark the First entry belonging to the PF or its VFs - * as the default SB. + * as the default SB [we'll reset IGU prior to first usage]. */ if ((p_block->status & QED_IGU_STATUS_VALID) && (p_igu_info->igu_dsb_id == QED_SB_INVALID_IDX)) { @@ -1952,7 +2086,7 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) p_igu_info->usage.free_cnt_iov = p_igu_info->usage.iov_cnt; DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, - "igu_dsb_id=0x%x, num Free SBs - PF: %04x VF: %04x\n", + "igu_dsb_id=0x%x, num Free SBs - PF: %04x VF: %04x [might change after resource allocation]\n", p_igu_info->igu_dsb_id, p_igu_info->usage.cnt, p_igu_info->usage.iov_cnt); diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index bc61c5013b6e..5199634ed630 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -224,8 +224,17 @@ struct qed_igu_info { struct qed_sb_cnt_info usage; + bool b_allow_pf_vf_change; }; +/** + * @brief - Make sure the IGU CAM reflects the resources provided by MFW + * + * @param p_hwfn + * @param p_ptt + */ +int qed_int_igu_reset_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); + /** * @brief Translate the weakly-defined client sb-id into an IGU sb-id * -- cgit v1.2.3 From 1ee240e31d4c0a5fd37ebaf064ca1f6cb6adcb6f Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Thu, 1 Jun 2017 15:29:11 +0300 Subject: qed: No need to reset SBs on IOV init Since we're resetting the IGU CAM each time we initialize the PF device, there's no need to reset the VF SBs again when initializing IOV. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 30 +---------------------------- drivers/net/ethernet/qlogic/qed/qed_sriov.h | 5 ++--- 3 files changed, 4 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 939e85cc63a0..7649f35000db 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1030,7 +1030,7 @@ void qed_resc_setup(struct qed_dev *cdev) qed_int_setup(p_hwfn, p_hwfn->p_main_ptt); - qed_iov_setup(p_hwfn, p_hwfn->p_main_ptt); + qed_iov_setup(p_hwfn); #ifdef CONFIG_QED_LL2 if (p_hwfn->using_ll2) qed_ll2_setup(p_hwfn); diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index cb9123b8c8fc..5ae8827534f8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -378,33 +378,6 @@ static int qed_iov_pci_cfg_info(struct qed_dev *cdev) return 0; } -static void qed_iov_clear_vf_igu_blocks(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt) -{ - struct qed_igu_block *p_sb; - u16 sb_id; - u32 val; - - if (!p_hwfn->hw_info.p_igu_info) { - DP_ERR(p_hwfn, - "qed_iov_clear_vf_igu_blocks IGU Info not initialized\n"); - return; - } - - for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev); - sb_id++) { - p_sb = &p_hwfn->hw_info.p_igu_info->entry[sb_id]; - if ((p_sb->status & QED_IGU_STATUS_FREE) && - !(p_sb->status & QED_IGU_STATUS_PF)) { - val = qed_rd(p_hwfn, p_ptt, - IGU_REG_MAPPING_MEMORY + sb_id * 4); - SET_FIELD(val, IGU_MAPPING_LINE_VALID, 0); - qed_wr(p_hwfn, p_ptt, - IGU_REG_MAPPING_MEMORY + 4 * sb_id, val); - } - } -} - static void qed_iov_setup_vfdb(struct qed_hwfn *p_hwfn) { struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; @@ -555,13 +528,12 @@ int qed_iov_alloc(struct qed_hwfn *p_hwfn) return qed_iov_allocate_vfdb(p_hwfn); } -void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +void qed_iov_setup(struct qed_hwfn *p_hwfn) { if (!IS_PF_SRIOV(p_hwfn) || !IS_PF_SRIOV_ALLOC(p_hwfn)) return; qed_iov_setup_vfdb(p_hwfn); - qed_iov_clear_vf_igu_blocks(p_hwfn, p_ptt); } void qed_iov_free(struct qed_hwfn *p_hwfn) diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index 81a497ce6585..801cc005e52b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -316,9 +316,8 @@ int qed_iov_alloc(struct qed_hwfn *p_hwfn); * @brief qed_iov_setup - setup sriov related resources * * @param p_hwfn - * @param p_ptt */ -void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +void qed_iov_setup(struct qed_hwfn *p_hwfn); /** * @brief qed_iov_free - free sriov related resources @@ -397,7 +396,7 @@ static inline int qed_iov_alloc(struct qed_hwfn *p_hwfn) return 0; } -static inline void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +static inline void qed_iov_setup(struct qed_hwfn *p_hwfn) { } -- cgit v1.2.3 From ce6ef68f433f2c97e5d2cf35d2b694e17592d350 Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Thu, 1 Jun 2017 16:26:46 +0300 Subject: mlxsw: spectrum: Implement the ethtool flash_device callback Add callback to the ethtool flash_device op. This callback uses the mlxfw module to flash the new firmware file to the device. As the firmware flash process takes about 20 seconds and ethtool takes the rtnl lock during the flash_device callback, release the rtnl lock at the beginning of the flash process and take it again before leaving the callback. This way, the rtnl is not held during the process. To make sure the device does not get deleted during the flash process, take a reference to it before releasing the rtnl lock. Signed-off-by: Yotam Gigi Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 51 +++++++++++++++++++++----- 1 file changed, 42 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 666bcf4854e6..1e6a97d9a87d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -321,6 +321,21 @@ static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = { .fsm_release = mlxsw_sp_fsm_release }; +static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp, + const struct firmware *firmware) +{ + struct mlxsw_sp_mlxfw_dev mlxsw_sp_mlxfw_dev = { + .mlxfw_dev = { + .ops = &mlxsw_sp_mlxfw_dev_ops, + .psid = mlxsw_sp->bus_info->psid, + .psid_size = strlen(mlxsw_sp->bus_info->psid), + }, + .mlxsw_sp = mlxsw_sp + }; + + return mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware); +} + static bool mlxsw_sp_fw_rev_ge(const struct mlxsw_fw_rev *a, const struct mlxsw_fw_rev *b) { @@ -334,14 +349,6 @@ static bool mlxsw_sp_fw_rev_ge(const struct mlxsw_fw_rev *a, static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp) { const struct mlxsw_fw_rev *rev = &mlxsw_sp->bus_info->fw_rev; - struct mlxsw_sp_mlxfw_dev mlxsw_sp_mlxfw_dev = { - .mlxfw_dev = { - .ops = &mlxsw_sp_mlxfw_dev_ops, - .psid = mlxsw_sp->bus_info->psid, - .psid_size = strlen(mlxsw_sp->bus_info->psid), - }, - .mlxsw_sp = mlxsw_sp - }; const struct firmware *firmware; int err; @@ -361,7 +368,7 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp) return err; } - err = mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware); + err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware); release_firmware(firmware); return err; } @@ -2495,6 +2502,31 @@ mlxsw_sp_port_set_link_ksettings(struct net_device *dev, return 0; } +static int mlxsw_sp_flash_device(struct net_device *dev, + struct ethtool_flash *flash) +{ + struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + const struct firmware *firmware; + int err; + + if (flash->region != ETHTOOL_FLASH_ALL_REGIONS) + return -EOPNOTSUPP; + + dev_hold(dev); + rtnl_unlock(); + + err = request_firmware_direct(&firmware, flash->data, &dev->dev); + if (err) + goto out; + err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware); + release_firmware(firmware); +out: + rtnl_lock(); + dev_put(dev); + return err; +} + static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { .get_drvinfo = mlxsw_sp_port_get_drvinfo, .get_link = ethtool_op_get_link, @@ -2506,6 +2538,7 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { .get_sset_count = mlxsw_sp_port_get_sset_count, .get_link_ksettings = mlxsw_sp_port_get_link_ksettings, .set_link_ksettings = mlxsw_sp_port_set_link_ksettings, + .flash_device = mlxsw_sp_flash_device, }; static int -- cgit v1.2.3 From 3874191898675ac34b6d1d94cfe997c570492bbb Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 31 May 2017 09:18:32 +0200 Subject: net-next: stmmac: export stmmac_set_mac_addr/stmmac_get_mac_addr Thoses symbol will be needed for the dwmac-sun8i ethernet driver. For letting it to be build as module, they need to be exported. Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index 38f94305aab5..67af0bdd7f10 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -248,6 +248,7 @@ void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; writel(data, ioaddr + low); } +EXPORT_SYMBOL_GPL(stmmac_set_mac_addr); /* Enable disable MAC RX/TX */ void stmmac_set_mac(void __iomem *ioaddr, bool enable) @@ -279,4 +280,4 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, addr[4] = hi_addr & 0xff; addr[5] = (hi_addr >> 8) & 0xff; } - +EXPORT_SYMBOL_GPL(stmmac_get_mac_addr); -- cgit v1.2.3 From ec33d71de7309c50531c2ae0eb178244899e6e46 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 31 May 2017 09:18:33 +0200 Subject: net-next: stmmac: add optional setup function Instead of adding more ifthen logic for adding a new mac_device_info setup function, it is easier to add a function pointer to the function needed. Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f158273eab9b..c80c9c3b67db 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3933,7 +3933,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv) struct mac_device_info *mac; /* Identify the MAC HW device */ - if (priv->plat->has_gmac) { + if (priv->plat->setup) { + mac = priv->plat->setup(priv); + } else if (priv->plat->has_gmac) { priv->dev->priv_flags |= IFF_UNICAST_FLT; mac = dwmac1000_setup(priv->ioaddr, priv->plat->multicast_filter_bins, -- cgit v1.2.3 From 9f93ac8d4085f718d3c7c5fedcb98dbdd2287648 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Wed, 31 May 2017 09:18:36 +0200 Subject: net-next: stmmac: Add dwmac-sun8i The dwmac-sun8i is a heavy hacked version of stmmac hardware by allwinner. In fact the only common part is the descriptor management and the first register function. Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 + drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 990 +++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 15 + .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 9 +- 5 files changed, 1024 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index cfbe3634dfa1..85c0e41f8021 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -145,6 +145,17 @@ config DWMAC_SUNXI This selects Allwinner SoC glue layer support for the stmmac device driver. This driver is used for A20/A31 GMAC ethernet controller. + +config DWMAC_SUN8I + tristate "Allwinner sun8i GMAC support" + default ARCH_SUNXI + depends on OF && (ARCH_SUNXI || COMPILE_TEST) + ---help--- + Support for Allwinner H3 A83T A64 EMAC ethernet controllers. + + This selects Allwinner SoC glue layer support for the + stmmac device driver. This driver is used for H3/A83T/A64 + EMAC ethernet controller. endif config STMMAC_PCI diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 700c60336674..fd4937a7fcab 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o +obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o stmmac-platform-objs:= stmmac_platform.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c new file mode 100644 index 000000000000..1a6bfe6c958f --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -0,0 +1,990 @@ +/* + * dwmac-sun8i.c - Allwinner sun8i DWMAC specific glue layer + * + * Copyright (C) 2017 Corentin Labbe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stmmac.h" +#include "stmmac_platform.h" + +/* General notes on dwmac-sun8i: + * Locking: no locking is necessary in this file because all necessary locking + * is done in the "stmmac files" + */ + +/* struct emac_variant - Descrive dwmac-sun8i hardware variant + * @default_syscon_value: The default value of the EMAC register in syscon + * This value is used for disabling properly EMAC + * and used as a good starting value in case of the + * boot process(uboot) leave some stuff. + * @internal_phy: Does the MAC embed an internal PHY + * @support_mii: Does the MAC handle MII + * @support_rmii: Does the MAC handle RMII + * @support_rgmii: Does the MAC handle RGMII + */ +struct emac_variant { + u32 default_syscon_value; + int internal_phy; + bool support_mii; + bool support_rmii; + bool support_rgmii; +}; + +/* struct sunxi_priv_data - hold all sunxi private data + * @tx_clk: reference to MAC TX clock + * @ephy_clk: reference to the optional EPHY clock for the internal PHY + * @regulator: reference to the optional regulator + * @rst_ephy: reference to the optional EPHY reset for the internal PHY + * @variant: reference to the current board variant + * @regmap: regmap for using the syscon + * @use_internal_phy: Does the current PHY choice imply using the internal PHY + */ +struct sunxi_priv_data { + struct clk *tx_clk; + struct clk *ephy_clk; + struct regulator *regulator; + struct reset_control *rst_ephy; + const struct emac_variant *variant; + struct regmap *regmap; + bool use_internal_phy; +}; + +static const struct emac_variant emac_variant_h3 = { + .default_syscon_value = 0x58000, + .internal_phy = PHY_INTERFACE_MODE_MII, + .support_mii = true, + .support_rmii = true, + .support_rgmii = true +}; + +static const struct emac_variant emac_variant_a83t = { + .default_syscon_value = 0, + .internal_phy = 0, + .support_mii = true, + .support_rgmii = true +}; + +static const struct emac_variant emac_variant_a64 = { + .default_syscon_value = 0, + .internal_phy = 0, + .support_mii = true, + .support_rmii = true, + .support_rgmii = true +}; + +#define EMAC_BASIC_CTL0 0x00 +#define EMAC_BASIC_CTL1 0x04 +#define EMAC_INT_STA 0x08 +#define EMAC_INT_EN 0x0C +#define EMAC_TX_CTL0 0x10 +#define EMAC_TX_CTL1 0x14 +#define EMAC_TX_FLOW_CTL 0x1C +#define EMAC_TX_DESC_LIST 0x20 +#define EMAC_RX_CTL0 0x24 +#define EMAC_RX_CTL1 0x28 +#define EMAC_RX_DESC_LIST 0x34 +#define EMAC_RX_FRM_FLT 0x38 +#define EMAC_MDIO_CMD 0x48 +#define EMAC_MDIO_DATA 0x4C +#define EMAC_MACADDR_HI(reg) (0x50 + (reg) * 8) +#define EMAC_MACADDR_LO(reg) (0x54 + (reg) * 8) +#define EMAC_TX_DMA_STA 0xB0 +#define EMAC_TX_CUR_DESC 0xB4 +#define EMAC_TX_CUR_BUF 0xB8 +#define EMAC_RX_DMA_STA 0xC0 +#define EMAC_RX_CUR_DESC 0xC4 +#define EMAC_RX_CUR_BUF 0xC8 + +/* Use in EMAC_BASIC_CTL0 */ +#define EMAC_DUPLEX_FULL BIT(0) +#define EMAC_LOOPBACK BIT(1) +#define EMAC_SPEED_1000 0 +#define EMAC_SPEED_100 (0x03 << 2) +#define EMAC_SPEED_10 (0x02 << 2) + +/* Use in EMAC_BASIC_CTL1 */ +#define EMAC_BURSTLEN_SHIFT 24 + +/* Used in EMAC_RX_FRM_FLT */ +#define EMAC_FRM_FLT_RXALL BIT(0) +#define EMAC_FRM_FLT_CTL BIT(13) +#define EMAC_FRM_FLT_MULTICAST BIT(16) + +/* Used in RX_CTL1*/ +#define EMAC_RX_MD BIT(1) +#define EMAC_RX_TH_MASK GENMASK(4, 5) +#define EMAC_RX_TH_32 0 +#define EMAC_RX_TH_64 (0x1 << 4) +#define EMAC_RX_TH_96 (0x2 << 4) +#define EMAC_RX_TH_128 (0x3 << 4) +#define EMAC_RX_DMA_EN BIT(30) +#define EMAC_RX_DMA_START BIT(31) + +/* Used in TX_CTL1*/ +#define EMAC_TX_MD BIT(1) +#define EMAC_TX_NEXT_FRM BIT(2) +#define EMAC_TX_TH_MASK GENMASK(8, 10) +#define EMAC_TX_TH_64 0 +#define EMAC_TX_TH_128 (0x1 << 8) +#define EMAC_TX_TH_192 (0x2 << 8) +#define EMAC_TX_TH_256 (0x3 << 8) +#define EMAC_TX_DMA_EN BIT(30) +#define EMAC_TX_DMA_START BIT(31) + +/* Used in RX_CTL0 */ +#define EMAC_RX_RECEIVER_EN BIT(31) +#define EMAC_RX_DO_CRC BIT(27) +#define EMAC_RX_FLOW_CTL_EN BIT(16) + +/* Used in TX_CTL0 */ +#define EMAC_TX_TRANSMITTER_EN BIT(31) + +/* Used in EMAC_TX_FLOW_CTL */ +#define EMAC_TX_FLOW_CTL_EN BIT(0) + +/* Used in EMAC_INT_STA */ +#define EMAC_TX_INT BIT(0) +#define EMAC_TX_DMA_STOP_INT BIT(1) +#define EMAC_TX_BUF_UA_INT BIT(2) +#define EMAC_TX_TIMEOUT_INT BIT(3) +#define EMAC_TX_UNDERFLOW_INT BIT(4) +#define EMAC_TX_EARLY_INT BIT(5) +#define EMAC_RX_INT BIT(8) +#define EMAC_RX_BUF_UA_INT BIT(9) +#define EMAC_RX_DMA_STOP_INT BIT(10) +#define EMAC_RX_TIMEOUT_INT BIT(11) +#define EMAC_RX_OVERFLOW_INT BIT(12) +#define EMAC_RX_EARLY_INT BIT(13) +#define EMAC_RGMII_STA_INT BIT(16) + +#define MAC_ADDR_TYPE_DST BIT(31) + +/* H3 specific bits for EPHY */ +#define H3_EPHY_ADDR_SHIFT 20 +#define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */ +#define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */ +#define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */ + +/* H3/A64 specific bits */ +#define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */ + +/* Generic system control EMAC_CLK bits */ +#define SYSCON_ETXDC_MASK GENMASK(2, 0) +#define SYSCON_ETXDC_SHIFT 10 +#define SYSCON_ERXDC_MASK GENMASK(4, 0) +#define SYSCON_ERXDC_SHIFT 5 +/* EMAC PHY Interface Type */ +#define SYSCON_EPIT BIT(2) /* 1: RGMII, 0: MII */ +#define SYSCON_ETCS_MASK GENMASK(1, 0) +#define SYSCON_ETCS_MII 0x0 +#define SYSCON_ETCS_EXT_GMII 0x1 +#define SYSCON_ETCS_INT_GMII 0x2 +#define SYSCON_EMAC_REG 0x30 + +/* sun8i_dwmac_dma_reset() - reset the EMAC + * Called from stmmac via stmmac_dma_ops->reset + */ +static int sun8i_dwmac_dma_reset(void __iomem *ioaddr) +{ + writel(0, ioaddr + EMAC_RX_CTL1); + writel(0, ioaddr + EMAC_TX_CTL1); + writel(0, ioaddr + EMAC_RX_FRM_FLT); + writel(0, ioaddr + EMAC_RX_DESC_LIST); + writel(0, ioaddr + EMAC_TX_DESC_LIST); + writel(0, ioaddr + EMAC_INT_EN); + writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); + return 0; +} + +/* sun8i_dwmac_dma_init() - initialize the EMAC + * Called from stmmac via stmmac_dma_ops->init + */ +static void sun8i_dwmac_dma_init(void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, + u32 dma_tx, u32 dma_rx, int atds) +{ + /* Write TX and RX descriptors address */ + writel(dma_rx, ioaddr + EMAC_RX_DESC_LIST); + writel(dma_tx, ioaddr + EMAC_TX_DESC_LIST); + + writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); + writel(0x1FFFFFF, ioaddr + EMAC_INT_STA); +} + +/* sun8i_dwmac_dump_regs() - Dump EMAC address space + * Called from stmmac_dma_ops->dump_regs + * Used for ethtool + */ +static void sun8i_dwmac_dump_regs(void __iomem *ioaddr, u32 *reg_space) +{ + int i; + + for (i = 0; i < 0xC8; i += 4) { + if (i == 0x32 || i == 0x3C) + continue; + reg_space[i / 4] = readl(ioaddr + i); + } +} + +/* sun8i_dwmac_dump_mac_regs() - Dump EMAC address space + * Called from stmmac_ops->dump_regs + * Used for ethtool + */ +static void sun8i_dwmac_dump_mac_regs(struct mac_device_info *hw, + u32 *reg_space) +{ + int i; + void __iomem *ioaddr = hw->pcsr; + + for (i = 0; i < 0xC8; i += 4) { + if (i == 0x32 || i == 0x3C) + continue; + reg_space[i / 4] = readl(ioaddr + i); + } +} + +static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN); +} + +static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan) +{ + writel(0, ioaddr + EMAC_INT_EN); +} + +static void sun8i_dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan) +{ + u32 v; + + v = readl(ioaddr + EMAC_TX_CTL1); + v |= EMAC_TX_DMA_START; + v |= EMAC_TX_DMA_EN; + writel(v, ioaddr + EMAC_TX_CTL1); +} + +static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr) +{ + u32 v; + + v = readl(ioaddr + EMAC_TX_CTL1); + v |= EMAC_TX_DMA_START; + v |= EMAC_TX_DMA_EN; + writel(v, ioaddr + EMAC_TX_CTL1); +} + +static void sun8i_dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan) +{ + u32 v; + + v = readl(ioaddr + EMAC_TX_CTL1); + v &= ~EMAC_TX_DMA_EN; + writel(v, ioaddr + EMAC_TX_CTL1); +} + +static void sun8i_dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan) +{ + u32 v; + + v = readl(ioaddr + EMAC_RX_CTL1); + v |= EMAC_RX_DMA_START; + v |= EMAC_RX_DMA_EN; + writel(v, ioaddr + EMAC_RX_CTL1); +} + +static void sun8i_dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan) +{ + u32 v; + + v = readl(ioaddr + EMAC_RX_CTL1); + v &= ~EMAC_RX_DMA_EN; + writel(v, ioaddr + EMAC_RX_CTL1); +} + +static int sun8i_dwmac_dma_interrupt(void __iomem *ioaddr, + struct stmmac_extra_stats *x, u32 chan) +{ + u32 v; + int ret = 0; + + v = readl(ioaddr + EMAC_INT_STA); + + if (v & EMAC_TX_INT) { + ret |= handle_tx; + x->tx_normal_irq_n++; + } + + if (v & EMAC_TX_DMA_STOP_INT) + x->tx_process_stopped_irq++; + + if (v & EMAC_TX_BUF_UA_INT) + x->tx_process_stopped_irq++; + + if (v & EMAC_TX_TIMEOUT_INT) + ret |= tx_hard_error; + + if (v & EMAC_TX_UNDERFLOW_INT) { + ret |= tx_hard_error; + x->tx_undeflow_irq++; + } + + if (v & EMAC_TX_EARLY_INT) + x->tx_early_irq++; + + if (v & EMAC_RX_INT) { + ret |= handle_rx; + x->rx_normal_irq_n++; + } + + if (v & EMAC_RX_BUF_UA_INT) + x->rx_buf_unav_irq++; + + if (v & EMAC_RX_DMA_STOP_INT) + x->rx_process_stopped_irq++; + + if (v & EMAC_RX_TIMEOUT_INT) + ret |= tx_hard_error; + + if (v & EMAC_RX_OVERFLOW_INT) { + ret |= tx_hard_error; + x->rx_overflow_irq++; + } + + if (v & EMAC_RX_EARLY_INT) + x->rx_early_irq++; + + if (v & EMAC_RGMII_STA_INT) + x->irq_rgmii_n++; + + writel(v, ioaddr + EMAC_INT_STA); + + return ret; +} + +static void sun8i_dwmac_dma_operation_mode(void __iomem *ioaddr, int txmode, + int rxmode, int rxfifosz) +{ + u32 v; + + v = readl(ioaddr + EMAC_TX_CTL1); + if (txmode == SF_DMA_MODE) { + v |= EMAC_TX_MD; + /* Undocumented bit (called TX_NEXT_FRM in BSP), the original + * comment is + * "Operating on second frame increase the performance + * especially when transmit store-and-forward is used." + */ + v |= EMAC_TX_NEXT_FRM; + } else { + v &= ~EMAC_TX_MD; + v &= ~EMAC_TX_TH_MASK; + if (txmode < 64) + v |= EMAC_TX_TH_64; + else if (txmode < 128) + v |= EMAC_TX_TH_128; + else if (txmode < 192) + v |= EMAC_TX_TH_192; + else if (txmode < 256) + v |= EMAC_TX_TH_256; + } + writel(v, ioaddr + EMAC_TX_CTL1); + + v = readl(ioaddr + EMAC_RX_CTL1); + if (rxmode == SF_DMA_MODE) { + v |= EMAC_RX_MD; + } else { + v &= ~EMAC_RX_MD; + v &= ~EMAC_RX_TH_MASK; + if (rxmode < 32) + v |= EMAC_RX_TH_32; + else if (rxmode < 64) + v |= EMAC_RX_TH_64; + else if (rxmode < 96) + v |= EMAC_RX_TH_96; + else if (rxmode < 128) + v |= EMAC_RX_TH_128; + } + writel(v, ioaddr + EMAC_RX_CTL1); +} + +static const struct stmmac_dma_ops sun8i_dwmac_dma_ops = { + .reset = sun8i_dwmac_dma_reset, + .init = sun8i_dwmac_dma_init, + .dump_regs = sun8i_dwmac_dump_regs, + .dma_mode = sun8i_dwmac_dma_operation_mode, + .enable_dma_transmission = sun8i_dwmac_enable_dma_transmission, + .enable_dma_irq = sun8i_dwmac_enable_dma_irq, + .disable_dma_irq = sun8i_dwmac_disable_dma_irq, + .start_tx = sun8i_dwmac_dma_start_tx, + .stop_tx = sun8i_dwmac_dma_stop_tx, + .start_rx = sun8i_dwmac_dma_start_rx, + .stop_rx = sun8i_dwmac_dma_stop_rx, + .dma_interrupt = sun8i_dwmac_dma_interrupt, +}; + +static int sun8i_dwmac_init(struct platform_device *pdev, void *priv) +{ + struct sunxi_priv_data *gmac = priv; + int ret; + + if (gmac->regulator) { + ret = regulator_enable(gmac->regulator); + if (ret) { + dev_err(&pdev->dev, "Fail to enable regulator\n"); + return ret; + } + } + + ret = clk_prepare_enable(gmac->tx_clk); + if (ret) { + if (gmac->regulator) + regulator_disable(gmac->regulator); + dev_err(&pdev->dev, "Could not enable AHB clock\n"); + return ret; + } + + return 0; +} + +static void sun8i_dwmac_core_init(struct mac_device_info *hw, int mtu) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + + v = (8 << EMAC_BURSTLEN_SHIFT); /* burst len */ + writel(v, ioaddr + EMAC_BASIC_CTL1); +} + +static void sun8i_dwmac_set_mac(void __iomem *ioaddr, bool enable) +{ + u32 t, r; + + t = readl(ioaddr + EMAC_TX_CTL0); + r = readl(ioaddr + EMAC_RX_CTL0); + if (enable) { + t |= EMAC_TX_TRANSMITTER_EN; + r |= EMAC_RX_RECEIVER_EN; + } else { + t &= ~EMAC_TX_TRANSMITTER_EN; + r &= ~EMAC_RX_RECEIVER_EN; + } + writel(t, ioaddr + EMAC_TX_CTL0); + writel(r, ioaddr + EMAC_RX_CTL0); +} + +/* Set MAC address at slot reg_n + * All slot > 0 need to be enabled with MAC_ADDR_TYPE_DST + * If addr is NULL, clear the slot + */ +static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw, + unsigned char *addr, + unsigned int reg_n) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + + if (!addr) { + writel(0, ioaddr + EMAC_MACADDR_HI(reg_n)); + return; + } + + stmmac_set_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), + EMAC_MACADDR_LO(reg_n)); + if (reg_n > 0) { + v = readl(ioaddr + EMAC_MACADDR_HI(reg_n)); + v |= MAC_ADDR_TYPE_DST; + writel(v, ioaddr + EMAC_MACADDR_HI(reg_n)); + } +} + +static void sun8i_dwmac_get_umac_addr(struct mac_device_info *hw, + unsigned char *addr, + unsigned int reg_n) +{ + void __iomem *ioaddr = hw->pcsr; + + stmmac_get_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n), + EMAC_MACADDR_LO(reg_n)); +} + +/* caution this function must return non 0 to work */ +static int sun8i_dwmac_rx_ipc_enable(struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + + v = readl(ioaddr + EMAC_RX_CTL0); + v |= EMAC_RX_DO_CRC; + writel(v, ioaddr + EMAC_RX_CTL0); + + return 1; +} + +static void sun8i_dwmac_set_filter(struct mac_device_info *hw, + struct net_device *dev) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + int i = 1; + struct netdev_hw_addr *ha; + int macaddrs = netdev_uc_count(dev) + netdev_mc_count(dev) + 1; + + v = EMAC_FRM_FLT_CTL; + + if (dev->flags & IFF_PROMISC) { + v = EMAC_FRM_FLT_RXALL; + } else if (dev->flags & IFF_ALLMULTI) { + v |= EMAC_FRM_FLT_MULTICAST; + } else if (macaddrs <= hw->unicast_filter_entries) { + if (!netdev_mc_empty(dev)) { + netdev_for_each_mc_addr(ha, dev) { + sun8i_dwmac_set_umac_addr(hw, ha->addr, i); + i++; + } + } + if (!netdev_uc_empty(dev)) { + netdev_for_each_uc_addr(ha, dev) { + sun8i_dwmac_set_umac_addr(hw, ha->addr, i); + i++; + } + } + } else { + netdev_info(dev, "Too many address, switching to promiscuous\n"); + v = EMAC_FRM_FLT_RXALL; + } + + /* Disable unused address filter slots */ + while (i < hw->unicast_filter_entries) + sun8i_dwmac_set_umac_addr(hw, NULL, i++); + + writel(v, ioaddr + EMAC_RX_FRM_FLT); +} + +static void sun8i_dwmac_flow_ctrl(struct mac_device_info *hw, + unsigned int duplex, unsigned int fc, + unsigned int pause_time, u32 tx_cnt) +{ + void __iomem *ioaddr = hw->pcsr; + u32 v; + + v = readl(ioaddr + EMAC_RX_CTL0); + if (fc == FLOW_AUTO) + v |= EMAC_RX_FLOW_CTL_EN; + else + v &= ~EMAC_RX_FLOW_CTL_EN; + writel(v, ioaddr + EMAC_RX_CTL0); + + v = readl(ioaddr + EMAC_TX_FLOW_CTL); + if (fc == FLOW_AUTO) + v |= EMAC_TX_FLOW_CTL_EN; + else + v &= ~EMAC_TX_FLOW_CTL_EN; + writel(v, ioaddr + EMAC_TX_FLOW_CTL); +} + +static int sun8i_dwmac_reset(struct stmmac_priv *priv) +{ + u32 v; + int err; + + v = readl(priv->ioaddr + EMAC_BASIC_CTL1); + writel(v | 0x01, priv->ioaddr + EMAC_BASIC_CTL1); + + /* The timeout was previoulsy set to 10ms, but some board (OrangePI0) + * need more if no cable plugged. 100ms seems OK + */ + err = readl_poll_timeout(priv->ioaddr + EMAC_BASIC_CTL1, v, + !(v & 0x01), 100, 100000); + + if (err) { + dev_err(priv->device, "EMAC reset timeout\n"); + return -EFAULT; + } + return 0; +} + +static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) +{ + struct sunxi_priv_data *gmac = priv->plat->bsp_priv; + struct device_node *node = priv->device->of_node; + int ret; + u32 reg, val; + + regmap_read(gmac->regmap, SYSCON_EMAC_REG, &val); + reg = gmac->variant->default_syscon_value; + if (reg != val) + dev_warn(priv->device, + "Current syscon value is not the default %x (expect %x)\n", + val, reg); + + if (gmac->variant->internal_phy) { + if (!gmac->use_internal_phy) { + /* switch to external PHY interface */ + reg &= ~H3_EPHY_SELECT; + } else { + reg |= H3_EPHY_SELECT; + reg &= ~H3_EPHY_SHUTDOWN; + dev_dbg(priv->device, "Select internal_phy %x\n", reg); + + if (of_property_read_bool(priv->plat->phy_node, + "allwinner,leds-active-low")) + reg |= H3_EPHY_LED_POL; + else + reg &= ~H3_EPHY_LED_POL; + + ret = of_mdio_parse_addr(priv->device, + priv->plat->phy_node); + if (ret < 0) { + dev_err(priv->device, "Could not parse MDIO addr\n"); + return ret; + } + /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY + * address. No need to mask it again. + */ + reg |= ret << H3_EPHY_ADDR_SHIFT; + } + } + + if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) { + if (val % 100) { + dev_err(priv->device, "tx-delay must be a multiple of 100\n"); + return -EINVAL; + } + val /= 100; + dev_dbg(priv->device, "set tx-delay to %x\n", val); + if (val <= SYSCON_ETXDC_MASK) { + reg &= ~(SYSCON_ETXDC_MASK << SYSCON_ETXDC_SHIFT); + reg |= (val << SYSCON_ETXDC_SHIFT); + } else { + dev_err(priv->device, "Invalid TX clock delay: %d\n", + val); + return -EINVAL; + } + } + + if (!of_property_read_u32(node, "allwinner,rx-delay-ps", &val)) { + if (val % 100) { + dev_err(priv->device, "rx-delay must be a multiple of 100\n"); + return -EINVAL; + } + val /= 100; + dev_dbg(priv->device, "set rx-delay to %x\n", val); + if (val <= SYSCON_ERXDC_MASK) { + reg &= ~(SYSCON_ERXDC_MASK << SYSCON_ERXDC_SHIFT); + reg |= (val << SYSCON_ERXDC_SHIFT); + } else { + dev_err(priv->device, "Invalid RX clock delay: %d\n", + val); + return -EINVAL; + } + } + + /* Clear interface mode bits */ + reg &= ~(SYSCON_ETCS_MASK | SYSCON_EPIT); + if (gmac->variant->support_rmii) + reg &= ~SYSCON_RMII_EN; + + switch (priv->plat->interface) { + case PHY_INTERFACE_MODE_MII: + /* default */ + break; + case PHY_INTERFACE_MODE_RGMII: + reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII; + break; + case PHY_INTERFACE_MODE_RMII: + reg |= SYSCON_RMII_EN | SYSCON_ETCS_EXT_GMII; + break; + default: + dev_err(priv->device, "Unsupported interface mode: %s", + phy_modes(priv->plat->interface)); + return -EINVAL; + } + + regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg); + + return 0; +} + +static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac) +{ + u32 reg = gmac->variant->default_syscon_value; + + regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg); +} + +static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv) +{ + struct sunxi_priv_data *gmac = priv->plat->bsp_priv; + int ret; + + if (!gmac->use_internal_phy) + return 0; + + ret = clk_prepare_enable(gmac->ephy_clk); + if (ret) { + dev_err(priv->device, "Cannot enable ephy\n"); + return ret; + } + + ret = reset_control_deassert(gmac->rst_ephy); + if (ret) { + dev_err(priv->device, "Cannot deassert ephy\n"); + clk_disable_unprepare(gmac->ephy_clk); + return ret; + } + + return 0; +} + +static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac) +{ + if (!gmac->use_internal_phy) + return 0; + + clk_disable_unprepare(gmac->ephy_clk); + reset_control_assert(gmac->rst_ephy); + return 0; +} + +/* sun8i_power_phy() - Activate the PHY: + * In case of error, no need to call sun8i_unpower_phy(), + * it will be called anyway by sun8i_dwmac_exit() + */ +static int sun8i_power_phy(struct stmmac_priv *priv) +{ + int ret; + + ret = sun8i_dwmac_power_internal_phy(priv); + if (ret) + return ret; + + ret = sun8i_dwmac_set_syscon(priv); + if (ret) + return ret; + + /* After changing syscon value, the MAC need reset or it will use + * the last value (and so the last PHY set. + */ + ret = sun8i_dwmac_reset(priv); + if (ret) + return ret; + return 0; +} + +static void sun8i_unpower_phy(struct sunxi_priv_data *gmac) +{ + sun8i_dwmac_unset_syscon(gmac); + sun8i_dwmac_unpower_internal_phy(gmac); +} + +static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv) +{ + struct sunxi_priv_data *gmac = priv; + + sun8i_unpower_phy(gmac); + + clk_disable_unprepare(gmac->tx_clk); + + if (gmac->regulator) + regulator_disable(gmac->regulator); +} + +static const struct stmmac_ops sun8i_dwmac_ops = { + .core_init = sun8i_dwmac_core_init, + .set_mac = sun8i_dwmac_set_mac, + .dump_regs = sun8i_dwmac_dump_mac_regs, + .rx_ipc = sun8i_dwmac_rx_ipc_enable, + .set_filter = sun8i_dwmac_set_filter, + .flow_ctrl = sun8i_dwmac_flow_ctrl, + .set_umac_addr = sun8i_dwmac_set_umac_addr, + .get_umac_addr = sun8i_dwmac_get_umac_addr, +}; + +static struct mac_device_info *sun8i_dwmac_setup(void *ppriv) +{ + struct mac_device_info *mac; + struct stmmac_priv *priv = ppriv; + int ret; + + mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); + if (!mac) + return NULL; + + ret = sun8i_power_phy(priv); + if (ret) + return NULL; + + mac->pcsr = priv->ioaddr; + mac->mac = &sun8i_dwmac_ops; + mac->dma = &sun8i_dwmac_dma_ops; + + /* The loopback bit seems to be re-set when link change + * Simply mask it each time + * Speed 10/100/1000 are set in BIT(2)/BIT(3) + */ + mac->link.speed_mask = GENMASK(3, 2) | EMAC_LOOPBACK; + mac->link.speed10 = EMAC_SPEED_10; + mac->link.speed100 = EMAC_SPEED_100; + mac->link.speed1000 = EMAC_SPEED_1000; + mac->link.duplex = EMAC_DUPLEX_FULL; + mac->mii.addr = EMAC_MDIO_CMD; + mac->mii.data = EMAC_MDIO_DATA; + mac->mii.reg_shift = 4; + mac->mii.reg_mask = GENMASK(8, 4); + mac->mii.addr_shift = 12; + mac->mii.addr_mask = GENMASK(16, 12); + mac->mii.clk_csr_shift = 20; + mac->mii.clk_csr_mask = GENMASK(22, 20); + mac->unicast_filter_entries = 8; + + /* Synopsys Id is not available */ + priv->synopsys_id = 0; + + return mac; +} + +static int sun8i_dwmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct sunxi_priv_data *gmac; + struct device *dev = &pdev->dev; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); + + gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); + if (!gmac) + return -ENOMEM; + + gmac->variant = of_device_get_match_data(&pdev->dev); + if (!gmac->variant) { + dev_err(&pdev->dev, "Missing dwmac-sun8i variant\n"); + return -EINVAL; + } + + gmac->tx_clk = devm_clk_get(dev, "stmmaceth"); + if (IS_ERR(gmac->tx_clk)) { + dev_err(dev, "Could not get TX clock\n"); + return PTR_ERR(gmac->tx_clk); + } + + /* Optional regulator for PHY */ + gmac->regulator = devm_regulator_get_optional(dev, "phy"); + if (IS_ERR(gmac->regulator)) { + if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_info(dev, "No regulator found\n"); + gmac->regulator = NULL; + } + + gmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "syscon"); + if (IS_ERR(gmac->regmap)) { + ret = PTR_ERR(gmac->regmap); + dev_err(&pdev->dev, "Unable to map syscon: %d\n", ret); + return ret; + } + + plat_dat->interface = of_get_phy_mode(dev->of_node); + if (plat_dat->interface == gmac->variant->internal_phy) { + dev_info(&pdev->dev, "Will use internal PHY\n"); + gmac->use_internal_phy = true; + gmac->ephy_clk = of_clk_get(plat_dat->phy_node, 0); + if (IS_ERR(gmac->ephy_clk)) { + ret = PTR_ERR(gmac->ephy_clk); + dev_err(&pdev->dev, "Cannot get EPHY clock: %d\n", ret); + return -EINVAL; + } + + gmac->rst_ephy = of_reset_control_get(plat_dat->phy_node, NULL); + if (IS_ERR(gmac->rst_ephy)) { + ret = PTR_ERR(gmac->rst_ephy); + if (ret == -EPROBE_DEFER) + return ret; + dev_err(&pdev->dev, "No EPHY reset control found %d\n", + ret); + return -EINVAL; + } + } else { + dev_info(&pdev->dev, "Will use external PHY\n"); + gmac->use_internal_phy = false; + } + + /* platform data specifying hardware features and callbacks. + * hardware features were copied from Allwinner drivers. + */ + plat_dat->rx_coe = STMMAC_RX_COE_TYPE2; + plat_dat->tx_coe = 1; + plat_dat->has_sun8i = true; + plat_dat->bsp_priv = gmac; + plat_dat->init = sun8i_dwmac_init; + plat_dat->exit = sun8i_dwmac_exit; + plat_dat->setup = sun8i_dwmac_setup; + + ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv); + if (ret) + return ret; + + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) + sun8i_dwmac_exit(pdev, plat_dat->bsp_priv); + + return ret; +} + +static const struct of_device_id sun8i_dwmac_match[] = { + { .compatible = "allwinner,sun8i-h3-emac", + .data = &emac_variant_h3 }, + { .compatible = "allwinner,sun8i-a83t-emac", + .data = &emac_variant_a83t }, + { .compatible = "allwinner,sun50i-a64-emac", + .data = &emac_variant_a64 }, + { } +}; +MODULE_DEVICE_TABLE(of, sun8i_dwmac_match); + +static struct platform_driver sun8i_dwmac_driver = { + .probe = sun8i_dwmac_probe, + .remove = stmmac_pltfr_remove, + .driver = { + .name = "dwmac-sun8i", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = sun8i_dwmac_match, + }, +}; +module_platform_driver(sun8i_dwmac_driver); + +MODULE_AUTHOR("Corentin Labbe "); +MODULE_DESCRIPTION("Allwinner sun8i DWMAC specific glue layer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c80c9c3b67db..68a188e74c54 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -235,6 +235,17 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv) else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M)) priv->clk_csr = STMMAC_CSR_250_300M; } + + if (priv->plat->has_sun8i) { + if (clk_rate > 160000000) + priv->clk_csr = 0x03; + else if (clk_rate > 80000000) + priv->clk_csr = 0x02; + else if (clk_rate > 40000000) + priv->clk_csr = 0x01; + else + priv->clk_csr = 0; + } } static void print_pkt(unsigned char *buf, int len) @@ -3955,6 +3966,10 @@ static int stmmac_hw_init(struct stmmac_priv *priv) priv->hw = mac; + /* dwmac-sun8i only work in chain mode */ + if (priv->plat->has_sun8i) + chain_mode = 1; + /* To use the chained or ring mode */ if (priv->synopsys_id >= DWMAC_CORE_4_00) { priv->hw->mode = &dwmac4_ring_mode_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 7fc3a1ef395a..3840529344ed 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -309,6 +309,12 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat, struct device_node *np, struct device *dev) { bool mdio = true; + static const struct of_device_id need_mdio_ids[] = { + { .compatible = "snps,dwc-qos-ethernet-4.10" }, + { .compatible = "allwinner,sun8i-a83t-emac" }, + { .compatible = "allwinner,sun8i-h3-emac" }, + { .compatible = "allwinner,sun50i-a64-emac" }, + }; /* If phy-handle property is passed from DT, use it as the PHY */ plat->phy_node = of_parse_phandle(np, "phy-handle", 0); @@ -325,8 +331,7 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat, mdio = false; } - /* exception for dwmac-dwc-qos-eth glue logic */ - if (of_device_is_compatible(np, "snps,dwc-qos-ethernet-4.10")) { + if (of_match_node(need_mdio_ids, np)) { plat->mdio_node = of_get_child_by_name(np, "mdio"); } else { /** -- cgit v1.2.3 From 0266f79778de0afadd070941aae493c28529d974 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 31 May 2017 21:33:42 +0300 Subject: mlxsw: spectrum: Add bridge dependency for spectrum When BRIDGE is a loadable module, MLXSW_SPECTRUM mustn't be built-in: drivers/built-in.o: In function `mlxsw_sp_bridge_device_create': drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c:145: undefined reference to `br_vlan_enabled' drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c:158: undefined reference to `br_multicast_enabled' drivers/built-in.o: In function `mlxsw_sp_dev_rif_type': drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c:2972: undefined reference to `br_vlan_enabled' drivers/built-in.o: In function `mlxsw_sp_inetaddr_vlan_event': drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c:3310: undefined reference to `br_vlan_enabled' Add Kconfig dependency to enforce usable configurations. Fixes: c57529e1d5d8 ("mlxsw: spectrum: Replace vPorts with Port-VLAN") Signed-off-by: Ido Schimmel Reported-by: Nikolay Aleksandrov Tested-by: Nikolay Aleksandrov Cc: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig index b9f80c2a8ae9..695adff89d71 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig @@ -74,6 +74,7 @@ config MLXSW_SPECTRUM tristate "Mellanox Technologies Spectrum support" depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV && VLAN_8021Q depends on PSAMPLE || PSAMPLE=n + depends on BRIDGE || BRIDGE=n select PARMAN select MLXFW default m -- cgit v1.2.3 From 392908033308892b9da71551a65b4e59c5006b1c Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:08 -0700 Subject: i40evf: drop i40e_type.h include This drops the i40e_type.h include in anticipation of the next patch which moves this file to a location where type.h doesn't exist, and all the places this file is included already include i40e_type.h before this file. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h index b0b8de5d6f57..7d6da3ac24f4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h @@ -27,8 +27,6 @@ #ifndef _I40E_VIRTCHNL_H_ #define _I40E_VIRTCHNL_H_ -#include "i40e_type.h" - /* Description: * This header file describes the VF-PF communication protocol used * by the various i40e drivers. -- cgit v1.2.3 From 681bdf80cff6844f81216b6b05516d82f69c23fd Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:09 -0700 Subject: i40e/i40evf: create and use new unified header file This moves a header for i40evf to include/linux/avf/virtchnl.h. The directory name AVF is an acronym for the Intel(R) Adaptive Virtual Function. This first step creates the new file, which is a rename of drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h to include/linux/avf/virtchnl.h, and should show up in git as a rename when using git log --follow. To keep things building after the move, the changes to the i40evf driver are made to point to the new include file location. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40e_common.c | 2 +- drivers/net/ethernet/intel/i40evf/i40e_prototype.h | 2 +- drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h | 446 --------------------- drivers/net/ethernet/intel/i40evf/i40evf.h | 2 +- 4 files changed, 3 insertions(+), 449 deletions(-) delete mode 100644 drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 6729624fda5b..1db028ac96f4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -27,7 +27,7 @@ #include "i40e_type.h" #include "i40e_adminq.h" #include "i40e_prototype.h" -#include "i40e_virtchnl.h" +#include /** * i40e_set_mac_type - Sets MAC type diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h index 741223d5d809..227905b23690 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h @@ -29,7 +29,7 @@ #include "i40e_type.h" #include "i40e_alloc.h" -#include "i40e_virtchnl.h" +#include /* Prototypes for shared code functions that are not in * the standard function pointer structures. These are diff --git a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h deleted file mode 100644 index 7d6da3ac24f4..000000000000 --- a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h +++ /dev/null @@ -1,446 +0,0 @@ -/******************************************************************************* - * - * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 - 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * e1000-devel Mailing List - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - ******************************************************************************/ - -#ifndef _I40E_VIRTCHNL_H_ -#define _I40E_VIRTCHNL_H_ - -/* Description: - * This header file describes the VF-PF communication protocol used - * by the various i40e drivers. - * - * Admin queue buffer usage: - * desc->opcode is always i40e_aqc_opc_send_msg_to_pf - * flags, retval, datalen, and data addr are all used normally. - * Firmware copies the cookie fields when sending messages between the PF and - * VF, but uses all other fields internally. Due to this limitation, we - * must send all messages as "indirect", i.e. using an external buffer. - * - * All the vsi indexes are relative to the VF. Each VF can have maximum of - * three VSIs. All the queue indexes are relative to the VSI. Each VF can - * have a maximum of sixteen queues for all of its VSIs. - * - * The PF is required to return a status code in v_retval for all messages - * except RESET_VF, which does not require any response. The return value is of - * i40e_status_code type, defined in the i40e_type.h. - * - * In general, VF driver initialization should roughly follow the order of these - * opcodes. The VF driver must first validate the API version of the PF driver, - * then request a reset, then get resources, then configure queues and - * interrupts. After these operations are complete, the VF driver may start - * its queues, optionally add MAC and VLAN filters, and process traffic. - */ - -/* Opcodes for VF-PF communication. These are placed in the v_opcode field - * of the virtchnl_msg structure. - */ -enum i40e_virtchnl_ops { -/* The PF sends status change events to VFs using - * the I40E_VIRTCHNL_OP_EVENT opcode. - * VFs send requests to the PF using the other ops. - */ - I40E_VIRTCHNL_OP_UNKNOWN = 0, - I40E_VIRTCHNL_OP_VERSION = 1, /* must ALWAYS be 1 */ - I40E_VIRTCHNL_OP_RESET_VF = 2, - I40E_VIRTCHNL_OP_GET_VF_RESOURCES = 3, - I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE = 4, - I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE = 5, - I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES = 6, - I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP = 7, - I40E_VIRTCHNL_OP_ENABLE_QUEUES = 8, - I40E_VIRTCHNL_OP_DISABLE_QUEUES = 9, - I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS = 10, - I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS = 11, - I40E_VIRTCHNL_OP_ADD_VLAN = 12, - I40E_VIRTCHNL_OP_DEL_VLAN = 13, - I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE = 14, - I40E_VIRTCHNL_OP_GET_STATS = 15, - I40E_VIRTCHNL_OP_RSVD = 16, - I40E_VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */ - I40E_VIRTCHNL_OP_IWARP = 20, - I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21, - I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP = 22, - I40E_VIRTCHNL_OP_CONFIG_RSS_KEY = 23, - I40E_VIRTCHNL_OP_CONFIG_RSS_LUT = 24, - I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS = 25, - I40E_VIRTCHNL_OP_SET_RSS_HENA = 26, - -}; - -/* Virtual channel message descriptor. This overlays the admin queue - * descriptor. All other data is passed in external buffers. - */ - -struct i40e_virtchnl_msg { - u8 pad[8]; /* AQ flags/opcode/len/retval fields */ - enum i40e_virtchnl_ops v_opcode; /* avoid confusion with desc->opcode */ - i40e_status v_retval; /* ditto for desc->retval */ - u32 vfid; /* used by PF when sending to VF */ -}; - -/* Message descriptions and data structures.*/ - -/* I40E_VIRTCHNL_OP_VERSION - * VF posts its version number to the PF. PF responds with its version number - * in the same format, along with a return code. - * Reply from PF has its major/minor versions also in param0 and param1. - * If there is a major version mismatch, then the VF cannot operate. - * If there is a minor version mismatch, then the VF can operate but should - * add a warning to the system log. - * - * This enum element MUST always be specified as == 1, regardless of other - * changes in the API. The PF must always respond to this message without - * error regardless of version mismatch. - */ -#define I40E_VIRTCHNL_VERSION_MAJOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS 0 - -struct i40e_virtchnl_version_info { - u32 major; - u32 minor; -}; - -/* I40E_VIRTCHNL_OP_RESET_VF - * VF sends this request to PF with no parameters - * PF does NOT respond! VF driver must delay then poll VFGEN_RSTAT register - * until reset completion is indicated. The admin queue must be reinitialized - * after this operation. - * - * When reset is complete, PF must ensure that all queues in all VSIs associated - * with the VF are stopped, all queue configurations in the HMC are set to 0, - * and all MAC and VLAN filters (except the default MAC address) on all VSIs - * are cleared. - */ - -/* I40E_VIRTCHNL_OP_GET_VF_RESOURCES - * Version 1.0 VF sends this request to PF with no parameters - * Version 1.1 VF sends this request to PF with u32 bitmap of its capabilities - * PF responds with an indirect message containing - * i40e_virtchnl_vf_resource and one or more - * i40e_virtchnl_vsi_resource structures. - */ - -struct i40e_virtchnl_vsi_resource { - u16 vsi_id; - u16 num_queue_pairs; - enum i40e_vsi_type vsi_type; - u16 qset_handle; - u8 default_mac_addr[ETH_ALEN]; -}; -/* VF offload flags */ -#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 -#define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 -#define I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR 0x00000020 -#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING 0x00020000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 0x00040000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF 0X00080000 -#define I40E_VIRTCHNL_VF_OFFLOAD_ENCAP 0X00100000 -#define I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM 0X00200000 - -#define I40E_VF_BASE_MODE_OFFLOADS (I40E_VIRTCHNL_VF_OFFLOAD_L2 | \ - I40E_VIRTCHNL_VF_OFFLOAD_VLAN | \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) - -struct i40e_virtchnl_vf_resource { - u16 num_vsis; - u16 num_queue_pairs; - u16 max_vectors; - u16 max_mtu; - - u32 vf_offload_flags; - u32 rss_key_size; - u32 rss_lut_size; - - struct i40e_virtchnl_vsi_resource vsi_res[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE - * VF sends this message to set up parameters for one TX queue. - * External data buffer contains one instance of i40e_virtchnl_txq_info. - * PF configures requested queue and returns a status code. - */ - -/* Tx queue config info */ -struct i40e_virtchnl_txq_info { - u16 vsi_id; - u16 queue_id; - u16 ring_len; /* number of descriptors, multiple of 8 */ - u16 headwb_enabled; - u64 dma_ring_addr; - u64 dma_headwb_addr; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE - * VF sends this message to set up parameters for one RX queue. - * External data buffer contains one instance of i40e_virtchnl_rxq_info. - * PF configures requested queue and returns a status code. - */ - -/* Rx queue config info */ -struct i40e_virtchnl_rxq_info { - u16 vsi_id; - u16 queue_id; - u32 ring_len; /* number of descriptors, multiple of 32 */ - u16 hdr_size; - u16 splithdr_enabled; - u32 databuffer_size; - u32 max_pkt_size; - u64 dma_ring_addr; - enum i40e_hmc_obj_rx_hsplit_0 rx_split_pos; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES - * VF sends this message to set parameters for all active TX and RX queues - * associated with the specified VSI. - * PF configures queues and returns status. - * If the number of queues specified is greater than the number of queues - * associated with the VSI, an error is returned and no queues are configured. - */ -struct i40e_virtchnl_queue_pair_info { - /* NOTE: vsi_id and queue_id should be identical for both queues. */ - struct i40e_virtchnl_txq_info txq; - struct i40e_virtchnl_rxq_info rxq; -}; - -struct i40e_virtchnl_vsi_queue_config_info { - u16 vsi_id; - u16 num_queue_pairs; - struct i40e_virtchnl_queue_pair_info qpair[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP - * VF uses this message to map vectors to queues. - * The rxq_map and txq_map fields are bitmaps used to indicate which queues - * are to be associated with the specified vector. - * The "other" causes are always mapped to vector 0. - * PF configures interrupt mapping and returns status. - */ -struct i40e_virtchnl_vector_map { - u16 vsi_id; - u16 vector_id; - u16 rxq_map; - u16 txq_map; - u16 rxitr_idx; - u16 txitr_idx; -}; - -struct i40e_virtchnl_irq_map_info { - u16 num_vectors; - struct i40e_virtchnl_vector_map vecmap[1]; -}; - -/* I40E_VIRTCHNL_OP_ENABLE_QUEUES - * I40E_VIRTCHNL_OP_DISABLE_QUEUES - * VF sends these message to enable or disable TX/RX queue pairs. - * The queues fields are bitmaps indicating which queues to act upon. - * (Currently, we only support 16 queues per VF, but we make the field - * u32 to allow for expansion.) - * PF performs requested action and returns status. - */ -struct i40e_virtchnl_queue_select { - u16 vsi_id; - u16 pad; - u32 rx_queues; - u32 tx_queues; -}; - -/* I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS - * VF sends this message in order to add one or more unicast or multicast - * address filters for the specified VSI. - * PF adds the filters and returns status. - */ - -/* I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS - * VF sends this message in order to remove one or more unicast or multicast - * filters for the specified VSI. - * PF removes the filters and returns status. - */ - -struct i40e_virtchnl_ether_addr { - u8 addr[ETH_ALEN]; - u8 pad[2]; -}; - -struct i40e_virtchnl_ether_addr_list { - u16 vsi_id; - u16 num_elements; - struct i40e_virtchnl_ether_addr list[1]; -}; - -/* I40E_VIRTCHNL_OP_ADD_VLAN - * VF sends this message to add one or more VLAN tag filters for receives. - * PF adds the filters and returns status. - * If a port VLAN is configured by the PF, this operation will return an - * error to the VF. - */ - -/* I40E_VIRTCHNL_OP_DEL_VLAN - * VF sends this message to remove one or more VLAN tag filters for receives. - * PF removes the filters and returns status. - * If a port VLAN is configured by the PF, this operation will return an - * error to the VF. - */ - -struct i40e_virtchnl_vlan_filter_list { - u16 vsi_id; - u16 num_elements; - u16 vlan_id[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE - * VF sends VSI id and flags. - * PF returns status code in retval. - * Note: we assume that broadcast accept mode is always enabled. - */ -struct i40e_virtchnl_promisc_info { - u16 vsi_id; - u16 flags; -}; - -#define I40E_FLAG_VF_UNICAST_PROMISC 0x00000001 -#define I40E_FLAG_VF_MULTICAST_PROMISC 0x00000002 - -/* I40E_VIRTCHNL_OP_GET_STATS - * VF sends this message to request stats for the selected VSI. VF uses - * the i40e_virtchnl_queue_select struct to specify the VSI. The queue_id - * field is ignored by the PF. - * - * PF replies with struct i40e_eth_stats in an external buffer. - */ - -/* I40E_VIRTCHNL_OP_CONFIG_RSS_KEY - * I40E_VIRTCHNL_OP_CONFIG_RSS_LUT - * VF sends these messages to configure RSS. Only supported if both PF - * and VF drivers set the I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF bit during - * configuration negotiation. If this is the case, then the RSS fields in - * the VF resource struct are valid. - * Both the key and LUT are initialized to 0 by the PF, meaning that - * RSS is effectively disabled until set up by the VF. - */ -struct i40e_virtchnl_rss_key { - u16 vsi_id; - u16 key_len; - u8 key[1]; /* RSS hash key, packed bytes */ -}; - -struct i40e_virtchnl_rss_lut { - u16 vsi_id; - u16 lut_entries; - u8 lut[1]; /* RSS lookup table*/ -}; - -/* I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS - * I40E_VIRTCHNL_OP_SET_RSS_HENA - * VF sends these messages to get and set the hash filter enable bits for RSS. - * By default, the PF sets these to all possible traffic types that the - * hardware supports. The VF can query this value if it wants to change the - * traffic types that are hashed by the hardware. - * Traffic types are defined in the i40e_filter_pctype enum in i40e_type.h - */ -struct i40e_virtchnl_rss_hena { - u64 hena; -}; - -/* I40E_VIRTCHNL_OP_EVENT - * PF sends this message to inform the VF driver of events that may affect it. - * No direct response is expected from the VF, though it may generate other - * messages in response to this one. - */ -enum i40e_virtchnl_event_codes { - I40E_VIRTCHNL_EVENT_UNKNOWN = 0, - I40E_VIRTCHNL_EVENT_LINK_CHANGE, - I40E_VIRTCHNL_EVENT_RESET_IMPENDING, - I40E_VIRTCHNL_EVENT_PF_DRIVER_CLOSE, -}; -#define I40E_PF_EVENT_SEVERITY_INFO 0 -#define I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM 255 - -struct i40e_virtchnl_pf_event { - enum i40e_virtchnl_event_codes event; - union { - struct { - enum i40e_aq_link_speed link_speed; - bool link_status; - } link_event; - } event_data; - - int severity; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP - * VF uses this message to request PF to map IWARP vectors to IWARP queues. - * The request for this originates from the VF IWARP driver through - * a client interface between VF LAN and VF IWARP driver. - * A vector could have an AEQ and CEQ attached to it although - * there is a single AEQ per VF IWARP instance in which case - * most vectors will have an INVALID_IDX for aeq and valid idx for ceq. - * There will never be a case where there will be multiple CEQs attached - * to a single vector. - * PF configures interrupt mapping and returns status. - */ - -/* HW does not define a type value for AEQ; only for RX/TX and CEQ. - * In order for us to keep the interface simple, SW will define a - * unique type value for AEQ. - */ -#define I40E_QUEUE_TYPE_PE_AEQ 0x80 -#define I40E_QUEUE_INVALID_IDX 0xFFFF - -struct i40e_virtchnl_iwarp_qv_info { - u32 v_idx; /* msix_vector */ - u16 ceq_idx; - u16 aeq_idx; - u8 itr_idx; -}; - -struct i40e_virtchnl_iwarp_qvlist_info { - u32 num_vectors; - struct i40e_virtchnl_iwarp_qv_info qv_info[1]; -}; - -/* VF reset states - these are written into the RSTAT register: - * I40E_VFGEN_RSTAT1 on the PF - * I40E_VFGEN_RSTAT on the VF - * When the PF initiates a reset, it writes 0 - * When the reset is complete, it writes 1 - * When the PF detects that the VF has recovered, it writes 2 - * VF checks this register periodically to determine if a reset has occurred, - * then polls it to know when the reset is complete. - * If either the PF or VF reads the register while the hardware - * is in a reset state, it will return DEADBEEF, which, when masked - * will result in 3. - */ -enum i40e_vfr_states { - I40E_VFR_INPROGRESS = 0, - I40E_VFR_COMPLETED, - I40E_VFR_VFACTIVE, - I40E_VFR_UNKNOWN, -}; - -#endif /* _I40E_VIRTCHNL_H_ */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index b8ada6d8d890..75d314b1a9bb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -43,7 +43,7 @@ #include #include "i40e_type.h" -#include "i40e_virtchnl.h" +#include #include "i40e_txrx.h" #define DEFAULT_DEBUG_LEVEL_SHIFT 3 -- cgit v1.2.3 From 55cdfd48f217533d2eef3e68ccc5b7af098e8640 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:10 -0700 Subject: i40e: use new unified virtchnl header file This patch changes the i40e driver to start using the new virtchnl interface header file, and removes an already existing duplicate of the i40e_virtchnl.h file contained in the i40e directory. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 2 +- drivers/net/ethernet/intel/i40e/i40e_common.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_prototype.h | 2 +- drivers/net/ethernet/intel/i40e/i40e_virtchnl.h | 449 ----------------------- 4 files changed, 3 insertions(+), 452 deletions(-) delete mode 100644 drivers/net/ethernet/intel/i40e/i40e_virtchnl.h (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 25bf336c5f38..60dc9b2c19ff 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -57,7 +57,7 @@ #include "i40e_type.h" #include "i40e_prototype.h" #include "i40e_client.h" -#include "i40e_virtchnl.h" +#include #include "i40e_virtchnl_pf.h" #include "i40e_txrx.h" #include "i40e_dcb.h" diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 24f020655291..cbad4eba7ae7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -27,7 +27,7 @@ #include "i40e_type.h" #include "i40e_adminq.h" #include "i40e_prototype.h" -#include "i40e_virtchnl.h" +#include /** * i40e_set_mac_type - Sets MAC type diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index c56d976cf85a..d9c555050e64 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -29,7 +29,7 @@ #include "i40e_type.h" #include "i40e_alloc.h" -#include "i40e_virtchnl.h" +#include /* Prototypes for shared code functions that are not in * the standard function pointer structures. These are diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h deleted file mode 100644 index 8552192a5bde..000000000000 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h +++ /dev/null @@ -1,449 +0,0 @@ -/******************************************************************************* - * - * Intel Ethernet Controller XL710 Family Linux Driver - * Copyright(c) 2013 - 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * e1000-devel Mailing List - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - ******************************************************************************/ - -#ifndef _I40E_VIRTCHNL_H_ -#define _I40E_VIRTCHNL_H_ - -#include "i40e_type.h" - -/* Description: - * This header file describes the VF-PF communication protocol used - * by the various i40e drivers. - * - * Admin queue buffer usage: - * desc->opcode is always i40e_aqc_opc_send_msg_to_pf - * flags, retval, datalen, and data addr are all used normally. - * Firmware copies the cookie fields when sending messages between the PF and - * VF, but uses all other fields internally. Due to this limitation, we - * must send all messages as "indirect", i.e. using an external buffer. - * - * All the vsi indexes are relative to the VF. Each VF can have maximum of - * three VSIs. All the queue indexes are relative to the VSI. Each VF can - * have a maximum of sixteen queues for all of its VSIs. - * - * The PF is required to return a status code in v_retval for all messages - * except RESET_VF, which does not require any response. The return value is of - * i40e_status_code type, defined in the i40e_type.h. - * - * In general, VF driver initialization should roughly follow the order of these - * opcodes. The VF driver must first validate the API version of the PF driver, - * then request a reset, then get resources, then configure queues and - * interrupts. After these operations are complete, the VF driver may start - * its queues, optionally add MAC and VLAN filters, and process traffic. - */ - -/* Opcodes for VF-PF communication. These are placed in the v_opcode field - * of the virtchnl_msg structure. - */ -enum i40e_virtchnl_ops { -/* The PF sends status change events to VFs using - * the I40E_VIRTCHNL_OP_EVENT opcode. - * VFs send requests to the PF using the other ops. - */ - I40E_VIRTCHNL_OP_UNKNOWN = 0, - I40E_VIRTCHNL_OP_VERSION = 1, /* must ALWAYS be 1 */ - I40E_VIRTCHNL_OP_RESET_VF = 2, - I40E_VIRTCHNL_OP_GET_VF_RESOURCES = 3, - I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE = 4, - I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE = 5, - I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES = 6, - I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP = 7, - I40E_VIRTCHNL_OP_ENABLE_QUEUES = 8, - I40E_VIRTCHNL_OP_DISABLE_QUEUES = 9, - I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS = 10, - I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS = 11, - I40E_VIRTCHNL_OP_ADD_VLAN = 12, - I40E_VIRTCHNL_OP_DEL_VLAN = 13, - I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE = 14, - I40E_VIRTCHNL_OP_GET_STATS = 15, - I40E_VIRTCHNL_OP_FCOE = 16, - I40E_VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */ - I40E_VIRTCHNL_OP_IWARP = 20, - I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21, - I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP = 22, - I40E_VIRTCHNL_OP_CONFIG_RSS_KEY = 23, - I40E_VIRTCHNL_OP_CONFIG_RSS_LUT = 24, - I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS = 25, - I40E_VIRTCHNL_OP_SET_RSS_HENA = 26, - -}; - -/* Virtual channel message descriptor. This overlays the admin queue - * descriptor. All other data is passed in external buffers. - */ - -struct i40e_virtchnl_msg { - u8 pad[8]; /* AQ flags/opcode/len/retval fields */ - enum i40e_virtchnl_ops v_opcode; /* avoid confusion with desc->opcode */ - i40e_status v_retval; /* ditto for desc->retval */ - u32 vfid; /* used by PF when sending to VF */ -}; - -/* Message descriptions and data structures.*/ - -/* I40E_VIRTCHNL_OP_VERSION - * VF posts its version number to the PF. PF responds with its version number - * in the same format, along with a return code. - * Reply from PF has its major/minor versions also in param0 and param1. - * If there is a major version mismatch, then the VF cannot operate. - * If there is a minor version mismatch, then the VF can operate but should - * add a warning to the system log. - * - * This enum element MUST always be specified as == 1, regardless of other - * changes in the API. The PF must always respond to this message without - * error regardless of version mismatch. - */ -#define I40E_VIRTCHNL_VERSION_MAJOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS 0 - -struct i40e_virtchnl_version_info { - u32 major; - u32 minor; -}; - -/* I40E_VIRTCHNL_OP_RESET_VF - * VF sends this request to PF with no parameters - * PF does NOT respond! VF driver must delay then poll VFGEN_RSTAT register - * until reset completion is indicated. The admin queue must be reinitialized - * after this operation. - * - * When reset is complete, PF must ensure that all queues in all VSIs associated - * with the VF are stopped, all queue configurations in the HMC are set to 0, - * and all MAC and VLAN filters (except the default MAC address) on all VSIs - * are cleared. - */ - -/* I40E_VIRTCHNL_OP_GET_VF_RESOURCES - * Version 1.0 VF sends this request to PF with no parameters - * Version 1.1 VF sends this request to PF with u32 bitmap of its capabilities - * PF responds with an indirect message containing - * i40e_virtchnl_vf_resource and one or more - * i40e_virtchnl_vsi_resource structures. - */ - -struct i40e_virtchnl_vsi_resource { - u16 vsi_id; - u16 num_queue_pairs; - enum i40e_vsi_type vsi_type; - u16 qset_handle; - u8 default_mac_addr[ETH_ALEN]; -}; -/* VF offload flags */ -#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 -#define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002 -#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 -#define I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR 0x00000020 -#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING 0x00020000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 0x00040000 -#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF 0X00080000 -#define I40E_VIRTCHNL_VF_OFFLOAD_ENCAP 0X00100000 -#define I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM 0X00200000 - -#define I40E_VF_BASE_MODE_OFFLOADS (I40E_VIRTCHNL_VF_OFFLOAD_L2 | \ - I40E_VIRTCHNL_VF_OFFLOAD_VLAN | \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) - -struct i40e_virtchnl_vf_resource { - u16 num_vsis; - u16 num_queue_pairs; - u16 max_vectors; - u16 max_mtu; - - u32 vf_offload_flags; - u32 rss_key_size; - u32 rss_lut_size; - - struct i40e_virtchnl_vsi_resource vsi_res[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE - * VF sends this message to set up parameters for one TX queue. - * External data buffer contains one instance of i40e_virtchnl_txq_info. - * PF configures requested queue and returns a status code. - */ - -/* Tx queue config info */ -struct i40e_virtchnl_txq_info { - u16 vsi_id; - u16 queue_id; - u16 ring_len; /* number of descriptors, multiple of 8 */ - u16 headwb_enabled; - u64 dma_ring_addr; - u64 dma_headwb_addr; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE - * VF sends this message to set up parameters for one RX queue. - * External data buffer contains one instance of i40e_virtchnl_rxq_info. - * PF configures requested queue and returns a status code. - */ - -/* Rx queue config info */ -struct i40e_virtchnl_rxq_info { - u16 vsi_id; - u16 queue_id; - u32 ring_len; /* number of descriptors, multiple of 32 */ - u16 hdr_size; - u16 splithdr_enabled; - u32 databuffer_size; - u32 max_pkt_size; - u64 dma_ring_addr; - enum i40e_hmc_obj_rx_hsplit_0 rx_split_pos; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES - * VF sends this message to set parameters for all active TX and RX queues - * associated with the specified VSI. - * PF configures queues and returns status. - * If the number of queues specified is greater than the number of queues - * associated with the VSI, an error is returned and no queues are configured. - */ -struct i40e_virtchnl_queue_pair_info { - /* NOTE: vsi_id and queue_id should be identical for both queues. */ - struct i40e_virtchnl_txq_info txq; - struct i40e_virtchnl_rxq_info rxq; -}; - -struct i40e_virtchnl_vsi_queue_config_info { - u16 vsi_id; - u16 num_queue_pairs; - struct i40e_virtchnl_queue_pair_info qpair[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP - * VF uses this message to map vectors to queues. - * The rxq_map and txq_map fields are bitmaps used to indicate which queues - * are to be associated with the specified vector. - * The "other" causes are always mapped to vector 0. - * PF configures interrupt mapping and returns status. - */ -struct i40e_virtchnl_vector_map { - u16 vsi_id; - u16 vector_id; - u16 rxq_map; - u16 txq_map; - u16 rxitr_idx; - u16 txitr_idx; -}; - -struct i40e_virtchnl_irq_map_info { - u16 num_vectors; - struct i40e_virtchnl_vector_map vecmap[1]; -}; - -/* I40E_VIRTCHNL_OP_ENABLE_QUEUES - * I40E_VIRTCHNL_OP_DISABLE_QUEUES - * VF sends these message to enable or disable TX/RX queue pairs. - * The queues fields are bitmaps indicating which queues to act upon. - * (Currently, we only support 16 queues per VF, but we make the field - * u32 to allow for expansion.) - * PF performs requested action and returns status. - */ -struct i40e_virtchnl_queue_select { - u16 vsi_id; - u16 pad; - u32 rx_queues; - u32 tx_queues; -}; - -/* I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS - * VF sends this message in order to add one or more unicast or multicast - * address filters for the specified VSI. - * PF adds the filters and returns status. - */ - -/* I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS - * VF sends this message in order to remove one or more unicast or multicast - * filters for the specified VSI. - * PF removes the filters and returns status. - */ - -struct i40e_virtchnl_ether_addr { - u8 addr[ETH_ALEN]; - u8 pad[2]; -}; - -struct i40e_virtchnl_ether_addr_list { - u16 vsi_id; - u16 num_elements; - struct i40e_virtchnl_ether_addr list[1]; -}; - -/* I40E_VIRTCHNL_OP_ADD_VLAN - * VF sends this message to add one or more VLAN tag filters for receives. - * PF adds the filters and returns status. - * If a port VLAN is configured by the PF, this operation will return an - * error to the VF. - */ - -/* I40E_VIRTCHNL_OP_DEL_VLAN - * VF sends this message to remove one or more VLAN tag filters for receives. - * PF removes the filters and returns status. - * If a port VLAN is configured by the PF, this operation will return an - * error to the VF. - */ - -struct i40e_virtchnl_vlan_filter_list { - u16 vsi_id; - u16 num_elements; - u16 vlan_id[1]; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE - * VF sends VSI id and flags. - * PF returns status code in retval. - * Note: we assume that broadcast accept mode is always enabled. - */ -struct i40e_virtchnl_promisc_info { - u16 vsi_id; - u16 flags; -}; - -#define I40E_FLAG_VF_UNICAST_PROMISC 0x00000001 -#define I40E_FLAG_VF_MULTICAST_PROMISC 0x00000002 - -/* I40E_VIRTCHNL_OP_GET_STATS - * VF sends this message to request stats for the selected VSI. VF uses - * the i40e_virtchnl_queue_select struct to specify the VSI. The queue_id - * field is ignored by the PF. - * - * PF replies with struct i40e_eth_stats in an external buffer. - */ - -/* I40E_VIRTCHNL_OP_CONFIG_RSS_KEY - * I40E_VIRTCHNL_OP_CONFIG_RSS_LUT - * VF sends these messages to configure RSS. Only supported if both PF - * and VF drivers set the I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF bit during - * configuration negotiation. If this is the case, then the RSS fields in - * the VF resource struct are valid. - * Both the key and LUT are initialized to 0 by the PF, meaning that - * RSS is effectively disabled until set up by the VF. - */ -struct i40e_virtchnl_rss_key { - u16 vsi_id; - u16 key_len; - u8 key[1]; /* RSS hash key, packed bytes */ -}; - -struct i40e_virtchnl_rss_lut { - u16 vsi_id; - u16 lut_entries; - u8 lut[1]; /* RSS lookup table*/ -}; - -/* I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS - * I40E_VIRTCHNL_OP_SET_RSS_HENA - * VF sends these messages to get and set the hash filter enable bits for RSS. - * By default, the PF sets these to all possible traffic types that the - * hardware supports. The VF can query this value if it wants to change the - * traffic types that are hashed by the hardware. - * Traffic types are defined in the i40e_filter_pctype enum in i40e_type.h - */ -struct i40e_virtchnl_rss_hena { - u64 hena; -}; - -/* I40E_VIRTCHNL_OP_EVENT - * PF sends this message to inform the VF driver of events that may affect it. - * No direct response is expected from the VF, though it may generate other - * messages in response to this one. - */ -enum i40e_virtchnl_event_codes { - I40E_VIRTCHNL_EVENT_UNKNOWN = 0, - I40E_VIRTCHNL_EVENT_LINK_CHANGE, - I40E_VIRTCHNL_EVENT_RESET_IMPENDING, - I40E_VIRTCHNL_EVENT_PF_DRIVER_CLOSE, -}; -#define I40E_PF_EVENT_SEVERITY_INFO 0 -#define I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM 255 - -struct i40e_virtchnl_pf_event { - enum i40e_virtchnl_event_codes event; - union { - struct { - enum i40e_aq_link_speed link_speed; - bool link_status; - } link_event; - } event_data; - - int severity; -}; - -/* I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP - * VF uses this message to request PF to map IWARP vectors to IWARP queues. - * The request for this originates from the VF IWARP driver through - * a client interface between VF LAN and VF IWARP driver. - * A vector could have an AEQ and CEQ attached to it although - * there is a single AEQ per VF IWARP instance in which case - * most vectors will have an INVALID_IDX for aeq and valid idx for ceq. - * There will never be a case where there will be multiple CEQs attached - * to a single vector. - * PF configures interrupt mapping and returns status. - */ - -/* HW does not define a type value for AEQ; only for RX/TX and CEQ. - * In order for us to keep the interface simple, SW will define a - * unique type value for AEQ. -*/ -#define I40E_QUEUE_TYPE_PE_AEQ 0x80 -#define I40E_QUEUE_INVALID_IDX 0xFFFF - -struct i40e_virtchnl_iwarp_qv_info { - u32 v_idx; /* msix_vector */ - u16 ceq_idx; - u16 aeq_idx; - u8 itr_idx; -}; - -struct i40e_virtchnl_iwarp_qvlist_info { - u32 num_vectors; - struct i40e_virtchnl_iwarp_qv_info qv_info[1]; -}; - -/* VF reset states - these are written into the RSTAT register: - * I40E_VFGEN_RSTAT1 on the PF - * I40E_VFGEN_RSTAT on the VF - * When the PF initiates a reset, it writes 0 - * When the reset is complete, it writes 1 - * When the PF detects that the VF has recovered, it writes 2 - * VF checks this register periodically to determine if a reset has occurred, - * then polls it to know when the reset is complete. - * If either the PF or VF reads the register while the hardware - * is in a reset state, it will return DEADBEEF, which, when masked - * will result in 3. - */ -enum i40e_vfr_states { - I40E_VFR_INPROGRESS = 0, - I40E_VFR_COMPLETED, - I40E_VFR_VFACTIVE, - I40E_VFR_UNKNOWN, -}; - -#endif /* _I40E_VIRTCHNL_H_ */ -- cgit v1.2.3 From 310a2ad92e3fd9139e3641464f1de113fa89825b Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:11 -0700 Subject: virtchnl: rename i40e to generic virtchnl This morphs all the i40e and i40evf references to/in virtchnl.h to be generic, using only automated methods. Updates all the callers to use the new names. A followup patch provides separate clean ups for messy line conversions from these "automatic" changes, to make them more reviewable. Was executed with the following sed script: sed -i -f transform_script drivers/net/ethernet/intel/i40e/i40e_client.c sed -i -f transform_script drivers/net/ethernet/intel/i40e/i40e_prototype.h sed -i -f transform_script drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c sed -i -f transform_script drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h sed -i -f transform_script drivers/net/ethernet/intel/i40evf/i40e_common.c sed -i -f transform_script drivers/net/ethernet/intel/i40evf/i40e_prototype.h sed -i -f transform_script drivers/net/ethernet/intel/i40evf/i40evf.h sed -i -f transform_script drivers/net/ethernet/intel/i40evf/i40evf_client.c sed -i -f transform_script drivers/net/ethernet/intel/i40evf/i40evf_main.c sed -i -f transform_script drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c sed -i -f transform_script include/linux/avf/virtchnl.h transform_script: ----8<---- s/I40E_VIRTCHNL_SUPPORTED_QTYPES/SAVE_ME_SUPPORTED_QTYPES/g s/I40E_VIRTCHNL_VF_CAP/SAVE_ME_VF_CAP/g s/I40E_VIRTCHNL_/VIRTCHNL_/g s/i40e_virtchnl_/virtchnl_/g s/i40e_vfr_/virtchnl_vfr_/g s/I40E_VFR_/VIRTCHNL_VFR_/g s/VIRTCHNL_OP_ADD_ETHER_ADDRESS/VIRTCHNL_OP_ADD_ETH_ADDR/g s/VIRTCHNL_OP_DEL_ETHER_ADDRESS/VIRTCHNL_OP_DEL_ETH_ADDR/g s/VIRTCHNL_OP_FCOE/VIRTCHNL_OP_RSVD/g s/SAVE_ME_SUPPORTED_QTYPES/I40E_VIRTCHNL_SUPPORTED_QTYPES/g s/SAVE_ME_VF_CAP/I40E_VIRTCHNL_VF_CAP/g ----8<---- Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_client.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_prototype.h | 4 +- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 370 ++++++++++----------- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 6 +- drivers/net/ethernet/intel/i40evf/i40e_common.c | 10 +- drivers/net/ethernet/intel/i40evf/i40e_prototype.h | 4 +- drivers/net/ethernet/intel/i40evf/i40evf.h | 22 +- drivers/net/ethernet/intel/i40evf/i40evf_client.c | 18 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 48 +-- .../net/ethernet/intel/i40evf/i40evf_virtchnl.c | 280 ++++++++-------- 10 files changed, 382 insertions(+), 382 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_client.c b/drivers/net/ethernet/intel/i40e/i40e_client.c index 088b4a43bd2a..36f694ccdc09 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_client.c +++ b/drivers/net/ethernet/intel/i40e/i40e_client.c @@ -565,7 +565,7 @@ static int i40e_client_virtchnl_send(struct i40e_info *ldev, struct i40e_hw *hw = &pf->hw; i40e_status err; - err = i40e_aq_send_msg_to_vf(hw, vf_id, I40E_VIRTCHNL_OP_IWARP, + err = i40e_aq_send_msg_to_vf(hw, vf_id, VIRTCHNL_OP_IWARP, 0, msg, len, NULL); if (err) dev_err(&pf->pdev->dev, "Unable to send iWarp message to VF, error %d, aq status %d\n", diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index d9c555050e64..df613ea40313 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -333,10 +333,10 @@ static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) /* i40e_common for VF drivers*/ void i40e_vf_parse_hw_config(struct i40e_hw *hw, - struct i40e_virtchnl_vf_resource *msg); + struct virtchnl_vf_resource *msg); i40e_status i40e_vf_reset(struct i40e_hw *hw); i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 95c23fbaa211..9f361e810990 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -39,7 +39,7 @@ * send a message to all VFs on a given PF **/ static void i40e_vc_vf_broadcast(struct i40e_pf *pf, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen) { @@ -70,13 +70,13 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf, **/ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf) { - struct i40e_virtchnl_pf_event pfe; + struct virtchnl_pf_event pfe; struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; struct i40e_link_status *ls = &pf->hw.phy.link_info; int abs_vf_id = vf->vf_id + (int)hw->func_caps.vf_base_id; - pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE; + pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; pfe.severity = I40E_PF_EVENT_SEVERITY_INFO; if (vf->link_forced) { pfe.event_data.link_event.link_status = vf->link_up; @@ -87,7 +87,7 @@ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf) ls->link_info & I40E_AQ_LINK_UP; pfe.event_data.link_event.link_speed = ls->link_speed; } - i40e_aq_send_msg_to_vf(hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, + i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(pfe), NULL); } @@ -113,12 +113,12 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf) **/ void i40e_vc_notify_reset(struct i40e_pf *pf) { - struct i40e_virtchnl_pf_event pfe; + struct virtchnl_pf_event pfe; - pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING; + pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM; - i40e_vc_vf_broadcast(pf, I40E_VIRTCHNL_OP_EVENT, 0, - (u8 *)&pfe, sizeof(struct i40e_virtchnl_pf_event)); + i40e_vc_vf_broadcast(pf, VIRTCHNL_OP_EVENT, 0, + (u8 *)&pfe, sizeof(struct virtchnl_pf_event)); } /** @@ -129,7 +129,7 @@ void i40e_vc_notify_reset(struct i40e_pf *pf) **/ void i40e_vc_notify_vf_reset(struct i40e_vf *vf) { - struct i40e_virtchnl_pf_event pfe; + struct virtchnl_pf_event pfe; int abs_vf_id; /* validate the request */ @@ -143,11 +143,11 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf) abs_vf_id = vf->vf_id + (int)vf->pf->hw.func_caps.vf_base_id; - pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING; + pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM; - i40e_aq_send_msg_to_vf(&vf->pf->hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, + i40e_aq_send_msg_to_vf(&vf->pf->hw, abs_vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, - sizeof(struct i40e_virtchnl_pf_event), NULL); + sizeof(struct virtchnl_pf_event), NULL); } /***********************misc routines*****************************/ @@ -250,7 +250,7 @@ static u16 i40e_vc_get_pf_queue_id(struct i40e_vf *vf, u16 vsi_id, * configure irq link list from the map **/ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, - struct i40e_virtchnl_vector_map *vecmap) + struct virtchnl_vector_map *vecmap) { unsigned long linklistmap = 0, tempmap; struct i40e_pf *pf = vf->pf; @@ -338,7 +338,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, /* if the vf is running in polling mode and using interrupt zero, * need to disable auto-mask on enabling zero interrupt for VFs. */ - if ((vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING) && + if ((vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) && (vector_id == 0)) { reg = rd32(hw, I40E_GLINT_CTL); if (!(reg & I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK)) { @@ -359,7 +359,7 @@ irq_list_done: static void i40e_release_iwarp_qvlist(struct i40e_vf *vf) { struct i40e_pf *pf = vf->pf; - struct i40e_virtchnl_iwarp_qvlist_info *qvlist_info = vf->qvlist_info; + struct virtchnl_iwarp_qvlist_info *qvlist_info = vf->qvlist_info; u32 msix_vf; u32 i; @@ -368,7 +368,7 @@ static void i40e_release_iwarp_qvlist(struct i40e_vf *vf) msix_vf = pf->hw.func_caps.num_msix_vectors_vf; for (i = 0; i < qvlist_info->num_vectors; i++) { - struct i40e_virtchnl_iwarp_qv_info *qv_info; + struct virtchnl_iwarp_qv_info *qv_info; u32 next_q_index, next_q_type; struct i40e_hw *hw = &pf->hw; u32 v_idx, reg_idx, reg; @@ -409,17 +409,17 @@ static void i40e_release_iwarp_qvlist(struct i40e_vf *vf) * Return 0 on success or < 0 on error **/ static int i40e_config_iwarp_qvlist(struct i40e_vf *vf, - struct i40e_virtchnl_iwarp_qvlist_info *qvlist_info) + struct virtchnl_iwarp_qvlist_info *qvlist_info) { struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; - struct i40e_virtchnl_iwarp_qv_info *qv_info; + struct virtchnl_iwarp_qv_info *qv_info; u32 v_idx, i, reg_idx, reg; u32 next_q_idx, next_q_type; u32 msix_vf, size; - size = sizeof(struct i40e_virtchnl_iwarp_qvlist_info) + - (sizeof(struct i40e_virtchnl_iwarp_qv_info) * + size = sizeof(struct virtchnl_iwarp_qvlist_info) + + (sizeof(struct virtchnl_iwarp_qv_info) * (qvlist_info->num_vectors - 1)); vf->qvlist_info = kzalloc(size, GFP_KERNEL); vf->qvlist_info->num_vectors = qvlist_info->num_vectors; @@ -492,7 +492,7 @@ err: **/ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id, u16 vsi_queue_id, - struct i40e_virtchnl_txq_info *info) + struct virtchnl_txq_info *info) { struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; @@ -569,7 +569,7 @@ error_context: **/ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id, u16 vsi_queue_id, - struct i40e_virtchnl_rxq_info *info) + struct virtchnl_rxq_info *info) { struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; @@ -1017,7 +1017,7 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf) * after VF has been fully initialized, because the VF driver may * request resources immediately after setting this flag. */ - wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE); + wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), VIRTCHNL_VFR_VFACTIVE); } /** @@ -1461,7 +1461,7 @@ static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode, * send resp msg to VF **/ static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf, - enum i40e_virtchnl_ops opcode, + enum virtchnl_ops opcode, i40e_status retval) { return i40e_vc_send_msg_to_vf(vf, opcode, retval, NULL, 0); @@ -1475,18 +1475,18 @@ static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf, **/ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) { - struct i40e_virtchnl_version_info info = { - I40E_VIRTCHNL_VERSION_MAJOR, I40E_VIRTCHNL_VERSION_MINOR + struct virtchnl_version_info info = { + VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR }; - vf->vf_ver = *(struct i40e_virtchnl_version_info *)msg; + vf->vf_ver = *(struct virtchnl_version_info *)msg; /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */ if (VF_IS_V10(vf)) - info.minor = I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; - return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_VERSION, + info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; + return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION, I40E_SUCCESS, (u8 *)&info, sizeof(struct - i40e_virtchnl_version_info)); + virtchnl_version_info)); } /** @@ -1499,7 +1499,7 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) **/ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) { - struct i40e_virtchnl_vf_resource *vfres = NULL; + struct virtchnl_vf_resource *vfres = NULL; struct i40e_pf *pf = vf->pf; i40e_status aq_ret = 0; struct i40e_vsi *vsi; @@ -1512,8 +1512,8 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) goto err; } - len = (sizeof(struct i40e_virtchnl_vf_resource) + - sizeof(struct i40e_virtchnl_vsi_resource) * num_vsis); + len = (sizeof(struct virtchnl_vf_resource) + + sizeof(struct virtchnl_vsi_resource) * num_vsis); vfres = kzalloc(len, GFP_KERNEL); if (!vfres) { @@ -1524,47 +1524,47 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) if (VF_IS_V11(vf)) vf->driver_caps = *(u32 *)msg; else - vf->driver_caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | - I40E_VIRTCHNL_VF_OFFLOAD_VLAN; + vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 | + VIRTCHNL_VF_OFFLOAD_RSS_REG | + VIRTCHNL_VF_OFFLOAD_VLAN; - vfres->vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2; + vfres->vf_offload_flags = VIRTCHNL_VF_OFFLOAD_L2; vsi = pf->vsi[vf->lan_vsi_idx]; if (!vsi->info.pvid) - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN; + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_VLAN; if (i40e_vf_client_capable(pf, vf->vf_id) && - (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_IWARP)) { - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_IWARP; + (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_IWARP)) { + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_IWARP; set_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states); } - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) { - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF; + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) { + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF; } else { if ((pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) && - (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ)) + (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ)) vfres->vf_offload_flags |= - I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ; + VIRTCHNL_VF_OFFLOAD_RSS_AQ; else vfres->vf_offload_flags |= - I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG; + VIRTCHNL_VF_OFFLOAD_RSS_REG; } if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE) { - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) vfres->vf_offload_flags |= - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2; + VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2; } - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_ENCAP) - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_ENCAP; + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP) + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP; if ((pf->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE) && - (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; + (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING) { + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) { if (pf->flags & I40E_FLAG_MFP_ENABLED) { dev_err(&pf->pdev->dev, "VF %d requested polling mode: this feature is supported only when the device is running in single function per port (SFP) mode\n", @@ -1572,13 +1572,13 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) ret = I40E_ERR_PARAM; goto err; } - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING; + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING; } if (pf->flags & I40E_FLAG_WB_ON_ITR_CAPABLE) { - if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) vfres->vf_offload_flags |= - I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR; + VIRTCHNL_VF_OFFLOAD_WB_ON_ITR; } vfres->num_vsis = num_vsis; @@ -1601,7 +1601,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) err: /* send the response back to the VF */ - ret = i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + ret = i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_VF_RESOURCES, aq_ret, (u8 *)vfres, len); kfree(vfres); @@ -1655,8 +1655,8 @@ static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi) static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_promisc_info *info = - (struct i40e_virtchnl_promisc_info *)msg; + struct virtchnl_promisc_info *info = + (struct virtchnl_promisc_info *)msg; struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; struct i40e_mac_filter *f; @@ -1788,7 +1788,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, error_param: /* send the response to the VF */ return i40e_vc_send_resp_to_vf(vf, - I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, + VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, aq_ret); } @@ -1803,9 +1803,9 @@ error_param: **/ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_vsi_queue_config_info *qci = - (struct i40e_virtchnl_vsi_queue_config_info *)msg; - struct i40e_virtchnl_queue_pair_info *qpi; + struct virtchnl_vsi_queue_config_info *qci = + (struct virtchnl_vsi_queue_config_info *)msg; + struct virtchnl_queue_pair_info *qpi; struct i40e_pf *pf = vf->pf; u16 vsi_id, vsi_queue_id; i40e_status aq_ret = 0; @@ -1845,7 +1845,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, aq_ret); } @@ -1860,9 +1860,9 @@ error_param: **/ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_irq_map_info *irqmap_info = - (struct i40e_virtchnl_irq_map_info *)msg; - struct i40e_virtchnl_vector_map *map; + struct virtchnl_irq_map_info *irqmap_info = + (struct virtchnl_irq_map_info *)msg; + struct virtchnl_vector_map *map; u16 vsi_id, vsi_queue_id, vector_id; i40e_status aq_ret = 0; unsigned long tempmap; @@ -1908,7 +1908,7 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) } error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, aq_ret); } @@ -1922,8 +1922,8 @@ error_param: **/ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_queue_select *vqs = - (struct i40e_virtchnl_queue_select *)msg; + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; struct i40e_pf *pf = vf->pf; u16 vsi_id = vqs->vsi_id; i40e_status aq_ret = 0; @@ -1947,7 +1947,7 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = I40E_ERR_TIMEOUT; error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES, aq_ret); } @@ -1962,8 +1962,8 @@ error_param: **/ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_queue_select *vqs = - (struct i40e_virtchnl_queue_select *)msg; + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; struct i40e_pf *pf = vf->pf; i40e_status aq_ret = 0; @@ -1986,7 +1986,7 @@ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES, aq_ret); } @@ -2000,8 +2000,8 @@ error_param: **/ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_queue_select *vqs = - (struct i40e_virtchnl_queue_select *)msg; + struct virtchnl_queue_select *vqs = + (struct virtchnl_queue_select *)msg; struct i40e_pf *pf = vf->pf; struct i40e_eth_stats stats; i40e_status aq_ret = 0; @@ -2029,7 +2029,7 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response back to the VF */ - return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_STATS, aq_ret, + return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_STATS, aq_ret, (u8 *)&stats, sizeof(stats)); } @@ -2088,8 +2088,8 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, u8 *macaddr) **/ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_ether_addr_list *al = - (struct i40e_virtchnl_ether_addr_list *)msg; + struct virtchnl_ether_addr_list *al = + (struct virtchnl_ether_addr_list *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = al->vsi_id; @@ -2143,7 +2143,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_ETH_ADDR, ret); } @@ -2157,8 +2157,8 @@ error_param: **/ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_ether_addr_list *al = - (struct i40e_virtchnl_ether_addr_list *)msg; + struct virtchnl_ether_addr_list *al = + (struct virtchnl_ether_addr_list *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = al->vsi_id; @@ -2203,7 +2203,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_ETH_ADDR, ret); } @@ -2217,8 +2217,8 @@ error_param: **/ static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_vlan_filter_list *vfl = - (struct i40e_virtchnl_vlan_filter_list *)msg; + struct virtchnl_vlan_filter_list *vfl = + (struct virtchnl_vlan_filter_list *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = vfl->vsi_id; @@ -2277,7 +2277,7 @@ static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ADD_VLAN, aq_ret); + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_VLAN, aq_ret); } /** @@ -2290,8 +2290,8 @@ error_param: **/ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_vlan_filter_list *vfl = - (struct i40e_virtchnl_vlan_filter_list *)msg; + struct virtchnl_vlan_filter_list *vfl = + (struct virtchnl_vlan_filter_list *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = vfl->vsi_id; @@ -2335,7 +2335,7 @@ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DEL_VLAN, aq_ret); + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_VLAN, aq_ret); } /** @@ -2363,7 +2363,7 @@ static int i40e_vc_iwarp_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) error_param: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_IWARP, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_IWARP, aq_ret); } @@ -2379,8 +2379,8 @@ error_param: static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, u16 msglen, bool config) { - struct i40e_virtchnl_iwarp_qvlist_info *qvlist_info = - (struct i40e_virtchnl_iwarp_qvlist_info *)msg; + struct virtchnl_iwarp_qvlist_info *qvlist_info = + (struct virtchnl_iwarp_qvlist_info *)msg; i40e_status aq_ret = 0; if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) || @@ -2399,8 +2399,8 @@ static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, u16 msglen, error_param: /* send the response to the VF */ return i40e_vc_send_resp_to_vf(vf, - config ? I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP : - I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, + config ? VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP : + VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, aq_ret); } @@ -2414,8 +2414,8 @@ error_param: **/ static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_rss_key *vrk = - (struct i40e_virtchnl_rss_key *)msg; + struct virtchnl_rss_key *vrk = + (struct virtchnl_rss_key *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = vrk->vsi_id; @@ -2432,7 +2432,7 @@ static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = i40e_config_rss(vsi, vrk->key, NULL, 0); err: /* send the response to the VF */ - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_RSS_KEY, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY, aq_ret); } @@ -2446,8 +2446,8 @@ err: **/ static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_rss_lut *vrl = - (struct i40e_virtchnl_rss_lut *)msg; + struct virtchnl_rss_lut *vrl = + (struct virtchnl_rss_lut *)msg; struct i40e_pf *pf = vf->pf; struct i40e_vsi *vsi = NULL; u16 vsi_id = vrl->vsi_id; @@ -2464,7 +2464,7 @@ static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = i40e_config_rss(vsi, NULL, vrl->lut, I40E_VF_HLUT_ARRAY_SIZE); /* send the response to the VF */ err: - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_RSS_LUT, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, aq_ret); } @@ -2478,7 +2478,7 @@ err: **/ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_rss_hena *vrh = NULL; + struct virtchnl_rss_hena *vrh = NULL; struct i40e_pf *pf = vf->pf; i40e_status aq_ret = 0; int len = 0; @@ -2487,7 +2487,7 @@ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = I40E_ERR_PARAM; goto err; } - len = sizeof(struct i40e_virtchnl_rss_hena); + len = sizeof(struct virtchnl_rss_hena); vrh = kzalloc(len, GFP_KERNEL); if (!vrh) { @@ -2498,7 +2498,7 @@ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) vrh->hena = i40e_pf_get_default_rss_hena(pf); err: /* send the response back to the VF */ - aq_ret = i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS, + aq_ret = i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_RSS_HENA_CAPS, aq_ret, (u8 *)vrh, len); kfree(vrh); return aq_ret; @@ -2514,8 +2514,8 @@ err: **/ static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) { - struct i40e_virtchnl_rss_hena *vrh = - (struct i40e_virtchnl_rss_hena *)msg; + struct virtchnl_rss_hena *vrh = + (struct virtchnl_rss_hena *)msg; struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; i40e_status aq_ret = 0; @@ -2530,7 +2530,7 @@ static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) /* send the response to the VF */ err: - return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_SET_RSS_HENA, + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_SET_RSS_HENA, aq_ret); } @@ -2555,78 +2555,78 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, /* Validate message length. */ switch (v_opcode) { - case I40E_VIRTCHNL_OP_VERSION: - valid_len = sizeof(struct i40e_virtchnl_version_info); + case VIRTCHNL_OP_VERSION: + valid_len = sizeof(struct virtchnl_version_info); break; - case I40E_VIRTCHNL_OP_RESET_VF: + case VIRTCHNL_OP_RESET_VF: break; - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: + case VIRTCHNL_OP_GET_VF_RESOURCES: if (VF_IS_V11(vf)) valid_len = sizeof(u32); break; - case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: - valid_len = sizeof(struct i40e_virtchnl_txq_info); + case VIRTCHNL_OP_CONFIG_TX_QUEUE: + valid_len = sizeof(struct virtchnl_txq_info); break; - case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE: - valid_len = sizeof(struct i40e_virtchnl_rxq_info); + case VIRTCHNL_OP_CONFIG_RX_QUEUE: + valid_len = sizeof(struct virtchnl_rxq_info); break; - case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: - valid_len = sizeof(struct i40e_virtchnl_vsi_queue_config_info); + case VIRTCHNL_OP_CONFIG_VSI_QUEUES: + valid_len = sizeof(struct virtchnl_vsi_queue_config_info); if (msglen >= valid_len) { - struct i40e_virtchnl_vsi_queue_config_info *vqc = - (struct i40e_virtchnl_vsi_queue_config_info *)msg; + struct virtchnl_vsi_queue_config_info *vqc = + (struct virtchnl_vsi_queue_config_info *)msg; valid_len += (vqc->num_queue_pairs * sizeof(struct - i40e_virtchnl_queue_pair_info)); + virtchnl_queue_pair_info)); if (vqc->num_queue_pairs == 0) err_msg_format = true; } break; - case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: - valid_len = sizeof(struct i40e_virtchnl_irq_map_info); + case VIRTCHNL_OP_CONFIG_IRQ_MAP: + valid_len = sizeof(struct virtchnl_irq_map_info); if (msglen >= valid_len) { - struct i40e_virtchnl_irq_map_info *vimi = - (struct i40e_virtchnl_irq_map_info *)msg; + struct virtchnl_irq_map_info *vimi = + (struct virtchnl_irq_map_info *)msg; valid_len += (vimi->num_vectors * - sizeof(struct i40e_virtchnl_vector_map)); + sizeof(struct virtchnl_vector_map)); if (vimi->num_vectors == 0) err_msg_format = true; } break; - case I40E_VIRTCHNL_OP_ENABLE_QUEUES: - case I40E_VIRTCHNL_OP_DISABLE_QUEUES: - valid_len = sizeof(struct i40e_virtchnl_queue_select); + case VIRTCHNL_OP_ENABLE_QUEUES: + case VIRTCHNL_OP_DISABLE_QUEUES: + valid_len = sizeof(struct virtchnl_queue_select); break; - case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: - case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: - valid_len = sizeof(struct i40e_virtchnl_ether_addr_list); + case VIRTCHNL_OP_ADD_ETH_ADDR: + case VIRTCHNL_OP_DEL_ETH_ADDR: + valid_len = sizeof(struct virtchnl_ether_addr_list); if (msglen >= valid_len) { - struct i40e_virtchnl_ether_addr_list *veal = - (struct i40e_virtchnl_ether_addr_list *)msg; + struct virtchnl_ether_addr_list *veal = + (struct virtchnl_ether_addr_list *)msg; valid_len += veal->num_elements * - sizeof(struct i40e_virtchnl_ether_addr); + sizeof(struct virtchnl_ether_addr); if (veal->num_elements == 0) err_msg_format = true; } break; - case I40E_VIRTCHNL_OP_ADD_VLAN: - case I40E_VIRTCHNL_OP_DEL_VLAN: - valid_len = sizeof(struct i40e_virtchnl_vlan_filter_list); + case VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_DEL_VLAN: + valid_len = sizeof(struct virtchnl_vlan_filter_list); if (msglen >= valid_len) { - struct i40e_virtchnl_vlan_filter_list *vfl = - (struct i40e_virtchnl_vlan_filter_list *)msg; + struct virtchnl_vlan_filter_list *vfl = + (struct virtchnl_vlan_filter_list *)msg; valid_len += vfl->num_elements * sizeof(u16); if (vfl->num_elements == 0) err_msg_format = true; } break; - case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: - valid_len = sizeof(struct i40e_virtchnl_promisc_info); + case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: + valid_len = sizeof(struct virtchnl_promisc_info); break; - case I40E_VIRTCHNL_OP_GET_STATS: - valid_len = sizeof(struct i40e_virtchnl_queue_select); + case VIRTCHNL_OP_GET_STATS: + valid_len = sizeof(struct virtchnl_queue_select); break; - case I40E_VIRTCHNL_OP_IWARP: + case VIRTCHNL_OP_IWARP: /* These messages are opaque to us and will be validated in * the RDMA client code. We just need to check for nonzero * length. The firmware will enforce max length restrictions. @@ -2636,27 +2636,27 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, else err_msg_format = true; break; - case I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: + case VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: valid_len = 0; break; - case I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: - valid_len = sizeof(struct i40e_virtchnl_iwarp_qvlist_info); + case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: + valid_len = sizeof(struct virtchnl_iwarp_qvlist_info); if (msglen >= valid_len) { - struct i40e_virtchnl_iwarp_qvlist_info *qv = - (struct i40e_virtchnl_iwarp_qvlist_info *)msg; + struct virtchnl_iwarp_qvlist_info *qv = + (struct virtchnl_iwarp_qvlist_info *)msg; if (qv->num_vectors == 0) { err_msg_format = true; break; } valid_len += ((qv->num_vectors - 1) * - sizeof(struct i40e_virtchnl_iwarp_qv_info)); + sizeof(struct virtchnl_iwarp_qv_info)); } break; - case I40E_VIRTCHNL_OP_CONFIG_RSS_KEY: - valid_len = sizeof(struct i40e_virtchnl_rss_key); + case VIRTCHNL_OP_CONFIG_RSS_KEY: + valid_len = sizeof(struct virtchnl_rss_key); if (msglen >= valid_len) { - struct i40e_virtchnl_rss_key *vrk = - (struct i40e_virtchnl_rss_key *)msg; + struct virtchnl_rss_key *vrk = + (struct virtchnl_rss_key *)msg; if (vrk->key_len != I40E_HKEY_ARRAY_SIZE) { err_msg_format = true; break; @@ -2664,11 +2664,11 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, valid_len += vrk->key_len - 1; } break; - case I40E_VIRTCHNL_OP_CONFIG_RSS_LUT: - valid_len = sizeof(struct i40e_virtchnl_rss_lut); + case VIRTCHNL_OP_CONFIG_RSS_LUT: + valid_len = sizeof(struct virtchnl_rss_lut); if (msglen >= valid_len) { - struct i40e_virtchnl_rss_lut *vrl = - (struct i40e_virtchnl_rss_lut *)msg; + struct virtchnl_rss_lut *vrl = + (struct virtchnl_rss_lut *)msg; if (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE) { err_msg_format = true; break; @@ -2676,14 +2676,14 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, valid_len += vrl->lut_entries - 1; } break; - case I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS: + case VIRTCHNL_OP_GET_RSS_HENA_CAPS: break; - case I40E_VIRTCHNL_OP_SET_RSS_HENA: - valid_len = sizeof(struct i40e_virtchnl_rss_hena); + case VIRTCHNL_OP_SET_RSS_HENA: + valid_len = sizeof(struct virtchnl_rss_hena); break; /* These are always errors coming from the VF. */ - case I40E_VIRTCHNL_OP_EVENT: - case I40E_VIRTCHNL_OP_UNKNOWN: + case VIRTCHNL_OP_EVENT: + case VIRTCHNL_OP_UNKNOWN: default: return -EPERM; } @@ -2729,70 +2729,70 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode, } switch (v_opcode) { - case I40E_VIRTCHNL_OP_VERSION: + case VIRTCHNL_OP_VERSION: ret = i40e_vc_get_version_msg(vf, msg); break; - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: + case VIRTCHNL_OP_GET_VF_RESOURCES: ret = i40e_vc_get_vf_resources_msg(vf, msg); break; - case I40E_VIRTCHNL_OP_RESET_VF: + case VIRTCHNL_OP_RESET_VF: i40e_vc_reset_vf_msg(vf); ret = 0; break; - case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: + case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: ret = i40e_vc_config_promiscuous_mode_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: + case VIRTCHNL_OP_CONFIG_VSI_QUEUES: ret = i40e_vc_config_queues_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: + case VIRTCHNL_OP_CONFIG_IRQ_MAP: ret = i40e_vc_config_irq_map_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_ENABLE_QUEUES: + case VIRTCHNL_OP_ENABLE_QUEUES: ret = i40e_vc_enable_queues_msg(vf, msg, msglen); i40e_vc_notify_vf_link_state(vf); break; - case I40E_VIRTCHNL_OP_DISABLE_QUEUES: + case VIRTCHNL_OP_DISABLE_QUEUES: ret = i40e_vc_disable_queues_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: + case VIRTCHNL_OP_ADD_ETH_ADDR: ret = i40e_vc_add_mac_addr_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: + case VIRTCHNL_OP_DEL_ETH_ADDR: ret = i40e_vc_del_mac_addr_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_ADD_VLAN: ret = i40e_vc_add_vlan_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_DEL_VLAN: + case VIRTCHNL_OP_DEL_VLAN: ret = i40e_vc_remove_vlan_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_GET_STATS: + case VIRTCHNL_OP_GET_STATS: ret = i40e_vc_get_stats_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_IWARP: + case VIRTCHNL_OP_IWARP: ret = i40e_vc_iwarp_msg(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: + case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, true); break; - case I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: + case VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, false); break; - case I40E_VIRTCHNL_OP_CONFIG_RSS_KEY: + case VIRTCHNL_OP_CONFIG_RSS_KEY: ret = i40e_vc_config_rss_key(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_RSS_LUT: + case VIRTCHNL_OP_CONFIG_RSS_LUT: ret = i40e_vc_config_rss_lut(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS: + case VIRTCHNL_OP_GET_RSS_HENA_CAPS: ret = i40e_vc_get_rss_hena(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_SET_RSS_HENA: + case VIRTCHNL_OP_SET_RSS_HENA: ret = i40e_vc_set_rss_hena(vf, msg, msglen); break; - case I40E_VIRTCHNL_OP_UNKNOWN: + case VIRTCHNL_OP_UNKNOWN: default: dev_err(&pf->pdev->dev, "Unsupported opcode %d from VF %d\n", v_opcode, local_vf_id); @@ -3218,7 +3218,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; - struct i40e_virtchnl_pf_event pfe; + struct virtchnl_pf_event pfe; struct i40e_hw *hw = &pf->hw; struct i40e_vf *vf; int abs_vf_id; @@ -3234,7 +3234,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) vf = &pf->vf[vf_id]; abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; - pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE; + pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; pfe.severity = I40E_PF_EVENT_SEVERITY_INFO; switch (link) { @@ -3262,7 +3262,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) goto error_out; } /* Notify the VF of its new link state */ - i40e_aq_send_msg_to_vf(hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, + i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(pfe), NULL); error_out: diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 20d7c8160e9e..b57ffffce141 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -81,13 +81,13 @@ struct i40e_vf { s16 vf_id; /* all VF vsis connect to the same parent */ enum i40e_switch_element_types parent_type; - struct i40e_virtchnl_version_info vf_ver; + struct virtchnl_version_info vf_ver; u32 driver_caps; /* reported by VF driver */ /* VF Port Extender (PE) stag if used */ u16 stag; - struct i40e_virtchnl_ether_addr default_lan_addr; + struct virtchnl_ether_addr default_lan_addr; u16 port_vlan_id; bool pf_set_mac; /* The VMM admin set the VF MAC address */ bool trusted; @@ -115,7 +115,7 @@ struct i40e_vf { u16 num_vlan; /* RDMA Client */ - struct i40e_virtchnl_iwarp_qvlist_info *qvlist_info; + struct virtchnl_iwarp_qvlist_info *qvlist_info; }; void i40e_free_vfs(struct i40e_pf *pf); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 1db028ac96f4..9a7d995080b6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -1054,7 +1054,7 @@ do_retry: * completion before returning. **/ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details) @@ -1092,9 +1092,9 @@ i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, * with appropriate information. **/ void i40e_vf_parse_hw_config(struct i40e_hw *hw, - struct i40e_virtchnl_vf_resource *msg) + struct virtchnl_vf_resource *msg) { - struct i40e_virtchnl_vsi_resource *vsi_res; + struct virtchnl_vsi_resource *vsi_res; int i; vsi_res = &msg->vsi_res[0]; @@ -1104,7 +1104,7 @@ void i40e_vf_parse_hw_config(struct i40e_hw *hw, hw->dev_caps.num_tx_qp = msg->num_queue_pairs; hw->dev_caps.num_msix_vectors_vf = msg->max_vectors; hw->dev_caps.dcb = msg->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_L2; + VIRTCHNL_VF_OFFLOAD_L2; hw->dev_caps.fcoe = 0; for (i = 0; i < msg->num_vsis; i++) { if (vsi_res->vsi_type == I40E_VSI_SRIOV) { @@ -1127,7 +1127,7 @@ void i40e_vf_parse_hw_config(struct i40e_hw *hw, **/ i40e_status i40e_vf_reset(struct i40e_hw *hw) { - return i40e_aq_send_msg_to_pf(hw, I40E_VIRTCHNL_OP_RESET_VF, + return i40e_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF, 0, NULL, 0, NULL); } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h index 227905b23690..c9836bba487d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h @@ -87,10 +87,10 @@ static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) /* i40e_common for VF drivers*/ void i40e_vf_parse_hw_config(struct i40e_hw *hw, - struct i40e_virtchnl_vf_resource *msg); + struct virtchnl_vf_resource *msg); i40e_status i40e_vf_reset(struct i40e_hw *hw); i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index 75d314b1a9bb..9d8c21b36332 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -264,25 +264,25 @@ struct i40evf_adapter { bool netdev_registered; bool link_up; enum i40e_aq_link_speed link_speed; - enum i40e_virtchnl_ops current_op; + enum virtchnl_ops current_op; #define CLIENT_ALLOWED(_a) ((_a)->vf_res ? \ (_a)->vf_res->vf_offload_flags & \ - I40E_VIRTCHNL_VF_OFFLOAD_IWARP : \ + VIRTCHNL_VF_OFFLOAD_IWARP : \ 0) #define CLIENT_ENABLED(_a) ((_a)->cinst) /* RSS by the PF should be preferred over RSS via other methods. */ #define RSS_PF(_a) ((_a)->vf_res->vf_offload_flags & \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) + VIRTCHNL_VF_OFFLOAD_RSS_PF) #define RSS_AQ(_a) ((_a)->vf_res->vf_offload_flags & \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ) + VIRTCHNL_VF_OFFLOAD_RSS_AQ) #define RSS_REG(_a) (!((_a)->vf_res->vf_offload_flags & \ - (I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ | \ - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF))) + (VIRTCHNL_VF_OFFLOAD_RSS_AQ | \ + VIRTCHNL_VF_OFFLOAD_RSS_PF))) #define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_offload_flags & \ - I40E_VIRTCHNL_VF_OFFLOAD_VLAN) - struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */ - struct i40e_virtchnl_vsi_resource *vsi_res; /* our LAN VSI */ - struct i40e_virtchnl_version_info pf_version; + VIRTCHNL_VF_OFFLOAD_VLAN) + struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */ + struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */ + struct virtchnl_version_info pf_version; #define PF_IS_V11(_a) (((_a)->pf_version.major == 1) && \ ((_a)->pf_version.minor == 1)) u16 msg_enable; @@ -348,7 +348,7 @@ void i40evf_set_hena(struct i40evf_adapter *adapter); void i40evf_set_rss_key(struct i40evf_adapter *adapter); void i40evf_set_rss_lut(struct i40evf_adapter *adapter); void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen); int i40evf_config_rss(struct i40evf_adapter *adapter); int i40evf_lan_add_device(struct i40evf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_client.c b/drivers/net/ethernet/intel/i40evf/i40evf_client.c index ee737680a0e9..93cf5fd17d91 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_client.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_client.c @@ -120,7 +120,7 @@ static int i40evf_client_release_qvlist(struct i40e_info *ldev) return -EAGAIN; err = i40e_aq_send_msg_to_pf(&adapter->hw, - I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, + VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP, I40E_SUCCESS, NULL, 0, NULL); if (err) @@ -410,7 +410,7 @@ static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev, if (adapter->aq_required) return -EAGAIN; - err = i40e_aq_send_msg_to_pf(&adapter->hw, I40E_VIRTCHNL_OP_IWARP, + err = i40e_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_IWARP, I40E_SUCCESS, msg, len, NULL); if (err) dev_err(&adapter->pdev->dev, "Unable to send iWarp message to PF, error %d, aq status %d\n", @@ -431,7 +431,7 @@ static int i40evf_client_setup_qvlist(struct i40e_info *ldev, struct i40e_client *client, struct i40e_qvlist_info *qvlist_info) { - struct i40e_virtchnl_iwarp_qvlist_info *v_qvlist_info; + struct virtchnl_iwarp_qvlist_info *v_qvlist_info; struct i40evf_adapter *adapter = ldev->vf; struct i40e_qv_info *qv_info; i40e_status err; @@ -453,14 +453,14 @@ static int i40evf_client_setup_qvlist(struct i40e_info *ldev, return -EINVAL; } - v_qvlist_info = (struct i40e_virtchnl_iwarp_qvlist_info *)qvlist_info; - msg_size = sizeof(struct i40e_virtchnl_iwarp_qvlist_info) + - (sizeof(struct i40e_virtchnl_iwarp_qv_info) * + v_qvlist_info = (struct virtchnl_iwarp_qvlist_info *)qvlist_info; + msg_size = sizeof(struct virtchnl_iwarp_qvlist_info) + + (sizeof(struct virtchnl_iwarp_qv_info) * (v_qvlist_info->num_vectors - 1)); - adapter->client_pending |= BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP); + adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP); err = i40e_aq_send_msg_to_pf(&adapter->hw, - I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP, + VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP, I40E_SUCCESS, (u8 *)v_qvlist_info, msg_size, NULL); if (err) { @@ -474,7 +474,7 @@ static int i40evf_client_setup_qvlist(struct i40e_info *ldev, for (i = 0; i < 5; i++) { msleep(100); if (!(adapter->client_pending & - BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP))) { + BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP))) { err = 0; break; } diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index ea110a730e16..5d7b613e0d62 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1131,7 +1131,7 @@ void i40evf_down(struct i40evf_adapter *adapter) if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) && adapter->state != __I40EVF_RESETTING) { /* cancel any current operation */ - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; /* Schedule operations to close down the HW. Don't wait * here for this to complete. The watchdog is still running * and it will take care of this. @@ -1311,7 +1311,7 @@ static int i40evf_config_rss_aq(struct i40evf_adapter *adapter) struct i40e_hw *hw = &adapter->hw; int ret = 0; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot configure RSS, command %d pending\n", adapter->current_op); @@ -1410,7 +1410,7 @@ static int i40evf_init_rss(struct i40evf_adapter *adapter) if (!RSS_PF(adapter)) { /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */ if (adapter->vf_res->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) + VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) adapter->hena = I40E_DEFAULT_RSS_HENA_EXPANDED; else adapter->hena = I40E_DEFAULT_RSS_HENA; @@ -1588,8 +1588,8 @@ static void i40evf_watchdog_task(struct work_struct *work) if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { reg_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if ((reg_val == I40E_VFR_VFACTIVE) || - (reg_val == I40E_VFR_COMPLETED)) { + if ((reg_val == VIRTCHNL_VFR_VFACTIVE) || + (reg_val == VIRTCHNL_VFR_COMPLETED)) { /* A chance for redemption! */ dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n"); adapter->state = __I40EVF_STARTUP; @@ -1605,7 +1605,7 @@ static void i40evf_watchdog_task(struct work_struct *work) return; } adapter->aq_required = 0; - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; goto watchdog_done; } @@ -1621,7 +1621,7 @@ static void i40evf_watchdog_task(struct work_struct *work) dev_err(&adapter->pdev->dev, "Hardware reset detected\n"); schedule_work(&adapter->reset_task); adapter->aq_required = 0; - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; goto watchdog_done; } @@ -1854,7 +1854,7 @@ static void i40evf_reset_task(struct work_struct *work) reg_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if (reg_val == I40E_VFR_VFACTIVE) + if (reg_val == VIRTCHNL_VFR_VFACTIVE) break; } @@ -1888,7 +1888,7 @@ continue_reset: /* kill and reinit the admin queue */ i40evf_shutdown_adminq(hw); - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; err = i40evf_init_adminq(hw); if (err) dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n", @@ -1949,7 +1949,7 @@ static void i40evf_adminq_task(struct work_struct *work) container_of(work, struct i40evf_adapter, adminq_task); struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; - struct i40e_virtchnl_msg *v_msg; + struct virtchnl_msg *v_msg; i40e_status ret; u32 val, oldval; u16 pending; @@ -1962,7 +1962,7 @@ static void i40evf_adminq_task(struct work_struct *work) if (!event.msg_buf) goto out; - v_msg = (struct i40e_virtchnl_msg *)&event.desc; + v_msg = (struct virtchnl_msg *)&event.desc; do { ret = i40evf_clean_arq_element(hw, &event, &pending); if (ret || !v_msg->v_opcode) @@ -2347,7 +2347,7 @@ static netdev_features_t i40evf_fix_features(struct net_device *netdev, struct i40evf_adapter *adapter = netdev_priv(netdev); features &= ~I40EVF_VLAN_FEATURES; - if (adapter->vf_res->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_VLAN) + if (adapter->vf_res->vf_offload_flags & VIRTCHNL_VF_OFFLOAD_VLAN) features |= I40EVF_VLAN_FEATURES; return features; } @@ -2384,8 +2384,8 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw) for (i = 0; i < 100; i++) { rstat = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if ((rstat == I40E_VFR_VFACTIVE) || - (rstat == I40E_VFR_COMPLETED)) + if ((rstat == VIRTCHNL_VFR_VFACTIVE) || + (rstat == VIRTCHNL_VFR_COMPLETED)) return 0; usleep_range(10, 20); } @@ -2401,7 +2401,7 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw) **/ int i40evf_process_config(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_vf_resource *vfres = adapter->vf_res; + struct virtchnl_vf_resource *vfres = adapter->vf_res; struct net_device *netdev = adapter->netdev; struct i40e_vsi *vsi = &adapter->vsi; int i; @@ -2434,7 +2434,7 @@ int i40evf_process_config(struct i40evf_adapter *adapter) /* advertise to stack only if offloads for encapsulated packets is * supported */ - if (vfres->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_ENCAP) { + if (vfres->vf_offload_flags & VIRTCHNL_VF_OFFLOAD_ENCAP) { hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | @@ -2445,7 +2445,7 @@ int i40evf_process_config(struct i40evf_adapter *adapter) 0; if (!(vfres->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) + VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM)) netdev->gso_partial_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM; @@ -2472,7 +2472,7 @@ int i40evf_process_config(struct i40evf_adapter *adapter) adapter->vsi.work_limit = I40E_DEFAULT_IRQ_WORK; vsi->netdev = adapter->netdev; vsi->qs_handle = adapter->vsi_res->qset_handle; - if (vfres->vf_offload_flags & I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) { + if (vfres->vf_offload_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) { adapter->rss_key_size = vfres->rss_key_size; adapter->rss_lut_size = vfres->rss_lut_size; } else { @@ -2558,8 +2558,8 @@ static void i40evf_init_task(struct work_struct *work) dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n", adapter->pf_version.major, adapter->pf_version.minor, - I40E_VIRTCHNL_VERSION_MAJOR, - I40E_VIRTCHNL_VERSION_MINOR); + VIRTCHNL_VERSION_MAJOR, + VIRTCHNL_VERSION_MINOR); goto err; } err = i40evf_send_vf_config_msg(adapter); @@ -2573,9 +2573,9 @@ static void i40evf_init_task(struct work_struct *work) case __I40EVF_INIT_GET_RESOURCES: /* aq msg sent, awaiting reply */ if (!adapter->vf_res) { - bufsz = sizeof(struct i40e_virtchnl_vf_resource) + + bufsz = sizeof(struct virtchnl_vf_resource) + (I40E_MAX_VF_VSI * - sizeof(struct i40e_virtchnl_vsi_resource)); + sizeof(struct virtchnl_vsi_resource)); adapter->vf_res = kzalloc(bufsz, GFP_KERNEL); if (!adapter->vf_res) goto err; @@ -2606,7 +2606,7 @@ static void i40evf_init_task(struct work_struct *work) if (i40evf_process_config(adapter)) goto err_alloc; - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED; @@ -2644,7 +2644,7 @@ static void i40evf_init_task(struct work_struct *work) goto err_sw_init; i40evf_map_rings_to_vectors(adapter); if (adapter->vf_res->vf_offload_flags & - I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) + VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) adapter->flags |= I40EVF_FLAG_WB_ON_ITR_CAPABLE; err = i40evf_request_misc_irq(adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 91b21f26f8d4..90a17b0347b9 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -42,7 +42,7 @@ * Send message to PF and print status if failure. **/ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, - enum i40e_virtchnl_ops op, u8 *msg, u16 len) + enum virtchnl_ops op, u8 *msg, u16 len) { struct i40e_hw *hw = &adapter->hw; i40e_status err; @@ -68,12 +68,12 @@ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, **/ int i40evf_send_api_ver(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_version_info vvi; + struct virtchnl_version_info vvi; - vvi.major = I40E_VIRTCHNL_VERSION_MAJOR; - vvi.minor = I40E_VIRTCHNL_VERSION_MINOR; + vvi.major = VIRTCHNL_VERSION_MAJOR; + vvi.minor = VIRTCHNL_VERSION_MINOR; - return i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_VERSION, (u8 *)&vvi, + return i40evf_send_pf_msg(adapter, VIRTCHNL_OP_VERSION, (u8 *)&vvi, sizeof(vvi)); } @@ -88,10 +88,10 @@ int i40evf_send_api_ver(struct i40evf_adapter *adapter) **/ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_version_info *pf_vvi; + struct virtchnl_version_info *pf_vvi; struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; - enum i40e_virtchnl_ops op; + enum virtchnl_ops op; i40e_status err; event.buf_len = I40EVF_MAX_AQ_BUF_SIZE; @@ -109,8 +109,8 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) if (err) goto out_alloc; op = - (enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high); - if (op == I40E_VIRTCHNL_OP_VERSION) + (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high); + if (op == VIRTCHNL_OP_VERSION) break; } @@ -119,19 +119,19 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) if (err) goto out_alloc; - if (op != I40E_VIRTCHNL_OP_VERSION) { + if (op != VIRTCHNL_OP_VERSION) { dev_info(&adapter->pdev->dev, "Invalid reply type %d from PF\n", op); err = -EIO; goto out_alloc; } - pf_vvi = (struct i40e_virtchnl_version_info *)event.msg_buf; + pf_vvi = (struct virtchnl_version_info *)event.msg_buf; adapter->pf_version = *pf_vvi; - if ((pf_vvi->major > I40E_VIRTCHNL_VERSION_MAJOR) || - ((pf_vvi->major == I40E_VIRTCHNL_VERSION_MAJOR) && - (pf_vvi->minor > I40E_VIRTCHNL_VERSION_MINOR))) + if ((pf_vvi->major > VIRTCHNL_VERSION_MAJOR) || + ((pf_vvi->major == VIRTCHNL_VERSION_MAJOR) && + (pf_vvi->minor > VIRTCHNL_VERSION_MINOR))) err = -EIO; out_alloc: @@ -152,25 +152,25 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) { u32 caps; - caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | - I40E_VIRTCHNL_VF_OFFLOAD_VLAN | - I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 | - I40E_VIRTCHNL_VF_OFFLOAD_ENCAP | - I40E_VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; - - adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES; + caps = VIRTCHNL_VF_OFFLOAD_L2 | + VIRTCHNL_VF_OFFLOAD_RSS_PF | + VIRTCHNL_VF_OFFLOAD_RSS_AQ | + VIRTCHNL_VF_OFFLOAD_RSS_REG | + VIRTCHNL_VF_OFFLOAD_VLAN | + VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | + VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 | + VIRTCHNL_VF_OFFLOAD_ENCAP | + VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; + + adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES; adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; if (PF_IS_V11(adapter)) return i40evf_send_pf_msg(adapter, - I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + VIRTCHNL_OP_GET_VF_RESOURCES, (u8 *)&caps, sizeof(caps)); else return i40evf_send_pf_msg(adapter, - I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + VIRTCHNL_OP_GET_VF_RESOURCES, NULL, 0); } @@ -188,12 +188,12 @@ int i40evf_get_vf_config(struct i40evf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; struct i40e_arq_event_info event; - enum i40e_virtchnl_ops op; + enum virtchnl_ops op; i40e_status err; u16 len; - len = sizeof(struct i40e_virtchnl_vf_resource) + - I40E_MAX_VF_VSI * sizeof(struct i40e_virtchnl_vsi_resource); + len = sizeof(struct virtchnl_vf_resource) + + I40E_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource); event.buf_len = len; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); if (!event.msg_buf) { @@ -209,8 +209,8 @@ int i40evf_get_vf_config(struct i40evf_adapter *adapter) if (err) goto out_alloc; op = - (enum i40e_virtchnl_ops)le32_to_cpu(event.desc.cookie_high); - if (op == I40E_VIRTCHNL_OP_GET_VF_RESOURCES) + (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high); + if (op == VIRTCHNL_OP_GET_VF_RESOURCES) break; } @@ -232,20 +232,20 @@ out: **/ void i40evf_configure_queues(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_vsi_queue_config_info *vqci; - struct i40e_virtchnl_queue_pair_info *vqpi; + struct virtchnl_vsi_queue_config_info *vqci; + struct virtchnl_queue_pair_info *vqpi; int pairs = adapter->num_active_queues; int i, len, max_frame = I40E_MAX_RXBUFFER; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot configure queues, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES; - len = sizeof(struct i40e_virtchnl_vsi_queue_config_info) + - (sizeof(struct i40e_virtchnl_queue_pair_info) * pairs); + adapter->current_op = VIRTCHNL_OP_CONFIG_VSI_QUEUES; + len = sizeof(struct virtchnl_vsi_queue_config_info) + + (sizeof(struct virtchnl_queue_pair_info) * pairs); vqci = kzalloc(len, GFP_KERNEL); if (!vqci) return; @@ -278,7 +278,7 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter) } adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_QUEUES; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_VSI_QUEUES, (u8 *)vqci, len); kfree(vqci); } @@ -291,20 +291,20 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter) **/ void i40evf_enable_queues(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_queue_select vqs; + struct virtchnl_queue_select vqs; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot enable queues, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_ENABLE_QUEUES; + adapter->current_op = VIRTCHNL_OP_ENABLE_QUEUES; vqs.vsi_id = adapter->vsi_res->vsi_id; vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_QUEUES; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ENABLE_QUEUES, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_QUEUES, (u8 *)&vqs, sizeof(vqs)); } @@ -316,20 +316,20 @@ void i40evf_enable_queues(struct i40evf_adapter *adapter) **/ void i40evf_disable_queues(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_queue_select vqs; + struct virtchnl_queue_select vqs; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot disable queues, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_DISABLE_QUEUES; + adapter->current_op = VIRTCHNL_OP_DISABLE_QUEUES; vqs.vsi_id = adapter->vsi_res->vsi_id; vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_QUEUES; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DISABLE_QUEUES, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_QUEUES, (u8 *)&vqs, sizeof(vqs)); } @@ -342,23 +342,23 @@ void i40evf_disable_queues(struct i40evf_adapter *adapter) **/ void i40evf_map_queues(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_irq_map_info *vimi; + struct virtchnl_irq_map_info *vimi; int v_idx, q_vectors, len; struct i40e_q_vector *q_vector; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot map queues to vectors, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP; + adapter->current_op = VIRTCHNL_OP_CONFIG_IRQ_MAP; q_vectors = adapter->num_msix_vectors - NONQ_VECS; - len = sizeof(struct i40e_virtchnl_irq_map_info) + + len = sizeof(struct virtchnl_irq_map_info) + (adapter->num_msix_vectors * - sizeof(struct i40e_virtchnl_vector_map)); + sizeof(struct virtchnl_vector_map)); vimi = kzalloc(len, GFP_KERNEL); if (!vimi) return; @@ -379,7 +379,7 @@ void i40evf_map_queues(struct i40evf_adapter *adapter) vimi->vecmap[v_idx].rxq_map = 0; adapter->aq_required &= ~I40EVF_FLAG_AQ_MAP_VECTORS; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_IRQ_MAP, (u8 *)vimi, len); kfree(vimi); } @@ -394,12 +394,12 @@ void i40evf_map_queues(struct i40evf_adapter *adapter) **/ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_ether_addr_list *veal; + struct virtchnl_ether_addr_list *veal; int len, i = 0, count = 0; struct i40evf_mac_filter *f; bool more = false; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot add filters, command %d pending\n", adapter->current_op); @@ -413,17 +413,17 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; return; } - adapter->current_op = I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS; + adapter->current_op = VIRTCHNL_OP_ADD_ETH_ADDR; - len = sizeof(struct i40e_virtchnl_ether_addr_list) + - (count * sizeof(struct i40e_virtchnl_ether_addr)); + len = sizeof(struct virtchnl_ether_addr_list) + + (count * sizeof(struct virtchnl_ether_addr)); if (len > I40EVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many add MAC changes in one request\n"); count = (I40EVF_MAX_AQ_BUF_SIZE - - sizeof(struct i40e_virtchnl_ether_addr_list)) / - sizeof(struct i40e_virtchnl_ether_addr); - len = sizeof(struct i40e_virtchnl_ether_addr_list) + - (count * sizeof(struct i40e_virtchnl_ether_addr)); + sizeof(struct virtchnl_ether_addr_list)) / + sizeof(struct virtchnl_ether_addr); + len = sizeof(struct virtchnl_ether_addr_list) + + (count * sizeof(struct virtchnl_ether_addr)); more = true; } @@ -444,7 +444,7 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) } if (!more) adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)veal, len); kfree(veal); } @@ -459,12 +459,12 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter) **/ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_ether_addr_list *veal; + struct virtchnl_ether_addr_list *veal; struct i40evf_mac_filter *f, *ftmp; int len, i = 0, count = 0; bool more = false; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot remove filters, command %d pending\n", adapter->current_op); @@ -478,17 +478,17 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; return; } - adapter->current_op = I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS; + adapter->current_op = VIRTCHNL_OP_DEL_ETH_ADDR; - len = sizeof(struct i40e_virtchnl_ether_addr_list) + - (count * sizeof(struct i40e_virtchnl_ether_addr)); + len = sizeof(struct virtchnl_ether_addr_list) + + (count * sizeof(struct virtchnl_ether_addr)); if (len > I40EVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many delete MAC changes in one request\n"); count = (I40EVF_MAX_AQ_BUF_SIZE - - sizeof(struct i40e_virtchnl_ether_addr_list)) / - sizeof(struct i40e_virtchnl_ether_addr); - len = sizeof(struct i40e_virtchnl_ether_addr_list) + - (count * sizeof(struct i40e_virtchnl_ether_addr)); + sizeof(struct virtchnl_ether_addr_list)) / + sizeof(struct virtchnl_ether_addr); + len = sizeof(struct virtchnl_ether_addr_list) + + (count * sizeof(struct virtchnl_ether_addr)); more = true; } veal = kzalloc(len, GFP_KERNEL); @@ -509,7 +509,7 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) } if (!more) adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_ETH_ADDR, (u8 *)veal, len); kfree(veal); } @@ -524,12 +524,12 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter) **/ void i40evf_add_vlans(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_vlan_filter_list *vvfl; + struct virtchnl_vlan_filter_list *vvfl; int len, i = 0, count = 0; struct i40evf_vlan_filter *f; bool more = false; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot add VLANs, command %d pending\n", adapter->current_op); @@ -544,16 +544,16 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER; return; } - adapter->current_op = I40E_VIRTCHNL_OP_ADD_VLAN; + adapter->current_op = VIRTCHNL_OP_ADD_VLAN; - len = sizeof(struct i40e_virtchnl_vlan_filter_list) + + len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); if (len > I40EVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n"); count = (I40EVF_MAX_AQ_BUF_SIZE - - sizeof(struct i40e_virtchnl_vlan_filter_list)) / + sizeof(struct virtchnl_vlan_filter_list)) / sizeof(u16); - len = sizeof(struct i40e_virtchnl_vlan_filter_list) + + len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); more = true; } @@ -574,7 +574,7 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) } if (!more) adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len); + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len); kfree(vvfl); } @@ -588,12 +588,12 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter) **/ void i40evf_del_vlans(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_vlan_filter_list *vvfl; + struct virtchnl_vlan_filter_list *vvfl; struct i40evf_vlan_filter *f, *ftmp; int len, i = 0, count = 0; bool more = false; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot remove VLANs, command %d pending\n", adapter->current_op); @@ -608,16 +608,16 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER; return; } - adapter->current_op = I40E_VIRTCHNL_OP_DEL_VLAN; + adapter->current_op = VIRTCHNL_OP_DEL_VLAN; - len = sizeof(struct i40e_virtchnl_vlan_filter_list) + + len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); if (len > I40EVF_MAX_AQ_BUF_SIZE) { dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n"); count = (I40EVF_MAX_AQ_BUF_SIZE - - sizeof(struct i40e_virtchnl_vlan_filter_list)) / + sizeof(struct virtchnl_vlan_filter_list)) / sizeof(u16); - len = sizeof(struct i40e_virtchnl_vlan_filter_list) + + len = sizeof(struct virtchnl_vlan_filter_list) + (count * sizeof(u16)); more = true; } @@ -639,7 +639,7 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) } if (!more) adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len); + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len); kfree(vvfl); } @@ -652,10 +652,10 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter) **/ void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) { - struct i40e_virtchnl_promisc_info vpi; + struct virtchnl_promisc_info vpi; int promisc_all; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot set promiscuous mode, command %d pending\n", adapter->current_op); @@ -682,10 +682,10 @@ void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) dev_info(&adapter->pdev->dev, "Leaving promiscuous mode\n"); } - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE; + adapter->current_op = VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE; vpi.vsi_id = adapter->vsi_res->vsi_id; vpi.flags = flags; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, (u8 *)&vpi, sizeof(vpi)); } @@ -697,19 +697,19 @@ void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) **/ void i40evf_request_stats(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_queue_select vqs; + struct virtchnl_queue_select vqs; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* no error message, this isn't crucial */ return; } - adapter->current_op = I40E_VIRTCHNL_OP_GET_STATS; + adapter->current_op = VIRTCHNL_OP_GET_STATS; vqs.vsi_id = adapter->vsi_res->vsi_id; /* queue maps are ignored for this message - only the vsi is used */ - if (i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_GET_STATS, + if (i40evf_send_pf_msg(adapter, VIRTCHNL_OP_GET_STATS, (u8 *)&vqs, sizeof(vqs))) /* if the request failed, don't lock out others */ - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; } /** @@ -720,15 +720,15 @@ void i40evf_request_stats(struct i40evf_adapter *adapter) **/ void i40evf_get_hena(struct i40evf_adapter *adapter) { - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot get RSS hash capabilities, command %d pending\n", adapter->current_op); return; } - adapter->current_op = I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS; + adapter->current_op = VIRTCHNL_OP_GET_RSS_HENA_CAPS; adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_HENA; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_GET_RSS_HENA_CAPS, NULL, 0); } @@ -740,18 +740,18 @@ void i40evf_get_hena(struct i40evf_adapter *adapter) **/ void i40evf_set_hena(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_rss_hena vrh; + struct virtchnl_rss_hena vrh; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot set RSS hash enable, command %d pending\n", adapter->current_op); return; } vrh.hena = adapter->hena; - adapter->current_op = I40E_VIRTCHNL_OP_SET_RSS_HENA; + adapter->current_op = VIRTCHNL_OP_SET_RSS_HENA; adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_HENA; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_SET_RSS_HENA, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_SET_RSS_HENA, (u8 *)&vrh, sizeof(vrh)); } @@ -763,16 +763,16 @@ void i40evf_set_hena(struct i40evf_adapter *adapter) **/ void i40evf_set_rss_key(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_rss_key *vrk; + struct virtchnl_rss_key *vrk; int len; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot set RSS key, command %d pending\n", adapter->current_op); return; } - len = sizeof(struct i40e_virtchnl_rss_key) + + len = sizeof(struct virtchnl_rss_key) + (adapter->rss_key_size * sizeof(u8)) - 1; vrk = kzalloc(len, GFP_KERNEL); if (!vrk) @@ -781,9 +781,9 @@ void i40evf_set_rss_key(struct i40evf_adapter *adapter) vrk->key_len = adapter->rss_key_size; memcpy(vrk->key, adapter->rss_key, adapter->rss_key_size); - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_RSS_KEY; + adapter->current_op = VIRTCHNL_OP_CONFIG_RSS_KEY; adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_RSS_KEY; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_RSS_KEY, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_KEY, (u8 *)vrk, len); kfree(vrk); } @@ -796,16 +796,16 @@ void i40evf_set_rss_key(struct i40evf_adapter *adapter) **/ void i40evf_set_rss_lut(struct i40evf_adapter *adapter) { - struct i40e_virtchnl_rss_lut *vrl; + struct virtchnl_rss_lut *vrl; int len; - if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { /* bail because we already have a command pending */ dev_err(&adapter->pdev->dev, "Cannot set RSS LUT, command %d pending\n", adapter->current_op); return; } - len = sizeof(struct i40e_virtchnl_rss_lut) + + len = sizeof(struct virtchnl_rss_lut) + (adapter->rss_lut_size * sizeof(u8)) - 1; vrl = kzalloc(len, GFP_KERNEL); if (!vrl) @@ -813,9 +813,9 @@ void i40evf_set_rss_lut(struct i40evf_adapter *adapter) vrl->vsi_id = adapter->vsi.id; vrl->lut_entries = adapter->rss_lut_size; memcpy(vrl->lut, adapter->rss_lut, adapter->rss_lut_size); - adapter->current_op = I40E_VIRTCHNL_OP_CONFIG_RSS_LUT; + adapter->current_op = VIRTCHNL_OP_CONFIG_RSS_LUT; adapter->aq_required &= ~I40EVF_FLAG_AQ_SET_RSS_LUT; - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_CONFIG_RSS_LUT, + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_LUT, (u8 *)vrl, len); kfree(vrl); } @@ -871,8 +871,8 @@ static void i40evf_print_link_message(struct i40evf_adapter *adapter) void i40evf_request_reset(struct i40evf_adapter *adapter) { /* Don't check CURRENT_OP - this is always higher priority */ - i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_RESET_VF, NULL, 0); - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + i40evf_send_pf_msg(adapter, VIRTCHNL_OP_RESET_VF, NULL, 0); + adapter->current_op = VIRTCHNL_OP_UNKNOWN; } /** @@ -888,17 +888,17 @@ void i40evf_request_reset(struct i40evf_adapter *adapter) * This function handles the reply messages. **/ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, - enum i40e_virtchnl_ops v_opcode, + enum virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen) { struct net_device *netdev = adapter->netdev; - if (v_opcode == I40E_VIRTCHNL_OP_EVENT) { - struct i40e_virtchnl_pf_event *vpe = - (struct i40e_virtchnl_pf_event *)msg; + if (v_opcode == VIRTCHNL_OP_EVENT) { + struct virtchnl_pf_event *vpe = + (struct virtchnl_pf_event *)msg; switch (vpe->event) { - case I40E_VIRTCHNL_EVENT_LINK_CHANGE: + case VIRTCHNL_EVENT_LINK_CHANGE: adapter->link_speed = vpe->event_data.link_event.link_speed; if (adapter->link_up != @@ -915,7 +915,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, i40evf_print_link_message(adapter); } break; - case I40E_VIRTCHNL_EVENT_RESET_IMPENDING: + case VIRTCHNL_EVENT_RESET_IMPENDING: dev_info(&adapter->pdev->dev, "PF reset warning received\n"); if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) { adapter->flags |= I40EVF_FLAG_RESET_PENDING; @@ -932,19 +932,19 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, } if (v_retval) { switch (v_opcode) { - case I40E_VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_ADD_VLAN: dev_err(&adapter->pdev->dev, "Failed to add VLAN filter, error %s\n", i40evf_stat_str(&adapter->hw, v_retval)); break; - case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS: + case VIRTCHNL_OP_ADD_ETH_ADDR: dev_err(&adapter->pdev->dev, "Failed to add MAC filter, error %s\n", i40evf_stat_str(&adapter->hw, v_retval)); break; - case I40E_VIRTCHNL_OP_DEL_VLAN: + case VIRTCHNL_OP_DEL_VLAN: dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", i40evf_stat_str(&adapter->hw, v_retval)); break; - case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS: + case VIRTCHNL_OP_DEL_ETH_ADDR: dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", i40evf_stat_str(&adapter->hw, v_retval)); break; @@ -956,7 +956,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, } } switch (v_opcode) { - case I40E_VIRTCHNL_OP_GET_STATS: { + case VIRTCHNL_OP_GET_STATS: { struct i40e_eth_stats *stats = (struct i40e_eth_stats *)msg; netdev->stats.rx_packets = stats->rx_unicast + @@ -973,10 +973,10 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, adapter->current_stats = *stats; } break; - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: { - u16 len = sizeof(struct i40e_virtchnl_vf_resource) + + case VIRTCHNL_OP_GET_VF_RESOURCES: { + u16 len = sizeof(struct virtchnl_vf_resource) + I40E_MAX_VF_VSI * - sizeof(struct i40e_virtchnl_vsi_resource); + sizeof(struct virtchnl_vsi_resource); memcpy(adapter->vf_res, msg, min(msglen, len)); i40e_vf_parse_hw_config(&adapter->hw, adapter->vf_res); /* restore current mac address */ @@ -984,18 +984,18 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, i40evf_process_config(adapter); } break; - case I40E_VIRTCHNL_OP_ENABLE_QUEUES: + case VIRTCHNL_OP_ENABLE_QUEUES: /* enable transmits */ i40evf_irq_enable(adapter, true); break; - case I40E_VIRTCHNL_OP_DISABLE_QUEUES: + case VIRTCHNL_OP_DISABLE_QUEUES: i40evf_free_all_tx_resources(adapter); i40evf_free_all_rx_resources(adapter); if (adapter->state == __I40EVF_DOWN_PENDING) adapter->state = __I40EVF_DOWN; break; - case I40E_VIRTCHNL_OP_VERSION: - case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: + case VIRTCHNL_OP_VERSION: + case VIRTCHNL_OP_CONFIG_IRQ_MAP: /* Don't display an error if we get these out of sequence. * If the firmware needed to get kicked, we'll get these and * it's no problem. @@ -1003,7 +1003,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, if (v_opcode != adapter->current_op) return; break; - case I40E_VIRTCHNL_OP_IWARP: + case VIRTCHNL_OP_IWARP: /* Gobble zero-length replies from the PF. They indicate that * a previous message was received OK, and the client doesn't * care about that. @@ -1013,13 +1013,13 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, msg, msglen); break; - case I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: + case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: adapter->client_pending &= - ~(BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP)); + ~(BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP)); break; - case I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS: { - struct i40e_virtchnl_rss_hena *vrh = - (struct i40e_virtchnl_rss_hena *)msg; + case VIRTCHNL_OP_GET_RSS_HENA_CAPS: { + struct virtchnl_rss_hena *vrh = + (struct virtchnl_rss_hena *)msg; if (msglen == sizeof(*vrh)) adapter->hena = vrh->hena; else @@ -1033,5 +1033,5 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, adapter->current_op, v_opcode); break; } /* switch v_opcode */ - adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->current_op = VIRTCHNL_OP_UNKNOWN; } -- cgit v1.2.3 From 260e93820ad6c35d189210b4d86989a1df054e55 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:12 -0700 Subject: virtchnl: move some code to core driver Before moving this function over to virtchnl.h, move some driver specific checks that had snuck into a fairly generic function, back into the caller of the function. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 30 +++++++++++++--------- 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 9f361e810990..d7fcc4ffa393 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2549,10 +2549,6 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, bool err_msg_format = false; int valid_len = 0; - /* Check if VF is disabled. */ - if (test_bit(I40E_VF_STATE_DISABLED, &vf->vf_states)) - return I40E_ERR_PARAM; - /* Validate message length. */ switch (v_opcode) { case VIRTCHNL_OP_VERSION: @@ -2657,10 +2653,6 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, if (msglen >= valid_len) { struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg; - if (vrk->key_len != I40E_HKEY_ARRAY_SIZE) { - err_msg_format = true; - break; - } valid_len += vrk->key_len - 1; } break; @@ -2669,10 +2661,6 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, if (msglen >= valid_len) { struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; - if (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE) { - err_msg_format = true; - break; - } valid_len += vrl->lut_entries - 1; } break; @@ -2719,9 +2707,27 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode, if (local_vf_id >= pf->num_alloc_vfs) return -EINVAL; vf = &(pf->vf[local_vf_id]); + + /* Check if VF is disabled. */ + if (test_bit(I40E_VF_STATE_DISABLED, &vf->vf_states)) + return I40E_ERR_PARAM; + /* perform basic checks on the msg */ ret = i40e_vc_validate_vf_msg(vf, v_opcode, v_retval, msg, msglen); + /* perform additional checks specific to this driver */ + if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_KEY) { + struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg; + + if (vrk->key_len != I40E_HKEY_ARRAY_SIZE) + ret = -EINVAL; + } else if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_LUT) { + struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; + + if (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE) + ret = -EINVAL; + } + if (ret) { dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d\n", local_vf_id, v_opcode, msglen); -- cgit v1.2.3 From eedcfef85b15ae02c488625556702594a618c616 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:13 -0700 Subject: virtchnl: convert to new macros As part of the conversion, change the arguments to VF_IS_V1[01] macros and move them to virtchnl.h Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 6 +++--- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index d7fcc4ffa393..923026a255c0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1481,7 +1481,7 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) vf->vf_ver = *(struct virtchnl_version_info *)msg; /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */ - if (VF_IS_V10(vf)) + if (VF_IS_V10(&vf->vf_ver)) info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION, I40E_SUCCESS, (u8 *)&info, @@ -1521,7 +1521,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) len = 0; goto err; } - if (VF_IS_V11(vf)) + if (VF_IS_V11(&vf->vf_ver)) vf->driver_caps = *(u32 *)msg; else vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 | @@ -2557,7 +2557,7 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, case VIRTCHNL_OP_RESET_VF: break; case VIRTCHNL_OP_GET_VF_RESOURCES: - if (VF_IS_V11(vf)) + if (VF_IS_V11(&vf->vf_ver)) valid_len = sizeof(u32); break; case VIRTCHNL_OP_CONFIG_TX_QUEUE: diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index b57ffffce141..1f4b0c504368 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -40,9 +40,6 @@ #define I40E_VLAN_MASK 0xFFF #define I40E_PRIORITY_MASK 0x7000 -#define VF_IS_V10(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 0)) -#define VF_IS_V11(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 1)) - /* Various queue ctrls */ enum i40e_queue_ctrl { I40E_QUEUE_CTRL_UNKNOWN = 0, -- cgit v1.2.3 From 764430ce6f8c38d7ed3b6d2cfe9450b9d3c78809 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:14 -0700 Subject: i40e/virtchnl: refactor code for validate checks This change updates the arguments passed to the validate function and fixes the caller, as well as uses the new return values added to virtchnl.h One other minor tweak, remove a duplicate set to zero of valid_len. This is in preparation for moving the function to virtchnl.h. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 36 ++++++++++++---------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 923026a255c0..61f948c587ad 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2536,15 +2536,16 @@ err: /** * i40e_vc_validate_vf_msg - * @vf: pointer to the VF info + * @ver: Virtchnl version info + * @v_opcode: Opcode for the message * @msg: pointer to the msg buffer * @msglen: msg length - * @msghndl: msg handle * - * validate msg + * validate msg format against struct for each opcode **/ -static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, - u32 v_retval, u8 *msg, u16 msglen) +static int +i40e_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode, + u8 *msg, u16 msglen) { bool err_msg_format = false; int valid_len = 0; @@ -2557,7 +2558,7 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, case VIRTCHNL_OP_RESET_VF: break; case VIRTCHNL_OP_GET_VF_RESOURCES: - if (VF_IS_V11(&vf->vf_ver)) + if (VF_IS_V11(ver)) valid_len = sizeof(u32); break; case VIRTCHNL_OP_CONFIG_TX_QUEUE: @@ -2633,7 +2634,6 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, err_msg_format = true; break; case VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: - valid_len = 0; break; case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: valid_len = sizeof(struct virtchnl_iwarp_qvlist_info); @@ -2673,15 +2673,13 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, case VIRTCHNL_OP_EVENT: case VIRTCHNL_OP_UNKNOWN: default: - return -EPERM; + return VIRTCHNL_ERR_PARAM; } /* few more checks */ - if ((valid_len != msglen) || (err_msg_format)) { - i40e_vc_send_resp_to_vf(vf, v_opcode, I40E_ERR_PARAM); - return -EINVAL; - } else { - return 0; - } + if ((valid_len != msglen) || (err_msg_format)) + return VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH; + + return 0; } /** @@ -2713,7 +2711,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode, return I40E_ERR_PARAM; /* perform basic checks on the msg */ - ret = i40e_vc_validate_vf_msg(vf, v_opcode, v_retval, msg, msglen); + ret = i40e_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen); /* perform additional checks specific to this driver */ if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_KEY) { @@ -2729,9 +2727,15 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode, } if (ret) { + i40e_vc_send_resp_to_vf(vf, v_opcode, I40E_ERR_PARAM); dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d\n", local_vf_id, v_opcode, msglen); - return ret; + switch (ret) { + case VIRTCHNL_ERR_PARAM: + return -EPERM; + default: + return -EINVAL; + } } switch (v_opcode) { -- cgit v1.2.3 From f0adc6e831baaef16577ea2af5eb3e91fd4efef4 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:15 -0700 Subject: i40evf/virtchnl: whitespace cleanups This patch fixes up a bunch of whitespace issues introduced by the previous automated change of name from i40e to virtchnl. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 12 ++++-------- drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 3 +-- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 61f948c587ad..422cccf0de86 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1485,8 +1485,7 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION, I40E_SUCCESS, (u8 *)&info, - sizeof(struct - virtchnl_version_info)); + sizeof(struct virtchnl_version_info)); } /** @@ -1544,11 +1543,9 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) } else { if ((pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) && (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ)) - vfres->vf_offload_flags |= - VIRTCHNL_VF_OFFLOAD_RSS_AQ; + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ; else - vfres->vf_offload_flags |= - VIRTCHNL_VF_OFFLOAD_RSS_REG; + vfres->vf_offload_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG; } if (pf->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE) { @@ -2530,8 +2527,7 @@ static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen) /* send the response to the VF */ err: - return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_SET_RSS_HENA, - aq_ret); + return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_SET_RSS_HENA, aq_ret); } /** diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 90a17b0347b9..d9f040900373 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -1018,8 +1018,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, ~(BIT(VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP)); break; case VIRTCHNL_OP_GET_RSS_HENA_CAPS: { - struct virtchnl_rss_hena *vrh = - (struct virtchnl_rss_hena *)msg; + struct virtchnl_rss_hena *vrh = (struct virtchnl_rss_hena *)msg; if (msglen == sizeof(*vrh)) adapter->hena = vrh->hena; else -- cgit v1.2.3 From ff3f4cc267f6f39c2fc525c8918c929809defbfa Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:16 -0700 Subject: virtchnl: finish conversion to virtchnl interface This patch implements the complete version of the virtchnl.h file with final renames, and fixes the related code in i40e and i40evf. It also expands comments, and adds details on the usage of certain fields. In addition, due to the changes a couple of casts are needed to prevent errors found by sparse after renaming some fields. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 18 ++++++++++-------- drivers/net/ethernet/intel/i40evf/i40e_common.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf.h | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 11 ++++++----- drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 6 +++--- 5 files changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 422cccf0de86..352d9d2ef3d2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -77,7 +77,7 @@ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf) int abs_vf_id = vf->vf_id + (int)hw->func_caps.vf_base_id; pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; - pfe.severity = I40E_PF_EVENT_SEVERITY_INFO; + pfe.severity = PF_EVENT_SEVERITY_INFO; if (vf->link_forced) { pfe.event_data.link_event.link_status = vf->link_up; pfe.event_data.link_event.link_speed = @@ -85,7 +85,8 @@ static void i40e_vc_notify_vf_link_state(struct i40e_vf *vf) } else { pfe.event_data.link_event.link_status = ls->link_info & I40E_AQ_LINK_UP; - pfe.event_data.link_event.link_speed = ls->link_speed; + pfe.event_data.link_event.link_speed = + (enum virtchnl_link_speed)ls->link_speed; } i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(pfe), NULL); @@ -116,7 +117,7 @@ void i40e_vc_notify_reset(struct i40e_pf *pf) struct virtchnl_pf_event pfe; pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; - pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM; + pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; i40e_vc_vf_broadcast(pf, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(struct virtchnl_pf_event)); } @@ -144,7 +145,7 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf) abs_vf_id = vf->vf_id + (int)vf->pf->hw.func_caps.vf_base_id; pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; - pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM; + pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; i40e_aq_send_msg_to_vf(&vf->pf->hw, abs_vf_id, VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(struct virtchnl_pf_event), NULL); @@ -1586,7 +1587,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) if (vf->lan_vsi_idx) { vfres->vsi_res[0].vsi_id = vf->lan_vsi_id; - vfres->vsi_res[0].vsi_type = I40E_VSI_SRIOV; + vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV; vfres->vsi_res[0].num_queue_pairs = vsi->alloc_queue_pairs; /* VFs only use TC 0 */ vfres->vsi_res[0].qset_handle @@ -1680,7 +1681,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, goto error_param; } /* Multicast promiscuous handling*/ - if (info->flags & I40E_FLAG_VF_MULTICAST_PROMISC) + if (info->flags & FLAG_VF_MULTICAST_PROMISC) allmulti = true; if (vf->port_vlan_id) { @@ -1731,7 +1732,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, clear_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states); } - if (info->flags & I40E_FLAG_VF_UNICAST_PROMISC) + if (info->flags & FLAG_VF_UNICAST_PROMISC) alluni = true; if (vf->port_vlan_id) { aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid, @@ -3241,7 +3242,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; - pfe.severity = I40E_PF_EVENT_SEVERITY_INFO; + pfe.severity = PF_EVENT_SEVERITY_INFO; switch (link) { case IFLA_VF_LINK_STATE_AUTO: @@ -3249,6 +3250,7 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) pfe.event_data.link_event.link_status = pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP; pfe.event_data.link_event.link_speed = + (enum virtchnl_link_speed) pf->hw.phy.link_info.link_speed; break; case IFLA_VF_LINK_STATE_ENABLE: diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 9a7d995080b6..9dec7753911c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -1107,7 +1107,7 @@ void i40e_vf_parse_hw_config(struct i40e_hw *hw, VIRTCHNL_VF_OFFLOAD_L2; hw->dev_caps.fcoe = 0; for (i = 0; i < msg->num_vsis; i++) { - if (vsi_res->vsi_type == I40E_VSI_SRIOV) { + if (vsi_res->vsi_type == VIRTCHNL_VSI_SRIOV) { ether_addr_copy(hw->mac.perm_addr, vsi_res->default_mac_addr); ether_addr_copy(hw->mac.addr, diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index 9d8c21b36332..6cc92089fecb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -263,7 +263,7 @@ struct i40evf_adapter { struct work_struct watchdog_task; bool netdev_registered; bool link_up; - enum i40e_aq_link_speed link_speed; + enum virtchnl_link_speed link_speed; enum virtchnl_ops current_op; #define CLIENT_ALLOWED(_a) ((_a)->vf_res ? \ (_a)->vf_res->vf_offload_flags & \ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 5d7b613e0d62..1b00274de530 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1707,13 +1707,13 @@ static void i40evf_watchdog_task(struct work_struct *work) } if (adapter->aq_required & I40EVF_FLAG_AQ_REQUEST_PROMISC) { - i40evf_set_promiscuous(adapter, I40E_FLAG_VF_UNICAST_PROMISC | - I40E_FLAG_VF_MULTICAST_PROMISC); + i40evf_set_promiscuous(adapter, FLAG_VF_UNICAST_PROMISC | + FLAG_VF_MULTICAST_PROMISC); goto watchdog_done; } if (adapter->aq_required & I40EVF_FLAG_AQ_REQUEST_ALLMULTI) { - i40evf_set_promiscuous(adapter, I40E_FLAG_VF_MULTICAST_PROMISC); + i40evf_set_promiscuous(adapter, FLAG_VF_MULTICAST_PROMISC); goto watchdog_done; } @@ -1969,7 +1969,8 @@ static void i40evf_adminq_task(struct work_struct *work) break; /* No event to process or error cleaning ARQ */ i40evf_virtchnl_completion(adapter, v_msg->v_opcode, - v_msg->v_retval, event.msg_buf, + (i40e_status)v_msg->v_retval, + event.msg_buf, event.msg_len); if (pending != 0) memset(event.msg_buf, 0, I40EVF_MAX_AQ_BUF_SIZE); @@ -2410,7 +2411,7 @@ int i40evf_process_config(struct i40evf_adapter *adapter) /* got VF config message back from PF, now we can parse it */ for (i = 0; i < vfres->num_vsis; i++) { - if (vfres->vsi_res[i].vsi_type == I40E_VSI_SRIOV) + if (vfres->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV) adapter->vsi_res = &vfres->vsi_res[i]; } if (!adapter->vsi_res) { diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index d9f040900373..d2bb250a71af 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -662,15 +662,15 @@ void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags) return; } - promisc_all = I40E_FLAG_VF_UNICAST_PROMISC | - I40E_FLAG_VF_MULTICAST_PROMISC; + promisc_all = FLAG_VF_UNICAST_PROMISC | + FLAG_VF_MULTICAST_PROMISC; if ((flags & promisc_all) == promisc_all) { adapter->flags |= I40EVF_FLAG_PROMISC_ON; adapter->aq_required &= ~I40EVF_FLAG_AQ_REQUEST_PROMISC; dev_info(&adapter->pdev->dev, "Entering promiscuous mode\n"); } - if (flags & I40E_FLAG_VF_MULTICAST_PROMISC) { + if (flags & FLAG_VF_MULTICAST_PROMISC) { adapter->flags |= I40EVF_FLAG_ALLMULTI_ON; adapter->aq_required &= ~I40EVF_FLAG_AQ_REQUEST_ALLMULTI; dev_info(&adapter->pdev->dev, "Entering multicast promiscuous mode\n"); -- cgit v1.2.3 From 735e35c56bbc91621942dc5111b2970beb00e75a Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2017 11:23:17 -0700 Subject: i40e/virtchnl: move function to virtchnl This moves a function that is needed for the virtchnl interface from the i40e PF driver over to the virtchnl.h file. It was manually verified that the function in question is unchanged except for the function name and function header, which explains the slight difference in the number of lines removed/added. Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 150 +-------------------- 1 file changed, 1 insertion(+), 149 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 352d9d2ef3d2..6bee254d34ee 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2531,154 +2531,6 @@ err: return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_SET_RSS_HENA, aq_ret); } -/** - * i40e_vc_validate_vf_msg - * @ver: Virtchnl version info - * @v_opcode: Opcode for the message - * @msg: pointer to the msg buffer - * @msglen: msg length - * - * validate msg format against struct for each opcode - **/ -static int -i40e_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode, - u8 *msg, u16 msglen) -{ - bool err_msg_format = false; - int valid_len = 0; - - /* Validate message length. */ - switch (v_opcode) { - case VIRTCHNL_OP_VERSION: - valid_len = sizeof(struct virtchnl_version_info); - break; - case VIRTCHNL_OP_RESET_VF: - break; - case VIRTCHNL_OP_GET_VF_RESOURCES: - if (VF_IS_V11(ver)) - valid_len = sizeof(u32); - break; - case VIRTCHNL_OP_CONFIG_TX_QUEUE: - valid_len = sizeof(struct virtchnl_txq_info); - break; - case VIRTCHNL_OP_CONFIG_RX_QUEUE: - valid_len = sizeof(struct virtchnl_rxq_info); - break; - case VIRTCHNL_OP_CONFIG_VSI_QUEUES: - valid_len = sizeof(struct virtchnl_vsi_queue_config_info); - if (msglen >= valid_len) { - struct virtchnl_vsi_queue_config_info *vqc = - (struct virtchnl_vsi_queue_config_info *)msg; - valid_len += (vqc->num_queue_pairs * - sizeof(struct - virtchnl_queue_pair_info)); - if (vqc->num_queue_pairs == 0) - err_msg_format = true; - } - break; - case VIRTCHNL_OP_CONFIG_IRQ_MAP: - valid_len = sizeof(struct virtchnl_irq_map_info); - if (msglen >= valid_len) { - struct virtchnl_irq_map_info *vimi = - (struct virtchnl_irq_map_info *)msg; - valid_len += (vimi->num_vectors * - sizeof(struct virtchnl_vector_map)); - if (vimi->num_vectors == 0) - err_msg_format = true; - } - break; - case VIRTCHNL_OP_ENABLE_QUEUES: - case VIRTCHNL_OP_DISABLE_QUEUES: - valid_len = sizeof(struct virtchnl_queue_select); - break; - case VIRTCHNL_OP_ADD_ETH_ADDR: - case VIRTCHNL_OP_DEL_ETH_ADDR: - valid_len = sizeof(struct virtchnl_ether_addr_list); - if (msglen >= valid_len) { - struct virtchnl_ether_addr_list *veal = - (struct virtchnl_ether_addr_list *)msg; - valid_len += veal->num_elements * - sizeof(struct virtchnl_ether_addr); - if (veal->num_elements == 0) - err_msg_format = true; - } - break; - case VIRTCHNL_OP_ADD_VLAN: - case VIRTCHNL_OP_DEL_VLAN: - valid_len = sizeof(struct virtchnl_vlan_filter_list); - if (msglen >= valid_len) { - struct virtchnl_vlan_filter_list *vfl = - (struct virtchnl_vlan_filter_list *)msg; - valid_len += vfl->num_elements * sizeof(u16); - if (vfl->num_elements == 0) - err_msg_format = true; - } - break; - case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: - valid_len = sizeof(struct virtchnl_promisc_info); - break; - case VIRTCHNL_OP_GET_STATS: - valid_len = sizeof(struct virtchnl_queue_select); - break; - case VIRTCHNL_OP_IWARP: - /* These messages are opaque to us and will be validated in - * the RDMA client code. We just need to check for nonzero - * length. The firmware will enforce max length restrictions. - */ - if (msglen) - valid_len = msglen; - else - err_msg_format = true; - break; - case VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP: - break; - case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: - valid_len = sizeof(struct virtchnl_iwarp_qvlist_info); - if (msglen >= valid_len) { - struct virtchnl_iwarp_qvlist_info *qv = - (struct virtchnl_iwarp_qvlist_info *)msg; - if (qv->num_vectors == 0) { - err_msg_format = true; - break; - } - valid_len += ((qv->num_vectors - 1) * - sizeof(struct virtchnl_iwarp_qv_info)); - } - break; - case VIRTCHNL_OP_CONFIG_RSS_KEY: - valid_len = sizeof(struct virtchnl_rss_key); - if (msglen >= valid_len) { - struct virtchnl_rss_key *vrk = - (struct virtchnl_rss_key *)msg; - valid_len += vrk->key_len - 1; - } - break; - case VIRTCHNL_OP_CONFIG_RSS_LUT: - valid_len = sizeof(struct virtchnl_rss_lut); - if (msglen >= valid_len) { - struct virtchnl_rss_lut *vrl = - (struct virtchnl_rss_lut *)msg; - valid_len += vrl->lut_entries - 1; - } - break; - case VIRTCHNL_OP_GET_RSS_HENA_CAPS: - break; - case VIRTCHNL_OP_SET_RSS_HENA: - valid_len = sizeof(struct virtchnl_rss_hena); - break; - /* These are always errors coming from the VF. */ - case VIRTCHNL_OP_EVENT: - case VIRTCHNL_OP_UNKNOWN: - default: - return VIRTCHNL_ERR_PARAM; - } - /* few more checks */ - if ((valid_len != msglen) || (err_msg_format)) - return VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH; - - return 0; -} - /** * i40e_vc_process_vf_msg * @pf: pointer to the PF structure @@ -2708,7 +2560,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode, return I40E_ERR_PARAM; /* perform basic checks on the msg */ - ret = i40e_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen); + ret = virtchnl_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen); /* perform additional checks specific to this driver */ if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_KEY) { -- cgit v1.2.3 From abf709a1e7316b3f99647bb88c4031b1e62e1c75 Mon Sep 17 00:00:00 2001 From: Preethi Banala Date: Thu, 11 May 2017 11:23:20 -0700 Subject: i40evf: Add support for Adaptive Virtual Function Add device ID define and mac_type assignment needed for Adaptive Virtual Function (VF Base Mode Support). Also, update version to v3.0.0 in order to indicate clearly that this is the first driver supporting the AVF device ID. Signed-off-by: Preethi Banala Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/Kconfig | 10 ++++++---- drivers/net/ethernet/intel/i40evf/i40e_common.c | 1 + drivers/net/ethernet/intel/i40evf/i40e_devids.h | 1 + drivers/net/ethernet/intel/i40evf/i40evf_main.c | 7 ++++--- 4 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 1542a2158e96..1feb54b6d92e 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -236,12 +236,14 @@ config I40E_DCB If unsure, say N. config I40EVF - tristate "Intel(R) XL710 X710 Virtual Function Ethernet support" + tristate "Intel(R) Ethernet Adaptive Virtual Function support" depends on PCI_MSI ---help--- - This driver supports Intel(R) XL710 and X710 virtual functions. - For more information on how to identify your adapter, go to the - Adapter & Driver ID Guide that can be located at: + This driver supports virtual functions for Intel XL710, + X710, X722, and all devices advertising support for Intel + Ethernet Adaptive Virtual Function devices. For more + information on how to identify your adapter, go to the Adapter + & Driver ID Guide that can be located at: diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 9dec7753911c..1dd1938f594f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -68,6 +68,7 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw) break; case I40E_DEV_ID_VF: case I40E_DEV_ID_VF_HV: + case I40E_DEV_ID_ADAPTIVE_VF: hw->mac.type = I40E_MAC_VF; break; default: diff --git a/drivers/net/ethernet/intel/i40evf/i40e_devids.h b/drivers/net/ethernet/intel/i40evf/i40e_devids.h index d76393c95056..0469e4bfd3ec 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_devids.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_devids.h @@ -43,6 +43,7 @@ #define I40E_DEV_ID_25G_SFP28 0x158B #define I40E_DEV_ID_VF 0x154C #define I40E_DEV_ID_VF_HV 0x1571 +#define I40E_DEV_ID_ADAPTIVE_VF 0x1889 #define I40E_DEV_ID_SFP_X722 0x37D0 #define I40E_DEV_ID_1G_BASE_T_X722 0x37D1 #define I40E_DEV_ID_10G_BASE_T_X722 0x37D2 diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 1b00274de530..3a3ca965b242 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -44,9 +44,9 @@ static const char i40evf_driver_string[] = #define DRV_KERN "-k" -#define DRV_VERSION_MAJOR 2 -#define DRV_VERSION_MINOR 1 -#define DRV_VERSION_BUILD 14 +#define DRV_VERSION_MAJOR 3 +#define DRV_VERSION_MINOR 0 +#define DRV_VERSION_BUILD 0 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) \ @@ -67,6 +67,7 @@ static const struct pci_device_id i40evf_pci_tbl[] = { {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF_HV), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_X722_VF), 0}, + {PCI_VDEVICE(INTEL, I40E_DEV_ID_ADAPTIVE_VF), 0}, /* required last entry */ {0, } }; -- cgit v1.2.3 From d49394a131060fda209ba91e903c9d6316db2e4d Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 5 Mar 2017 13:01:08 +0200 Subject: iwlwifi: mvm: flush per station for DQA mode Avoid using the global flush and move to flush per station whenever possible in DQA mode. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 26 ++++++++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 6 ++++- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 5 ++++- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 17 ++++++++++++++ 5 files changed, 42 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index a67aa1f5a51c..f4437d5b2e73 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1451,7 +1451,7 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, { u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif); - if (tfd_msk) { + if (tfd_msk && !iwl_mvm_is_dqa_supported(mvm)) { /* * mac80211 first removes all the stations of the vif and * then removes the vif. When it removes a station it also @@ -1460,6 +1460,8 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, * of these AMPDU sessions are properly closed. * We still need to take care of the shared queues of the vif. * Flush them here. + * For DQA mode there is no need - broacast and multicast queue + * are flushed separately. */ mutex_lock(&mvm->mutex); iwl_mvm_flush_tx_path(mvm, tfd_msk, 0); @@ -3988,21 +3990,21 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, /* make sure only TDLS peers or the AP are flushed */ WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls); - msk |= mvmsta->tfd_queue_msk; + if (drop) { + if (iwl_mvm_flush_sta(mvm, mvmsta, false, 0)) + IWL_ERR(mvm, "flush request fail\n"); + } else { + msk |= mvmsta->tfd_queue_msk; + } } - if (drop) { - if (iwl_mvm_flush_tx_path(mvm, msk, 0)) - IWL_ERR(mvm, "flush request fail\n"); - mutex_unlock(&mvm->mutex); - } else { - mutex_unlock(&mvm->mutex); + mutex_unlock(&mvm->mutex); - /* this can take a while, and we may need/want other operations - * to succeed while doing this, so do it without the mutex held - */ + /* this can take a while, and we may need/want other operations + * to succeed while doing this, so do it without the mutex held + */ + if (!drop) iwl_trans_wait_tx_queues_empty(mvm->trans, msk); - } } static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 4e74a6b90e70..53fbdb9136ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1355,6 +1355,8 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status); static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } #endif int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags); +int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool int_sta, u32 flags); + void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index f5c786ddc526..bf105c6572ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1611,7 +1611,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (ret) return ret; /* flush its queues here since we are freeing mvm_sta */ - ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, 0); + ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0); if (ret) return ret; ret = iwl_trans_wait_tx_queues_empty(mvm->trans, @@ -1978,6 +1978,8 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); + iwl_mvm_flush_sta(mvm, &mvmvif->bcast_sta, true, 0); + if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC) iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue, @@ -2176,6 +2178,8 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (!iwl_mvm_is_dqa_supported(mvm)) return 0; + iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0); + iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue, IWL_MAX_TID_COUNT, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 2c12789e7550..3e4fa853b44d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -130,7 +130,10 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) * issue as it will have to complete before the next command is * executed, and a new time event means a new command. */ - iwl_mvm_flush_tx_path(mvm, queues, CMD_ASYNC); + if (iwl_mvm_is_dqa_supported(mvm)) + iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true, CMD_ASYNC); + else + iwl_mvm_flush_tx_path(mvm, queues, CMD_ASYNC); } static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index bcaceb64a6e8..aa76c8baecce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1884,3 +1884,20 @@ int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags) IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret); return ret; } + +int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool int_sta, u32 flags) +{ + u32 mask; + + if (int_sta) { + struct iwl_mvm_int_sta *int_sta = sta; + + mask = int_sta->tfd_queue_msk; + } else { + struct iwl_mvm_sta *mvm_sta = sta; + + mask = mvm_sta->tfd_queue_msk; + } + + return iwl_mvm_flush_tx_path(mvm, mask, flags); +} -- cgit v1.2.3 From e9e1ba3dbf00bb2eed4e681ae59f433e45d2e78f Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 8 Jan 2017 16:46:14 +0200 Subject: iwlwifi: mvm: support getting nvm data from firmware This API replaces the complex NVM parsing of the iwlwifi module. Instead, we get all needed data from firmware. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 77 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 37 +++++----- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 + drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 90 ++++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 9 ++- 6 files changed, 194 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index f545c5f9e4e3..0996127897c1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -345,6 +345,7 @@ enum iwl_prot_offload_subcmd_ids { enum iwl_regulatory_and_nvm_subcmd_ids { NVM_ACCESS_COMPLETE = 0x0, + NVM_GET_INFO = 0x2, }; enum iwl_debug_cmds { @@ -2259,4 +2260,80 @@ struct iwl_init_extended_cfg_cmd { __le32 init_flags; } __packed; /* INIT_EXTENDED_CFG_CMD_API_S_VER_1 */ +/* + * struct iwl_nvm_get_info - request to get NVM data + */ +struct iwl_nvm_get_info { + __le32 reserved; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_general - general NVM data + * @flags: 1 - empty, 0 - valid + * @nvm_version: nvm version + * @board_type: board type + */ +struct iwl_nvm_get_info_general { + __le32 flags; + __le16 nvm_version; + u8 board_type; + u8 reserved; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_GENERAL_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_sku - mac information + * @enable_24g: band 2.4G enabled + * @enable_5g: band 5G enabled + * @enable_11n: 11n enabled + * @enable_11ac: 11ac enabled + * @mimo_disable: MIMO enabled + * @ext_crypto: Extended crypto enabled + */ +struct iwl_nvm_get_info_sku { + __le32 enable_24g; + __le32 enable_5g; + __le32 enable_11n; + __le32 enable_11ac; + __le32 mimo_disable; + __le32 ext_crypto; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_MAC_SKU_SECTION_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_phy - phy information + * @tx_chains: BIT 0 chain A, BIT 1 chain B + * @rx_chains: BIT 0 chain A, BIT 1 chain B + */ +struct iwl_nvm_get_info_phy { + __le32 tx_chains; + __le32 rx_chains; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ + +#define IWL_NUM_CHANNELS (51) + +/** + * struct iwl_nvm_get_info_regulatory - regulatory information + * @lar_enabled: is LAR enabled + * @channel_profile: regulatory data of this channel + * @regulatory: regulatory data, see &enum iwl_nvm_channel_flags for data + */ +struct iwl_nvm_get_info_regulatory { + __le32 lar_enabled; + __le16 channel_profile[IWL_NUM_CHANNELS]; + __le16 reserved; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_rsp - response to get NVM data + * @general: general NVM data + * @mac_sku: data relating to MAC sku + * @phy_sku: data relating to PHY sku + * @regulatory: regulatory data + */ +struct iwl_nvm_get_info_rsp { + struct iwl_nvm_get_info_general general; + struct iwl_nvm_get_info_sku mac_sku; + struct iwl_nvm_get_info_phy phy_sku; + struct iwl_nvm_get_info_regulatory regulatory; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_1 */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index e6c9528eeeda..3d68595243fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -738,23 +738,11 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) goto error; } - /* Read the NVM only at driver load time, no need to do this twice */ - if (read_nvm) { - /* Read nvm */ - ret = iwl_nvm_init(mvm, true); - if (ret) { - IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); - goto error; - } - } - - /* In case we read the NVM from external file, load it to the NIC */ - if (mvm->nvm_file_name) + /* Load NVM to NIC if needed */ + if (mvm->nvm_file_name) { + iwl_mvm_read_external_nvm(mvm); iwl_mvm_load_nvm_to_nic(mvm); - - ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); - if (WARN_ON(ret)) - goto error; + } ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_ACCESS_COMPLETE), 0, @@ -766,8 +754,21 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) } /* We wait for the INIT complete notification */ - return iwl_wait_notification(&mvm->notif_wait, &init_wait, - MVM_UCODE_ALIVE_TIMEOUT); + ret = iwl_wait_notification(&mvm->notif_wait, &init_wait, + MVM_UCODE_ALIVE_TIMEOUT); + if (ret) + return ret; + + /* Read the NVM only at driver load time, no need to do this twice */ + if (read_nvm) { + ret = iwl_mvm_nvm_get_from_fw(mvm); + if (ret) { + IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); + return ret; + } + } + + return 0; error: iwl_remove_notification(&mvm->notif_wait, &init_wait); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 53fbdb9136ab..aa725bbb90ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1383,7 +1383,9 @@ void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm); /* NVM */ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic); +int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm); int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm); +int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm); static inline u8 iwl_mvm_get_valid_tx_ant(struct iwl_mvm *mvm) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 283c41df622c..67a6c9c9af27 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -374,7 +374,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) * * 4. save as "iNVM_xxx.bin" under /lib/firmware */ -static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) +int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) { int ret, section_size; u16 section_id; @@ -551,6 +551,94 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm) return ret; } +int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm) +{ + struct iwl_nvm_get_info cmd = {}; + struct iwl_nvm_get_info_rsp *rsp; + struct iwl_trans *trans = mvm->trans; + struct iwl_host_cmd hcmd = { + .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, + .data = { &cmd, }, + .len = { sizeof(cmd) }, + .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO) + }; + int ret; + bool lar_fw_supported = !iwlwifi_mod_params.lar_disable && + fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_LAR_SUPPORT); + + lockdep_assert_held(&mvm->mutex); + + ret = iwl_mvm_send_cmd(mvm, &hcmd); + if (ret) + return ret; + + if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp), + "Invalid payload len in NVM response from FW %d", + iwl_rx_packet_payload_len(hcmd.resp_pkt))) { + ret = -EINVAL; + goto out; + } + + rsp = (void *)hcmd.resp_pkt->data; + if (le32_to_cpu(rsp->general.flags)) { + IWL_ERR(mvm, "Invalid NVM data from FW\n"); + ret = -EINVAL; + goto out; + } + + mvm->nvm_data = kzalloc(sizeof(*mvm->nvm_data) + + sizeof(struct ieee80211_channel) * + IWL_NUM_CHANNELS, GFP_KERNEL); + if (!mvm->nvm_data) { + ret = -ENOMEM; + goto out; + } + + iwl_set_hw_address_from_csr(trans, mvm->nvm_data); + /* TODO: if platform NVM has MAC address - override it here */ + + if (!is_valid_ether_addr(mvm->nvm_data->hw_addr)) { + IWL_ERR(trans, "no valid mac address was found\n"); + ret = -EINVAL; + goto out; + } + + /* Initialize general data */ + mvm->nvm_data->nvm_version = le16_to_cpu(rsp->general.nvm_version); + + /* Initialize MAC sku data */ + mvm->nvm_data->sku_cap_11ac_enable = + le32_to_cpu(rsp->mac_sku.enable_11ac); + mvm->nvm_data->sku_cap_11n_enable = + le32_to_cpu(rsp->mac_sku.enable_11n); + mvm->nvm_data->sku_cap_band_24GHz_enable = + le32_to_cpu(rsp->mac_sku.enable_24g); + mvm->nvm_data->sku_cap_band_52GHz_enable = + le32_to_cpu(rsp->mac_sku.enable_5g); + mvm->nvm_data->sku_cap_mimo_disabled = + le32_to_cpu(rsp->mac_sku.mimo_disable); + + /* Initialize PHY sku data */ + mvm->nvm_data->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); + mvm->nvm_data->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains); + + /* Initialize regulatory data */ + mvm->nvm_data->lar_enabled = + le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported; + + iwl_init_sbands(trans->dev, trans->cfg, mvm->nvm_data, + rsp->regulatory.channel_profile, + mvm->nvm_data->valid_tx_ant & mvm->fw->valid_tx_ant, + mvm->nvm_data->valid_rx_ant & mvm->fw->valid_rx_ant, + rsp->regulatory.lar_enabled && lar_fw_supported); + + ret = 0; +out: + iwl_free_resp(&hcmd); + return ret; +} + int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) { int ret, section; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 9ffff6ed8133..607cc83908b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -483,6 +483,7 @@ static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_regulatory_and_nvm_names[] = { HCMD_NAME(NVM_ACCESS_COMPLETE), + HCMD_NAME(NVM_GET_INFO), }; static const struct iwl_hcmd_arr iwl_mvm_groups[] = { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 9fb46a6f47cf..9c9bfbbabdf1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -906,7 +906,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, if (WARN_ON(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp))) { ret = -EINVAL; - goto error; + goto error_free_resp; } rsp = (void *)hcmd.resp_pkt->data; @@ -915,13 +915,13 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, if (qid > ARRAY_SIZE(trans_pcie->txq)) { WARN_ONCE(1, "queue index %d unsupported", qid); ret = -EIO; - goto error; + goto error_free_resp; } if (test_and_set_bit(qid, trans_pcie->queue_used)) { WARN_ONCE(1, "queue %d already used", qid); ret = -EIO; - goto error; + goto error_free_resp; } txq->id = qid; @@ -934,8 +934,11 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, (txq->write_ptr) | (qid << 16)); IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d\n", qid); + iwl_free_resp(&hcmd); return qid; +error_free_resp: + iwl_free_resp(&hcmd); error: iwl_pcie_gen2_txq_free_memory(trans, txq); return ret; -- cgit v1.2.3 From d4f3695eccf9481801d42bebc7a282c5a2af7281 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 6 Mar 2017 11:13:02 +0200 Subject: iwlwifi: mvm: support old method of NVM parsing Add configuration for allowing driver's nvm parsing and bypassing the new host command, for debugging. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/constants.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 4eeb6b78d952..6fda8627b726 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -110,6 +110,7 @@ #define IWL_MVM_TOF_IS_RESPONDER 0 #define IWL_MVM_SW_TX_CSUM_OFFLOAD 0 #define IWL_MVM_HW_CSUM_DISABLE 0 +#define IWL_MVM_PARSE_NVM 0 #define IWL_MVM_COLLECT_FW_ERR_DUMP 1 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 3d68595243fc..a8804bc979fe 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -744,6 +744,14 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) iwl_mvm_load_nvm_to_nic(mvm); } + if (IWL_MVM_PARSE_NVM && read_nvm) { + ret = iwl_nvm_init(mvm, true); + if (ret) { + IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); + goto error; + } + } + ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_ACCESS_COMPLETE), 0, sizeof(nvm_complete), &nvm_complete); @@ -760,7 +768,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) return ret; /* Read the NVM only at driver load time, no need to do this twice */ - if (read_nvm) { + if (!IWL_MVM_PARSE_NVM && read_nvm) { ret = iwl_mvm_nvm_get_from_fw(mvm); if (ret) { IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); -- cgit v1.2.3 From 6909afcade61f760b528118ccb837c8506c23cc1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Mar 2017 13:40:23 +0100 Subject: iwlwifi: mvm: fix endianness in lq_cmd declaration This member doesn't seem to be used, so this doesn't really fix anything, but it's better to have the right type there. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h index 1b7d265ffb0a..019a9a92a1ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h @@ -387,7 +387,7 @@ enum { struct iwl_lq_cmd { u8 sta_id; u8 reduced_tpc; - u16 control; + __le16 control; /* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */ u8 flags; u8 mimo_delim; -- cgit v1.2.3 From 72361c3d28cf4102b7b514609d3710707b1a1096 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Mar 2017 17:06:45 +0100 Subject: iwlwifi: mvm: document which group enums are used with which group ID Make it explicit which command definition enum is supposed to be used with which command group, rather than relying on being able to figure it out by name. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 27 ++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 0996127897c1..c69aff91404b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -131,7 +131,7 @@ enum iwl_mvm_tx_fifo { /* commands */ -enum { +enum iwl_legacy_cmds { MVM_ALIVE = 0x1, REPLY_ERROR = 0x2, ECHO_CMD = 0x3, @@ -354,8 +354,29 @@ enum iwl_debug_cmds { MFU_ASSERT_DUMP_NTF = 0xFE, }; -/* command groups */ -enum { +/** + * enum iwl_mvm_command_groups - command groups for the firmware + * @LEGACY_GROUP: legacy group, uses command IDs from &enum iwl_legacy_cmds + * @LONG_GROUP: legacy group with long header, also uses command IDs + * from &enum iwl_legacy_cmds + * @SYSTEM_GROUP: system group, uses command IDs from + * &enum iwl_system_subcmd_ids + * @MAC_CONF_GROUP: MAC configuration group, uses command IDs from + * &enum iwl_mac_conf_subcmd_ids + * @PHY_OPS_GROUP: PHY operations group, uses command IDs from + * &enum iwl_phy_ops_subcmd_ids + * @DATA_PATH_GROUP: data path group, uses command IDs from + * &enum iwl_data_path_subcmd_ids + * @SCAN_GROUP: scan group, uses command IDs from &enum iwl_scan_subcmd_ids + * @NAN_GROUP: NAN group, uses command IDs from &enum iwl_nan_subcmd_ids + * @TOF_GROUP: TOF group, uses command IDs from &enum iwl_tof_subcmd_ids + * @PROT_OFFLOAD_GROUP: protocol offload group, uses command IDs from + * &enum iwl_prot_offload_subcmd_ids + * @REGULATORY_AND_NVM_GROUP: regulatory/NVM group, uses command IDs from + * &enum iwl_regulatory_and_nvm_subcmd_ids + * @DEBUG_GROUP: Debug group, uses command IDs from &enum iwl_debug_cmds + */ +enum iwl_mvm_command_groups { LEGACY_GROUP = 0x0, LONG_GROUP = 0x1, SYSTEM_GROUP = 0x2, -- cgit v1.2.3 From 3dc6dd9698174b2cf6d078ddfba39ff8640afe47 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Mar 2017 14:08:51 +0100 Subject: iwlwifi: mvm: use proper sta_addr in firmware API There's no point to declare an address as a __le32/__le16 and then only take a pointer to it anyway, change that to just a sta_addr[ETH_ALEN]. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 6 ++---- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 81b98915b1a4..c03fbb81efd1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -594,8 +594,7 @@ struct iwl_mvm_tx_resp { /** * struct iwl_mvm_ba_notif - notifies about reception of BA * ( BA_NOTIF = 0xc5 ) - * @sta_addr_lo32: lower 32 bits of the MAC address - * @sta_addr_hi16: upper 16 bits of the MAC address + * @sta_addr: MAC address * @sta_id: Index of recipient (BA-sending) station in fw's station table * @tid: tid of the session * @seq_ctl: @@ -609,8 +608,7 @@ struct iwl_mvm_tx_resp { * for Tx-ing then this value will be set to 0 by FW. */ struct iwl_mvm_ba_notif { - __le32 sta_addr_lo32; - __le16 sta_addr_hi16; + u8 sta_addr[ETH_ALEN]; __le16 reserved; u8 sta_id; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index aa76c8baecce..64ca8b92f8d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1850,7 +1850,7 @@ out: IWL_DEBUG_TX_REPLY(mvm, "BA_NOTIFICATION Received from %pM, sta_id = %d\n", - (u8 *)&ba_notif->sta_addr_lo32, ba_notif->sta_id); + ba_notif->sta_addr, ba_notif->sta_id); IWL_DEBUG_TX_REPLY(mvm, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n", -- cgit v1.2.3 From 56c1f3c4bd1ee04f8032345fba97cff616fea22a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Mar 2017 12:07:52 +0100 Subject: iwlwifi: mvm: fix MCC endianness bug Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index c69aff91404b..8e4919a27cc7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -1681,7 +1681,7 @@ struct iwl_mcc_update_resp { * @reserved1: reserved for alignment */ struct iwl_mcc_chub_notif { - u16 mcc; + __le16 mcc; u8 source_id; u8 reserved1; } __packed; /* LAR_MCC_NOTIFY_S */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 67a6c9c9af27..e7b16ecccb86 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -913,8 +913,8 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) return; - mcc[0] = notif->mcc >> 8; - mcc[1] = notif->mcc & 0xff; + mcc[0] = le16_to_cpu(notif->mcc) >> 8; + mcc[1] = le16_to_cpu(notif->mcc) & 0xff; mcc[2] = '\0'; src = notif->source_id; -- cgit v1.2.3 From aed35826d67f31afe010c1d25d204badf7057a25 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Mar 2017 12:47:37 +0100 Subject: iwlwifi: mvm: use u8 for reserved fields There's no saying what kind of type a reserved field will get in the future, so use u8 arrays to reserve space. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h index 6371c342b96d..809ec1ba5025 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h @@ -72,7 +72,7 @@ struct mvm_statistics_dbg { __le32 burst_check; __le32 burst_count; __le32 wait_for_silence_timeout_cnt; - __le32 reserved[3]; + u8 reserved[12]; } __packed; /* STATISTICS_DEBUG_API_S_VER_2 */ struct mvm_statistics_div { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 8e4919a27cc7..69f3065ba600 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -1612,7 +1612,7 @@ struct iwl_mcc_update_cmd { u8 source_id; u8 reserved; __le32 key; - __le32 reserved2[5]; + u8 reserved2[20]; } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */ /** @@ -2196,7 +2196,7 @@ struct iwl_link_qual_msrmnt_notif { __le32 tx_frame_dropped; __le32 mac_id; __le32 status; - __le32 reserved[3]; + u8 reserved[12]; } __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */ /** -- cgit v1.2.3 From 3b43fbcac4765ac5f7b92464b7d9685eaa34467b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Mar 2017 21:48:39 +0100 Subject: iwlwifi: mvm: disentangle paging command structs Instead of using a union and hard-coding the size difference, declare both command structs properly, use a union on the stack to build them and the right sizeof() for the size. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 29 +++++++++++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 19 +++++++++------- 2 files changed, 33 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 69f3065ba600..a1cce18460bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -508,7 +508,26 @@ struct iwl_nvm_access_cmd { #define NUM_OF_FW_PAGING_BLOCKS 33 /* 32 for data and 1 block for CSS */ -/* +/** + * struct iwl_fw_paging_cmd_v1 - paging layout + * + * (FW_PAGING_BLOCK_CMD = 0x4f) + * + * Send to FW the paging layout in the driver. + * + * @flags: various flags for the command + * @block_size: the block size in powers of 2 + * @block_num: number of blocks specified in the command. + * @device_phy_addr: virtual addresses from device side + */ +struct iwl_fw_paging_cmd_v1 { + __le32 flags; + __le32 block_size; + __le32 block_num; + __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; +} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ + +/** * struct iwl_fw_paging_cmd - paging layout * * (FW_PAGING_BLOCK_CMD = 0x4f) @@ -519,16 +538,12 @@ struct iwl_nvm_access_cmd { * @block_size: the block size in powers of 2 * @block_num: number of blocks specified in the command. * @device_phy_addr: virtual addresses from device side - * 32 bit address for API version 1, 64 bit address for API version 2. -*/ + */ struct iwl_fw_paging_cmd { __le32 flags; __le32 block_size; __le32 block_num; - union { - __le32 addr32[NUM_OF_FW_PAGING_BLOCKS]; - __le64 addr64[NUM_OF_FW_PAGING_BLOCKS]; - } device_phy_addr; + __le64 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; } __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_2 */ /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index a8804bc979fe..8bdeb7c891e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -384,20 +384,23 @@ static int iwl_save_fw_paging(struct iwl_mvm *mvm, /* send paging cmd to FW in case CPU2 has paging image */ static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) { - struct iwl_fw_paging_cmd paging_cmd = { - .flags = + union { + struct iwl_fw_paging_cmd v2; + struct iwl_fw_paging_cmd_v1 v1; + } paging_cmd = { + .v2.flags = cpu_to_le32(PAGING_CMD_IS_SECURED | PAGING_CMD_IS_ENABLED | (mvm->num_of_pages_in_last_blk << PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), - .block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), - .block_num = cpu_to_le32(mvm->num_of_paging_blk), + .v2.block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), + .v2.block_num = cpu_to_le32(mvm->num_of_paging_blk), }; - int blk_idx, size = sizeof(paging_cmd); + int blk_idx, size = sizeof(paging_cmd.v2); /* A bit hard coded - but this is the old API and will be deprecated */ if (!iwl_mvm_has_new_tx_api(mvm)) - size -= NUM_OF_FW_PAGING_BLOCKS * 4; + size = sizeof(paging_cmd.v1); /* loop for for all paging blocks + CSS block */ for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { @@ -408,11 +411,11 @@ static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) if (iwl_mvm_has_new_tx_api(mvm)) { __le64 phy_addr = cpu_to_le64(addr); - paging_cmd.device_phy_addr.addr64[blk_idx] = phy_addr; + paging_cmd.v2.device_phy_addr[blk_idx] = phy_addr; } else { __le32 phy_addr = cpu_to_le32(addr); - paging_cmd.device_phy_addr.addr32[blk_idx] = phy_addr; + paging_cmd.v1.device_phy_addr[blk_idx] = phy_addr; } } -- cgit v1.2.3 From 816dc0bc549a34673ef6533b3cb9c135c0b869f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Mar 2017 10:55:09 +0100 Subject: iwlwifi: mvm: add documentation to some WoWLAN commands Add some documentation for the WoWLAN commands, also linking the correct enums used. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h | 29 +++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h index 5f22cc7ac26a..edde49202786 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -254,6 +255,17 @@ enum iwl_wowlan_flags { ENABLE_STORE_BEACON = BIT(4), }; +/** + * struct iwl_wowlan_config_cmd - WoWLAN configuration + * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters + * @non_qos_seq: non-QoS sequence counter to use next + * @qos_seq: QoS sequence counters to use next + * @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down + * @is_11n_connection: indicates HT connection + * @offloading_tid: TID reserved for firmware use + * @flags: extra flags, see &enum iwl_wowlan_flags + * @reserved: reserved + */ struct iwl_wowlan_config_cmd { __le32 wakeup_filter; __le16 non_qos_seq; @@ -370,6 +382,21 @@ struct iwl_wowlan_gtk_status { struct iwl_wowlan_rsc_tsc_params_cmd rsc; } __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */ +/** + * struct iwl_wowlan_status - WoWLAN status + * @gtk: GTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched pattern + * @non_qos_seq_ctr: non-QoS sequence counter to use next + * @qos_seq_ctr: QoS sequence counters to use next + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @wake_packet_length: wakeup packet length + * @wake_packet_bufsize: wakeup packet buffer size + * @wake_packet: wakeup packet + */ struct iwl_wowlan_status { struct iwl_wowlan_gtk_status gtk; __le64 replay_ctr; -- cgit v1.2.3 From 0b90964a265d6e0b60182b88f3947c6ef0ae4184 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 9 Mar 2017 13:09:03 +0200 Subject: iwlwifi: mvm: wait for the flushed queue only The function flushed only agg queue and no more traffic is queued on it. However, it waits for all queues to empty, which is not necessary and may take more time. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index bf105c6572ba..9f74d4ff6b73 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2850,8 +2850,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_drain_sta(mvm, mvmsta, true); if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), 0)) IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); - iwl_trans_wait_tx_queues_empty(mvm->trans, - mvmsta->tfd_queue_msk); + iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(txq_id)); iwl_mvm_drain_sta(mvm, mvmsta, false); iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); -- cgit v1.2.3 From 31a658b2afc7bff8a4d51418677b579d85060b31 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Mar 2017 15:56:57 +0100 Subject: iwlwifi: mvm: fix some kernel-doc This mostly fixes missing tags/struct names, but also some other things. Lots of issues remain though. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 4 +- .../net/wireless/intel/iwlwifi/mvm/fw-api-power.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 7 +-- .../net/wireless/intel/iwlwifi/mvm/fw-api-scan.h | 32 +++++------ .../net/wireless/intel/iwlwifi/mvm/fw-api-sta.h | 22 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 17 +++--- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 62 +++++++++++----------- 7 files changed, 78 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 44419e82da1b..89bc008e152f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -395,8 +395,8 @@ enum iwl_ucode_tlv_capa { #define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) #define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) -/* - * Calibration control struct. +/** + * struct iwl_tlv_calib_ctrl - Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to * flow triggers. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h index 750510aff70b..3d56ba4c0c71 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h @@ -411,7 +411,7 @@ struct iwl_geo_tx_power_profiles_cmd { * Threshold. Typical energy threshold is -72dBm. * @bf_temp_threshold: This threshold determines the type of temperature * filtering (Slow or Fast) that is selected (Units are in Celsuis): - * If the current temperature is above this threshold - Fast filter + * If the current temperature is above this threshold - Fast filter * will be used, If the current temperature is below this threshold - * Slow filter will be used. * @bf_temp_fast_filter: Send Beacon to driver if delta in temperature values diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index b530fa47d68a..67dffd725690 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -147,7 +147,8 @@ enum iwl_csum_rx_assist_info { /** * struct iwl_rx_mpdu_res_start - phy info - * @assist: see CSUM_RX_ASSIST_ above + * @byte_count: byte count of the frame + * @assist: see &enum iwl_csum_rx_assist_info */ struct iwl_rx_mpdu_res_start { __le16 byte_count; @@ -447,7 +448,7 @@ struct iwl_rxq_sync_notification { } __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */ /** - * Internal message identifier + * enum iwl_mvm_rxq_notif_type - Internal message identifier * * @IWL_MVM_RXQ_EMPTY: empty sync notification * @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA @@ -491,7 +492,7 @@ enum iwl_mvm_pm_event { /** * struct iwl_mvm_pm_state_notification - station PM state notification * @sta_id: station ID of the station changing state - * @type: the new powersave state, see IWL_MVM_PM_EVENT_ above + * @type: the new powersave state, see &enum iwl_mvm_pm_event */ struct iwl_mvm_pm_state_notification { u8 sta_id; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h index 3178eb96e395..dded91d7eb96 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -111,7 +112,7 @@ enum scan_framework_client { }; /** - * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S + * struct iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S * @ssid: MAC address to filter out * @reported_rssi: AP rssi reported to the host * @client_bitmap: clients ignore this entry - enum scan_framework_client @@ -135,7 +136,7 @@ enum iwl_scan_offload_band_selection { }; /** - * iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S + * struct iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S * @ssid_index: index to ssid list in fixed part * @unicast_cipher: encryption algorithm to match - bitmap * @aut_alg: authentication algorithm to match - bitmap @@ -154,8 +155,7 @@ struct iwl_scan_offload_profile { } __packed; /** - * iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1 - * @blaclist: AP list to filter off from scan results + * struct iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1 * @profiles: profiles to search for match * @blacklist_len: length of blacklist * @num_profiles: num of profiles in the list @@ -176,7 +176,7 @@ struct iwl_scan_offload_profile_cfg { } __packed; /** - * iwl_scan_schedule_lmac - schedule of scan offload + * struct iwl_scan_schedule_lmac - schedule of scan offload * @delay: delay between iterations, in seconds. * @iterations: num of scan iterations * @full_scan_mul: number of partial scans before each full scan @@ -200,7 +200,7 @@ enum iwl_scan_ebs_status { }; /** - * iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S + * struct iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S * @tx_flags: combination of TX_CMD_FLG_* * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* @@ -220,7 +220,7 @@ enum iwl_scan_channel_flags_lmac { }; /** - * iwl_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2 + * struct iwl_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2 * @flags: bits 1-20: directed scan to i'th ssid * other bits &enum iwl_scan_channel_flags_lmac * @channel_number: channel number 1-13 etc @@ -235,7 +235,7 @@ struct iwl_scan_channel_cfg_lmac { } __packed; /* - * iwl_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1 + * struct iwl_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1 * @offset: offset in the data block * @len: length of the segment */ @@ -263,7 +263,7 @@ enum iwl_scan_channel_flags { IWL_SCAN_CHANNEL_FLAG_CACHE_ADD = BIT(2), }; -/* iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S +/* struct iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S * @flags: enum iwl_scan_channel_flags * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is * involved. @@ -276,7 +276,7 @@ struct iwl_scan_channel_opt { } __packed; /** - * iwl_mvm_lmac_scan_flags + * enum iwl_mvm_lmac_scan_flags - LMAC scan flags * @IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL: pass all beacons and probe responses * without filtering. * @IWL_MVM_LMAC_SCAN_FLAG_PASSIVE: force passive scan on all channels @@ -320,7 +320,7 @@ enum iwl_scan_priority_ext { }; /** - * iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1 + * struct iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1 * @reserved1: for alignment and future use * @channel_num: num of channels to scan * @active-dwell: dwell time for active channels @@ -410,7 +410,7 @@ struct iwl_lmac_scan_complete_notif { } __packed; /** - * iwl_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 + * struct iwl_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 * @last_schedule_line: last schedule line executed (fast or regular) * @last_schedule_iteration: last scan iteration executed before scan abort * @status: enum iwl_scan_offload_complete_status @@ -547,12 +547,12 @@ struct iwl_scan_config { } __packed; /* SCAN_CONFIG_DB_CMD_API_S_3 */ /** - * iwl_umac_scan_flags - *@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request + * enum iwl_umac_scan_flags - UMAC scan flags + * @IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request * can be preempted by other scan requests with higher priority. * The low priority scan will be resumed when the higher proirity scan is * completed. - *@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver + * @IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver * when scan starts. */ enum iwl_umac_scan_flags { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 421b9dd1fb66..894b8f6c8adc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -223,7 +223,7 @@ enum iwl_sta_sleep_flag { /** * struct iwl_mvm_keyinfo - key information - * @key_flags: type %iwl_sta_key_flag + * @key_flags: type &enum iwl_sta_key_flag * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx * @key_offset: key offset in the fw's key table @@ -258,12 +258,13 @@ struct iwl_mvm_keyinfo { * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to - * @addr[ETH_ALEN]: station's MAC address + * @addr: station's MAC address * @sta_id: index of station in uCode's station table * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. - * @station_flags: look at %iwl_sta_flags - * @station_flags_msk: what of %station_flags have changed + * @station_flags: look at &enum iwl_sta_flags + * @station_flags_msk: what of %station_flags have changed, + * also &enum iwl_sta_flags * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. @@ -274,7 +275,7 @@ struct iwl_mvm_keyinfo { * @sleep_tx_count: number of packets to transmit to station even though it is * asleep. Used to synchronise PS-poll and u-APSD responses while ucode * keeps track of STA sleep state. - * @sleep_state_flags: Look at %iwl_sta_sleep_flag. + * @sleep_state_flags: Look at &enum iwl_sta_sleep_flag. * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP * mac-addr. * @beamform_flags: beam forming controls @@ -335,12 +336,13 @@ enum iwl_sta_type { * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to - * @addr[ETH_ALEN]: station's MAC address + * @addr: station's MAC address * @sta_id: index of station in uCode's station table * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. - * @station_flags: look at %iwl_sta_flags - * @station_flags_msk: what of %station_flags have changed + * @station_flags: look at &enum iwl_sta_flags + * @station_flags_msk: what of %station_flags have changed, + * also &enum iwl_sta_flags * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. @@ -352,7 +354,7 @@ enum iwl_sta_type { * asleep. Used to synchronise PS-poll and u-APSD responses while ucode * keeps track of STA sleep state. * @station_type: type of this station. See &enum iwl_sta_type. - * @sleep_state_flags: Look at %iwl_sta_sleep_flag. + * @sleep_state_flags: Look at &enum iwl_sta_sleep_flag. * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP * mac-addr. * @beamform_flags: beam forming controls @@ -401,7 +403,7 @@ struct iwl_mvm_add_sta_cmd { * ( REPLY_ADD_STA_KEY = 0x17 ) * @sta_id: index of station in uCode's station table * @key_offset: key offset in key storage - * @key_flags: type %iwl_sta_key_flag + * @key_flags: type &enum iwl_sta_key_flag * @key: key material data * @rx_secur_seq_cnt: RX security sequence counter for the key */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index c03fbb81efd1..e1c7c798e139 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -595,9 +595,10 @@ struct iwl_mvm_tx_resp { * struct iwl_mvm_ba_notif - notifies about reception of BA * ( BA_NOTIF = 0xc5 ) * @sta_addr: MAC address + * @reserved: reserved * @sta_id: Index of recipient (BA-sending) station in fw's station table * @tid: tid of the session - * @seq_ctl: + * @seq_ctl: sequence control field * @bitmap: the bitmap of the BA notification as seen in the air * @scd_flow: the tx queue this BA relates to * @scd_ssn: the index of the last contiguously sent packet @@ -606,6 +607,7 @@ struct iwl_mvm_tx_resp { * @reduced_txp: power reduced according to TPC. This is the actual value and * not a copy from the LQ command. Thus, if not the first rate was used * for Tx-ing then this value will be set to 0 by FW. + * @reserved1: reserved */ struct iwl_mvm_ba_notif { u8 sta_addr[ETH_ALEN]; @@ -628,13 +630,13 @@ struct iwl_mvm_ba_notif { * @q_num: TFD queue number * @tfd_index: Index of first un-acked frame in the TFD queue * @scd_queue: For debug only - the physical queue the TFD queue is bound to + * @reserved: reserved for alignment */ struct iwl_mvm_compressed_ba_tfd { __le16 q_num; __le16 tfd_index; u8 scd_queue; - u8 reserved; - __le16 reserved2; + u8 reserved[3]; } __packed; /* COMPRESSED_BA_TFD_API_S_VER_1 */ /** @@ -682,11 +684,12 @@ enum iwl_mvm_ba_resp_flags { * @query_frame_cnt: SCD query frame count * @txed: number of frames sent in the aggregation (all-TIDs) * @done: number of frames that were Acked by the BA (all-TIDs) + * @reserved: reserved (for alignment) * @wireless_time: Wireless-media time * @tx_rate: the rate the aggregation was sent at * @tfd_cnt: number of TFD-Q elements * @ra_tid_cnt: number of RATID-Q elements - * @ba_tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd + * @tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd * for details. * @ra_tid: array of RA-TID queue status updates. For debug purposes only. See * &iwl_mvm_compressed_ba_ratid for more details. @@ -760,6 +763,7 @@ struct iwl_mac_beacon_cmd_v7 { * struct iwl_mac_beacon_cmd - beacon template command with offloaded CSA * @byte_cnt: byte count of the beacon frame * @flags: for future use + * @reserved: reserved * @data: see &iwl_mac_beacon_cmd_data */ struct iwl_mac_beacon_cmd { @@ -819,9 +823,9 @@ enum iwl_scd_cfg_actions { /** * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command - * @token: + * @token: unused * @sta_id: station id - * @tid: + * @tid: TID * @scd_queue: scheduler queue to confiug * @action: 1 queue enable, 0 queue disable, 2 change txq's tid owner * Value is one of %iwl_scd_cfg_actions options @@ -829,6 +833,7 @@ enum iwl_scd_cfg_actions { * @tx_fifo: %enum iwl_mvm_tx_fifo * @window: BA window size * @ssn: SSN for the BA agreement + * @reserved: reserved */ struct iwl_scd_txq_cfg_cmd { u8 token; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index a1cce18460bb..3f42efb76f06 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -412,13 +412,13 @@ struct iwl_tx_ant_cfg_cmd { __le32 valid; } __packed; -/* - * Calibration control struct. +/** + * struct iwl_calib_ctrl - Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to - * flow triggers. + * flow triggers, using &enum iwl_calib_cfg * @event_trigger: bitmap for which calibrations to perform according to - * event triggers. + * event triggers, using &enum iwl_calib_cfg */ struct iwl_calib_ctrl { __le32 flow_trigger; @@ -450,8 +450,10 @@ enum iwl_calib_cfg { IWL_CALIB_CFG_AGC_IDX = BIT(18), }; -/* - * Phy configuration command. +/** + * struct iwl_phy_cfg_cmd - Phy configuration command + * @phy_cfg: PHY configuration value, uses &enum iwl_fw_phy_cfg + * @calib_control: calibration control data */ struct iwl_phy_cfg_cmd { __le32 phy_cfg; @@ -1576,8 +1578,8 @@ enum iwl_sf_scenario { #define SF_CFG_DUMMY_NOTIF_OFF BIT(16) /** - * Smart Fifo configuration command. - * @state: smart fifo state, types listed in enum %iwl_sf_sate. + * struct iwl_sf_cfg_cmd - Smart Fifo configuration command. + * @state: smart fifo state, types listed in &enum iwl_sf_state. * @watermark: Minimum allowed availabe free space in RXF for transient state. * @long_delay_timeouts: aging and idle timer values for each scenario * in long delay state. @@ -1631,7 +1633,7 @@ struct iwl_mcc_update_cmd { } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */ /** - * iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD. + * struct iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. @@ -1654,7 +1656,7 @@ struct iwl_mcc_update_resp_v1 { } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */ /** - * iwl_mcc_update_resp - response to MCC_UPDATE_CMD. + * struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. @@ -1736,10 +1738,10 @@ enum iwl_dts_measurement_flags { }; /** - * iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements + * struct iwl_dts_measurement_cmd - request DTS temp and/or voltage measurements * - * @flags: indicates which measurements we want as specified in &enum - * iwl_dts_measurement_flags + * @flags: indicates which measurements we want as specified in + * &enum iwl_dts_measurement_flags */ struct iwl_dts_measurement_cmd { __le32 flags; @@ -1791,7 +1793,7 @@ enum iwl_dts_bit_mode { }; /** - * iwl_ext_dts_measurement_cmd - request extended DTS temperature measurements + * struct iwl_ext_dts_measurement_cmd - request extended DTS temp measurements * @control_mode: see &enum iwl_dts_control_measurement_mode * @temperature: used when over write DTS mode is selected * @sensor: set temperature sensor to use. See &enum iwl_dts_used @@ -1871,7 +1873,7 @@ struct iwl_mvm_ctdp_cmd { #define IWL_MAX_DTS_TRIPS 8 /** - * struct iwl_temp_report_ths_cmd - set temperature thresholds + * struct temp_report_ths_cmd - set temperature thresholds * * @num_temps: number of temperature thresholds passed * @thresholds: array with the thresholds to be configured @@ -1893,7 +1895,7 @@ enum iwl_tdls_channel_switch_type { }; /* TDLS_STA_CHANNEL_SWITCH_CMD_TYPE_API_E_VER_1 */ /** - * Switch timing sub-element in a TDLS channel-switch command + * struct iwl_tdls_channel_switch_timing - Switch timing in TDLS channel-switch * @frame_timestamp: GP2 timestamp of channel-switch request/response packet * received from peer * @max_offchan_duration: What amount of microseconds out of a DTIM is given @@ -1913,7 +1915,7 @@ struct iwl_tdls_channel_switch_timing { #define IWL_TDLS_CH_SW_FRAME_MAX_SIZE 200 /** - * TDLS channel switch frame template + * struct iwl_tdls_channel_switch_frame - TDLS channel switch frame template * * A template representing a TDLS channel-switch request or response frame * @@ -1928,7 +1930,7 @@ struct iwl_tdls_channel_switch_frame { } __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */ /** - * TDLS channel switch command + * struct iwl_tdls_channel_switch_cmd - TDLS channel switch command * * The command is sent to initiate a channel switch and also in response to * incoming TDLS channel-switch request/response packets from remote peers. @@ -1948,7 +1950,7 @@ struct iwl_tdls_channel_switch_cmd { } __packed; /* TDLS_STA_CHANNEL_SWITCH_CMD_API_S_VER_1 */ /** - * TDLS channel switch start notification + * struct iwl_tdls_channel_switch_notif - TDLS channel switch start notification * * @status: non-zero on success * @offchannel_duration: duration given in microseconds @@ -1961,7 +1963,7 @@ struct iwl_tdls_channel_switch_notif { } __packed; /* TDLS_STA_CHANNEL_SWITCH_NTFY_API_S_VER_1 */ /** - * TDLS station info + * struct iwl_tdls_sta_info - TDLS station info * * @sta_id: station id of the TDLS peer * @tx_to_peer_tid: TID reserved vs. the peer for FW based Tx @@ -1976,7 +1978,7 @@ struct iwl_tdls_sta_info { } __packed; /* TDLS_STA_INFO_VER_1 */ /** - * TDLS basic config command + * struct iwl_tdls_config_cmd - TDLS basic config command * * @id_and_color: MAC id and color being configured * @tdls_peer_count: amount of currently connected TDLS peers @@ -2000,7 +2002,7 @@ struct iwl_tdls_config_cmd { } __packed; /* TDLS_CONFIG_CMD_API_S_VER_1 */ /** - * TDLS per-station config information from FW + * struct iwl_tdls_config_sta_info_res - TDLS per-station config information * * @sta_id: station id of the TDLS peer * @tx_to_peer_last_seq: last sequence number used by FW during FW-based Tx to @@ -2012,7 +2014,7 @@ struct iwl_tdls_config_sta_info_res { } __packed; /* TDLS_STA_INFO_RSP_VER_1 */ /** - * TDLS config information from FW + * struct iwl_tdls_config_res - TDLS config information from FW * * @tx_to_ap_last_seq: last sequence number used by FW during FW-based Tx to AP * @sta_info: per-station TDLS config information @@ -2028,7 +2030,7 @@ struct iwl_tdls_config_res { #define TX_FIFO_INTERNAL_MAX_NUM 6 /** - * Shared memory configuration information from the FW + * struct iwl_shared_mem_cfg_v1 - Shared memory configuration information * * @shared_mem_addr: shared memory addr (pre 8000 HW set to 0x0 as MARBH is not * accessible) @@ -2082,7 +2084,7 @@ struct iwl_shared_mem_lmac_cfg { } __packed; /* SHARED_MEM_ALLOC_LMAC_API_S_VER_1 */ /** - * Shared memory configuration information from the FW + * struct iwl_shared_mem_cfg - Shared memory configuration information * * @shared_mem_addr: shared memory address * @shared_mem_size: shared memory size @@ -2110,7 +2112,7 @@ struct iwl_shared_mem_cfg { } __packed; /* SHARED_MEM_ALLOC_API_S_VER_3 */ /** - * VHT MU-MIMO group configuration + * struct iwl_mu_group_mgmt_cmd - VHT MU-MIMO group configuration * * @membership_status: a bitmap of MU groups * @user_position:the position of station in a group. If the station is in the @@ -2137,7 +2139,7 @@ struct iwl_mu_group_mgmt_notif { #define MAX_STORED_BEACON_SIZE 600 /** - * Stored beacon notification + * struct iwl_stored_beacon_notif - Stored beacon notification * * @system_time: system time on air rise * @tsf: TSF on air rise @@ -2172,7 +2174,7 @@ enum iwl_lqm_status { }; /** - * Link Quality Measurement command + * struct iwl_link_qual_msrmnt_cmd - Link Quality Measurement command * @cmd_operatrion: command operation to be performed (start or stop) * as defined above. * @mac_id: MAC ID the measurement applies to. @@ -2187,7 +2189,7 @@ struct iwl_link_qual_msrmnt_cmd { } __packed /* LQM_CMD_API_S_VER_1 */; /** - * Link Quality Measurement notification + * struct iwl_link_qual_msrmnt_notif - Link Quality Measurement notification * * @frequent_stations_air_time: an array containing the total air time * (in uSec) used by the most frequently transmitting stations. @@ -2215,7 +2217,7 @@ struct iwl_link_qual_msrmnt_notif { } __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */ /** - * Channel switch NOA notification + * struct iwl_channel_switch_noa_notif - Channel switch NOA notification * * @id_and_color: ID and color of the MAC */ -- cgit v1.2.3 From 676258651742e69cd77460ea62a591be1aaf2f0e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Mar 2017 11:01:27 +0100 Subject: iwlwifi: mvm: add documentation links to various fields Link various fields to the documentation of the enums that define their values. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/fw-api-coex.h | 10 +++---- .../net/wireless/intel/iwlwifi/mvm/fw-api-mac.h | 10 +++---- .../net/wireless/intel/iwlwifi/mvm/fw-api-power.h | 4 +-- .../net/wireless/intel/iwlwifi/mvm/fw-api-sta.h | 14 +++++----- .../net/wireless/intel/iwlwifi/mvm/fw-api-stats.h | 4 +++ drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 31 +++++++++++++--------- 7 files changed, 45 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h index 204c1b13988b..c432fdb98630 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h @@ -99,8 +99,8 @@ enum iwl_bt_coex_enabled_modules { /** * struct iwl_bt_coex_cmd - bt coex configuration command - * @mode: enum %iwl_bt_coex_mode - * @enabled_modules: enum %iwl_bt_coex_enabled_modules + * @mode: &enum iwl_bt_coex_mode + * @enabled_modules: &enum iwl_bt_coex_enabled_modules * * The structure is used for the BT_COEX command. */ @@ -234,9 +234,9 @@ enum iwl_bt_ci_compliance { * @mbox_msg: message from BT to WiFi * @msg_idx: the index of the message * @bt_ci_compliance: enum %iwl_bt_ci_compliance - * @primary_ch_lut: LUT used for primary channel enum %iwl_bt_coex_lut_type - * @secondary_ch_lut: LUT used for secondary channel enume %iwl_bt_coex_lut_type - * @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading + * @primary_ch_lut: LUT used for primary channel &enum iwl_bt_coex_lut_type + * @secondary_ch_lut: LUT used for secondary channel &enum iwl_bt_coex_lut_type + * @bt_activity_grading: the activity of BT &enum iwl_bt_activity_grading * @ttc_rrc_status: is TTC or RRC enabled - one bit per PHY */ struct iwl_bt_coex_profile_notif { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h index 970b030ed28d..aa5aaf7c940d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h @@ -329,17 +329,17 @@ struct iwl_ac_qos { * ( MAC_CONTEXT_CMD = 0x28 ) * @id_and_color: ID and color of the MAC * @action: action to perform, one of FW_CTXT_ACTION_* - * @mac_type: one of FW_MAC_TYPE_* - * @tsd_id: TSF HW timer, one of TSF_ID_* + * @mac_type: one of &enum iwl_mac_types + * @tsd_id: TSF HW timer, one of &enum iwl_tsf_id * @node_addr: MAC address * @bssid_addr: BSSID * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM - * @protection_flags: combination of MAC_PROT_FLG_FLAG_* + * @protection_flags: combination of &enum iwl_mac_protection_flags * @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise * @short_slot: 0x10 for enabling short slots, 0 otherwise - * @filter_flags: combination of MAC_FILTER_* - * @qos_flags: from MAC_QOS_FLG_* + * @filter_flags: combination of &enum iwl_mac_filter_flags + * @qos_flags: from &enum iwl_mac_qos_flags * @ac: one iwl_mac_qos configuration for each AC * @mac_specific: one of struct iwl_mac_data_*, according to mac_type */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h index 3d56ba4c0c71..f329e87cd97c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h @@ -202,7 +202,7 @@ enum iwl_device_power_flags { * struct iwl_device_power_cmd - device wide power command. * DEVICE_POWER_CMD = 0x77 (command, has simple generic response) * - * @flags: Power table command flags from DEVICE_POWER_FLAGS_* + * @flags: Power table command flags from &enum iwl_device_power_flags */ struct iwl_device_power_cmd { /* PM_POWER_TABLE_CMD_API_S_VER_6 */ @@ -213,7 +213,7 @@ struct iwl_device_power_cmd { /** * struct iwl_mac_power_cmd - New power command containing uAPSD support * MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) - * @id_and_color: MAC contex identifier + * @id_and_color: MAC contex identifier, &enum iwl_mvm_id_and_color * @flags: Power table command flags from POWER_FLAGS_* * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. * Minimum allowed:- 3 * DTIM. Keep alive period must be diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 894b8f6c8adc..0f6264fdfed1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -253,11 +253,12 @@ struct iwl_mvm_keyinfo { /** * struct iwl_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) - * @add_modify: 1: modify existing, 0: add new station + * @add_modify: see &enum iwl_sta_mode * @awake_acs: * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. - * @mac_id_n_color: the Mac context this station belongs to + * @mac_id_n_color: the Mac context this station belongs to, + * see &enum iwl_mvm_id_and_color * @addr: station's MAC address * @sta_id: index of station in uCode's station table * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave @@ -331,11 +332,12 @@ enum iwl_sta_type { /** * struct iwl_mvm_add_sta_cmd - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) - * @add_modify: 1: modify existing, 0: add new station + * @add_modify: see &enum iwl_sta_mode * @awake_acs: * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. - * @mac_id_n_color: the Mac context this station belongs to + * @mac_id_n_color: the Mac context this station belongs to, + * see &enum iwl_mvm_id_and_color * @addr: station's MAC address * @sta_id: index of station in uCode's station table * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave @@ -470,7 +472,7 @@ struct iwl_mvm_rm_sta_cmd { /** * struct iwl_mvm_mgmt_mcast_key_cmd_v1 * ( MGMT_MCAST_KEY = 0x1f ) - * @ctrl_flags: %iwl_sta_key_flag + * @ctrl_flags: &enum iwl_sta_key_flag * @igtk: * @k1: unused * @k2: unused @@ -491,7 +493,7 @@ struct iwl_mvm_mgmt_mcast_key_cmd_v1 { /** * struct iwl_mvm_mgmt_mcast_key_cmd * ( MGMT_MCAST_KEY = 0x1f ) - * @ctrl_flags: %iwl_sta_key_flag + * @ctrl_flags: &enum iwl_sta_key_flag * @igtk: IGTK master key * @sta_id: station ID that support IGTK * @key_id: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h index 809ec1ba5025..c8561b16add4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h @@ -326,6 +326,10 @@ struct iwl_notif_statistics_cdb { #define IWL_STATISTICS_FLG_CLEAR 0x1 #define IWL_STATISTICS_FLG_DISABLE_NOTIF 0x2 +/** + * struct iwl_statistics_cmd - statistics config command + * @flags: flags from &enum iwl_statistics_flags + */ struct iwl_statistics_cmd { __le32 flags; } __packed; /* STATISTICS_CMD_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index e1c7c798e139..052b7f0db889 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -828,9 +828,9 @@ enum iwl_scd_cfg_actions { * @tid: TID * @scd_queue: scheduler queue to confiug * @action: 1 queue enable, 0 queue disable, 2 change txq's tid owner - * Value is one of %iwl_scd_cfg_actions options + * Value is one of &enum iwl_scd_cfg_actions options * @aggregate: 1 aggregated queue, 0 otherwise - * @tx_fifo: %enum iwl_mvm_tx_fifo + * @tx_fifo: &enum iwl_mvm_tx_fifo * @window: BA window size * @ssn: SSN for the BA agreement * @reserved: reserved diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 3f42efb76f06..a4567d5206e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -491,10 +491,10 @@ enum { }; /** - * struct iwl_nvm_access_cmd_ver2 - Request the device to send an NVM section - * @op_code: 0 - read, 1 - write - * @target: NVM_ACCESS_TARGET_* - * @type: NVM_SECTION_TYPE_* + * struct iwl_nvm_access_cmd - Request the device to send an NVM section + * @op_code: &enum iwl_nvm_access_op + * @target: &enum iwl_nvm_access_target + * @type: &enum iwl_nvm_section_type * @offset: offset in bytes into the section * @length: in bytes, to read/write * @data: if write operation, the data to write. On read its empty @@ -918,12 +918,13 @@ enum { }; /** - * struct iwl_time_event_cmd_api - configuring Time Events + * struct iwl_time_event_cmd - configuring Time Events * with struct MAC_TIME_EVENT_DATA_API_S_VER_2 (see also * with version 1. determined by IWL_UCODE_TLV_FLAGS) * ( TIME_EVENT_CMD = 0x29 ) - * @id_and_color: ID and color of the relevant MAC - * @action: action to perform, one of FW_CTXT_ACTION_* + * @id_and_color: ID and color of the relevant MAC, + * &enum iwl_mvm_id_and_color + * @action: action to perform, one of &enum iwl_phy_ctxt_action * @id: this field has two meanings, depending on the action: * If the action is ADD, then it means the type of event to add. * For all other actions it is the unique event ID assigned when the @@ -939,7 +940,8 @@ enum { * on event and/or fragment start and/or end * using one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF * TE_EVENT_SOCIOPATHIC - * using TE_ABSENCE and using TE_NOTIF_* + * using TE_ABSENCE and using TE_NOTIF_*, + * &enum iwl_time_event_policy */ struct iwl_time_event_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ @@ -962,7 +964,8 @@ struct iwl_time_event_cmd { * @status: bit 0 indicates success, all others specify errors * @id: the Time Event type * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE - * @id_and_color: ID and color of the relevant MAC + * @id_and_color: ID and color of the relevant MAC, + * &enum iwl_mvm_id_and_color */ struct iwl_time_event_resp { __le32 status; @@ -978,7 +981,7 @@ struct iwl_time_event_resp { * @session_id: session's unique id * @unique_id: unique id of the Time Event itself * @id_and_color: ID and color of the relevant MAC - * @action: one of TE_NOTIF_START or TE_NOTIF_END + * @action: &enum iwl_time_event_policy * @status: true if scheduled, false otherwise (not executed) */ struct iwl_time_event_notif { @@ -996,10 +999,13 @@ struct iwl_time_event_notif { /** * struct iwl_binding_cmd - configuring bindings * ( BINDING_CONTEXT_CMD = 0x2b ) - * @id_and_color: ID and color of the relevant Binding + * @id_and_color: ID and color of the relevant Binding, + * &enum iwl_mvm_id_and_color * @action: action to perform, one of FW_CTXT_ACTION_* * @macs: array of MAC id and colors which belong to the binding + * &enum iwl_mvm_id_and_color * @phy: PHY id and color which belongs to the binding + * &enum iwl_mvm_id_and_color * @lmac_id: the lmac id the binding belongs to */ struct iwl_binding_cmd { @@ -1022,7 +1028,8 @@ struct iwl_binding_cmd { /** * struct iwl_time_quota_data - configuration of time quota per binding - * @id_and_color: ID and color of the relevant Binding + * @id_and_color: ID and color of the relevant Binding, + * &enum iwl_mvm_id_and_color * @quota: absolute time quota in TU. The scheduler will try to divide the * remainig quota (after Time Events) according to this quota. * @max_duration: max uninterrupted context duration in TU -- cgit v1.2.3 From a85281ebdef114bde8fc93fa99c79f1c567f23d8 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 12 Mar 2017 10:34:10 +0200 Subject: iwlwifi: update device ID for a000 family Three configurations will share device ID 2720, and will be differentiated by RF ID. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 3 ++- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 12 +++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index fa120fb55373..c9481b23b1a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -348,7 +348,8 @@ enum { /* RF_ID value */ #define CSR_HW_RF_ID_TYPE_JF (0x00105000) -#define CSR_HW_RF_ID_TYPE_HR (0x00109000) +#define CSR_HW_RF_ID_TYPE_HR (0x0010A000) +#define CSR_HW_RF_ID_TYPE_HRCDB (0x00109000) /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index e51760e752d4..2d92d3708619 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -538,7 +538,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* a000 Series */ {IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg_hr_cdb)}, - {IWL_PCI_DEVICE(0x2722, 0x0A10, iwla000_2ac_cfg_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x0310, iwla000_2ac_cfg_jf)}, #endif /* CONFIG_IWLMVM */ {0} @@ -672,10 +672,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_trans->cfg = cfg_7265d; } - if (iwl_trans->cfg->rf_id && - (cfg == &iwla000_2ac_cfg_hr || cfg == &iwla000_2ac_cfg_hr_cdb) && - iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF) { - cfg = &iwla000_2ac_cfg_jf; + if (iwl_trans->cfg->rf_id && cfg == &iwla000_2ac_cfg_hr_cdb) { + if (iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF) + cfg = &iwla000_2ac_cfg_jf; + else if (iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_HR) + cfg = &iwla000_2ac_cfg_hr; + iwl_trans->cfg = cfg; } #endif -- cgit v1.2.3 From 4d151c2e22532d1167370349ed71125ac2dd5228 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Mar 2017 11:04:06 +0100 Subject: iwlwifi: mvm: disentangle binding command versions The comments/size of the different binding commands get lost in documentation, so introduce two different command structs that can be used there. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index a4567d5206e2..4c5f38e50caa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -996,6 +996,26 @@ struct iwl_time_event_notif { /* Bindings and Time Quota */ +/** + * struct iwl_binding_cmd_v1 - configuring bindings + * ( BINDING_CONTEXT_CMD = 0x2b ) + * @id_and_color: ID and color of the relevant Binding, + * &enum iwl_mvm_id_and_color + * @action: action to perform, one of FW_CTXT_ACTION_* + * @macs: array of MAC id and colors which belong to the binding, + * &enum iwl_mvm_id_and_color + * @phy: PHY id and color which belongs to the binding, + * &enum iwl_mvm_id_and_color + */ +struct iwl_binding_cmd_v1 { + /* COMMON_INDEX_HDR_API_S_VER_1 */ + __le32 id_and_color; + __le32 action; + /* BINDING_DATA_API_S_VER_1 */ + __le32 macs[MAX_MACS_IN_BINDING]; + __le32 phy; +} __packed; /* BINDING_CMD_API_S_VER_1 */ + /** * struct iwl_binding_cmd - configuring bindings * ( BINDING_CONTEXT_CMD = 0x2b ) @@ -1015,11 +1035,10 @@ struct iwl_binding_cmd { /* BINDING_DATA_API_S_VER_1 */ __le32 macs[MAX_MACS_IN_BINDING]; __le32 phy; - /* BINDING_CMD_API_S_VER_1 */ __le32 lmac_id; } __packed; /* BINDING_CMD_API_S_VER_2 */ -#define IWL_BINDING_CMD_SIZE_V1 offsetof(struct iwl_binding_cmd, lmac_id) +#define IWL_BINDING_CMD_SIZE_V1 sizeof(struct iwl_binding_cmd_v1) #define IWL_LMAC_24G_INDEX 0 #define IWL_LMAC_5G_INDEX 1 -- cgit v1.2.3 From d69f0a2d88dd7c8e82f027d2d48238426c45e07e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Mar 2017 10:58:16 +0100 Subject: iwlwifi: mvm: create/name various enums Some values should be in enums so documentation can refer to them, some values should be named for the same reason. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/fw-api-sta.h | 10 +++- .../net/wireless/intel/iwlwifi/mvm/fw-api-stats.h | 25 +++++++-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 61 +++++++++++++++++----- 3 files changed, 77 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 0f6264fdfed1..c14ebd7ff77d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -197,7 +197,15 @@ enum iwl_sta_modify_flag { STA_MODIFY_QUEUES = BIT(7), }; -#define STA_MODE_MODIFY 1 +/** + * enum iwl_sta_mode - station command mode + * @STA_MODE_ADD: add new station + * @STA_MODE_MODIFY: modify the station + */ +enum iwl_sta_mode { + STA_MODE_ADD = 0, + STA_MODE_MODIFY = 1, +}; /** * enum iwl_sta_sleep_flag - type of sleep of the station diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h index c8561b16add4..4286222f54f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -323,12 +323,29 @@ struct iwl_notif_statistics_cdb { struct mvm_statistics_load_cdb load_stats; } __packed; /* STATISTICS_NTFY_API_S_VER_12 */ -#define IWL_STATISTICS_FLG_CLEAR 0x1 -#define IWL_STATISTICS_FLG_DISABLE_NOTIF 0x2 +/** + * enum iwl_statistics_notif_flags - flags used in statistics notification + * @IWL_STATISTICS_REPLY_FLG_CLEAR: statistics were cleared after this report + */ +enum iwl_statistics_notif_flags { + IWL_STATISTICS_REPLY_FLG_CLEAR = 0x1, +}; + +/** + * enum iwl_statistics_cmd_flags - flags used in statistics command + * @IWL_STATISTICS_FLG_CLEAR: request to clear statistics after the report + * that's sent after this command + * @IWL_STATISTICS_FLG_DISABLE_NOTIF: disable unilateral statistics + * notifications + */ +enum iwl_statistics_cmd_flags { + IWL_STATISTICS_FLG_CLEAR = 0x1, + IWL_STATISTICS_FLG_DISABLE_NOTIF = 0x2, +}; /** * struct iwl_statistics_cmd - statistics config command - * @flags: flags from &enum iwl_statistics_flags + * @flags: flags from &enum iwl_statistics_cmd_flags */ struct iwl_statistics_cmd { __le32 flags; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 4c5f38e50caa..6e0e65eb2b4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -472,15 +472,39 @@ struct iwl_phy_cfg_cmd { #define PHY_CFG_RX_CHAIN_C BIT(14) -/* Target of the NVM_ACCESS_CMD */ -enum { +/** + * enum iwl_nvm_access_op - NVM access opcode + * @IWL_NVM_READ: read NVM + * @IWL_NVM_WRITE: write NVM + */ +enum iwl_nvm_access_op { + IWL_NVM_READ = 0, + IWL_NVM_WRITE = 1, +}; + +/** + * enum iwl_nvm_access_target - target of the NVM_ACCESS_CMD + * @NVM_ACCESS_TARGET_CACHE: access the cache + * @NVM_ACCESS_TARGET_OTP: access the OTP + * @NVM_ACCESS_TARGET_EEPROM: access the EEPROM + */ +enum iwl_nvm_access_target { NVM_ACCESS_TARGET_CACHE = 0, NVM_ACCESS_TARGET_OTP = 1, NVM_ACCESS_TARGET_EEPROM = 2, }; -/* Section types for NVM_ACCESS_CMD */ -enum { +/** + * enum iwl_nvm_section_type - section types for NVM_ACCESS_CMD + * @NVM_SECTION_TYPE_SW: software section + * @NVM_SECTION_TYPE_REGULATORY: regulatory section + * @NVM_SECTION_TYPE_CALIBRATION: calibration section + * @NVM_SECTION_TYPE_PRODUCTION: production section + * @NVM_SECTION_TYPE_MAC_OVERRIDE: MAC override section + * @NVM_SECTION_TYPE_PHY_SKU: PHY SKU section + * @NVM_MAX_NUM_SECTIONS: number of sections + */ +enum iwl_nvm_section_type { NVM_SECTION_TYPE_SW = 1, NVM_SECTION_TYPE_REGULATORY = 3, NVM_SECTION_TYPE_CALIBRATION = 4, @@ -718,12 +742,21 @@ struct iwl_error_resp { #define MAX_MACS_IN_BINDING (3) #define MAX_BINDINGS (4) -/* Used to extract ID and color from the context dword */ -#define FW_CTXT_ID_POS (0) -#define FW_CTXT_ID_MSK (0xff << FW_CTXT_ID_POS) -#define FW_CTXT_COLOR_POS (8) -#define FW_CTXT_COLOR_MSK (0xff << FW_CTXT_COLOR_POS) -#define FW_CTXT_INVALID (0xffffffff) +/** + * enum iwl_mvm_id_and_color - ID and color fields in context dword + * @FW_CTXT_ID_POS: position of the ID + * @FW_CTXT_ID_MSK: mask of the ID + * @FW_CTXT_COLOR_POS: position of the color + * @FW_CTXT_COLOR_MSK: mask of the color + * @FW_CTXT_INVALID: value used to indicate unused/invalid + */ +enum iwl_mvm_id_and_color { + FW_CTXT_ID_POS = 0, + FW_CTXT_ID_MSK = 0xff << FW_CTXT_ID_POS, + FW_CTXT_COLOR_POS = 8, + FW_CTXT_COLOR_MSK = 0xff << FW_CTXT_COLOR_POS, + FW_CTXT_INVALID = 0xffffffff, +}; #define FW_CMD_ID_AND_COLOR(_id, _color) ((_id << FW_CTXT_ID_POS) |\ (_color << FW_CTXT_COLOR_POS)) @@ -871,7 +904,8 @@ enum { #define TE_V2_PLACEMENT_POS 12 #define TE_V2_ABSENCE_POS 15 -/* Time event policy values +/** + * enum iwl_time_event_policy - Time event policy values * A notification (both event and fragment) includes a status indicating weather * the FW was able to schedule the event or not. For fragment start/end * notification the status is always success. There is no start/end fragment @@ -886,12 +920,13 @@ enum { * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. + * @T2_V2_START_IMMEDIATELY: start time event immediately * @TE_V2_DEP_OTHER: depends on another time event * @TE_V2_DEP_TSF: depends on a specific time * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC * @TE_V2_ABSENCE: are we present or absent during the Time Event. */ -enum { +enum iwl_time_event_policy { TE_V2_DEFAULT_POLICY = 0x0, /* notifications (event start/stop, fragment start/stop) */ @@ -906,8 +941,6 @@ enum { TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), T2_V2_START_IMMEDIATELY = BIT(11), - TE_V2_NOTIF_MSK = 0xff, - /* placement characteristics */ TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), TE_V2_DEP_TSF = BIT(TE_V2_PLACEMENT_POS + 1), -- cgit v1.2.3 From 15fc196d6ec388f724093f4950b5927efd31d5b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Mar 2017 14:01:42 +0100 Subject: iwlwifi: mvm: document structures used by commands Add documentation to a lot of command IDs that links to the appropriate structure(s) used with those IDs. In one case, actually add and use a new struct for that purpose. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 3 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 218 ++++++++++++++++++++++-- 2 files changed, 209 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 49b4418e6c35..fe7f1e424f55 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -914,7 +914,8 @@ void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - u32 ant_isolation = le32_to_cpup((void *)pkt->data); + struct iwl_mvm_antenna_coupling_notif *notif = (void *)pkt->data; + u32 ant_isolation = le32_to_cpu(notif->isolation); struct iwl_bt_coex_corun_lut_update_cmd cmd = {}; u8 __maybe_unused lower_bound, upper_bound; u8 lut; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 6e0e65eb2b4d..332f204761cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -130,31 +130,86 @@ enum iwl_mvm_tx_fifo { }; -/* commands */ +/** + * enum iwl_legacy_cmds - legacy group command IDs + */ enum iwl_legacy_cmds { + /** + * @MVM_ALIVE: + * Alive data from the firmware, as described in + * &struct mvm_alive_resp_v3 or &struct mvm_alive_resp. + */ MVM_ALIVE = 0x1, + + /** + * @REPLY_ERROR: Cause an error in the firmware, for testing purposes. + */ REPLY_ERROR = 0x2, + + /** + * @ECHO_CMD: Send data to the device to have it returned immediately. + */ ECHO_CMD = 0x3, + /** + * @INIT_COMPLETE_NOTIF: Notification that initialization is complete. + */ INIT_COMPLETE_NOTIF = 0x4, - /* PHY context commands */ + /** + * @PHY_CONTEXT_CMD: + * Add/modify/remove a PHY context, using &struct iwl_phy_context_cmd. + */ PHY_CONTEXT_CMD = 0x8, + + /** + * @DBG_CFG: Debug configuration command. + */ DBG_CFG = 0x9, + + /** + * @ANTENNA_COUPLING_NOTIFICATION: + * Antenna coupling data, &struct iwl_mvm_antenna_coupling_notif + */ ANTENNA_COUPLING_NOTIFICATION = 0xa, - /* UMAC scan commands */ + /** + * @SCAN_ITERATION_COMPLETE_UMAC: + * Firmware indicates a scan iteration completed, using + * &struct iwl_umac_scan_iter_complete_notif. + */ SCAN_ITERATION_COMPLETE_UMAC = 0xb5, + + /** + * @SCAN_CFG_CMD: + * uses &struct iwl_scan_config_v1 or &struct iwl_scan_config + */ SCAN_CFG_CMD = 0xc, SCAN_REQ_UMAC = 0xd, SCAN_ABORT_UMAC = 0xe, + + /** + * @SCAN_COMPLETE_UMAC: uses &struct iwl_umac_scan_complete + */ SCAN_COMPLETE_UMAC = 0xf, BA_WINDOW_STATUS_NOTIFICATION_ID = 0x13, - /* station table */ + /** + * @ADD_STA_KEY: + * &struct iwl_mvm_add_sta_key_cmd_v1 or + * &struct iwl_mvm_add_sta_key_cmd. + */ ADD_STA_KEY = 0x17, + + /** + * @ADD_STA: + * &struct iwl_mvm_add_sta_cmd or &struct iwl_mvm_add_sta_cmd_v7. + */ ADD_STA = 0x18, + /** + * @REMOVE_STA: &struct iwl_mvm_rm_sta_cmd + */ REMOVE_STA = 0x19, /* paging get item */ @@ -162,10 +217,23 @@ enum iwl_legacy_cmds { /* TX */ TX_CMD = 0x1c, + + /** + * @TXPATH_FLUSH: &struct iwl_tx_path_flush_cmd + */ TXPATH_FLUSH = 0x1e, + + /** + * @MGMT_MCAST_KEY: + * &struct iwl_mvm_mgmt_mcast_key_cmd or + * &struct iwl_mvm_mgmt_mcast_key_cmd_v1 + */ MGMT_MCAST_KEY = 0x1f, /* scheduler config */ + /** + * @SCD_QUEUE_CFG: &struct iwl_scd_txq_cfg_cmd + */ SCD_QUEUE_CFG = 0x1d, /* global key */ @@ -179,17 +247,40 @@ enum iwl_legacy_cmds { TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa, TDLS_CONFIG_CMD = 0xa7, - /* MAC and Binding commands */ + /** + * @MAC_CONTEXT_CMD: &struct iwl_mac_ctx_cmd + */ MAC_CONTEXT_CMD = 0x28, + + /** + * @TIME_EVENT_CMD: + * &struct iwl_time_event_cmd, response in &struct iwl_time_event_resp + */ TIME_EVENT_CMD = 0x29, /* both CMD and response */ + /** + * @TIME_EVENT_NOTIFICATION: &struct iwl_time_event_notif + */ TIME_EVENT_NOTIFICATION = 0x2a, + /** + * @BINDING_CONTEXT_CMD: + * &struct iwl_binding_cmd or &struct iwl_binding_cmd_v1 + */ BINDING_CONTEXT_CMD = 0x2b, + /** + * @TIME_QUOTA_CMD: &struct iwl_time_quota_cmd + */ TIME_QUOTA_CMD = 0x2c, NON_QOS_TX_COUNTER_CMD = 0x2d, + /** + * @LQ_CMD: using &struct iwl_lq_cmd + */ LQ_CMD = 0x4e, - /* paging block to FW cpu2 */ + /** + * @FW_PAGING_BLOCK_CMD: + * &struct iwl_fw_paging_cmd or &struct iwl_fw_paging_cmd_v1 + */ FW_PAGING_BLOCK_CMD = 0x4f, /* Scan offload */ @@ -203,6 +294,9 @@ enum iwl_legacy_cmds { SCAN_ITERATION_COMPLETE = 0xe7, /* Phy */ + /** + * @PHY_CONFIGURATION_CMD: &struct iwl_phy_cfg_cmd + */ PHY_CONFIGURATION_CMD = 0x6a, CALIB_RES_NOTIF_PHY_DB = 0x6b, PHY_DB_CMD = 0x6c, @@ -211,7 +305,9 @@ enum iwl_legacy_cmds { TOF_CMD = 0x10, TOF_NOTIFICATION = 0x11, - /* Power - legacy power table command */ + /** + * @POWER_TABLE_CMD: &struct iwl_device_power_cmd + */ POWER_TABLE_CMD = 0x77, PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, LTR_CONFIG = 0xee, @@ -222,17 +318,38 @@ enum iwl_legacy_cmds { /* Set/Get DC2DC frequency tune */ DC2DC_CONFIG_CMD = 0x83, - /* NVM */ + /** + * @NVM_ACCESS_CMD: using &struct iwl_nvm_access_cmd + */ NVM_ACCESS_CMD = 0x88, SET_CALIB_DEFAULT_CMD = 0x8e, BEACON_NOTIFICATION = 0x90, BEACON_TEMPLATE_CMD = 0x91, + /** + * @TX_ANT_CONFIGURATION_CMD: &struct iwl_tx_ant_cfg_cmd + */ TX_ANT_CONFIGURATION_CMD = 0x98, + + /** + * @STATISTICS_CMD: &struct iwl_statistics_cmd + */ STATISTICS_CMD = 0x9c, + + /** + * @STATISTICS_NOTIFICATION: + * one of &struct iwl_notif_statistics_v10, + * &struct iwl_notif_statistics_v11, + * &struct iwl_notif_statistics_cdb + */ STATISTICS_NOTIFICATION = 0x9d, EOSP_NOTIFICATION = 0x9e, + + /** + * @REDUCE_TX_POWER_CMD: + * &struct iwl_dev_tx_power_cmd_v3 or &struct iwl_dev_tx_power_cmd + */ REDUCE_TX_POWER_CMD = 0x9f, /* RF-KILL commands and notifications */ @@ -241,11 +358,19 @@ enum iwl_legacy_cmds { MISSED_BEACONS_NOTIFICATION = 0xa2, - /* Power - new power table command */ + /** + * @MAC_PM_POWER_TABLE: using &struct iwl_mac_power_cmd + */ MAC_PM_POWER_TABLE = 0xa9, + /** + * @MFUART_LOAD_NOTIFICATION: &struct iwl_mfuart_load_notif + */ MFUART_LOAD_NOTIFICATION = 0xb1, + /** + * @RSS_CONFIG_CMD: &struct iwl_rss_config_cmd + */ RSS_CONFIG_CMD = 0xb3, REPLY_RX_PHY_CMD = 0xc0, @@ -254,7 +379,14 @@ enum iwl_legacy_cmds { BA_NOTIF = 0xc5, /* Location Aware Regulatory */ + /** + * @MCC_UPDATE_CMD: using &struct iwl_mcc_update_cmd + */ MCC_UPDATE_CMD = 0xc8, + + /** + * @MCC_CHUB_UPDATE_CMD: using &struct iwl_mcc_chub_notif + */ MCC_CHUB_UPDATE_CMD = 0xc9, MARKER_CMD = 0xcb, @@ -262,14 +394,29 @@ enum iwl_legacy_cmds { /* BT Coex */ BT_COEX_PRIO_TABLE = 0xcc, BT_COEX_PROT_ENV = 0xcd, + /** + * @BT_PROFILE_NOTIFICATION: &struct iwl_bt_coex_profile_notif + */ BT_PROFILE_NOTIFICATION = 0xce, + /** + * @BT_CONFIG: &struct iwl_bt_coex_cmd + */ BT_CONFIG = 0x9b, BT_COEX_UPDATE_SW_BOOST = 0x5a, BT_COEX_UPDATE_CORUN_LUT = 0x5b, BT_COEX_UPDATE_REDUCED_TXP = 0x5c, + /** + * @BT_COEX_CI: &struct iwl_bt_coex_ci_cmd + */ BT_COEX_CI = 0x5d, + /** + * @REPLY_SF_CFG_CMD: &struct iwl_sf_cfg_cmd + */ REPLY_SF_CFG_CMD = 0xd1, + /** + * @REPLY_BEACON_FILTERING_CMD: &struct iwl_beacon_filter_cmd + */ REPLY_BEACON_FILTERING_CMD = 0xd2, /* DTS measurements */ @@ -283,19 +430,39 @@ enum iwl_legacy_cmds { BCAST_FILTER_CMD = 0xcf, MCAST_FILTER_CMD = 0xd0, - /* D3 commands/notifications */ + /** + * @D3_CONFIG_CMD: &struct iwl_d3_manager_config + */ D3_CONFIG_CMD = 0xd3, PROT_OFFLOAD_CONFIG_CMD = 0xd4, OFFLOADS_QUERY_CMD = 0xd5, REMOTE_WAKE_CONFIG_CMD = 0xd6, D0I3_END_CMD = 0xed, - /* for WoWLAN in particular */ + /** + * @WOWLAN_PATTERNS: &struct iwl_wowlan_patterns_cmd + */ WOWLAN_PATTERNS = 0xe0, + + /** + * @WOWLAN_CONFIGURATION: &struct iwl_wowlan_config_cmd + */ WOWLAN_CONFIGURATION = 0xe1, + /** + * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd + */ WOWLAN_TSC_RSC_PARAM = 0xe2, + /** + * @WOWLAN_TKIP_PARAM: &struct iwl_wowlan_tkip_params_cmd + */ WOWLAN_TKIP_PARAM = 0xe3, + /** + * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd + */ WOWLAN_KEK_KCK_MATERIAL = 0xe4, + /** + * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status + */ WOWLAN_GET_STATUSES = 0xe5, WOWLAN_TX_POWER_PER_DB = 0xe6, @@ -316,21 +483,42 @@ enum iwl_mac_conf_subcmd_ids { CHANNEL_SWITCH_NOA_NOTIF = 0xFF, }; +/** + * enum iwl_phy_ops_subcmd_ids - PHY group commands + */ enum iwl_phy_ops_subcmd_ids { CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, CTDP_CONFIG_CMD = 0x03, + + /** + * @TEMP_REPORTING_THRESHOLDS_CMD: &struct temp_report_ths_cmd + */ TEMP_REPORTING_THRESHOLDS_CMD = 0x04, GEO_TX_POWER_LIMIT = 0x05, CT_KILL_NOTIFICATION = 0xFE, DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, }; +/** + * enum iwl_system_subcmd_ids - system group command IDs + */ enum iwl_system_subcmd_ids { + /** + * @SHARED_MEM_CFG_CMD: + * response in &struct iwl_shared_mem_cfg or + * &struct iwl_shared_mem_cfg_v1 + */ SHARED_MEM_CFG_CMD = 0x0, INIT_EXTENDED_CFG_CMD = 0x03, }; +/** + * enum iwl_data_path_subcmd_ids - data path group commands + */ enum iwl_data_path_subcmd_ids { + /** + * @DQA_ENABLE_CMD: &struct iwl_dqa_enable_cmd + */ DQA_ENABLE_CMD = 0x0, UPDATE_MU_GROUPS_CMD = 0x1, TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2, @@ -2433,4 +2621,12 @@ struct iwl_nvm_get_info_rsp { struct iwl_nvm_get_info_regulatory regulatory; } __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_1 */ +/** + * struct iwl_mvm_antenna_coupling_notif - antenna coupling notification + * @isolation: antenna isolation value + */ +struct iwl_mvm_antenna_coupling_notif { + __le32 isolation; +} __packed; + #endif /* __fw_api_h__ */ -- cgit v1.2.3 From 2ba57c8bf9d4dbeb5d23c0ee94ace119e8ea41c9 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 12 Mar 2017 11:00:04 +0200 Subject: iwlwifi: mvm: remove wrt support of page dumps in gen2 In gen2, page dumping should be done in transport layer, since the addresses needed for the paging mechanism reside there. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index 7b86a4f1b574..d8b592aa362c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -691,7 +691,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } /* Make room for fw's virtual image pages, if it exists */ - if (mvm->fw->img[mvm->cur_ucode].paging_mem_size && + if (!mvm->trans->cfg->gen2 && + mvm->fw->img[mvm->cur_ucode].paging_mem_size && mvm->fw_paging_db[0].fw_paging_block) file_len += mvm->num_of_paging_blk * (sizeof(*dump_data) + @@ -850,7 +851,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } /* Dump fw's virtual image */ - if (mvm->fw->img[mvm->cur_ucode].paging_mem_size && + if (!mvm->trans->cfg->gen2 && + mvm->fw->img[mvm->cur_ucode].paging_mem_size && mvm->fw_paging_db[0].fw_paging_block) { for (i = 1; i < mvm->num_of_paging_blk + 1; i++) { struct iwl_fw_error_dump_paging *paging; -- cgit v1.2.3 From 5538409ba3935aa1ecaff8255137c3a6a19e0a30 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 12 Mar 2017 11:09:58 +0200 Subject: iwlwifi: pcie: support page dumping in wrt in gen2 In gen2, page dumping needs to be done in the trans layer, as it is the one with access to the paging pointers. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 70acf850a9f1..85f44d8f1c41 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2754,6 +2754,13 @@ static struct iwl_trans_dump_data (PAGE_SIZE << trans_pcie->rx_page_order)); } + /* Paged memory for gen2 HW */ + if (trans->cfg->gen2) + for (i = 0; i < trans_pcie->init_dram.paging_cnt; i++) + len += sizeof(*data) + + sizeof(struct iwl_fw_error_dump_paging) + + trans_pcie->init_dram.paging[i].size; + dump_data = vzalloc(len); if (!dump_data) return NULL; @@ -2793,6 +2800,28 @@ static struct iwl_trans_dump_data if (dump_rbs) len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs); + /* Paged memory for gen2 HW */ + if (trans->cfg->gen2) { + for (i = 0; i < trans_pcie->init_dram.paging_cnt; i++) { + struct iwl_fw_error_dump_paging *paging; + dma_addr_t addr = + trans_pcie->init_dram.paging[i].physical; + u32 page_len = trans_pcie->init_dram.paging[i].size; + + data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING); + data->len = cpu_to_le32(sizeof(*paging) + page_len); + paging = (void *)data->data; + paging->index = cpu_to_le32(i); + dma_sync_single_for_cpu(trans->dev, addr, page_len, + DMA_BIDIRECTIONAL); + memcpy(paging->data, + trans_pcie->init_dram.paging[i].block, page_len); + data = iwl_fw_error_next_data(data); + + len += sizeof(*data) + sizeof(*paging) + page_len; + } + } + len += iwl_trans_pcie_dump_monitor(trans, &data, monitor_len); dump_data->len = len; -- cgit v1.2.3 From 0705b953eee4fe20b01ff8e13b8f32c7eac78446 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Thu, 9 Mar 2017 15:18:58 +0200 Subject: iwlwifi: Add fw_name_pre_rf_next_step to support different rf steps Integrated chip may have different HW and RF steps. Currently, the driver supports only different HW steps. Add logic to support different RF steps enables combining different HW and RF steps. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 6 ++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 3 +++ drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 5 +++++ drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 4 ++++ 4 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index 110ceefccc15..a2ee6aad3ce3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -73,10 +73,13 @@ #define IWL9000_SMEM_LEN 0x68000 #define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-" +#define IWL9000RFB_FW_PRE "iwlwifi-9000-pu-a0-jf-b0-" #define IWL9260A_FW_PRE "iwlwifi-9260-th-a0-jf-a0-" #define IWL9260B_FW_PRE "iwlwifi-9260-th-b0-jf-b0-" #define IWL9000_MODULE_FIRMWARE(api) \ IWL9000_FW_PRE "-" __stringify(api) ".ucode" +#define IWL9000RFB_MODULE_FIRMWARE(api) \ + IWL9000RFB_FW_PRE "-" __stringify(api) ".ucode" #define IWL9260A_MODULE_FIRMWARE(api) \ IWL9260A_FW_PRE "-" __stringify(api) ".ucode" #define IWL9260B_MODULE_FIRMWARE(api) \ @@ -182,6 +185,7 @@ const struct iwl_cfg iwl9270_2ac_cfg = { const struct iwl_cfg iwl9460_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9460", .fw_name_pre = IWL9000_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, IWL_DEVICE_9000, .ht_params = &iwl9000_ht_params, .nvm_ver = IWL9000_NVM_VERSION, @@ -193,6 +197,7 @@ const struct iwl_cfg iwl9460_2ac_cfg = { const struct iwl_cfg iwl9560_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9560", .fw_name_pre = IWL9000_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, IWL_DEVICE_9000, .ht_params = &iwl9000_ht_params, .nvm_ver = IWL9000_NVM_VERSION, @@ -202,5 +207,6 @@ const struct iwl_cfg iwl9560_2ac_cfg = { }; MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9260A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9260B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index a12197e3ce78..8b3ebd1d4a3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -275,6 +275,8 @@ struct iwl_pwr_tx_backoff { * filename is constructed as fw_name_pre.ucode. * @fw_name_pre_next_step: same as @fw_name_pre, only for next step * (if supported) + * @fw_name_pre_rf_next_step: same as @fw_name_pre_next_step, only for rf next + * step. Supported only in integrated solutions. * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. * @max_inst_size: The maximal length of the fw inst section @@ -325,6 +327,7 @@ struct iwl_cfg { const char *name; const char *fw_name_pre; const char *fw_name_pre_next_step; + const char *fw_name_pre_rf_next_step; /* params not likely to change within a device family */ const struct iwl_base_params *base_params; /* params likely to change within a device family */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index c9481b23b1a7..36fb20168598 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -316,6 +316,11 @@ #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) #define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) +/* HW RFID */ +#define CSR_HW_RFID_FLAVOR(_val) (((_val) & 0x000000F) >> 0) +#define CSR_HW_RFID_DASH(_val) (((_val) & 0x00000F0) >> 4) +#define CSR_HW_RFID_STEP(_val) (((_val) & 0x0000F00) >> 8) +#define CSR_HW_RFID_TYPE(_val) (((_val) & 0x0FFF000) >> 12) /** * hw_rev values diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 5cfacb0bca84..806933377c58 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -218,6 +218,10 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_B_STEP) fw_pre_name = cfg->fw_name_pre_next_step; + else if (drv->trans->cfg->integrated && + CSR_HW_RFID_STEP(drv->trans->hw_rf_id) == SILICON_B_STEP && + cfg->fw_name_pre_rf_next_step) + fw_pre_name = cfg->fw_name_pre_rf_next_step; else fw_pre_name = cfg->fw_name_pre; -- cgit v1.2.3 From b1e06c65fb69c5e3fddcd91987561e225eaa9bfa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Mar 2017 09:53:13 +0100 Subject: iwlwifi: mvm: remove unused TX_CMD_NEXT_FRAME_* Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 25 +--------------------- 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 052b7f0db889..30008237323a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -177,29 +177,6 @@ enum iwl_tx_cmd_sec_ctrl { TX_CMD_SEC_KEY_FROM_TABLE = 0x10, }; -/* TODO: how does these values are OK with only 16 bit variable??? */ -/* - * TX command next frame info - * - * bits 0:2 - security control (TX_CMD_SEC_*) - * bit 3 - immediate ACK required - * bit 4 - rate is taken from STA table - * bit 5 - frame belongs to BA stream - * bit 6 - immediate BA response expected - * bit 7 - unused - * bits 8:15 - Station ID - * bits 16:31 - rate - */ -#define TX_CMD_NEXT_FRAME_ACK_MSK (0x8) -#define TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10) -#define TX_CMD_NEXT_FRAME_BA_MSK (0x20) -#define TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40) -#define TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8) -#define TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00) -#define TX_CMD_NEXT_FRAME_STA_ID_POS (8) -#define TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000) -#define TX_CMD_NEXT_FRAME_RATE_POS (16) - /* * TX command Frame life time in us - to be written in pm_frame_timeout */ @@ -265,7 +242,7 @@ enum iwl_tx_offload_assist_flags_pos { * @initial_rate_index: index into the the rate table for initial TX attempt. * Applied if TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames. * @key: security key - * @next_frame_flags: TX_CMD_SEC_* and TX_CMD_NEXT_FRAME_* + * @reserved3: reserved * @life_time: frame life time (usecs??) * @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt + * btkill_cnd + reserved), first 32 bits. "0" disables usage. -- cgit v1.2.3 From 69d22e737e07c37def4674ef4e8fe63fef8a654c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Mar 2017 10:02:23 +0100 Subject: iwlwifi: kernel-doc: make proper links Using %enum instead of &enum (and in one case, %struct) results in the wrong parsing. Fix that so that if documentation is generated, the result is clickable links. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h | 8 ++++---- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 10 +++++----- drivers/net/wireless/intel/iwlwifi/iwl-modparams.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h index 420c31dab263..cfebde68a391 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h @@ -116,7 +116,7 @@ enum iwl_fw_error_dump_type { /** * struct iwl_fw_error_dump_data - data for one type - * @type: %enum iwl_fw_error_dump_type + * @type: &enum iwl_fw_error_dump_type * @len: the length starting from %data * @data: the data itself */ @@ -130,7 +130,7 @@ struct iwl_fw_error_dump_data { * struct iwl_fw_error_dump_file - the layout of the header of the file * @barker: must be %IWL_FW_ERROR_DUMP_BARKER * @file_len: the length of all the file starting from %barker - * @data: array of %struct iwl_fw_error_dump_data + * @data: array of &struct iwl_fw_error_dump_data */ struct iwl_fw_error_dump_file { __le32 barker; @@ -225,7 +225,7 @@ enum iwl_fw_error_dump_mem_type { /** * struct iwl_fw_error_dump_mem - chunk of memory - * @type: %enum iwl_fw_error_dump_mem_type + * @type: &enum iwl_fw_error_dump_mem_type * @offset: the offset from which the memory was read * @data: the content of the memory */ @@ -324,7 +324,7 @@ enum iwl_fw_dbg_trigger { /** * struct iwl_fw_error_dump_trigger_desc - describes the trigger condition - * @type: %enum iwl_fw_dbg_trigger + * @type: &enum iwl_fw_dbg_trigger * @data: raw data about what happened */ struct iwl_fw_error_dump_trigger_desc { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 89bc008e152f..c178c8f32466 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -468,7 +468,7 @@ enum iwl_fw_dbg_reg_operator { /** * struct iwl_fw_dbg_reg_op - an operation on a register * - * @op: %enum iwl_fw_dbg_reg_operator + * @op: &enum iwl_fw_dbg_reg_operator * @addr: offset of the register * @val: value */ @@ -526,7 +526,7 @@ struct iwl_fw_dbg_mem_seg_tlv { * struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data * * @version: version of the TLV - currently 0 - * @monitor_mode: %enum iwl_fw_dbg_monitor_mode + * @monitor_mode: &enum iwl_fw_dbg_monitor_mode * @size_power: buffer size will be 2^(size_power + 11) * @base_reg: addr of the base addr register (PRPH) * @end_reg: addr of the end addr register (PRPH) @@ -595,15 +595,15 @@ enum iwl_fw_dbg_trigger_vif_type { /** * struct iwl_fw_dbg_trigger_tlv - a TLV that describes the trigger - * @id: %enum iwl_fw_dbg_trigger - * @vif_type: %enum iwl_fw_dbg_trigger_vif_type + * @id: &enum iwl_fw_dbg_trigger + * @vif_type: &enum iwl_fw_dbg_trigger_vif_type * @stop_conf_ids: bitmap of configurations this trigger relates to. * if the mode is %IWL_FW_DBG_TRIGGER_STOP, then if the bit corresponding * to the currently running configuration is set, the data should be * collected. * @stop_delay: how many milliseconds to wait before collecting the data * after the STOP trigger fires. - * @mode: %enum iwl_fw_dbg_trigger_mode - can be stop / start of both + * @mode: &enum iwl_fw_dbg_trigger_mode - can be stop / start of both * @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what * configuration should be applied when the triggers kicks in. * @occurrences: number of occurrences. 0 means the trigger will never fire. diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index 4d32b10fe50c..0bd85e58cc2c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -114,7 +114,7 @@ enum iwl_uapsd_disable { * @debug_level: levels are IWL_DL_* * @ant_coupling: antenna coupling in dB, default = 0 * @nvm_file: specifies a external NVM file - * @uapsd_disable: disable U-APSD, see %enum iwl_uapsd_disable, default = + * @uapsd_disable: disable U-APSD, see &enum iwl_uapsd_disable, default = * IWL_DISABLE_UAPSD_BSS | IWL_DISABLE_UAPSD_P2P_CLIENT * @d0i3_disable: disable d0i3, default = 1, * @d0i3_entry_delay: time to wait after no refs are taken before diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h index f329e87cd97c..0d88721b7b52 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h @@ -95,7 +95,7 @@ enum iwl_ltr_config_flags { /** * struct iwl_ltr_config_cmd_v1 - configures the LTR - * @flags: See %enum iwl_ltr_config_flags + * @flags: See &enum iwl_ltr_config_flags */ struct iwl_ltr_config_cmd_v1 { __le32 flags; @@ -107,7 +107,7 @@ struct iwl_ltr_config_cmd_v1 { /** * struct iwl_ltr_config_cmd - configures the LTR - * @flags: See %enum iwl_ltr_config_flags + * @flags: See &enum iwl_ltr_config_flags * @static_long: * @static_short: * @ltr_cfg_values: -- cgit v1.2.3 From e4eb275ac5cfe71686612d929a9829345b2a4ada Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Mar 2017 10:22:06 +0100 Subject: iwlwifi: mvm: remove unused REPLY_MAX This value is unused, and there's no reason we'd ever use it. Just remove it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 332f204761cc..ef8b47faa265 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -470,8 +470,6 @@ enum iwl_legacy_cmds { SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD = 0x58, SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD = 0x59, - - REPLY_MAX = 0xff, }; /* Please keep this enum *SORTED* by hex value. -- cgit v1.2.3 From 3a07d36c2d891b30c25e03146eceaeb6e6375810 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Mar 2017 10:18:20 +0100 Subject: iwlwifi: mvm: fix many kernel-doc warnings Fix many kernel-doc warnings. In one case, this required adding a new enum value to be able to document things properly. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/fw-api-power.h | 35 ++++++++++++++-------- .../net/wireless/intel/iwlwifi/mvm/fw-api-tof.h | 16 ++++++---- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 15 ++++++++-- 3 files changed, 46 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h index 0d88721b7b52..9d87fddd29b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h @@ -82,6 +82,8 @@ * @LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register * @LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register * @LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD + * @LTR_CFG_FLAG_UPDATE_VALUES: update config values and short + * idle timeout */ enum iwl_ltr_config_flags { LTR_CFG_FLAG_FEATURE_ENABLE = BIT(0), @@ -91,11 +93,14 @@ enum iwl_ltr_config_flags { LTR_CFG_FLAG_SW_SET_SHORT = BIT(4), LTR_CFG_FLAG_SW_SET_LONG = BIT(5), LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6), + LTR_CFG_FLAG_UPDATE_VALUES = BIT(7), }; /** * struct iwl_ltr_config_cmd_v1 - configures the LTR * @flags: See &enum iwl_ltr_config_flags + * @static_long: static LTR Long register value. + * @static_short: static LTR Short register value. */ struct iwl_ltr_config_cmd_v1 { __le32 flags; @@ -108,10 +113,13 @@ struct iwl_ltr_config_cmd_v1 { /** * struct iwl_ltr_config_cmd - configures the LTR * @flags: See &enum iwl_ltr_config_flags - * @static_long: - * @static_short: - * @ltr_cfg_values: - * @ltr_short_idle_timeout: + * @static_long: static LTR Long register value. + * @static_short: static LTR Short register value. + * @ltr_cfg_values: LTR parameters table values (in usec) in folowing order: + * TX, RX, Short Idle, Long Idle. Used only if %LTR_CFG_FLAG_UPDATE_VALUES + * is set. + * @ltr_short_idle_timeout: LTR Short Idle timeout (in usec). Used only if + * %LTR_CFG_FLAG_UPDATE_VALUES is set. */ struct iwl_ltr_config_cmd { __le32 flags; @@ -140,7 +148,7 @@ struct iwl_ltr_config_cmd { * PBW Snoozing enabled * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. - * @POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving + * @POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving * detection enablement */ enum iwl_power_flags { @@ -166,6 +174,7 @@ enum iwl_power_flags { * Minimum allowed:- 3 * DTIM. Keep alive period must be * set regardless of power scheme or current power state. * FW use this value also when PM is disabled. + * @debug_flags: debug flags * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to * PSM transition - legacy PM * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to @@ -191,7 +200,8 @@ struct iwl_powertable_cmd { /** * enum iwl_device_power_flags - masks for device power command flags - * @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off + * @DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK: + * '1' Allow to save power by turning off * receiver and transmitter. '0' - does not allow. */ enum iwl_device_power_flags { @@ -203,6 +213,7 @@ enum iwl_device_power_flags { * DEVICE_POWER_CMD = 0x77 (command, has simple generic response) * * @flags: Power table command flags from &enum iwl_device_power_flags + * @reserved: reserved (padding) */ struct iwl_device_power_cmd { /* PM_POWER_TABLE_CMD_API_S_VER_6 */ @@ -223,7 +234,6 @@ struct iwl_device_power_cmd { * PSM transition - legacy PM * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to * PSM transition - legacy PM - * @sleep_interval: not in use * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag * is set. For example, if it is required to skip over * one DTIM, this value need to be set to 2 (DTIM periods). @@ -233,7 +243,6 @@ struct iwl_device_power_cmd { * PSM transition - uAPSD * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. * Default: 80dbm - * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set * @snooze_interval: Maximum time between attempts to retrieve buffered data * from the AP [msec] * @snooze_window: A window of time in which PBW snoozing insures that all @@ -251,8 +260,9 @@ struct iwl_device_power_cmd { * @heavy_rx_thld_packets: RX threshold measured in number of packets * @heavy_tx_thld_percentage: TX threshold measured in load's percentage * @heavy_rx_thld_percentage: RX threshold measured in load's percentage - * @limited_ps_threshold: -*/ + * @limited_ps_threshold: (unused) + * @reserved: reserved (padding) + */ struct iwl_mac_power_cmd { /* CONTEXT_DESC_API_T_VER_1 */ __le32 id_and_color; @@ -343,6 +353,7 @@ struct iwl_dev_tx_power_cmd_v3 { * @v3: version 3 of the command, embedded here for easier software handling * @enable_ack_reduction: enable or disable close range ack TX power * reduction. + * @reserved: reserved (padding) */ struct iwl_dev_tx_power_cmd { /* v4 is just an extension of v3 - keep this here */ @@ -393,7 +404,6 @@ struct iwl_geo_tx_power_profiles_cmd { /** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) - * @id_and_color: MAC contex identifier * @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon * to driver if delta in Energy values calculated for this and last * passed beacon is greater than this threshold. Zero value means that @@ -425,7 +435,8 @@ struct iwl_geo_tx_power_profiles_cmd { * beacon filtering; beacons will not be forced to be sent to driver * regardless of whether its temerature has been changed. * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled. - * @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed + * @bf_debug_flag: beacon filtering debug configuration + * @bf_escape_timer: Send beacons to to driver if no beacons were passed * for a specific period of time. Units: Beacons. * @ba_escape_timer: Fully receive and parse beacon if no beacons were passed * for a longer period of time then this escape-timeout. Units: Beacons. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h index 86aa51b2210e..eae036af880e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h @@ -118,11 +118,17 @@ struct iwl_tof_config_cmd { * @bandwidth: current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz * @rate: current AP rate * @ctrl_ch_position: coding of the control channel position relative to - * the center frequency. - * 40MHz 0 below center, 1 above center - * 80MHz bits [0..1]: 0 the near 20MHz to the center, - * 1 the far 20MHz to the center - * bit[2] as above 40MHz + * the center frequency: + * + * 40 MHz + * 0 below center, 1 above center + * + * 80 MHz + * bits [0..1] + * * 0 the near 20MHz to the center, + * * 1 the far 20MHz to the center + * bit[2] + * as above 40MHz * @ftm_per_burst: FTMs per Burst * @ftm_resp_ts_avail: '0' - we don't measure over the Initial FTM Response, * '1' - we measure over the Initial FTM Response diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 30008237323a..e7610add13f6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -74,6 +74,7 @@ * Otherwise, use rate_n_flags from the TX command * @TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected * Must set TX_CMD_FLG_ACK with this flag. + * @TX_CMD_FLG_TXOP_PROT: TXOP protection requested * @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence * @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence * @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) @@ -201,7 +202,7 @@ enum iwl_tx_cmd_sec_ctrl { /** * enum iwl_tx_offload_assist_flags_pos - set %iwl_tx_cmd offload_assist values - * @TX_CMD_OFFLD_IP_HDR_OFFSET: offset to start of IP header (in words) + * @TX_CMD_OFFLD_IP_HDR: offset to start of IP header (in words) * from mac header end. For normal case it is 4 words for SNAP. * note: tx_cmd, mac header and pad are not counted in the offset. * This is used to help the offload in case there is tunneling such as @@ -235,12 +236,14 @@ enum iwl_tx_offload_assist_flags_pos { * @len: in bytes of the payload, see below for details * @offload_assist: TX offload configuration * @tx_flags: combination of TX_CMD_FLG_* + * @scratch: scratch buffer used by the device * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* * @sta_id: index of destination station in FW station table * @sec_ctl: security control, TX_CMD_SEC_* * @initial_rate_index: index into the the rate table for initial TX attempt. * Applied if TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames. + * @reserved2: reserved * @key: security key * @reserved3: reserved * @life_time: frame life time (usecs??) @@ -249,8 +252,11 @@ enum iwl_tx_offload_assist_flags_pos { * @dram_msb_ptr: upper bits of the scratch physical address * @rts_retry_limit: max attempts for RTS * @data_retry_limit: max attempts to send the data packet - * @tid_spec: TID/tspec + * @tid_tspec: TID/tspec * @pm_frame_timeout: PM TX frame timeout + * @reserved4: reserved + * @payload: payload (same as @hdr) + * @hdr: 802.11 header (same as @payload) * * The byte count (both len and next_frame_len) includes MAC header * (24/26/30/32 bytes) @@ -304,10 +310,11 @@ struct iwl_dram_sec_info { * ( TX_CMD = 0x1c ) * @len: in bytes of the payload, see below for details * @offload_assist: TX offload configuration - * @tx_flags: combination of &iwl_tx_cmd_flags + * @flags: combination of &enum iwl_tx_cmd_flags * @dram_info: FW internal DRAM storage * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* + * @hdr: 802.11 header */ struct iwl_tx_cmd_gen2 { __le16 len; @@ -519,6 +526,8 @@ struct agg_tx_status { * @pa_integ_res_b: tx power info * @pa_integ_res_c: tx power info * @measurement_req_id: tx power info + * @reduced_tpc: transmit power reduction used + * @reserved: reserved * @tfd_info: TFD information set by the FH * @seq_ctl: sequence control from the Tx cmd * @byte_cnt: byte count from the Tx cmd -- cgit v1.2.3 From d6d517b7730c2dada199db83ebbc670c50fa9952 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 6 Mar 2017 10:16:11 +0200 Subject: iwlwifi: add wait for tx queue empty Now that we have 512 queues, add a wait for single TX queue to gen2. This replaces gen1 wait_tx_queues_empty, which was limited to 32 queues. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 2 + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 20 ++++++- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 41 ++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 2 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 72 ++++++++++++++--------- 6 files changed, 107 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 0bde26bab15d..c0871f8f2c68 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -102,6 +102,8 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, if (!trans->dev_cmd_pool) return NULL; + WARN_ON(!ops->wait_txq_empty && !ops->wait_tx_queues_empty); + return trans; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 0ebfdbb22992..d3a78a11821a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -619,7 +619,8 @@ struct iwl_tx_queue_cfg_rsp { * @txq_disable: de-configure a Tx queue to send AMPDUs * Must be atomic * @txq_set_shared_mode: change Tx queue shared/unshared marking - * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. + * @wait_tx_queues_empty: wait until tx queues are empty. May sleep. + * @wait_txq_empty: wait until specific tx queue is empty. May sleep. * @freeze_txq_timer: prevents the timer of the queue from firing until the * queue is set to awake. Must be atomic. * @block_txq_ptrs: stop updating the write pointers of the Tx queues. Note @@ -692,6 +693,7 @@ struct iwl_trans_ops { bool shared); int (*wait_tx_queues_empty)(struct iwl_trans *trans, u32 txq_bm); + int (*wait_txq_empty)(struct iwl_trans *trans, int queue); void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs, bool freeze); void (*block_txq_ptrs)(struct iwl_trans *trans, bool block); @@ -1198,6 +1200,9 @@ static inline void iwl_trans_block_txq_ptrs(struct iwl_trans *trans, static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, u32 txqs) { + if (WARN_ON_ONCE(!trans->ops->wait_tx_queues_empty)) + return -ENOTSUPP; + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); return -EIO; @@ -1206,6 +1211,19 @@ static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, return trans->ops->wait_tx_queues_empty(trans, txqs); } +static inline int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue) +{ + if (WARN_ON_ONCE(!trans->ops->wait_txq_empty)) + return -ENOTSUPP; + + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { + IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return -EIO; + } + + return trans->ops->wait_txq_empty(trans, queue); +} + static inline void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) { trans->ops->write8(trans, ofs, val); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index f4437d5b2e73..50510e96a82d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3995,6 +3995,8 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, IWL_ERR(mvm, "flush request fail\n"); } else { msk |= mvmsta->tfd_queue_msk; + if (iwl_mvm_has_new_tx_api(mvm)) + iwl_mvm_wait_sta_queues_empty(mvm, mvmsta); } } @@ -4003,7 +4005,7 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, /* this can take a while, and we may need/want other operations * to succeed while doing this, so do it without the mutex held */ - if (!drop) + if (!drop && !iwl_mvm_has_new_tx_api(mvm)) iwl_trans_wait_tx_queues_empty(mvm->trans, msk); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 9f74d4ff6b73..3dad87b79cf0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1590,6 +1590,29 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm, } } +int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvm_sta) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(mvm_sta->tid_data); i++) { + u16 txq_id; + + spin_lock_bh(&mvm_sta->lock); + txq_id = mvm_sta->tid_data[i].txq_id; + spin_unlock_bh(&mvm_sta->lock); + + if (txq_id == IWL_MVM_INVALID_QUEUE) + continue; + + ret = iwl_trans_wait_txq_empty(mvm->trans, txq_id); + if (ret) + break; + } + + return ret; +} + int iwl_mvm_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -1614,8 +1637,14 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0); if (ret) return ret; - ret = iwl_trans_wait_tx_queues_empty(mvm->trans, - mvm_sta->tfd_queue_msk); + if (iwl_mvm_has_new_tx_api(mvm)) { + ret = iwl_mvm_wait_sta_queues_empty(mvm, mvm_sta); + } else { + u32 q_mask = mvm_sta->tfd_queue_msk; + + ret = iwl_trans_wait_tx_queues_empty(mvm->trans, + q_mask); + } if (ret) return ret; ret = iwl_mvm_drain_sta(mvm, mvm_sta, false); @@ -2850,7 +2879,13 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_drain_sta(mvm, mvmsta, true); if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), 0)) IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); - iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(txq_id)); + + if (iwl_mvm_has_new_tx_api(mvm)) + iwl_trans_wait_txq_empty(mvm->trans, txq_id); + + else + iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(txq_id)); + iwl_mvm_drain_sta(mvm, mvmsta, false); iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 2716cb5483bf..1c28caecaa1e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -487,6 +487,8 @@ static inline int iwl_mvm_update_sta(struct iwl_mvm *mvm, return iwl_mvm_sta_send_to_fw(mvm, sta, true, 0); } +int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvm_sta); int iwl_mvm_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 85f44d8f1c41..a6c171c5b26f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2045,17 +2045,52 @@ void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq) iwl_read_direct32(trans, FH_TX_TRB_REG(fifo))); } -static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) +static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq; - int cnt; unsigned long now = jiffies; + u8 wr_ptr; + + if (!test_bit(txq_idx, trans_pcie->queue_used)) + return -EINVAL; + + IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", txq_idx); + txq = trans_pcie->txq[txq_idx]; + wr_ptr = ACCESS_ONCE(txq->write_ptr); + + while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) && + !time_after(jiffies, + now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) { + u8 write_ptr = ACCESS_ONCE(txq->write_ptr); + + if (WARN_ONCE(wr_ptr != write_ptr, + "WR pointer moved while flushing %d -> %d\n", + wr_ptr, write_ptr)) + return -ETIMEDOUT; + usleep_range(1000, 2000); + } + + if (txq->read_ptr != txq->write_ptr) { + IWL_ERR(trans, + "fail to flush all tx fifo queues Q %d\n", txq_idx); + iwl_trans_pcie_log_scd_error(trans, txq); + return -ETIMEDOUT; + } + + IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", txq_idx); + + return 0; +} + +static int iwl_trans_pcie_wait_txqs_empty(struct iwl_trans *trans, u32 txq_bm) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int cnt; int ret = 0; /* waiting for all the tx frames complete might take a while */ for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { - u8 wr_ptr; if (cnt == trans_pcie->cmd_queue) continue; @@ -2064,34 +2099,11 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) if (!(BIT(cnt) & txq_bm)) continue; - IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", cnt); - txq = trans_pcie->txq[cnt]; - wr_ptr = ACCESS_ONCE(txq->write_ptr); - - while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) && - !time_after(jiffies, - now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) { - u8 write_ptr = ACCESS_ONCE(txq->write_ptr); - - if (WARN_ONCE(wr_ptr != write_ptr, - "WR pointer moved while flushing %d -> %d\n", - wr_ptr, write_ptr)) - return -ETIMEDOUT; - usleep_range(1000, 2000); - } - - if (txq->read_ptr != txq->write_ptr) { - IWL_ERR(trans, - "fail to flush all tx fifo queues Q %d\n", cnt); - ret = -ETIMEDOUT; + ret = iwl_trans_pcie_wait_txq_empty(trans, cnt); + if (ret) break; - } - IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", cnt); } - if (ret) - iwl_trans_pcie_log_scd_error(trans, txq); - return ret; } @@ -2862,7 +2874,6 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans) .ref = iwl_trans_pcie_ref, \ .unref = iwl_trans_pcie_unref, \ .dump_data = iwl_trans_pcie_dump_data, \ - .wait_tx_queues_empty = iwl_trans_pcie_wait_txq_empty, \ .d3_suspend = iwl_trans_pcie_d3_suspend, \ .d3_resume = iwl_trans_pcie_d3_resume @@ -2892,6 +2903,8 @@ static const struct iwl_trans_ops trans_ops_pcie = { .txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode, + .wait_tx_queues_empty = iwl_trans_pcie_wait_txqs_empty, + .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, }; @@ -2911,6 +2924,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .txq_alloc = iwl_trans_pcie_dyn_txq_alloc, .txq_free = iwl_trans_pcie_dyn_txq_free, + .wait_txq_empty = iwl_trans_pcie_wait_txq_empty, }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, -- cgit v1.2.3 From 3a5f8997dc643a0e0e9a0895c2214b21e5e774a2 Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Thu, 1 Jun 2017 15:37:02 +0800 Subject: team: add macro MODULE_ALIAS_TEAM_MODE for team mode alias Add a new macro MODULE_ALIAS_TEAM_MODE to unify and simplify the declaration of team mode alias. Signed-off-by: Zhang Shengju Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/team/team_mode_activebackup.c | 2 +- drivers/net/team/team_mode_broadcast.c | 2 +- drivers/net/team/team_mode_loadbalance.c | 2 +- drivers/net/team/team_mode_random.c | 2 +- drivers/net/team/team_mode_roundrobin.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c index 3f189823ba3b..ddd16a0c1fc1 100644 --- a/drivers/net/team/team_mode_activebackup.c +++ b/drivers/net/team/team_mode_activebackup.c @@ -146,4 +146,4 @@ module_exit(ab_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko "); MODULE_DESCRIPTION("Active-backup mode for team"); -MODULE_ALIAS("team-mode-activebackup"); +MODULE_ALIAS_TEAM_MODE("activebackup"); diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c index 302ff35b0cbc..e4eac3de1862 100644 --- a/drivers/net/team/team_mode_broadcast.c +++ b/drivers/net/team/team_mode_broadcast.c @@ -75,4 +75,4 @@ module_exit(bc_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko "); MODULE_DESCRIPTION("Broadcast mode for team"); -MODULE_ALIAS("team-mode-broadcast"); +MODULE_ALIAS_TEAM_MODE("broadcast"); diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c index b228bea7931f..1468ddf424cc 100644 --- a/drivers/net/team/team_mode_loadbalance.c +++ b/drivers/net/team/team_mode_loadbalance.c @@ -695,4 +695,4 @@ module_exit(lb_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko "); MODULE_DESCRIPTION("Load-balancing mode for team"); -MODULE_ALIAS("team-mode-loadbalance"); +MODULE_ALIAS_TEAM_MODE("loadbalance"); diff --git a/drivers/net/team/team_mode_random.c b/drivers/net/team/team_mode_random.c index 215f845782db..c20b9446e2e4 100644 --- a/drivers/net/team/team_mode_random.c +++ b/drivers/net/team/team_mode_random.c @@ -65,4 +65,4 @@ module_exit(rnd_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko "); MODULE_DESCRIPTION("Random mode for team"); -MODULE_ALIAS("team-mode-random"); +MODULE_ALIAS_TEAM_MODE("random"); diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c index 0aa234118c03..66c3209dc4a6 100644 --- a/drivers/net/team/team_mode_roundrobin.c +++ b/drivers/net/team/team_mode_roundrobin.c @@ -77,4 +77,4 @@ module_exit(rr_cleanup_module); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jiri Pirko "); MODULE_DESCRIPTION("Round-robin mode for team"); -MODULE_ALIAS("team-mode-roundrobin"); +MODULE_ALIAS_TEAM_MODE("roundrobin"); -- cgit v1.2.3 From 5779675912fa87d8d0af651537acc0e312f06c70 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 2 Jun 2017 08:58:30 +0300 Subject: qed: Correct order of wwnn and wwpn Driver reads values via HSI splitting this 8-byte into 2 32-bit values and builds a single u64 field - but it does so by shifting the lower field instead of the higher. Luckily, we still don't use these fields for anything - but we're about to start. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 31c88e192cd0..e82f32950361 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1736,10 +1736,10 @@ int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); } - info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_upper | - (((u64)shmem_info.fcoe_wwn_port_name_lower) << 32); - info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_upper | - (((u64)shmem_info.fcoe_wwn_node_name_lower) << 32); + info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_lower | + (((u64)shmem_info.fcoe_wwn_port_name_upper) << 32); + info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_lower | + (((u64)shmem_info.fcoe_wwn_node_name_upper) << 32); info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); -- cgit v1.2.3 From 3c5da94278026a4583320f97f6547573fb3a93aa Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 2 Jun 2017 08:58:31 +0300 Subject: qed: Share additional information with qedf Share several new tidbits with qedf: - wwpn & wwnn - Absolute pf-id [this one is actually meant for qedi as well] - Number of available CQs While we're at it, now that qedf will be aware of the available CQs we can add some validation on the inputs it provides. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 8 +++++++- drivers/net/ethernet/qlogic/qed/qed_fcoe.c | 14 ++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_main.c | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 7649f35000db..2d88d4883483 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -2071,16 +2071,22 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) QED_VF_L2_QUE)); } + if (p_hwfn->hw_info.personality == QED_PCI_FCOE) + feat_num[QED_FCOE_CQ] = min_t(u32, sb_cnt.cnt, + RESC_NUM(p_hwfn, + QED_CMDQS_CQS)); + if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) feat_num[QED_ISCSI_CQ] = min_t(u32, sb_cnt.cnt, RESC_NUM(p_hwfn, QED_CMDQS_CQS)); DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE, - "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d ISCSI_CQ=%d #SBS=%d\n", + "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d FCOE_CQ=%d ISCSI_CQ=%d #SBS=%d\n", (int)FEAT_NUM(p_hwfn, QED_PF_L2_QUE), (int)FEAT_NUM(p_hwfn, QED_VF_L2_QUE), (int)FEAT_NUM(p_hwfn, QED_RDMA_CNQ), + (int)FEAT_NUM(p_hwfn, QED_FCOE_CQ), (int)FEAT_NUM(p_hwfn, QED_ISCSI_CQ), (int)sb_cnt.cnt); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c index 3fc4ff22960e..df195c02b711 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c @@ -141,6 +141,15 @@ qed_sp_fcoe_func_start(struct qed_hwfn *p_hwfn, p_data = &p_ramrod->init_ramrod_data; fcoe_pf_params = &p_hwfn->pf_params.fcoe_pf_params; + /* Sanity */ + if (fcoe_pf_params->num_cqs > p_hwfn->hw_info.feat_num[QED_FCOE_CQ]) { + DP_ERR(p_hwfn, + "Cannot satisfy CQ amount. CQs requested %d, CQs available %d. Aborting function start\n", + fcoe_pf_params->num_cqs, + p_hwfn->hw_info.feat_num[QED_FCOE_CQ]); + return -EINVAL; + } + p_data->mtu = cpu_to_le16(fcoe_pf_params->mtu); tmp = cpu_to_le16(fcoe_pf_params->sq_num_pbl_pages); p_data->sq_num_pages_in_pbl = tmp; @@ -739,6 +748,11 @@ static int qed_fill_fcoe_dev_info(struct qed_dev *cdev, info->secondary_bdq_rq_addr = qed_fcoe_get_secondary_bdq_prod(hwfn, BDQ_ID_RQ); + info->wwpn = hwfn->mcp_info->func_info.wwn_port; + info->wwnn = hwfn->mcp_info->func_info.wwn_node; + + info->num_cqs = FEAT_NUM(hwfn, QED_FCOE_CQ); + return rc; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index ac3bdcd9f0b6..baebd5926895 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -269,6 +269,8 @@ int qed_fill_dev_info(struct qed_dev *cdev, if (QED_LEADING_HWFN(cdev)->hw_info.b_wol_support == QED_WOL_SUPPORT_PME) dev_info->wol_support = true; + + dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id; } else { qed_vf_get_fw_version(&cdev->hwfns[0], &dev_info->fw_major, &dev_info->fw_minor, &dev_info->fw_rev, -- cgit v1.2.3 From 20675b37ee76d11430fd3d4da0851fc6a4e36abc Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 2 Jun 2017 08:58:32 +0300 Subject: qed: Support NVM-image reading API Storage drivers require images from the nvram in boot-from-SAN scenarios. This provides the necessary API between qed and the protocol drivers to perform such reads. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_main.c | 16 ++++++ drivers/net/ethernet/qlogic/qed/qed_mcp.c | 89 ++++++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_mcp.h | 21 +++++++ 3 files changed, 126 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index baebd5926895..6ac10ce14e5b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -1535,6 +1535,21 @@ static int qed_drain(struct qed_dev *cdev) return 0; } +static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, + u8 *buf, u16 len) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_ptt *ptt = qed_ptt_acquire(hwfn); + int rc; + + if (!ptt) + return -EAGAIN; + + rc = qed_mcp_get_nvm_image(hwfn, ptt, type, buf, len); + qed_ptt_release(hwfn, ptt); + return rc; +} + static void qed_get_coalesce(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal) { *rx_coal = cdev->rx_coalesce_usecs; @@ -1712,6 +1727,7 @@ const struct qed_common_ops qed_common_ops_pass = { .dbg_all_data_size = &qed_dbg_all_data_size, .chain_alloc = &qed_chain_alloc, .chain_free = &qed_chain_free, + .nvm_get_image = &qed_nvm_get_image, .get_coalesce = &qed_get_coalesce, .set_coalesce = &qed_set_coalesce, .set_led = &qed_set_led, diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index e82f32950361..9da91045d167 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -2310,6 +2310,95 @@ int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn, return rc; } +static int +qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_nvm_images image_id, + struct qed_nvm_image_att *p_image_att) +{ + struct bist_nvm_image_att mfw_image_att; + enum nvm_image_type type; + u32 num_images, i; + int rc; + + /* Translate image_id into MFW definitions */ + switch (image_id) { + case QED_NVM_IMAGE_ISCSI_CFG: + type = NVM_TYPE_ISCSI_CFG; + break; + case QED_NVM_IMAGE_FCOE_CFG: + type = NVM_TYPE_FCOE_CFG; + break; + default: + DP_NOTICE(p_hwfn, "Unknown request of image_id %08x\n", + image_id); + return -EINVAL; + } + + /* Learn number of images, then traverse and see if one fits */ + rc = qed_mcp_bist_nvm_test_get_num_images(p_hwfn, p_ptt, &num_images); + if (rc || !num_images) + return -EINVAL; + + for (i = 0; i < num_images; i++) { + rc = qed_mcp_bist_nvm_test_get_image_att(p_hwfn, p_ptt, + &mfw_image_att, i); + if (rc) + return rc; + + if (type == mfw_image_att.image_type) + break; + } + if (i == num_images) { + DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, + "Failed to find nvram image of type %08x\n", + image_id); + return -EINVAL; + } + + p_image_att->start_addr = mfw_image_att.nvm_start_addr; + p_image_att->length = mfw_image_att.len; + + return 0; +} + +int qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_nvm_images image_id, + u8 *p_buffer, u32 buffer_len) +{ + struct qed_nvm_image_att image_att; + int rc; + + memset(p_buffer, 0, buffer_len); + + rc = qed_mcp_get_nvm_image_att(p_hwfn, p_ptt, image_id, &image_att); + if (rc) + return rc; + + /* Validate sizes - both the image's and the supplied buffer's */ + if (image_att.length <= 4) { + DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, + "Image [%d] is too small - only %d bytes\n", + image_id, image_att.length); + return -EINVAL; + } + + /* Each NVM image is suffixed by CRC; Upper-layer has no need for it */ + image_att.length -= 4; + + if (image_att.length > buffer_len) { + DP_VERBOSE(p_hwfn, + QED_MSG_STORAGE, + "Image [%d] is too big - %08x bytes where only %08x are available\n", + image_id, image_att.length, buffer_len); + return -ENOMEM; + } + + return qed_mcp_nvm_read(p_hwfn->cdev, image_att.start_addr, + p_buffer, image_att.length); +} + static enum resource_id_enum qed_mcp_get_mfw_res_id(enum qed_resources res_id) { enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 40247593e772..af03b3651411 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -430,6 +430,27 @@ int qed_mcp_set_led(struct qed_hwfn *p_hwfn, */ int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len); +struct qed_nvm_image_att { + u32 start_addr; + u32 length; +}; + +/** + * @brief Allows reading a whole nvram image + * + * @param p_hwfn + * @param p_ptt + * @param image_id - image requested for reading + * @param p_buffer - allocated buffer into which to fill data + * @param buffer_len - length of the allocated buffer. + * + * @return 0 iff p_buffer now contains the nvram image. + */ +int qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + enum qed_nvm_images image_id, + u8 *p_buffer, u32 buffer_len); + /** * @brief Bist register test * -- cgit v1.2.3 From dc4528e9e890f82900d75ac6276aba8ce89a80b6 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 2 Jun 2017 08:58:33 +0300 Subject: qed: Add support for changing iSCSI mac Enhance API between qedi and qed, allowing qedi to inform device's firmware when the iSCSI mac is to be changed. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 66 +++++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_sp.h | 1 + 2 files changed, 67 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index bc8ce09d390f..6103723d7118 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -488,6 +488,54 @@ static int qed_sp_iscsi_conn_update(struct qed_hwfn *p_hwfn, return qed_spq_post(p_hwfn, p_ent, NULL); } +static int +qed_sp_iscsi_mac_update(struct qed_hwfn *p_hwfn, + struct qed_iscsi_conn *p_conn, + enum spq_mode comp_mode, + struct qed_spq_comp_cb *p_comp_addr) +{ + struct iscsi_spe_conn_mac_update *p_ramrod = NULL; + struct qed_spq_entry *p_ent = NULL; + struct qed_sp_init_data init_data; + int rc = -EINVAL; + u8 ucval; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = p_conn->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = comp_mode; + init_data.p_comp_data = p_comp_addr; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + ISCSI_RAMROD_CMD_ID_MAC_UPDATE, + PROTOCOLID_ISCSI, &init_data); + if (rc) + return rc; + + p_ramrod = &p_ent->ramrod.iscsi_conn_mac_update; + p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_MAC_UPDATE; + SET_FIELD(p_ramrod->hdr.flags, + ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code); + + p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id); + p_ramrod->fw_cid = cpu_to_le32(p_conn->icid); + ucval = p_conn->remote_mac[1]; + ((u8 *)(&p_ramrod->remote_mac_addr_hi))[0] = ucval; + ucval = p_conn->remote_mac[0]; + ((u8 *)(&p_ramrod->remote_mac_addr_hi))[1] = ucval; + ucval = p_conn->remote_mac[3]; + ((u8 *)(&p_ramrod->remote_mac_addr_mid))[0] = ucval; + ucval = p_conn->remote_mac[2]; + ((u8 *)(&p_ramrod->remote_mac_addr_mid))[1] = ucval; + ucval = p_conn->remote_mac[5]; + ((u8 *)(&p_ramrod->remote_mac_addr_lo))[0] = ucval; + ucval = p_conn->remote_mac[4]; + ((u8 *)(&p_ramrod->remote_mac_addr_lo))[1] = ucval; + + return qed_spq_post(p_hwfn, p_ent, NULL); +} + static int qed_sp_iscsi_conn_terminate(struct qed_hwfn *p_hwfn, struct qed_iscsi_conn *p_conn, enum spq_mode comp_mode, @@ -1324,6 +1372,23 @@ static int qed_iscsi_stats(struct qed_dev *cdev, struct qed_iscsi_stats *stats) return qed_iscsi_get_stats(QED_LEADING_HWFN(cdev), stats); } +static int qed_iscsi_change_mac(struct qed_dev *cdev, + u32 handle, const u8 *mac) +{ + struct qed_hash_iscsi_con *hash_con; + + hash_con = qed_iscsi_get_hash(cdev, handle); + if (!hash_con) { + DP_NOTICE(cdev, "Failed to find connection for handle %d\n", + handle); + return -EINVAL; + } + + return qed_sp_iscsi_mac_update(QED_LEADING_HWFN(cdev), + hash_con->con, + QED_SPQ_MODE_EBLOCK, NULL); +} + void qed_get_protocol_stats_iscsi(struct qed_dev *cdev, struct qed_mcp_iscsi_stats *stats) { @@ -1358,6 +1423,7 @@ static const struct qed_iscsi_ops qed_iscsi_ops_pass = { .destroy_conn = &qed_iscsi_destroy_conn, .clear_sq = &qed_iscsi_clear_conn_sq, .get_stats = &qed_iscsi_stats, + .change_mac = &qed_iscsi_change_mac, }; const struct qed_iscsi_ops *qed_get_iscsi_ops(void) diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index b9464f3ab0e2..00dd50f8c42f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -120,6 +120,7 @@ union ramrod_data { struct iscsi_spe_func_dstry iscsi_destroy; struct iscsi_spe_conn_offload iscsi_conn_offload; struct iscsi_conn_update_ramrod_params iscsi_conn_update; + struct iscsi_spe_conn_mac_update iscsi_conn_mac_update; struct iscsi_spe_conn_termination iscsi_conn_terminate; struct vf_start_ramrod_data vf_start; -- cgit v1.2.3 From a97051f4553551d13e586ab3cb6ae13093a44a81 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Wed, 31 May 2017 19:10:21 +0530 Subject: cxgb4: fix incorrect cim_la output for T6 take care of UpDbgLaRdPtr[0-3] restriction for T6. Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 9160c882fbfc..822c560fb310 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -8312,7 +8312,16 @@ int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]); if (ret) break; - idx = (idx + 1) & UPDBGLARDPTR_M; + + /* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to + * identify the 32-bit portion of the full 312-bit data + */ + if (is_t6(adap->params.chip) && (idx & 0xf) >= 9) + idx = (idx & 0xff0) + 0x10; + else + idx++; + /* address can't exceed 0xfff */ + idx &= UPDBGLARDPTR_M; } restart: if (cfg & UPDBGLAEN_F) { -- cgit v1.2.3 From 4c1588a27991c9047cbd3a109632597514722e47 Mon Sep 17 00:00:00 2001 From: Rick Farrington Date: Wed, 31 May 2017 09:48:09 -0700 Subject: liquidio: VF interrupt initialization cleanup Set initialization state variable to (reflect interrupt initialization) at correct time (immediately after having configured interrupts). This fixes problem of inconsistent IRQ allocation in case of [obscure] failure when negotiating with PF driver during init. Clean-up of interrupt enablement during initialization & avoid potential race condition with chip-specific code (i.e. perform interrupt control in main driver module). Added explanatory comments regarding interrupt enablement. Signed-off-by: Rick Farrington Signed-off-by: Satanand Burla Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../net/ethernet/cavium/liquidio/cn23xx_vf_device.c | 10 ---------- drivers/net/ethernet/cavium/liquidio/lio_vf_main.c | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c index b6117b6a1de2..20f3d2adf0c2 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c @@ -431,11 +431,6 @@ int cn23xx_octeon_pfvf_handshake(struct octeon_device *oct) mbox_cmd.fn = (octeon_mbox_callback_t)octeon_pfvf_hs_callback; mbox_cmd.fn_arg = &status; - /* Interrupts are not enabled at this point. - * Enable them with default oq ticks - */ - oct->fn_list.enable_interrupt(oct, OCTEON_ALL_INTR); - octeon_mbox_write(oct, &mbox_cmd); atomic_set(&status, 0); @@ -444,11 +439,6 @@ int cn23xx_octeon_pfvf_handshake(struct octeon_device *oct) schedule_timeout_uninterruptible(1); } while ((!atomic_read(&status)) && (count++ < 100000)); - /* Disable the interrupt so that the interrupsts will be reenabled - * with the oq ticks received from the PF - */ - oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR); - ret = atomic_read(&status); if (!ret) { dev_err(&oct->pci_dev->dev, "octeon_pfvf_handshake timeout\n"); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 31d737c22648..07124096db48 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -3188,13 +3188,28 @@ static int octeon_device_init(struct octeon_device *oct) if (octeon_setup_interrupt(oct)) return 1; + atomic_set(&oct->status, OCT_DEV_INTR_SET_DONE); + + /* *************************************************************** + * The interrupts need to be enabled for the PF<-->VF handshake. + * They are [re]-enabled after the PF<-->VF handshake so that the + * correct OQ tick value is used (i.e. the value retrieved from + * the PF as part of the handshake). + */ + + /* Enable Octeon device interrupts */ + oct->fn_list.enable_interrupt(oct, OCTEON_ALL_INTR); + if (cn23xx_octeon_pfvf_handshake(oct)) return 1; + /* Here we [re]-enable the interrupts so that the correct OQ tick value + * is used (i.e. the value that was retrieved during the handshake) + */ + /* Enable Octeon device interrupts */ oct->fn_list.enable_interrupt(oct, OCTEON_ALL_INTR); - - atomic_set(&oct->status, OCT_DEV_INTR_SET_DONE); + /* *************************************************************** */ /* Enable the input and output queues for this Octeon device */ if (oct->fn_list.enable_io_queues(oct)) { -- cgit v1.2.3 From 9ae122c62a26ed3022d0affb5b7fffe0292bae16 Mon Sep 17 00:00:00 2001 From: Satanand Burla Date: Wed, 31 May 2017 10:45:15 -0700 Subject: liquidio: Fix checkpatch errors with references crossing single line Signed-off-by: Satanand Burla Signed-off-by: Derek Chickles Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_ethtool.c | 8 ++++---- drivers/net/ethernet/cavium/liquidio/octeon_droq.c | 11 +++++------ drivers/net/ethernet/cavium/liquidio/request_manager.c | 3 +-- 3 files changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index 579dc7336f58..2e253061460b 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -984,11 +984,11 @@ lio_get_ethtool_stats(struct net_device *netdev, data[i++] = CVM_CAST64(oct_dev->instr_queue[j]->stats.instr_posted); /*# of instructions processed */ - data[i++] = CVM_CAST64(oct_dev->instr_queue[j]-> - stats.instr_processed); + data[i++] = CVM_CAST64( + oct_dev->instr_queue[j]->stats.instr_processed); /*# of instructions could not be processed */ - data[i++] = CVM_CAST64(oct_dev->instr_queue[j]-> - stats.instr_dropped); + data[i++] = CVM_CAST64( + oct_dev->instr_queue[j]->stats.instr_dropped); /*bytes sent through the queue */ data[i++] = CVM_CAST64(oct_dev->instr_queue[j]->stats.bytes_sent); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index 286be5539cef..d3a6a1c28053 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -425,8 +425,7 @@ octeon_droq_refill_pullup_descs(struct octeon_droq *droq, droq->max_count); desc_refilled++; droq->refill_count--; - } while (droq->recv_buf_list[droq->refill_idx]. - buffer); + } while (droq->recv_buf_list[droq->refill_idx].buffer); } refill_index = incr_index(refill_index, 1, droq->max_count); } /* while */ @@ -490,8 +489,8 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq) droq->recv_buf_list[droq->refill_idx].data = data; desc_ring[droq->refill_idx].buffer_ptr = - lio_map_ring(droq->recv_buf_list[droq-> - refill_idx].buffer); + lio_map_ring(droq->recv_buf_list[ + droq->refill_idx].buffer); /* Reset any previous values in the length field. */ droq->info_list[droq->refill_idx].length = 0; @@ -690,8 +689,8 @@ octeon_droq_fast_process_packets(struct octeon_device *oct, nicbuf, cpy_len, idx); - buf = droq->recv_buf_list[idx]. - buffer; + buf = droq->recv_buf_list[ + idx].buffer; recv_buffer_fast_free(buf); droq->recv_buf_list[idx].buffer = NULL; diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c index 261f448f9de2..7b297f1f6dbe 100644 --- a/drivers/net/ethernet/cavium/liquidio/request_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c @@ -252,8 +252,7 @@ int lio_wait_for_instr_fetch(struct octeon_device *oct) if (!(oct->io_qmask.iq & BIT_ULL(i))) continue; pending = - atomic_read(&oct-> - instr_queue[i]->instr_pending); + atomic_read(&oct->instr_queue[i]->instr_pending); if (pending) __check_db_timeout(oct, i); instr_cnt += pending; -- cgit v1.2.3 From d0a65400eba812e86aa5676524dad09af3292f5a Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Wed, 31 May 2017 15:43:30 -0400 Subject: net: phy: use of_mdio_parse_addr use of_mdio_parse_addr() in place of an OF read of reg and a bounds check (which is litterally the exact same thing that of_mdio_parse_addr() does) Signed-off-by: Jon Mason Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 8e73f5f36e71..d4782e902e2e 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -263,21 +263,10 @@ static void of_mdiobus_link_mdiodev(struct mii_bus *bus, for_each_available_child_of_node(bus->dev.of_node, child) { int addr; - int ret; - ret = of_property_read_u32(child, "reg", &addr); - if (ret < 0) { - dev_err(dev, "%s has invalid MDIO address\n", - child->full_name); + addr = of_mdio_parse_addr(dev, child); + if (addr < 0) continue; - } - - /* A MDIO device must have a reg property in the range [0-31] */ - if (addr >= PHY_MAX_ADDR) { - dev_err(dev, "%s MDIO address %i is too large\n", - child->full_name, addr); - continue; - } if (addr == mdiodev->addr) { dev->of_node = child; -- cgit v1.2.3 From e77834ec0a3dcb1b4976f64efc7078ae84ec76db Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 1 Jun 2017 21:37:39 +0300 Subject: net/mlx5e: Offload TC matching on tcp flags Enable offloading of TC matching on tcp flags. Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 7914a32a3036..066045b5eb4c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -581,7 +581,8 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | - BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL))) { + BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | + BIT(FLOW_DISSECTOR_KEY_TCP))) { netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n", f->dissector->used_keys); return -EOPNOTSUPP; @@ -808,6 +809,25 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, *min_inline = MLX5_INLINE_MODE_TCP_UDP; } + if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP)) { + struct flow_dissector_key_tcp *key = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_TCP, + f->key); + struct flow_dissector_key_tcp *mask = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_TCP, + f->mask); + + MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_flags, + ntohs(mask->flags)); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags, + ntohs(key->flags)); + + if (mask->flags) + *min_inline = MLX5_INLINE_MODE_TCP_UDP; + } + return 0; } -- cgit v1.2.3 From fd7da28b280d0c8b94417e85e49fea3db1ba7965 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 1 Jun 2017 21:37:40 +0300 Subject: net/mlx5e: Offload TC matching on ip tos / traffic-class Enable offloading of TC matching on ipv4 tos or ipv6 traffic-class. Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 26 ++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 066045b5eb4c..8ec13f9be660 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -582,7 +582,8 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | - BIT(FLOW_DISSECTOR_KEY_TCP))) { + BIT(FLOW_DISSECTOR_KEY_TCP) | + BIT(FLOW_DISSECTOR_KEY_IP))) { netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n", f->dissector->used_keys); return -EOPNOTSUPP; @@ -809,6 +810,29 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, *min_inline = MLX5_INLINE_MODE_TCP_UDP; } + if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IP)) { + struct flow_dissector_key_ip *key = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_IP, + f->key); + struct flow_dissector_key_ip *mask = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_IP, + f->mask); + + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn, mask->tos & 0x3); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, key->tos & 0x3); + + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp, mask->tos >> 2); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, key->tos >> 2); + + if (mask->tos) + *min_inline = MLX5_INLINE_MODE_IP; + + if (mask->ttl) /* currently not supported */ + return -EOPNOTSUPP; + } + if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP)) { struct flow_dissector_key_tcp *key = skb_flow_dissector_target(f->dissector, -- cgit v1.2.3 From 342fa1964439511268265be44b3e08825bbe4d05 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Wed, 31 May 2017 15:44:50 -0400 Subject: mdio: mux: make child bus walking more permissive and errors more verbose If any errors are encountered while walking the device tree structure of the MDIO bus for children, the code may silently continue, silently exit, or throw an error and exit. This make it difficult for device tree writers to know there is an error. Also, it makes any error in a child entry of the MDIO bus be fatal for all entries. Instead, we should provide verbose errors describing the error and then attempt to continue if it all possible. Also, use of_mdio_parse_addr() Signed-off-by: Jon Mason Signed-off-by: David S. Miller --- drivers/net/phy/mdio-mux.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 599ce24c514f..47ded3904050 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c @@ -135,27 +135,33 @@ int mdio_mux_init(struct device *dev, for_each_available_child_of_node(dev->of_node, child_bus_node) { u32 v; - r = of_property_read_u32(child_bus_node, "reg", &v); - if (r) + v = of_mdio_parse_addr(dev, child_bus_node); + if (v < 0) { + dev_err(dev, + "Error: Failed to find reg for child %s\n", + of_node_full_name(child_bus_node)); continue; + } cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL); if (cb == NULL) { dev_err(dev, - "Error: Failed to allocate memory for child\n"); + "Error: Failed to allocate memory for child %s\n", + of_node_full_name(child_bus_node)); ret_val = -ENOMEM; - of_node_put(child_bus_node); - break; + continue; } cb->bus_number = v; cb->parent = pb; cb->mii_bus = mdiobus_alloc(); if (!cb->mii_bus) { + dev_err(dev, + "Error: Failed to allocate MDIO bus for child %s\n", + of_node_full_name(child_bus_node)); ret_val = -ENOMEM; devm_kfree(dev, cb); - of_node_put(child_bus_node); - break; + continue; } cb->mii_bus->priv = cb; @@ -167,6 +173,9 @@ int mdio_mux_init(struct device *dev, cb->mii_bus->write = mdio_mux_write; r = of_mdiobus_register(cb->mii_bus, child_bus_node); if (r) { + dev_err(dev, + "Error: Failed to register MDIO bus for child %s\n", + of_node_full_name(child_bus_node)); mdiobus_free(cb->mii_bus); devm_kfree(dev, cb); } else { @@ -180,6 +189,7 @@ int mdio_mux_init(struct device *dev, return 0; } + dev_err(dev, "Error: No acceptable child buses found\n"); devm_kfree(dev, pb); err_pb_kz: /* balance the reference of_mdio_find_bus() took */ -- cgit v1.2.3 From a5eb62f3cb39fdd32e86d4b722e5b44c38e08890 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Fri, 2 Jun 2017 13:36:27 +0200 Subject: netxen: remove writeq/readq function definitions Instead of rewriting write/readq, use linux/io-64-nonatomic-lo-hi.h which already have them. Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c index a996801d442d..66ff15d08bad 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hw.c @@ -21,6 +21,7 @@ * */ +#include #include #include "netxen_nic.h" #include "netxen_nic_hw.h" @@ -44,20 +45,6 @@ static void netxen_nic_io_write_128M(struct netxen_adapter *adapter, void __iomem *addr, u32 data); static u32 netxen_nic_io_read_128M(struct netxen_adapter *adapter, void __iomem *addr); -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel(((u32) (val)), (addr)); - writel(((u32) (val >> 32)), (addr + 4)); -} -#endif #define PCI_OFFSET_FIRST_RANGE(adapter, off) \ ((adapter)->ahw.pci_base0 + (off)) -- cgit v1.2.3 From f0a4581605802cc136f68cfcf325035054fa92a3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 2 Jun 2017 15:13:34 +0100 Subject: net: phy: marvell: make some functions static functions m88e1510_get_temp_critical, m88e1510_set_temp_critical and m88e1510_get_temp_alarm can be made static as they not need to be in global scope. Cleans up sparse warnings: "symbol 'm88e1510_get_temp_alarm' was not declared. Should it be static?" "symbol 'm88e1510_get_temp_critical' was not declared. Should it be static?" Signed-off-by: Colin Ian King Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 1a72bebc588a..4c5246fed69b 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1706,7 +1706,7 @@ error: return ret; } -int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) +static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) { int oldpage; int ret; @@ -1737,7 +1737,7 @@ error: return ret; } -int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) +static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) { int oldpage; int ret; @@ -1767,7 +1767,7 @@ error: return ret; } -int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) +static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) { int oldpage; int ret; -- cgit v1.2.3 From 4d5f2ba77801c9ce81dc7a7b32de2d6aa63fbe93 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 2 Jun 2017 17:06:15 -0400 Subject: net: dsa: mv88e6xxx: rename chip header The mv88e6xxx.h is meant to contains the chip structures and data. Rename it to chip.h, as for other source/header pairs of the driver. At the same time, ensure that relative header inclusions are separated by a newline and sorted alphabetically. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- drivers/net/dsa/mv88e6xxx/chip.h | 928 ++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/global1.c | 2 +- drivers/net/dsa/mv88e6xxx/global1.h | 2 +- drivers/net/dsa/mv88e6xxx/global1_atu.c | 2 +- drivers/net/dsa/mv88e6xxx/global1_vtu.c | 2 +- drivers/net/dsa/mv88e6xxx/global2.c | 3 +- drivers/net/dsa/mv88e6xxx/global2.h | 2 +- drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 927 ------------------------------- drivers/net/dsa/mv88e6xxx/phy.c | 2 +- drivers/net/dsa/mv88e6xxx/port.c | 3 +- drivers/net/dsa/mv88e6xxx/port.h | 2 +- drivers/net/dsa/mv88e6xxx/serdes.c | 2 +- drivers/net/dsa/mv88e6xxx/serdes.h | 2 +- 14 files changed, 942 insertions(+), 939 deletions(-) create mode 100644 drivers/net/dsa/mv88e6xxx/chip.h delete mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx.h (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 7cf470c3e662..0176254cb3c7 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -33,7 +33,7 @@ #include #include -#include "mv88e6xxx.h" +#include "chip.h" #include "global1.h" #include "global2.h" #include "phy.h" diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h new file mode 100644 index 000000000000..ae7aed533aa5 --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -0,0 +1,928 @@ +/* + * Marvell 88E6xxx Ethernet switch single-chip definition + * + * Copyright (c) 2008 Marvell Semiconductor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _MV88E6XXX_CHIP_H +#define _MV88E6XXX_CHIP_H + +#include +#include +#include +#include +#include + +#ifndef UINT64_MAX +#define UINT64_MAX (u64)(~((u64)0)) +#endif + +#define SMI_CMD 0x00 +#define SMI_CMD_BUSY BIT(15) +#define SMI_CMD_CLAUSE_22 BIT(12) +#define SMI_CMD_OP_22_WRITE ((1 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) +#define SMI_CMD_OP_22_READ ((2 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) +#define SMI_CMD_OP_45_WRITE_ADDR ((0 << 10) | SMI_CMD_BUSY) +#define SMI_CMD_OP_45_WRITE_DATA ((1 << 10) | SMI_CMD_BUSY) +#define SMI_CMD_OP_45_READ_DATA ((2 << 10) | SMI_CMD_BUSY) +#define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) +#define SMI_DATA 0x01 + +/* PHY Registers */ +#define PHY_PAGE 0x16 +#define PHY_PAGE_COPPER 0x00 + +#define PORT_STATUS 0x00 +#define PORT_STATUS_PAUSE_EN BIT(15) +#define PORT_STATUS_MY_PAUSE BIT(14) +#define PORT_STATUS_HD_FLOW BIT(13) +#define PORT_STATUS_PHY_DETECT BIT(12) +#define PORT_STATUS_LINK BIT(11) +#define PORT_STATUS_DUPLEX BIT(10) +#define PORT_STATUS_SPEED_MASK 0x0300 +#define PORT_STATUS_SPEED_10 0x0000 +#define PORT_STATUS_SPEED_100 0x0100 +#define PORT_STATUS_SPEED_1000 0x0200 +#define PORT_STATUS_EEE BIT(6) /* 6352 */ +#define PORT_STATUS_AM_DIS BIT(6) /* 6165 */ +#define PORT_STATUS_MGMII BIT(6) /* 6185 */ +#define PORT_STATUS_TX_PAUSED BIT(5) +#define PORT_STATUS_FLOW_CTRL BIT(4) +#define PORT_STATUS_CMODE_MASK 0x0f +#define PORT_STATUS_CMODE_100BASE_X 0x8 +#define PORT_STATUS_CMODE_1000BASE_X 0x9 +#define PORT_STATUS_CMODE_SGMII 0xa +#define PORT_STATUS_CMODE_2500BASEX 0xb +#define PORT_STATUS_CMODE_XAUI 0xc +#define PORT_STATUS_CMODE_RXAUI 0xd +#define PORT_PCS_CTRL 0x01 +#define PORT_PCS_CTRL_RGMII_DELAY_RXCLK BIT(15) +#define PORT_PCS_CTRL_RGMII_DELAY_TXCLK BIT(14) +#define PORT_PCS_CTRL_FORCE_SPEED BIT(13) /* 6390 */ +#define PORT_PCS_CTRL_ALTSPEED BIT(12) /* 6390 */ +#define PORT_PCS_CTRL_200BASE BIT(12) /* 6352 */ +#define PORT_PCS_CTRL_FC BIT(7) +#define PORT_PCS_CTRL_FORCE_FC BIT(6) +#define PORT_PCS_CTRL_LINK_UP BIT(5) +#define PORT_PCS_CTRL_FORCE_LINK BIT(4) +#define PORT_PCS_CTRL_DUPLEX_FULL BIT(3) +#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2) +#define PORT_PCS_CTRL_SPEED_MASK (0x03) +#define PORT_PCS_CTRL_SPEED_10 (0x00) +#define PORT_PCS_CTRL_SPEED_100 (0x01) +#define PORT_PCS_CTRL_SPEED_200 (0x02) /* 6065 and non Gb chips */ +#define PORT_PCS_CTRL_SPEED_1000 (0x02) +#define PORT_PCS_CTRL_SPEED_10000 (0x03) /* 6390X */ +#define PORT_PCS_CTRL_SPEED_UNFORCED (0x03) +#define PORT_PAUSE_CTRL 0x02 +#define PORT_FLOW_CTRL_LIMIT_IN ((0x00 << 8) | BIT(15)) +#define PORT_FLOW_CTRL_LIMIT_OUT ((0x01 << 8) | BIT(15)) +#define PORT_SWITCH_ID 0x03 +#define PORT_SWITCH_ID_PROD_NUM_6085 0x04a +#define PORT_SWITCH_ID_PROD_NUM_6095 0x095 +#define PORT_SWITCH_ID_PROD_NUM_6097 0x099 +#define PORT_SWITCH_ID_PROD_NUM_6131 0x106 +#define PORT_SWITCH_ID_PROD_NUM_6320 0x115 +#define PORT_SWITCH_ID_PROD_NUM_6123 0x121 +#define PORT_SWITCH_ID_PROD_NUM_6141 0x340 +#define PORT_SWITCH_ID_PROD_NUM_6161 0x161 +#define PORT_SWITCH_ID_PROD_NUM_6165 0x165 +#define PORT_SWITCH_ID_PROD_NUM_6171 0x171 +#define PORT_SWITCH_ID_PROD_NUM_6172 0x172 +#define PORT_SWITCH_ID_PROD_NUM_6175 0x175 +#define PORT_SWITCH_ID_PROD_NUM_6176 0x176 +#define PORT_SWITCH_ID_PROD_NUM_6185 0x1a7 +#define PORT_SWITCH_ID_PROD_NUM_6190 0x190 +#define PORT_SWITCH_ID_PROD_NUM_6190X 0x0a0 +#define PORT_SWITCH_ID_PROD_NUM_6191 0x191 +#define PORT_SWITCH_ID_PROD_NUM_6240 0x240 +#define PORT_SWITCH_ID_PROD_NUM_6290 0x290 +#define PORT_SWITCH_ID_PROD_NUM_6321 0x310 +#define PORT_SWITCH_ID_PROD_NUM_6341 0x341 +#define PORT_SWITCH_ID_PROD_NUM_6352 0x352 +#define PORT_SWITCH_ID_PROD_NUM_6350 0x371 +#define PORT_SWITCH_ID_PROD_NUM_6351 0x375 +#define PORT_SWITCH_ID_PROD_NUM_6390 0x390 +#define PORT_SWITCH_ID_PROD_NUM_6390X 0x0a1 +#define PORT_CONTROL 0x04 +#define PORT_CONTROL_USE_CORE_TAG BIT(15) +#define PORT_CONTROL_DROP_ON_LOCK BIT(14) +#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12) +#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12) +#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12) +#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12) +#define PORT_CONTROL_EGRESS_MASK (0x3 << 12) +#define PORT_CONTROL_HEADER BIT(11) +#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10) +#define PORT_CONTROL_DOUBLE_TAG BIT(9) +#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8) +#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8) +#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8) +#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8) +#define PORT_CONTROL_FRAME_MASK (0x3 << 8) +#define PORT_CONTROL_DSA_TAG BIT(8) +#define PORT_CONTROL_VLAN_TUNNEL BIT(7) +#define PORT_CONTROL_TAG_IF_BOTH BIT(6) +#define PORT_CONTROL_USE_IP BIT(5) +#define PORT_CONTROL_USE_TAG BIT(4) +#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2) +#define PORT_CONTROL_EGRESS_FLOODS_MASK (0x3 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA (0x0 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA (0x1 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA (0x2 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA (0x3 << 2) +#define PORT_CONTROL_STATE_MASK 0x03 +#define PORT_CONTROL_STATE_DISABLED 0x00 +#define PORT_CONTROL_STATE_BLOCKING 0x01 +#define PORT_CONTROL_STATE_LEARNING 0x02 +#define PORT_CONTROL_STATE_FORWARDING 0x03 +#define PORT_CONTROL_1 0x05 +#define PORT_CONTROL_1_MESSAGE_PORT BIT(15) +#define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) +#define PORT_BASE_VLAN 0x06 +#define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12) +#define PORT_DEFAULT_VLAN 0x07 +#define PORT_DEFAULT_VLAN_MASK 0xfff +#define PORT_CONTROL_2 0x08 +#define PORT_CONTROL_2_IGNORE_FCS BIT(15) +#define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14) +#define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13) +#define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12) +#define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12) +#define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12) +#define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12) +#define PORT_CONTROL_2_8021Q_MASK (0x03 << 10) +#define PORT_CONTROL_2_8021Q_DISABLED (0x00 << 10) +#define PORT_CONTROL_2_8021Q_FALLBACK (0x01 << 10) +#define PORT_CONTROL_2_8021Q_CHECK (0x02 << 10) +#define PORT_CONTROL_2_8021Q_SECURE (0x03 << 10) +#define PORT_CONTROL_2_DISCARD_TAGGED BIT(9) +#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8) +#define PORT_CONTROL_2_MAP_DA BIT(7) +#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6) +#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5) +#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4) +#define PORT_CONTROL_2_UPSTREAM_MASK 0x0f +#define PORT_RATE_CONTROL 0x09 +#define PORT_RATE_CONTROL_2 0x0a +#define PORT_ASSOC_VECTOR 0x0b +#define PORT_ASSOC_VECTOR_HOLD_AT_1 BIT(15) +#define PORT_ASSOC_VECTOR_INT_AGE_OUT BIT(14) +#define PORT_ASSOC_VECTOR_LOCKED_PORT BIT(13) +#define PORT_ASSOC_VECTOR_IGNORE_WRONG BIT(12) +#define PORT_ASSOC_VECTOR_REFRESH_LOCKED BIT(11) +#define PORT_ATU_CONTROL 0x0c +#define PORT_PRI_OVERRIDE 0x0d +#define PORT_ETH_TYPE 0x0f +#define PORT_ETH_TYPE_DEFAULT 0x9100 +#define PORT_IN_DISCARD_LO 0x10 +#define PORT_IN_DISCARD_HI 0x11 +#define PORT_IN_FILTERED 0x12 +#define PORT_OUT_FILTERED 0x13 +#define PORT_TAG_REGMAP_0123 0x18 +#define PORT_TAG_REGMAP_4567 0x19 +#define PORT_IEEE_PRIO_MAP_TABLE 0x18 /* 6390 */ +#define PORT_IEEE_PRIO_MAP_TABLE_UPDATE BIT(15) +#define PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP (0x0 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP (0x1 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP (0x2 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP (0x3 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP (0x5 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP (0x6 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP (0x7 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9 + +#define GLOBAL_STATUS 0x00 +#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ +#define GLOBAL_STATUS_PPU_STATE_MASK (0x3 << 14) /* 6165 6185 */ +#define GLOBAL_STATUS_PPU_STATE_DISABLED_RST (0x0 << 14) +#define GLOBAL_STATUS_PPU_STATE_INITIALIZING (0x1 << 14) +#define GLOBAL_STATUS_PPU_STATE_DISABLED (0x2 << 14) +#define GLOBAL_STATUS_PPU_STATE_POLLING (0x3 << 14) +#define GLOBAL_STATUS_INIT_READY BIT(11) +#define GLOBAL_STATUS_IRQ_AVB 8 +#define GLOBAL_STATUS_IRQ_DEVICE 7 +#define GLOBAL_STATUS_IRQ_STATS 6 +#define GLOBAL_STATUS_IRQ_VTU_PROBLEM 5 +#define GLOBAL_STATUS_IRQ_VTU_DONE 4 +#define GLOBAL_STATUS_IRQ_ATU_PROBLEM 3 +#define GLOBAL_STATUS_IRQ_ATU_DONE 2 +#define GLOBAL_STATUS_IRQ_TCAM_DONE 1 +#define GLOBAL_STATUS_IRQ_EEPROM_DONE 0 +#define GLOBAL_MAC_01 0x01 +#define GLOBAL_MAC_23 0x02 +#define GLOBAL_MAC_45 0x03 +#define GLOBAL_ATU_FID 0x01 +#define GLOBAL_VTU_FID 0x02 +#define GLOBAL_VTU_FID_MASK 0xfff +#define GLOBAL_VTU_SID 0x03 /* 6097 6165 6351 6352 */ +#define GLOBAL_VTU_SID_MASK 0x3f +#define GLOBAL_CONTROL 0x04 +#define GLOBAL_CONTROL_SW_RESET BIT(15) +#define GLOBAL_CONTROL_PPU_ENABLE BIT(14) +#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */ +#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */ +#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */ +#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */ +#define GLOBAL_CONTROL_DEVICE_EN BIT(7) +#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6) +#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5) +#define GLOBAL_CONTROL_VTU_DONE_EN BIT(4) +#define GLOBAL_CONTROL_ATU_PROBLEM_EN BIT(3) +#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) +#define GLOBAL_CONTROL_TCAM_EN BIT(1) +#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) +#define GLOBAL_VTU_OP 0x05 +#define GLOBAL_VTU_OP_BUSY BIT(15) +#define GLOBAL_VTU_OP_FLUSH_ALL ((0x01 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_VTU_LOAD_PURGE ((0x03 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_VTU_GET_NEXT ((0x04 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_STU_LOAD_PURGE ((0x05 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_STU_GET_NEXT ((0x06 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_VID 0x06 +#define GLOBAL_VTU_VID_MASK 0xfff +#define GLOBAL_VTU_VID_PAGE BIT(13) +#define GLOBAL_VTU_VID_VALID BIT(12) +#define GLOBAL_VTU_DATA_0_3 0x07 +#define GLOBAL_VTU_DATA_4_7 0x08 +#define GLOBAL_VTU_DATA_8_11 0x09 +#define GLOBAL_VTU_STU_DATA_MASK 0x03 +#define GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED 0x00 +#define GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED 0x01 +#define GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED 0x02 +#define GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER 0x03 +#define GLOBAL_STU_DATA_PORT_STATE_DISABLED 0x00 +#define GLOBAL_STU_DATA_PORT_STATE_BLOCKING 0x01 +#define GLOBAL_STU_DATA_PORT_STATE_LEARNING 0x02 +#define GLOBAL_STU_DATA_PORT_STATE_FORWARDING 0x03 +#define GLOBAL_ATU_CONTROL 0x0a +#define GLOBAL_ATU_CONTROL_LEARN2ALL BIT(3) +#define GLOBAL_ATU_OP 0x0b +#define GLOBAL_ATU_OP_BUSY BIT(15) +#define GLOBAL_ATU_OP_NOP (0 << 12) +#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC ((2 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_DATA 0x0c +#define GLOBAL_ATU_DATA_TRUNK BIT(15) +#define GLOBAL_ATU_DATA_TRUNK_ID_MASK 0x00f0 +#define GLOBAL_ATU_DATA_TRUNK_ID_SHIFT 4 +#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 +#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4 +#define GLOBAL_ATU_DATA_STATE_MASK 0x0f +#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 +#define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d +#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e +#define GLOBAL_ATU_DATA_STATE_UC_PRIO_OVER 0x0f +#define GLOBAL_ATU_DATA_STATE_MC_NONE_RATE 0x05 +#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 +#define GLOBAL_ATU_DATA_STATE_MC_MGMT 0x0e +#define GLOBAL_ATU_DATA_STATE_MC_PRIO_OVER 0x0f +#define GLOBAL_ATU_MAC_01 0x0d +#define GLOBAL_ATU_MAC_23 0x0e +#define GLOBAL_ATU_MAC_45 0x0f +#define GLOBAL_IP_PRI_0 0x10 +#define GLOBAL_IP_PRI_1 0x11 +#define GLOBAL_IP_PRI_2 0x12 +#define GLOBAL_IP_PRI_3 0x13 +#define GLOBAL_IP_PRI_4 0x14 +#define GLOBAL_IP_PRI_5 0x15 +#define GLOBAL_IP_PRI_6 0x16 +#define GLOBAL_IP_PRI_7 0x17 +#define GLOBAL_IEEE_PRI 0x18 +#define GLOBAL_CORE_TAG_TYPE 0x19 +#define GLOBAL_MONITOR_CONTROL 0x1a +#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12 +#define GLOBAL_MONITOR_CONTROL_INGRESS_MASK (0xf << 12) +#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8 +#define GLOBAL_MONITOR_CONTROL_EGRESS_MASK (0xf << 8) +#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4 +#define GLOBAL_MONITOR_CONTROL_ARP_MASK (0xf << 4) +#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0 +#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0) +#define GLOBAL_MONITOR_CONTROL_UPDATE BIT(15) +#define GLOBAL_MONITOR_CONTROL_0180C280000000XLO (0x00 << 8) +#define GLOBAL_MONITOR_CONTROL_0180C280000000XHI (0x01 << 8) +#define GLOBAL_MONITOR_CONTROL_0180C280000002XLO (0x02 << 8) +#define GLOBAL_MONITOR_CONTROL_0180C280000002XHI (0x03 << 8) +#define GLOBAL_MONITOR_CONTROL_INGRESS (0x20 << 8) +#define GLOBAL_MONITOR_CONTROL_EGRESS (0x21 << 8) +#define GLOBAL_MONITOR_CONTROL_CPU_DEST (0x30 << 8) +#define GLOBAL_CONTROL_2 0x1c +#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000 +#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000 +#define GLOBAL_CONTROL_2_HIST_RX (0x1 << 6) +#define GLOBAL_CONTROL_2_HIST_TX (0x2 << 6) +#define GLOBAL_CONTROL_2_HIST_RX_TX (0x3 << 6) +#define GLOBAL_STATS_OP 0x1d +#define GLOBAL_STATS_OP_BUSY BIT(15) +#define GLOBAL_STATS_OP_NOP (0 << 12) +#define GLOBAL_STATS_OP_FLUSH_ALL ((1 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_FLUSH_PORT ((2 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_READ_CAPTURED ((4 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_CAPTURE_PORT ((5 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_BANK_1_BIT_9 BIT(9) +#define GLOBAL_STATS_OP_BANK_1_BIT_10 BIT(10) +#define GLOBAL_STATS_COUNTER_32 0x1e +#define GLOBAL_STATS_COUNTER_01 0x1f + +#define GLOBAL2_INT_SOURCE 0x00 +#define GLOBAL2_INT_SOURCE_WATCHDOG 15 +#define GLOBAL2_INT_MASK 0x01 +#define GLOBAL2_MGMT_EN_2X 0x02 +#define GLOBAL2_MGMT_EN_0X 0x03 +#define GLOBAL2_FLOW_CONTROL 0x04 +#define GLOBAL2_SWITCH_MGMT 0x05 +#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA BIT(15) +#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS BIT(14) +#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13) +#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7) +#define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3) +#define GLOBAL2_DEVICE_MAPPING 0x06 +#define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15) +#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8 +#define GLOBAL2_DEVICE_MAPPING_PORT_MASK 0x0f +#define GLOBAL2_TRUNK_MASK 0x07 +#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15) +#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12 +#define GLOBAL2_TRUNK_MASK_HASK BIT(11) +#define GLOBAL2_TRUNK_MAPPING 0x08 +#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) +#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 +#define GLOBAL2_IRL_CMD 0x09 +#define GLOBAL2_IRL_CMD_BUSY BIT(15) +#define GLOBAL2_IRL_CMD_OP_INIT_ALL ((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_INIT_SEL ((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_WRITE_SEL ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_READ_SEL ((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_DATA 0x0a +#define GLOBAL2_PVT_ADDR 0x0b +#define GLOBAL2_PVT_ADDR_BUSY BIT(15) +#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_DATA 0x0c +#define GLOBAL2_SWITCH_MAC 0x0d +#define GLOBAL2_ATU_STATS 0x0e +#define GLOBAL2_PRIO_OVERRIDE 0x0f +#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7) +#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 +#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) +#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 +#define GLOBAL2_EEPROM_CMD 0x14 +#define GLOBAL2_EEPROM_CMD_BUSY BIT(15) +#define GLOBAL2_EEPROM_CMD_OP_WRITE ((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY) +#define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY) +#define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY) +#define GLOBAL2_EEPROM_CMD_RUNNING BIT(11) +#define GLOBAL2_EEPROM_CMD_WRITE_EN BIT(10) +#define GLOBAL2_EEPROM_CMD_ADDR_MASK 0xff +#define GLOBAL2_EEPROM_DATA 0x15 +#define GLOBAL2_EEPROM_ADDR 0x15 /* 6390, 6341 */ +#define GLOBAL2_PTP_AVB_OP 0x16 +#define GLOBAL2_PTP_AVB_DATA 0x17 +#define GLOBAL2_SMI_PHY_CMD 0x18 +#define GLOBAL2_SMI_PHY_CMD_BUSY BIT(15) +#define GLOBAL2_SMI_PHY_CMD_EXTERNAL BIT(13) +#define GLOBAL2_SMI_PHY_CMD_MODE_22 BIT(12) +#define GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA ((0x1 << 10) | \ + GLOBAL2_SMI_PHY_CMD_MODE_22 | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA ((0x2 << 10) | \ + GLOBAL2_SMI_PHY_CMD_MODE_22 | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_ADDR ((0x0 << 10) | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_DATA ((0x1 << 10) | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_45_READ_DATA ((0x3 << 10) | \ + GLOBAL2_SMI_PHY_CMD_BUSY) + +#define GLOBAL2_SMI_PHY_DATA 0x19 +#define GLOBAL2_SCRATCH_MISC 0x1a +#define GLOBAL2_SCRATCH_BUSY BIT(15) +#define GLOBAL2_SCRATCH_REGISTER_SHIFT 8 +#define GLOBAL2_SCRATCH_VALUE_MASK 0xff +#define GLOBAL2_WDOG_CONTROL 0x1b +#define GLOBAL2_WDOG_CONTROL_EGRESS_EVENT BIT(7) +#define GLOBAL2_WDOG_CONTROL_RMU_TIMEOUT BIT(6) +#define GLOBAL2_WDOG_CONTROL_QC_ENABLE BIT(5) +#define GLOBAL2_WDOG_CONTROL_EGRESS_HISTORY BIT(4) +#define GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE BIT(3) +#define GLOBAL2_WDOG_CONTROL_FORCE_IRQ BIT(2) +#define GLOBAL2_WDOG_CONTROL_HISTORY BIT(1) +#define GLOBAL2_WDOG_CONTROL_SWRESET BIT(0) +#define GLOBAL2_WDOG_UPDATE BIT(15) +#define GLOBAL2_WDOG_INT_SOURCE (0x00 << 8) +#define GLOBAL2_WDOG_INT_STATUS (0x10 << 8) +#define GLOBAL2_WDOG_INT_ENABLE (0x11 << 8) +#define GLOBAL2_WDOG_EVENT (0x12 << 8) +#define GLOBAL2_WDOG_HISTORY (0x13 << 8) +#define GLOBAL2_WDOG_DATA_MASK 0xff +#define GLOBAL2_WDOG_CUT_THROUGH BIT(3) +#define GLOBAL2_WDOG_QUEUE_CONTROLLER BIT(2) +#define GLOBAL2_WDOG_EGRESS BIT(1) +#define GLOBAL2_WDOG_FORCE_IRQ BIT(0) +#define GLOBAL2_QOS_WEIGHT 0x1c +#define GLOBAL2_MISC 0x1d +#define GLOBAL2_MISC_5_BIT_PORT BIT(14) + +#define MV88E6XXX_N_FID 4096 + +/* PVT limits for 4-bit port and 5-bit switch */ +#define MV88E6XXX_MAX_PVT_SWITCHES 32 +#define MV88E6XXX_MAX_PVT_PORTS 16 + +enum mv88e6xxx_frame_mode { + MV88E6XXX_FRAME_MODE_NORMAL, + MV88E6XXX_FRAME_MODE_DSA, + MV88E6XXX_FRAME_MODE_PROVIDER, + MV88E6XXX_FRAME_MODE_ETHERTYPE, +}; + +/* List of supported models */ +enum mv88e6xxx_model { + MV88E6085, + MV88E6095, + MV88E6097, + MV88E6123, + MV88E6131, + MV88E6141, + MV88E6161, + MV88E6165, + MV88E6171, + MV88E6172, + MV88E6175, + MV88E6176, + MV88E6185, + MV88E6190, + MV88E6190X, + MV88E6191, + MV88E6240, + MV88E6290, + MV88E6320, + MV88E6321, + MV88E6341, + MV88E6350, + MV88E6351, + MV88E6352, + MV88E6390, + MV88E6390X, +}; + +enum mv88e6xxx_family { + MV88E6XXX_FAMILY_NONE, + MV88E6XXX_FAMILY_6065, /* 6031 6035 6061 6065 */ + MV88E6XXX_FAMILY_6095, /* 6092 6095 */ + MV88E6XXX_FAMILY_6097, /* 6046 6085 6096 6097 */ + MV88E6XXX_FAMILY_6165, /* 6123 6161 6165 */ + MV88E6XXX_FAMILY_6185, /* 6108 6121 6122 6131 6152 6155 6182 6185 */ + MV88E6XXX_FAMILY_6320, /* 6320 6321 */ + MV88E6XXX_FAMILY_6341, /* 6141 6341 */ + MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */ + MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */ + MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */ +}; + +enum mv88e6xxx_cap { + /* Energy Efficient Ethernet. + */ + MV88E6XXX_CAP_EEE, + + /* Multi-chip Addressing Mode. + * Some chips respond to only 2 registers of its own SMI device address + * when it is non-zero, and use indirect access to internal registers. + */ + MV88E6XXX_CAP_SMI_CMD, /* (0x00) SMI Command */ + MV88E6XXX_CAP_SMI_DATA, /* (0x01) SMI Data */ + + /* Switch Global (1) Registers. + */ + MV88E6XXX_CAP_G1_ATU_FID, /* (0x01) ATU FID Register */ + MV88E6XXX_CAP_G1_VTU_FID, /* (0x02) VTU FID Register */ + + /* Switch Global 2 Registers. + * The device contains a second set of global 16-bit registers. + */ + MV88E6XXX_CAP_GLOBAL2, + MV88E6XXX_CAP_G2_INT, /* (0x00) Interrupt Status */ + MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */ + MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */ + MV88E6XXX_CAP_G2_IRL_CMD, /* (0x09) Ingress Rate Command */ + MV88E6XXX_CAP_G2_IRL_DATA, /* (0x0a) Ingress Rate Data */ + MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */ + + /* Per VLAN Spanning Tree Unit (STU). + * The Port State database, if present, is accessed through VTU + * operations and dedicated SID registers. See GLOBAL_VTU_SID. + */ + MV88E6XXX_CAP_STU, + + /* VLAN Table Unit. + * The VTU is used to program 802.1Q VLANs. See GLOBAL_VTU_OP. + */ + MV88E6XXX_CAP_VTU, +}; + +/* Bitmask of capabilities */ +#define MV88E6XXX_FLAG_EEE BIT_ULL(MV88E6XXX_CAP_EEE) + +#define MV88E6XXX_FLAG_SMI_CMD BIT_ULL(MV88E6XXX_CAP_SMI_CMD) +#define MV88E6XXX_FLAG_SMI_DATA BIT_ULL(MV88E6XXX_CAP_SMI_DATA) + +#define MV88E6XXX_FLAG_G1_VTU_FID BIT_ULL(MV88E6XXX_CAP_G1_VTU_FID) + +#define MV88E6XXX_FLAG_GLOBAL2 BIT_ULL(MV88E6XXX_CAP_GLOBAL2) +#define MV88E6XXX_FLAG_G2_INT BIT_ULL(MV88E6XXX_CAP_G2_INT) +#define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_2X) +#define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_0X) +#define MV88E6XXX_FLAG_G2_IRL_CMD BIT_ULL(MV88E6XXX_CAP_G2_IRL_CMD) +#define MV88E6XXX_FLAG_G2_IRL_DATA BIT_ULL(MV88E6XXX_CAP_G2_IRL_DATA) +#define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT) + +/* Ingress Rate Limit unit */ +#define MV88E6XXX_FLAGS_IRL \ + (MV88E6XXX_FLAG_G2_IRL_CMD | \ + MV88E6XXX_FLAG_G2_IRL_DATA) + +/* Multi-chip Addressing Mode */ +#define MV88E6XXX_FLAGS_MULTI_CHIP \ + (MV88E6XXX_FLAG_SMI_CMD | \ + MV88E6XXX_FLAG_SMI_DATA) + +#define MV88E6XXX_FLAGS_FAMILY_6095 \ + (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6097 \ + (MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6165 \ + (MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6185 \ + (MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6320 \ + (MV88E6XXX_FLAG_EEE | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6341 \ + (MV88E6XXX_FLAG_EEE | \ + MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6351 \ + (MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6352 \ + (MV88E6XXX_FLAG_EEE | \ + MV88E6XXX_FLAG_G1_VTU_FID | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ + MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ + MV88E6XXX_FLAG_G2_POT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +#define MV88E6XXX_FLAGS_FAMILY_6390 \ + (MV88E6XXX_FLAG_EEE | \ + MV88E6XXX_FLAG_GLOBAL2 | \ + MV88E6XXX_FLAG_G2_INT | \ + MV88E6XXX_FLAGS_IRL | \ + MV88E6XXX_FLAGS_MULTI_CHIP) + +struct mv88e6xxx_ops; + +struct mv88e6xxx_info { + enum mv88e6xxx_family family; + u16 prod_num; + const char *name; + unsigned int num_databases; + unsigned int num_ports; + unsigned int max_vid; + unsigned int port_base_addr; + unsigned int global1_addr; + unsigned int age_time_coeff; + unsigned int g1_irqs; + bool pvt; + enum dsa_tag_protocol tag_protocol; + unsigned long long flags; + + /* Mask for FromPort and ToPort value of PortVec used in ATU Move + * operation. 0 means that the ATU Move operation is not supported. + */ + u8 atu_move_port_mask; + const struct mv88e6xxx_ops *ops; +}; + +struct mv88e6xxx_atu_entry { + u8 state; + bool trunk; + u16 portvec; + u8 mac[ETH_ALEN]; +}; + +struct mv88e6xxx_vtu_entry { + u16 vid; + u16 fid; + u8 sid; + bool valid; + u8 member[DSA_MAX_PORTS]; + u8 state[DSA_MAX_PORTS]; +}; + +struct mv88e6xxx_bus_ops; +struct mv88e6xxx_irq_ops; + +struct mv88e6xxx_irq { + u16 masked; + struct irq_chip chip; + struct irq_domain *domain; + unsigned int nirqs; +}; + +struct mv88e6xxx_chip { + const struct mv88e6xxx_info *info; + + /* The dsa_switch this private structure is related to */ + struct dsa_switch *ds; + + /* The device this structure is associated to */ + struct device *dev; + + /* This mutex protects the access to the switch registers */ + struct mutex reg_lock; + + /* The MII bus and the address on the bus that is used to + * communication with the switch + */ + const struct mv88e6xxx_bus_ops *smi_ops; + struct mii_bus *bus; + int sw_addr; + + /* Handles automatic disabling and re-enabling of the PHY + * polling unit. + */ + const struct mv88e6xxx_bus_ops *phy_ops; + struct mutex ppu_mutex; + int ppu_disabled; + struct work_struct ppu_work; + struct timer_list ppu_timer; + + /* This mutex serialises access to the statistics unit. + * Hold this mutex over snapshot + dump sequences. + */ + struct mutex stats_mutex; + + /* A switch may have a GPIO line tied to its reset pin. Parse + * this from the device tree, and use it before performing + * switch soft reset. + */ + struct gpio_desc *reset; + + /* set to size of eeprom if supported by the switch */ + int eeprom_len; + + /* List of mdio busses */ + struct list_head mdios; + + /* There can be two interrupt controllers, which are chained + * off a GPIO as interrupt source + */ + struct mv88e6xxx_irq g1_irq; + struct mv88e6xxx_irq g2_irq; + int irq; + int device_irq; + int watchdog_irq; +}; + +struct mv88e6xxx_bus_ops { + int (*read)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); + int (*write)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); +}; + +struct mv88e6xxx_mdio_bus { + struct mii_bus *bus; + struct mv88e6xxx_chip *chip; + struct list_head list; + bool external; +}; + +struct mv88e6xxx_ops { + int (*get_eeprom)(struct mv88e6xxx_chip *chip, + struct ethtool_eeprom *eeprom, u8 *data); + int (*set_eeprom)(struct mv88e6xxx_chip *chip, + struct ethtool_eeprom *eeprom, u8 *data); + + int (*set_switch_mac)(struct mv88e6xxx_chip *chip, u8 *addr); + + int (*phy_read)(struct mv88e6xxx_chip *chip, + struct mii_bus *bus, + int addr, int reg, u16 *val); + int (*phy_write)(struct mv88e6xxx_chip *chip, + struct mii_bus *bus, + int addr, int reg, u16 val); + + /* PHY Polling Unit (PPU) operations */ + int (*ppu_enable)(struct mv88e6xxx_chip *chip); + int (*ppu_disable)(struct mv88e6xxx_chip *chip); + + /* Switch Software Reset */ + int (*reset)(struct mv88e6xxx_chip *chip); + + /* RGMII Receive/Transmit Timing Control + * Add delay on PHY_INTERFACE_MODE_RGMII_*ID, no delay otherwise. + */ + int (*port_set_rgmii_delay)(struct mv88e6xxx_chip *chip, int port, + phy_interface_t mode); + +#define LINK_FORCED_DOWN 0 +#define LINK_FORCED_UP 1 +#define LINK_UNFORCED -2 + + /* Port's MAC link state + * Use LINK_FORCED_UP or LINK_FORCED_DOWN to force link up or down, + * or LINK_UNFORCED for normal link detection. + */ + int (*port_set_link)(struct mv88e6xxx_chip *chip, int port, int link); + +#define DUPLEX_UNFORCED -2 + + /* Port's MAC duplex mode + * + * Use DUPLEX_HALF or DUPLEX_FULL to force half or full duplex, + * or DUPLEX_UNFORCED for normal duplex detection. + */ + int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup); + +#define SPEED_MAX INT_MAX +#define SPEED_UNFORCED -2 + + /* Port's MAC speed (in Mbps) + * + * Depending on the chip, 10, 100, 200, 1000, 2500, 10000 are valid. + * Use SPEED_UNFORCED for normal detection, SPEED_MAX for max value. + */ + int (*port_set_speed)(struct mv88e6xxx_chip *chip, int port, int speed); + + int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port); + + int (*port_set_frame_mode)(struct mv88e6xxx_chip *chip, int port, + enum mv88e6xxx_frame_mode mode); + int (*port_set_egress_floods)(struct mv88e6xxx_chip *chip, int port, + bool unicast, bool multicast); + int (*port_set_ether_type)(struct mv88e6xxx_chip *chip, int port, + u16 etype); + int (*port_jumbo_config)(struct mv88e6xxx_chip *chip, int port); + + int (*port_egress_rate_limiting)(struct mv88e6xxx_chip *chip, int port); + int (*port_pause_config)(struct mv88e6xxx_chip *chip, int port); + int (*port_disable_learn_limit)(struct mv88e6xxx_chip *chip, int port); + int (*port_disable_pri_override)(struct mv88e6xxx_chip *chip, int port); + + /* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc. + * Some chips allow this to be configured on specific ports. + */ + int (*port_set_cmode)(struct mv88e6xxx_chip *chip, int port, + phy_interface_t mode); + + /* Some devices have a per port register indicating what is + * the upstream port this port should forward to. + */ + int (*port_set_upstream_port)(struct mv88e6xxx_chip *chip, int port, + int upstream_port); + + /* Snapshot the statistics for a port. The statistics can then + * be read back a leisure but still with a consistent view. + */ + int (*stats_snapshot)(struct mv88e6xxx_chip *chip, int port); + + /* Set the histogram mode for statistics, when the control registers + * are separated out of the STATS_OP register. + */ + int (*stats_set_histogram)(struct mv88e6xxx_chip *chip); + + /* Return the number of strings describing statistics */ + int (*stats_get_sset_count)(struct mv88e6xxx_chip *chip); + void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data); + void (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port, + uint64_t *data); + int (*g1_set_cpu_port)(struct mv88e6xxx_chip *chip, int port); + int (*g1_set_egress_port)(struct mv88e6xxx_chip *chip, int port); + const struct mv88e6xxx_irq_ops *watchdog_ops; + + /* Can be either in g1 or g2, so don't use a prefix */ + int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip); + + /* Power on/off a SERDES interface */ + int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on); + + /* VLAN Translation Unit operations */ + int (*vtu_getnext)(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); + int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry); +}; + +struct mv88e6xxx_irq_ops { + /* Action to be performed when the interrupt happens */ + int (*irq_action)(struct mv88e6xxx_chip *chip, int irq); + /* Setup the hardware to generate the interrupt */ + int (*irq_setup)(struct mv88e6xxx_chip *chip); + /* Reset the hardware to stop generating the interrupt */ + void (*irq_free)(struct mv88e6xxx_chip *chip); +}; + +#define STATS_TYPE_PORT BIT(0) +#define STATS_TYPE_BANK0 BIT(1) +#define STATS_TYPE_BANK1 BIT(2) + +struct mv88e6xxx_hw_stat { + char string[ETH_GSTRING_LEN]; + int sizeof_stat; + int reg; + int type; +}; + +static inline bool mv88e6xxx_has(struct mv88e6xxx_chip *chip, + unsigned long flags) +{ + return (chip->info->flags & flags) == flags; +} + +static inline bool mv88e6xxx_has_pvt(struct mv88e6xxx_chip *chip) +{ + return chip->info->pvt; +} + +static inline unsigned int mv88e6xxx_num_databases(struct mv88e6xxx_chip *chip) +{ + return chip->info->num_databases; +} + +static inline unsigned int mv88e6xxx_num_ports(struct mv88e6xxx_chip *chip) +{ + return chip->info->num_ports; +} + +static inline u16 mv88e6xxx_port_mask(struct mv88e6xxx_chip *chip) +{ + return GENMASK(mv88e6xxx_num_ports(chip) - 1, 0); +} + +int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); +int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); +int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, + u16 update); +int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask); +struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip); + +#endif /* _MV88E6XXX_CHIP_H */ diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 39825837a1c9..4081ff0d38a0 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -12,7 +12,7 @@ * (at your option) any later version. */ -#include "mv88e6xxx.h" +#include "chip.h" #include "global1.h" int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 46a4ea0f8c47..3b8f356b348c 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -15,7 +15,7 @@ #ifndef _MV88E6XXX_GLOBAL1_H #define _MV88E6XXX_GLOBAL1_H -#include "mv88e6xxx.h" +#include "chip.h" int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val); int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val); diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index fa7e7db5171b..6b0cf44dc07d 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -10,7 +10,7 @@ * (at your option) any later version. */ -#include "mv88e6xxx.h" +#include "chip.h" #include "global1.h" /* Offset 0x01: ATU FID Register */ diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c index 9aea22d4c9e2..bf593c7aaa9b 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c @@ -11,7 +11,7 @@ * (at your option) any later version. */ -#include "mv88e6xxx.h" +#include "chip.h" #include "global1.h" /* Offset 0x02: VTU FID Register */ diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index b3fea55071e3..0defce71e381 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -15,7 +15,8 @@ #include #include -#include "mv88e6xxx.h" + +#include "chip.h" #include "global2.h" #define ADDR_GLOBAL2 0x1c diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 96046bb12ca1..b5cfe041ee59 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -15,7 +15,7 @@ #ifndef _MV88E6XXX_GLOBAL2_H #define _MV88E6XXX_GLOBAL2_H -#include "mv88e6xxx.h" +#include "chip.h" #ifdef CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h deleted file mode 100644 index 9087cb009cc3..000000000000 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ /dev/null @@ -1,927 +0,0 @@ -/* - * Marvell 88e6xxx common definitions - * - * Copyright (c) 2008 Marvell Semiconductor - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __MV88E6XXX_H -#define __MV88E6XXX_H - -#include -#include -#include -#include -#include - -#ifndef UINT64_MAX -#define UINT64_MAX (u64)(~((u64)0)) -#endif - -#define SMI_CMD 0x00 -#define SMI_CMD_BUSY BIT(15) -#define SMI_CMD_CLAUSE_22 BIT(12) -#define SMI_CMD_OP_22_WRITE ((1 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) -#define SMI_CMD_OP_22_READ ((2 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) -#define SMI_CMD_OP_45_WRITE_ADDR ((0 << 10) | SMI_CMD_BUSY) -#define SMI_CMD_OP_45_WRITE_DATA ((1 << 10) | SMI_CMD_BUSY) -#define SMI_CMD_OP_45_READ_DATA ((2 << 10) | SMI_CMD_BUSY) -#define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) -#define SMI_DATA 0x01 - -/* PHY Registers */ -#define PHY_PAGE 0x16 -#define PHY_PAGE_COPPER 0x00 - -#define PORT_STATUS 0x00 -#define PORT_STATUS_PAUSE_EN BIT(15) -#define PORT_STATUS_MY_PAUSE BIT(14) -#define PORT_STATUS_HD_FLOW BIT(13) -#define PORT_STATUS_PHY_DETECT BIT(12) -#define PORT_STATUS_LINK BIT(11) -#define PORT_STATUS_DUPLEX BIT(10) -#define PORT_STATUS_SPEED_MASK 0x0300 -#define PORT_STATUS_SPEED_10 0x0000 -#define PORT_STATUS_SPEED_100 0x0100 -#define PORT_STATUS_SPEED_1000 0x0200 -#define PORT_STATUS_EEE BIT(6) /* 6352 */ -#define PORT_STATUS_AM_DIS BIT(6) /* 6165 */ -#define PORT_STATUS_MGMII BIT(6) /* 6185 */ -#define PORT_STATUS_TX_PAUSED BIT(5) -#define PORT_STATUS_FLOW_CTRL BIT(4) -#define PORT_STATUS_CMODE_MASK 0x0f -#define PORT_STATUS_CMODE_100BASE_X 0x8 -#define PORT_STATUS_CMODE_1000BASE_X 0x9 -#define PORT_STATUS_CMODE_SGMII 0xa -#define PORT_STATUS_CMODE_2500BASEX 0xb -#define PORT_STATUS_CMODE_XAUI 0xc -#define PORT_STATUS_CMODE_RXAUI 0xd -#define PORT_PCS_CTRL 0x01 -#define PORT_PCS_CTRL_RGMII_DELAY_RXCLK BIT(15) -#define PORT_PCS_CTRL_RGMII_DELAY_TXCLK BIT(14) -#define PORT_PCS_CTRL_FORCE_SPEED BIT(13) /* 6390 */ -#define PORT_PCS_CTRL_ALTSPEED BIT(12) /* 6390 */ -#define PORT_PCS_CTRL_200BASE BIT(12) /* 6352 */ -#define PORT_PCS_CTRL_FC BIT(7) -#define PORT_PCS_CTRL_FORCE_FC BIT(6) -#define PORT_PCS_CTRL_LINK_UP BIT(5) -#define PORT_PCS_CTRL_FORCE_LINK BIT(4) -#define PORT_PCS_CTRL_DUPLEX_FULL BIT(3) -#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2) -#define PORT_PCS_CTRL_SPEED_MASK (0x03) -#define PORT_PCS_CTRL_SPEED_10 (0x00) -#define PORT_PCS_CTRL_SPEED_100 (0x01) -#define PORT_PCS_CTRL_SPEED_200 (0x02) /* 6065 and non Gb chips */ -#define PORT_PCS_CTRL_SPEED_1000 (0x02) -#define PORT_PCS_CTRL_SPEED_10000 (0x03) /* 6390X */ -#define PORT_PCS_CTRL_SPEED_UNFORCED (0x03) -#define PORT_PAUSE_CTRL 0x02 -#define PORT_FLOW_CTRL_LIMIT_IN ((0x00 << 8) | BIT(15)) -#define PORT_FLOW_CTRL_LIMIT_OUT ((0x01 << 8) | BIT(15)) -#define PORT_SWITCH_ID 0x03 -#define PORT_SWITCH_ID_PROD_NUM_6085 0x04a -#define PORT_SWITCH_ID_PROD_NUM_6095 0x095 -#define PORT_SWITCH_ID_PROD_NUM_6097 0x099 -#define PORT_SWITCH_ID_PROD_NUM_6131 0x106 -#define PORT_SWITCH_ID_PROD_NUM_6320 0x115 -#define PORT_SWITCH_ID_PROD_NUM_6123 0x121 -#define PORT_SWITCH_ID_PROD_NUM_6141 0x340 -#define PORT_SWITCH_ID_PROD_NUM_6161 0x161 -#define PORT_SWITCH_ID_PROD_NUM_6165 0x165 -#define PORT_SWITCH_ID_PROD_NUM_6171 0x171 -#define PORT_SWITCH_ID_PROD_NUM_6172 0x172 -#define PORT_SWITCH_ID_PROD_NUM_6175 0x175 -#define PORT_SWITCH_ID_PROD_NUM_6176 0x176 -#define PORT_SWITCH_ID_PROD_NUM_6185 0x1a7 -#define PORT_SWITCH_ID_PROD_NUM_6190 0x190 -#define PORT_SWITCH_ID_PROD_NUM_6190X 0x0a0 -#define PORT_SWITCH_ID_PROD_NUM_6191 0x191 -#define PORT_SWITCH_ID_PROD_NUM_6240 0x240 -#define PORT_SWITCH_ID_PROD_NUM_6290 0x290 -#define PORT_SWITCH_ID_PROD_NUM_6321 0x310 -#define PORT_SWITCH_ID_PROD_NUM_6341 0x341 -#define PORT_SWITCH_ID_PROD_NUM_6352 0x352 -#define PORT_SWITCH_ID_PROD_NUM_6350 0x371 -#define PORT_SWITCH_ID_PROD_NUM_6351 0x375 -#define PORT_SWITCH_ID_PROD_NUM_6390 0x390 -#define PORT_SWITCH_ID_PROD_NUM_6390X 0x0a1 -#define PORT_CONTROL 0x04 -#define PORT_CONTROL_USE_CORE_TAG BIT(15) -#define PORT_CONTROL_DROP_ON_LOCK BIT(14) -#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12) -#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12) -#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12) -#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12) -#define PORT_CONTROL_EGRESS_MASK (0x3 << 12) -#define PORT_CONTROL_HEADER BIT(11) -#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10) -#define PORT_CONTROL_DOUBLE_TAG BIT(9) -#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8) -#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8) -#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8) -#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8) -#define PORT_CONTROL_FRAME_MASK (0x3 << 8) -#define PORT_CONTROL_DSA_TAG BIT(8) -#define PORT_CONTROL_VLAN_TUNNEL BIT(7) -#define PORT_CONTROL_TAG_IF_BOTH BIT(6) -#define PORT_CONTROL_USE_IP BIT(5) -#define PORT_CONTROL_USE_TAG BIT(4) -#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2) -#define PORT_CONTROL_EGRESS_FLOODS_MASK (0x3 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA (0x0 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA (0x1 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA (0x2 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA (0x3 << 2) -#define PORT_CONTROL_STATE_MASK 0x03 -#define PORT_CONTROL_STATE_DISABLED 0x00 -#define PORT_CONTROL_STATE_BLOCKING 0x01 -#define PORT_CONTROL_STATE_LEARNING 0x02 -#define PORT_CONTROL_STATE_FORWARDING 0x03 -#define PORT_CONTROL_1 0x05 -#define PORT_CONTROL_1_MESSAGE_PORT BIT(15) -#define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) -#define PORT_BASE_VLAN 0x06 -#define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12) -#define PORT_DEFAULT_VLAN 0x07 -#define PORT_DEFAULT_VLAN_MASK 0xfff -#define PORT_CONTROL_2 0x08 -#define PORT_CONTROL_2_IGNORE_FCS BIT(15) -#define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14) -#define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13) -#define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12) -#define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12) -#define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12) -#define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12) -#define PORT_CONTROL_2_8021Q_MASK (0x03 << 10) -#define PORT_CONTROL_2_8021Q_DISABLED (0x00 << 10) -#define PORT_CONTROL_2_8021Q_FALLBACK (0x01 << 10) -#define PORT_CONTROL_2_8021Q_CHECK (0x02 << 10) -#define PORT_CONTROL_2_8021Q_SECURE (0x03 << 10) -#define PORT_CONTROL_2_DISCARD_TAGGED BIT(9) -#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8) -#define PORT_CONTROL_2_MAP_DA BIT(7) -#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6) -#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5) -#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4) -#define PORT_CONTROL_2_UPSTREAM_MASK 0x0f -#define PORT_RATE_CONTROL 0x09 -#define PORT_RATE_CONTROL_2 0x0a -#define PORT_ASSOC_VECTOR 0x0b -#define PORT_ASSOC_VECTOR_HOLD_AT_1 BIT(15) -#define PORT_ASSOC_VECTOR_INT_AGE_OUT BIT(14) -#define PORT_ASSOC_VECTOR_LOCKED_PORT BIT(13) -#define PORT_ASSOC_VECTOR_IGNORE_WRONG BIT(12) -#define PORT_ASSOC_VECTOR_REFRESH_LOCKED BIT(11) -#define PORT_ATU_CONTROL 0x0c -#define PORT_PRI_OVERRIDE 0x0d -#define PORT_ETH_TYPE 0x0f -#define PORT_ETH_TYPE_DEFAULT 0x9100 -#define PORT_IN_DISCARD_LO 0x10 -#define PORT_IN_DISCARD_HI 0x11 -#define PORT_IN_FILTERED 0x12 -#define PORT_OUT_FILTERED 0x13 -#define PORT_TAG_REGMAP_0123 0x18 -#define PORT_TAG_REGMAP_4567 0x19 -#define PORT_IEEE_PRIO_MAP_TABLE 0x18 /* 6390 */ -#define PORT_IEEE_PRIO_MAP_TABLE_UPDATE BIT(15) -#define PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP (0x0 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP (0x1 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP (0x2 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP (0x3 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP (0x5 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP (0x6 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP (0x7 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9 - -#define GLOBAL_STATUS 0x00 -#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ -#define GLOBAL_STATUS_PPU_STATE_MASK (0x3 << 14) /* 6165 6185 */ -#define GLOBAL_STATUS_PPU_STATE_DISABLED_RST (0x0 << 14) -#define GLOBAL_STATUS_PPU_STATE_INITIALIZING (0x1 << 14) -#define GLOBAL_STATUS_PPU_STATE_DISABLED (0x2 << 14) -#define GLOBAL_STATUS_PPU_STATE_POLLING (0x3 << 14) -#define GLOBAL_STATUS_INIT_READY BIT(11) -#define GLOBAL_STATUS_IRQ_AVB 8 -#define GLOBAL_STATUS_IRQ_DEVICE 7 -#define GLOBAL_STATUS_IRQ_STATS 6 -#define GLOBAL_STATUS_IRQ_VTU_PROBLEM 5 -#define GLOBAL_STATUS_IRQ_VTU_DONE 4 -#define GLOBAL_STATUS_IRQ_ATU_PROBLEM 3 -#define GLOBAL_STATUS_IRQ_ATU_DONE 2 -#define GLOBAL_STATUS_IRQ_TCAM_DONE 1 -#define GLOBAL_STATUS_IRQ_EEPROM_DONE 0 -#define GLOBAL_MAC_01 0x01 -#define GLOBAL_MAC_23 0x02 -#define GLOBAL_MAC_45 0x03 -#define GLOBAL_ATU_FID 0x01 -#define GLOBAL_VTU_FID 0x02 -#define GLOBAL_VTU_FID_MASK 0xfff -#define GLOBAL_VTU_SID 0x03 /* 6097 6165 6351 6352 */ -#define GLOBAL_VTU_SID_MASK 0x3f -#define GLOBAL_CONTROL 0x04 -#define GLOBAL_CONTROL_SW_RESET BIT(15) -#define GLOBAL_CONTROL_PPU_ENABLE BIT(14) -#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */ -#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */ -#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */ -#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */ -#define GLOBAL_CONTROL_DEVICE_EN BIT(7) -#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6) -#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5) -#define GLOBAL_CONTROL_VTU_DONE_EN BIT(4) -#define GLOBAL_CONTROL_ATU_PROBLEM_EN BIT(3) -#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) -#define GLOBAL_CONTROL_TCAM_EN BIT(1) -#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) -#define GLOBAL_VTU_OP 0x05 -#define GLOBAL_VTU_OP_BUSY BIT(15) -#define GLOBAL_VTU_OP_FLUSH_ALL ((0x01 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_VTU_LOAD_PURGE ((0x03 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_VTU_GET_NEXT ((0x04 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_STU_LOAD_PURGE ((0x05 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_STU_GET_NEXT ((0x06 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_VID 0x06 -#define GLOBAL_VTU_VID_MASK 0xfff -#define GLOBAL_VTU_VID_PAGE BIT(13) -#define GLOBAL_VTU_VID_VALID BIT(12) -#define GLOBAL_VTU_DATA_0_3 0x07 -#define GLOBAL_VTU_DATA_4_7 0x08 -#define GLOBAL_VTU_DATA_8_11 0x09 -#define GLOBAL_VTU_STU_DATA_MASK 0x03 -#define GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED 0x00 -#define GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED 0x01 -#define GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED 0x02 -#define GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER 0x03 -#define GLOBAL_STU_DATA_PORT_STATE_DISABLED 0x00 -#define GLOBAL_STU_DATA_PORT_STATE_BLOCKING 0x01 -#define GLOBAL_STU_DATA_PORT_STATE_LEARNING 0x02 -#define GLOBAL_STU_DATA_PORT_STATE_FORWARDING 0x03 -#define GLOBAL_ATU_CONTROL 0x0a -#define GLOBAL_ATU_CONTROL_LEARN2ALL BIT(3) -#define GLOBAL_ATU_OP 0x0b -#define GLOBAL_ATU_OP_BUSY BIT(15) -#define GLOBAL_ATU_OP_NOP (0 << 12) -#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC ((2 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_DATA 0x0c -#define GLOBAL_ATU_DATA_TRUNK BIT(15) -#define GLOBAL_ATU_DATA_TRUNK_ID_MASK 0x00f0 -#define GLOBAL_ATU_DATA_TRUNK_ID_SHIFT 4 -#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 -#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4 -#define GLOBAL_ATU_DATA_STATE_MASK 0x0f -#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 -#define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d -#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e -#define GLOBAL_ATU_DATA_STATE_UC_PRIO_OVER 0x0f -#define GLOBAL_ATU_DATA_STATE_MC_NONE_RATE 0x05 -#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 -#define GLOBAL_ATU_DATA_STATE_MC_MGMT 0x0e -#define GLOBAL_ATU_DATA_STATE_MC_PRIO_OVER 0x0f -#define GLOBAL_ATU_MAC_01 0x0d -#define GLOBAL_ATU_MAC_23 0x0e -#define GLOBAL_ATU_MAC_45 0x0f -#define GLOBAL_IP_PRI_0 0x10 -#define GLOBAL_IP_PRI_1 0x11 -#define GLOBAL_IP_PRI_2 0x12 -#define GLOBAL_IP_PRI_3 0x13 -#define GLOBAL_IP_PRI_4 0x14 -#define GLOBAL_IP_PRI_5 0x15 -#define GLOBAL_IP_PRI_6 0x16 -#define GLOBAL_IP_PRI_7 0x17 -#define GLOBAL_IEEE_PRI 0x18 -#define GLOBAL_CORE_TAG_TYPE 0x19 -#define GLOBAL_MONITOR_CONTROL 0x1a -#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12 -#define GLOBAL_MONITOR_CONTROL_INGRESS_MASK (0xf << 12) -#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8 -#define GLOBAL_MONITOR_CONTROL_EGRESS_MASK (0xf << 8) -#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4 -#define GLOBAL_MONITOR_CONTROL_ARP_MASK (0xf << 4) -#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0 -#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0) -#define GLOBAL_MONITOR_CONTROL_UPDATE BIT(15) -#define GLOBAL_MONITOR_CONTROL_0180C280000000XLO (0x00 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000000XHI (0x01 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000002XLO (0x02 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000002XHI (0x03 << 8) -#define GLOBAL_MONITOR_CONTROL_INGRESS (0x20 << 8) -#define GLOBAL_MONITOR_CONTROL_EGRESS (0x21 << 8) -#define GLOBAL_MONITOR_CONTROL_CPU_DEST (0x30 << 8) -#define GLOBAL_CONTROL_2 0x1c -#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000 -#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000 -#define GLOBAL_CONTROL_2_HIST_RX (0x1 << 6) -#define GLOBAL_CONTROL_2_HIST_TX (0x2 << 6) -#define GLOBAL_CONTROL_2_HIST_RX_TX (0x3 << 6) -#define GLOBAL_STATS_OP 0x1d -#define GLOBAL_STATS_OP_BUSY BIT(15) -#define GLOBAL_STATS_OP_NOP (0 << 12) -#define GLOBAL_STATS_OP_FLUSH_ALL ((1 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_FLUSH_PORT ((2 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_READ_CAPTURED ((4 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_CAPTURE_PORT ((5 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_BANK_1_BIT_9 BIT(9) -#define GLOBAL_STATS_OP_BANK_1_BIT_10 BIT(10) -#define GLOBAL_STATS_COUNTER_32 0x1e -#define GLOBAL_STATS_COUNTER_01 0x1f - -#define GLOBAL2_INT_SOURCE 0x00 -#define GLOBAL2_INT_SOURCE_WATCHDOG 15 -#define GLOBAL2_INT_MASK 0x01 -#define GLOBAL2_MGMT_EN_2X 0x02 -#define GLOBAL2_MGMT_EN_0X 0x03 -#define GLOBAL2_FLOW_CONTROL 0x04 -#define GLOBAL2_SWITCH_MGMT 0x05 -#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA BIT(15) -#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS BIT(14) -#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13) -#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7) -#define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3) -#define GLOBAL2_DEVICE_MAPPING 0x06 -#define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15) -#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8 -#define GLOBAL2_DEVICE_MAPPING_PORT_MASK 0x0f -#define GLOBAL2_TRUNK_MASK 0x07 -#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15) -#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12 -#define GLOBAL2_TRUNK_MASK_HASK BIT(11) -#define GLOBAL2_TRUNK_MAPPING 0x08 -#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) -#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 -#define GLOBAL2_IRL_CMD 0x09 -#define GLOBAL2_IRL_CMD_BUSY BIT(15) -#define GLOBAL2_IRL_CMD_OP_INIT_ALL ((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_INIT_SEL ((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_WRITE_SEL ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_READ_SEL ((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_DATA 0x0a -#define GLOBAL2_PVT_ADDR 0x0b -#define GLOBAL2_PVT_ADDR_BUSY BIT(15) -#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_DATA 0x0c -#define GLOBAL2_SWITCH_MAC 0x0d -#define GLOBAL2_ATU_STATS 0x0e -#define GLOBAL2_PRIO_OVERRIDE 0x0f -#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7) -#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 -#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) -#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 -#define GLOBAL2_EEPROM_CMD 0x14 -#define GLOBAL2_EEPROM_CMD_BUSY BIT(15) -#define GLOBAL2_EEPROM_CMD_OP_WRITE ((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_RUNNING BIT(11) -#define GLOBAL2_EEPROM_CMD_WRITE_EN BIT(10) -#define GLOBAL2_EEPROM_CMD_ADDR_MASK 0xff -#define GLOBAL2_EEPROM_DATA 0x15 -#define GLOBAL2_EEPROM_ADDR 0x15 /* 6390, 6341 */ -#define GLOBAL2_PTP_AVB_OP 0x16 -#define GLOBAL2_PTP_AVB_DATA 0x17 -#define GLOBAL2_SMI_PHY_CMD 0x18 -#define GLOBAL2_SMI_PHY_CMD_BUSY BIT(15) -#define GLOBAL2_SMI_PHY_CMD_EXTERNAL BIT(13) -#define GLOBAL2_SMI_PHY_CMD_MODE_22 BIT(12) -#define GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA ((0x1 << 10) | \ - GLOBAL2_SMI_PHY_CMD_MODE_22 | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA ((0x2 << 10) | \ - GLOBAL2_SMI_PHY_CMD_MODE_22 | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_ADDR ((0x0 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_DATA ((0x1 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_READ_DATA ((0x3 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) - -#define GLOBAL2_SMI_PHY_DATA 0x19 -#define GLOBAL2_SCRATCH_MISC 0x1a -#define GLOBAL2_SCRATCH_BUSY BIT(15) -#define GLOBAL2_SCRATCH_REGISTER_SHIFT 8 -#define GLOBAL2_SCRATCH_VALUE_MASK 0xff -#define GLOBAL2_WDOG_CONTROL 0x1b -#define GLOBAL2_WDOG_CONTROL_EGRESS_EVENT BIT(7) -#define GLOBAL2_WDOG_CONTROL_RMU_TIMEOUT BIT(6) -#define GLOBAL2_WDOG_CONTROL_QC_ENABLE BIT(5) -#define GLOBAL2_WDOG_CONTROL_EGRESS_HISTORY BIT(4) -#define GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE BIT(3) -#define GLOBAL2_WDOG_CONTROL_FORCE_IRQ BIT(2) -#define GLOBAL2_WDOG_CONTROL_HISTORY BIT(1) -#define GLOBAL2_WDOG_CONTROL_SWRESET BIT(0) -#define GLOBAL2_WDOG_UPDATE BIT(15) -#define GLOBAL2_WDOG_INT_SOURCE (0x00 << 8) -#define GLOBAL2_WDOG_INT_STATUS (0x10 << 8) -#define GLOBAL2_WDOG_INT_ENABLE (0x11 << 8) -#define GLOBAL2_WDOG_EVENT (0x12 << 8) -#define GLOBAL2_WDOG_HISTORY (0x13 << 8) -#define GLOBAL2_WDOG_DATA_MASK 0xff -#define GLOBAL2_WDOG_CUT_THROUGH BIT(3) -#define GLOBAL2_WDOG_QUEUE_CONTROLLER BIT(2) -#define GLOBAL2_WDOG_EGRESS BIT(1) -#define GLOBAL2_WDOG_FORCE_IRQ BIT(0) -#define GLOBAL2_QOS_WEIGHT 0x1c -#define GLOBAL2_MISC 0x1d -#define GLOBAL2_MISC_5_BIT_PORT BIT(14) - -#define MV88E6XXX_N_FID 4096 - -/* PVT limits for 4-bit port and 5-bit switch */ -#define MV88E6XXX_MAX_PVT_SWITCHES 32 -#define MV88E6XXX_MAX_PVT_PORTS 16 - -enum mv88e6xxx_frame_mode { - MV88E6XXX_FRAME_MODE_NORMAL, - MV88E6XXX_FRAME_MODE_DSA, - MV88E6XXX_FRAME_MODE_PROVIDER, - MV88E6XXX_FRAME_MODE_ETHERTYPE, -}; - -/* List of supported models */ -enum mv88e6xxx_model { - MV88E6085, - MV88E6095, - MV88E6097, - MV88E6123, - MV88E6131, - MV88E6141, - MV88E6161, - MV88E6165, - MV88E6171, - MV88E6172, - MV88E6175, - MV88E6176, - MV88E6185, - MV88E6190, - MV88E6190X, - MV88E6191, - MV88E6240, - MV88E6290, - MV88E6320, - MV88E6321, - MV88E6341, - MV88E6350, - MV88E6351, - MV88E6352, - MV88E6390, - MV88E6390X, -}; - -enum mv88e6xxx_family { - MV88E6XXX_FAMILY_NONE, - MV88E6XXX_FAMILY_6065, /* 6031 6035 6061 6065 */ - MV88E6XXX_FAMILY_6095, /* 6092 6095 */ - MV88E6XXX_FAMILY_6097, /* 6046 6085 6096 6097 */ - MV88E6XXX_FAMILY_6165, /* 6123 6161 6165 */ - MV88E6XXX_FAMILY_6185, /* 6108 6121 6122 6131 6152 6155 6182 6185 */ - MV88E6XXX_FAMILY_6320, /* 6320 6321 */ - MV88E6XXX_FAMILY_6341, /* 6141 6341 */ - MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */ - MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */ - MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */ -}; - -enum mv88e6xxx_cap { - /* Energy Efficient Ethernet. - */ - MV88E6XXX_CAP_EEE, - - /* Multi-chip Addressing Mode. - * Some chips respond to only 2 registers of its own SMI device address - * when it is non-zero, and use indirect access to internal registers. - */ - MV88E6XXX_CAP_SMI_CMD, /* (0x00) SMI Command */ - MV88E6XXX_CAP_SMI_DATA, /* (0x01) SMI Data */ - - /* Switch Global (1) Registers. - */ - MV88E6XXX_CAP_G1_ATU_FID, /* (0x01) ATU FID Register */ - MV88E6XXX_CAP_G1_VTU_FID, /* (0x02) VTU FID Register */ - - /* Switch Global 2 Registers. - * The device contains a second set of global 16-bit registers. - */ - MV88E6XXX_CAP_GLOBAL2, - MV88E6XXX_CAP_G2_INT, /* (0x00) Interrupt Status */ - MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */ - MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */ - MV88E6XXX_CAP_G2_IRL_CMD, /* (0x09) Ingress Rate Command */ - MV88E6XXX_CAP_G2_IRL_DATA, /* (0x0a) Ingress Rate Data */ - MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */ - - /* Per VLAN Spanning Tree Unit (STU). - * The Port State database, if present, is accessed through VTU - * operations and dedicated SID registers. See GLOBAL_VTU_SID. - */ - MV88E6XXX_CAP_STU, - - /* VLAN Table Unit. - * The VTU is used to program 802.1Q VLANs. See GLOBAL_VTU_OP. - */ - MV88E6XXX_CAP_VTU, -}; - -/* Bitmask of capabilities */ -#define MV88E6XXX_FLAG_EEE BIT_ULL(MV88E6XXX_CAP_EEE) - -#define MV88E6XXX_FLAG_SMI_CMD BIT_ULL(MV88E6XXX_CAP_SMI_CMD) -#define MV88E6XXX_FLAG_SMI_DATA BIT_ULL(MV88E6XXX_CAP_SMI_DATA) - -#define MV88E6XXX_FLAG_G1_VTU_FID BIT_ULL(MV88E6XXX_CAP_G1_VTU_FID) - -#define MV88E6XXX_FLAG_GLOBAL2 BIT_ULL(MV88E6XXX_CAP_GLOBAL2) -#define MV88E6XXX_FLAG_G2_INT BIT_ULL(MV88E6XXX_CAP_G2_INT) -#define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_2X) -#define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_0X) -#define MV88E6XXX_FLAG_G2_IRL_CMD BIT_ULL(MV88E6XXX_CAP_G2_IRL_CMD) -#define MV88E6XXX_FLAG_G2_IRL_DATA BIT_ULL(MV88E6XXX_CAP_G2_IRL_DATA) -#define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT) - -/* Ingress Rate Limit unit */ -#define MV88E6XXX_FLAGS_IRL \ - (MV88E6XXX_FLAG_G2_IRL_CMD | \ - MV88E6XXX_FLAG_G2_IRL_DATA) - -/* Multi-chip Addressing Mode */ -#define MV88E6XXX_FLAGS_MULTI_CHIP \ - (MV88E6XXX_FLAG_SMI_CMD | \ - MV88E6XXX_FLAG_SMI_DATA) - -#define MV88E6XXX_FLAGS_FAMILY_6095 \ - (MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6097 \ - (MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6165 \ - (MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6185 \ - (MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6320 \ - (MV88E6XXX_FLAG_EEE | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6341 \ - (MV88E6XXX_FLAG_EEE | \ - MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6351 \ - (MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6352 \ - (MV88E6XXX_FLAG_EEE | \ - MV88E6XXX_FLAG_G1_VTU_FID | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ - MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ - MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -#define MV88E6XXX_FLAGS_FAMILY_6390 \ - (MV88E6XXX_FLAG_EEE | \ - MV88E6XXX_FLAG_GLOBAL2 | \ - MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAGS_IRL | \ - MV88E6XXX_FLAGS_MULTI_CHIP) - -struct mv88e6xxx_ops; - -struct mv88e6xxx_info { - enum mv88e6xxx_family family; - u16 prod_num; - const char *name; - unsigned int num_databases; - unsigned int num_ports; - unsigned int max_vid; - unsigned int port_base_addr; - unsigned int global1_addr; - unsigned int age_time_coeff; - unsigned int g1_irqs; - bool pvt; - enum dsa_tag_protocol tag_protocol; - unsigned long long flags; - - /* Mask for FromPort and ToPort value of PortVec used in ATU Move - * operation. 0 means that the ATU Move operation is not supported. - */ - u8 atu_move_port_mask; - const struct mv88e6xxx_ops *ops; -}; - -struct mv88e6xxx_atu_entry { - u8 state; - bool trunk; - u16 portvec; - u8 mac[ETH_ALEN]; -}; - -struct mv88e6xxx_vtu_entry { - u16 vid; - u16 fid; - u8 sid; - bool valid; - u8 member[DSA_MAX_PORTS]; - u8 state[DSA_MAX_PORTS]; -}; - -struct mv88e6xxx_bus_ops; -struct mv88e6xxx_irq_ops; - -struct mv88e6xxx_irq { - u16 masked; - struct irq_chip chip; - struct irq_domain *domain; - unsigned int nirqs; -}; - -struct mv88e6xxx_chip { - const struct mv88e6xxx_info *info; - - /* The dsa_switch this private structure is related to */ - struct dsa_switch *ds; - - /* The device this structure is associated to */ - struct device *dev; - - /* This mutex protects the access to the switch registers */ - struct mutex reg_lock; - - /* The MII bus and the address on the bus that is used to - * communication with the switch - */ - const struct mv88e6xxx_bus_ops *smi_ops; - struct mii_bus *bus; - int sw_addr; - - /* Handles automatic disabling and re-enabling of the PHY - * polling unit. - */ - const struct mv88e6xxx_bus_ops *phy_ops; - struct mutex ppu_mutex; - int ppu_disabled; - struct work_struct ppu_work; - struct timer_list ppu_timer; - - /* This mutex serialises access to the statistics unit. - * Hold this mutex over snapshot + dump sequences. - */ - struct mutex stats_mutex; - - /* A switch may have a GPIO line tied to its reset pin. Parse - * this from the device tree, and use it before performing - * switch soft reset. - */ - struct gpio_desc *reset; - - /* set to size of eeprom if supported by the switch */ - int eeprom_len; - - /* List of mdio busses */ - struct list_head mdios; - - /* There can be two interrupt controllers, which are chained - * off a GPIO as interrupt source - */ - struct mv88e6xxx_irq g1_irq; - struct mv88e6xxx_irq g2_irq; - int irq; - int device_irq; - int watchdog_irq; -}; - -struct mv88e6xxx_bus_ops { - int (*read)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); - int (*write)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); -}; - -struct mv88e6xxx_mdio_bus { - struct mii_bus *bus; - struct mv88e6xxx_chip *chip; - struct list_head list; - bool external; -}; - -struct mv88e6xxx_ops { - int (*get_eeprom)(struct mv88e6xxx_chip *chip, - struct ethtool_eeprom *eeprom, u8 *data); - int (*set_eeprom)(struct mv88e6xxx_chip *chip, - struct ethtool_eeprom *eeprom, u8 *data); - - int (*set_switch_mac)(struct mv88e6xxx_chip *chip, u8 *addr); - - int (*phy_read)(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 *val); - int (*phy_write)(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 val); - - /* PHY Polling Unit (PPU) operations */ - int (*ppu_enable)(struct mv88e6xxx_chip *chip); - int (*ppu_disable)(struct mv88e6xxx_chip *chip); - - /* Switch Software Reset */ - int (*reset)(struct mv88e6xxx_chip *chip); - - /* RGMII Receive/Transmit Timing Control - * Add delay on PHY_INTERFACE_MODE_RGMII_*ID, no delay otherwise. - */ - int (*port_set_rgmii_delay)(struct mv88e6xxx_chip *chip, int port, - phy_interface_t mode); - -#define LINK_FORCED_DOWN 0 -#define LINK_FORCED_UP 1 -#define LINK_UNFORCED -2 - - /* Port's MAC link state - * Use LINK_FORCED_UP or LINK_FORCED_DOWN to force link up or down, - * or LINK_UNFORCED for normal link detection. - */ - int (*port_set_link)(struct mv88e6xxx_chip *chip, int port, int link); - -#define DUPLEX_UNFORCED -2 - - /* Port's MAC duplex mode - * - * Use DUPLEX_HALF or DUPLEX_FULL to force half or full duplex, - * or DUPLEX_UNFORCED for normal duplex detection. - */ - int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup); - -#define SPEED_MAX INT_MAX -#define SPEED_UNFORCED -2 - - /* Port's MAC speed (in Mbps) - * - * Depending on the chip, 10, 100, 200, 1000, 2500, 10000 are valid. - * Use SPEED_UNFORCED for normal detection, SPEED_MAX for max value. - */ - int (*port_set_speed)(struct mv88e6xxx_chip *chip, int port, int speed); - - int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port); - - int (*port_set_frame_mode)(struct mv88e6xxx_chip *chip, int port, - enum mv88e6xxx_frame_mode mode); - int (*port_set_egress_floods)(struct mv88e6xxx_chip *chip, int port, - bool unicast, bool multicast); - int (*port_set_ether_type)(struct mv88e6xxx_chip *chip, int port, - u16 etype); - int (*port_jumbo_config)(struct mv88e6xxx_chip *chip, int port); - - int (*port_egress_rate_limiting)(struct mv88e6xxx_chip *chip, int port); - int (*port_pause_config)(struct mv88e6xxx_chip *chip, int port); - int (*port_disable_learn_limit)(struct mv88e6xxx_chip *chip, int port); - int (*port_disable_pri_override)(struct mv88e6xxx_chip *chip, int port); - - /* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc. - * Some chips allow this to be configured on specific ports. - */ - int (*port_set_cmode)(struct mv88e6xxx_chip *chip, int port, - phy_interface_t mode); - - /* Some devices have a per port register indicating what is - * the upstream port this port should forward to. - */ - int (*port_set_upstream_port)(struct mv88e6xxx_chip *chip, int port, - int upstream_port); - - /* Snapshot the statistics for a port. The statistics can then - * be read back a leisure but still with a consistent view. - */ - int (*stats_snapshot)(struct mv88e6xxx_chip *chip, int port); - - /* Set the histogram mode for statistics, when the control registers - * are separated out of the STATS_OP register. - */ - int (*stats_set_histogram)(struct mv88e6xxx_chip *chip); - - /* Return the number of strings describing statistics */ - int (*stats_get_sset_count)(struct mv88e6xxx_chip *chip); - void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data); - void (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port, - uint64_t *data); - int (*g1_set_cpu_port)(struct mv88e6xxx_chip *chip, int port); - int (*g1_set_egress_port)(struct mv88e6xxx_chip *chip, int port); - const struct mv88e6xxx_irq_ops *watchdog_ops; - - /* Can be either in g1 or g2, so don't use a prefix */ - int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip); - - /* Power on/off a SERDES interface */ - int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on); - - /* VLAN Translation Unit operations */ - int (*vtu_getnext)(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry); - int (*vtu_loadpurge)(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry); -}; - -struct mv88e6xxx_irq_ops { - /* Action to be performed when the interrupt happens */ - int (*irq_action)(struct mv88e6xxx_chip *chip, int irq); - /* Setup the hardware to generate the interrupt */ - int (*irq_setup)(struct mv88e6xxx_chip *chip); - /* Reset the hardware to stop generating the interrupt */ - void (*irq_free)(struct mv88e6xxx_chip *chip); -}; - -#define STATS_TYPE_PORT BIT(0) -#define STATS_TYPE_BANK0 BIT(1) -#define STATS_TYPE_BANK1 BIT(2) - -struct mv88e6xxx_hw_stat { - char string[ETH_GSTRING_LEN]; - int sizeof_stat; - int reg; - int type; -}; - -static inline bool mv88e6xxx_has(struct mv88e6xxx_chip *chip, - unsigned long flags) -{ - return (chip->info->flags & flags) == flags; -} - -static inline bool mv88e6xxx_has_pvt(struct mv88e6xxx_chip *chip) -{ - return chip->info->pvt; -} - -static inline unsigned int mv88e6xxx_num_databases(struct mv88e6xxx_chip *chip) -{ - return chip->info->num_databases; -} - -static inline unsigned int mv88e6xxx_num_ports(struct mv88e6xxx_chip *chip) -{ - return chip->info->num_ports; -} - -static inline u16 mv88e6xxx_port_mask(struct mv88e6xxx_chip *chip) -{ - return GENMASK(mv88e6xxx_num_ports(chip) - 1, 0); -} - -int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val); -int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val); -int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, - u16 update); -int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask); -struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip); -#endif diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c index d47a6e08d88c..0db624f0993c 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.c +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -15,7 +15,7 @@ #include #include -#include "mv88e6xxx.h" +#include "chip.h" #include "phy.h" int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 548a956637ee..360c77854f2a 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -13,7 +13,8 @@ */ #include -#include "mv88e6xxx.h" + +#include "chip.h" #include "port.h" int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 86f40887b6d2..497a6911b2bd 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -15,7 +15,7 @@ #ifndef _MV88E6XXX_PORT_H #define _MV88E6XXX_PORT_H -#include "mv88e6xxx.h" +#include "chip.h" int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, u16 *val); diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 53795676bd70..78f5b1eb44ea 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -13,8 +13,8 @@ #include +#include "chip.h" #include "global2.h" -#include "mv88e6xxx.h" #include "phy.h" #include "port.h" #include "serdes.h" diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index eb3ceaef790f..5c1cd6d8e9a5 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -14,7 +14,7 @@ #ifndef _MV88E6XXX_SERDES_H #define _MV88E6XXX_SERDES_H -#include "mv88e6xxx.h" +#include "chip.h" #define MV88E6352_ADDR_SERDES 0x0f #define MV88E6352_SERDES_PAGE_FIBER 0x01 -- cgit v1.2.3 From c4530ee177f309f7c339f21b70fa6f77798650b8 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 2 Jun 2017 17:06:16 -0400 Subject: net: dsa: mv88e6xxx: move PHY macros Move the PHY_* macros where they belong, in the related phy.h header. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.h | 4 ---- drivers/net/dsa/mv88e6xxx/phy.h | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index ae7aed533aa5..2929132fb52d 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -33,10 +33,6 @@ #define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) #define SMI_DATA 0x01 -/* PHY Registers */ -#define PHY_PAGE 0x16 -#define PHY_PAGE_COPPER 0x00 - #define PORT_STATUS 0x00 #define PORT_STATUS_PAUSE_EN BIT(15) #define PORT_STATUS_MY_PAUSE BIT(14) diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h index 91fe3c3e9aea..4131a4e8206a 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.h +++ b/drivers/net/dsa/mv88e6xxx/phy.h @@ -14,6 +14,9 @@ #ifndef _MV88E6XXX_PHY_H #define _MV88E6XXX_PHY_H +#define PHY_PAGE 0x16 +#define PHY_PAGE_COPPER 0x00 + /* PHY Registers accesses implementations */ int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 *val); -- cgit v1.2.3 From d2a160b5a70990361c3045f0fec74aad188b3f7c Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 2 Jun 2017 17:06:17 -0400 Subject: net: dsa: mv88e6xxx: move the Port macros Move the PORT_* macros where they belong, in the related port.h header. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.h | 160 --------------------------------------- drivers/net/dsa/mv88e6xxx/port.h | 160 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 160 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 2929132fb52d..a7c71a43503b 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -33,166 +33,6 @@ #define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) #define SMI_DATA 0x01 -#define PORT_STATUS 0x00 -#define PORT_STATUS_PAUSE_EN BIT(15) -#define PORT_STATUS_MY_PAUSE BIT(14) -#define PORT_STATUS_HD_FLOW BIT(13) -#define PORT_STATUS_PHY_DETECT BIT(12) -#define PORT_STATUS_LINK BIT(11) -#define PORT_STATUS_DUPLEX BIT(10) -#define PORT_STATUS_SPEED_MASK 0x0300 -#define PORT_STATUS_SPEED_10 0x0000 -#define PORT_STATUS_SPEED_100 0x0100 -#define PORT_STATUS_SPEED_1000 0x0200 -#define PORT_STATUS_EEE BIT(6) /* 6352 */ -#define PORT_STATUS_AM_DIS BIT(6) /* 6165 */ -#define PORT_STATUS_MGMII BIT(6) /* 6185 */ -#define PORT_STATUS_TX_PAUSED BIT(5) -#define PORT_STATUS_FLOW_CTRL BIT(4) -#define PORT_STATUS_CMODE_MASK 0x0f -#define PORT_STATUS_CMODE_100BASE_X 0x8 -#define PORT_STATUS_CMODE_1000BASE_X 0x9 -#define PORT_STATUS_CMODE_SGMII 0xa -#define PORT_STATUS_CMODE_2500BASEX 0xb -#define PORT_STATUS_CMODE_XAUI 0xc -#define PORT_STATUS_CMODE_RXAUI 0xd -#define PORT_PCS_CTRL 0x01 -#define PORT_PCS_CTRL_RGMII_DELAY_RXCLK BIT(15) -#define PORT_PCS_CTRL_RGMII_DELAY_TXCLK BIT(14) -#define PORT_PCS_CTRL_FORCE_SPEED BIT(13) /* 6390 */ -#define PORT_PCS_CTRL_ALTSPEED BIT(12) /* 6390 */ -#define PORT_PCS_CTRL_200BASE BIT(12) /* 6352 */ -#define PORT_PCS_CTRL_FC BIT(7) -#define PORT_PCS_CTRL_FORCE_FC BIT(6) -#define PORT_PCS_CTRL_LINK_UP BIT(5) -#define PORT_PCS_CTRL_FORCE_LINK BIT(4) -#define PORT_PCS_CTRL_DUPLEX_FULL BIT(3) -#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2) -#define PORT_PCS_CTRL_SPEED_MASK (0x03) -#define PORT_PCS_CTRL_SPEED_10 (0x00) -#define PORT_PCS_CTRL_SPEED_100 (0x01) -#define PORT_PCS_CTRL_SPEED_200 (0x02) /* 6065 and non Gb chips */ -#define PORT_PCS_CTRL_SPEED_1000 (0x02) -#define PORT_PCS_CTRL_SPEED_10000 (0x03) /* 6390X */ -#define PORT_PCS_CTRL_SPEED_UNFORCED (0x03) -#define PORT_PAUSE_CTRL 0x02 -#define PORT_FLOW_CTRL_LIMIT_IN ((0x00 << 8) | BIT(15)) -#define PORT_FLOW_CTRL_LIMIT_OUT ((0x01 << 8) | BIT(15)) -#define PORT_SWITCH_ID 0x03 -#define PORT_SWITCH_ID_PROD_NUM_6085 0x04a -#define PORT_SWITCH_ID_PROD_NUM_6095 0x095 -#define PORT_SWITCH_ID_PROD_NUM_6097 0x099 -#define PORT_SWITCH_ID_PROD_NUM_6131 0x106 -#define PORT_SWITCH_ID_PROD_NUM_6320 0x115 -#define PORT_SWITCH_ID_PROD_NUM_6123 0x121 -#define PORT_SWITCH_ID_PROD_NUM_6141 0x340 -#define PORT_SWITCH_ID_PROD_NUM_6161 0x161 -#define PORT_SWITCH_ID_PROD_NUM_6165 0x165 -#define PORT_SWITCH_ID_PROD_NUM_6171 0x171 -#define PORT_SWITCH_ID_PROD_NUM_6172 0x172 -#define PORT_SWITCH_ID_PROD_NUM_6175 0x175 -#define PORT_SWITCH_ID_PROD_NUM_6176 0x176 -#define PORT_SWITCH_ID_PROD_NUM_6185 0x1a7 -#define PORT_SWITCH_ID_PROD_NUM_6190 0x190 -#define PORT_SWITCH_ID_PROD_NUM_6190X 0x0a0 -#define PORT_SWITCH_ID_PROD_NUM_6191 0x191 -#define PORT_SWITCH_ID_PROD_NUM_6240 0x240 -#define PORT_SWITCH_ID_PROD_NUM_6290 0x290 -#define PORT_SWITCH_ID_PROD_NUM_6321 0x310 -#define PORT_SWITCH_ID_PROD_NUM_6341 0x341 -#define PORT_SWITCH_ID_PROD_NUM_6352 0x352 -#define PORT_SWITCH_ID_PROD_NUM_6350 0x371 -#define PORT_SWITCH_ID_PROD_NUM_6351 0x375 -#define PORT_SWITCH_ID_PROD_NUM_6390 0x390 -#define PORT_SWITCH_ID_PROD_NUM_6390X 0x0a1 -#define PORT_CONTROL 0x04 -#define PORT_CONTROL_USE_CORE_TAG BIT(15) -#define PORT_CONTROL_DROP_ON_LOCK BIT(14) -#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12) -#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12) -#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12) -#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12) -#define PORT_CONTROL_EGRESS_MASK (0x3 << 12) -#define PORT_CONTROL_HEADER BIT(11) -#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10) -#define PORT_CONTROL_DOUBLE_TAG BIT(9) -#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8) -#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8) -#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8) -#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8) -#define PORT_CONTROL_FRAME_MASK (0x3 << 8) -#define PORT_CONTROL_DSA_TAG BIT(8) -#define PORT_CONTROL_VLAN_TUNNEL BIT(7) -#define PORT_CONTROL_TAG_IF_BOTH BIT(6) -#define PORT_CONTROL_USE_IP BIT(5) -#define PORT_CONTROL_USE_TAG BIT(4) -#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2) -#define PORT_CONTROL_EGRESS_FLOODS_MASK (0x3 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA (0x0 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA (0x1 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA (0x2 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA (0x3 << 2) -#define PORT_CONTROL_STATE_MASK 0x03 -#define PORT_CONTROL_STATE_DISABLED 0x00 -#define PORT_CONTROL_STATE_BLOCKING 0x01 -#define PORT_CONTROL_STATE_LEARNING 0x02 -#define PORT_CONTROL_STATE_FORWARDING 0x03 -#define PORT_CONTROL_1 0x05 -#define PORT_CONTROL_1_MESSAGE_PORT BIT(15) -#define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) -#define PORT_BASE_VLAN 0x06 -#define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12) -#define PORT_DEFAULT_VLAN 0x07 -#define PORT_DEFAULT_VLAN_MASK 0xfff -#define PORT_CONTROL_2 0x08 -#define PORT_CONTROL_2_IGNORE_FCS BIT(15) -#define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14) -#define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13) -#define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12) -#define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12) -#define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12) -#define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12) -#define PORT_CONTROL_2_8021Q_MASK (0x03 << 10) -#define PORT_CONTROL_2_8021Q_DISABLED (0x00 << 10) -#define PORT_CONTROL_2_8021Q_FALLBACK (0x01 << 10) -#define PORT_CONTROL_2_8021Q_CHECK (0x02 << 10) -#define PORT_CONTROL_2_8021Q_SECURE (0x03 << 10) -#define PORT_CONTROL_2_DISCARD_TAGGED BIT(9) -#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8) -#define PORT_CONTROL_2_MAP_DA BIT(7) -#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6) -#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5) -#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4) -#define PORT_CONTROL_2_UPSTREAM_MASK 0x0f -#define PORT_RATE_CONTROL 0x09 -#define PORT_RATE_CONTROL_2 0x0a -#define PORT_ASSOC_VECTOR 0x0b -#define PORT_ASSOC_VECTOR_HOLD_AT_1 BIT(15) -#define PORT_ASSOC_VECTOR_INT_AGE_OUT BIT(14) -#define PORT_ASSOC_VECTOR_LOCKED_PORT BIT(13) -#define PORT_ASSOC_VECTOR_IGNORE_WRONG BIT(12) -#define PORT_ASSOC_VECTOR_REFRESH_LOCKED BIT(11) -#define PORT_ATU_CONTROL 0x0c -#define PORT_PRI_OVERRIDE 0x0d -#define PORT_ETH_TYPE 0x0f -#define PORT_ETH_TYPE_DEFAULT 0x9100 -#define PORT_IN_DISCARD_LO 0x10 -#define PORT_IN_DISCARD_HI 0x11 -#define PORT_IN_FILTERED 0x12 -#define PORT_OUT_FILTERED 0x13 -#define PORT_TAG_REGMAP_0123 0x18 -#define PORT_TAG_REGMAP_4567 0x19 -#define PORT_IEEE_PRIO_MAP_TABLE 0x18 /* 6390 */ -#define PORT_IEEE_PRIO_MAP_TABLE_UPDATE BIT(15) -#define PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP (0x0 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP (0x1 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP (0x2 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP (0x3 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP (0x5 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP (0x6 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP (0x7 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9 - #define GLOBAL_STATUS 0x00 #define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ #define GLOBAL_STATUS_PPU_STATE_MASK (0x3 << 14) /* 6165 6185 */ diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 497a6911b2bd..4f5e1ccfadc6 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -17,6 +17,166 @@ #include "chip.h" +#define PORT_STATUS 0x00 +#define PORT_STATUS_PAUSE_EN BIT(15) +#define PORT_STATUS_MY_PAUSE BIT(14) +#define PORT_STATUS_HD_FLOW BIT(13) +#define PORT_STATUS_PHY_DETECT BIT(12) +#define PORT_STATUS_LINK BIT(11) +#define PORT_STATUS_DUPLEX BIT(10) +#define PORT_STATUS_SPEED_MASK 0x0300 +#define PORT_STATUS_SPEED_10 0x0000 +#define PORT_STATUS_SPEED_100 0x0100 +#define PORT_STATUS_SPEED_1000 0x0200 +#define PORT_STATUS_EEE BIT(6) /* 6352 */ +#define PORT_STATUS_AM_DIS BIT(6) /* 6165 */ +#define PORT_STATUS_MGMII BIT(6) /* 6185 */ +#define PORT_STATUS_TX_PAUSED BIT(5) +#define PORT_STATUS_FLOW_CTRL BIT(4) +#define PORT_STATUS_CMODE_MASK 0x0f +#define PORT_STATUS_CMODE_100BASE_X 0x8 +#define PORT_STATUS_CMODE_1000BASE_X 0x9 +#define PORT_STATUS_CMODE_SGMII 0xa +#define PORT_STATUS_CMODE_2500BASEX 0xb +#define PORT_STATUS_CMODE_XAUI 0xc +#define PORT_STATUS_CMODE_RXAUI 0xd +#define PORT_PCS_CTRL 0x01 +#define PORT_PCS_CTRL_RGMII_DELAY_RXCLK BIT(15) +#define PORT_PCS_CTRL_RGMII_DELAY_TXCLK BIT(14) +#define PORT_PCS_CTRL_FORCE_SPEED BIT(13) /* 6390 */ +#define PORT_PCS_CTRL_ALTSPEED BIT(12) /* 6390 */ +#define PORT_PCS_CTRL_200BASE BIT(12) /* 6352 */ +#define PORT_PCS_CTRL_FC BIT(7) +#define PORT_PCS_CTRL_FORCE_FC BIT(6) +#define PORT_PCS_CTRL_LINK_UP BIT(5) +#define PORT_PCS_CTRL_FORCE_LINK BIT(4) +#define PORT_PCS_CTRL_DUPLEX_FULL BIT(3) +#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2) +#define PORT_PCS_CTRL_SPEED_MASK (0x03) +#define PORT_PCS_CTRL_SPEED_10 (0x00) +#define PORT_PCS_CTRL_SPEED_100 (0x01) +#define PORT_PCS_CTRL_SPEED_200 (0x02) /* 6065 and non Gb chips */ +#define PORT_PCS_CTRL_SPEED_1000 (0x02) +#define PORT_PCS_CTRL_SPEED_10000 (0x03) /* 6390X */ +#define PORT_PCS_CTRL_SPEED_UNFORCED (0x03) +#define PORT_PAUSE_CTRL 0x02 +#define PORT_FLOW_CTRL_LIMIT_IN ((0x00 << 8) | BIT(15)) +#define PORT_FLOW_CTRL_LIMIT_OUT ((0x01 << 8) | BIT(15)) +#define PORT_SWITCH_ID 0x03 +#define PORT_SWITCH_ID_PROD_NUM_6085 0x04a +#define PORT_SWITCH_ID_PROD_NUM_6095 0x095 +#define PORT_SWITCH_ID_PROD_NUM_6097 0x099 +#define PORT_SWITCH_ID_PROD_NUM_6131 0x106 +#define PORT_SWITCH_ID_PROD_NUM_6320 0x115 +#define PORT_SWITCH_ID_PROD_NUM_6123 0x121 +#define PORT_SWITCH_ID_PROD_NUM_6141 0x340 +#define PORT_SWITCH_ID_PROD_NUM_6161 0x161 +#define PORT_SWITCH_ID_PROD_NUM_6165 0x165 +#define PORT_SWITCH_ID_PROD_NUM_6171 0x171 +#define PORT_SWITCH_ID_PROD_NUM_6172 0x172 +#define PORT_SWITCH_ID_PROD_NUM_6175 0x175 +#define PORT_SWITCH_ID_PROD_NUM_6176 0x176 +#define PORT_SWITCH_ID_PROD_NUM_6185 0x1a7 +#define PORT_SWITCH_ID_PROD_NUM_6190 0x190 +#define PORT_SWITCH_ID_PROD_NUM_6190X 0x0a0 +#define PORT_SWITCH_ID_PROD_NUM_6191 0x191 +#define PORT_SWITCH_ID_PROD_NUM_6240 0x240 +#define PORT_SWITCH_ID_PROD_NUM_6290 0x290 +#define PORT_SWITCH_ID_PROD_NUM_6321 0x310 +#define PORT_SWITCH_ID_PROD_NUM_6341 0x341 +#define PORT_SWITCH_ID_PROD_NUM_6352 0x352 +#define PORT_SWITCH_ID_PROD_NUM_6350 0x371 +#define PORT_SWITCH_ID_PROD_NUM_6351 0x375 +#define PORT_SWITCH_ID_PROD_NUM_6390 0x390 +#define PORT_SWITCH_ID_PROD_NUM_6390X 0x0a1 +#define PORT_CONTROL 0x04 +#define PORT_CONTROL_USE_CORE_TAG BIT(15) +#define PORT_CONTROL_DROP_ON_LOCK BIT(14) +#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12) +#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12) +#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12) +#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12) +#define PORT_CONTROL_EGRESS_MASK (0x3 << 12) +#define PORT_CONTROL_HEADER BIT(11) +#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10) +#define PORT_CONTROL_DOUBLE_TAG BIT(9) +#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8) +#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8) +#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8) +#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8) +#define PORT_CONTROL_FRAME_MASK (0x3 << 8) +#define PORT_CONTROL_DSA_TAG BIT(8) +#define PORT_CONTROL_VLAN_TUNNEL BIT(7) +#define PORT_CONTROL_TAG_IF_BOTH BIT(6) +#define PORT_CONTROL_USE_IP BIT(5) +#define PORT_CONTROL_USE_TAG BIT(4) +#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2) +#define PORT_CONTROL_EGRESS_FLOODS_MASK (0x3 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA (0x0 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA (0x1 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA (0x2 << 2) +#define PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA (0x3 << 2) +#define PORT_CONTROL_STATE_MASK 0x03 +#define PORT_CONTROL_STATE_DISABLED 0x00 +#define PORT_CONTROL_STATE_BLOCKING 0x01 +#define PORT_CONTROL_STATE_LEARNING 0x02 +#define PORT_CONTROL_STATE_FORWARDING 0x03 +#define PORT_CONTROL_1 0x05 +#define PORT_CONTROL_1_MESSAGE_PORT BIT(15) +#define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) +#define PORT_BASE_VLAN 0x06 +#define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12) +#define PORT_DEFAULT_VLAN 0x07 +#define PORT_DEFAULT_VLAN_MASK 0xfff +#define PORT_CONTROL_2 0x08 +#define PORT_CONTROL_2_IGNORE_FCS BIT(15) +#define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14) +#define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13) +#define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12) +#define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12) +#define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12) +#define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12) +#define PORT_CONTROL_2_8021Q_MASK (0x03 << 10) +#define PORT_CONTROL_2_8021Q_DISABLED (0x00 << 10) +#define PORT_CONTROL_2_8021Q_FALLBACK (0x01 << 10) +#define PORT_CONTROL_2_8021Q_CHECK (0x02 << 10) +#define PORT_CONTROL_2_8021Q_SECURE (0x03 << 10) +#define PORT_CONTROL_2_DISCARD_TAGGED BIT(9) +#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8) +#define PORT_CONTROL_2_MAP_DA BIT(7) +#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6) +#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5) +#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4) +#define PORT_CONTROL_2_UPSTREAM_MASK 0x0f +#define PORT_RATE_CONTROL 0x09 +#define PORT_RATE_CONTROL_2 0x0a +#define PORT_ASSOC_VECTOR 0x0b +#define PORT_ASSOC_VECTOR_HOLD_AT_1 BIT(15) +#define PORT_ASSOC_VECTOR_INT_AGE_OUT BIT(14) +#define PORT_ASSOC_VECTOR_LOCKED_PORT BIT(13) +#define PORT_ASSOC_VECTOR_IGNORE_WRONG BIT(12) +#define PORT_ASSOC_VECTOR_REFRESH_LOCKED BIT(11) +#define PORT_ATU_CONTROL 0x0c +#define PORT_PRI_OVERRIDE 0x0d +#define PORT_ETH_TYPE 0x0f +#define PORT_ETH_TYPE_DEFAULT 0x9100 +#define PORT_IN_DISCARD_LO 0x10 +#define PORT_IN_DISCARD_HI 0x11 +#define PORT_IN_FILTERED 0x12 +#define PORT_OUT_FILTERED 0x13 +#define PORT_TAG_REGMAP_0123 0x18 +#define PORT_TAG_REGMAP_4567 0x19 +#define PORT_IEEE_PRIO_MAP_TABLE 0x18 /* 6390 */ +#define PORT_IEEE_PRIO_MAP_TABLE_UPDATE BIT(15) +#define PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP (0x0 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP (0x1 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP (0x2 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP (0x3 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP (0x5 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP (0x6 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP (0x7 << 12) +#define PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9 + int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, u16 *val); int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, -- cgit v1.2.3 From e097097b2738ba7c6fa26629faa561021f03fa42 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 2 Jun 2017 17:06:18 -0400 Subject: net: dsa: mv88e6xxx: move the Global 1 macros Move the GLOBAL_* macros where they belong, in the related global1.h header. Include it in global2.c which uses GLOBAL_STATUS_IRQ_DEVICE. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.h | 141 ------------------------------------ drivers/net/dsa/mv88e6xxx/global1.h | 141 ++++++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/global2.c | 1 + 3 files changed, 142 insertions(+), 141 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index a7c71a43503b..7e558e9ba35d 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -33,147 +33,6 @@ #define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) #define SMI_DATA 0x01 -#define GLOBAL_STATUS 0x00 -#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ -#define GLOBAL_STATUS_PPU_STATE_MASK (0x3 << 14) /* 6165 6185 */ -#define GLOBAL_STATUS_PPU_STATE_DISABLED_RST (0x0 << 14) -#define GLOBAL_STATUS_PPU_STATE_INITIALIZING (0x1 << 14) -#define GLOBAL_STATUS_PPU_STATE_DISABLED (0x2 << 14) -#define GLOBAL_STATUS_PPU_STATE_POLLING (0x3 << 14) -#define GLOBAL_STATUS_INIT_READY BIT(11) -#define GLOBAL_STATUS_IRQ_AVB 8 -#define GLOBAL_STATUS_IRQ_DEVICE 7 -#define GLOBAL_STATUS_IRQ_STATS 6 -#define GLOBAL_STATUS_IRQ_VTU_PROBLEM 5 -#define GLOBAL_STATUS_IRQ_VTU_DONE 4 -#define GLOBAL_STATUS_IRQ_ATU_PROBLEM 3 -#define GLOBAL_STATUS_IRQ_ATU_DONE 2 -#define GLOBAL_STATUS_IRQ_TCAM_DONE 1 -#define GLOBAL_STATUS_IRQ_EEPROM_DONE 0 -#define GLOBAL_MAC_01 0x01 -#define GLOBAL_MAC_23 0x02 -#define GLOBAL_MAC_45 0x03 -#define GLOBAL_ATU_FID 0x01 -#define GLOBAL_VTU_FID 0x02 -#define GLOBAL_VTU_FID_MASK 0xfff -#define GLOBAL_VTU_SID 0x03 /* 6097 6165 6351 6352 */ -#define GLOBAL_VTU_SID_MASK 0x3f -#define GLOBAL_CONTROL 0x04 -#define GLOBAL_CONTROL_SW_RESET BIT(15) -#define GLOBAL_CONTROL_PPU_ENABLE BIT(14) -#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */ -#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */ -#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */ -#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */ -#define GLOBAL_CONTROL_DEVICE_EN BIT(7) -#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6) -#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5) -#define GLOBAL_CONTROL_VTU_DONE_EN BIT(4) -#define GLOBAL_CONTROL_ATU_PROBLEM_EN BIT(3) -#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) -#define GLOBAL_CONTROL_TCAM_EN BIT(1) -#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) -#define GLOBAL_VTU_OP 0x05 -#define GLOBAL_VTU_OP_BUSY BIT(15) -#define GLOBAL_VTU_OP_FLUSH_ALL ((0x01 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_VTU_LOAD_PURGE ((0x03 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_VTU_GET_NEXT ((0x04 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_STU_LOAD_PURGE ((0x05 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_STU_GET_NEXT ((0x06 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_VID 0x06 -#define GLOBAL_VTU_VID_MASK 0xfff -#define GLOBAL_VTU_VID_PAGE BIT(13) -#define GLOBAL_VTU_VID_VALID BIT(12) -#define GLOBAL_VTU_DATA_0_3 0x07 -#define GLOBAL_VTU_DATA_4_7 0x08 -#define GLOBAL_VTU_DATA_8_11 0x09 -#define GLOBAL_VTU_STU_DATA_MASK 0x03 -#define GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED 0x00 -#define GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED 0x01 -#define GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED 0x02 -#define GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER 0x03 -#define GLOBAL_STU_DATA_PORT_STATE_DISABLED 0x00 -#define GLOBAL_STU_DATA_PORT_STATE_BLOCKING 0x01 -#define GLOBAL_STU_DATA_PORT_STATE_LEARNING 0x02 -#define GLOBAL_STU_DATA_PORT_STATE_FORWARDING 0x03 -#define GLOBAL_ATU_CONTROL 0x0a -#define GLOBAL_ATU_CONTROL_LEARN2ALL BIT(3) -#define GLOBAL_ATU_OP 0x0b -#define GLOBAL_ATU_OP_BUSY BIT(15) -#define GLOBAL_ATU_OP_NOP (0 << 12) -#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC ((2 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_DATA 0x0c -#define GLOBAL_ATU_DATA_TRUNK BIT(15) -#define GLOBAL_ATU_DATA_TRUNK_ID_MASK 0x00f0 -#define GLOBAL_ATU_DATA_TRUNK_ID_SHIFT 4 -#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 -#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4 -#define GLOBAL_ATU_DATA_STATE_MASK 0x0f -#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 -#define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d -#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e -#define GLOBAL_ATU_DATA_STATE_UC_PRIO_OVER 0x0f -#define GLOBAL_ATU_DATA_STATE_MC_NONE_RATE 0x05 -#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 -#define GLOBAL_ATU_DATA_STATE_MC_MGMT 0x0e -#define GLOBAL_ATU_DATA_STATE_MC_PRIO_OVER 0x0f -#define GLOBAL_ATU_MAC_01 0x0d -#define GLOBAL_ATU_MAC_23 0x0e -#define GLOBAL_ATU_MAC_45 0x0f -#define GLOBAL_IP_PRI_0 0x10 -#define GLOBAL_IP_PRI_1 0x11 -#define GLOBAL_IP_PRI_2 0x12 -#define GLOBAL_IP_PRI_3 0x13 -#define GLOBAL_IP_PRI_4 0x14 -#define GLOBAL_IP_PRI_5 0x15 -#define GLOBAL_IP_PRI_6 0x16 -#define GLOBAL_IP_PRI_7 0x17 -#define GLOBAL_IEEE_PRI 0x18 -#define GLOBAL_CORE_TAG_TYPE 0x19 -#define GLOBAL_MONITOR_CONTROL 0x1a -#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12 -#define GLOBAL_MONITOR_CONTROL_INGRESS_MASK (0xf << 12) -#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8 -#define GLOBAL_MONITOR_CONTROL_EGRESS_MASK (0xf << 8) -#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4 -#define GLOBAL_MONITOR_CONTROL_ARP_MASK (0xf << 4) -#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0 -#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0) -#define GLOBAL_MONITOR_CONTROL_UPDATE BIT(15) -#define GLOBAL_MONITOR_CONTROL_0180C280000000XLO (0x00 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000000XHI (0x01 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000002XLO (0x02 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000002XHI (0x03 << 8) -#define GLOBAL_MONITOR_CONTROL_INGRESS (0x20 << 8) -#define GLOBAL_MONITOR_CONTROL_EGRESS (0x21 << 8) -#define GLOBAL_MONITOR_CONTROL_CPU_DEST (0x30 << 8) -#define GLOBAL_CONTROL_2 0x1c -#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000 -#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000 -#define GLOBAL_CONTROL_2_HIST_RX (0x1 << 6) -#define GLOBAL_CONTROL_2_HIST_TX (0x2 << 6) -#define GLOBAL_CONTROL_2_HIST_RX_TX (0x3 << 6) -#define GLOBAL_STATS_OP 0x1d -#define GLOBAL_STATS_OP_BUSY BIT(15) -#define GLOBAL_STATS_OP_NOP (0 << 12) -#define GLOBAL_STATS_OP_FLUSH_ALL ((1 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_FLUSH_PORT ((2 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_READ_CAPTURED ((4 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_CAPTURE_PORT ((5 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_BANK_1_BIT_9 BIT(9) -#define GLOBAL_STATS_OP_BANK_1_BIT_10 BIT(10) -#define GLOBAL_STATS_COUNTER_32 0x1e -#define GLOBAL_STATS_COUNTER_01 0x1f - #define GLOBAL2_INT_SOURCE 0x00 #define GLOBAL2_INT_SOURCE_WATCHDOG 15 #define GLOBAL2_INT_MASK 0x01 diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 3b8f356b348c..3e2765c53f89 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -17,6 +17,147 @@ #include "chip.h" +#define GLOBAL_STATUS 0x00 +#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ +#define GLOBAL_STATUS_PPU_STATE_MASK (0x3 << 14) /* 6165 6185 */ +#define GLOBAL_STATUS_PPU_STATE_DISABLED_RST (0x0 << 14) +#define GLOBAL_STATUS_PPU_STATE_INITIALIZING (0x1 << 14) +#define GLOBAL_STATUS_PPU_STATE_DISABLED (0x2 << 14) +#define GLOBAL_STATUS_PPU_STATE_POLLING (0x3 << 14) +#define GLOBAL_STATUS_INIT_READY BIT(11) +#define GLOBAL_STATUS_IRQ_AVB 8 +#define GLOBAL_STATUS_IRQ_DEVICE 7 +#define GLOBAL_STATUS_IRQ_STATS 6 +#define GLOBAL_STATUS_IRQ_VTU_PROBLEM 5 +#define GLOBAL_STATUS_IRQ_VTU_DONE 4 +#define GLOBAL_STATUS_IRQ_ATU_PROBLEM 3 +#define GLOBAL_STATUS_IRQ_ATU_DONE 2 +#define GLOBAL_STATUS_IRQ_TCAM_DONE 1 +#define GLOBAL_STATUS_IRQ_EEPROM_DONE 0 +#define GLOBAL_MAC_01 0x01 +#define GLOBAL_MAC_23 0x02 +#define GLOBAL_MAC_45 0x03 +#define GLOBAL_ATU_FID 0x01 +#define GLOBAL_VTU_FID 0x02 +#define GLOBAL_VTU_FID_MASK 0xfff +#define GLOBAL_VTU_SID 0x03 /* 6097 6165 6351 6352 */ +#define GLOBAL_VTU_SID_MASK 0x3f +#define GLOBAL_CONTROL 0x04 +#define GLOBAL_CONTROL_SW_RESET BIT(15) +#define GLOBAL_CONTROL_PPU_ENABLE BIT(14) +#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */ +#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */ +#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */ +#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */ +#define GLOBAL_CONTROL_DEVICE_EN BIT(7) +#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6) +#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5) +#define GLOBAL_CONTROL_VTU_DONE_EN BIT(4) +#define GLOBAL_CONTROL_ATU_PROBLEM_EN BIT(3) +#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) +#define GLOBAL_CONTROL_TCAM_EN BIT(1) +#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) +#define GLOBAL_VTU_OP 0x05 +#define GLOBAL_VTU_OP_BUSY BIT(15) +#define GLOBAL_VTU_OP_FLUSH_ALL ((0x01 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_VTU_LOAD_PURGE ((0x03 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_VTU_GET_NEXT ((0x04 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_STU_LOAD_PURGE ((0x05 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_OP_STU_GET_NEXT ((0x06 << 12) | GLOBAL_VTU_OP_BUSY) +#define GLOBAL_VTU_VID 0x06 +#define GLOBAL_VTU_VID_MASK 0xfff +#define GLOBAL_VTU_VID_PAGE BIT(13) +#define GLOBAL_VTU_VID_VALID BIT(12) +#define GLOBAL_VTU_DATA_0_3 0x07 +#define GLOBAL_VTU_DATA_4_7 0x08 +#define GLOBAL_VTU_DATA_8_11 0x09 +#define GLOBAL_VTU_STU_DATA_MASK 0x03 +#define GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED 0x00 +#define GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED 0x01 +#define GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED 0x02 +#define GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER 0x03 +#define GLOBAL_STU_DATA_PORT_STATE_DISABLED 0x00 +#define GLOBAL_STU_DATA_PORT_STATE_BLOCKING 0x01 +#define GLOBAL_STU_DATA_PORT_STATE_LEARNING 0x02 +#define GLOBAL_STU_DATA_PORT_STATE_FORWARDING 0x03 +#define GLOBAL_ATU_CONTROL 0x0a +#define GLOBAL_ATU_CONTROL_LEARN2ALL BIT(3) +#define GLOBAL_ATU_OP 0x0b +#define GLOBAL_ATU_OP_BUSY BIT(15) +#define GLOBAL_ATU_OP_NOP (0 << 12) +#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC ((2 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_DATA 0x0c +#define GLOBAL_ATU_DATA_TRUNK BIT(15) +#define GLOBAL_ATU_DATA_TRUNK_ID_MASK 0x00f0 +#define GLOBAL_ATU_DATA_TRUNK_ID_SHIFT 4 +#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 +#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4 +#define GLOBAL_ATU_DATA_STATE_MASK 0x0f +#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 +#define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d +#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e +#define GLOBAL_ATU_DATA_STATE_UC_PRIO_OVER 0x0f +#define GLOBAL_ATU_DATA_STATE_MC_NONE_RATE 0x05 +#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 +#define GLOBAL_ATU_DATA_STATE_MC_MGMT 0x0e +#define GLOBAL_ATU_DATA_STATE_MC_PRIO_OVER 0x0f +#define GLOBAL_ATU_MAC_01 0x0d +#define GLOBAL_ATU_MAC_23 0x0e +#define GLOBAL_ATU_MAC_45 0x0f +#define GLOBAL_IP_PRI_0 0x10 +#define GLOBAL_IP_PRI_1 0x11 +#define GLOBAL_IP_PRI_2 0x12 +#define GLOBAL_IP_PRI_3 0x13 +#define GLOBAL_IP_PRI_4 0x14 +#define GLOBAL_IP_PRI_5 0x15 +#define GLOBAL_IP_PRI_6 0x16 +#define GLOBAL_IP_PRI_7 0x17 +#define GLOBAL_IEEE_PRI 0x18 +#define GLOBAL_CORE_TAG_TYPE 0x19 +#define GLOBAL_MONITOR_CONTROL 0x1a +#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12 +#define GLOBAL_MONITOR_CONTROL_INGRESS_MASK (0xf << 12) +#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8 +#define GLOBAL_MONITOR_CONTROL_EGRESS_MASK (0xf << 8) +#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4 +#define GLOBAL_MONITOR_CONTROL_ARP_MASK (0xf << 4) +#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0 +#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0) +#define GLOBAL_MONITOR_CONTROL_UPDATE BIT(15) +#define GLOBAL_MONITOR_CONTROL_0180C280000000XLO (0x00 << 8) +#define GLOBAL_MONITOR_CONTROL_0180C280000000XHI (0x01 << 8) +#define GLOBAL_MONITOR_CONTROL_0180C280000002XLO (0x02 << 8) +#define GLOBAL_MONITOR_CONTROL_0180C280000002XHI (0x03 << 8) +#define GLOBAL_MONITOR_CONTROL_INGRESS (0x20 << 8) +#define GLOBAL_MONITOR_CONTROL_EGRESS (0x21 << 8) +#define GLOBAL_MONITOR_CONTROL_CPU_DEST (0x30 << 8) +#define GLOBAL_CONTROL_2 0x1c +#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000 +#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000 +#define GLOBAL_CONTROL_2_HIST_RX (0x1 << 6) +#define GLOBAL_CONTROL_2_HIST_TX (0x2 << 6) +#define GLOBAL_CONTROL_2_HIST_RX_TX (0x3 << 6) +#define GLOBAL_STATS_OP 0x1d +#define GLOBAL_STATS_OP_BUSY BIT(15) +#define GLOBAL_STATS_OP_NOP (0 << 12) +#define GLOBAL_STATS_OP_FLUSH_ALL ((1 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_FLUSH_PORT ((2 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_READ_CAPTURED ((4 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_CAPTURE_PORT ((5 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_BANK_1_BIT_9 BIT(9) +#define GLOBAL_STATS_OP_BANK_1_BIT_10 BIT(10) +#define GLOBAL_STATS_COUNTER_32 0x1e +#define GLOBAL_STATS_COUNTER_01 0x1f + int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val); int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val); int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask); diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 0defce71e381..538a8a27d912 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -17,6 +17,7 @@ #include #include "chip.h" +#include "global1.h" /* for GLOBAL_STATUS_IRQ_DEVICE */ #include "global2.h" #define ADDR_GLOBAL2 0x1c -- cgit v1.2.3 From d23a83f2ae4062bfefc2a1a701a1dcb5416b9c61 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 2 Jun 2017 17:06:19 -0400 Subject: net: dsa: mv88e6xxx: move the Global 2 macros Move the GLOBAL2_* macros where they belong, in the related global2.h header. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.h | 101 ----------------------------------- drivers/net/dsa/mv88e6xxx/global2.c | 2 - drivers/net/dsa/mv88e6xxx/global2.h | 103 ++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 7e558e9ba35d..98c24af977fd 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -33,107 +33,6 @@ #define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) #define SMI_DATA 0x01 -#define GLOBAL2_INT_SOURCE 0x00 -#define GLOBAL2_INT_SOURCE_WATCHDOG 15 -#define GLOBAL2_INT_MASK 0x01 -#define GLOBAL2_MGMT_EN_2X 0x02 -#define GLOBAL2_MGMT_EN_0X 0x03 -#define GLOBAL2_FLOW_CONTROL 0x04 -#define GLOBAL2_SWITCH_MGMT 0x05 -#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA BIT(15) -#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS BIT(14) -#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13) -#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7) -#define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3) -#define GLOBAL2_DEVICE_MAPPING 0x06 -#define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15) -#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8 -#define GLOBAL2_DEVICE_MAPPING_PORT_MASK 0x0f -#define GLOBAL2_TRUNK_MASK 0x07 -#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15) -#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12 -#define GLOBAL2_TRUNK_MASK_HASK BIT(11) -#define GLOBAL2_TRUNK_MAPPING 0x08 -#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) -#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 -#define GLOBAL2_IRL_CMD 0x09 -#define GLOBAL2_IRL_CMD_BUSY BIT(15) -#define GLOBAL2_IRL_CMD_OP_INIT_ALL ((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_INIT_SEL ((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_WRITE_SEL ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_READ_SEL ((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_DATA 0x0a -#define GLOBAL2_PVT_ADDR 0x0b -#define GLOBAL2_PVT_ADDR_BUSY BIT(15) -#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_DATA 0x0c -#define GLOBAL2_SWITCH_MAC 0x0d -#define GLOBAL2_ATU_STATS 0x0e -#define GLOBAL2_PRIO_OVERRIDE 0x0f -#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7) -#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 -#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) -#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 -#define GLOBAL2_EEPROM_CMD 0x14 -#define GLOBAL2_EEPROM_CMD_BUSY BIT(15) -#define GLOBAL2_EEPROM_CMD_OP_WRITE ((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_RUNNING BIT(11) -#define GLOBAL2_EEPROM_CMD_WRITE_EN BIT(10) -#define GLOBAL2_EEPROM_CMD_ADDR_MASK 0xff -#define GLOBAL2_EEPROM_DATA 0x15 -#define GLOBAL2_EEPROM_ADDR 0x15 /* 6390, 6341 */ -#define GLOBAL2_PTP_AVB_OP 0x16 -#define GLOBAL2_PTP_AVB_DATA 0x17 -#define GLOBAL2_SMI_PHY_CMD 0x18 -#define GLOBAL2_SMI_PHY_CMD_BUSY BIT(15) -#define GLOBAL2_SMI_PHY_CMD_EXTERNAL BIT(13) -#define GLOBAL2_SMI_PHY_CMD_MODE_22 BIT(12) -#define GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA ((0x1 << 10) | \ - GLOBAL2_SMI_PHY_CMD_MODE_22 | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA ((0x2 << 10) | \ - GLOBAL2_SMI_PHY_CMD_MODE_22 | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_ADDR ((0x0 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_DATA ((0x1 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_READ_DATA ((0x3 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) - -#define GLOBAL2_SMI_PHY_DATA 0x19 -#define GLOBAL2_SCRATCH_MISC 0x1a -#define GLOBAL2_SCRATCH_BUSY BIT(15) -#define GLOBAL2_SCRATCH_REGISTER_SHIFT 8 -#define GLOBAL2_SCRATCH_VALUE_MASK 0xff -#define GLOBAL2_WDOG_CONTROL 0x1b -#define GLOBAL2_WDOG_CONTROL_EGRESS_EVENT BIT(7) -#define GLOBAL2_WDOG_CONTROL_RMU_TIMEOUT BIT(6) -#define GLOBAL2_WDOG_CONTROL_QC_ENABLE BIT(5) -#define GLOBAL2_WDOG_CONTROL_EGRESS_HISTORY BIT(4) -#define GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE BIT(3) -#define GLOBAL2_WDOG_CONTROL_FORCE_IRQ BIT(2) -#define GLOBAL2_WDOG_CONTROL_HISTORY BIT(1) -#define GLOBAL2_WDOG_CONTROL_SWRESET BIT(0) -#define GLOBAL2_WDOG_UPDATE BIT(15) -#define GLOBAL2_WDOG_INT_SOURCE (0x00 << 8) -#define GLOBAL2_WDOG_INT_STATUS (0x10 << 8) -#define GLOBAL2_WDOG_INT_ENABLE (0x11 << 8) -#define GLOBAL2_WDOG_EVENT (0x12 << 8) -#define GLOBAL2_WDOG_HISTORY (0x13 << 8) -#define GLOBAL2_WDOG_DATA_MASK 0xff -#define GLOBAL2_WDOG_CUT_THROUGH BIT(3) -#define GLOBAL2_WDOG_QUEUE_CONTROLLER BIT(2) -#define GLOBAL2_WDOG_EGRESS BIT(1) -#define GLOBAL2_WDOG_FORCE_IRQ BIT(0) -#define GLOBAL2_QOS_WEIGHT 0x1c -#define GLOBAL2_MISC 0x1d -#define GLOBAL2_MISC_5_BIT_PORT BIT(14) - #define MV88E6XXX_N_FID 4096 /* PVT limits for 4-bit port and 5-bit switch */ diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 538a8a27d912..d63af31e7840 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -20,8 +20,6 @@ #include "global1.h" /* for GLOBAL_STATUS_IRQ_DEVICE */ #include "global2.h" -#define ADDR_GLOBAL2 0x1c - static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) { return mv88e6xxx_read(chip, ADDR_GLOBAL2, reg, val); diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index b5cfe041ee59..84a5ea69a4ac 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -17,6 +17,109 @@ #include "chip.h" +#define ADDR_GLOBAL2 0x1c + +#define GLOBAL2_INT_SOURCE 0x00 +#define GLOBAL2_INT_SOURCE_WATCHDOG 15 +#define GLOBAL2_INT_MASK 0x01 +#define GLOBAL2_MGMT_EN_2X 0x02 +#define GLOBAL2_MGMT_EN_0X 0x03 +#define GLOBAL2_FLOW_CONTROL 0x04 +#define GLOBAL2_SWITCH_MGMT 0x05 +#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA BIT(15) +#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS BIT(14) +#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13) +#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7) +#define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3) +#define GLOBAL2_DEVICE_MAPPING 0x06 +#define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15) +#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8 +#define GLOBAL2_DEVICE_MAPPING_PORT_MASK 0x0f +#define GLOBAL2_TRUNK_MASK 0x07 +#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15) +#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12 +#define GLOBAL2_TRUNK_MASK_HASK BIT(11) +#define GLOBAL2_TRUNK_MAPPING 0x08 +#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) +#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 +#define GLOBAL2_IRL_CMD 0x09 +#define GLOBAL2_IRL_CMD_BUSY BIT(15) +#define GLOBAL2_IRL_CMD_OP_INIT_ALL ((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_INIT_SEL ((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_WRITE_SEL ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_CMD_OP_READ_SEL ((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY) +#define GLOBAL2_IRL_DATA 0x0a +#define GLOBAL2_PVT_ADDR 0x0b +#define GLOBAL2_PVT_ADDR_BUSY BIT(15) +#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY) +#define GLOBAL2_PVT_DATA 0x0c +#define GLOBAL2_SWITCH_MAC 0x0d +#define GLOBAL2_ATU_STATS 0x0e +#define GLOBAL2_PRIO_OVERRIDE 0x0f +#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7) +#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 +#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) +#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 +#define GLOBAL2_EEPROM_CMD 0x14 +#define GLOBAL2_EEPROM_CMD_BUSY BIT(15) +#define GLOBAL2_EEPROM_CMD_OP_WRITE ((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY) +#define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY) +#define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY) +#define GLOBAL2_EEPROM_CMD_RUNNING BIT(11) +#define GLOBAL2_EEPROM_CMD_WRITE_EN BIT(10) +#define GLOBAL2_EEPROM_CMD_ADDR_MASK 0xff +#define GLOBAL2_EEPROM_DATA 0x15 +#define GLOBAL2_EEPROM_ADDR 0x15 /* 6390, 6341 */ +#define GLOBAL2_PTP_AVB_OP 0x16 +#define GLOBAL2_PTP_AVB_DATA 0x17 +#define GLOBAL2_SMI_PHY_CMD 0x18 +#define GLOBAL2_SMI_PHY_CMD_BUSY BIT(15) +#define GLOBAL2_SMI_PHY_CMD_EXTERNAL BIT(13) +#define GLOBAL2_SMI_PHY_CMD_MODE_22 BIT(12) +#define GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA ((0x1 << 10) | \ + GLOBAL2_SMI_PHY_CMD_MODE_22 | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA ((0x2 << 10) | \ + GLOBAL2_SMI_PHY_CMD_MODE_22 | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_ADDR ((0x0 << 10) | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_DATA ((0x1 << 10) | \ + GLOBAL2_SMI_PHY_CMD_BUSY) +#define GLOBAL2_SMI_PHY_CMD_OP_45_READ_DATA ((0x3 << 10) | \ + GLOBAL2_SMI_PHY_CMD_BUSY) + +#define GLOBAL2_SMI_PHY_DATA 0x19 +#define GLOBAL2_SCRATCH_MISC 0x1a +#define GLOBAL2_SCRATCH_BUSY BIT(15) +#define GLOBAL2_SCRATCH_REGISTER_SHIFT 8 +#define GLOBAL2_SCRATCH_VALUE_MASK 0xff +#define GLOBAL2_WDOG_CONTROL 0x1b +#define GLOBAL2_WDOG_CONTROL_EGRESS_EVENT BIT(7) +#define GLOBAL2_WDOG_CONTROL_RMU_TIMEOUT BIT(6) +#define GLOBAL2_WDOG_CONTROL_QC_ENABLE BIT(5) +#define GLOBAL2_WDOG_CONTROL_EGRESS_HISTORY BIT(4) +#define GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE BIT(3) +#define GLOBAL2_WDOG_CONTROL_FORCE_IRQ BIT(2) +#define GLOBAL2_WDOG_CONTROL_HISTORY BIT(1) +#define GLOBAL2_WDOG_CONTROL_SWRESET BIT(0) +#define GLOBAL2_WDOG_UPDATE BIT(15) +#define GLOBAL2_WDOG_INT_SOURCE (0x00 << 8) +#define GLOBAL2_WDOG_INT_STATUS (0x10 << 8) +#define GLOBAL2_WDOG_INT_ENABLE (0x11 << 8) +#define GLOBAL2_WDOG_EVENT (0x12 << 8) +#define GLOBAL2_WDOG_HISTORY (0x13 << 8) +#define GLOBAL2_WDOG_DATA_MASK 0xff +#define GLOBAL2_WDOG_CUT_THROUGH BIT(3) +#define GLOBAL2_WDOG_QUEUE_CONTROLLER BIT(2) +#define GLOBAL2_WDOG_EGRESS BIT(1) +#define GLOBAL2_WDOG_FORCE_IRQ BIT(0) +#define GLOBAL2_QOS_WEIGHT 0x1c +#define GLOBAL2_MISC 0x1d +#define GLOBAL2_MISC_5_BIT_PORT BIT(14) + #ifdef CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip) -- cgit v1.2.3 From ec8378bb4d8ebfaae035c0e949311f8efefc3a87 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 2 Jun 2017 23:22:45 +0200 Subject: net: dsa: mv88e6xxx: 6161 uses global 2 for PHY access Access to the internal PHYs of the 6161 and 6123 go through global 2 SMI registers. Fix the ops structure. Signed-off-by: Andrew Lunn Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 0176254cb3c7..5751723a0911 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2455,8 +2455,8 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { static const struct mv88e6xxx_ops mv88e6123_ops = { /* MV88E6XXX_FAMILY_6165 */ .set_switch_mac = mv88e6xxx_g2_set_switch_mac, - .phy_read = mv88e6165_phy_read, - .phy_write = mv88e6165_phy_write, + .phy_read = mv88e6xxx_g2_smi_phy_read, + .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, @@ -2544,8 +2544,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { static const struct mv88e6xxx_ops mv88e6161_ops = { /* MV88E6XXX_FAMILY_6165 */ .set_switch_mac = mv88e6xxx_g2_set_switch_mac, - .phy_read = mv88e6165_phy_read, - .phy_write = mv88e6165_phy_write, + .phy_read = mv88e6xxx_g2_smi_phy_read, + .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_speed = mv88e6185_port_set_speed, -- cgit v1.2.3 From 0ac64c39490041cb684350823803e6476815a3fb Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 2 Jun 2017 23:22:46 +0200 Subject: net: dsa: mv88e6xxx: mv88e6161 uses mv88e6320 stats snapshot The mv88e6161 was using the wrong method to perform statistics snapshot. Signed-off-by: Andrew Lunn Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 5751723a0911..117f275e3fb6 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2464,7 +2464,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, - .stats_snapshot = mv88e6xxx_g1_stats_snapshot, + .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, @@ -2558,7 +2558,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .port_pause_config = mv88e6097_port_pause_config, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, - .stats_snapshot = mv88e6xxx_g1_stats_snapshot, + .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, -- cgit v1.2.3 From 030a89028db07a7987f1f3bd6ee43114e36f5060 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 3 Jun 2017 20:00:36 +0200 Subject: net: phy: smsc: Implement PHY statistics Most of the PHYs supported by the SMSC driver have a counter of symbol errors. This is 16 bit wide and wraps around when it reaches its maximum value. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Reviewed-By: Woojung Huh Signed-off-by: David S. Miller --- drivers/net/phy/smsc.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 67c9f2b26c8e..1b8204be064c 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -25,6 +25,16 @@ #include #include +struct smsc_hw_stat { + const char *string; + u8 reg; + u8 bits; +}; + +static struct smsc_hw_stat smsc_hw_stats[] = { + { "phy_symbol_errors", 26, 16}, +}; + struct smsc_phy_priv { bool energy_enable; }; @@ -143,6 +153,48 @@ static int lan87xx_read_status(struct phy_device *phydev) return err; } +static int smsc_get_sset_count(struct phy_device *phydev) +{ + return ARRAY_SIZE(smsc_hw_stats); +} + +static void smsc_get_strings(struct phy_device *phydev, u8 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) { + memcpy(data + i * ETH_GSTRING_LEN, + smsc_hw_stats[i].string, ETH_GSTRING_LEN); + } +} + +#ifndef UINT64_MAX +#define UINT64_MAX (u64)(~((u64)0)) +#endif +static u64 smsc_get_stat(struct phy_device *phydev, int i) +{ + struct smsc_hw_stat stat = smsc_hw_stats[i]; + int val; + u64 ret; + + val = phy_read(phydev, stat.reg); + if (val < 0) + ret = UINT64_MAX; + else + ret = val; + + return ret; +} + +static void smsc_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) + data[i] = smsc_get_stat(phydev, i); +} + static int smsc_phy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -206,6 +258,11 @@ static struct phy_driver smsc_phy_driver[] = { .ack_interrupt = smsc_phy_ack_interrupt, .config_intr = smsc_phy_config_intr, + /* Statistics */ + .get_sset_count = smsc_get_sset_count, + .get_strings = smsc_get_strings, + .get_stats = smsc_get_stats, + .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -228,6 +285,11 @@ static struct phy_driver smsc_phy_driver[] = { .ack_interrupt = smsc_phy_ack_interrupt, .config_intr = smsc_phy_config_intr, + /* Statistics */ + .get_sset_count = smsc_get_sset_count, + .get_strings = smsc_get_strings, + .get_stats = smsc_get_stats, + .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -271,6 +333,11 @@ static struct phy_driver smsc_phy_driver[] = { .ack_interrupt = smsc_phy_ack_interrupt, .config_intr = smsc_phy_config_intr, + /* Statistics */ + .get_sset_count = smsc_get_sset_count, + .get_strings = smsc_get_strings, + .get_stats = smsc_get_stats, + .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -293,6 +360,11 @@ static struct phy_driver smsc_phy_driver[] = { .ack_interrupt = smsc_phy_ack_interrupt, .config_intr = smsc_phy_config_intr, + /* Statistics */ + .get_sset_count = smsc_get_sset_count, + .get_strings = smsc_get_strings, + .get_stats = smsc_get_stats, + .suspend = genphy_suspend, .resume = genphy_resume, } }; -- cgit v1.2.3 From cda7ea6903502af34015000e16be290a79f07638 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 4 Jun 2017 04:16:25 +0200 Subject: macsec: check return value of skb_to_sgvec always Signed-off-by: Jason A. Donenfeld Cc: Sabrina Dubroca Signed-off-by: David S. Miller --- drivers/net/macsec.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 91642fd87cd1..b79513b8322f 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -740,7 +740,12 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, macsec_fill_iv(iv, secy->sci, pn); sg_init_table(sg, ret); - skb_to_sgvec(skb, sg, 0, skb->len); + ret = skb_to_sgvec(skb, sg, 0, skb->len); + if (unlikely(ret < 0)) { + macsec_txsa_put(tx_sa); + kfree_skb(skb); + return ERR_PTR(ret); + } if (tx_sc->encrypt) { int len = skb->len - macsec_hdr_len(sci_present) - @@ -947,7 +952,11 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb, macsec_fill_iv(iv, sci, ntohl(hdr->packet_number)); sg_init_table(sg, ret); - skb_to_sgvec(skb, sg, 0, skb->len); + ret = skb_to_sgvec(skb, sg, 0, skb->len); + if (unlikely(ret < 0)) { + kfree_skb(skb); + return ERR_PTR(ret); + } if (hdr->tci_an & MACSEC_TCI_E) { /* confidentiality: ethernet + macsec header -- cgit v1.2.3 From e2fcad58fd230f635a74e4e983c6f4ea893642d2 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 4 Jun 2017 04:16:26 +0200 Subject: virtio_net: check return value of skb_to_sgvec always Signed-off-by: Jason A. Donenfeld Reviewed-by: Sergei Shtylyov Cc: "Michael S. Tsirkin" Cc: Jason Wang Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 3e9246cc49c3..57763d30cabb 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1150,7 +1150,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) struct virtio_net_hdr_mrg_rxbuf *hdr; const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; struct virtnet_info *vi = sq->vq->vdev->priv; - unsigned num_sg; + int num_sg; unsigned hdr_len = vi->hdr_len; bool can_push; @@ -1177,11 +1177,16 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) if (can_push) { __skb_push(skb, hdr_len); num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len); + if (unlikely(num_sg < 0)) + return num_sg; /* Pull header back to avoid skew in tx bytes calculations. */ __skb_pull(skb, hdr_len); } else { sg_set_buf(sq->sg, hdr, hdr_len); - num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1; + num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len); + if (unlikely(num_sg < 0)) + return num_sg; + num_sg++; } return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC); } -- cgit v1.2.3 From 6bea61da1716761c95cd32117be6004b0e14b4b2 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:30:59 +0300 Subject: qed: Add bitmaps for VF CIDs Each PF has a bitmap for its own ranges of CIDs, to allow easy grabbing of an available CID when such is needed. But VFs are not using the same mechanism, instead relying on hard-coded CIDs [ queue-index == cid ]. As an infrastructure step toward increasing number of CIDs of VFs, the PF is going to maintain bitmaps for the VF CIDs as well - the bitmaps would be per-VF and the ranges would be the same [in HW all VFs of a given PF have the same mapping of CIDs, and the HW is capable of distinguishing between those according to the VF index] Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 222 ++++++++++++++++++++++-------- drivers/net/ethernet/qlogic/qed/qed_cxt.h | 54 ++++++-- 2 files changed, 202 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 694845793af2..25d5b91f7928 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -135,7 +135,6 @@ struct qed_tid_seg { struct qed_conn_type_cfg { u32 cid_count; - u32 cid_start; u32 cids_per_vf; struct qed_tid_seg tid_seg[TASK_SEGMENTS]; }; @@ -222,6 +221,9 @@ struct qed_cxt_mngr { /* Acquired CIDs */ struct qed_cid_acquired_map acquired[MAX_CONN_TYPES]; + struct qed_cid_acquired_map + acquired_vf[MAX_CONN_TYPES][MAX_NUM_VFS]; + /* ILT shadow table */ struct qed_dma_mem *ilt_shadow; u32 pf_start_line; @@ -1121,45 +1123,76 @@ ilt_shadow_fail: static void qed_cid_map_free(struct qed_hwfn *p_hwfn) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; - u32 type; + u32 type, vf; for (type = 0; type < MAX_CONN_TYPES; type++) { kfree(p_mngr->acquired[type].cid_map); p_mngr->acquired[type].max_count = 0; p_mngr->acquired[type].start_cid = 0; + + for (vf = 0; vf < MAX_NUM_VFS; vf++) { + kfree(p_mngr->acquired_vf[type][vf].cid_map); + p_mngr->acquired_vf[type][vf].max_count = 0; + p_mngr->acquired_vf[type][vf].start_cid = 0; + } } } +static int +qed_cid_map_alloc_single(struct qed_hwfn *p_hwfn, + u32 type, + u32 cid_start, + u32 cid_count, struct qed_cid_acquired_map *p_map) +{ + u32 size; + + if (!cid_count) + return 0; + + size = DIV_ROUND_UP(cid_count, + sizeof(unsigned long) * BITS_PER_BYTE) * + sizeof(unsigned long); + p_map->cid_map = kzalloc(size, GFP_KERNEL); + if (!p_map->cid_map) + return -ENOMEM; + + p_map->max_count = cid_count; + p_map->start_cid = cid_start; + + DP_VERBOSE(p_hwfn, QED_MSG_CXT, + "Type %08x start: %08x count %08x\n", + type, p_map->start_cid, p_map->max_count); + + return 0; +} + static int qed_cid_map_alloc(struct qed_hwfn *p_hwfn) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; - u32 start_cid = 0; - u32 type; + u32 start_cid = 0, vf_start_cid = 0; + u32 type, vf; for (type = 0; type < MAX_CONN_TYPES; type++) { - u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count; - u32 size; + struct qed_conn_type_cfg *p_cfg = &p_mngr->conn_cfg[type]; + struct qed_cid_acquired_map *p_map; - if (cid_cnt == 0) - continue; - - size = DIV_ROUND_UP(cid_cnt, - sizeof(unsigned long) * BITS_PER_BYTE) * - sizeof(unsigned long); - p_mngr->acquired[type].cid_map = kzalloc(size, GFP_KERNEL); - if (!p_mngr->acquired[type].cid_map) + /* Handle PF maps */ + p_map = &p_mngr->acquired[type]; + if (qed_cid_map_alloc_single(p_hwfn, type, start_cid, + p_cfg->cid_count, p_map)) goto cid_map_fail; - p_mngr->acquired[type].max_count = cid_cnt; - p_mngr->acquired[type].start_cid = start_cid; - - p_hwfn->p_cxt_mngr->conn_cfg[type].cid_start = start_cid; + /* Handle VF maps */ + for (vf = 0; vf < MAX_NUM_VFS; vf++) { + p_map = &p_mngr->acquired_vf[type][vf]; + if (qed_cid_map_alloc_single(p_hwfn, type, + vf_start_cid, + p_cfg->cids_per_vf, p_map)) + goto cid_map_fail; + } - DP_VERBOSE(p_hwfn, QED_MSG_CXT, - "Type %08x start: %08x count %08x\n", - type, p_mngr->acquired[type].start_cid, - p_mngr->acquired[type].max_count); - start_cid += cid_cnt; + start_cid += p_cfg->cid_count; + vf_start_cid += p_cfg->cids_per_vf; } return 0; @@ -1265,19 +1298,36 @@ void qed_cxt_mngr_free(struct qed_hwfn *p_hwfn) void qed_cxt_mngr_setup(struct qed_hwfn *p_hwfn) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_cid_acquired_map *p_map; + struct qed_conn_type_cfg *p_cfg; int type; + u32 len; /* Reset acquired cids */ for (type = 0; type < MAX_CONN_TYPES; type++) { - u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count; + u32 vf; + + p_cfg = &p_mngr->conn_cfg[type]; + if (p_cfg->cid_count) { + p_map = &p_mngr->acquired[type]; + len = DIV_ROUND_UP(p_map->max_count, + sizeof(unsigned long) * + BITS_PER_BYTE) * + sizeof(unsigned long); + memset(p_map->cid_map, 0, len); + } - if (cid_cnt == 0) + if (!p_cfg->cids_per_vf) continue; - memset(p_mngr->acquired[type].cid_map, 0, - DIV_ROUND_UP(cid_cnt, - sizeof(unsigned long) * BITS_PER_BYTE) * - sizeof(unsigned long)); + for (vf = 0; vf < MAX_NUM_VFS; vf++) { + p_map = &p_mngr->acquired_vf[type][vf]; + len = DIV_ROUND_UP(p_map->max_count, + sizeof(unsigned long) * + BITS_PER_BYTE) * + sizeof(unsigned long); + memset(p_map->cid_map, 0, len); + } } } @@ -1841,91 +1891,145 @@ void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) qed_prs_init_pf(p_hwfn); } -int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, - enum protocol_type type, u32 *p_cid) +int _qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, u32 *p_cid, u8 vfid) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_cid_acquired_map *p_map; u32 rel_cid; - if (type >= MAX_CONN_TYPES || !p_mngr->acquired[type].cid_map) { + if (type >= MAX_CONN_TYPES) { + DP_NOTICE(p_hwfn, "Invalid protocol type %d", type); + return -EINVAL; + } + + if (vfid >= MAX_NUM_VFS && vfid != QED_CXT_PF_CID) { + DP_NOTICE(p_hwfn, "VF [%02x] is out of range\n", vfid); + return -EINVAL; + } + + /* Determine the right map to take this CID from */ + if (vfid == QED_CXT_PF_CID) + p_map = &p_mngr->acquired[type]; + else + p_map = &p_mngr->acquired_vf[type][vfid]; + + if (!p_map->cid_map) { DP_NOTICE(p_hwfn, "Invalid protocol type %d", type); return -EINVAL; } - rel_cid = find_first_zero_bit(p_mngr->acquired[type].cid_map, - p_mngr->acquired[type].max_count); + rel_cid = find_first_zero_bit(p_map->cid_map, p_map->max_count); - if (rel_cid >= p_mngr->acquired[type].max_count) { + if (rel_cid >= p_map->max_count) { DP_NOTICE(p_hwfn, "no CID available for protocol %d\n", type); return -EINVAL; } - __set_bit(rel_cid, p_mngr->acquired[type].cid_map); + __set_bit(rel_cid, p_map->cid_map); + + *p_cid = rel_cid + p_map->start_cid; - *p_cid = rel_cid + p_mngr->acquired[type].start_cid; + DP_VERBOSE(p_hwfn, QED_MSG_CXT, + "Acquired cid 0x%08x [rel. %08x] vfid %02x type %d\n", + *p_cid, rel_cid, vfid, type); return 0; } +int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, u32 *p_cid) +{ + return _qed_cxt_acquire_cid(p_hwfn, type, p_cid, QED_CXT_PF_CID); +} + static bool qed_cxt_test_cid_acquired(struct qed_hwfn *p_hwfn, - u32 cid, enum protocol_type *p_type) + u32 cid, + u8 vfid, + enum protocol_type *p_type, + struct qed_cid_acquired_map **pp_map) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; - struct qed_cid_acquired_map *p_map; - enum protocol_type p; u32 rel_cid; /* Iterate over protocols and find matching cid range */ - for (p = 0; p < MAX_CONN_TYPES; p++) { - p_map = &p_mngr->acquired[p]; + for (*p_type = 0; *p_type < MAX_CONN_TYPES; (*p_type)++) { + if (vfid == QED_CXT_PF_CID) + *pp_map = &p_mngr->acquired[*p_type]; + else + *pp_map = &p_mngr->acquired_vf[*p_type][vfid]; - if (!p_map->cid_map) + if (!((*pp_map)->cid_map)) continue; - if (cid >= p_map->start_cid && - cid < p_map->start_cid + p_map->max_count) + if (cid >= (*pp_map)->start_cid && + cid < (*pp_map)->start_cid + (*pp_map)->max_count) break; } - *p_type = p; - if (p == MAX_CONN_TYPES) { - DP_NOTICE(p_hwfn, "Invalid CID %d", cid); - return false; + if (*p_type == MAX_CONN_TYPES) { + DP_NOTICE(p_hwfn, "Invalid CID %d vfid %02x", cid, vfid); + goto fail; } - rel_cid = cid - p_map->start_cid; - if (!test_bit(rel_cid, p_map->cid_map)) { - DP_NOTICE(p_hwfn, "CID %d not acquired", cid); - return false; + rel_cid = cid - (*pp_map)->start_cid; + if (!test_bit(rel_cid, (*pp_map)->cid_map)) { + DP_NOTICE(p_hwfn, "CID %d [vifd %02x] not acquired", + cid, vfid); + goto fail; } + return true; +fail: + *p_type = MAX_CONN_TYPES; + *pp_map = NULL; + return false; } -void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid) +void _qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid, u8 vfid) { - struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_cid_acquired_map *p_map = NULL; enum protocol_type type; bool b_acquired; u32 rel_cid; + if (vfid != QED_CXT_PF_CID && vfid > MAX_NUM_VFS) { + DP_NOTICE(p_hwfn, + "Trying to return incorrect CID belonging to VF %02x\n", + vfid); + return; + } + /* Test acquired and find matching per-protocol map */ - b_acquired = qed_cxt_test_cid_acquired(p_hwfn, cid, &type); + b_acquired = qed_cxt_test_cid_acquired(p_hwfn, cid, vfid, + &type, &p_map); if (!b_acquired) return; - rel_cid = cid - p_mngr->acquired[type].start_cid; - __clear_bit(rel_cid, p_mngr->acquired[type].cid_map); + rel_cid = cid - p_map->start_cid; + clear_bit(rel_cid, p_map->cid_map); + + DP_VERBOSE(p_hwfn, QED_MSG_CXT, + "Released CID 0x%08x [rel. %08x] vfid %02x type %d\n", + cid, rel_cid, vfid, type); +} + +void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid) +{ + _qed_cxt_release_cid(p_hwfn, cid, QED_CXT_PF_CID); } int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn, struct qed_cxt_info *p_info) { struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr; + struct qed_cid_acquired_map *p_map = NULL; u32 conn_cxt_size, hw_p_size, cxts_per_p, line; enum protocol_type type; bool b_acquired; /* Test acquired and find matching per-protocol map */ - b_acquired = qed_cxt_test_cid_acquired(p_hwfn, p_info->iid, &type); + b_acquired = qed_cxt_test_cid_acquired(p_hwfn, p_info->iid, + QED_CXT_PF_CID, &type, &p_map); if (!b_acquired) return -EINVAL; diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.h b/drivers/net/ethernet/qlogic/qed/qed_cxt.h index 53ad532dc212..17836349a274 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.h +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.h @@ -53,19 +53,6 @@ struct qed_tid_mem { u8 *blocks[MAX_TID_BLOCKS]; /* 4K */ }; -/** - * @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type - * - * @param p_hwfn - * @param type - * @param p_cid - * - * @return int - */ -int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, - enum protocol_type type, - u32 *p_cid); - /** * @brief qedo_cid_get_cxt_info - Returns the context info for a specific cid * @@ -195,14 +182,51 @@ void qed_qm_init_pf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); */ int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +#define QED_CXT_PF_CID (0xff) + /** * @brief qed_cxt_release - Release a cid * * @param p_hwfn * @param cid */ -void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, - u32 cid); +void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid); + +/** + * @brief qed_cxt_release - Release a cid belonging to a vf-queue + * + * @param p_hwfn + * @param cid + * @param vfid - engine relative index. QED_CXT_PF_CID if belongs to PF + */ +void _qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid, u8 vfid); + +/** + * @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type + * + * @param p_hwfn + * @param type + * @param p_cid + * + * @return int + */ +int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, u32 *p_cid); + +/** + * @brief _qed_cxt_acquire - Acquire a new cid of a specific protocol type + * for a vf-queue + * + * @param p_hwfn + * @param type + * @param p_cid + * @param vfid - engine relative index. QED_CXT_PF_CID if belongs to PF + * + * @return int + */ +int _qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn, + enum protocol_type type, u32 *p_cid, u8 vfid); + int qed_cxt_dynamic_ilt_alloc(struct qed_hwfn *p_hwfn, enum qed_cxt_elem_type elem_type, u32 iid); u32 qed_cxt_get_proto_tid_count(struct qed_hwfn *p_hwfn, -- cgit v1.2.3 From 0db711bb26209992da375730eab6b3cec1edee7a Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:00 +0300 Subject: qed: Create L2 queue database First step in allowing a single PF/VF to open multiple queues on the same queue zone is to add per-hwfn database of queue-cids as a two-dimensional array where entry would be according to [queue zone][internal index]. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 3 ++ drivers/net/ethernet/qlogic/qed/qed_dev.c | 24 +++++++-- drivers/net/ethernet/qlogic/qed/qed_l2.c | 86 +++++++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_l2.h | 6 +++ drivers/net/ethernet/qlogic/qed/qed_vf.c | 5 ++ drivers/net/ethernet/qlogic/qed/qed_vf.h | 12 +++++ 6 files changed, 133 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index ffc080795be7..cfb575859cc6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -533,6 +533,9 @@ struct qed_hwfn { u8 dcbx_no_edpm; u8 db_bar_no_edpm; + /* L2-related */ + struct qed_l2_info *p_l2_info; + struct qed_ptt *p_arfs_ptt; struct qed_simd_fp_handler simd_proto_handler[64]; diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 2d88d4883483..e983113d4558 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -154,8 +154,11 @@ void qed_resc_free(struct qed_dev *cdev) { int i; - if (IS_VF(cdev)) + if (IS_VF(cdev)) { + for_each_hwfn(cdev, i) + qed_l2_free(&cdev->hwfns[i]); return; + } kfree(cdev->fw_data); cdev->fw_data = NULL; @@ -183,6 +186,7 @@ void qed_resc_free(struct qed_dev *cdev) qed_ooo_free(p_hwfn); } qed_iov_free(p_hwfn); + qed_l2_free(p_hwfn); qed_dmae_info_free(p_hwfn); qed_dcbx_info_free(p_hwfn); } @@ -848,8 +852,14 @@ int qed_resc_alloc(struct qed_dev *cdev) u32 line_count; int i, rc = 0; - if (IS_VF(cdev)) + if (IS_VF(cdev)) { + for_each_hwfn(cdev, i) { + rc = qed_l2_alloc(&cdev->hwfns[i]); + if (rc) + return rc; + } return rc; + } cdev->fw_data = kzalloc(sizeof(*cdev->fw_data), GFP_KERNEL); if (!cdev->fw_data) @@ -960,6 +970,10 @@ int qed_resc_alloc(struct qed_dev *cdev) if (rc) goto alloc_err; + rc = qed_l2_alloc(p_hwfn); + if (rc) + goto alloc_err; + #ifdef CONFIG_QED_LL2 if (p_hwfn->using_ll2) { rc = qed_ll2_alloc(p_hwfn); @@ -1011,8 +1025,11 @@ void qed_resc_setup(struct qed_dev *cdev) { int i; - if (IS_VF(cdev)) + if (IS_VF(cdev)) { + for_each_hwfn(cdev, i) + qed_l2_setup(&cdev->hwfns[i]); return; + } for_each_hwfn(cdev, i) { struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; @@ -1030,6 +1047,7 @@ void qed_resc_setup(struct qed_dev *cdev) qed_int_setup(p_hwfn, p_hwfn->p_main_ptt); + qed_l2_setup(p_hwfn); qed_iov_setup(p_hwfn); #ifdef CONFIG_QED_LL2 if (p_hwfn->using_ll2) diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 93dd781cf61d..9d5791155fcf 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -65,6 +65,92 @@ #define QED_MAX_SGES_NUM 16 #define CRC32_POLY 0x1edc6f41 +struct qed_l2_info { + u32 queues; + unsigned long **pp_qid_usage; + + /* The lock is meant to synchronize access to the qid usage */ + struct mutex lock; +}; + +int qed_l2_alloc(struct qed_hwfn *p_hwfn) +{ + struct qed_l2_info *p_l2_info; + unsigned long **pp_qids; + u32 i; + + if (p_hwfn->hw_info.personality != QED_PCI_ETH && + p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + return 0; + + p_l2_info = kzalloc(sizeof(*p_l2_info), GFP_KERNEL); + if (!p_l2_info) + return -ENOMEM; + p_hwfn->p_l2_info = p_l2_info; + + if (IS_PF(p_hwfn->cdev)) { + p_l2_info->queues = RESC_NUM(p_hwfn, QED_L2_QUEUE); + } else { + u8 rx = 0, tx = 0; + + qed_vf_get_num_rxqs(p_hwfn, &rx); + qed_vf_get_num_txqs(p_hwfn, &tx); + + p_l2_info->queues = max_t(u8, rx, tx); + } + + pp_qids = kzalloc(sizeof(unsigned long *) * p_l2_info->queues, + GFP_KERNEL); + if (!pp_qids) + return -ENOMEM; + p_l2_info->pp_qid_usage = pp_qids; + + for (i = 0; i < p_l2_info->queues; i++) { + pp_qids[i] = kzalloc(MAX_QUEUES_PER_QZONE / 8, GFP_KERNEL); + if (!pp_qids[i]) + return -ENOMEM; + } + + return 0; +} + +void qed_l2_setup(struct qed_hwfn *p_hwfn) +{ + if (p_hwfn->hw_info.personality != QED_PCI_ETH && + p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + return; + + mutex_init(&p_hwfn->p_l2_info->lock); +} + +void qed_l2_free(struct qed_hwfn *p_hwfn) +{ + u32 i; + + if (p_hwfn->hw_info.personality != QED_PCI_ETH && + p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + return; + + if (!p_hwfn->p_l2_info) + return; + + if (!p_hwfn->p_l2_info->pp_qid_usage) + goto out_l2_info; + + /* Free until hit first uninitialized entry */ + for (i = 0; i < p_hwfn->p_l2_info->queues; i++) { + if (!p_hwfn->p_l2_info->pp_qid_usage[i]) + break; + kfree(p_hwfn->p_l2_info->pp_qid_usage[i]); + } + + kfree(p_hwfn->p_l2_info->pp_qid_usage); + +out_l2_info: + kfree(p_hwfn->p_l2_info); + p_hwfn->p_l2_info = NULL; +} + void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid) { diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h b/drivers/net/ethernet/qlogic/qed/qed_l2.h index 6f44229899eb..8606bbfa6612 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h @@ -277,6 +277,8 @@ void qed_get_vport_stats(struct qed_dev *cdev, struct qed_eth_stats *stats); void qed_reset_vport_stats(struct qed_dev *cdev); +#define MAX_QUEUES_PER_QZONE (sizeof(unsigned long) * 8) + struct qed_queue_cid { /* 'Relative' is a relative term ;-). Usually the indices [not counting * SBs] would be PF-relative, but there are some cases where that isn't @@ -302,6 +304,10 @@ struct qed_queue_cid { struct qed_hwfn *p_owner; }; +int qed_l2_alloc(struct qed_hwfn *p_hwfn); +void qed_l2_setup(struct qed_hwfn *p_hwfn); +void qed_l2_free(struct qed_hwfn *p_hwfn); + void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid); diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index 3703b22a3973..29d74074238f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -1363,6 +1363,11 @@ void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs) *num_rxqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_rxqs; } +void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs) +{ + *num_txqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_txqs; +} + void qed_vf_get_port_mac(struct qed_hwfn *p_hwfn, u8 *port_mac) { memcpy(port_mac, diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index 67862085f032..d7b9c90b2f60 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h @@ -683,6 +683,14 @@ void qed_vf_get_link_caps(struct qed_hwfn *p_hwfn, */ void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs); +/** + * @brief Get number of Rx queues allocated for VF by qed + * + * @param p_hwfn + * @param num_txqs - allocated RX queues + */ +void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs); + /** * @brief Get port mac address for VF * @@ -956,6 +964,10 @@ static inline void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs) { } +static inline void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs) +{ +} + static inline void qed_vf_get_port_mac(struct qed_hwfn *p_hwfn, u8 *port_mac) { } -- cgit v1.2.3 From f604b17d7fdef574792a7e0b39f1b926d6b43d9d Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:01 +0300 Subject: qed*: L2 interface to use the SB structures directly Part of an effort of a cleaner seperation between qed and the protocol drivers, the L2 interface is to use the SB structure for initialization purposes opaquely. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_l2.c | 32 +++++++++++++++------------- drivers/net/ethernet/qlogic/qed/qed_l2.h | 24 +++++++++++++++------ drivers/net/ethernet/qlogic/qed/qed_sriov.c | 13 +++++++++-- drivers/net/ethernet/qlogic/qed/qed_vf.c | 8 +++---- drivers/net/ethernet/qlogic/qede/qede_main.c | 4 ++-- 5 files changed, 51 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 9d5791155fcf..262b2ba13e79 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -182,9 +182,15 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, p_cid->opaque_fid = opaque_fid; p_cid->cid = cid; p_cid->vf_qid = vf_qid; - p_cid->rel = *p_params; p_cid->p_owner = p_hwfn; + /* Fill in parameters */ + p_cid->rel.vport_id = p_params->vport_id; + p_cid->rel.queue_id = p_params->queue_id; + p_cid->rel.stats_id = p_params->stats_id; + p_cid->sb_igu_id = p_params->p_sb->igu_sb_id; + p_cid->sb_idx = p_params->sb_idx; + /* Don't try calculating the absolute indices for VFs */ if (IS_VF(p_hwfn->cdev)) { p_cid->abs = p_cid->rel; @@ -215,10 +221,6 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, p_cid->abs.stats_id = p_cid->rel.stats_id; } - /* SBs relevant information was already provided as absolute */ - p_cid->abs.sb = p_cid->rel.sb; - p_cid->abs.sb_idx = p_cid->rel.sb_idx; - /* This is tricky - we're actually interested in whehter this is a PF * entry meant for the VF. */ @@ -235,7 +237,7 @@ out: p_cid->rel.queue_id, p_cid->abs.queue_id, p_cid->rel.stats_id, - p_cid->abs.stats_id, p_cid->abs.sb, p_cid->abs.sb_idx); + p_cid->abs.stats_id, p_cid->sb_igu_id, p_cid->sb_idx); return p_cid; @@ -767,7 +769,7 @@ int qed_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn, DP_VERBOSE(p_hwfn, QED_MSG_SP, "opaque_fid=0x%x, cid=0x%x, rx_qzone=0x%x, vport_id=0x%x, sb_id=0x%x\n", p_cid->opaque_fid, p_cid->cid, - p_cid->abs.queue_id, p_cid->abs.vport_id, p_cid->abs.sb); + p_cid->abs.queue_id, p_cid->abs.vport_id, p_cid->sb_igu_id); /* Get SPQ entry */ memset(&init_data, 0, sizeof(init_data)); @@ -783,8 +785,8 @@ int qed_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn, p_ramrod = &p_ent->ramrod.rx_queue_start; - p_ramrod->sb_id = cpu_to_le16(p_cid->abs.sb); - p_ramrod->sb_index = p_cid->abs.sb_idx; + p_ramrod->sb_id = cpu_to_le16(p_cid->sb_igu_id); + p_ramrod->sb_index = p_cid->sb_idx; p_ramrod->vport_id = p_cid->abs.vport_id; p_ramrod->stats_counter_id = p_cid->abs.stats_id; p_ramrod->rx_queue_id = cpu_to_le16(p_cid->abs.queue_id); @@ -1001,8 +1003,8 @@ qed_eth_txq_start_ramrod(struct qed_hwfn *p_hwfn, p_ramrod = &p_ent->ramrod.tx_queue_start; p_ramrod->vport_id = p_cid->abs.vport_id; - p_ramrod->sb_id = cpu_to_le16(p_cid->abs.sb); - p_ramrod->sb_index = p_cid->abs.sb_idx; + p_ramrod->sb_id = cpu_to_le16(p_cid->sb_igu_id); + p_ramrod->sb_index = p_cid->sb_idx; p_ramrod->stats_counter_id = p_cid->abs.stats_id; p_ramrod->queue_zone_id = cpu_to_le16(p_cid->abs.queue_id); @@ -2279,9 +2281,9 @@ static int qed_start_rxq(struct qed_dev *cdev, } DP_VERBOSE(cdev, (QED_MSG_SPQ | NETIF_MSG_IFUP), - "Started RX-Q %d [rss_num %d] on V-PORT %d and SB %d\n", + "Started RX-Q %d [rss_num %d] on V-PORT %d and SB igu %d\n", p_params->queue_id, rss_num, p_params->vport_id, - p_params->sb); + p_params->p_sb->igu_sb_id); return 0; } @@ -2329,9 +2331,9 @@ static int qed_start_txq(struct qed_dev *cdev, } DP_VERBOSE(cdev, (QED_MSG_SPQ | NETIF_MSG_IFUP), - "Started TX-Q %d [rss_num %d] on V-PORT %d and SB %d\n", + "Started TX-Q %d [rss_num %d] on V-PORT %d and SB igu %d\n", p_params->queue_id, rss_num, p_params->vport_id, - p_params->sb); + p_params->p_sb->igu_sb_id); return 0; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h b/drivers/net/ethernet/qlogic/qed/qed_l2.h index 8606bbfa6612..6ad36449dae9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h @@ -279,14 +279,24 @@ void qed_reset_vport_stats(struct qed_dev *cdev); #define MAX_QUEUES_PER_QZONE (sizeof(unsigned long) * 8) +/* Almost identical to the qed_queue_start_common_params, + * but here we maintain the SB index in IGU CAM. + */ +struct qed_queue_cid_params { + u8 vport_id; + u16 queue_id; + u8 stats_id; +}; + struct qed_queue_cid { - /* 'Relative' is a relative term ;-). Usually the indices [not counting - * SBs] would be PF-relative, but there are some cases where that isn't - * the case - specifically for a PF configuring its VF indices it's - * possible some fields [E.g., stats-id] in 'rel' would already be abs. - */ - struct qed_queue_start_common_params rel; - struct qed_queue_start_common_params abs; + /* For stats-id, the `rel' is actually absolute as well */ + struct qed_queue_cid_params rel; + struct qed_queue_cid_params abs; + + /* These have no 'relative' meaning */ + u16 sb_igu_id; + u8 sb_idx; + u32 cid; u16 opaque_fid; diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 5ae8827534f8..498c83ebc385 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -1951,6 +1951,7 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, u8 status = PFVF_STATUS_NO_RESOURCE; struct qed_vf_q_info *p_queue; struct vfpf_start_rxq_tlv *req; + struct qed_sb_info sb_dummy; bool b_legacy_vf = false; int rc; @@ -1968,7 +1969,10 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, params.queue_id = p_queue->fw_rx_qid; params.vport_id = vf->vport_id; params.stats_id = vf->abs_vf_id + 0x10; - params.sb = req->hw_sb; + /* Since IGU index is passed via sb_info, construct a dummy one */ + memset(&sb_dummy, 0, sizeof(sb_dummy)); + sb_dummy.igu_sb_id = req->hw_sb; + params.p_sb = &sb_dummy; params.sb_idx = req->sb_index; p_queue->p_rx_cid = _qed_eth_queue_to_cid(p_hwfn, @@ -2273,6 +2277,7 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, u8 status = PFVF_STATUS_NO_RESOURCE; struct vfpf_start_txq_tlv *req; struct qed_vf_q_info *p_queue; + struct qed_sb_info sb_dummy; int rc; u16 pq; @@ -2290,7 +2295,11 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, params.queue_id = p_queue->fw_tx_qid; params.vport_id = vf->vport_id; params.stats_id = vf->abs_vf_id + 0x10; - params.sb = req->hw_sb; + + /* Since IGU index is passed via sb_info, construct a dummy one */ + memset(&sb_dummy, 0, sizeof(sb_dummy)); + sb_dummy.igu_sb_id = req->hw_sb; + params.p_sb = &sb_dummy; params.sb_idx = req->sb_index; p_queue->p_tx_cid = _qed_eth_queue_to_cid(p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index 29d74074238f..877d41e456e4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -588,8 +588,8 @@ qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn, req->cqe_pbl_addr = cqe_pbl_addr; req->cqe_pbl_size = cqe_pbl_size; req->rxq_addr = bd_chain_phys_addr; - req->hw_sb = p_cid->rel.sb; - req->sb_index = p_cid->rel.sb_idx; + req->hw_sb = p_cid->sb_igu_id; + req->sb_index = p_cid->sb_idx; req->bd_max_bytes = bd_max_bytes; req->stat_id = -1; @@ -697,8 +697,8 @@ qed_vf_pf_txq_start(struct qed_hwfn *p_hwfn, /* Tx */ req->pbl_addr = pbl_addr; req->pbl_size = pbl_size; - req->hw_sb = p_cid->rel.sb; - req->sb_index = p_cid->rel.sb_idx; + req->hw_sb = p_cid->sb_igu_id; + req->sb_index = p_cid->sb_idx; /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 00c70625f8a4..ad1e24962bdb 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1770,7 +1770,7 @@ static int qede_start_txq(struct qede_dev *edev, else params.queue_id = txq->index; - params.sb = fp->sb_info->igu_sb_id; + params.p_sb = fp->sb_info; params.sb_idx = sb_idx; rc = edev->ops->q_tx_start(edev->cdev, rss_id, ¶ms, phys_table, @@ -1849,7 +1849,7 @@ static int qede_start_queues(struct qede_dev *edev, bool clear_stats) memset(&q_params, 0, sizeof(q_params)); q_params.queue_id = rxq->rxq_id; q_params.vport_id = 0; - q_params.sb = fp->sb_info->igu_sb_id; + q_params.p_sb = fp->sb_info; q_params.sb_idx = RX_PI; p_phys_table = -- cgit v1.2.3 From 3946497aff655b9bb1807ef7e2ecbe799e6d832a Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:02 +0300 Subject: qed: Pass vf_params when creating a queue-cid We're going to need additional information for queue-cids that a PF creates for its VFs, so start by refactoring existing logic used for initializing said struct into receiving a structure encapsulating the VF-specific information that needs to be provided. This also introduces QED_QUEUE_CID_SELF - each queue-cid would hold an indication to whether it belongs to the hw-function holding it [whether that's a PF or a VF], or else what's the VF id it belongs to. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_l2.c | 67 ++++++++++++++++++----------- drivers/net/ethernet/qlogic/qed/qed_l2.h | 33 +++++++++++--- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 40 +++++++++++------ 3 files changed, 95 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 262b2ba13e79..150a8e9354b7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -155,7 +155,8 @@ void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid) { /* VFs' CIDs are 0-based in PF-view, and uninitialized on VF */ - if (!p_cid->is_vf && IS_PF(p_hwfn->cdev)) + if ((p_cid->vfid == QED_QUEUE_CID_SELF) && + IS_PF(p_hwfn->cdev)) qed_cxt_release_cid(p_hwfn, p_cid->cid); vfree(p_cid); } @@ -163,14 +164,13 @@ void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, /* The internal is only meant to be directly called by PFs initializeing CIDs * for their VFs. */ -struct qed_queue_cid * +static struct qed_queue_cid * _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, u16 opaque_fid, u32 cid, - u8 vf_qid, - struct qed_queue_start_common_params *p_params) + struct qed_queue_start_common_params *p_params, + struct qed_queue_cid_vf_params *p_vf_params) { - bool b_is_same = (p_hwfn->hw_info.opaque_fid == opaque_fid); struct qed_queue_cid *p_cid; int rc; @@ -181,7 +181,6 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, p_cid->opaque_fid = opaque_fid; p_cid->cid = cid; - p_cid->vf_qid = vf_qid; p_cid->p_owner = p_hwfn; /* Fill in parameters */ @@ -191,6 +190,15 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, p_cid->sb_igu_id = p_params->p_sb->igu_sb_id; p_cid->sb_idx = p_params->sb_idx; + /* Fill-in bits related to VFs' queues if information was provided */ + if (p_vf_params) { + p_cid->vfid = p_vf_params->vfid; + p_cid->vf_qid = p_vf_params->vf_qid; + p_cid->b_legacy_vf = p_vf_params->vf_legacy; + } else { + p_cid->vfid = QED_QUEUE_CID_SELF; + } + /* Don't try calculating the absolute indices for VFs */ if (IS_VF(p_hwfn->cdev)) { p_cid->abs = p_cid->rel; @@ -212,7 +220,7 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, /* In case of a PF configuring its VF's queues, the stats-id is already * absolute [since there's a single index that's suitable per-VF]. */ - if (b_is_same) { + if (p_cid->vfid == QED_QUEUE_CID_SELF) { rc = qed_fw_vport(p_hwfn, p_cid->rel.stats_id, &p_cid->abs.stats_id); if (rc) @@ -221,11 +229,6 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, p_cid->abs.stats_id = p_cid->rel.stats_id; } - /* This is tricky - we're actually interested in whehter this is a PF - * entry meant for the VF. - */ - if (!b_is_same) - p_cid->is_vf = true; out: DP_VERBOSE(p_hwfn, QED_MSG_SP, @@ -246,32 +249,47 @@ fail: return NULL; } -static struct qed_queue_cid *qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, - u16 opaque_fid, struct - qed_queue_start_common_params - *p_params) +struct qed_queue_cid * +qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, + u16 opaque_fid, + struct qed_queue_start_common_params *p_params, + struct qed_queue_cid_vf_params *p_vf_params) { struct qed_queue_cid *p_cid; + bool b_legacy_vf = false; u32 cid = 0; + /* Currently, PF doesn't need to allocate CIDs for any VF */ + if (p_vf_params) + b_legacy_vf = true; /* Get a unique firmware CID for this queue, in case it's a PF. * VF's don't need a CID as the queue configuration will be done * by PF. */ - if (IS_PF(p_hwfn->cdev)) { + if (IS_PF(p_hwfn->cdev) && !b_legacy_vf) { if (qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_ETH, &cid)) { DP_NOTICE(p_hwfn, "Failed to acquire cid\n"); return NULL; } } - p_cid = _qed_eth_queue_to_cid(p_hwfn, opaque_fid, cid, 0, p_params); - if (!p_cid && IS_PF(p_hwfn->cdev)) + p_cid = _qed_eth_queue_to_cid(p_hwfn, opaque_fid, cid, + p_params, p_vf_params); + if (!p_cid && IS_PF(p_hwfn->cdev) && !b_legacy_vf) qed_cxt_release_cid(p_hwfn, cid); return p_cid; } +static struct qed_queue_cid * +qed_eth_queue_to_cid_pf(struct qed_hwfn *p_hwfn, + u16 opaque_fid, + struct qed_queue_start_common_params *p_params) +{ + return qed_eth_queue_to_cid(p_hwfn, opaque_fid, p_params, + NULL); +} + int qed_sp_eth_vport_start(struct qed_hwfn *p_hwfn, struct qed_sp_vport_start_params *p_params) { @@ -799,7 +817,7 @@ int qed_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn, p_ramrod->num_of_pbl_pages = cpu_to_le16(cqe_pbl_size); DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr, cqe_pbl_addr); - if (p_cid->is_vf) { + if (p_cid->vfid != QED_QUEUE_CID_SELF) { p_ramrod->vf_rx_prod_index = p_cid->vf_qid; DP_VERBOSE(p_hwfn, QED_MSG_SP, "Queue%s is meant for VF rxq[%02x]\n", @@ -849,7 +867,7 @@ qed_eth_rx_queue_start(struct qed_hwfn *p_hwfn, int rc; /* Allocate a CID for the queue */ - p_cid = qed_eth_queue_to_cid(p_hwfn, opaque_fid, p_params); + p_cid = qed_eth_queue_to_cid_pf(p_hwfn, opaque_fid, p_params); if (!p_cid) return -ENOMEM; @@ -951,10 +969,11 @@ qed_eth_pf_rx_queue_stop(struct qed_hwfn *p_hwfn, /* Cleaning the queue requires the completion to arrive there. * In addition, VFs require the answer to come as eqe to PF. */ - p_ramrod->complete_cqe_flg = (!p_cid->is_vf && + p_ramrod->complete_cqe_flg = ((p_cid->vfid == QED_QUEUE_CID_SELF) && !b_eq_completion_only) || b_cqe_completion; - p_ramrod->complete_event_flg = p_cid->is_vf || b_eq_completion_only; + p_ramrod->complete_event_flg = (p_cid->vfid != QED_QUEUE_CID_SELF) || + b_eq_completion_only; return qed_spq_post(p_hwfn, p_ent, NULL); } @@ -1053,7 +1072,7 @@ qed_eth_tx_queue_start(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid; int rc; - p_cid = qed_eth_queue_to_cid(p_hwfn, opaque_fid, p_params); + p_cid = qed_eth_queue_to_cid_pf(p_hwfn, opaque_fid, p_params); if (!p_cid) return -EINVAL; diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h b/drivers/net/ethernet/qlogic/qed/qed_l2.h index 6ad36449dae9..43aeaa882828 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h @@ -278,6 +278,7 @@ void qed_get_vport_stats(struct qed_dev *cdev, struct qed_eth_stats *stats); void qed_reset_vport_stats(struct qed_dev *cdev); #define MAX_QUEUES_PER_QZONE (sizeof(unsigned long) * 8) +#define QED_QUEUE_CID_SELF (0xff) /* Almost identical to the qed_queue_start_common_params, * but here we maintain the SB index in IGU CAM. @@ -288,6 +289,25 @@ struct qed_queue_cid_params { u8 stats_id; }; +/* Additional parameters required for initialization of the queue_cid + * and are relevant only for a PF initializing one for its VFs. + */ +struct qed_queue_cid_vf_params { + /* Should match the VF's relative index */ + u8 vfid; + + /* 0-based queue index. Should reflect the relative qzone the + * VF thinks is associated with it [in its range]. + */ + u8 vf_qid; + + /* Indicates a VF is legacy, making it differ in: + * - Producers would be placed in a different place. + */ + bool vf_legacy; + +}; + struct qed_queue_cid { /* For stats-id, the `rel' is actually absolute as well */ struct qed_queue_cid_params rel; @@ -305,7 +325,7 @@ struct qed_queue_cid { * Notice this is relevant on the *PF* queue-cid of its VF's queues, * and not on the VF itself. */ - bool is_vf; + u8 vfid; u8 vf_qid; /* Legacy VFs might have Rx producer located elsewhere */ @@ -321,12 +341,11 @@ void qed_l2_free(struct qed_hwfn *p_hwfn); void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid); -struct qed_queue_cid *_qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, - u16 opaque_fid, - u32 cid, - u8 vf_qid, - struct qed_queue_start_common_params - *p_params); +struct qed_queue_cid * +qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, + u16 opaque_fid, + struct qed_queue_start_common_params *p_params, + struct qed_queue_cid_vf_params *p_vf_params); int qed_sp_eth_vport_start(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 498c83ebc385..7ea00bf3e9b8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -1947,6 +1947,7 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, struct qed_vf_info *vf) { struct qed_queue_start_common_params params; + struct qed_queue_cid_vf_params vf_params; struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_NO_RESOURCE; struct qed_vf_q_info *p_queue; @@ -1965,6 +1966,10 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, /* Acquire a new queue-cid */ p_queue = &vf->vf_queues[req->rx_qid]; + if (vf->acquire.vfdev_info.eth_fp_hsi_minor == + ETH_HSI_VER_NO_PKT_LEN_TUNN) + b_legacy_vf = true; + memset(¶ms, 0, sizeof(params)); params.queue_id = p_queue->fw_rx_qid; params.vport_id = vf->vport_id; @@ -1975,26 +1980,23 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, params.p_sb = &sb_dummy; params.sb_idx = req->sb_index; - p_queue->p_rx_cid = _qed_eth_queue_to_cid(p_hwfn, - vf->opaque_fid, - p_queue->fw_cid, - req->rx_qid, ¶ms); + memset(&vf_params, 0, sizeof(vf_params)); + vf_params.vfid = vf->relative_vf_id; + vf_params.vf_qid = (u8)req->rx_qid; + vf_params.vf_legacy = b_legacy_vf; + p_queue->p_rx_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, + ¶ms, &vf_params); if (!p_queue->p_rx_cid) goto out; /* Legacy VFs have their Producers in a different location, which they * calculate on their own and clean the producer prior to this. */ - if (vf->acquire.vfdev_info.eth_fp_hsi_minor == - ETH_HSI_VER_NO_PKT_LEN_TUNN) { - b_legacy_vf = true; - } else { + if (!b_legacy_vf) REG_WR(p_hwfn, GTT_BAR0_MAP_REG_MSDM_RAM + MSTORM_ETH_VF_PRODS_OFFSET(vf->abs_vf_id, req->rx_qid), 0); - } - p_queue->p_rx_cid->b_legacy_vf = b_legacy_vf; rc = qed_eth_rxq_start_ramrod(p_hwfn, p_queue->p_rx_cid, @@ -2273,11 +2275,13 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, struct qed_vf_info *vf) { struct qed_queue_start_common_params params; + struct qed_queue_cid_vf_params vf_params; struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_NO_RESOURCE; struct vfpf_start_txq_tlv *req; struct qed_vf_q_info *p_queue; struct qed_sb_info sb_dummy; + bool b_vf_legacy = false; int rc; u16 pq; @@ -2292,6 +2296,10 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, /* Acquire a new queue-cid */ p_queue = &vf->vf_queues[req->tx_qid]; + if (vf->acquire.vfdev_info.eth_fp_hsi_minor == + ETH_HSI_VER_NO_PKT_LEN_TUNN) + b_vf_legacy = true; + params.queue_id = p_queue->fw_tx_qid; params.vport_id = vf->vport_id; params.stats_id = vf->abs_vf_id + 0x10; @@ -2302,10 +2310,14 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, params.p_sb = &sb_dummy; params.sb_idx = req->sb_index; - p_queue->p_tx_cid = _qed_eth_queue_to_cid(p_hwfn, - vf->opaque_fid, - p_queue->fw_cid, - req->tx_qid, ¶ms); + memset(&vf_params, 0, sizeof(vf_params)); + vf_params.vfid = vf->relative_vf_id; + vf_params.vf_qid = (u8)req->tx_qid; + vf_params.vf_legacy = b_vf_legacy; + + p_queue->p_tx_cid = qed_eth_queue_to_cid(p_hwfn, + vf->opaque_fid, + ¶ms, &vf_params); if (!p_queue->p_tx_cid) goto out; -- cgit v1.2.3 From bbe3f233ec5ea99049f33471c0c0d0d2a78e2116 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:03 +0300 Subject: qed: Assign a unique per-queue index to queue-cid When a queue-cid is allocated, assign an index inside that's CID's queue-zone. For PFs and VFS, this number is going to be unique and derive from a per-queue-zone bitmap, while for PF's VFs queues the number is currently going to constant; Later, we'd add the capability of a VF to communicate such an index to its PF. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_l2.c | 62 ++++++++++++++++++++++++++++- drivers/net/ethernet/qlogic/qed/qed_l2.h | 7 ++++ drivers/net/ethernet/qlogic/qed/qed_sriov.c | 20 ++++++++-- drivers/net/ethernet/qlogic/qed/qed_sriov.h | 3 ++ 4 files changed, 88 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 150a8e9354b7..0a8d3a82d248 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -151,6 +151,50 @@ out_l2_info: p_hwfn->p_l2_info = NULL; } +static bool qed_eth_queue_qid_usage_add(struct qed_hwfn *p_hwfn, + struct qed_queue_cid *p_cid) +{ + struct qed_l2_info *p_l2_info = p_hwfn->p_l2_info; + u16 queue_id = p_cid->rel.queue_id; + bool b_rc = true; + u8 first; + + mutex_lock(&p_l2_info->lock); + + if (queue_id > p_l2_info->queues) { + DP_NOTICE(p_hwfn, + "Requested to increase usage for qzone %04x out of %08x\n", + queue_id, p_l2_info->queues); + b_rc = false; + goto out; + } + + first = (u8)find_first_zero_bit(p_l2_info->pp_qid_usage[queue_id], + MAX_QUEUES_PER_QZONE); + if (first >= MAX_QUEUES_PER_QZONE) { + b_rc = false; + goto out; + } + + __set_bit(first, p_l2_info->pp_qid_usage[queue_id]); + p_cid->qid_usage_idx = first; + +out: + mutex_unlock(&p_l2_info->lock); + return b_rc; +} + +static void qed_eth_queue_qid_usage_del(struct qed_hwfn *p_hwfn, + struct qed_queue_cid *p_cid) +{ + mutex_lock(&p_hwfn->p_l2_info->lock); + + clear_bit(p_cid->qid_usage_idx, + p_hwfn->p_l2_info->pp_qid_usage[p_cid->rel.queue_id]); + + mutex_unlock(&p_hwfn->p_l2_info->lock); +} + void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid) { @@ -158,6 +202,11 @@ void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, if ((p_cid->vfid == QED_QUEUE_CID_SELF) && IS_PF(p_hwfn->cdev)) qed_cxt_release_cid(p_hwfn, p_cid->cid); + + /* For PF's VFs we maintain the index inside queue-zone in IOV */ + if (p_cid->vfid == QED_QUEUE_CID_SELF) + qed_eth_queue_qid_usage_del(p_hwfn, p_cid); + vfree(p_cid); } @@ -230,14 +279,25 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, } out: + /* VF-images have provided the qid_usage_idx on their own. + * Otherwise, we need to allocate a unique one. + */ + if (!p_vf_params) { + if (!qed_eth_queue_qid_usage_add(p_hwfn, p_cid)) + goto fail; + } else { + p_cid->qid_usage_idx = p_vf_params->qid_usage_idx; + } + DP_VERBOSE(p_hwfn, QED_MSG_SP, - "opaque_fid: %04x CID %08x vport %02x [%02x] qzone %04x [%04x] stats %02x [%02x] SB %04x PI %02x\n", + "opaque_fid: %04x CID %08x vport %02x [%02x] qzone %04x.%02x [%04x] stats %02x [%02x] SB %04x PI %02x\n", p_cid->opaque_fid, p_cid->cid, p_cid->rel.vport_id, p_cid->abs.vport_id, p_cid->rel.queue_id, + p_cid->qid_usage_idx, p_cid->abs.queue_id, p_cid->rel.stats_id, p_cid->abs.stats_id, p_cid->sb_igu_id, p_cid->sb_idx); diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h b/drivers/net/ethernet/qlogic/qed/qed_l2.h index 43aeaa882828..59c2ba3eb6c1 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h @@ -306,6 +306,7 @@ struct qed_queue_cid_vf_params { */ bool vf_legacy; + u8 qid_usage_idx; }; struct qed_queue_cid { @@ -328,6 +329,12 @@ struct qed_queue_cid { u8 vfid; u8 vf_qid; + /* We need an additional index to differentiate between queues opened + * for same queue-zone, as VFs would have to communicate the info + * to the PF [otherwise PF has no way to differentiate]. + */ + u8 qid_usage_idx; + /* Legacy VFs might have Rx producer located elsewhere */ bool b_legacy_vf; diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 7ea00bf3e9b8..c205e476d39e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -1942,6 +1942,15 @@ static void qed_iov_vf_mbx_start_rxq_resp(struct qed_hwfn *p_hwfn, qed_iov_send_response(p_hwfn, p_ptt, vf, length, status); } +static u8 qed_iov_vf_mbx_qid(struct qed_hwfn *p_hwfn, + struct qed_vf_info *p_vf, bool b_is_tx) +{ + if (b_is_tx) + return QED_IOV_LEGACY_QID_TX; + else + return QED_IOV_LEGACY_QID_RX; +} + static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *vf) @@ -1954,6 +1963,7 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, struct vfpf_start_rxq_tlv *req; struct qed_sb_info sb_dummy; bool b_legacy_vf = false; + u8 qid_usage_idx; int rc; req = &mbx->req_virt->start_rxq; @@ -1963,13 +1973,13 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb)) goto out; - /* Acquire a new queue-cid */ + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); p_queue = &vf->vf_queues[req->rx_qid]; if (vf->acquire.vfdev_info.eth_fp_hsi_minor == ETH_HSI_VER_NO_PKT_LEN_TUNN) - b_legacy_vf = true; + /* Acquire a new queue-cid */ memset(¶ms, 0, sizeof(params)); params.queue_id = p_queue->fw_rx_qid; params.vport_id = vf->vport_id; @@ -1984,6 +1994,7 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, vf_params.vfid = vf->relative_vf_id; vf_params.vf_qid = (u8)req->rx_qid; vf_params.vf_legacy = b_legacy_vf; + vf_params.qid_usage_idx = qid_usage_idx; p_queue->p_rx_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, ¶ms, &vf_params); if (!p_queue->p_rx_cid) @@ -2282,6 +2293,7 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, struct qed_vf_q_info *p_queue; struct qed_sb_info sb_dummy; bool b_vf_legacy = false; + u8 qid_usage_idx; int rc; u16 pq; @@ -2293,13 +2305,14 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb)) goto out; - /* Acquire a new queue-cid */ + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); p_queue = &vf->vf_queues[req->tx_qid]; if (vf->acquire.vfdev_info.eth_fp_hsi_minor == ETH_HSI_VER_NO_PKT_LEN_TUNN) b_vf_legacy = true; + /* Acquire a new queue-cid */ params.queue_id = p_queue->fw_tx_qid; params.vport_id = vf->vport_id; params.stats_id = vf->abs_vf_id + 0x10; @@ -2314,6 +2327,7 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, vf_params.vfid = vf->relative_vf_id; vf_params.vf_qid = (u8)req->tx_qid; vf_params.vf_legacy = b_vf_legacy; + vf_params.qid_usage_idx = qid_usage_idx; p_queue->p_tx_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index 801cc005e52b..09a951365816 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -149,6 +149,9 @@ struct qed_iov_vf_mbx { struct vfpf_first_tlv first_tlv; }; +#define QED_IOV_LEGACY_QID_RX (0) +#define QED_IOV_LEGACY_QID_TX (1) + struct qed_vf_q_info { u16 fw_rx_qid; struct qed_queue_cid *p_rx_cid; -- cgit v1.2.3 From 3b19f47820756f9905e7ef184747fbb3c8ed062f Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:04 +0300 Subject: qed: Make VF legacy a bitfield Until now we used to have a single VF legacy compatibility mode, one that affected the place of the Rx producers of those VFs [mostly]. As PF would soon support allocating CIDs for VFs instead of having a static CID<->queue configuration for them, we'll need to have an additional legacy mode since existing VFs would need to continue on using the older mode of operation. Change the infrastrucutre so that the legacy would be able to indicate which of the legacy behaviors is needed for a given VF. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_l2.c | 10 +++++---- drivers/net/ethernet/qlogic/qed/qed_l2.h | 10 +++++---- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 34 ++++++++++++++++++----------- 3 files changed, 33 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 0a8d3a82d248..7096a3c0103d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -243,7 +243,7 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, if (p_vf_params) { p_cid->vfid = p_vf_params->vfid; p_cid->vf_qid = p_vf_params->vf_qid; - p_cid->b_legacy_vf = p_vf_params->vf_legacy; + p_cid->vf_legacy = p_vf_params->vf_legacy; } else { p_cid->vfid = QED_QUEUE_CID_SELF; } @@ -878,12 +878,14 @@ int qed_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn, DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr, cqe_pbl_addr); if (p_cid->vfid != QED_QUEUE_CID_SELF) { + bool b_legacy_vf = !!(p_cid->vf_legacy & + QED_QCID_LEGACY_VF_RX_PROD); + p_ramrod->vf_rx_prod_index = p_cid->vf_qid; DP_VERBOSE(p_hwfn, QED_MSG_SP, "Queue%s is meant for VF rxq[%02x]\n", - !!p_cid->b_legacy_vf ? " [legacy]" : "", - p_cid->vf_qid); - p_ramrod->vf_rx_prod_use_zone_a = !!p_cid->b_legacy_vf; + b_legacy_vf ? " [legacy]" : "", p_cid->vf_qid); + p_ramrod->vf_rx_prod_use_zone_a = b_legacy_vf; } return qed_spq_post(p_hwfn, p_ent, NULL); diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h b/drivers/net/ethernet/qlogic/qed/qed_l2.h index 59c2ba3eb6c1..3f94c2207dff 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h @@ -301,10 +301,11 @@ struct qed_queue_cid_vf_params { */ u8 vf_qid; - /* Indicates a VF is legacy, making it differ in: + /* Indicates a VF is legacy, making it differ in several things: * - Producers would be placed in a different place. + * - Makes assumptions regarding the CIDs. */ - bool vf_legacy; + u8 vf_legacy; u8 qid_usage_idx; }; @@ -335,8 +336,9 @@ struct qed_queue_cid { */ u8 qid_usage_idx; - /* Legacy VFs might have Rx producer located elsewhere */ - bool b_legacy_vf; + u8 vf_legacy; +#define QED_QCID_LEGACY_VF_RX_PROD (BIT(0)) +#define QED_QCID_LEGACY_VF_CID (BIT(1)) struct qed_hwfn *p_owner; }; diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index c205e476d39e..ed35ae03d080 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -45,6 +45,17 @@ #include "qed_sriov.h" #include "qed_vf.h" +static u8 qed_vf_calculate_legacy(struct qed_vf_info *p_vf) +{ + u8 legacy = QED_QCID_LEGACY_VF_CID; + + if (p_vf->acquire.vfdev_info.eth_fp_hsi_minor == + ETH_HSI_VER_NO_PKT_LEN_TUNN) + legacy |= QED_QCID_LEGACY_VF_RX_PROD; + + return legacy; +} + /* IOV ramrods */ static int qed_sp_vf_start(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf) { @@ -1959,11 +1970,10 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, struct qed_queue_cid_vf_params vf_params; struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_NO_RESOURCE; + u8 qid_usage_idx, vf_legacy = 0; struct qed_vf_q_info *p_queue; struct vfpf_start_rxq_tlv *req; struct qed_sb_info sb_dummy; - bool b_legacy_vf = false; - u8 qid_usage_idx; int rc; req = &mbx->req_virt->start_rxq; @@ -1976,8 +1986,7 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); p_queue = &vf->vf_queues[req->rx_qid]; - if (vf->acquire.vfdev_info.eth_fp_hsi_minor == - ETH_HSI_VER_NO_PKT_LEN_TUNN) + vf_legacy = qed_vf_calculate_legacy(vf); /* Acquire a new queue-cid */ memset(¶ms, 0, sizeof(params)); @@ -1993,7 +2002,7 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, memset(&vf_params, 0, sizeof(vf_params)); vf_params.vfid = vf->relative_vf_id; vf_params.vf_qid = (u8)req->rx_qid; - vf_params.vf_legacy = b_legacy_vf; + vf_params.vf_legacy = vf_legacy; vf_params.qid_usage_idx = qid_usage_idx; p_queue->p_rx_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, ¶ms, &vf_params); @@ -2003,7 +2012,7 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, /* Legacy VFs have their Producers in a different location, which they * calculate on their own and clean the producer prior to this. */ - if (!b_legacy_vf) + if (!(vf_legacy & QED_QCID_LEGACY_VF_RX_PROD)) REG_WR(p_hwfn, GTT_BAR0_MAP_REG_MSDM_RAM + MSTORM_ETH_VF_PRODS_OFFSET(vf->abs_vf_id, req->rx_qid), @@ -2024,7 +2033,9 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, } out: - qed_iov_vf_mbx_start_rxq_resp(p_hwfn, p_ptt, vf, status, b_legacy_vf); + qed_iov_vf_mbx_start_rxq_resp(p_hwfn, p_ptt, vf, status, + !!(vf_legacy & + QED_QCID_LEGACY_VF_RX_PROD)); } static void @@ -2292,8 +2303,7 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, struct vfpf_start_txq_tlv *req; struct qed_vf_q_info *p_queue; struct qed_sb_info sb_dummy; - bool b_vf_legacy = false; - u8 qid_usage_idx; + u8 qid_usage_idx, vf_legacy; int rc; u16 pq; @@ -2308,9 +2318,7 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); p_queue = &vf->vf_queues[req->tx_qid]; - if (vf->acquire.vfdev_info.eth_fp_hsi_minor == - ETH_HSI_VER_NO_PKT_LEN_TUNN) - b_vf_legacy = true; + vf_legacy = qed_vf_calculate_legacy(vf); /* Acquire a new queue-cid */ params.queue_id = p_queue->fw_tx_qid; @@ -2326,7 +2334,7 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, memset(&vf_params, 0, sizeof(vf_params)); vf_params.vfid = vf->relative_vf_id; vf_params.vf_qid = (u8)req->tx_qid; - vf_params.vf_legacy = b_vf_legacy; + vf_params.vf_legacy = vf_legacy; vf_params.qid_usage_idx = qid_usage_idx; p_queue->p_tx_cid = qed_eth_queue_to_cid(p_hwfn, -- cgit v1.2.3 From 007bc37179c14a6d1ff1545695e2492b3a376bc1 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:05 +0300 Subject: qed: IOV db support multiple queues per qzone Allow the infrastructure a PF maintains for each one of its VFs to support multiple queue-cids on a single queue-zone. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_l2.c | 12 +- drivers/net/ethernet/qlogic/qed/qed_l2.h | 3 + drivers/net/ethernet/qlogic/qed/qed_sriov.c | 164 +++++++++++++++++----------- drivers/net/ethernet/qlogic/qed/qed_sriov.h | 16 ++- 4 files changed, 123 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 7096a3c0103d..75643c322642 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -218,6 +218,7 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, u16 opaque_fid, u32 cid, struct qed_queue_start_common_params *p_params, + bool b_is_rx, struct qed_queue_cid_vf_params *p_vf_params) { struct qed_queue_cid *p_cid; @@ -237,6 +238,7 @@ _qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, p_cid->rel.queue_id = p_params->queue_id; p_cid->rel.stats_id = p_params->stats_id; p_cid->sb_igu_id = p_params->p_sb->igu_sb_id; + p_cid->b_is_rx = b_is_rx; p_cid->sb_idx = p_params->sb_idx; /* Fill-in bits related to VFs' queues if information was provided */ @@ -313,6 +315,7 @@ struct qed_queue_cid * qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, u16 opaque_fid, struct qed_queue_start_common_params *p_params, + bool b_is_rx, struct qed_queue_cid_vf_params *p_vf_params) { struct qed_queue_cid *p_cid; @@ -334,7 +337,7 @@ qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, } p_cid = _qed_eth_queue_to_cid(p_hwfn, opaque_fid, cid, - p_params, p_vf_params); + p_params, b_is_rx, p_vf_params); if (!p_cid && IS_PF(p_hwfn->cdev) && !b_legacy_vf) qed_cxt_release_cid(p_hwfn, cid); @@ -344,9 +347,10 @@ qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, static struct qed_queue_cid * qed_eth_queue_to_cid_pf(struct qed_hwfn *p_hwfn, u16 opaque_fid, + bool b_is_rx, struct qed_queue_start_common_params *p_params) { - return qed_eth_queue_to_cid(p_hwfn, opaque_fid, p_params, + return qed_eth_queue_to_cid(p_hwfn, opaque_fid, p_params, b_is_rx, NULL); } @@ -929,7 +933,7 @@ qed_eth_rx_queue_start(struct qed_hwfn *p_hwfn, int rc; /* Allocate a CID for the queue */ - p_cid = qed_eth_queue_to_cid_pf(p_hwfn, opaque_fid, p_params); + p_cid = qed_eth_queue_to_cid_pf(p_hwfn, opaque_fid, true, p_params); if (!p_cid) return -ENOMEM; @@ -1134,7 +1138,7 @@ qed_eth_tx_queue_start(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid; int rc; - p_cid = qed_eth_queue_to_cid_pf(p_hwfn, opaque_fid, p_params); + p_cid = qed_eth_queue_to_cid_pf(p_hwfn, opaque_fid, false, p_params); if (!p_cid) return -EINVAL; diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h b/drivers/net/ethernet/qlogic/qed/qed_l2.h index 3f94c2207dff..f8f09aadced7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h @@ -322,6 +322,8 @@ struct qed_queue_cid { u32 cid; u16 opaque_fid; + bool b_is_rx; + /* VFs queues are mapped differently, so we need to know the * relative queue associated with them [0-based]. * Notice this is relevant on the *PF* queue-cid of its VF's queues, @@ -354,6 +356,7 @@ struct qed_queue_cid * qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, u16 opaque_fid, struct qed_queue_start_common_params *p_params, + bool b_is_rx, struct qed_queue_cid_vf_params *p_vf_params); int diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index ed35ae03d080..e6fb5684b8fd 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -189,6 +189,19 @@ static struct qed_vf_info *qed_iov_get_vf_info(struct qed_hwfn *p_hwfn, return vf; } +static struct qed_queue_cid * +qed_iov_get_vf_rx_queue_cid(struct qed_vf_queue *p_queue) +{ + int i; + + for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { + if (p_queue->cids[i].p_cid && !p_queue->cids[i].b_is_tx) + return p_queue->cids[i].p_cid; + } + + return NULL; +} + enum qed_iov_validate_q_mode { QED_IOV_VALIDATE_Q_NA, QED_IOV_VALIDATE_Q_ENABLE, @@ -201,12 +214,24 @@ static bool qed_iov_validate_queue_mode(struct qed_hwfn *p_hwfn, enum qed_iov_validate_q_mode mode, bool b_is_tx) { + int i; + if (mode == QED_IOV_VALIDATE_Q_NA) return true; - if ((b_is_tx && p_vf->vf_queues[qid].p_tx_cid) || - (!b_is_tx && p_vf->vf_queues[qid].p_rx_cid)) + for (i = 0; i < MAX_QUEUES_PER_QZONE; i++) { + struct qed_vf_queue_cid *p_qcid; + + p_qcid = &p_vf->vf_queues[qid].cids[i]; + + if (!p_qcid->p_cid) + continue; + + if (p_qcid->b_is_tx != b_is_tx) + continue; + return mode == QED_IOV_VALIDATE_Q_ENABLE; + } /* In case we haven't found any valid cid, then its disabled */ return mode == QED_IOV_VALIDATE_Q_DISABLE; @@ -1030,20 +1055,15 @@ static int qed_iov_init_hw_for_vf(struct qed_hwfn *p_hwfn, vf->num_txqs = num_of_vf_avaiable_chains; for (i = 0; i < vf->num_rxqs; i++) { - struct qed_vf_q_info *p_queue = &vf->vf_queues[i]; + struct qed_vf_queue *p_queue = &vf->vf_queues[i]; p_queue->fw_rx_qid = p_params->req_rx_queue[i]; p_queue->fw_tx_qid = p_params->req_tx_queue[i]; - /* CIDs are per-VF, so no problem having them 0-based. */ - p_queue->fw_cid = i; - DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "VF[%d] - Q[%d] SB %04x, qid [Rx %04x Tx %04x] CID %04x\n", - vf->relative_vf_id, - i, vf->igu_sbs[i], - p_queue->fw_rx_qid, - p_queue->fw_tx_qid, p_queue->fw_cid); + "VF[%d] - Q[%d] SB %04x, qid [Rx %04x Tx %04x]\n", + vf->relative_vf_id, i, vf->igu_sbs[i], + p_queue->fw_rx_qid, p_queue->fw_tx_qid); } /* Update the link configuration in bulletin */ @@ -1330,7 +1350,7 @@ static void qed_iov_clean_vf(struct qed_hwfn *p_hwfn, u8 vfid) static void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf) { - u32 i; + u32 i, j; p_vf->vf_bulletin = 0; p_vf->vport_instance = 0; @@ -1343,16 +1363,15 @@ static void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn, p_vf->num_active_rxqs = 0; for (i = 0; i < QED_MAX_VF_CHAINS_PER_PF; i++) { - struct qed_vf_q_info *p_queue = &p_vf->vf_queues[i]; + struct qed_vf_queue *p_queue = &p_vf->vf_queues[i]; - if (p_queue->p_rx_cid) { - qed_eth_queue_cid_release(p_hwfn, p_queue->p_rx_cid); - p_queue->p_rx_cid = NULL; - } + for (j = 0; j < MAX_QUEUES_PER_QZONE; j++) { + if (!p_queue->cids[j].p_cid) + continue; - if (p_queue->p_tx_cid) { - qed_eth_queue_cid_release(p_hwfn, p_queue->p_tx_cid); - p_queue->p_tx_cid = NULL; + qed_eth_queue_cid_release(p_hwfn, + p_queue->cids[j].p_cid); + p_queue->cids[j].p_cid = NULL; } } @@ -1367,7 +1386,7 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, struct vf_pf_resc_request *p_req, struct pf_vf_resc *p_resp) { - int i; + u8 i; /* Queue related information */ p_resp->num_rxqs = p_vf->num_rxqs; @@ -1385,7 +1404,7 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, for (i = 0; i < p_resp->num_rxqs; i++) { qed_fw_l2_queue(p_hwfn, p_vf->vf_queues[i].fw_rx_qid, (u16 *)&p_resp->hw_qid[i]); - p_resp->cid[i] = p_vf->vf_queues[i].fw_cid; + p_resp->cid[i] = i; } /* Filter related information */ @@ -1760,9 +1779,11 @@ static int qed_iov_configure_vport_forced(struct qed_hwfn *p_hwfn, /* Update all the Rx queues */ for (i = 0; i < QED_MAX_VF_CHAINS_PER_PF; i++) { - struct qed_queue_cid *p_cid; + struct qed_vf_queue *p_queue = &p_vf->vf_queues[i]; + struct qed_queue_cid *p_cid = NULL; - p_cid = p_vf->vf_queues[i].p_rx_cid; + /* There can be at most 1 Rx queue on qzone. Find it */ + p_cid = qed_iov_get_vf_rx_queue_cid(p_queue); if (!p_cid) continue; @@ -1971,8 +1992,9 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_NO_RESOURCE; u8 qid_usage_idx, vf_legacy = 0; - struct qed_vf_q_info *p_queue; struct vfpf_start_rxq_tlv *req; + struct qed_vf_queue *p_queue; + struct qed_queue_cid *p_cid; struct qed_sb_info sb_dummy; int rc; @@ -2004,9 +2026,9 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, vf_params.vf_qid = (u8)req->rx_qid; vf_params.vf_legacy = vf_legacy; vf_params.qid_usage_idx = qid_usage_idx; - p_queue->p_rx_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, - ¶ms, &vf_params); - if (!p_queue->p_rx_cid) + p_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, + ¶ms, true, &vf_params); + if (!p_cid) goto out; /* Legacy VFs have their Producers in a different location, which they @@ -2018,16 +2040,16 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, MSTORM_ETH_VF_PRODS_OFFSET(vf->abs_vf_id, req->rx_qid), 0); - rc = qed_eth_rxq_start_ramrod(p_hwfn, - p_queue->p_rx_cid, + rc = qed_eth_rxq_start_ramrod(p_hwfn, p_cid, req->bd_max_bytes, req->rxq_addr, req->cqe_pbl_addr, req->cqe_pbl_size); if (rc) { status = PFVF_STATUS_FAILURE; - qed_eth_queue_cid_release(p_hwfn, p_queue->p_rx_cid); - p_queue->p_rx_cid = NULL; + qed_eth_queue_cid_release(p_hwfn, p_cid); } else { + p_queue->cids[qid_usage_idx].p_cid = p_cid; + p_queue->cids[qid_usage_idx].b_is_tx = false; status = PFVF_STATUS_SUCCESS; vf->num_active_rxqs++; } @@ -2254,7 +2276,8 @@ send_resp: static void qed_iov_vf_mbx_start_txq_resp(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - struct qed_vf_info *p_vf, u8 status) + struct qed_vf_info *p_vf, + u32 cid, u8 status) { struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx; struct pfvf_start_queue_resp_tlv *p_tlv; @@ -2282,12 +2305,8 @@ static void qed_iov_vf_mbx_start_txq_resp(struct qed_hwfn *p_hwfn, sizeof(struct channel_list_end_tlv)); /* Update the TLV with the response */ - if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) { - u16 qid = mbx->req_virt->start_txq.tx_qid; - - p_tlv->offset = qed_db_addr_vf(p_vf->vf_queues[qid].fw_cid, - DQ_DEMS_LEGACY); - } + if ((status == PFVF_STATUS_SUCCESS) && !b_legacy) + p_tlv->offset = qed_db_addr_vf(cid, DQ_DEMS_LEGACY); qed_iov_send_response(p_hwfn, p_ptt, p_vf, length, status); } @@ -2301,9 +2320,11 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_NO_RESOURCE; struct vfpf_start_txq_tlv *req; - struct qed_vf_q_info *p_queue; + struct qed_vf_queue *p_queue; + struct qed_queue_cid *p_cid; struct qed_sb_info sb_dummy; u8 qid_usage_idx, vf_legacy; + u32 cid = 0; int rc; u16 pq; @@ -2337,32 +2358,34 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, vf_params.vf_legacy = vf_legacy; vf_params.qid_usage_idx = qid_usage_idx; - p_queue->p_tx_cid = qed_eth_queue_to_cid(p_hwfn, - vf->opaque_fid, - ¶ms, &vf_params); - if (!p_queue->p_tx_cid) + p_cid = qed_eth_queue_to_cid(p_hwfn, vf->opaque_fid, + ¶ms, false, &vf_params); + if (!p_cid) goto out; pq = qed_get_cm_pq_idx_vf(p_hwfn, vf->relative_vf_id); - rc = qed_eth_txq_start_ramrod(p_hwfn, p_queue->p_tx_cid, + rc = qed_eth_txq_start_ramrod(p_hwfn, p_cid, req->pbl_addr, req->pbl_size, pq); if (rc) { status = PFVF_STATUS_FAILURE; - qed_eth_queue_cid_release(p_hwfn, p_queue->p_tx_cid); - p_queue->p_tx_cid = NULL; + qed_eth_queue_cid_release(p_hwfn, p_cid); } else { status = PFVF_STATUS_SUCCESS; + p_queue->cids[qid_usage_idx].p_cid = p_cid; + p_queue->cids[qid_usage_idx].b_is_tx = true; + cid = p_cid->cid; } out: - qed_iov_vf_mbx_start_txq_resp(p_hwfn, p_ptt, vf, status); + qed_iov_vf_mbx_start_txq_resp(p_hwfn, p_ptt, vf, cid, status); } static int qed_iov_vf_stop_rxqs(struct qed_hwfn *p_hwfn, struct qed_vf_info *vf, - u16 rxq_id, bool cqe_completion) + u16 rxq_id, + u8 qid_usage_idx, bool cqe_completion) { - struct qed_vf_q_info *p_queue; + struct qed_vf_queue *p_queue; int rc = 0; if (!qed_iov_validate_rxq(p_hwfn, vf, rxq_id, @@ -2377,21 +2400,22 @@ static int qed_iov_vf_stop_rxqs(struct qed_hwfn *p_hwfn, p_queue = &vf->vf_queues[rxq_id]; rc = qed_eth_rx_queue_stop(p_hwfn, - p_queue->p_rx_cid, + p_queue->cids[qid_usage_idx].p_cid, false, cqe_completion); if (rc) return rc; - p_queue->p_rx_cid = NULL; + p_queue->cids[qid_usage_idx].p_cid = NULL; vf->num_active_rxqs--; return 0; } static int qed_iov_vf_stop_txqs(struct qed_hwfn *p_hwfn, - struct qed_vf_info *vf, u16 txq_id) + struct qed_vf_info *vf, + u16 txq_id, u8 qid_usage_idx) { - struct qed_vf_q_info *p_queue; + struct qed_vf_queue *p_queue; int rc = 0; if (!qed_iov_validate_txq(p_hwfn, vf, txq_id, @@ -2400,12 +2424,11 @@ static int qed_iov_vf_stop_txqs(struct qed_hwfn *p_hwfn, p_queue = &vf->vf_queues[txq_id]; - rc = qed_eth_tx_queue_stop(p_hwfn, p_queue->p_tx_cid); + rc = qed_eth_tx_queue_stop(p_hwfn, p_queue->cids[qid_usage_idx].p_cid); if (rc) return rc; - p_queue->p_tx_cid = NULL; - + p_queue->cids[qid_usage_idx].p_cid = NULL; return 0; } @@ -2417,6 +2440,7 @@ static void qed_iov_vf_mbx_stop_rxqs(struct qed_hwfn *p_hwfn, struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_FAILURE; struct vfpf_stop_rxqs_tlv *req; + u8 qid_usage_idx; int rc; /* There has never been an official driver that used this interface @@ -2432,8 +2456,11 @@ static void qed_iov_vf_mbx_stop_rxqs(struct qed_hwfn *p_hwfn, goto out; } + /* Find which qid-index is associated with the queue */ + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); + rc = qed_iov_vf_stop_rxqs(p_hwfn, vf, req->rx_qid, - req->cqe_completion); + qid_usage_idx, req->cqe_completion); if (!rc) status = PFVF_STATUS_SUCCESS; out: @@ -2449,6 +2476,7 @@ static void qed_iov_vf_mbx_stop_txqs(struct qed_hwfn *p_hwfn, struct qed_iov_vf_mbx *mbx = &vf->vf_mbx; u8 status = PFVF_STATUS_FAILURE; struct vfpf_stop_txqs_tlv *req; + u8 qid_usage_idx; int rc; /* There has never been an official driver that used this interface @@ -2463,7 +2491,11 @@ static void qed_iov_vf_mbx_stop_txqs(struct qed_hwfn *p_hwfn, status = PFVF_STATUS_NOT_SUPPORTED; goto out; } - rc = qed_iov_vf_stop_txqs(p_hwfn, vf, req->tx_qid); + + /* Find which qid-index is associated with the queue */ + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); + + rc = qed_iov_vf_stop_txqs(p_hwfn, vf, req->tx_qid, qid_usage_idx); if (!rc) status = PFVF_STATUS_SUCCESS; @@ -2483,7 +2515,7 @@ static void qed_iov_vf_mbx_update_rxqs(struct qed_hwfn *p_hwfn, u8 status = PFVF_STATUS_FAILURE; u8 complete_event_flg; u8 complete_cqe_flg; - u16 qid; + u8 qid_usage_idx; int rc; u8 i; @@ -2491,6 +2523,8 @@ static void qed_iov_vf_mbx_update_rxqs(struct qed_hwfn *p_hwfn, complete_cqe_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_CQE_FLAG); complete_event_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_EVENT_FLAG); + qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); + /* Validate inputs */ for (i = req->rx_qid; i < req->rx_qid + req->num_rxqs; i++) if (!qed_iov_validate_rxq(p_hwfn, vf, i, @@ -2502,8 +2536,9 @@ static void qed_iov_vf_mbx_update_rxqs(struct qed_hwfn *p_hwfn, /* Prepare the handlers */ for (i = 0; i < req->num_rxqs; i++) { - qid = req->rx_qid + i; - handlers[i] = vf->vf_queues[qid].p_rx_cid; + u16 qid = req->rx_qid + i; + + handlers[i] = vf->vf_queues[qid].cids[qid_usage_idx].p_cid; } rc = qed_sp_eth_rx_queues_update(p_hwfn, (void **)&handlers, @@ -2717,6 +2752,8 @@ qed_iov_vp_update_rss_param(struct qed_hwfn *p_hwfn, (1 << p_rss_tlv->rss_table_size_log)); for (i = 0; i < table_size; i++) { + struct qed_queue_cid *p_cid; + q_idx = p_rss_tlv->rss_ind_table[i]; if (!qed_iov_validate_rxq(p_hwfn, vf, q_idx, QED_IOV_VALIDATE_Q_ENABLE)) { @@ -2728,7 +2765,8 @@ qed_iov_vp_update_rss_param(struct qed_hwfn *p_hwfn, goto out; } - p_rss->rss_ind_table[i] = vf->vf_queues[q_idx].p_rx_cid; + p_cid = qed_iov_get_vf_rx_queue_cid(&vf->vf_queues[q_idx]); + p_rss->rss_ind_table[i] = p_cid; } p_data->rss_params = p_rss; diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index 09a951365816..480cd99c69b5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -152,12 +152,17 @@ struct qed_iov_vf_mbx { #define QED_IOV_LEGACY_QID_RX (0) #define QED_IOV_LEGACY_QID_TX (1) -struct qed_vf_q_info { +struct qed_vf_queue_cid { + bool b_is_tx; + struct qed_queue_cid *p_cid; +}; + +/* Describes a qzone associated with the VF */ +struct qed_vf_queue { u16 fw_rx_qid; - struct qed_queue_cid *p_rx_cid; u16 fw_tx_qid; - struct qed_queue_cid *p_tx_cid; - u8 fw_cid; + + struct qed_vf_queue_cid cids[MAX_QUEUES_PER_QZONE]; }; enum vf_state { @@ -215,7 +220,8 @@ struct qed_vf_info { u8 num_mac_filters; u8 num_vlan_filters; - struct qed_vf_q_info vf_queues[QED_MAX_VF_CHAINS_PER_PF]; + + struct qed_vf_queue vf_queues[QED_MAX_VF_CHAINS_PER_PF]; u16 igu_sbs[QED_MAX_VF_CHAINS_PER_PF]; u8 num_active_rxqs; struct qed_public_vf_info p_vf_info; -- cgit v1.2.3 From 08bc8f15e69cbd9f8e3d7bbba4814cec50d51cfe Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:06 +0300 Subject: qed: Multiple qzone queues for VFs This adds the infrastructure for supporting VFs that want to open multiple transmission queues on the same queue-zone. At this point, there are no VFs that actually request this functionality, but later patches would remedy that. a. VF and PF would communicate the capability during ACQUIRE; Legacy VFs would continue on behaving as they do today b. PF would communicate number of supported CIDs to the VF and would enforce said limitation c. Whenever VF passes a request for a given queue configuration it would also pass an associated index within said queue-zone Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 8 +- drivers/net/ethernet/qlogic/qed/qed_l2.c | 30 ++++-- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 136 ++++++++++++++++++++++++---- drivers/net/ethernet/qlogic/qed/qed_sriov.h | 1 + drivers/net/ethernet/qlogic/qed/qed_vf.c | 39 +++++++- drivers/net/ethernet/qlogic/qed/qed_vf.h | 32 ++++++- 6 files changed, 211 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 25d5b91f7928..e201214764db 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -2116,8 +2116,12 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 rdma_tasks) struct qed_eth_pf_params *p_params = &p_hwfn->pf_params.eth_pf_params; - qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH, - p_params->num_cons, 1); + if (!p_params->num_vf_cons) + p_params->num_vf_cons = + ETH_PF_PARAMS_VF_CONS_DEFAULT; + qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH, + p_params->num_cons, + p_params->num_vf_cons); p_hwfn->p_cxt_mngr->arfs_count = p_params->num_arfs_filters; break; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 75643c322642..cffa8e7e539b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -198,10 +198,10 @@ static void qed_eth_queue_qid_usage_del(struct qed_hwfn *p_hwfn, void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid) { - /* VFs' CIDs are 0-based in PF-view, and uninitialized on VF */ - if ((p_cid->vfid == QED_QUEUE_CID_SELF) && - IS_PF(p_hwfn->cdev)) - qed_cxt_release_cid(p_hwfn, p_cid->cid); + bool b_legacy_vf = !!(p_cid->vf_legacy & QED_QCID_LEGACY_VF_CID); + + if (IS_PF(p_hwfn->cdev) && !b_legacy_vf) + _qed_cxt_release_cid(p_hwfn, p_cid->cid, p_cid->vfid); /* For PF's VFs we maintain the index inside queue-zone in IOV */ if (p_cid->vfid == QED_QUEUE_CID_SELF) @@ -319,18 +319,30 @@ qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, struct qed_queue_cid_vf_params *p_vf_params) { struct qed_queue_cid *p_cid; + u8 vfid = QED_CXT_PF_CID; bool b_legacy_vf = false; u32 cid = 0; - /* Currently, PF doesn't need to allocate CIDs for any VF */ - if (p_vf_params) - b_legacy_vf = true; + /* In case of legacy VFs, The CID can be derived from the additional + * VF parameters - the VF assumes queue X uses CID X, so we can simply + * use the vf_qid for this purpose as well. + */ + if (p_vf_params) { + vfid = p_vf_params->vfid; + + if (p_vf_params->vf_legacy & QED_QCID_LEGACY_VF_CID) { + b_legacy_vf = true; + cid = p_vf_params->vf_qid; + } + } + /* Get a unique firmware CID for this queue, in case it's a PF. * VF's don't need a CID as the queue configuration will be done * by PF. */ if (IS_PF(p_hwfn->cdev) && !b_legacy_vf) { - if (qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_ETH, &cid)) { + if (_qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_ETH, + &cid, vfid)) { DP_NOTICE(p_hwfn, "Failed to acquire cid\n"); return NULL; } @@ -339,7 +351,7 @@ qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn, p_cid = _qed_eth_queue_to_cid(p_hwfn, opaque_fid, cid, p_params, b_is_rx, p_vf_params); if (!p_cid && IS_PF(p_hwfn->cdev) && !b_legacy_vf) - qed_cxt_release_cid(p_hwfn, cid); + _qed_cxt_release_cid(p_hwfn, cid, vfid); return p_cid; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index e6fb5684b8fd..c620a5fa250b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -47,12 +47,16 @@ static u8 qed_vf_calculate_legacy(struct qed_vf_info *p_vf) { - u8 legacy = QED_QCID_LEGACY_VF_CID; + u8 legacy = 0; if (p_vf->acquire.vfdev_info.eth_fp_hsi_minor == ETH_HSI_VER_NO_PKT_LEN_TUNN) legacy |= QED_QCID_LEGACY_VF_RX_PROD; + if (!(p_vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_QUEUE_QIDS)) + legacy |= QED_QCID_LEGACY_VF_CID; + return legacy; } @@ -1413,6 +1417,10 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, p_resp->num_vlan_filters = min_t(u8, p_vf->num_vlan_filters, p_req->num_vlan_filters); + p_resp->num_cids = + min_t(u8, p_req->num_cids, + p_hwfn->pf_params.eth_pf_params.num_vf_cons); + /* This isn't really needed/enforced, but some legacy VFs might depend * on the correct filling of this field. */ @@ -1424,10 +1432,11 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, p_resp->num_sbs < p_req->num_sbs || p_resp->num_mac_filters < p_req->num_mac_filters || p_resp->num_vlan_filters < p_req->num_vlan_filters || - p_resp->num_mc_filters < p_req->num_mc_filters) { + p_resp->num_mc_filters < p_req->num_mc_filters || + p_resp->num_cids < p_req->num_cids) { DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "VF[%d] - Insufficient resources: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x]\n", + "VF[%d] - Insufficient resources: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x] cids [%02x/%02x]\n", p_vf->abs_vf_id, p_req->num_rxqs, p_resp->num_rxqs, @@ -1439,7 +1448,9 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, p_resp->num_mac_filters, p_req->num_vlan_filters, p_resp->num_vlan_filters, - p_req->num_mc_filters, p_resp->num_mc_filters); + p_req->num_mc_filters, + p_resp->num_mc_filters, + p_req->num_cids, p_resp->num_cids); /* Some legacy OSes are incapable of correctly handling this * failure. @@ -1555,6 +1566,12 @@ static void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn, if (p_hwfn->cdev->num_hwfns > 1) pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_100G; + /* Share our ability to use multiple queue-ids only with VFs + * that request it. + */ + if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_QUEUE_QIDS) + pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_QUEUE_QIDS; + qed_iov_vf_mbx_acquire_stats(p_hwfn, &pfdev_info->stats_info); memcpy(pfdev_info->port_mac, p_hwfn->hw_info.hw_mac_addr, ETH_ALEN); @@ -1977,10 +1994,37 @@ static void qed_iov_vf_mbx_start_rxq_resp(struct qed_hwfn *p_hwfn, static u8 qed_iov_vf_mbx_qid(struct qed_hwfn *p_hwfn, struct qed_vf_info *p_vf, bool b_is_tx) { - if (b_is_tx) - return QED_IOV_LEGACY_QID_TX; - else - return QED_IOV_LEGACY_QID_RX; + struct qed_iov_vf_mbx *p_mbx = &p_vf->vf_mbx; + struct vfpf_qid_tlv *p_qid_tlv; + + /* Search for the qid if the VF published its going to provide it */ + if (!(p_vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_QUEUE_QIDS)) { + if (b_is_tx) + return QED_IOV_LEGACY_QID_TX; + else + return QED_IOV_LEGACY_QID_RX; + } + + p_qid_tlv = (struct vfpf_qid_tlv *) + qed_iov_search_list_tlvs(p_hwfn, p_mbx->req_virt, + CHANNEL_TLV_QID); + if (!p_qid_tlv) { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "VF[%2x]: Failed to provide qid\n", + p_vf->relative_vf_id); + + return QED_IOV_QID_INVALID; + } + + if (p_qid_tlv->qid >= MAX_QUEUES_PER_QZONE) { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "VF[%02x]: Provided qid out-of-bounds %02x\n", + p_vf->relative_vf_id, p_qid_tlv->qid); + return QED_IOV_QID_INVALID; + } + + return p_qid_tlv->qid; } static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, @@ -2006,7 +2050,12 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, goto out; qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; + p_queue = &vf->vf_queues[req->rx_qid]; + if (p_queue->cids[qid_usage_idx].p_cid) + goto out; vf_legacy = qed_vf_calculate_legacy(vf); @@ -2332,12 +2381,17 @@ static void qed_iov_vf_mbx_start_txq(struct qed_hwfn *p_hwfn, req = &mbx->req_virt->start_txq; if (!qed_iov_validate_txq(p_hwfn, vf, req->tx_qid, - QED_IOV_VALIDATE_Q_DISABLE) || + QED_IOV_VALIDATE_Q_NA) || !qed_iov_validate_sb(p_hwfn, vf, req->hw_sb)) goto out; qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; + p_queue = &vf->vf_queues[req->tx_qid]; + if (p_queue->cids[qid_usage_idx].p_cid) + goto out; vf_legacy = qed_vf_calculate_legacy(vf); @@ -2388,17 +2442,33 @@ static int qed_iov_vf_stop_rxqs(struct qed_hwfn *p_hwfn, struct qed_vf_queue *p_queue; int rc = 0; - if (!qed_iov_validate_rxq(p_hwfn, vf, rxq_id, - QED_IOV_VALIDATE_Q_ENABLE)) { + if (!qed_iov_validate_rxq(p_hwfn, vf, rxq_id, QED_IOV_VALIDATE_Q_NA)) { DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "VF[%d] Tried Closing Rx 0x%04x which is inactive\n", - vf->relative_vf_id, rxq_id); + "VF[%d] Tried Closing Rx 0x%04x.%02x which is inactive\n", + vf->relative_vf_id, rxq_id, qid_usage_idx); return -EINVAL; } p_queue = &vf->vf_queues[rxq_id]; + /* We've validated the index and the existence of the active RXQ - + * now we need to make sure that it's using the correct qid. + */ + if (!p_queue->cids[qid_usage_idx].p_cid || + p_queue->cids[qid_usage_idx].b_is_tx) { + struct qed_queue_cid *p_cid; + + p_cid = qed_iov_get_vf_rx_queue_cid(p_queue); + DP_VERBOSE(p_hwfn, + QED_MSG_IOV, + "VF[%d] - Tried Closing Rx 0x%04x.%02x, but Rx is at %04x.%02x\n", + vf->relative_vf_id, + rxq_id, qid_usage_idx, rxq_id, p_cid->qid_usage_idx); + return -EINVAL; + } + + /* Now that we know we have a valid Rx-queue - close it */ rc = qed_eth_rx_queue_stop(p_hwfn, p_queue->cids[qid_usage_idx].p_cid, false, cqe_completion); @@ -2418,11 +2488,13 @@ static int qed_iov_vf_stop_txqs(struct qed_hwfn *p_hwfn, struct qed_vf_queue *p_queue; int rc = 0; - if (!qed_iov_validate_txq(p_hwfn, vf, txq_id, - QED_IOV_VALIDATE_Q_ENABLE)) + if (!qed_iov_validate_txq(p_hwfn, vf, txq_id, QED_IOV_VALIDATE_Q_NA)) return -EINVAL; p_queue = &vf->vf_queues[txq_id]; + if (!p_queue->cids[qid_usage_idx].p_cid || + !p_queue->cids[qid_usage_idx].b_is_tx) + return -EINVAL; rc = qed_eth_tx_queue_stop(p_hwfn, p_queue->cids[qid_usage_idx].p_cid); if (rc) @@ -2458,6 +2530,8 @@ static void qed_iov_vf_mbx_stop_rxqs(struct qed_hwfn *p_hwfn, /* Find which qid-index is associated with the queue */ qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; rc = qed_iov_vf_stop_rxqs(p_hwfn, vf, req->rx_qid, qid_usage_idx, req->cqe_completion); @@ -2494,6 +2568,8 @@ static void qed_iov_vf_mbx_stop_txqs(struct qed_hwfn *p_hwfn, /* Find which qid-index is associated with the queue */ qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, true); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; rc = qed_iov_vf_stop_txqs(p_hwfn, vf, req->tx_qid, qid_usage_idx); if (!rc) @@ -2524,15 +2600,35 @@ static void qed_iov_vf_mbx_update_rxqs(struct qed_hwfn *p_hwfn, complete_event_flg = !!(req->flags & VFPF_RXQ_UPD_COMPLETE_EVENT_FLAG); qid_usage_idx = qed_iov_vf_mbx_qid(p_hwfn, vf, false); + if (qid_usage_idx == QED_IOV_QID_INVALID) + goto out; - /* Validate inputs */ - for (i = req->rx_qid; i < req->rx_qid + req->num_rxqs; i++) + /* There shouldn't exist a VF that uses queue-qids yet uses this + * API with multiple Rx queues. Validate this. + */ + if ((vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_QUEUE_QIDS) && req->num_rxqs != 1) { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "VF[%d] supports QIDs but sends multiple queues\n", + vf->relative_vf_id); + goto out; + } + + /* Validate inputs - for the legacy case this is still true since + * qid_usage_idx for each Rx queue would be LEGACY_QID_RX. + */ + for (i = req->rx_qid; i < req->rx_qid + req->num_rxqs; i++) { if (!qed_iov_validate_rxq(p_hwfn, vf, i, - QED_IOV_VALIDATE_Q_ENABLE)) { - DP_INFO(p_hwfn, "VF[%d]: Incorrect Rxqs [%04x, %02x]\n", - vf->relative_vf_id, req->rx_qid, req->num_rxqs); + QED_IOV_VALIDATE_Q_NA) || + !vf->vf_queues[i].cids[qid_usage_idx].p_cid || + vf->vf_queues[i].cids[qid_usage_idx].b_is_tx) { + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "VF[%d]: Incorrect Rxqs [%04x, %02x]\n", + vf->relative_vf_id, req->rx_qid, + req->num_rxqs); goto out; } + } /* Prepare the handlers */ for (i = 0; i < req->num_rxqs; i++) { diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index 480cd99c69b5..95f55ae2ee8b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -151,6 +151,7 @@ struct qed_iov_vf_mbx { #define QED_IOV_LEGACY_QID_RX (0) #define QED_IOV_LEGACY_QID_TX (1) +#define QED_IOV_QID_INVALID (0xFE) struct qed_vf_queue_cid { bool b_is_tx; diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index 877d41e456e4..c0d2febad86a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -153,6 +153,22 @@ static int qed_send_msg2pf(struct qed_hwfn *p_hwfn, u8 *done, u32 resp_size) return rc; } +static void qed_vf_pf_add_qid(struct qed_hwfn *p_hwfn, + struct qed_queue_cid *p_cid) +{ + struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; + struct vfpf_qid_tlv *p_qid_tlv; + + /* Only add QIDs for the queue if it was negotiated with PF */ + if (!(p_iov->acquire_resp.pfdev_info.capabilities & + PFVF_ACQUIRE_CAP_QUEUE_QIDS)) + return; + + p_qid_tlv = qed_add_tlv(p_hwfn, &p_iov->offset, + CHANNEL_TLV_QID, sizeof(*p_qid_tlv)); + p_qid_tlv->qid = p_cid->qid_usage_idx; +} + #define VF_ACQUIRE_THRESH 3 static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, struct vf_pf_resc_request *p_req, @@ -160,7 +176,7 @@ static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, { DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "PF unwilling to fullill resource request: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x]. Try PF recommended amount\n", + "PF unwilling to fullill resource request: rxq [%02x/%02x] txq [%02x/%02x] sbs [%02x/%02x] mac [%02x/%02x] vlan [%02x/%02x] mc [%02x/%02x] cids [%02x/%02x]. Try PF recommended amount\n", p_req->num_rxqs, p_resp->num_rxqs, p_req->num_rxqs, @@ -171,7 +187,8 @@ static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, p_resp->num_mac_filters, p_req->num_vlan_filters, p_resp->num_vlan_filters, - p_req->num_mc_filters, p_resp->num_mc_filters); + p_req->num_mc_filters, + p_resp->num_mc_filters, p_req->num_cids, p_resp->num_cids); /* humble our request */ p_req->num_txqs = p_resp->num_txqs; @@ -180,6 +197,7 @@ static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, p_req->num_mac_filters = p_resp->num_mac_filters; p_req->num_vlan_filters = p_resp->num_vlan_filters; p_req->num_mc_filters = p_resp->num_mc_filters; + p_req->num_cids = p_resp->num_cids; } static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) @@ -204,6 +222,7 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) p_resc->num_sbs = QED_MAX_VF_CHAINS_PER_PF; p_resc->num_mac_filters = QED_ETH_VF_NUM_MAC_FILTERS; p_resc->num_vlan_filters = QED_ETH_VF_NUM_VLAN_FILTERS; + p_resc->num_cids = QED_ETH_VF_DEFAULT_NUM_CIDS; req->vfdev_info.os_type = VFPF_ACQUIRE_OS_LINUX; req->vfdev_info.fw_major = FW_MAJOR_VERSION; @@ -307,6 +326,13 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_PRE_FP_HSI) p_iov->b_pre_fp_hsi = true; + /* In case PF doesn't support multi-queue Tx, update the number of + * CIDs to reflect the number of queues [older PFs didn't fill that + * field]. + */ + if (!(resp->pfdev_info.capabilities & PFVF_ACQUIRE_CAP_QUEUE_QIDS)) + resp->resc.num_cids = resp->resc.num_rxqs + resp->resc.num_txqs; + /* Update bulletin board size with response from PF */ p_iov->bulletin.size = resp->bulletin_size; @@ -609,6 +635,9 @@ qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn, __internal_ram_wr(p_hwfn, *pp_prod, sizeof(u32), (u32 *)(&init_prod_val)); } + + qed_vf_pf_add_qid(p_hwfn, p_cid); + /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); @@ -657,6 +686,8 @@ int qed_vf_pf_rxq_stop(struct qed_hwfn *p_hwfn, req->num_rxqs = 1; req->cqe_completion = cqe_completion; + qed_vf_pf_add_qid(p_hwfn, p_cid); + /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); @@ -700,6 +731,8 @@ qed_vf_pf_txq_start(struct qed_hwfn *p_hwfn, req->hw_sb = p_cid->sb_igu_id; req->sb_index = p_cid->sb_idx; + qed_vf_pf_add_qid(p_hwfn, p_cid); + /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); @@ -749,6 +782,8 @@ int qed_vf_pf_txq_stop(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid) req->tx_qid = p_cid->rel.queue_id; req->num_txqs = 1; + qed_vf_pf_add_qid(p_hwfn, p_cid); + /* add list termination tlv */ qed_add_tlv(p_hwfn, &p_iov->offset, CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index d7b9c90b2f60..9588ae779267 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h @@ -46,7 +46,8 @@ struct vf_pf_resc_request { u8 num_mac_filters; u8 num_vlan_filters; u8 num_mc_filters; - u16 padding; + u8 num_cids; + u8 padding; }; struct hw_sb_info { @@ -113,6 +114,11 @@ struct vfpf_acquire_tlv { struct vf_pf_vfdev_info { #define VFPF_ACQUIRE_CAP_PRE_FP_HSI (1 << 0) /* VF pre-FP hsi version */ #define VFPF_ACQUIRE_CAP_100G (1 << 1) /* VF can support 100g */ + /* A requirement for supporting multi-Tx queues on a single queue-zone, + * VF would pass qids as additional information whenever passing queue + * references. + */ +#define VFPF_ACQUIRE_CAP_QUEUE_QIDS BIT(2) u64 capabilities; u8 fw_major; u8 fw_minor; @@ -185,6 +191,9 @@ struct pfvf_acquire_resp_tlv { */ #define PFVF_ACQUIRE_CAP_POST_FW_OVERRIDE BIT(2) + /* PF expects queues to be received with additional qids */ +#define PFVF_ACQUIRE_CAP_QUEUE_QIDS BIT(3) + u16 db_size; u8 indices_per_sb; u8 os_type; @@ -221,7 +230,8 @@ struct pfvf_acquire_resp_tlv { u8 num_mac_filters; u8 num_vlan_filters; u8 num_mc_filters; - u8 padding[2]; + u8 num_cids; + u8 padding; } resc; u32 bulletin_size; @@ -234,6 +244,16 @@ struct pfvf_start_queue_resp_tlv { u8 padding[4]; }; +/* Extended queue information - additional index for reference inside qzone. + * If commmunicated between VF/PF, each TLV relating to queues should be + * extended by one such [or have a future base TLV that already contains info]. + */ +struct vfpf_qid_tlv { + struct channel_tlv tl; + u8 qid; + u8 padding[3]; +}; + /* Setup Queue */ struct vfpf_start_rxq_tlv { struct vfpf_first_tlv first_tlv; @@ -597,6 +617,8 @@ enum { CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN, CHANNEL_TLV_VPORT_UPDATE_SGE_TPA, CHANNEL_TLV_UPDATE_TUNN_PARAM, + CHANNEL_TLV_RESERVED, + CHANNEL_TLV_QID, CHANNEL_TLV_MAX, /* Required for iterating over vport-update tlvs. @@ -605,6 +627,12 @@ enum { CHANNEL_TLV_VPORT_UPDATE_MAX = CHANNEL_TLV_VPORT_UPDATE_SGE_TPA + 1, }; +/* Default number of CIDs [total of both Rx and Tx] to be requested + * by default, and maximum possible number. + */ +#define QED_ETH_VF_DEFAULT_NUM_CIDS (32) +#define QED_ETH_VF_MAX_NUM_CIDS (250) + /* This data is held in the qed_hwfn structure for VFs only. */ struct qed_vf_iov { union vfpf_tlvs *vf2pf_request; -- cgit v1.2.3 From 1a850bfc9e71871599ddbc0d4d4cffa2dc409855 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:07 +0300 Subject: qed: VFs to try utilizing the doorbell bar VFs are currently not mapping their doorbell bar, instead relying on the small doorbell window they have in their limited regview bar. In order to increase the number of possible Tx connections [queues] employeed by VF past 16, we need to start using the doorbell bar if one such is exposed - VF would communicate this fact to PF which would return the size-bar internally configured into chip, according to which the VF would decide whether to actually utilize the doorbell bar. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 5 + drivers/net/ethernet/qlogic/qed/qed_dev.c | 8 +- drivers/net/ethernet/qlogic/qed/qed_main.c | 24 ++-- drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 1 + drivers/net/ethernet/qlogic/qed/qed_sriov.c | 61 ++++++++- drivers/net/ethernet/qlogic/qed/qed_vf.c | 181 +++++++++++++++++-------- drivers/net/ethernet/qlogic/qed/qed_vf.h | 23 +++- 7 files changed, 231 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index cfb575859cc6..d7afc42f766c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -412,6 +412,11 @@ struct qed_fw_data { u32 init_ops_size; }; +enum BAR_ID { + BAR_ID_0, /* used for GRC */ + BAR_ID_1 /* Used for doorbells */ +}; + #define DRV_MODULE_VERSION \ __stringify(QED_MAJOR_VERSION) "." \ __stringify(QED_MINOR_VERSION) "." \ diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index e983113d4558..65fe4940f20d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -69,12 +69,6 @@ static DEFINE_SPINLOCK(qm_lock); #define QED_MIN_DPIS (4) #define QED_MIN_PWM_REGION (QED_WID_SIZE * QED_MIN_DPIS) -/* API common to all protocols */ -enum BAR_ID { - BAR_ID_0, /* used for GRC */ - BAR_ID_1 /* Used for doorbells */ -}; - static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, enum BAR_ID bar_id) { @@ -83,7 +77,7 @@ static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn, u32 val; if (IS_VF(p_hwfn->cdev)) - return 1 << 17; + return qed_vf_hw_bar_size(p_hwfn, bar_id); val = qed_rd(p_hwfn, p_ptt, bar_reg); if (val) diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 6ac10ce14e5b..9877d3e762fe 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -122,7 +122,7 @@ static void qed_free_pci(struct qed_dev *cdev) { struct pci_dev *pdev = cdev->pdev; - if (cdev->doorbells) + if (cdev->doorbells && cdev->db_size) iounmap(cdev->doorbells); if (cdev->regview) iounmap(cdev->regview); @@ -206,16 +206,24 @@ static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev) goto err2; } - if (IS_PF(cdev)) { - cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); - cdev->db_size = pci_resource_len(cdev->pdev, 2); - cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); - if (!cdev->doorbells) { - DP_NOTICE(cdev, "Cannot map doorbell space\n"); - return -ENOMEM; + cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2); + cdev->db_size = pci_resource_len(cdev->pdev, 2); + if (!cdev->db_size) { + if (IS_PF(cdev)) { + DP_NOTICE(cdev, "No Doorbell bar available\n"); + return -EINVAL; + } else { + return 0; } } + cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size); + + if (!cdev->doorbells) { + DP_NOTICE(cdev, "Cannot map doorbell space\n"); + return -ENOMEM; + } + return 0; err2: diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 67172d7a7868..7e4639c9207a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -560,6 +560,7 @@ 0x2aae60UL #define PGLUE_B_REG_PF_BAR1_SIZE \ 0x2aae64UL +#define PGLUE_B_REG_VF_BAR1_SIZE 0x2aae68UL #define PRS_REG_ENCAPSULATION_TYPE_EN 0x1f0730UL #define PRS_REG_GRE_PROTOCOL 0x1f0734UL #define PRS_REG_VXLAN_PORT 0x1f0738UL diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index c620a5fa250b..e39ad22947cf 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -1384,6 +1384,60 @@ static void qed_iov_vf_cleanup(struct qed_hwfn *p_hwfn, qed_iov_clean_vf(p_hwfn, p_vf->relative_vf_id); } +/* Returns either 0, or log(size) */ +static u32 qed_iov_vf_db_bar_size(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 val = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_VF_BAR1_SIZE); + + if (val) + return val + 11; + return 0; +} + +static void +qed_iov_vf_mbx_acquire_resc_cids(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_vf_info *p_vf, + struct vf_pf_resc_request *p_req, + struct pf_vf_resc *p_resp) +{ + u8 num_vf_cons = p_hwfn->pf_params.eth_pf_params.num_vf_cons; + u8 db_size = qed_db_addr_vf(1, DQ_DEMS_LEGACY) - + qed_db_addr_vf(0, DQ_DEMS_LEGACY); + u32 bar_size; + + p_resp->num_cids = min_t(u8, p_req->num_cids, num_vf_cons); + + /* If VF didn't bother asking for QIDs than don't bother limiting + * number of CIDs. The VF doesn't care about the number, and this + * has the likely result of causing an additional acquisition. + */ + if (!(p_vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_QUEUE_QIDS)) + return; + + /* If doorbell bar was mapped by VF, limit the VF CIDs to an amount + * that would make sure doorbells for all CIDs fall within the bar. + * If it doesn't, make sure regview window is sufficient. + */ + if (p_vf->acquire.vfdev_info.capabilities & + VFPF_ACQUIRE_CAP_PHYSICAL_BAR) { + bar_size = qed_iov_vf_db_bar_size(p_hwfn, p_ptt); + if (bar_size) + bar_size = 1 << bar_size; + + if (p_hwfn->cdev->num_hwfns > 1) + bar_size /= 2; + } else { + bar_size = PXP_VF_BAR0_DQ_LENGTH; + } + + if (bar_size / db_size < 256) + p_resp->num_cids = min_t(u8, p_resp->num_cids, + (u8)(bar_size / db_size)); +} + static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *p_vf, @@ -1417,9 +1471,7 @@ static u8 qed_iov_vf_mbx_acquire_resc(struct qed_hwfn *p_hwfn, p_resp->num_vlan_filters = min_t(u8, p_vf->num_vlan_filters, p_req->num_vlan_filters); - p_resp->num_cids = - min_t(u8, p_req->num_cids, - p_hwfn->pf_params.eth_pf_params.num_vf_cons); + qed_iov_vf_mbx_acquire_resc_cids(p_hwfn, p_ptt, p_vf, p_req, p_resp); /* This isn't really needed/enforced, but some legacy VFs might depend * on the correct filling of this field. @@ -1572,6 +1624,9 @@ static void qed_iov_vf_mbx_acquire(struct qed_hwfn *p_hwfn, if (req->vfdev_info.capabilities & VFPF_ACQUIRE_CAP_QUEUE_QIDS) pfdev_info->capabilities |= PFVF_ACQUIRE_CAP_QUEUE_QIDS; + /* Share the sizes of the bars with VF */ + resp->pfdev_info.bar_size = qed_iov_vf_db_bar_size(p_hwfn, p_ptt); + qed_iov_vf_mbx_acquire_stats(p_hwfn, &pfdev_info->stats_info); memcpy(pfdev_info->port_mac, p_hwfn->hw_info.hw_mac_addr, ETH_ALEN); diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index c0d2febad86a..cb81c357bf62 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -169,6 +169,61 @@ static void qed_vf_pf_add_qid(struct qed_hwfn *p_hwfn, p_qid_tlv->qid = p_cid->qid_usage_idx; } +int _qed_vf_pf_release(struct qed_hwfn *p_hwfn, bool b_final) +{ + struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; + struct pfvf_def_resp_tlv *resp; + struct vfpf_first_tlv *req; + u32 size; + int rc; + + /* clear mailbox and prep first tlv */ + req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_RELEASE, sizeof(*req)); + + /* add list termination tlv */ + qed_add_tlv(p_hwfn, &p_iov->offset, + CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); + + resp = &p_iov->pf2vf_reply->default_resp; + rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp)); + + if (!rc && resp->hdr.status != PFVF_STATUS_SUCCESS) + rc = -EAGAIN; + + qed_vf_pf_req_end(p_hwfn, rc); + if (!b_final) + return rc; + + p_hwfn->b_int_enabled = 0; + + if (p_iov->vf2pf_request) + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(union vfpf_tlvs), + p_iov->vf2pf_request, + p_iov->vf2pf_request_phys); + if (p_iov->pf2vf_reply) + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(union pfvf_tlvs), + p_iov->pf2vf_reply, p_iov->pf2vf_reply_phys); + + if (p_iov->bulletin.p_virt) { + size = sizeof(struct qed_bulletin_content); + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + size, + p_iov->bulletin.p_virt, p_iov->bulletin.phys); + } + + kfree(p_hwfn->vf_iov_info); + p_hwfn->vf_iov_info = NULL; + + return rc; +} + +int qed_vf_pf_release(struct qed_hwfn *p_hwfn) +{ + return _qed_vf_pf_release(p_hwfn, true); +} + #define VF_ACQUIRE_THRESH 3 static void qed_vf_pf_acquire_reduce_resc(struct qed_hwfn *p_hwfn, struct vf_pf_resc_request *p_req, @@ -235,6 +290,11 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) /* Fill capability field with any non-deprecated config we support */ req->vfdev_info.capabilities |= VFPF_ACQUIRE_CAP_100G; + /* If we've mapped the doorbell bar, try using queue qids */ + if (p_iov->b_doorbell_bar) + req->vfdev_info.capabilities |= VFPF_ACQUIRE_CAP_PHYSICAL_BAR | + VFPF_ACQUIRE_CAP_QUEUE_QIDS; + /* pf 2 vf bulletin board address */ req->bulletin_addr = p_iov->bulletin.phys; req->bulletin_size = p_iov->bulletin.size; @@ -364,10 +424,27 @@ exit: return rc; } +u32 qed_vf_hw_bar_size(struct qed_hwfn *p_hwfn, enum BAR_ID bar_id) +{ + u32 bar_size; + + /* Regview size is fixed */ + if (bar_id == BAR_ID_0) + return 1 << 17; + + /* Doorbell is received from PF */ + bar_size = p_hwfn->vf_iov_info->acquire_resp.pfdev_info.bar_size; + if (bar_size) + return 1 << bar_size; + return 0; +} + int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) { + struct qed_hwfn *p_lead = QED_LEADING_HWFN(p_hwfn->cdev); struct qed_vf_iov *p_iov; u32 reg; + int rc; /* Set number of hwfns - might be overriden once leading hwfn learns * actual configuration from PF. @@ -375,10 +452,6 @@ int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) if (IS_LEAD_HWFN(p_hwfn)) p_hwfn->cdev->num_hwfns = 1; - /* Set the doorbell bar. Assumption: regview is set */ - p_hwfn->doorbells = (u8 __iomem *)p_hwfn->regview + - PXP_VF_BAR0_START_DQ; - reg = PXP_VF_BAR0_ME_OPAQUE_ADDRESS; p_hwfn->hw_info.opaque_fid = (u16)REG_RD(p_hwfn, reg); @@ -390,6 +463,30 @@ int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) if (!p_iov) return -ENOMEM; + /* Doorbells are tricky; Upper-layer has alreday set the hwfn doorbell + * value, but there are several incompatibily scenarios where that + * would be incorrect and we'd need to override it. + */ + if (!p_hwfn->doorbells) { + p_hwfn->doorbells = (u8 __iomem *)p_hwfn->regview + + PXP_VF_BAR0_START_DQ; + } else if (p_hwfn == p_lead) { + /* For leading hw-function, value is always correct, but need + * to handle scenario where legacy PF would not support 100g + * mapped bars later. + */ + p_iov->b_doorbell_bar = true; + } else { + /* here, value would be correct ONLY if the leading hwfn + * received indication that mapped-bars are supported. + */ + if (p_lead->vf_iov_info->b_doorbell_bar) + p_iov->b_doorbell_bar = true; + else + p_hwfn->doorbells = (u8 __iomem *) + p_hwfn->regview + PXP_VF_BAR0_START_DQ; + } + /* Allocate vf2pf msg */ p_iov->vf2pf_request = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, sizeof(union vfpf_tlvs), @@ -429,7 +526,33 @@ int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn) p_hwfn->hw_info.personality = QED_PCI_ETH; - return qed_vf_pf_acquire(p_hwfn); + rc = qed_vf_pf_acquire(p_hwfn); + + /* If VF is 100g using a mapped bar and PF is too old to support that, + * acquisition would succeed - but the VF would have no way knowing + * the size of the doorbell bar configured in HW and thus will not + * know how to split it for 2nd hw-function. + * In this case we re-try without the indication of the mapped + * doorbell. + */ + if (!rc && p_iov->b_doorbell_bar && + !qed_vf_hw_bar_size(p_hwfn, BAR_ID_1) && + (p_hwfn->cdev->num_hwfns > 1)) { + rc = _qed_vf_pf_release(p_hwfn, false); + if (rc) + return rc; + + p_iov->b_doorbell_bar = false; + p_hwfn->doorbells = (u8 __iomem *)p_hwfn->regview + + PXP_VF_BAR0_START_DQ; + rc = qed_vf_pf_acquire(p_hwfn); + } + + DP_VERBOSE(p_hwfn, QED_MSG_IOV, + "Regview [%p], Doorbell [%p], Device-doorbell [%p]\n", + p_hwfn->regview, p_hwfn->doorbells, p_hwfn->cdev->doorbells); + + return rc; free_vf2pf_request: dma_free_coherent(&p_hwfn->cdev->pdev->dev, @@ -1133,54 +1256,6 @@ exit: return rc; } -int qed_vf_pf_release(struct qed_hwfn *p_hwfn) -{ - struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info; - struct pfvf_def_resp_tlv *resp; - struct vfpf_first_tlv *req; - u32 size; - int rc; - - /* clear mailbox and prep first tlv */ - req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_RELEASE, sizeof(*req)); - - /* add list termination tlv */ - qed_add_tlv(p_hwfn, &p_iov->offset, - CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv)); - - resp = &p_iov->pf2vf_reply->default_resp; - rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp)); - - if (!rc && resp->hdr.status != PFVF_STATUS_SUCCESS) - rc = -EAGAIN; - - qed_vf_pf_req_end(p_hwfn, rc); - - p_hwfn->b_int_enabled = 0; - - if (p_iov->vf2pf_request) - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(union vfpf_tlvs), - p_iov->vf2pf_request, - p_iov->vf2pf_request_phys); - if (p_iov->pf2vf_reply) - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(union pfvf_tlvs), - p_iov->pf2vf_reply, p_iov->pf2vf_reply_phys); - - if (p_iov->bulletin.p_virt) { - size = sizeof(struct qed_bulletin_content); - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - size, - p_iov->bulletin.p_virt, p_iov->bulletin.phys); - } - - kfree(p_hwfn->vf_iov_info); - p_hwfn->vf_iov_info = NULL; - - return rc; -} - void qed_vf_pf_filter_mcast(struct qed_hwfn *p_hwfn, struct qed_filter_mcast *p_filter_cmd) { diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index 9588ae779267..b8ce4bef8c94 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h @@ -119,6 +119,12 @@ struct vfpf_acquire_tlv { * references. */ #define VFPF_ACQUIRE_CAP_QUEUE_QIDS BIT(2) + + /* The VF is using the physical bar. While this is mostly internal + * to the VF, might affect the number of CIDs supported assuming + * QUEUE_QIDS is set. + */ +#define VFPF_ACQUIRE_CAP_PHYSICAL_BAR BIT(3) u64 capabilities; u8 fw_major; u8 fw_minor; @@ -202,7 +208,8 @@ struct pfvf_acquire_resp_tlv { u16 chip_rev; u8 dev_type; - u8 padding; + /* Doorbell bar size configured in HW: log(size) or 0 */ + u8 bar_size; struct pfvf_stats_info stats_info; @@ -663,6 +670,11 @@ struct qed_vf_iov { * compatibility [with older PFs] we'd still need to store these. */ struct qed_sb_info *sbs_info[PFVF_MAX_SBS_PER_VF]; + + /* Determines whether VF utilizes doorbells via limited register + * bar or via the doorbell bar. + */ + bool b_doorbell_bar; }; #ifdef CONFIG_QED_SRIOV @@ -971,6 +983,8 @@ void qed_iov_vf_task(struct work_struct *work); void qed_vf_set_vf_start_tunn_update_param(struct qed_tunnel_info *p_tun); int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn, struct qed_tunnel_info *p_tunn); + +u32 qed_vf_hw_bar_size(struct qed_hwfn *p_hwfn, enum BAR_ID bar_id); #else static inline void qed_vf_get_link_params(struct qed_hwfn *p_hwfn, struct qed_mcp_link_params *params) @@ -1147,6 +1161,13 @@ static inline int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn, { return -EINVAL; } + +static inline u32 +qed_vf_hw_bar_size(struct qed_hwfn *p_hwfn, + enum BAR_ID bar_id) +{ + return 0; +} #endif #endif -- cgit v1.2.3 From cbb8a12c089c7f04b86d08d89bdab71ec9bff1f5 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:08 +0300 Subject: qed: VF XDP support The final addition on the qed front - - VFs would now require their PFs to provide multiple CIDs - Based on the availability of connections from PF, determine whether XDP is feasible and share it with qede via dev_info. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_l2.c | 19 +++++++++++++++---- drivers/net/ethernet/qlogic/qed/qed_vf.c | 13 ++++++++++--- drivers/net/ethernet/qlogic/qed/qed_vf.h | 12 ++++++++++++ 3 files changed, 37 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index cffa8e7e539b..cb8b05dbfc6e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -2119,15 +2119,26 @@ static int qed_fill_eth_dev_info(struct qed_dev *cdev, ether_addr_copy(info->port_mac, cdev->hwfns[0].hw_info.hw_mac_addr); + + info->xdp_supported = true; } else { - qed_vf_get_num_rxqs(QED_LEADING_HWFN(cdev), &info->num_queues); - if (cdev->num_hwfns > 1) { - u8 queues = 0; + u16 total_cids = 0; + + /* Determine queues & XDP support */ + for_each_hwfn(cdev, i) { + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + u8 queues, cids; - qed_vf_get_num_rxqs(&cdev->hwfns[1], &queues); + qed_vf_get_num_cids(p_hwfn, &cids); + qed_vf_get_num_rxqs(p_hwfn, &queues); info->num_queues += queues; + total_cids += cids; } + /* Enable VF XDP in case PF guarntees sufficient connections */ + if (total_cids >= info->num_queues * 3) + info->xdp_supported = true; + qed_vf_get_num_vlan_filters(&cdev->hwfns[0], (u8 *)&info->num_vlan_filters); qed_vf_get_num_mac_filters(&cdev->hwfns[0], diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index cb81c357bf62..1926d1ed439f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -291,9 +291,11 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) req->vfdev_info.capabilities |= VFPF_ACQUIRE_CAP_100G; /* If we've mapped the doorbell bar, try using queue qids */ - if (p_iov->b_doorbell_bar) + if (p_iov->b_doorbell_bar) { req->vfdev_info.capabilities |= VFPF_ACQUIRE_CAP_PHYSICAL_BAR | VFPF_ACQUIRE_CAP_QUEUE_QIDS; + p_resc->num_cids = QED_ETH_VF_MAX_NUM_CIDS; + } /* pf 2 vf bulletin board address */ req->bulletin_addr = p_iov->bulletin.phys; @@ -884,8 +886,8 @@ qed_vf_pf_txq_start(struct qed_hwfn *p_hwfn, } DP_VERBOSE(p_hwfn, QED_MSG_IOV, - "Txq[0x%02x]: doorbell at %p [offset 0x%08x]\n", - qid, *pp_doorbell, resp->offset); + "Txq[0x%02x.%02x]: doorbell at %p [offset 0x%08x]\n", + qid, p_cid->qid_usage_idx, *pp_doorbell, resp->offset); exit: qed_vf_pf_req_end(p_hwfn, rc); @@ -1478,6 +1480,11 @@ void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs) *num_txqs = p_hwfn->vf_iov_info->acquire_resp.resc.num_txqs; } +void qed_vf_get_num_cids(struct qed_hwfn *p_hwfn, u8 *num_cids) +{ + *num_cids = p_hwfn->vf_iov_info->acquire_resp.resc.num_cids; +} + void qed_vf_get_port_mac(struct qed_hwfn *p_hwfn, u8 *port_mac) { memcpy(port_mac, diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index b8ce4bef8c94..b65bbc54a097 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h @@ -731,6 +731,14 @@ void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs); */ void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs); +/** + * @brief Get number of available connections [both Rx and Tx] for VF + * + * @param p_hwfn + * @param num_cids - allocated number of connections + */ +void qed_vf_get_num_cids(struct qed_hwfn *p_hwfn, u8 *num_cids); + /** * @brief Get port mac address for VF * @@ -1010,6 +1018,10 @@ static inline void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs) { } +static inline void qed_vf_get_num_cids(struct qed_hwfn *p_hwfn, u8 *num_cids) +{ +} + static inline void qed_vf_get_port_mac(struct qed_hwfn *p_hwfn, u8 *port_mac) { } -- cgit v1.2.3 From e7b80dece83b86f8f630a47a9e0419051c7b1005 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 4 Jun 2017 13:31:09 +0300 Subject: qede: VF XDP support This introduces 2 changes needed for XDP to be supported for VFs: a. On VF-side, publish the NDO based on qed outputs b. On PF-side, request qed to allocate sufficient cids per-VF to allow the child vfs to support it Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_main.c | 34 +++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index ad1e24962bdb..fdf04bc5406e 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -580,6 +580,24 @@ static const struct net_device_ops qede_netdev_vf_ops = { .ndo_features_check = qede_features_check, }; +static const struct net_device_ops qede_netdev_vf_xdp_ops = { + .ndo_open = qede_open, + .ndo_stop = qede_close, + .ndo_start_xmit = qede_start_xmit, + .ndo_set_rx_mode = qede_set_rx_mode, + .ndo_set_mac_address = qede_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = qede_change_mtu, + .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, + .ndo_set_features = qede_set_features, + .ndo_get_stats64 = qede_get_stats64, + .ndo_udp_tunnel_add = qede_udp_tunnel_add, + .ndo_udp_tunnel_del = qede_udp_tunnel_del, + .ndo_features_check = qede_features_check, + .ndo_xdp = qede_xdp, +}; + /* ------------------------------------------------------------------------- * START OF PROBE / REMOVE * ------------------------------------------------------------------------- @@ -645,10 +663,14 @@ static void qede_init_ndev(struct qede_dev *edev) ndev->watchdog_timeo = TX_TIMEOUT; - if (IS_VF(edev)) - ndev->netdev_ops = &qede_netdev_vf_ops; - else + if (IS_VF(edev)) { + if (edev->dev_info.xdp_supported) + ndev->netdev_ops = &qede_netdev_vf_xdp_ops; + else + ndev->netdev_ops = &qede_netdev_vf_ops; + } else { ndev->netdev_ops = &qede_netdev_ops; + } qede_set_ethtool_ops(ndev); @@ -846,6 +868,12 @@ static void qede_update_pf_params(struct qed_dev *cdev) /* 64 rx + 64 tx + 64 XDP */ memset(&pf_params, 0, sizeof(struct qed_pf_params)); pf_params.eth_pf_params.num_cons = (MAX_SB_PER_PF_MIMD - 1) * 3; + + /* Same for VFs - make sure they'll have sufficient connections + * to support XDP Tx queues. + */ + pf_params.eth_pf_params.num_vf_cons = 48; + #ifdef CONFIG_RFS_ACCEL pf_params.eth_pf_params.num_arfs_filters = QEDE_RFS_MAX_FLTR; #endif -- cgit v1.2.3 From a4e1ce24f7e2dc59d2bba5c11487778030f9d5bf Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Sun, 4 Jun 2017 16:49:58 +0200 Subject: mlxsw: spectrum: Rename the firmware file Change the firmware file name to be in "mellanox" directory. This commit is a followup to the linux-firmware commit a4c72696f5f4 ("Mellanox: Add firmware for mlxsw_spectrum") Signed-off-by: Yotam Gigi Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 1e6a97d9a87d..84b6f36eb421 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -81,7 +81,7 @@ static const struct mlxsw_fw_rev mlxsw_sp_supported_fw_rev = { }; #define MLXSW_SP_FW_FILENAME \ - "mlxsw_spectrum-" __stringify(MLXSW_FWREV_MAJOR) \ + "mellanox/mlxsw_spectrum-" __stringify(MLXSW_FWREV_MAJOR) \ "." __stringify(MLXSW_FWREV_MINOR) \ "." __stringify(MLXSW_FWREV_SUBMINOR) ".mfa2" -- cgit v1.2.3 From cb4cc0e0b18ef683eed191707fa812a1719b9723 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 4 Jun 2017 16:53:38 +0200 Subject: mlxsw: spectrum: Tidy up header file Make it clear where functions are defined and move misplaced declaration to their correct place. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 47 ++++++++++++++------------ 1 file changed, 25 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 1a834109bda1..99760fd55ba1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -233,12 +233,6 @@ struct mlxsw_sp_port { struct list_head vlans_list; }; -bool mlxsw_sp_port_dev_check(const struct net_device *dev); -struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev); -struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev); -struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); -void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); - static inline bool mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port) { @@ -278,6 +272,7 @@ enum mlxsw_sp_flood_type { MLXSW_SP_FLOOD_TYPE_MC, }; +/* spectrum_buffers.c */ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port); @@ -315,12 +310,11 @@ int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port, u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells); u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes); +/* spectrum_switchdev.c */ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, - u16 vid_end, bool is_member, bool untagged); int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, bool adding); void @@ -332,6 +326,7 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, struct net_device *brport_dev, struct net_device *br_dev); +/* spectrum.c */ int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index, bool dwrr, u8 dwrr_weight); @@ -352,24 +347,35 @@ int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); +int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, + u16 vid_end, bool is_member, bool untagged); +int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, + unsigned int counter_index, u64 *packets, + u64 *bytes); +int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, + unsigned int *p_counter_index); +void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, + unsigned int counter_index); +bool mlxsw_sp_port_dev_check(const struct net_device *dev); +struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev); +struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev); +struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); +void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); +/* spectrum_dcb.c */ #ifdef CONFIG_MLXSW_SPECTRUM_DCB - int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port); - #else - static inline int mlxsw_sp_port_dcb_init(struct mlxsw_sp_port *mlxsw_sp_port) { return 0; } - static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port) {} - #endif +/* spectrum_router.c */ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_router_netevent_event(struct notifier_block *unused, @@ -383,12 +389,11 @@ void mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif); +/* spectrum_kvdl.c */ int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count, u32 *p_entry_index); void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index); -struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl); - struct mlxsw_sp_acl_rule_info { unsigned int priority; struct mlxsw_afk_element_values values; @@ -429,6 +434,8 @@ struct mlxsw_sp_acl_ops { struct mlxsw_sp_acl_ruleset; +/* spectrum_acl.c */ +struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl); struct mlxsw_sp_acl_ruleset * mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev, bool ingress, @@ -492,22 +499,18 @@ struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp); +/* spectrum_acl_tcam.c */ extern const struct mlxsw_sp_acl_ops mlxsw_sp_acl_tcam_ops; +/* spectrum_flower.c */ int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, __be16 protocol, struct tc_cls_flower_offload *f); void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, struct tc_cls_flower_offload *f); int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress, struct tc_cls_flower_offload *f); -int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, - unsigned int counter_index, u64 *packets, - u64 *bytes); -int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, - unsigned int *p_counter_index); -void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, - unsigned int counter_index); +/* spectrum_fid.c */ int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_flood_type packet_type, u8 local_port, bool member); -- cgit v1.2.3 From da0abcf93fe5353268b0b5b30396fb10dc32bef4 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 4 Jun 2017 16:53:39 +0200 Subject: mlxsw: Fix typo inside enumeration Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 2 +- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 182150afd5ad..157b9b6f8485 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -958,7 +958,7 @@ enum mlxsw_flood_table_type { MLXSW_REG_SFGC_TABLE_TYPE_VID = 1, MLXSW_REG_SFGC_TABLE_TYPE_SINGLE = 2, MLXSW_REG_SFGC_TABLE_TYPE_ANY = 0, - MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST = 3, + MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET = 3, MLXSW_REG_SFGC_TABLE_TYPE_FID = 4, }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index c7590aea1aee..6afbe9ec64e2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -373,19 +373,19 @@ static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = { { .packet_type = MLXSW_SP_FLOOD_TYPE_UC, .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, - .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, .table_index = 0, }, { .packet_type = MLXSW_SP_FLOOD_TYPE_MC, .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, - .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, .table_index = 1, }, { .packet_type = MLXSW_SP_FLOOD_TYPE_BC, .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, - .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, .table_index = 2, }, }; -- cgit v1.2.3 From de5ed99e9777a487da4ad9c58e409ed26b640d9e Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 4 Jun 2017 16:53:40 +0200 Subject: mlxsw: spectrum_router: Align RIF index allocation with existing code The way we usually allocate an index is by letting the allocation function return an error instead of an invalid index. Do the same for RIF index. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index a4272c351e3a..20061058801e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2979,16 +2979,18 @@ mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp, return mlxsw_sp_fid_type_rif_type(mlxsw_sp, type); } -#define MLXSW_SP_INVALID_INDEX_RIF 0xffff -static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp) +static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_rif_index) { int i; - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) - if (!mlxsw_sp->router->rifs[i]) - return i; + for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) { + if (!mlxsw_sp->router->rifs[i]) { + *p_rif_index = i; + return 0; + } + } - return MLXSW_SP_INVALID_INDEX_RIF; + return -ENOBUFS; } static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, @@ -3048,11 +3050,9 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, if (IS_ERR(vr)) return ERR_CAST(vr); - rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp); - if (rif_index == MLXSW_SP_INVALID_INDEX_RIF) { - err = -ERANGE; - goto err_avail_rif_get; - } + err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index); + if (err) + goto err_rif_index_alloc; rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, params->dev); if (!rif) { @@ -3095,7 +3095,7 @@ err_configure: err_fid_get: kfree(rif); err_rif_alloc: -err_avail_rif_get: +err_rif_index_alloc: mlxsw_sp_vr_put(vr); return ERR_PTR(err); } -- cgit v1.2.3 From c7c6b8715a554a9868673fae7cd30795788228db Mon Sep 17 00:00:00 2001 From: "yuval.shaia@oracle.com" Date: Sun, 4 Jun 2017 20:08:51 +0300 Subject: net/dec: Make __de_get_link_ksettings return void Make return value void since function never return meaningfull value Signed-off-by: Yuval Shaia Signed-off-by: David S. Miller --- drivers/net/ethernet/dec/tulip/de2104x.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/dec/tulip/de2104x.c b/drivers/net/ethernet/dec/tulip/de2104x.c index 91b8f6f5a765..c87b8cc42963 100644 --- a/drivers/net/ethernet/dec/tulip/de2104x.c +++ b/drivers/net/ethernet/dec/tulip/de2104x.c @@ -1483,8 +1483,8 @@ static void __de_get_regs(struct de_private *de, u8 *buf) de_rx_missed(de, rbuf[8]); } -static int __de_get_link_ksettings(struct de_private *de, - struct ethtool_link_ksettings *cmd) +static void __de_get_link_ksettings(struct de_private *de, + struct ethtool_link_ksettings *cmd) { ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, de->media_supported); @@ -1517,8 +1517,6 @@ static int __de_get_link_ksettings(struct de_private *de, cmd->base.autoneg = AUTONEG_ENABLE; /* ignore maxtxpkt, maxrxpkt for now */ - - return 0; } static int __de_set_link_ksettings(struct de_private *de, @@ -1615,13 +1613,12 @@ static int de_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct de_private *de = netdev_priv(dev); - int rc; spin_lock_irq(&de->lock); - rc = __de_get_link_ksettings(de, cmd); + __de_get_link_ksettings(de, cmd); spin_unlock_irq(&de->lock); - return rc; + return 0; } static int de_set_link_ksettings(struct net_device *dev, -- cgit v1.2.3 From 82c01a84d5a9bd3b9347bb03eed2f05bbccef933 Mon Sep 17 00:00:00 2001 From: "yuval.shaia@oracle.com" Date: Sun, 4 Jun 2017 20:22:00 +0300 Subject: net/{mii, smsc}: Make mii_ethtool_get_link_ksettings and smc_netdev_get_ecmd return void Make return value void since functions never returns meaningfull value. Signed-off-by: Yuval Shaia Signed-off-by: David S. Miller --- drivers/net/cris/eth_v10.c | 5 ++--- drivers/net/ethernet/3com/3c59x.c | 4 +++- drivers/net/ethernet/amd/pcnet32.c | 5 +---- drivers/net/ethernet/cirrus/ep93xx_eth.c | 5 ++++- drivers/net/ethernet/dec/tulip/winbond-840.c | 5 ++--- drivers/net/ethernet/faraday/ftmac100.c | 5 ++++- drivers/net/ethernet/fealnx.c | 5 ++--- drivers/net/ethernet/intel/e100.c | 5 ++++- drivers/net/ethernet/jme.c | 5 ++--- drivers/net/ethernet/korina.c | 5 ++--- drivers/net/ethernet/micrel/ks8851.c | 5 ++++- drivers/net/ethernet/micrel/ks8851_mll.c | 5 ++++- drivers/net/ethernet/nuvoton/w90p910_ether.c | 5 ++++- drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c | 6 +++--- drivers/net/ethernet/realtek/8139cp.c | 5 ++--- drivers/net/ethernet/realtek/r8169.c | 4 +++- drivers/net/ethernet/sgi/ioc3-eth.c | 5 ++--- drivers/net/ethernet/sis/sis190.c | 4 +++- drivers/net/ethernet/smsc/epic100.c | 5 ++--- drivers/net/ethernet/smsc/smc911x.c | 7 +++---- drivers/net/ethernet/smsc/smc91c92_cs.c | 13 +++++-------- drivers/net/ethernet/smsc/smc91x.c | 7 ++----- drivers/net/ethernet/tundra/tsi108_eth.c | 5 ++--- drivers/net/ethernet/via/via-rhine.c | 5 ++--- drivers/net/mii.c | 8 ++------ drivers/net/usb/ax88179_178a.c | 5 ++++- drivers/net/usb/r8152.c | 2 +- drivers/net/usb/usbnet.c | 4 +++- 28 files changed, 77 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index da020418a652..017f48cdcab9 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1417,10 +1417,9 @@ static int e100_get_link_ksettings(struct net_device *dev, { struct net_local *np = netdev_priv(dev); u32 supported; - int err; spin_lock_irq(&np->lock); - err = mii_ethtool_get_link_ksettings(&np->mii_if, cmd); + mii_ethtool_get_link_ksettings(&np->mii_if, cmd); spin_unlock_irq(&np->lock); /* The PHY may support 1000baseT, but the Etrax100 does not. */ @@ -1432,7 +1431,7 @@ static int e100_get_link_ksettings(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, supported); - return err; + return 0; } static int e100_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index e41245a54f8b..14cff6017756 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -2912,7 +2912,9 @@ static int vortex_get_link_ksettings(struct net_device *dev, { struct vortex_private *vp = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&vp->mii, cmd); + mii_ethtool_get_link_ksettings(&vp->mii, cmd); + + return 0; } static int vortex_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index 86369d7c9a0f..7f60d17819ce 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -731,12 +731,10 @@ static int pcnet32_get_link_ksettings(struct net_device *dev, { struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; - int r = -EOPNOTSUPP; spin_lock_irqsave(&lp->lock, flags); if (lp->mii) { mii_ethtool_get_link_ksettings(&lp->mii_if, cmd); - r = 0; } else if (lp->chip_version == PCNET32_79C970A) { if (lp->autoneg) { cmd->base.autoneg = AUTONEG_ENABLE; @@ -753,10 +751,9 @@ static int pcnet32_get_link_ksettings(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode( cmd->link_modes.supported, SUPPORTED_TP | SUPPORTED_AUI); - r = 0; } spin_unlock_irqrestore(&lp->lock, flags); - return r; + return 0; } static int pcnet32_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c index 7a7c02f1f8b9..e2a702996db4 100644 --- a/drivers/net/ethernet/cirrus/ep93xx_eth.c +++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c @@ -702,7 +702,10 @@ static int ep93xx_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct ep93xx_priv *ep = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&ep->mii, cmd); + + mii_ethtool_get_link_ksettings(&ep->mii, cmd); + + return 0; } static int ep93xx_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index d1f2f3cc7cfa..32d7229544fa 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -1395,13 +1395,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); - int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_get_link_ksettings(&np->mii_if, cmd); + mii_ethtool_get_link_ksettings(&np->mii_if, cmd); spin_unlock_irq(&np->lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index 1536356e2ea8..66928a922824 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -829,7 +829,10 @@ static int ftmac100_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct ftmac100 *priv = netdev_priv(netdev); - return mii_ethtool_get_link_ksettings(&priv->mii, cmd); + + mii_ethtool_get_link_ksettings(&priv->mii, cmd); + + return 0; } static int ftmac100_set_link_ksettings(struct net_device *netdev, diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index 766636a7c25e..610f9c07c21d 100644 --- a/drivers/net/ethernet/fealnx.c +++ b/drivers/net/ethernet/fealnx.c @@ -1821,13 +1821,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct netdev_private *np = netdev_priv(dev); - int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_get_link_ksettings(&np->mii, cmd); + mii_ethtool_get_link_ksettings(&np->mii, cmd); spin_unlock_irq(&np->lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index 2b7323d392dc..4d10270ddf8f 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -2430,7 +2430,10 @@ static int e100_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct nic *nic = netdev_priv(netdev); - return mii_ethtool_get_link_ksettings(&nic->mii, cmd); + + mii_ethtool_get_link_ksettings(&nic->mii, cmd); + + return 0; } static int e100_set_link_ksettings(struct net_device *netdev, diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 0e5083a48937..62d848df26ef 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -2610,12 +2610,11 @@ jme_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct jme_adapter *jme = netdev_priv(netdev); - int rc; spin_lock_bh(&jme->phy_lock); - rc = mii_ethtool_get_link_ksettings(&jme->mii_if, cmd); + mii_ethtool_get_link_ksettings(&jme->mii_if, cmd); spin_unlock_bh(&jme->phy_lock); - return rc; + return 0; } static int diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c index 9fae98caf83a..3c0a6451273d 100644 --- a/drivers/net/ethernet/korina.c +++ b/drivers/net/ethernet/korina.c @@ -699,13 +699,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct korina_private *lp = netdev_priv(dev); - int rc; spin_lock_irq(&lp->lock); - rc = mii_ethtool_get_link_ksettings(&lp->mii_if, cmd); + mii_ethtool_get_link_ksettings(&lp->mii_if, cmd); spin_unlock_irq(&lp->lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c index 20358f87de57..2fe96f1f3fe5 100644 --- a/drivers/net/ethernet/micrel/ks8851.c +++ b/drivers/net/ethernet/micrel/ks8851.c @@ -1071,7 +1071,10 @@ static int ks8851_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct ks8851_net *ks = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&ks->mii, cmd); + + mii_ethtool_get_link_ksettings(&ks->mii, cmd); + + return 0; } static int ks8851_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c index 7647f7bdbcb8..f3e9dd47b56f 100644 --- a/drivers/net/ethernet/micrel/ks8851_mll.c +++ b/drivers/net/ethernet/micrel/ks8851_mll.c @@ -1315,7 +1315,10 @@ static int ks_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct ks_net *ks = netdev_priv(netdev); - return mii_ethtool_get_link_ksettings(&ks->mii, cmd); + + mii_ethtool_get_link_ksettings(&ks->mii, cmd); + + return 0; } static int ks_set_link_ksettings(struct net_device *netdev, diff --git a/drivers/net/ethernet/nuvoton/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c index 159564d8dcdb..89ab786da25f 100644 --- a/drivers/net/ethernet/nuvoton/w90p910_ether.c +++ b/drivers/net/ethernet/nuvoton/w90p910_ether.c @@ -868,7 +868,10 @@ static int w90p910_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct w90p910_ether *ether = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(ðer->mii, cmd); + + mii_ethtool_get_link_ksettings(ðer->mii, cmd); + + return 0; } static int w90p910_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c index 21093276d2b7..731ce1e419e4 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c @@ -85,9 +85,8 @@ static int pch_gbe_get_link_ksettings(struct net_device *netdev, { struct pch_gbe_adapter *adapter = netdev_priv(netdev); u32 supported, advertising; - int ret; - ret = mii_ethtool_get_link_ksettings(&adapter->mii, ecmd); + mii_ethtool_get_link_ksettings(&adapter->mii, ecmd); ethtool_convert_link_mode_to_legacy_u32(&supported, ecmd->link_modes.supported); @@ -104,7 +103,8 @@ static int pch_gbe_get_link_ksettings(struct net_device *netdev, if (!netif_carrier_ok(adapter->netdev)) ecmd->base.speed = SPEED_UNKNOWN; - return ret; + + return 0; } /** diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 72233ab9474b..e7ab23e87de2 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -1410,14 +1410,13 @@ static int cp_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct cp_private *cp = netdev_priv(dev); - int rc; unsigned long flags; spin_lock_irqsave(&cp->lock, flags); - rc = mii_ethtool_get_link_ksettings(&cp->mii_if, cmd); + mii_ethtool_get_link_ksettings(&cp->mii_if, cmd); spin_unlock_irqrestore(&cp->lock, flags); - return rc; + return 0; } static int cp_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 0a8f2817ea60..bd07a15d3b7c 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -2148,7 +2148,9 @@ static int rtl8169_get_link_ksettings_xmii(struct net_device *dev, { struct rtl8169_private *tp = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&tp->mii, cmd); + mii_ethtool_get_link_ksettings(&tp->mii, cmd); + + return 0; } static int rtl8169_get_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index 52ead5524de7..b607936e1b3e 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -1562,13 +1562,12 @@ static int ioc3_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct ioc3_private *ip = netdev_priv(dev); - int rc; spin_lock_irq(&ip->ioc3_lock); - rc = mii_ethtool_get_link_ksettings(&ip->mii, cmd); + mii_ethtool_get_link_ksettings(&ip->mii, cmd); spin_unlock_irq(&ip->ioc3_lock); - return rc; + return 0; } static int ioc3_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/sis/sis190.c b/drivers/net/ethernet/sis/sis190.c index 02da106c6e04..445109bd6910 100644 --- a/drivers/net/ethernet/sis/sis190.c +++ b/drivers/net/ethernet/sis/sis190.c @@ -1739,7 +1739,9 @@ static int sis190_get_link_ksettings(struct net_device *dev, { struct sis190_private *tp = netdev_priv(dev); - return mii_ethtool_get_link_ksettings(&tp->mii_if, cmd); + mii_ethtool_get_link_ksettings(&tp->mii_if, cmd); + + return 0; } static int sis190_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/smsc/epic100.c b/drivers/net/ethernet/smsc/epic100.c index db6dcb06193d..6a0e1d4b597c 100644 --- a/drivers/net/ethernet/smsc/epic100.c +++ b/drivers/net/ethernet/smsc/epic100.c @@ -1391,13 +1391,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct epic_private *np = netdev_priv(dev); - int rc; spin_lock_irq(&np->lock); - rc = mii_ethtool_get_link_ksettings(&np->mii, cmd); + mii_ethtool_get_link_ksettings(&np->mii, cmd); spin_unlock_irq(&np->lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index 36307d34f641..05157442a980 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -1450,7 +1450,7 @@ smc911x_ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct smc911x_local *lp = netdev_priv(dev); - int ret, status; + int status; unsigned long flags; u32 supported; @@ -1458,7 +1458,7 @@ smc911x_ethtool_get_link_ksettings(struct net_device *dev, if (lp->phy_type != 0) { spin_lock_irqsave(&lp->lock, flags); - ret = mii_ethtool_get_link_ksettings(&lp->mii, cmd); + mii_ethtool_get_link_ksettings(&lp->mii, cmd); spin_unlock_irqrestore(&lp->lock, flags); } else { supported = SUPPORTED_10baseT_Half | @@ -1480,10 +1480,9 @@ smc911x_ethtool_get_link_ksettings(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode( cmd->link_modes.supported, supported); - ret = 0; } - return ret; + return 0; } static int diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c index 976aa876789a..92c927aec66d 100644 --- a/drivers/net/ethernet/smsc/smc91c92_cs.c +++ b/drivers/net/ethernet/smsc/smc91c92_cs.c @@ -1843,8 +1843,8 @@ static int smc_link_ok(struct net_device *dev) } } -static int smc_netdev_get_ecmd(struct net_device *dev, - struct ethtool_link_ksettings *ecmd) +static void smc_netdev_get_ecmd(struct net_device *dev, + struct ethtool_link_ksettings *ecmd) { u16 tmp; unsigned int ioaddr = dev->base_addr; @@ -1865,8 +1865,6 @@ static int smc_netdev_get_ecmd(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported, supported); - - return 0; } static int smc_netdev_set_ecmd(struct net_device *dev, @@ -1918,18 +1916,17 @@ static int smc_get_link_ksettings(struct net_device *dev, struct smc_private *smc = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; u16 saved_bank = inw(ioaddr + BANK_SELECT); - int ret; unsigned long flags; spin_lock_irqsave(&smc->lock, flags); SMC_SELECT_BANK(3); if (smc->cfg & CFG_MII_SELECT) - ret = mii_ethtool_get_link_ksettings(&smc->mii_if, ecmd); + mii_ethtool_get_link_ksettings(&smc->mii_if, ecmd); else - ret = smc_netdev_get_ecmd(dev, ecmd); + smc_netdev_get_ecmd(dev, ecmd); SMC_SELECT_BANK(saved_bank); spin_unlock_irqrestore(&smc->lock, flags); - return ret; + return 0; } static int smc_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 91e9bd7159ab..0d230b125c6c 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -1539,11 +1539,10 @@ smc_ethtool_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct smc_local *lp = netdev_priv(dev); - int ret; if (lp->phy_type != 0) { spin_lock_irq(&lp->lock); - ret = mii_ethtool_get_link_ksettings(&lp->mii, cmd); + mii_ethtool_get_link_ksettings(&lp->mii, cmd); spin_unlock_irq(&lp->lock); } else { u32 supported = SUPPORTED_10baseT_Half | @@ -1562,11 +1561,9 @@ smc_ethtool_get_link_ksettings(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode( cmd->link_modes.supported, supported); - - ret = 0; } - return ret; + return 0; } static int diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c index 5ac6eaa9e785..c2d15d9c0c33 100644 --- a/drivers/net/ethernet/tundra/tsi108_eth.c +++ b/drivers/net/ethernet/tundra/tsi108_eth.c @@ -1504,13 +1504,12 @@ static int tsi108_get_link_ksettings(struct net_device *dev, { struct tsi108_prv_data *data = netdev_priv(dev); unsigned long flags; - int rc; spin_lock_irqsave(&data->txlock, flags); - rc = mii_ethtool_get_link_ksettings(&data->mii_if, cmd); + mii_ethtool_get_link_ksettings(&data->mii_if, cmd); spin_unlock_irqrestore(&data->txlock, flags); - return rc; + return 0; } static int tsi108_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index 4cf41f779d0e..acd29d60174a 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -2307,13 +2307,12 @@ static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct rhine_private *rp = netdev_priv(dev); - int rc; mutex_lock(&rp->task_lock); - rc = mii_ethtool_get_link_ksettings(&rp->mii_if, cmd); + mii_ethtool_get_link_ksettings(&rp->mii_if, cmd); mutex_unlock(&rp->task_lock); - return rc; + return 0; } static int netdev_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 6d953c53eed6..44612122338b 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -141,11 +141,9 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) * * The @cmd parameter is expected to have been cleared before calling * mii_ethtool_get_link_ksettings(). - * - * Returns 0 for success, negative on error. */ -int mii_ethtool_get_link_ksettings(struct mii_if_info *mii, - struct ethtool_link_ksettings *cmd) +void mii_ethtool_get_link_ksettings(struct mii_if_info *mii, + struct ethtool_link_ksettings *cmd) { struct net_device *dev = mii->dev; u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; @@ -227,8 +225,6 @@ int mii_ethtool_get_link_ksettings(struct mii_if_info *mii, lp_advertising); /* ignore maxtxpkt, maxrxpkt for now */ - - return 0; } /** diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 51cf60092a18..793ce900dffa 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -624,7 +624,10 @@ static int ax88179_get_link_ksettings(struct net_device *net, struct ethtool_link_ksettings *cmd) { struct usbnet *dev = netdev_priv(net); - return mii_ethtool_get_link_ksettings(&dev->mii, cmd); + + mii_ethtool_get_link_ksettings(&dev->mii, cmd); + + return 0; } static int ax88179_set_link_ksettings(struct net_device *net, diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index e902df9595b9..fd31fab2a9da 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3835,7 +3835,7 @@ int rtl8152_get_link_ksettings(struct net_device *netdev, mutex_lock(&tp->control); - ret = mii_ethtool_get_link_ksettings(&tp->mii, cmd); + mii_ethtool_get_link_ksettings(&tp->mii, cmd); mutex_unlock(&tp->control); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 79048e72c1bd..6510e5cc1817 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -956,7 +956,9 @@ int usbnet_get_link_ksettings(struct net_device *net, if (!dev->mii.mdio_read) return -EOPNOTSUPP; - return mii_ethtool_get_link_ksettings(&dev->mii, cmd); + mii_ethtool_get_link_ksettings(&dev->mii, cmd); + + return 0; } EXPORT_SYMBOL_GPL(usbnet_get_link_ksettings); -- cgit v1.2.3 From 697dae1ee1e320bb6b20c02f0259a0fa3a768b72 Mon Sep 17 00:00:00 2001 From: "yuval.shaia@oracle.com" Date: Sun, 4 Jun 2017 20:24:46 +0300 Subject: net/3com: Make el3_netdev_get_ecmd return void Make return value void since function never returns meaningfull value. Signed-off-by: Yuval Shaia Signed-off-by: David S. Miller --- drivers/net/ethernet/3com/3c509.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c index db8592d412ab..f66c9710cb81 100644 --- a/drivers/net/ethernet/3com/3c509.c +++ b/drivers/net/ethernet/3com/3c509.c @@ -1039,7 +1039,7 @@ el3_link_ok(struct net_device *dev) return tmp & (1<<11); } -static int +static void el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_link_ksettings *cmd) { u16 tmp; @@ -1082,7 +1082,6 @@ el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_link_ksettings *cmd) supported); cmd->base.speed = SPEED_10; EL3WINDOW(1); - return 0; } static int @@ -1151,12 +1150,11 @@ static int el3_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct el3_private *lp = netdev_priv(dev); - int ret; spin_lock_irq(&lp->lock); - ret = el3_netdev_get_ecmd(dev, cmd); + el3_netdev_get_ecmd(dev, cmd); spin_unlock_irq(&lp->lock); - return ret; + return 0; } static int el3_set_link_ksettings(struct net_device *dev, -- cgit v1.2.3 From 2f878491b3674b7c61d9b214aec35c66e5946da9 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Mon, 5 Jun 2017 01:53:23 +0800 Subject: net-next: stmmac: dwmac-sun8i: ensure the EPHY is properly reseted The EPHY may be already enabled by bootloaders which have Ethernet capability (e.g. current U-Boot). Thus it should be reseted properly before doing the enabling sequence in the dwmac-sun8i driver, otherwise the EMAC reset process may fail if no cable is plugged, and then fail the dwmac-sun8i probing. Tested on Orange Pi PC, One and Zero. All the boards fail to have dwmac-sun8i probed with "EMAC reset timeout" without cable plugged before, and with this fix they're now all able to successfully probe the EMAC without cable plugged and then use the connection after a cable is hot-plugged in. Fixes: 9f93ac8d408 ("net-next: stmmac: Add dwmac-sun8i") Signed-off-by: Icenowy Zheng Tested-by: Corentin Labbe Acked-by: Corentin Labbe Reviewed-by: Corentin Labbe Acked-by: is not as formal as Signed-off-by:. It is a record that the acker Reviewed-by: is similar. Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index 1a6bfe6c958f..54f93ee53ef7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -750,6 +750,11 @@ static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv) return ret; } + /* Make sure the EPHY is properly reseted, as U-Boot may leave + * it at deasserted state, and thus it may fail to reset EMAC. + */ + reset_control_assert(gmac->rst_ephy); + ret = reset_control_deassert(gmac->rst_ephy); if (ret) { dev_err(priv->device, "Cannot deassert ephy\n"); -- cgit v1.2.3 From f5bd90b72d613ad5a9c3b38dee6ae6b5e3565be4 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 16 Mar 2017 10:44:31 +0200 Subject: iwlwifi: mvm: add AMSDU flag to offload assist Enable offload assist for AMSDU when the AMSDU present flag is set. Fixes: a830baba9c2e ("iwlwifi: mvm: support new TX API") Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 64ca8b92f8d2..4d0d23b224c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -480,8 +480,14 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload; u16 offload_assist = iwl_mvm_tx_csum(mvm, skb, hdr, info); + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *qc = ieee80211_get_qos_ctl(hdr); + + if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) + offload_assist |= BIT(TX_CMD_OFFLD_AMSDU); + } + /* padding is inserted later in transport */ - /* FIXME - check for AMSDU may need to be removed */ if (ieee80211_hdrlen(hdr->frame_control) % 4 && !(offload_assist & BIT(TX_CMD_OFFLD_AMSDU))) offload_assist |= BIT(TX_CMD_OFFLD_PAD); -- cgit v1.2.3 From 6857df8c10e6986940ee7e14b587352e928589a2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Mar 2017 14:06:53 +0100 Subject: iwlwifi: mvm: document RX structures Document the structures used in RX and link them to the command ID. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 81 ++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 8 +++ 2 files changed, 84 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index 67dffd725690..ad7ab6dd86cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -349,35 +349,106 @@ enum iwl_rx_mpdu_mac_info { IWL_RX_MPDU_PHY_PHY_INDEX_MASK = 0xf0, }; +/** + * struct iwl_rx_mpdu_desc - RX MPDU descriptor + */ struct iwl_rx_mpdu_desc { /* DW2 */ + /** + * @mpdu_len: MPDU length + */ __le16 mpdu_len; + /** + * @mac_flags1: &enum iwl_rx_mpdu_mac_flags1 + */ u8 mac_flags1; + /** + * @mac_flags2: &enum iwl_rx_mpdu_mac_flags2 + */ u8 mac_flags2; /* DW3 */ + /** + * @amsdu_info: &enum iwl_rx_mpdu_amsdu_info + */ u8 amsdu_info; + /** + * @phy_info: &enum iwl_rx_mpdu_phy_info + */ __le16 phy_info; + /** + * @mac_phy_idx: MAC/PHY index + */ u8 mac_phy_idx; /* DW4 - carries csum data only when rpa_en == 1 */ - __le16 raw_csum; /* alledgedly unreliable */ + /** + * @raw_csum: raw checksum (alledgedly unreliable) + */ + __le16 raw_csum; + /** + * @l3l4_flags: &enum iwl_rx_l3l4_flags + */ __le16 l3l4_flags; /* DW5 */ + /** + * @status: &enum iwl_rx_mpdu_status + */ __le16 status; + /** + * @hash_filter: hash filter value + */ u8 hash_filter; + /** + * @sta_id_flags: &enum iwl_rx_mpdu_sta_id_flags + */ u8 sta_id_flags; /* DW6 */ + /** + * @reorder_data: &enum iwl_rx_mpdu_reorder_data + */ __le32 reorder_data; /* DW7 - carries rss_hash only when rpa_en == 1 */ + /** + * @rss_hash: RSS hash value + */ __le32 rss_hash; /* DW8 - carries filter_match only when rpa_en == 1 */ + /** + * @filter_match: filter match value + */ __le32 filter_match; /* DW9 */ + /** + * @rate_n_flags: RX rate/flags encoding + */ __le32 rate_n_flags; /* DW10 */ - u8 energy_a, energy_b, channel, mac_context; + /** + * @energy_a: energy chain A + */ + u8 energy_a; + /** + * @energy_b: energy chain B + */ + u8 energy_b; + /** + * @channel: channel number + */ + u8 channel; + /** + * @mac_context: MAC context mask + */ + u8 mac_context; /* DW11 */ + /** + * @gp2_on_air_rise: GP2 timer value on air rise (INA) + */ __le32 gp2_on_air_rise; - /* DW12 & DW13 - carries TSF only TSF_OVERLOAD bit == 0 */ + /* DW12 & DW13 */ + /** + * @tsf_on_air_rise: + * TSF value on air rise (INA), only valid if + * %IWL_RX_MPDU_PHY_TSF_OVERLOAD isn't set + */ __le64 tsf_on_air_rise; } __packed; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index ef8b47faa265..23edac4a7009 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -373,7 +373,15 @@ enum iwl_legacy_cmds { */ RSS_CONFIG_CMD = 0xb3, + /** + * @REPLY_RX_PHY_CMD: &struct iwl_rx_phy_info + */ REPLY_RX_PHY_CMD = 0xc0, + + /** + * @REPLY_RX_MPDU_CMD: + * &struct iwl_rx_mpdu_res_start or &struct iwl_rx_mpdu_desc + */ REPLY_RX_MPDU_CMD = 0xc1, FRAME_RELEASE = 0xc3, BA_NOTIF = 0xc5, -- cgit v1.2.3 From 6ffe5de35b05907faf4edb66cfd8ddf3c47e099f Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 16 Mar 2017 11:06:41 +0200 Subject: iwlwifi: pcie: add AMSDU to gen2 This is essentially the same code as gen1, except that it uses gen2 functions and SW checksum is not included. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 3 + drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 172 ++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 3 +- 3 files changed, 172 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index fd4faaaa1484..4b7be7ba9780 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -779,6 +779,9 @@ int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr, size_t size); void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr); void iwl_pcie_apply_destination(struct iwl_trans *trans); +#ifdef CONFIG_INET +struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len); +#endif /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 9c9bfbbabdf1..6e186501f43c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -49,6 +49,7 @@ * *****************************************************************************/ #include +#include #include "iwl-debug.h" #include "iwl-csr.h" @@ -226,6 +227,143 @@ static int iwl_pcie_gen2_set_tb(struct iwl_trans *trans, return idx; } +static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, + struct sk_buff *skb, + struct iwl_tfh_tfd *tfd, int start_len, + u8 hdr_len, struct iwl_device_cmd *dev_cmd) +{ +#ifdef CONFIG_INET + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload; + struct ieee80211_hdr *hdr = (void *)skb->data; + unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; + unsigned int mss = skb_shinfo(skb)->gso_size; + u16 length, iv_len, amsdu_pad; + u8 *start_hdr; + struct iwl_tso_hdr_page *hdr_page; + struct page **page_ptr; + struct tso_t tso; + + /* if the packet is protected, then it must be CCMP or GCMP */ + iv_len = ieee80211_has_protected(hdr->frame_control) ? + IEEE80211_CCMP_HDR_LEN : 0; + + trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), + &dev_cmd->hdr, start_len, NULL, 0); + + ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); + snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); + total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len - iv_len; + amsdu_pad = 0; + + /* total amount of header we may need for this A-MSDU */ + hdr_room = DIV_ROUND_UP(total_len, mss) * + (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len; + + /* Our device supports 9 segments at most, it will fit in 1 page */ + hdr_page = get_page_hdr(trans, hdr_room); + if (!hdr_page) + return -ENOMEM; + + get_page(hdr_page->page); + start_hdr = hdr_page->pos; + page_ptr = (void *)((u8 *)skb->cb + trans_pcie->page_offs); + *page_ptr = hdr_page->page; + memcpy(hdr_page->pos, skb->data + hdr_len, iv_len); + hdr_page->pos += iv_len; + + /* + * Pull the ieee80211 header + IV to be able to use TSO core, + * we will restore it for the tx_status flow. + */ + skb_pull(skb, hdr_len + iv_len); + + /* + * Remove the length of all the headers that we don't actually + * have in the MPDU by themselves, but that we duplicate into + * all the different MSDUs inside the A-MSDU. + */ + le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen); + + tso_start(skb, &tso); + + while (total_len) { + /* this is the data left for this subframe */ + unsigned int data_left = min_t(unsigned int, mss, total_len); + struct sk_buff *csum_skb = NULL; + unsigned int tb_len; + dma_addr_t tb_phys; + struct tcphdr *tcph; + u8 *iph, *subf_hdrs_start = hdr_page->pos; + + total_len -= data_left; + + memset(hdr_page->pos, 0, amsdu_pad); + hdr_page->pos += amsdu_pad; + amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen + + data_left)) & 0x3; + ether_addr_copy(hdr_page->pos, ieee80211_get_DA(hdr)); + hdr_page->pos += ETH_ALEN; + ether_addr_copy(hdr_page->pos, ieee80211_get_SA(hdr)); + hdr_page->pos += ETH_ALEN; + + length = snap_ip_tcp_hdrlen + data_left; + *((__be16 *)hdr_page->pos) = cpu_to_be16(length); + hdr_page->pos += sizeof(length); + + /* + * This will copy the SNAP as well which will be considered + * as MAC header. + */ + tso_build_hdr(skb, hdr_page->pos, &tso, data_left, !total_len); + iph = hdr_page->pos + 8; + tcph = (void *)(iph + ip_hdrlen); + + hdr_page->pos += snap_ip_tcp_hdrlen; + + tb_len = hdr_page->pos - start_hdr; + tb_phys = dma_map_single(trans->dev, start_hdr, + tb_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { + dev_kfree_skb(csum_skb); + goto out_err; + } + iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); + trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr, tb_len); + /* add this subframe's headers' length to the tx_cmd */ + le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); + + /* prepare the start_hdr for the next subframe */ + start_hdr = hdr_page->pos; + + /* put the payload */ + while (data_left) { + tb_len = min_t(unsigned int, tso.size, data_left); + tb_phys = dma_map_single(trans->dev, tso.data, + tb_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { + dev_kfree_skb(csum_skb); + goto out_err; + } + iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); + trace_iwlwifi_dev_tx_tso_chunk(trans->dev, tso.data, + tb_len); + + data_left -= tb_len; + tso_build_data(skb, &tso, tb_len); + } + } + + /* re -add the WiFi header and IV */ + skb_push(skb, hdr_len + iv_len); + + return 0; + +out_err: +#endif + return -EINVAL; +} + static struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, @@ -238,15 +376,21 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); dma_addr_t tb_phys; + bool amsdu; int i, len, tb1_len, tb2_len, hdr_len; void *tb1_addr; memset(tfd, 0, sizeof(*tfd)); + amsdu = ieee80211_is_data_qos(hdr->frame_control) && + (*ieee80211_get_qos_ctl(hdr) & + IEEE80211_QOS_CTL_A_MSDU_PRESENT); + tb_phys = iwl_pcie_get_first_tb_dma(txq, txq->write_ptr); /* The first TB points to bi-directional DMA data */ - memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, - IWL_FIRST_TB_SIZE); + if (!amsdu) + memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, + IWL_FIRST_TB_SIZE); iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, IWL_FIRST_TB_SIZE); @@ -262,7 +406,11 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, len = sizeof(struct iwl_tx_cmd_gen2) + sizeof(struct iwl_cmd_header) + ieee80211_hdrlen(hdr->frame_control) - IWL_FIRST_TB_SIZE; - tb1_len = ALIGN(len, 4); + /* do not align A-MSDU to dword as the subframe header aligns it */ + if (amsdu) + tb1_len = len; + else + tb1_len = ALIGN(len, 4); /* map the data for TB1 */ tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE; @@ -271,8 +419,24 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, goto out_err; iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb1_len); - /* set up TFD's third entry to point to remainder of skb's head */ hdr_len = ieee80211_hdrlen(hdr->frame_control); + + if (amsdu) { + if (!iwl_pcie_gen2_build_amsdu(trans, skb, tfd, + tb1_len + IWL_FIRST_TB_SIZE, + hdr_len, dev_cmd)) + goto out_err; + + /* + * building the A-MSDU might have changed this data, so memcpy + * it now + */ + memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, + IWL_FIRST_TB_SIZE); + return tfd; + } + + /* set up TFD's third entry to point to remainder of skb's head */ tb2_len = skb_headlen(skb) - hdr_len; if (tb2_len > 0) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 386950a2d616..b8675ad91459 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1987,8 +1987,7 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, } #ifdef CONFIG_INET -static struct iwl_tso_hdr_page * -get_page_hdr(struct iwl_trans *trans, size_t len) +struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tso_hdr_page *p = this_cpu_ptr(trans_pcie->tso_hdr_page); -- cgit v1.2.3 From 7042678dffa3707dea3feb34f09241d54e40648c Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 22 Mar 2017 12:20:40 +0200 Subject: iwlwifi: cleanup references to 8000 family in NVM code NVM code is tightly coupled with 8000 family, while it really refers to extended NVM format introduced back then. Separate it to a configuration dependent boolean, and rename defines accordingly. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 3 +- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 3 +- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 3 +- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 4 +- drivers/net/wireless/intel/iwlwifi/iwl-drv.h | 12 +-- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 95 ++++++++++------------ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 22 ++--- 8 files changed, 70 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index b9718c0cf174..502956b0ee91 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -165,7 +165,8 @@ static const struct iwl_tt_params iwl8000_tt_params = { .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B, \ .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, \ .thermal_params = &iwl8000_tt_params, \ - .apmg_not_supported = true + .apmg_not_supported = true, \ + .ext_nvm = true #define IWL_DEVICE_8000 \ IWL_DEVICE_8000_COMMON, \ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index a2ee6aad3ce3..3cb416157e73 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -147,7 +147,8 @@ static const struct iwl_tt_params iwl9000_tt_params = { .mq_rx_supported = true, \ .vht_mu_mimo_supported = true, \ .mac_addr_from_csr = true, \ - .rf_id = true + .rf_id = true, \ + .ext_nvm = true const struct iwl_cfg iwl9160_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9160", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index c648cfb981a3..ca913b3ddd11 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -123,7 +123,8 @@ static const struct iwl_ht_params iwl_a000_ht_params = { .mac_addr_from_csr = true, \ .use_tfh = true, \ .rf_id = true, \ - .gen2 = true + .gen2 = true, \ + .ext_nvm = true const struct iwl_cfg iwla000_2ac_cfg_hr = { .name = "Intel(R) Dual Band Wireless AC a000", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 8b3ebd1d4a3d..f0273ebd29d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -317,6 +317,7 @@ struct iwl_pwr_tx_backoff { * @integrated: discrete or integrated * @gen2: a000 and on transport operation * @cdb: CDB support + * @ext_nvm: extended NVM format * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -365,7 +366,8 @@ struct iwl_cfg { integrated:1, use_tfh:1, gen2:1, - cdb:1; + cdb:1, + ext_nvm:1; u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 6c537e04864e..1f8a2eeb7dff 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -79,12 +79,12 @@ #define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ #define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ -#define NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(x) (x & 0xF) -#define NVM_RF_CFG_DASH_MSK_FAMILY_8000(x) ((x >> 4) & 0xF) -#define NVM_RF_CFG_STEP_MSK_FAMILY_8000(x) ((x >> 8) & 0xF) -#define NVM_RF_CFG_TYPE_MSK_FAMILY_8000(x) ((x >> 12) & 0xFFF) -#define NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(x) ((x >> 24) & 0xF) -#define NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(x) ((x >> 28) & 0xF) +#define EXT_NVM_RF_CFG_FLAVOR_MSK(x) ((x) & 0xF) +#define EXT_NVM_RF_CFG_DASH_MSK(x) (((x) >> 4) & 0xF) +#define EXT_NVM_RF_CFG_STEP_MSK(x) (((x) >> 8) & 0xF) +#define EXT_NVM_RF_CFG_TYPE_MSK(x) (((x) >> 12) & 0xFFF) +#define EXT_NVM_RF_CFG_TX_ANT_MSK(x) (((x) >> 24) & 0xF) +#define EXT_NVM_RF_CFG_RX_ANT_MSK(x) (((x) >> 28) & 0xF) /** * DOC: Driver system flows - drv component diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 721ae6bef5da..070f3dfb94ce 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -94,30 +94,21 @@ enum wkp_nvm_offsets { XTAL_CALIB = 0x316 - NVM_CALIB_SECTION }; -enum family_8000_nvm_offsets { +enum ext_nvm_offsets { /* NVM HW-Section offset (in words) definitions */ - HW_ADDR0_WFPM_FAMILY_8000 = 0x12, - HW_ADDR1_WFPM_FAMILY_8000 = 0x16, - HW_ADDR0_PCIE_FAMILY_8000 = 0x8A, - HW_ADDR1_PCIE_FAMILY_8000 = 0x8E, - MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1, + MAC_ADDRESS_OVERRIDE_EXT_NVM = 1, /* NVM SW-Section offset (in words) definitions */ - NVM_SW_SECTION_FAMILY_8000 = 0x1C0, - NVM_VERSION_FAMILY_8000 = 0, - RADIO_CFG_FAMILY_8000 = 0, + NVM_VERSION_EXT_NVM = 0, + RADIO_CFG_FAMILY_EXT_NVM = 0, SKU_FAMILY_8000 = 2, N_HW_ADDRS_FAMILY_8000 = 3, /* NVM REGULATORY -Section offset (in words) definitions */ - NVM_CHANNELS_FAMILY_8000 = 0, - NVM_LAR_OFFSET_FAMILY_8000_OLD = 0x4C7, - NVM_LAR_OFFSET_FAMILY_8000 = 0x507, - NVM_LAR_ENABLED_FAMILY_8000 = 0x7, - - /* NVM calibration section offset (in words) definitions */ - NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8, - XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000 + NVM_CHANNELS_EXTENDED = 0, + NVM_LAR_OFFSET_OLD = 0x4C7, + NVM_LAR_OFFSET = 0x507, + NVM_LAR_ENABLED = 0x7, }; /* SKU Capabilities (actual values from NVM definition) */ @@ -141,7 +132,7 @@ static const u8 iwl_nvm_channels[] = { 149, 153, 157, 161, 165 }; -static const u8 iwl_nvm_channels_family_8000[] = { +static const u8 iwl_ext_nvm_channels[] = { /* 2.4 GHz */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 5 GHz */ @@ -151,9 +142,9 @@ static const u8 iwl_nvm_channels_family_8000[] = { }; #define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) -#define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000) +#define IWL_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels) #define NUM_2GHZ_CHANNELS 14 -#define NUM_2GHZ_CHANNELS_FAMILY_8000 14 +#define NUM_2GHZ_CHANNELS_EXT 14 #define FIRST_2GHZ_HT_MINUS 5 #define LAST_2GHZ_HT_PLUS 9 #define LAST_5GHZ_HT 165 @@ -219,7 +210,7 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, u32 flags = IEEE80211_CHAN_NO_HT40; u32 last_5ghz_ht = LAST_5GHZ_HT; - if (cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (cfg->ext_nvm) last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000; if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) { @@ -273,14 +264,14 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, num_2ghz_channels; const u8 *nvm_chan; - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!cfg->ext_nvm) { num_of_ch = IWL_NUM_CHANNELS; nvm_chan = &iwl_nvm_channels[0]; num_2ghz_channels = NUM_2GHZ_CHANNELS; } else { - num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000; - nvm_chan = &iwl_nvm_channels_family_8000[0]; - num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000; + num_of_ch = IWL_NUM_CHANNELS_EXT; + nvm_chan = &iwl_ext_nvm_channels[0]; + num_2ghz_channels = NUM_2GHZ_CHANNELS_EXT; } for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { @@ -479,7 +470,7 @@ IWL_EXPORT_SYMBOL(iwl_init_sbands); static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw, const __le16 *phy_sku) { - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) return le16_to_cpup(nvm_sw + SKU); return le32_to_cpup((__le32 *)(phy_sku + SKU_FAMILY_8000)); @@ -487,20 +478,20 @@ static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw, static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw) { - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) return le16_to_cpup(nvm_sw + NVM_VERSION); else return le32_to_cpup((__le32 *)(nvm_sw + - NVM_VERSION_FAMILY_8000)); + NVM_VERSION_EXT_NVM)); } static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw, const __le16 *phy_sku) { - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) return le16_to_cpup(nvm_sw + RADIO_CFG); - return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_8000)); + return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_EXT_NVM)); } @@ -508,7 +499,7 @@ static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, const __le16 *nvm_sw) { int n_hw_addr; - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) return le16_to_cpup(nvm_sw + N_HW_ADDRS); n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)); @@ -520,7 +511,7 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, struct iwl_nvm_data *data, u32 radio_cfg) { - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!cfg->ext_nvm) { data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); @@ -529,12 +520,12 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, } /* set the radio configuration for family 8000 */ - data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg); - data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg); - data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg); - data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg); - data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg); - data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg); + data->radio_cfg_type = EXT_NVM_RF_CFG_TYPE_MSK(radio_cfg); + data->radio_cfg_step = EXT_NVM_RF_CFG_STEP_MSK(radio_cfg); + data->radio_cfg_dash = EXT_NVM_RF_CFG_DASH_MSK(radio_cfg); + data->radio_cfg_pnum = EXT_NVM_RF_CFG_FLAVOR_MSK(radio_cfg); + data->valid_tx_ant = EXT_NVM_RF_CFG_TX_ANT_MSK(radio_cfg); + data->valid_rx_ant = EXT_NVM_RF_CFG_RX_ANT_MSK(radio_cfg); } static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) @@ -587,7 +578,7 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, }; hw_addr = (const u8 *)(mac_override + - MAC_ADDRESS_OVERRIDE_FAMILY_8000); + MAC_ADDRESS_OVERRIDE_EXT_NVM); /* * Store the MAC address from MAO section. @@ -629,7 +620,7 @@ static int iwl_set_hw_address(struct iwl_trans *trans, { if (cfg->mac_addr_from_csr) { iwl_set_hw_address_from_csr(trans, data); - } else if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + } else if (!cfg->ext_nvm) { const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR); /* The byte order is little endian 16 bit, meaning 214365 */ @@ -666,7 +657,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, u16 lar_config; const __le16 *ch_section; - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (!cfg->ext_nvm) data = kzalloc(sizeof(*data) + sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, @@ -674,7 +665,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, else data = kzalloc(sizeof(*data) + sizeof(struct ieee80211_channel) * - IWL_NUM_CHANNELS_FAMILY_8000, + IWL_NUM_CHANNELS_EXT, GFP_KERNEL); if (!data) return NULL; @@ -700,7 +691,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); - if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!cfg->ext_nvm) { /* Checking for required sections */ if (!nvm_calib) { IWL_ERR(trans, @@ -715,14 +706,14 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, ch_section = &nvm_sw[NVM_CHANNELS]; } else { u16 lar_offset = data->nvm_version < 0xE39 ? - NVM_LAR_OFFSET_FAMILY_8000_OLD : - NVM_LAR_OFFSET_FAMILY_8000; + NVM_LAR_OFFSET_OLD : + NVM_LAR_OFFSET; lar_config = le16_to_cpup(regulatory + lar_offset); data->lar_enabled = !!(lar_config & - NVM_LAR_ENABLED_FAMILY_8000); + NVM_LAR_ENABLED); lar_enabled = data->lar_enabled; - ch_section = ®ulatory[NVM_CHANNELS_FAMILY_8000]; + ch_section = ®ulatory[NVM_CHANNELS_EXTENDED]; } /* If no valid mac address was found - bail out */ @@ -746,7 +737,7 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan, u32 flags = NL80211_RRF_NO_HT40; u32 last_5ghz_ht = LAST_5GHZ_HT; - if (cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (cfg->ext_nvm) last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000; if (ch_idx < NUM_2GHZ_CHANNELS && @@ -793,8 +784,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, { int ch_idx; u16 ch_flags, prev_ch_flags = 0; - const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? - iwl_nvm_channels_family_8000 : iwl_nvm_channels; + const u8 *nvm_chan = cfg->ext_nvm ? + iwl_ext_nvm_channels : iwl_nvm_channels; struct ieee80211_regdomain *regd; int size_of_regd; struct ieee80211_reg_rule *rule; @@ -802,8 +793,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int center_freq, prev_center_freq = 0; int valid_rules = 0; bool new_rule; - int max_num_ch = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? - IWL_NUM_CHANNELS_FAMILY_8000 : IWL_NUM_CHANNELS; + int max_num_ch = cfg->ext_nvm ? + IWL_NUM_CHANNELS_EXT : IWL_NUM_CHANNELS; if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) return ERR_PTR(-EINVAL); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index aa725bbb90ec..7519fda01792 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1188,7 +1188,7 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) * Enable LAR only if it is supported by the FW (TLV) && * enabled in the NVM */ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (mvm->cfg->ext_nvm) return nvm_lar && tlv_lar; else return tlv_lar; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index e7b16ecccb86..e7631a9620bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -77,7 +77,7 @@ /* Default NVM size to read */ #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) #define IWL_MAX_NVM_SECTION_SIZE 0x1b58 -#define IWL_MAX_NVM_8000_SECTION_SIZE 0x1ffc +#define IWL_MAX_EXT_NVM_SECTION_SIZE 0x1ffc #define NVM_WRITE_OPCODE 1 #define NVM_READ_OPCODE 0 @@ -300,7 +300,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) bool lar_enabled; /* Checking for required sections */ - if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!mvm->trans->cfg->ext_nvm) { if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || !mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) { IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n"); @@ -391,19 +391,19 @@ int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) #define NVM_WORD2_ID(x) (x >> 12) -#define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8)) -#define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4) +#define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8)) +#define EXT_NVM_WORD1_ID(x) ((x) >> 4) #define NVM_HEADER_0 (0x2A504C54) #define NVM_HEADER_1 (0x4E564D2A) #define NVM_HEADER_SIZE (4 * sizeof(u32)) IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); - /* Maximal size depends on HW family and step */ - if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + /* Maximal size depends on NVM version */ + if (!mvm->trans->cfg->ext_nvm) max_section_size = IWL_MAX_NVM_SECTION_SIZE; else - max_section_size = IWL_MAX_NVM_8000_SECTION_SIZE; + max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE; /* * Obtain NVM image via request_firmware. Since we already used @@ -472,14 +472,14 @@ int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) break; } - if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (!mvm->trans->cfg->ext_nvm) { section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); } else { - section_size = 2 * NVM_WORD2_LEN_FAMILY_8000( + section_size = 2 * EXT_NVM_WORD2_LEN( le16_to_cpu(file_sec->word2)); - section_id = NVM_WORD1_ID_FAMILY_8000( + section_id = EXT_NVM_WORD1_ID( le16_to_cpu(file_sec->word1)); } @@ -846,7 +846,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) struct ieee80211_regdomain *regd; char mcc[3]; - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + if (mvm->cfg->ext_nvm) { tlv_lar = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT); nvm_lar = mvm->nvm_data->lar_enabled; -- cgit v1.2.3 From 8b4d649552ca857d4f6e903d2f51fec8936e65f0 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 22 Mar 2017 13:51:12 +0200 Subject: iwlwifi: remove references to 8000 B-step devices We don't have any 8000 B-step right now, and there is no firmware loading code for them anyway. Further more, 9000 B-step devices will hit those code paths. Remove code that was introduced only for 8000 B-step. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 2 -- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 - drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 21 --------------------- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 14 ++------------ 4 files changed, 2 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index 502956b0ee91..4d6135b5ff92 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -98,7 +98,6 @@ IWL8265_FW_PRE __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_8000 10 -#define DEFAULT_NVM_FILE_FAMILY_8000B "nvmData-8000B" #define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C" /* Max SDIO RX/TX aggregation sizes of the ADDBA request/response */ @@ -162,7 +161,6 @@ static const struct iwl_tt_params iwl8000_tt_params = { .dccm2_len = IWL8260_DCCM2_LEN, \ .smem_offset = IWL8260_SMEM_OFFSET, \ .smem_len = IWL8260_SMEM_LEN, \ - .default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B, \ .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, \ .thermal_params = &iwl8000_tt_params, \ .apmg_not_supported = true, \ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index f0273ebd29d8..5b0f1d65d199 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -335,7 +335,6 @@ struct iwl_cfg { const struct iwl_ht_params *ht_params; const struct iwl_eeprom_params *eeprom_params; const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; - const char *default_nvm_file_B_step; const char *default_nvm_file_C_step; const struct iwl_tt_params *thermal_params; enum iwl_device_family device_family; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index d8b592aa362c..8aa2992e1427 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -705,14 +705,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) sizeof(*dump_info); } - /* - * In 8000 HW family B-step include the ICCM (which resides separately) - */ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) - file_len += sizeof(*dump_data) + sizeof(*dump_mem) + - IWL8260_ICCM_LEN; - if (mvm->fw_dump_desc) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + mvm->fw_dump_desc->len; @@ -837,19 +829,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_data = iwl_fw_error_next_data(dump_data); } - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) { - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); - dump_data->len = cpu_to_le32(IWL8260_ICCM_LEN + - sizeof(*dump_mem)); - dump_mem = (void *)dump_data->data; - dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); - dump_mem->offset = cpu_to_le32(IWL8260_ICCM_OFFSET); - iwl_trans_read_mem_bytes(mvm->trans, IWL8260_ICCM_OFFSET, - dump_mem->data, IWL8260_ICCM_LEN); - dump_data = iwl_fw_error_next_data(dump_data); - } - /* Dump fw's virtual image */ if (!mvm->trans->cfg->gen2 && mvm->fw->img[mvm->cur_ucode].paging_mem_size && diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index e7631a9620bf..30ecbc14b3d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -448,9 +448,7 @@ int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) /* nvm file validation, dword_buff[2] holds the file version */ if ((CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP && - le32_to_cpu(dword_buff[2]) < 0xE4A) || - (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP && - le32_to_cpu(dword_buff[2]) >= 0xE4A)) { + le32_to_cpu(dword_buff[2]) < 0xE4A)) { ret = -EFAULT; goto out; } @@ -644,7 +642,6 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) int ret, section; u32 size_read = 0; u8 *nvm_buffer, *temp; - const char *nvm_file_B = mvm->cfg->default_nvm_file_B_step; const char *nvm_file_C = mvm->cfg->default_nvm_file_C_step; if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) @@ -714,14 +711,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) /* read External NVM file from the mod param */ ret = iwl_mvm_read_external_nvm(mvm); if (ret) { - /* choose the nvm_file name according to the - * HW step - */ - if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == - SILICON_B_STEP) - mvm->nvm_file_name = nvm_file_B; - else - mvm->nvm_file_name = nvm_file_C; + mvm->nvm_file_name = nvm_file_C; if ((ret == -EFAULT || ret == -ENOENT) && mvm->nvm_file_name) { -- cgit v1.2.3 From a02797c15dd98434774fa67b323ebee158dc6ecf Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 22 Mar 2017 14:06:41 +0200 Subject: iwlwifi: add dbgc_supported to transport configuration Use transport configuration to determine DBGC support instead of relying on device family. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 3 ++- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 3 ++- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 3 ++- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index 4d6135b5ff92..5d446740383a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -164,7 +164,8 @@ static const struct iwl_tt_params iwl8000_tt_params = { .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, \ .thermal_params = &iwl8000_tt_params, \ .apmg_not_supported = true, \ - .ext_nvm = true + .ext_nvm = true, \ + .dbgc_supported = true #define IWL_DEVICE_8000 \ IWL_DEVICE_8000_COMMON, \ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index 3cb416157e73..c7e6ba878af8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -148,7 +148,8 @@ static const struct iwl_tt_params iwl9000_tt_params = { .vht_mu_mimo_supported = true, \ .mac_addr_from_csr = true, \ .rf_id = true, \ - .ext_nvm = true + .ext_nvm = true, \ + .dbgc_supported = true const struct iwl_cfg iwl9160_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9160", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index ca913b3ddd11..9d09c7ebc3c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -124,7 +124,8 @@ static const struct iwl_ht_params iwl_a000_ht_params = { .use_tfh = true, \ .rf_id = true, \ .gen2 = true, \ - .ext_nvm = true + .ext_nvm = true, \ + .dbgc_supported = true const struct iwl_cfg iwla000_2ac_cfg_hr = { .name = "Intel(R) Dual Band Wireless AC a000", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 5b0f1d65d199..f7533045dbce 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -366,7 +366,8 @@ struct iwl_cfg { use_tfh:1, gen2:1, cdb:1, - ext_nvm:1; + ext_nvm:1, + dbgc_supported:1; u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; -- cgit v1.2.3 From 1247070d4763cf0dc8bd7b313d606941c6464e69 Mon Sep 17 00:00:00 2001 From: Beni Lev Date: Sun, 19 Mar 2017 19:03:51 +0200 Subject: iwlwifi: mvm: add TLV for NAN API differentiation Due to NAN FW API change, add TLV in order to distiguish between the 2 API versions Signed-off-by: Beni Lev Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index c178c8f32466..52616f3c0184 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -244,6 +244,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_TKIP_MIC_KEYS: This ucode supports version 2 of * ADD_MODIFY_STA_KEY_API_S_VER_2. * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. + * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -255,6 +256,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_SCAN_TSF_REPORT = (__force iwl_ucode_tlv_api_t)28, IWL_UCODE_TLV_API_TKIP_MIC_KEYS = (__force iwl_ucode_tlv_api_t)29, IWL_UCODE_TLV_API_STA_TYPE = (__force iwl_ucode_tlv_api_t)30, + IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31, NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ -- cgit v1.2.3 From de8ba41b5e5002e28756963df311246485c330d5 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Thu, 16 Mar 2017 13:00:59 +0200 Subject: iwlwifi: mvm: support init flow debugging In case an assert happens on init flow, the current driver powers down the NIC, except if iwlmvm modparam init_dbg=1, and only on very specific flows. Extend this capability to cover most failure cases by keeping track of what init configurations have been completed. This way, we can allow NOT powering down the NIC, while making sure that when the driver is removed we don't try to free resources that haven't been allocated. (This can result in a kernel panic.) Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 ++- drivers/net/wireless/intel/iwlwifi/mvm/led.c | 5 ++++- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 10 ++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 18 +++++++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/tof.c | 6 +++++- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 5 +++++ 7 files changed, 42 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 8bdeb7c891e9..16200960baf2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1639,7 +1639,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; error: - iwl_mvm_stop_device(mvm); + if (!iwlmvm_mod_params.init_dbg) + iwl_mvm_stop_device(mvm); return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c index 1e51fbe95f7c..3cac4278a5fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c @@ -123,14 +123,17 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm) return ret; } + mvm->init_status |= IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE; return 0; } void iwl_mvm_leds_exit(struct iwl_mvm *mvm) { - if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE) + if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE || + !(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE)) return; led_classdev_unregister(&mvm->led); kfree(mvm->led.name); + mvm->init_status &= ~IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 50510e96a82d..f52c251cd891 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -735,6 +735,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ret = ieee80211_register_hw(mvm->hw); if (ret) iwl_mvm_leds_exit(mvm); + mvm->init_status |= IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE; if (mvm->cfg->vht_mu_mimo_supported) wiphy_ext_feature_set(hw->wiphy, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 7519fda01792..05489694979e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -754,6 +754,8 @@ struct iwl_mvm { struct work_struct roc_done_wk; + unsigned long init_status; + unsigned long status; u32 queue_sync_cookie; @@ -1088,6 +1090,14 @@ enum iwl_mvm_status { IWL_MVM_STATUS_DUMPING_FW_LOG, }; +/* Keep track of completed init configuration */ +enum iwl_mvm_init_status { + IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE = BIT(0), + IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE = BIT(1), + IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE = BIT(2), + IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE = BIT(3), +}; + static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) { return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status) || diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 607cc83908b5..085dbe4d0fe9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -589,6 +590,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->fw = fw; mvm->hw = hw; + mvm->init_status = 0; + if (iwl_mvm_has_new_rx_api(mvm)) { op_mode->ops = &iwl_mvm_ops_mq; trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc); @@ -753,7 +756,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE); mutex_unlock(&mvm->mutex); /* returns 0 if successful, 1 if success but in rfkill */ - if (err < 0 && !iwlmvm_mod_params.init_dbg) { + if (err < 0) { IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); goto out_free; } @@ -791,12 +794,18 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, return op_mode; out_unregister: + if (iwlmvm_mod_params.init_dbg) + return op_mode; + ieee80211_unregister_hw(mvm->hw); mvm->hw_registered = false; iwl_mvm_leds_exit(mvm); iwl_mvm_thermal_exit(mvm); out_free: flush_delayed_work(&mvm->fw_dump_wk); + + if (iwlmvm_mod_params.init_dbg) + return op_mode; iwl_phy_db_free(mvm->phy_db); kfree(mvm->scan_cmd); iwl_trans_op_mode_leave(trans); @@ -821,7 +830,10 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) iwl_mvm_thermal_exit(mvm); - ieee80211_unregister_hw(mvm->hw); + if (mvm->init_status & IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE) { + ieee80211_unregister_hw(mvm->hw); + mvm->init_status &= ~IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE; + } kfree(mvm->scan_cmd); kfree(mvm->mcast_filter_cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c index 16ce8a56b5b9..634175b2480c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c @@ -93,17 +93,21 @@ void iwl_mvm_tof_init(struct iwl_mvm *mvm) cpu_to_le32(TOF_RANGE_REQ_EXT_CMD); mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + mvm->init_status |= IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE; } void iwl_mvm_tof_clean(struct iwl_mvm *mvm) { struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_TOF_SUPPORT) || + !(mvm->init_status & IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE)) return; memset(tof_data, 0, sizeof(*tof_data)); mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + mvm->init_status &= ~IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE; } static void iwl_tof_iterator(void *_data, u8 *mac, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index f9cbd197246f..4e03ea911a1f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -882,10 +882,14 @@ void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff) iwl_mvm_cooling_device_register(mvm); iwl_mvm_thermal_zone_register(mvm); #endif + mvm->init_status |= IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE; } void iwl_mvm_thermal_exit(struct iwl_mvm *mvm) { + if (!(mvm->init_status & IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE)) + return; + cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit); IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n"); @@ -893,4 +897,5 @@ void iwl_mvm_thermal_exit(struct iwl_mvm *mvm) iwl_mvm_cooling_device_unregister(mvm); iwl_mvm_thermal_zone_unregister(mvm); #endif + mvm->init_status &= ~IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE; } -- cgit v1.2.3 From 6e5848732288d93f14bb30ce81f09950988556dd Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 22 Mar 2017 14:07:50 +0200 Subject: iwlwifi: add 9000 and A000 device families Add two new device families to differentiate them from 8000. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-io.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 5 +++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 13 +++++++------ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 16 ++++++++-------- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 +- 11 files changed, 29 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index c7e6ba878af8..0f520d138414 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -128,7 +128,7 @@ static const struct iwl_tt_params iwl9000_tt_params = { #define IWL_DEVICE_9000 \ .ucode_api_max = IWL9000_UCODE_API_MAX, \ .ucode_api_min = IWL9000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_8000, \ + .device_family = IWL_DEVICE_FAMILY_9000, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl9000_base_params, \ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index 9d09c7ebc3c4..32ba70190d3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -103,7 +103,7 @@ static const struct iwl_ht_params iwl_a000_ht_params = { #define IWL_DEVICE_A000 \ .ucode_api_max = IWL_A000_UCODE_API_MAX, \ .ucode_api_min = IWL_A000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_8000, \ + .device_family = IWL_DEVICE_FAMILY_A000, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl_a000_base_params, \ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index f7533045dbce..f3236ea7edb5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -88,6 +88,8 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_6150, IWL_DEVICE_FAMILY_7000, IWL_DEVICE_FAMILY_8000, + IWL_DEVICE_FAMILY_9000, + IWL_DEVICE_FAMILY_A000, }; /* diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 806933377c58..c8d451474b64 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -215,7 +215,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) char tag[8]; const char *fw_pre_name; - if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_9000 && CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_B_STEP) fw_pre_name = cfg->fw_name_pre_next_step; else if (drv->trans->cfg->integrated && diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 9c8b09cf1f7b..c527b8c10370 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -241,12 +241,12 @@ IWL_EXPORT_SYMBOL(iwl_clear_bits_prph); void iwl_force_nmi(struct iwl_trans *trans) { - if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { + if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) { iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL_DRV); iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL_HW); - } else if (trans->cfg->gen2) { + } else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_A000) { iwl_write_prph(trans, UREG_NIC_SET_NMI_DRIVER, DEVICE_SET_NMI_8000_VAL); } else { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 402846650cbe..59aaab8274c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1008,7 +1008,7 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm, return -EOPNOTSUPP; if (dest->monitor_mode != SMEM_MODE || - trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) return -EOPNOTSUPP; ret = kstrtoint(buf, 0, &rec_mode); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 16200960baf2..26ccfbc34cfd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -644,12 +644,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, if (ret) { struct iwl_trans *trans = mvm->trans; - if (trans->cfg->gen2) + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_A000) IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", iwl_read_prph(trans, UMAG_SB_CPU_1_STATUS), iwl_read_prph(trans, UMAG_SB_CPU_2_STATUS)); - else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + else if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", iwl_read_prph(trans, SB_CPU_1_STATUS), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 30ecbc14b3d0..87b9ebfc653e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -447,8 +447,9 @@ int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) le32_to_cpu(dword_buff[3])); /* nvm file validation, dword_buff[2] holds the file version */ - if ((CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP && - le32_to_cpu(dword_buff[2]) < 0xE4A)) { + if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP && + le32_to_cpu(dword_buff[2]) < 0xE4A) { ret = -EFAULT; goto out; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 085dbe4d0fe9..2cf9a523f84b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -173,13 +173,14 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); /* - * TODO: Bits 7-8 of CSR in 8000 HW family set the ADC sampling, and - * shouldn't be set to any non-zero value. The same is supposed to be - * true of the other HW, but unsetting them (such as the 7260) causes - * automatic tests to fail on seemingly unrelated errors. Need to - * further investigate this, but for now we'll separate cases. + * TODO: Bits 7-8 of CSR in 8000 HW family and higher set the ADC + * sampling, and shouldn't be set to any non-zero value. + * The same is supposed to be true of the other HW, but unsetting + * them (such as the 7260) causes automatic tests to fail on seemingly + * unrelated errors. Need to further investigate this, but for now + * we'll separate cases. */ - if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index a6c171c5b26f..3af02f491e80 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -245,7 +245,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) */ /* Disable L0S exit timer (platform NMI Work/Around) */ - if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); @@ -478,7 +478,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_WAKE_ME); - else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + else if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) { iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, @@ -892,7 +892,7 @@ monitor: if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { iwl_write_prph(trans, le32_to_cpu(dest->base_reg), trans_pcie->fw_mon_phys >> dest->base_shift); - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) iwl_write_prph(trans, le32_to_cpu(dest->end_reg), (trans_pcie->fw_mon_phys + trans_pcie->fw_mon_size - 256) >> @@ -1318,7 +1318,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); /* Load the given image to the HW */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) ret = iwl_pcie_load_given_ucode_8000(trans, fw); else ret = iwl_pcie_load_given_ucode(trans, fw); @@ -1435,7 +1435,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); ret = iwl_poll_bit(trans, CSR_GP_CNTRL, @@ -1822,7 +1822,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, /* this bit wakes up the NIC */ __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); /* @@ -2726,7 +2726,7 @@ static struct iwl_trans_dump_data trans->dbg_dest_tlv->end_shift; /* Make "end" point to the actual end */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 || + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000 || trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) end += (1 << trans->dbg_dest_tlv->end_shift); monitor_len = end - base; @@ -3029,7 +3029,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, * "dash" value). To keep hw_rev backwards compatible - we'll store it * in the old format. */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) { unsigned long flags; trans->hw_rev = (trans->hw_rev & 0xfff0) | diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index b8675ad91459..61b171ee32ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -762,7 +762,7 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); /* Enable L1-Active */ - if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); } -- cgit v1.2.3 From 723b45e24150f1b9bde5c1f51f1a845982cb4eeb Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 26 Mar 2017 13:56:28 +0300 Subject: iwlwifi: pcie: support dumping FH in a000 hw FH in A000 HW are placed in a different location, and need to be read as prph, rather than direct. Support A000 dumping as well as legacy. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 2 ++ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 62f9fe926d78..2a992277c671 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -77,6 +77,8 @@ */ #define FH_MEM_LOWER_BOUND (0x1000) #define FH_MEM_UPPER_BOUND (0x2000) +#define FH_MEM_LOWER_BOUND_GEN2 (0xa06000) +#define FH_MEM_UPPER_BOUND_GEN2 (0xa08000) /** * Keep-Warm (KW) buffer base address. diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 3af02f491e80..375bdca15704 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2575,8 +2575,15 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans, (*data)->len = cpu_to_le32(fh_regs_len); val = (void *)(*data)->data; - for (i = FH_MEM_LOWER_BOUND; i < FH_MEM_UPPER_BOUND; i += sizeof(u32)) - *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); + if (!trans->cfg->gen2) + for (i = FH_MEM_LOWER_BOUND; i < FH_MEM_UPPER_BOUND; + i += sizeof(u32)) + *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); + else + for (i = FH_MEM_LOWER_BOUND_GEN2; i < FH_MEM_UPPER_BOUND_GEN2; + i += sizeof(u32)) + *val++ = cpu_to_le32(iwl_trans_pcie_read_prph(trans, + i)); iwl_trans_release_nic_access(trans, &flags); @@ -2752,7 +2759,12 @@ static struct iwl_trans_dump_data len += sizeof(*data) + IWL_CSR_TO_DUMP; /* FH registers */ - len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); + if (trans->cfg->gen2) + len += sizeof(*data) + + (FH_MEM_UPPER_BOUND_GEN2 - FH_MEM_LOWER_BOUND_GEN2); + else + len += sizeof(*data) + + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); if (dump_rbs) { /* Dump RBs is supported only for pre-9000 devices (1 queue) */ -- cgit v1.2.3 From 9eca702ca1da715199c104363cad041d989aafd1 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 26 Mar 2017 14:09:46 +0300 Subject: iwlwifi: mvm: disable prph collection in a000 hw Apart from the current list of PRPH that can't be collected in A000 HW, the rest of the debug dump data the driver collects is valid, so there is no need to disable collection only because of this. Disable PRPH collecting in A000 HW, and allow collecting the rest of the debug data. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index 8aa2992e1427..aac0426112c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -640,18 +640,21 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } /* Make room for PRPH registers */ - for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); i++) { - /* The range includes both boundaries */ - int num_bytes_in_chunk = - iwl_prph_dump_addr_comm[i].end - - iwl_prph_dump_addr_comm[i].start + 4; - - prph_len += sizeof(*dump_data) + - sizeof(struct iwl_fw_error_dump_prph) + - num_bytes_in_chunk; + if (!mvm->trans->cfg->gen2) { + for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); + i++) { + /* The range includes both boundaries */ + int num_bytes_in_chunk = + iwl_prph_dump_addr_comm[i].end - + iwl_prph_dump_addr_comm[i].start + 4; + + prph_len += sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_prph) + + num_bytes_in_chunk; + } } - if (mvm->cfg->mq_rx_supported) { + if (!mvm->trans->cfg->gen2 && mvm->cfg->mq_rx_supported) { for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) { /* The range includes both boundaries */ -- cgit v1.2.3 From 504bd624663cde6141ab025445c93420c387062e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Mar 2017 22:19:41 +0100 Subject: iwlwifi: mvm: check firmware is up in debugfs Protect various debugfs files that need to communicate with the firmware from being used when the firmware isn't running. Some will just reject getting written to, while others that store some state will simply store it and not apply it immediately. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 55 +++++++++++++++++++++--- 1 file changed, 49 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 59aaab8274c2..25092cb08c2e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -583,7 +583,11 @@ iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf, mvm->bt_force_ant_mode = bt_force_ant_mode; IWL_DEBUG_COEX(mvm, "Force mode: %s\n", modes_str[mvm->bt_force_ant_mode]); - ret = iwl_send_bt_init_conf(mvm); + + if (iwl_mvm_firmware_running(mvm)) + ret = iwl_send_bt_init_conf(mvm); + else + ret = 0; out: mutex_unlock(&mvm->mutex); @@ -800,6 +804,9 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, { int __maybe_unused ret; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + mutex_lock(&mvm->mutex); /* allow one more restart that we're provoking here */ @@ -817,7 +824,12 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI); + int ret; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI); if (ret) return ret; @@ -857,6 +869,9 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, { u8 scan_rx_ant; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + if (sscanf(buf, "%hhx", &scan_rx_ant) != 1) return -EINVAL; if (scan_rx_ant > ANT_ABC) @@ -911,7 +926,11 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm, netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key)); mutex_lock(&mvm->mutex); - ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); + if (iwl_mvm_firmware_running(mvm)) + ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, + sizeof(cmd), &cmd); + else + ret = 0; mutex_unlock(&mvm->mutex); return ret ?: count; @@ -931,6 +950,9 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm, int bin_len = count / 2; int ret = -EINVAL; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + /* supporting only 9000 descriptor */ if (!mvm->trans->cfg->mq_rx_supported) return -ENOTSUPP; @@ -1004,6 +1026,9 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm, struct iwl_continuous_record_cmd cont_rec = {}; int ret, rec_mode; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + if (!dest) return -EOPNOTSUPP; @@ -1034,6 +1059,9 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, unsigned int conf_id; int ret; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + ret = kstrtouint(buf, 0, &conf_id); if (ret) return ret; @@ -1052,8 +1080,12 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); + int ret; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); if (ret) return ret; if (count == 0) @@ -1184,7 +1216,8 @@ static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf, &filter, sizeof(filter)); /* send updated bcast filtering configuration */ - if (mvm->dbgfs_bcast_filtering.override && + if (iwl_mvm_firmware_running(mvm) && + mvm->dbgfs_bcast_filtering.override && iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, sizeof(cmd), &cmd); @@ -1256,7 +1289,8 @@ static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm, &mac, sizeof(mac)); /* send updated bcast filtering configuration */ - if (mvm->dbgfs_bcast_filtering.override && + if (iwl_mvm_firmware_running(mvm) && + mvm->dbgfs_bcast_filtering.override && iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, sizeof(cmd), &cmd); @@ -1473,6 +1507,9 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf, { int ret; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + mutex_lock(&mvm->mutex); ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL); mutex_unlock(&mvm->mutex); @@ -1534,6 +1571,9 @@ static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, size_t delta; ssize_t ret, len; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR, DEBUG_GROUP, 0); cmd.op = cpu_to_le32(DEBUG_MEM_OP_READ); @@ -1586,6 +1626,9 @@ static ssize_t iwl_dbgfs_mem_write(struct file *file, u32 op, len; ssize_t ret; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR, DEBUG_GROUP, 0); -- cgit v1.2.3 From 86bbb1e1e0ba8878b554bbb912d348f3b819f5c4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Mar 2017 21:44:59 +0100 Subject: iwlwifi: mvm: use schedule_delayed_work() There's no need to refer to system_wq directly, use the provided wrapper schedule_delayed_work(). Made with the following spatch: @@ expression E,F; @@ -queue_delayed_work(system_wq, E, F); +schedule_delayed_work(E, F); Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 6 +++--- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index aac0426112c7..a8353ea1df58 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -927,7 +927,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, mvm->fw_dump_desc = desc; mvm->fw_dump_trig = trigger; - queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay); + schedule_delayed_work(&mvm->fw_dump_wk, delay); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 0f1831b41915..d0806d27df58 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1632,9 +1632,9 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n"); - queue_delayed_work(system_wq, &mvm->cs_tx_unblock_dwork, - msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT * - csa_vif->bss_conf.beacon_int)); + schedule_delayed_work(&mvm->cs_tx_unblock_dwork, + msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT * + csa_vif->bss_conf.beacon_int)); ieee80211_csa_finish(csa_vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 8d1b994ae79f..d48c2ecc0893 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1421,8 +1421,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->scan_vif = iwl_mvm_vif_from_mac80211(vif); iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); - queue_delayed_work(system_wq, &mvm->scan_timeout_dwork, - msecs_to_jiffies(SCAN_TIMEOUT)); + schedule_delayed_work(&mvm->scan_timeout_dwork, + msecs_to_jiffies(SCAN_TIMEOUT)); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index df7cd87199ea..3d97436bbdf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -551,8 +551,7 @@ void iwl_mvm_tdls_ch_switch_work(struct work_struct *work) /* retry after a DTIM if we failed sending now */ delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int); - queue_delayed_work(system_wq, &mvm->tdls_cs.dwork, - msecs_to_jiffies(delay)); + schedule_delayed_work(&mvm->tdls_cs.dwork, msecs_to_jiffies(delay)); out: mutex_unlock(&mvm->mutex); } -- cgit v1.2.3 From aab6930d30d5176fe1ff38fe051a9fca2cac066d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Mar 2017 22:05:12 +0100 Subject: iwlwifi: mvm: add and use iwl_mvm_device_running() This will help refactor this later. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 25 ++++++++++++++--------- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 +++++ drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 13 ++++++++---- 4 files changed, 30 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 25092cb08c2e..744dc069ff23 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -82,7 +83,8 @@ static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, char buf[16]; int pos, budget; - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; mutex_lock(&mvm->mutex); @@ -102,7 +104,8 @@ static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf, { int ret; - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; mutex_lock(&mvm->mutex); @@ -118,7 +121,8 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, int ret; u32 scd_q_msk; - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; if (sscanf(buf, "%x", &scd_q_msk) != 1) @@ -139,7 +143,8 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, struct iwl_mvm_sta *mvmsta; int sta_id, drain, ret; - if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) @@ -172,7 +177,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t ret; u8 *ptr; - if (!mvm->ucode_loaded) + if (!iwl_mvm_firmware_running(mvm)) return -EINVAL; /* default is to dump the entire data segment */ @@ -205,7 +210,7 @@ static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, u32 offset, len; u32 img_offset, img_len; - if (!mvm->ucode_loaded) + if (!iwl_mvm_firmware_running(mvm)) return -EINVAL; img = &mvm->fw->img[mvm->cur_ucode]; @@ -258,7 +263,7 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, { int temperature; - if (!mvm->ucode_loaded && !mvm->temperature_test) + if (!iwl_mvm_firmware_running(mvm) && !mvm->temperature_test) return -EIO; if (kstrtoint(buf, 10, &temperature)) @@ -305,7 +310,7 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file, int pos, ret; s32 temp; - if (!mvm->ucode_loaded) + if (!iwl_mvm_firmware_running(mvm)) return -EIO; mutex_lock(&mvm->mutex); @@ -371,7 +376,7 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, { int ret, val; - if (!mvm->ucode_loaded) + if (!iwl_mvm_firmware_running(mvm)) return -EIO; if (!strncmp("disable_power_off_d0=", buf, 21)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index f52c251cd891..9e0c0f0e5999 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4028,7 +4028,7 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, mutex_lock(&mvm->mutex); - if (mvm->ucode_loaded) { + if (iwl_mvm_firmware_running(mvm)) { ret = iwl_mvm_request_statistics(mvm, false); if (ret) goto out; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 05489694979e..b47e1f1efc8a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1109,6 +1109,11 @@ static inline bool iwl_mvm_is_radio_hw_killed(struct iwl_mvm *mvm) return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); } +static inline bool iwl_mvm_firmware_running(struct iwl_mvm *mvm) +{ + return mvm->ucode_loaded; +} + /* Must be called with rcu_read_lock() held and it can only be * released when mvmsta is not needed anymore. */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 4e03ea911a1f..6414a46e8bb5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -628,7 +628,8 @@ static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device, mutex_lock(&mvm->mutex); - if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) { + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) { ret = -EIO; goto out; } @@ -678,7 +679,8 @@ static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device, mutex_lock(&mvm->mutex); - if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) { + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) { ret = -EIO; goto out; } @@ -790,8 +792,11 @@ static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev, struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata); int ret; - if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) - return -EIO; + if (!iwl_mvm_firmware_running(mvm) || + mvm->cur_ucode != IWL_UCODE_REGULAR) { + ret = -EIO; + goto unlock; + } mutex_lock(&mvm->mutex); -- cgit v1.2.3 From 65b280fe9bde124587f9ca290404515d52513b3f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Mar 2017 22:10:36 +0100 Subject: iwlwifi: mvm: convert ucode_loaded to a status bit Convert ucode_loaded to a status bit called FIRMWARE_RUNNING. This will make it easier to clear this earlier, to avoid any spurious accesses while shutting down, for example through debugfs. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 26ccfbc34cfd..24cc406d87ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -622,7 +622,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, if (WARN_ON(!fw)) return -EINVAL; mvm->cur_ucode = ucode_type; - mvm->ucode_loaded = false; + clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); iwl_init_notification_wait(&mvm->notif_wait, &alive_wait, alive_cmd, ARRAY_SIZE(alive_cmd), @@ -696,7 +696,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, for (i = 0; i < IEEE80211_MAX_QUEUES; i++) atomic_set(&mvm->mac80211_queue_stop_count[i], 0); - mvm->ucode_loaded = true; + set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b47e1f1efc8a..73bd56e06d95 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -767,7 +767,6 @@ struct iwl_mvm { struct iwl_mvm_vif *bf_allowed_vif; enum iwl_ucode_type cur_ucode; - bool ucode_loaded; bool hw_registered; bool calibrating; u32 error_event_table[2]; @@ -1088,6 +1087,7 @@ enum iwl_mvm_status { IWL_MVM_STATUS_ROC_AUX_RUNNING, IWL_MVM_STATUS_D3_RECONFIG, IWL_MVM_STATUS_DUMPING_FW_LOG, + IWL_MVM_STATUS_FIRMWARE_RUNNING, }; /* Keep track of completed init configuration */ @@ -1111,7 +1111,7 @@ static inline bool iwl_mvm_is_radio_hw_killed(struct iwl_mvm *mvm) static inline bool iwl_mvm_firmware_running(struct iwl_mvm *mvm) { - return mvm->ucode_loaded; + return test_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); } /* Must be called with rcu_read_lock() held and it can only be @@ -1771,7 +1771,7 @@ static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) { if (!iwl_mvm_has_new_tx_api(mvm)) iwl_free_fw_paging(mvm); - mvm->ucode_loaded = false; + clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); iwl_trans_stop_device(mvm->trans); } -- cgit v1.2.3 From 771147b0676fb545b7fd268277452609bcaf9243 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Mar 2017 22:26:03 +0100 Subject: iwlwifi: mvm: clear firmware running bit earlier Clear the firmware running bit before flushing the FW (error) dump work, because otherwise debugfs isn't blocked (previous patch) and can cause a new work to be scheduled, which will then run after we actually shut down the device, wreaking havoc. Clearing it ensures that debugfs can't interfere anymore, and we can safely cancel or flush the work struct. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 9e0c0f0e5999..08f86e77eba5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1244,6 +1244,17 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) flush_work(&mvm->d0i3_exit_work); flush_work(&mvm->async_handlers_wk); flush_work(&mvm->add_stream_wk); + + /* + * Lock and clear the firmware running bit here already, so that + * new commands coming in elsewhere, e.g. from debugfs, will not + * be able to proceed. This is important here because one of those + * debugfs files causes the fw_dump_wk to be triggered, and if we + * don't stop debugfs accesses before canceling that it could be + * retriggered after we flush it but before we've cleared the bit. + */ + clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); + cancel_delayed_work_sync(&mvm->fw_dump_wk); cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork); cancel_delayed_work_sync(&mvm->scan_timeout_dwork); -- cgit v1.2.3 From b8aed81cd38151928d7af81f2f2ed98481809f2f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Mar 2017 14:21:54 +0200 Subject: iwlwifi: fix a kernel-doc tag The kernel-doc here is on an enum, so don't tag it as struct but correctly as enum instead, preventing an error. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index d3a78a11821a..63e4857718c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -308,7 +308,7 @@ struct iwl_device_cmd { #define IWL_MAX_CMD_TBS_PER_TFD 2 /** - * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command + * enum iwl_hcmd_dataflag - flag for each one of the chunks of the command * * @IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's * ring. The transport layer doesn't map the command's buffer to DMA, but -- cgit v1.2.3 From 0aaece81114e403315ae01a6cd36044e32922d3b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Mar 2017 14:30:40 +0200 Subject: iwlwifi: split firmware API from iwl-trans.h In order to more clearly document which parts of this file are firmware API and which are something else, split the firmware API into a separate file to include here. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h | 205 ++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 137 +--------------- 2 files changed, 206 insertions(+), 136 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h new file mode 100644 index 000000000000..a004409fa984 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h @@ -0,0 +1,205 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_fw_api_h__ +#define __iwl_fw_api_h__ + +/** + * DOC: Host command section + * + * A host command is a command issued by the upper layer to the fw. There are + * several versions of fw that have several APIs. The transport layer is + * completely agnostic to these differences. + * The transport does provide helper functionality (i.e. SYNC / ASYNC mode), + */ +#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) +#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) +#define SEQ_TO_INDEX(s) ((s) & 0xff) +#define INDEX_TO_SEQ(i) ((i) & 0xff) +#define SEQ_RX_FRAME cpu_to_le16(0x8000) + +/* + * those functions retrieve specific information from + * the id field in the iwl_host_cmd struct which contains + * the command id, the group id and the version of the command + * and vice versa +*/ +static inline u8 iwl_cmd_opcode(u32 cmdid) +{ + return cmdid & 0xFF; +} + +static inline u8 iwl_cmd_groupid(u32 cmdid) +{ + return ((cmdid & 0xFF00) >> 8); +} + +static inline u8 iwl_cmd_version(u32 cmdid) +{ + return ((cmdid & 0xFF0000) >> 16); +} + +static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) +{ + return opcode + (groupid << 8) + (version << 16); +} + +/* make u16 wide id out of u8 group and opcode */ +#define WIDE_ID(grp, opcode) (((grp) << 8) | (opcode)) +#define DEF_ID(opcode) ((1 << 8) | (opcode)) + +/* due to the conversion, this group is special; new groups + * should be defined in the appropriate fw-api header files + */ +#define IWL_ALWAYS_LONG_GROUP 1 + +/** + * struct iwl_cmd_header + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + */ +struct iwl_cmd_header { + u8 cmd; /* Command ID: REPLY_RXON, etc. */ + u8 group_id; + /* + * The driver sets up the sequence number to values of its choosing. + * uCode does not use this value, but passes it back to the driver + * when sending the response to each driver-originated command, so + * the driver can match the response to the command. Since the values + * don't get used by uCode, the driver may set up an arbitrary format. + * + * There is one exception: uCode sets bit 15 when it originates + * the response/notification, i.e. when the response/notification + * is not a direct response to a command sent by the driver. For + * example, uCode issues REPLY_RX when it sends a received frame + * to the driver; it is not a direct response to any driver command. + * + * The Linux driver uses the following format: + * + * 0:7 tfd index - position within TX queue + * 8:12 TX queue id + * 13:14 reserved + * 15 unsolicited RX or uCode-originated notification + */ + __le16 sequence; +} __packed; + +/** + * struct iwl_cmd_header_wide + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + * this is the wide version that contains more information about the command + * like length, version and command type + */ +struct iwl_cmd_header_wide { + u8 cmd; + u8 group_id; + __le16 sequence; + __le16 length; + u8 reserved; + u8 version; +} __packed; + +/** + * iwl_tx_queue_cfg_actions - TXQ config options + * @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue + * @TX_QUEUE_CFG_TFD_SHORT_FORMAT: use short TFD format + */ +enum iwl_tx_queue_cfg_actions { + TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0), + TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), +}; + +/** + * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command + * @sta_id: station id + * @tid: tid of the queue + * @flags: see &enum iwl_tx_queue_cfg_actions + * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. + * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) + * @byte_cnt_addr: address of byte count table + * @tfdq_addr: address of TFD circular buffer + */ +struct iwl_tx_queue_cfg_cmd { + u8 sta_id; + u8 tid; + __le16 flags; + __le32 cb_size; + __le64 byte_cnt_addr; + __le64 tfdq_addr; +} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ + +/** + * struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config + * @queue_number: queue number assigned to this RA -TID + * @flags: set on failure + * @write_pointer: initial value for write pointer + */ +struct iwl_tx_queue_cfg_rsp { + __le16 queue_number; + __le16 flags; + __le16 write_pointer; + __le16 reserved; +} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ + +#endif /* __iwl_fw_api_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 63e4857718c7..e965285f84f1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -76,6 +76,7 @@ #include "iwl-config.h" #include "iwl-fw.h" #include "iwl-op-mode.h" +#include "iwl-fw-api.h" /** * DOC: Transport layer - what is it ? @@ -111,104 +112,6 @@ * 6) Eventually, the free function will be called. */ -/** - * DOC: Host command section - * - * A host command is a command issued by the upper layer to the fw. There are - * several versions of fw that have several APIs. The transport layer is - * completely agnostic to these differences. - * The transport does provide helper functionality (i.e. SYNC / ASYNC mode), - */ -#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) -#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) -#define SEQ_TO_INDEX(s) ((s) & 0xff) -#define INDEX_TO_SEQ(i) ((i) & 0xff) -#define SEQ_RX_FRAME cpu_to_le16(0x8000) - -/* - * those functions retrieve specific information from - * the id field in the iwl_host_cmd struct which contains - * the command id, the group id and the version of the command - * and vice versa -*/ -static inline u8 iwl_cmd_opcode(u32 cmdid) -{ - return cmdid & 0xFF; -} - -static inline u8 iwl_cmd_groupid(u32 cmdid) -{ - return ((cmdid & 0xFF00) >> 8); -} - -static inline u8 iwl_cmd_version(u32 cmdid) -{ - return ((cmdid & 0xFF0000) >> 16); -} - -static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) -{ - return opcode + (groupid << 8) + (version << 16); -} - -/* make u16 wide id out of u8 group and opcode */ -#define WIDE_ID(grp, opcode) ((grp << 8) | opcode) -#define DEF_ID(opcode) ((1 << 8) | (opcode)) - -/* due to the conversion, this group is special; new groups - * should be defined in the appropriate fw-api header files - */ -#define IWL_ALWAYS_LONG_GROUP 1 - -/** - * struct iwl_cmd_header - * - * This header format appears in the beginning of each command sent from the - * driver, and each response/notification received from uCode. - */ -struct iwl_cmd_header { - u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 group_id; - /* - * The driver sets up the sequence number to values of its choosing. - * uCode does not use this value, but passes it back to the driver - * when sending the response to each driver-originated command, so - * the driver can match the response to the command. Since the values - * don't get used by uCode, the driver may set up an arbitrary format. - * - * There is one exception: uCode sets bit 15 when it originates - * the response/notification, i.e. when the response/notification - * is not a direct response to a command sent by the driver. For - * example, uCode issues REPLY_RX when it sends a received frame - * to the driver; it is not a direct response to any driver command. - * - * The Linux driver uses the following format: - * - * 0:7 tfd index - position within TX queue - * 8:12 TX queue id - * 13:14 reserved - * 15 unsolicited RX or uCode-originated notification - */ - __le16 sequence; -} __packed; - -/** - * struct iwl_cmd_header_wide - * - * This header format appears in the beginning of each command sent from the - * driver, and each response/notification received from uCode. - * this is the wide version that contains more information about the command - * like length, version and command type - */ -struct iwl_cmd_header_wide { - u8 cmd; - u8 group_id; - __le16 sequence; - __le16 length; - u8 reserved; - u8 version; -} __packed; - #define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */ #define FH_RSCSR_FRAME_INVALID 0x55550000 #define FH_RSCSR_FRAME_ALIGN 0x40 @@ -533,44 +436,6 @@ struct iwl_trans_txq_scd_cfg { int frame_limit; }; -/* Available options for &struct iwl_tx_queue_cfg_cmd */ -enum iwl_tx_queue_cfg_actions { - TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0), - TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), -}; - -/** - * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command - * @sta_id: station id - * @tid: tid of the queue - * @flags: Bit 0 - on enable, off - disable, Bit 1 - short TFD format - * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. - * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) - * @byte_cnt_addr: address of byte count table - * @tfdq_addr: address of TFD circular buffer - */ -struct iwl_tx_queue_cfg_cmd { - u8 sta_id; - u8 tid; - __le16 flags; - __le32 cb_size; - __le64 byte_cnt_addr; - __le64 tfdq_addr; -} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ - -/** - * struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config - * @queue_number: queue number assigned to this RA -TID - * @flags: set on failure - * @write_pointer: initial value for write pointer - */ -struct iwl_tx_queue_cfg_rsp { - __le16 queue_number; - __le16 flags; - __le16 write_pointer; - __le16 reserved; -} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ - /** * struct iwl_trans_ops - transport specific operations * -- cgit v1.2.3 From e153c1e4c37fcffa26e901251767c1404db83934 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Mar 2017 14:23:21 +0200 Subject: iwlwifi: mvm: link queue cmd docs to A000 command structs Document which structures are used with the command for the A000 hardware flavour. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 23edac4a7009..bf0523d8ca9a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -232,7 +232,9 @@ enum iwl_legacy_cmds { /* scheduler config */ /** - * @SCD_QUEUE_CFG: &struct iwl_scd_txq_cfg_cmd + * @SCD_QUEUE_CFG: &struct iwl_scd_txq_cfg_cmd for older hardware, + * &struct iwl_tx_queue_cfg_cmd with &struct iwl_tx_queue_cfg_rsp + * for newer (A000) hardware. */ SCD_QUEUE_CFG = 0x1d, -- cgit v1.2.3 From b7bea642d5e53291aaa1a55adbcaa7e481d11940 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Mar 2017 10:48:17 +0200 Subject: iwlwifi: mvm: document structures used for BEACON_TEMPLATE_CMD Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index bf0523d8ca9a..19cb0ee120c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -328,6 +328,12 @@ enum iwl_legacy_cmds { SET_CALIB_DEFAULT_CMD = 0x8e, BEACON_NOTIFICATION = 0x90, + /** + * @BEACON_TEMPLATE_CMD: + * Uses one of &struct iwl_mac_beacon_cmd_v6, + * &struct iwl_mac_beacon_cmd_v7 or &struct iwl_mac_beacon_cmd + * depending on the device version. + */ BEACON_TEMPLATE_CMD = 0x91, /** * @TX_ANT_CONFIGURATION_CMD: &struct iwl_tx_ant_cfg_cmd -- cgit v1.2.3 From e8226a5e4a687cbf9133f47b5d166eb09ddcda1d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Mar 2017 11:25:52 +0200 Subject: iwlwifi: mvm: link to TX commands in documentation Link from the TX_CMD enum value to the TX command structs. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 19cb0ee120c5..cfadc5fb0e1d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -215,7 +215,9 @@ enum iwl_legacy_cmds { /* paging get item */ FW_GET_ITEM_CMD = 0x1a, - /* TX */ + /** + * @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2 + */ TX_CMD = 0x1c, /** -- cgit v1.2.3 From 12edae864161c5fe9f7e5d9fad0d599f344e970d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Mar 2017 14:17:51 +0200 Subject: iwlwifi: mvm: remove SCAN_GROUP The firmware no longer uses this command group, so remove it from the driver as well. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index cfadc5fb0e1d..cc6af9bd4e10 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -571,7 +571,6 @@ enum iwl_debug_cmds { * &enum iwl_phy_ops_subcmd_ids * @DATA_PATH_GROUP: data path group, uses command IDs from * &enum iwl_data_path_subcmd_ids - * @SCAN_GROUP: scan group, uses command IDs from &enum iwl_scan_subcmd_ids * @NAN_GROUP: NAN group, uses command IDs from &enum iwl_nan_subcmd_ids * @TOF_GROUP: TOF group, uses command IDs from &enum iwl_tof_subcmd_ids * @PROT_OFFLOAD_GROUP: protocol offload group, uses command IDs from -- cgit v1.2.3 From fccdbaa849f62a0992f8b77878a13e3c54161b87 Mon Sep 17 00:00:00 2001 From: Mordechai Goodstein Date: Sun, 2 Apr 2017 18:25:06 +0300 Subject: iwlwifi: fw-api: cleanup cycle includes The include in the deleted file are included in the fw-api.h file. Which caused a cycle include in the dependencies. Signed-off-by: Mordechai Goodstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h | 2 -- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h index dded91d7eb96..d27c67b67015 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h @@ -68,8 +68,6 @@ #ifndef __fw_api_scan_h__ #define __fw_api_scan_h__ -#include "fw-api.h" - /* Scan Commands, Responses, Notifications */ /* Max number of IEs for direct SSID scans in a command */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h index eae036af880e..e2acf39f784d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h @@ -63,8 +63,6 @@ #ifndef __fw_api_tof_h__ #define __fw_api_tof_h__ -#include "fw-api.h" - /* ToF sub-group command IDs */ enum iwl_mvm_tof_sub_grp_ids { TOF_RANGE_REQ_CMD = 0x1, -- cgit v1.2.3 From b7e94bab81dc9cba5269542b2da524fc749078af Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 5 Jun 2017 23:21:19 +0300 Subject: iwlwifi: bump max FW API to 31 Bump the maximum accepted firmware API number for devices in the 8000, 9000 and A000 families. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index 5d446740383a..707f282b5afd 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -70,8 +70,8 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 30 -#define IWL8265_UCODE_API_MAX 30 +#define IWL8000_UCODE_API_MAX 31 +#define IWL8265_UCODE_API_MAX 31 /* Lowest firmware API version supported */ #define IWL8000_UCODE_API_MIN 17 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index 0f520d138414..42daaddfa740 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 30 +#define IWL9000_UCODE_API_MAX 31 /* Lowest firmware API version supported */ #define IWL9000_UCODE_API_MIN 30 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index 32ba70190d3d..63a4183c0de7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL_A000_UCODE_API_MAX 30 +#define IWL_A000_UCODE_API_MAX 31 /* Lowest firmware API version supported */ #define IWL_A000_UCODE_API_MIN 24 -- cgit v1.2.3 From 0ae0bb3f409d48251a9a1730a514b3521d8f6042 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 5 Apr 2017 09:42:18 +0300 Subject: iwlwifi: remove unnecessary code in iwl_trans_alloc_tx_cmd When we removed dev_cmd_headroom, the check for dev_cmd_ptr == NULL became unnecessary, since we just return dev_cmd_ptr anyway. Cleanup the function to avoid useless code. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index e965285f84f1..a150da3c824b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -908,13 +908,7 @@ iwl_trans_dump_data(struct iwl_trans *trans, static inline struct iwl_device_cmd * iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) { - struct iwl_device_cmd *dev_cmd_ptr = - kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC); - - if (unlikely(dev_cmd_ptr == NULL)) - return NULL; - - return dev_cmd_ptr; + return kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC); } int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); -- cgit v1.2.3 From 9d15e5cc8cb68326f7f89b76e04c834fe8e1a2db Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 5 Jun 2017 19:08:04 +0100 Subject: mdio: mux: fix an incorrect less than zero error check using a u32 The u32 variable v is being checked to see if an error return is less than zero and this check has no effect because it is unsigned. Fix this by making v and int (this also matches the type of cb->bus_number which is assigned to the value in v). Detected by CoverityScan, CID#1440454 ("Unsigned compared against zero") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/phy/mdio-mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 47ded3904050..00755b6a42cf 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c @@ -133,7 +133,7 @@ int mdio_mux_init(struct device *dev, ret_val = -ENODEV; for_each_available_child_of_node(dev->of_node, child_bus_node) { - u32 v; + int v; v = of_mdio_parse_addr(dev, child_bus_node); if (v < 0) { -- cgit v1.2.3 From 440aeca4b9858248d8f16d724d9fa87a4f65fa33 Mon Sep 17 00:00:00 2001 From: Matwey V Kornilov Date: Thu, 24 Nov 2016 13:32:48 +0300 Subject: igb: Explicitly select page 0 at initialization The functions igb_read_phy_reg_gs40g/igb_write_phy_reg_gs40g (which were removed in 2a3cdea) explicitly selected the required page at every phy_reg access. Currently, igb_get_phy_id_82575 relays on the fact that page 0 is already selected. The assumption is not fulfilled for my Lex 3I380CW motherboard with integrated dual i211 based gigabit ethernet. This leads to igb initialization failure and network interfaces are not working: igb: Intel(R) Gigabit Ethernet Network Driver - version 5.4.0-k igb: Copyright (c) 2007-2014 Intel Corporation. igb: probe of 0000:01:00.0 failed with error -2 igb: probe of 0000:02:00.0 failed with error -2 In order to fix it, we explicitly select page 0 before first access to phy registers. See also: https://bugzilla.suse.com/show_bug.cgi?id=1009911 See also: http://www.lex.com.tw/products/pdf/3I380A&3I380CW.pdf Fixes: 2a3cdea ("igb: Remove GS40G specific defines/functions") Cc: # 4.5+ Signed-off-by: Matwey V Kornilov Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index ee443985581f..4a50870e0fa7 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -257,6 +257,7 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) } /* Set phy->phy_addr and phy->id. */ + igb_write_phy_reg_82580(hw, I347AT4_PAGE_SELECT, 0); ret_val = igb_get_phy_id_82575(hw); if (ret_val) return ret_val; -- cgit v1.2.3 From 000ba1f2ebf0d6f93b9ae6cfbe5417e66f1b8e8c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 27 Apr 2017 21:09:52 +0200 Subject: igb: mark PM functions as __maybe_unused The new wake function is only used by the suspend/resume handlers that are defined in inside of an #ifdef, which can cause this harmless warning: drivers/net/ethernet/intel/igb/igb_main.c:7988:13: warning: 'igb_deliver_wake_packet' defined but not used [-Wunused-function] Removing the #ifdef, instead using a __maybe_unused annotation simplifies the code and avoids the warning. Fixes: b90fa8763560 ("igb: Enable reading of wake up packet") Signed-off-by: Arnd Bergmann Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 1cf74aa4ebd9..2d5bdb1fd37d 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -191,10 +191,7 @@ static int igb_disable_sriov(struct pci_dev *dev); static int igb_pci_disable_sriov(struct pci_dev *dev); #endif -#ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP static int igb_suspend(struct device *); -#endif static int igb_resume(struct device *); static int igb_runtime_suspend(struct device *dev); static int igb_runtime_resume(struct device *dev); @@ -204,7 +201,6 @@ static const struct dev_pm_ops igb_pm_ops = { SET_RUNTIME_PM_OPS(igb_runtime_suspend, igb_runtime_resume, igb_runtime_idle) }; -#endif static void igb_shutdown(struct pci_dev *); static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs); #ifdef CONFIG_IGB_DCA @@ -8015,9 +8011,7 @@ static void igb_deliver_wake_packet(struct net_device *netdev) netif_rx(skb); } -#ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP -static int igb_suspend(struct device *dev) +static int __maybe_unused igb_suspend(struct device *dev) { int retval; bool wake; @@ -8036,9 +8030,8 @@ static int igb_suspend(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ -static int igb_resume(struct device *dev) +static int __maybe_unused igb_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); @@ -8092,7 +8085,7 @@ static int igb_resume(struct device *dev) return err; } -static int igb_runtime_idle(struct device *dev) +static int __maybe_unused igb_runtime_idle(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); @@ -8104,7 +8097,7 @@ static int igb_runtime_idle(struct device *dev) return -EBUSY; } -static int igb_runtime_suspend(struct device *dev) +static int __maybe_unused igb_runtime_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); int retval; @@ -8124,11 +8117,10 @@ static int igb_runtime_suspend(struct device *dev) return 0; } -static int igb_runtime_resume(struct device *dev) +static int __maybe_unused igb_runtime_resume(struct device *dev) { return igb_resume(dev); } -#endif /* CONFIG_PM */ static void igb_shutdown(struct pci_dev *pdev) { -- cgit v1.2.3 From 5012863b7347866764c4a4e58b62fb05346b0d06 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:50 -0700 Subject: e1000e: fix race condition around skb_tstamp_tx() The e1000e driver and related hardware has a limitation on Tx PTP packets which requires we limit to timestamping a single packet at once. We do this by verifying that we never request a new Tx timestamp while we still have a tx_hwtstamp_skb pointer. Unfortunately the driver suffers from a race condition around this. The tx_hwtstamp_skb pointer is not set to NULL until after skb_tstamp_tx() is called. This function notifies the stack and applications of a new timestamp. Even a well behaved application that only sends a new request when the first one is finished might be woken up and possibly send a packet before we can free the timestamp in the driver again. The result is that we needlessly ignore some Tx timestamp requests in this corner case. Fix this by assigning the tx_hwtstamp_skb pointer prior to calling skb_tstamp_tx() and use a temporary pointer to hold the timestamped skb until that function finishes. This ensures that the application is not woken up until the driver is ready to begin timestamping a new packet. This ensures that well behaved applications do not accidentally race with condition to skip Tx timestamps. Obviously an application which sends multiple Tx timestamp requests at once will still only timestamp one packet at a time. Unfortunately there is nothing we can do about this. Reported-by: David Mirabito Signed-off-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 6ed3bc419b96..96257349a1b8 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1183,6 +1183,7 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) struct e1000_hw *hw = &adapter->hw; if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) { + struct sk_buff *skb = adapter->tx_hwtstamp_skb; struct skb_shared_hwtstamps shhwtstamps; u64 txstmp; @@ -1191,9 +1192,14 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp); - skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps); - dev_kfree_skb_any(adapter->tx_hwtstamp_skb); + /* Clear the global tx_hwtstamp_skb pointer and force writes + * prior to notifying the stack of a Tx timestamp. + */ adapter->tx_hwtstamp_skb = NULL; + wmb(); /* force write prior to skb_tstamp_tx */ + + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } else if (time_after(jiffies, adapter->tx_hwtstamp_start + adapter->tx_timeout_factor * HZ)) { dev_kfree_skb_any(adapter->tx_hwtstamp_skb); -- cgit v1.2.3 From 4ccdc013b0ae04755a8f7905e0525955d52a77d0 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:52 -0700 Subject: igb: fix race condition with PTP_TX_IN_PROGRESS bits Hardware related to the igb driver has a limitation of only handling one Tx timestamp at a time. Thus, the driver uses a state bit lock to enforce that only one timestamp request is honored at a time. Unfortunately this suffers from a simple race condition. The bit lock is not cleared until after skb_tstamp_tx() is called notifying the stack of a new Tx timestamp. Even a well behaved application which sends only one timestamp request at once and waits for a response might wake up and send a new packet before the bit lock is cleared. This results in needlessly dropping some Tx timestamp requests. We can fix this by unlocking the state bit as soon as we read the Timestamp register, as this is the first point at which it is safe to unlock. To avoid issues with the skb pointer, we'll use a copy of the pointer and set the global variable in the driver structure to NULL first. This ensures that the next timestamp request does not modify our local copy of the skb pointer. This ensures that well behaved applications do not accidentally race with the unlock bit. Obviously an application which sends multiple Tx timestamp requests at once will still only timestamp one packet at a time. Unfortunately there is nothing we can do about this. Reported-by: David Mirabito Signed-off-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_ptp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index d333d6d80194..ffd2c7c36d9c 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -721,6 +721,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter) **/ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) { + struct sk_buff *skb = adapter->ptp_tx_skb; struct e1000_hw *hw = &adapter->hw; struct skb_shared_hwtstamps shhwtstamps; u64 regval; @@ -748,10 +749,17 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) shhwtstamps.hwtstamp = ktime_add_ns(shhwtstamps.hwtstamp, adjust); - skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps); - dev_kfree_skb_any(adapter->ptp_tx_skb); + /* Clear the lock early before calling skb_tstamp_tx so that + * applications are not woken up before the lock bit is clear. We use + * a copy of the skb pointer to ensure other threads can't change it + * while we're notifying the stack. + */ adapter->ptp_tx_skb = NULL; clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); + + /* Notify the stack and free the skb after we've unlocked */ + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } /** -- cgit v1.2.3 From 74344e32fcc0d09342b77ed9d23ea74b3799d157 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:55 -0700 Subject: igb: avoid permanent lock of *_PTP_TX_IN_PROGRESS The igb driver uses a state bit lock to avoid handling more than one Tx timestamp request at once. This is required because hardware is limited to a single set of registers for Tx timestamps. The state bit lock is not properly cleaned up during igb_xmit_frame_ring() if the transmit fails such as due to DMA or TSO failure. In some hardware this results in blocking timestamps until the service task times out. In other hardware this results in a permanent lock of the timestamp bit because we never receive an interrupt indicating the timestamp occurred, since indeed the packet was never transmitted. Fix this by checking for DMA and TSO errors in igb_xmit_frame_ring() and properly cleaning up after ourselves when these occur. Reported-by: Reported-by: David Mirabito Signed-off-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 2d5bdb1fd37d..fefa46120cbc 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -5197,9 +5197,9 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size) return __igb_maybe_stop_tx(tx_ring, size); } -static void igb_tx_map(struct igb_ring *tx_ring, - struct igb_tx_buffer *first, - const u8 hdr_len) +static int igb_tx_map(struct igb_ring *tx_ring, + struct igb_tx_buffer *first, + const u8 hdr_len) { struct sk_buff *skb = first->skb; struct igb_tx_buffer *tx_buffer; @@ -5310,7 +5310,7 @@ static void igb_tx_map(struct igb_ring *tx_ring, */ mmiowb(); } - return; + return 0; dma_error: dev_err(tx_ring->dev, "TX DMA map failed\n"); @@ -5341,6 +5341,8 @@ dma_error: tx_buffer->skb = NULL; tx_ring->next_to_use = i; + + return -1; } netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, @@ -5406,13 +5408,24 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, else if (!tso) igb_tx_csum(tx_ring, first); - igb_tx_map(tx_ring, first, hdr_len); + if (igb_tx_map(tx_ring, first, hdr_len)) + goto cleanup_tx_tstamp; return NETDEV_TX_OK; out_drop: dev_kfree_skb_any(first->skb); first->skb = NULL; +cleanup_tx_tstamp: + if (unlikely(tx_flags & IGB_TX_FLAGS_TSTAMP)) { + struct igb_adapter *adapter = netdev_priv(tx_ring->netdev); + + dev_kfree_skb_any(adapter->ptp_tx_skb); + adapter->ptp_tx_skb = NULL; + if (adapter->hw.mac.type == e1000_82576) + cancel_work_sync(&adapter->ptp_tx_work); + clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); + } return NETDEV_TX_OK; } -- cgit v1.2.3 From cff57141456482b410a2312b88467ceb4c26d75d Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:57 -0700 Subject: e1000e: add statistic indicating number of skipped Tx timestamps The e1000e driver can only handle one Tx timestamp request at a time. This means it is possible for an application timestamp request to be ignored. There is no easy way for an administrator to determine if this occurred. Add a new statistic which tracks this, tx_hwtstamp_skipped. Signed-off-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/e1000.h | 1 + drivers/net/ethernet/intel/e1000e/ethtool.c | 1 + drivers/net/ethernet/intel/e1000e/netdev.c | 17 ++++++++++------- 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index c7c994eb410e..98e68888abb1 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -268,6 +268,7 @@ struct e1000_adapter { u32 tx_fifo_size; u32 tx_dma_failed; u32 tx_hwtstamp_timeouts; + u32 tx_hwtstamp_skipped; /* Rx */ bool (*clean_rx)(struct e1000_ring *ring, int *work_done, diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index e23dbd9190d6..c658f6ebf7cb 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -105,6 +105,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { E1000_STAT("uncorr_ecc_errors", uncorr_errors), E1000_STAT("corr_ecc_errors", corr_errors), E1000_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), + E1000_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), }; #define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 96257349a1b8..fc1d92ca3ea2 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5867,13 +5867,16 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, nr_frags); if (count) { if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - (adapter->flags & FLAG_HAS_HW_TIMESTAMP) && - !adapter->tx_hwtstamp_skb) { - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - tx_flags |= E1000_TX_FLAGS_HWTSTAMP; - adapter->tx_hwtstamp_skb = skb_get(skb); - adapter->tx_hwtstamp_start = jiffies; - schedule_work(&adapter->tx_hwtstamp_work); + (adapter->flags & FLAG_HAS_HW_TIMESTAMP)) { + if (!adapter->tx_hwtstamp_skb) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + tx_flags |= E1000_TX_FLAGS_HWTSTAMP; + adapter->tx_hwtstamp_skb = skb_get(skb); + adapter->tx_hwtstamp_start = jiffies; + schedule_work(&adapter->tx_hwtstamp_work); + } else { + adapter->tx_hwtstamp_skipped++; + } } skb_tx_timestamp(skb); -- cgit v1.2.3 From c3b8f85ec24674896aac9a6e41235b8d38db3dde Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:59 -0700 Subject: igb: add statistic indicating number of skipped Tx timestamps The igb driver can only handle one Tx timestamp request at a time. This means it is possible for an application timestamp request to be ignored. There is no easy way for an administrator to determine if this occurred. Add a new statistic which tracks this, tx_hwtstamp_skipped. Signed-off-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb.h | 1 + drivers/net/ethernet/intel/igb/igb_ethtool.c | 1 + drivers/net/ethernet/intel/igb/igb_main.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index bf9bf9056d0c..be35edcf6b08 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -563,6 +563,7 @@ struct igb_adapter { struct cyclecounter cc; struct timecounter tc; u32 tx_hwtstamp_timeouts; + u32 tx_hwtstamp_skipped; u32 rx_hwtstamp_cleared; bool pps_sys_wrap_on; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 0efb62db6efd..8730f7cbce68 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -90,6 +90,7 @@ static const struct igb_stats igb_gstrings_stats[] = { IGB_STAT("os2bmc_tx_by_host", stats.o2bspc), IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc), IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), + IGB_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), }; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index fefa46120cbc..06b81a609fa0 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -5388,6 +5388,8 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, adapter->ptp_tx_start = jiffies; if (adapter->hw.mac.type == e1000_82576) schedule_work(&adapter->ptp_tx_work); + } else { + adapter->tx_hwtstamp_skipped++; } } -- cgit v1.2.3 From e5f36ad14c93f2ca0b8b865f05cfa146c57c826d Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:29:03 -0700 Subject: igb: check for Tx timestamp timeouts during watchdog The igb driver has logic to handle only one Tx timestamp at a time, using a state bit lock to avoid multiple requests at once. It may be possible, if incredibly unlikely, that a Tx timestamp event is requested but never completes. Since we use an interrupt scheme to determine when the Tx timestamp occurred we would never clear the state bit in this case. Add an igb_ptp_tx_hang() function similar to the already existing igb_ptp_rx_hang() function. This function runs in the watchdog routine and makes sure we eventually recover from this case instead of permanently disabling Tx timestamps. Note: there is no currently known way to cause this without hacking the driver code to force it. Signed-off-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb.h | 1 + drivers/net/ethernet/intel/igb/igb_main.c | 1 + drivers/net/ethernet/intel/igb/igb_ptp.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index be35edcf6b08..ff4d9073781a 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -677,6 +677,7 @@ void igb_ptp_stop(struct igb_adapter *adapter); void igb_ptp_reset(struct igb_adapter *adapter); void igb_ptp_suspend(struct igb_adapter *adapter); void igb_ptp_rx_hang(struct igb_adapter *adapter); +void igb_ptp_tx_hang(struct igb_adapter *adapter); void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb); void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va, struct sk_buff *skb); diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 06b81a609fa0..0a333509d5d5 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -4722,6 +4722,7 @@ no_wait: igb_spoof_check(adapter); igb_ptp_rx_hang(adapter); + igb_ptp_tx_hang(adapter); /* Check LVMMC register on i350/i354 only */ if ((adapter->hw.mac.type == e1000_i350) || diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index ffd2c7c36d9c..841c2a083349 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -711,6 +711,35 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter) } } +/** + * igb_ptp_tx_hang - detect error case where Tx timestamp never finishes + * @adapter: private network adapter structure + */ +void igb_ptp_tx_hang(struct igb_adapter *adapter) +{ + bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + + IGB_PTP_TX_TIMEOUT); + + if (!adapter->ptp_tx_skb) + return; + + if (!test_bit(__IGB_PTP_TX_IN_PROGRESS, &adapter->state)) + return; + + /* If we haven't received a timestamp within the timeout, it is + * reasonable to assume that it will never occur, so we can unlock the + * timestamp bit when this occurs. + */ + if (timeout) { + cancel_work_sync(&adapter->ptp_tx_work); + dev_kfree_skb_any(adapter->ptp_tx_skb); + adapter->ptp_tx_skb = NULL; + clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); + adapter->tx_hwtstamp_timeouts++; + dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); + } +} + /** * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp * @adapter: Board private structure. -- cgit v1.2.3 From 81e3f64a9b2d837717a58606d9f22420a47fdf68 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Tue, 16 May 2017 15:55:16 -0700 Subject: igb: Remove useless argument Given that all callers of igb_update_stats() pass the same two arguments: (adapter, &adapter->stats64), the second argument can be removed. Signed-off-by: Benjamin Poirier Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb.h | 2 +- drivers/net/ethernet/intel/igb/igb_ethtool.c | 2 +- drivers/net/ethernet/intel/igb/igb_main.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index ff4d9073781a..06ffb2bc713e 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -667,7 +667,7 @@ void igb_setup_tctl(struct igb_adapter *); void igb_setup_rctl(struct igb_adapter *); netdev_tx_t igb_xmit_frame_ring(struct sk_buff *, struct igb_ring *); void igb_alloc_rx_buffers(struct igb_ring *, u16); -void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *); +void igb_update_stats(struct igb_adapter *); bool igb_has_link(struct igb_adapter *adapter); void igb_set_ethtool_ops(struct net_device *); void igb_power_up_link(struct igb_adapter *); diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 8730f7cbce68..d06a8db514d4 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2316,7 +2316,7 @@ static void igb_get_ethtool_stats(struct net_device *netdev, char *p; spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, net_stats); + igb_update_stats(adapter); for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { p = (char *)adapter + igb_gstrings_stats[i].stat_offset; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 0a333509d5d5..7e433344a13c 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1818,7 +1818,7 @@ void igb_down(struct igb_adapter *adapter) /* record the stats before reset*/ spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, &adapter->stats64); + igb_update_stats(adapter); spin_unlock(&adapter->stats64_lock); adapter->link_speed = 0; @@ -4686,7 +4686,7 @@ no_wait: } spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, &adapter->stats64); + igb_update_stats(adapter); spin_unlock(&adapter->stats64_lock); for (i = 0; i < adapter->num_tx_queues; i++) { @@ -5499,7 +5499,7 @@ static void igb_get_stats64(struct net_device *netdev, struct igb_adapter *adapter = netdev_priv(netdev); spin_lock(&adapter->stats64_lock); - igb_update_stats(adapter, &adapter->stats64); + igb_update_stats(adapter); memcpy(stats, &adapter->stats64, sizeof(*stats)); spin_unlock(&adapter->stats64_lock); } @@ -5548,9 +5548,9 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) * igb_update_stats - Update the board statistics counters * @adapter: board private structure **/ -void igb_update_stats(struct igb_adapter *adapter, - struct rtnl_link_stats64 *net_stats) +void igb_update_stats(struct igb_adapter *adapter) { + struct rtnl_link_stats64 *net_stats = &adapter->stats64; struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; u32 reg, mpc; -- cgit v1.2.3 From 24ad2a9209a0bf1ec37fac25a011c98551865abb Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Wed, 17 May 2017 16:24:13 -0400 Subject: e1000e: Don't return uninitialized stats Some statistics passed to ethtool are garbage because e1000e_get_stats64() doesn't write them, for example: tx_heartbeat_errors. This leaks kernel memory to userspace and confuses users. Do like ixgbe and use dev_get_stats() which first zeroes out rtnl_link_stats64. Fixes: 5944701df90d ("net: remove useless memset's in drivers get_stats64") Reported-by: Stefan Priebe Signed-off-by: Benjamin Poirier Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index c658f6ebf7cb..003cbd605799 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -2073,7 +2073,7 @@ static void e1000_get_ethtool_stats(struct net_device *netdev, pm_runtime_get_sync(netdev->dev.parent); - e1000e_get_stats64(netdev, &net_stats); + dev_get_stats(netdev, &net_stats); pm_runtime_put_sync(netdev->dev.parent); -- cgit v1.2.3 From fd8e597ba4afb769a8fb642555a6e0c5349a6ae8 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Fri, 19 May 2017 10:18:49 +0300 Subject: e1000e: use disable_hardirq() also for MSIX vectors in e1000_netpoll() Replace disable_irq() which waits for threaded irq handlers with disable_hardirq() which waits only for hardirq part. Fixes: 311191297125 ("e1000: use disable_hardirq() for e1000_netpoll()") Signed-off-by: Konstantin Khlebnikov Acked-by: Cong Wang Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index fc1d92ca3ea2..e1d46c11cb61 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6743,20 +6743,20 @@ static irqreturn_t e1000_intr_msix(int __always_unused irq, void *data) vector = 0; msix_irq = adapter->msix_entries[vector].vector; - disable_irq(msix_irq); - e1000_intr_msix_rx(msix_irq, netdev); + if (disable_hardirq(msix_irq)) + e1000_intr_msix_rx(msix_irq, netdev); enable_irq(msix_irq); vector++; msix_irq = adapter->msix_entries[vector].vector; - disable_irq(msix_irq); - e1000_intr_msix_tx(msix_irq, netdev); + if (disable_hardirq(msix_irq)) + e1000_intr_msix_tx(msix_irq, netdev); enable_irq(msix_irq); vector++; msix_irq = adapter->msix_entries[vector].vector; - disable_irq(msix_irq); - e1000_msix_other(msix_irq, netdev); + if (disable_hardirq(msix_irq)) + e1000_msix_other(msix_irq, netdev); enable_irq(msix_irq); } -- cgit v1.2.3 From 928a759593d21ec184536bde0b4816d21bcd5a86 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 6 Jun 2017 11:47:40 +0100 Subject: net/mlxfw: remove redundant goto on error check The check to see of err is set and the subsequent goto is extraneous as the next statement is where the goto is jumping to. Remove this redundant check and goto. Detected by CoverityScan, CID#1437734 ("Identical code for different branches") Signed-off-by: Colin Ian King Acked-by: Yotam Gigi Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c index 7e9589061d30..628150d28061 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c @@ -492,8 +492,6 @@ static int mlxfw_mfa2_file_cb_offset_xz(const struct mlxfw_mfa2_file *mfa2_file, dec_buf.out_pos = 0; dec_buf.out_size = size; err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished); - if (err) - goto out; out: xz_dec_end(xz_dec); return err; -- cgit v1.2.3 From be8408e1440cbc86683e4e1c65270ad517b4274a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 6 Jun 2017 14:12:04 +0200 Subject: mlxsw: pci: Fix size of trap_id field in CQE The "trap_id" is 9bits long. So far, this was not a problem since we used only traps with ids that fit into 8bits. But the ACL traps that are going to be introduced use the 9th bit. Fixes: eda6500a987a ("mlxsw: Add PCI bus implementation") Signed-off-by: Jiri Pirko Reviewed-by: Yotam Gigi Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci_hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index 0af3338bfcb4..a6441208e9d9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -155,7 +155,7 @@ MLXSW_ITEM32(pci, cqe, byte_count, 0x04, 0, 14); /* pci_cqe_trap_id * Trap ID that captured the packet. */ -MLXSW_ITEM32(pci, cqe, trap_id, 0x08, 0, 8); +MLXSW_ITEM32(pci, cqe, trap_id, 0x08, 0, 9); /* pci_cqe_crc * Length include CRC. Indicates the length field includes -- cgit v1.2.3 From 0db7b386f5e779085d5e20ad9d88b8a4b8767c02 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 6 Jun 2017 14:12:05 +0200 Subject: mlxsw: spectrum: Introduce ACL trap Introduce an ACL trap and put it into ip2me trap group. Signed-off-by: Jiri Pirko Reviewed-by: Yotam Gigi Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 +++- drivers/net/ethernet/mellanox/mlxsw/trap.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 84b6f36eb421..f60e2ba515d0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3261,7 +3261,9 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_NO_MARK(BGP_IPV4, TRAP_TO_CPU, BGP_IPV4, false), /* PKT Sample trap */ MLXSW_RXL(mlxsw_sp_rx_listener_sample_func, PKT_SAMPLE, MIRROR_TO_CPU, - false, SP_IP2ME, DISCARD) + false, SP_IP2ME, DISCARD), + /* ACL trap */ + MLXSW_SP_RXL_NO_MARK(ACL0, TRAP_TO_CPU, IP2ME, false), }; static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core) diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index e008fdbed20f..12b5ed58f3eb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -66,6 +66,7 @@ enum { MLXSW_TRAP_ID_RTR_INGRESS0 = 0x70, MLXSW_TRAP_ID_BGP_IPV4 = 0x88, MLXSW_TRAP_ID_HOST_MISS_IPV4 = 0x90, + MLXSW_TRAP_ID_ACL0 = 0x1C0, MLXSW_TRAP_ID_MAX = 0x1FF }; -- cgit v1.2.3 From df7eea963e4debe3b8286935c2fe9021c81ddbb6 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 6 Jun 2017 14:12:06 +0200 Subject: acl: Introduce ACL trap action Use trap/discard flex action to implement trap. Signed-off-by: Jiri Pirko Reviewed-by: Yotam Gigi Signed-off-by: David S. Miller --- .../mellanox/mlxsw/core_acl_flex_actions.c | 40 ++++++++++++++++++++-- .../mellanox/mlxsw/core_acl_flex_actions.h | 1 + drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 + drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 5 +++ 4 files changed, 45 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c index 46304ffb9449..5ae110172c22 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c @@ -40,6 +40,7 @@ #include #include "item.h" +#include "trap.h" #include "core_acl_flex_actions.h" enum mlxsw_afa_set_type { @@ -662,6 +663,16 @@ EXPORT_SYMBOL(mlxsw_afa_block_append_vlan_modify); #define MLXSW_AFA_TRAPDISC_CODE 0x03 #define MLXSW_AFA_TRAPDISC_SIZE 1 +enum mlxsw_afa_trapdisc_trap_action { + MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP = 0, + MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP = 2, +}; + +/* afa_trapdisc_trap_action + * Trap Action. + */ +MLXSW_ITEM32(afa, trapdisc, trap_action, 0x00, 24, 4); + enum mlxsw_afa_trapdisc_forward_action { MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD = 3, }; @@ -671,11 +682,20 @@ enum mlxsw_afa_trapdisc_forward_action { */ MLXSW_ITEM32(afa, trapdisc, forward_action, 0x00, 0, 4); +/* afa_trapdisc_trap_id + * Trap ID to configure. + */ +MLXSW_ITEM32(afa, trapdisc, trap_id, 0x04, 0, 9); + static inline void mlxsw_afa_trapdisc_pack(char *payload, - enum mlxsw_afa_trapdisc_forward_action forward_action) + enum mlxsw_afa_trapdisc_trap_action trap_action, + enum mlxsw_afa_trapdisc_forward_action forward_action, + u16 trap_id) { + mlxsw_afa_trapdisc_trap_action_set(payload, trap_action); mlxsw_afa_trapdisc_forward_action_set(payload, forward_action); + mlxsw_afa_trapdisc_trap_id_set(payload, trap_id); } int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block) @@ -686,11 +706,27 @@ int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block) if (!act) return -ENOBUFS; - mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD); + mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_NOP, + MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD, 0); return 0; } EXPORT_SYMBOL(mlxsw_afa_block_append_drop); +int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block) +{ + char *act = mlxsw_afa_block_append_action(block, + MLXSW_AFA_TRAPDISC_CODE, + MLXSW_AFA_TRAPDISC_SIZE); + + if (!act) + return -ENOBUFS; + mlxsw_afa_trapdisc_pack(act, MLXSW_AFA_TRAPDISC_TRAP_ACTION_TRAP, + MLXSW_AFA_TRAPDISC_FORWARD_ACTION_DISCARD, + MLXSW_TRAP_ID_ACL0); + return 0; +} +EXPORT_SYMBOL(mlxsw_afa_block_append_trap); + /* Forwarding Action * ----------------- * Forwarding Action can be used to implement Policy Based Switching (PBS) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h index bd8b91d02880..f99c341b2497 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h @@ -60,6 +60,7 @@ u32 mlxsw_afa_block_first_set_kvdl_index(struct mlxsw_afa_block *block); void mlxsw_afa_block_continue(struct mlxsw_afa_block *block); void mlxsw_afa_block_jump(struct mlxsw_afa_block *block, u16 group_id); int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block); +int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block); int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block, u8 local_port, bool in_port); int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 99760fd55ba1..4a7a39a9f1a1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -460,6 +460,7 @@ void mlxsw_sp_acl_rulei_act_continue(struct mlxsw_sp_acl_rule_info *rulei); void mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info *rulei, u16 group_id); int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei); +int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei); int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule_info *rulei, struct net_device *out_dev); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 1da889a044df..01a1501b56ca 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -347,6 +347,11 @@ int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei) return mlxsw_afa_block_append_drop(rulei->act_block); } +int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei) +{ + return mlxsw_afa_block_append_trap(rulei->act_block); +} + int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule_info *rulei, struct net_device *out_dev) -- cgit v1.2.3 From bd5ddba52dc0e2b37ce67e68ba1c419693009185 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 6 Jun 2017 14:12:07 +0200 Subject: spectrum_flower: Implement gact trap TC action offload Just use the previously prepared infrastructure and offload the gact trap action to ACL. Signed-off-by: Jiri Pirko Reviewed-by: Yotam Gigi Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 13af8e358847..21bb2bf62d3e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -67,6 +67,10 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, err = mlxsw_sp_acl_rulei_act_drop(rulei); if (err) return err; + } else if (is_tcf_gact_trap(a)) { + err = mlxsw_sp_acl_rulei_act_trap(rulei); + if (err) + return err; } else if (is_tcf_mirred_egress_redirect(a)) { int ifindex = tcf_mirred_ifindex(a); struct net_device *out_dev; -- cgit v1.2.3 From 4845b93ff2c9247f5fed88182ea71dba370e76bb Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:42 +0200 Subject: s390/qeth: remove support for IPA_IP_FRAGMENTATION This Assist was never actually implemented in any hardware, so just remove the leftovers. Signed-off-by: Julian Wiedmann Reviewed-by: Hans Wippel Reviewed-by: Thomas Richter Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 3 +-- drivers/s390/net/qeth_core_mpc.h | 2 +- drivers/s390/net/qeth_l3_main.c | 26 -------------------------- 3 files changed, 2 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index fc6d85f2b38d..dba7d00715e3 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4199,8 +4199,7 @@ int qeth_change_mtu(struct net_device *dev, int new_mtu) sprintf(dbf_text, "%8x", new_mtu); QETH_CARD_TEXT(card, 4, dbf_text); - if ((!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) && - (!qeth_mtu_is_valid(card, new_mtu))) + if (!qeth_mtu_is_valid(card, new_mtu)) return -EINVAL; dev->mtu = new_mtu; return 0; diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 4accb0a61ce0..45bbea2843bf 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -192,7 +192,7 @@ enum qeth_ipa_funcs { IPA_ARP_PROCESSING = 0x00000001L, IPA_INBOUND_CHECKSUM = 0x00000002L, IPA_OUTBOUND_CHECKSUM = 0x00000004L, - IPA_IP_FRAGMENTATION = 0x00000008L, + /* RESERVED = 0x00000008L,*/ IPA_FILTERING = 0x00000010L, IPA_IPV6 = 0x00000020L, IPA_MULTICASTING = 0x00000040L, diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d8df1e635163..ac8310fe2fb0 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -956,31 +956,6 @@ static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card) return rc; } -static int qeth_l3_start_ipa_ip_fragmentation(struct qeth_card *card) -{ - int rc; - - QETH_CARD_TEXT(card, 3, "ipaipfrg"); - - if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) { - dev_info(&card->gdev->dev, - "Hardware IP fragmentation not supported on %s\n", - QETH_CARD_IFNAME(card)); - return -EOPNOTSUPP; - } - - rc = qeth_send_simple_setassparms(card, IPA_IP_FRAGMENTATION, - IPA_CMD_ASS_START, 0); - if (rc) { - dev_warn(&card->gdev->dev, - "Starting IP fragmentation support for %s failed\n", - QETH_CARD_IFNAME(card)); - } else - dev_info(&card->gdev->dev, - "Hardware IP fragmentation enabled \n"); - return rc; -} - static int qeth_l3_start_ipa_source_mac(struct qeth_card *card) { int rc; @@ -1171,7 +1146,6 @@ static int qeth_l3_start_ipassists(struct qeth_card *card) if (qeth_set_access_ctrl_online(card, 0)) return -EIO; qeth_l3_start_ipa_arp_processing(card); /* go on*/ - qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ qeth_l3_start_ipa_source_mac(card); /* go on*/ qeth_l3_start_ipa_vlan(card); /* go on*/ qeth_l3_start_ipa_multicast(card); /* go on*/ -- cgit v1.2.3 From 94a9c981f7bdfdb6d092d1f92546bf61552c95d7 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:43 +0200 Subject: s390/qeth: remove skb_is_nonlinear() check on IQD qeth doesn't advertise NETIF_F_SG for L3 IQDs. So trust the stack to not hand us any nonlinear skbs, and remove an always-true condition. With the fact that data_offset < 0 is no longer possible on IQDs, apply a small cleanup to subsequent code. Signed-off-by: Julian Wiedmann Acked-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ac8310fe2fb0..56e813972d77 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2676,8 +2676,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, use_tso = skb_is_gso(skb) && (qeth_get_ip_protocol(skb) == IPPROTO_TCP) && (ipv == 4); - if ((card->info.type == QETH_CARD_TYPE_IQD) && - !skb_is_nonlinear(skb)) { + if (card->info.type == QETH_CARD_TYPE_IQD) { new_skb = skb; data_offset = ETH_HLEN; hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); @@ -2690,12 +2689,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, + VLAN_HLEN); if (!new_skb) goto tx_drop; - } - if (card->info.type == QETH_CARD_TYPE_IQD) { - if (data_offset < 0) - skb_pull(new_skb, ETH_HLEN); - } else { if (ipv == 4) { skb_pull(new_skb, ETH_HLEN); } -- cgit v1.2.3 From 23274596b565f8fba3d07e6cbed1de07947e365d Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:44 +0200 Subject: s390/qeth: query IPv6 IPA support on HiperSockets HiperSocket devices don't need the full IPv6 initialization, but we should still query the supported assists for logging purposes. Signed-off-by: Julian Wiedmann Acked-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 56e813972d77..fb4eee2a46ee 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1035,9 +1035,6 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) QETH_CARD_TEXT(card, 3, "softipv6"); - if (card->info.type == QETH_CARD_TYPE_IQD) - goto out; - rc = qeth_query_ipassists(card, QETH_PROT_IPV6); if (rc) { dev_err(&card->gdev->dev, @@ -1045,6 +1042,10 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) QETH_CARD_IFNAME(card)); return rc; } + + if (card->info.type == QETH_CARD_TYPE_IQD) + goto out; + rc = qeth_send_simple_setassparms(card, IPA_IPV6, IPA_CMD_ASS_START, 3); if (rc) { -- cgit v1.2.3 From 521c10ea2315366192a0641d5a063320685c0db1 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:45 +0200 Subject: s390/qeth: log bridgeport capabilities Bridgeport is a l2-specific feature, and we should write its capabilities to a debug entry. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l2_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index bd2df62a5cdf..70b633f951ea 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1017,6 +1017,13 @@ static int qeth_l2_start_ipassists(struct qeth_card *card) return 0; } +static void qeth_l2_trace_features(struct qeth_card *card) +{ + QETH_CARD_TEXT(card, 2, "l2featur"); + QETH_CARD_HEX(card, 2, &card->options.sbp.supported_funcs, + sizeof(card->options.sbp.supported_funcs)); +} + static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); @@ -1040,6 +1047,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_info(&card->gdev->dev, "The device represents a Bridge Capable Port\n"); qeth_trace_features(card); + qeth_l2_trace_features(card); if (!card->dev && qeth_l2_setup_netdev(card)) { rc = -ENODEV; -- cgit v1.2.3 From 84616e86f830490c4bbf93ddc1e374cd61865060 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:46 +0200 Subject: s390/qeth: add missing strings for IPA return codes commit 76b11f8e270f ("qeth: HiperSockets Network Traffic Analyzer") missed adding the human-readable translations when adding new RCs. Signed-off-by: Julian Wiedmann Acked-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_mpc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index beb4bdc26de5..ab9b1376467f 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c @@ -167,6 +167,8 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { {IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"}, {IPA_RC_UNKNOWN_ERROR, "IPA command failed - reason unknown"}, {IPA_RC_UNSUPPORTED_COMMAND, "Command not supported"}, + {IPA_RC_TRACE_ALREADY_ACTIVE, "trace already active"}, + {IPA_RC_INVALID_FORMAT, "invalid format or length"}, {IPA_RC_DUP_IPV6_REMOTE, "ipv6 address already registered remote"}, {IPA_RC_DUP_IPV6_HOME, "ipv6 address already registered"}, {IPA_RC_UNREGISTERED_ADDR, "Address not registered"}, -- cgit v1.2.3 From 664e42ac8b1bc39540ac9d657efa45c3e213e6c2 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:47 +0200 Subject: s390/qeth: consolidate pack buffer flushing qeth_switch_to_nonpacking_if_needed() contains an open-coded version of qeth_flush_buffers_on_no_pci(). Extract a single helper instead. Signed-off-by: Julian Wiedmann Acked-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 65 +++++++++++++++------------------------ 1 file changed, 25 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index dba7d00715e3..a159eb900d03 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3347,6 +3347,28 @@ static void qeth_handle_send_error(struct qeth_card *card, (u16)qdio_err, (u8)sbalf15); } +/** + * qeth_prep_flush_pack_buffer - Prepares flushing of a packing buffer. + * @queue: queue to check for packing buffer + * + * Returns number of buffers that were prepared for flush. + */ +static int qeth_prep_flush_pack_buffer(struct qeth_qdio_out_q *queue) +{ + struct qeth_qdio_out_buffer *buffer; + + buffer = queue->bufs[queue->next_buf_to_fill]; + if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) && + (buffer->next_element_to_fill > 0)) { + /* it's a packing buffer */ + atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); + queue->next_buf_to_fill = + (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; + return 1; + } + return 0; +} + /* * Switched to packing state if the number of used buffers on a queue * reaches a certain limit. @@ -3373,9 +3395,6 @@ static void qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue) */ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) { - struct qeth_qdio_out_buffer *buffer; - int flush_count = 0; - if (queue->do_pack) { if (atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) { @@ -3384,42 +3403,9 @@ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) if (queue->card->options.performance_stats) queue->card->perf_stats.sc_p_dp++; queue->do_pack = 0; - /* flush packing buffers */ - buffer = queue->bufs[queue->next_buf_to_fill]; - if ((atomic_read(&buffer->state) == - QETH_QDIO_BUF_EMPTY) && - (buffer->next_element_to_fill > 0)) { - atomic_set(&buffer->state, - QETH_QDIO_BUF_PRIMED); - flush_count++; - queue->next_buf_to_fill = - (queue->next_buf_to_fill + 1) % - QDIO_MAX_BUFFERS_PER_Q; - } + return qeth_prep_flush_pack_buffer(queue); } } - return flush_count; -} - - -/* - * Called to flush a packing buffer if no more pci flags are on the queue. - * Checks if there is a packing buffer and prepares it to be flushed. - * In that case returns 1, otherwise zero. - */ -static int qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue) -{ - struct qeth_qdio_out_buffer *buffer; - - buffer = queue->bufs[queue->next_buf_to_fill]; - if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) && - (buffer->next_element_to_fill > 0)) { - /* it's a packing buffer */ - atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); - queue->next_buf_to_fill = - (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; - return 1; - } return 0; } @@ -3532,8 +3518,7 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) flush_cnt += qeth_switch_to_nonpacking_if_needed(queue); if (!flush_cnt && !atomic_read(&queue->set_pci_flags_count)) - flush_cnt += - qeth_flush_buffers_on_no_pci(queue); + flush_cnt += qeth_prep_flush_pack_buffer(queue); if (queue->card->options.performance_stats && q_was_packing) queue->card->perf_stats.bufs_sent_pack += @@ -4127,7 +4112,7 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, * flag out on the queue */ if (!flush_count && !atomic_read(&queue->set_pci_flags_count)) - flush_count += qeth_flush_buffers_on_no_pci(queue); + flush_count += qeth_prep_flush_pack_buffer(queue); if (flush_count) qeth_flush_buffers(queue, start_index, flush_count); } -- cgit v1.2.3 From cf536ffea99472e043929749508d6656163138a1 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:48 +0200 Subject: s390/qeth: silence qeth_fix_features() Noting the lack of TSO support on every feature change is just silly, in particular since the requested features might not even affect NETIF_F_TSO. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index a159eb900d03..3cc802cff9d1 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -6390,11 +6390,8 @@ netdev_features_t qeth_fix_features(struct net_device *dev, features &= ~NETIF_F_IP_CSUM; if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) features &= ~NETIF_F_RXCSUM; - if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) { + if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) features &= ~NETIF_F_TSO; - dev_info(&card->gdev->dev, "Outbound TSO not supported on %s\n", - QETH_CARD_IFNAME(card)); - } /* if the card isn't up, remove features that require hw changes */ if (card->state == CARD_STATE_DOWN || card->state == CARD_STATE_RECOVER) -- cgit v1.2.3 From 79a04e40f7f0e968b485a0d0cb12dcffc7f509c6 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Tue, 6 Jun 2017 14:33:49 +0200 Subject: s390/qeth: add support for early L3 device setup Similar to how qeth currently does early L2 setup of OSM and OSN devices, add support for early setup of L3-only devices. This adds a qeth_l3_devtype that contains all core and l3-specific sysfs attributes, so that they can be created in one go while probing. This just adds the infrastructure, exploitation of the support happens in a subsequent patch. Signed-off-by: Ursula Braun Reviewed-by: Julian Wiedmann Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3.h | 1 + drivers/s390/net/qeth_l3_main.c | 18 +++++++++++++----- drivers/s390/net/qeth_l3_sys.c | 11 +++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 26f79533e62e..9b5e439f18cf 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -65,6 +65,7 @@ struct qeth_ipato_entry { int mask_bits; }; +extern const struct attribute_group *qeth_l3_attr_groups[]; void qeth_l3_ipaddr_to_string(enum qeth_prot_versions, const __u8 *, char *); int qeth_l3_string_to_ipaddr(const char *, enum qeth_prot_versions, __u8 *); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index fb4eee2a46ee..37b594231b76 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3005,14 +3005,21 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) return register_netdev(card->dev); } +static const struct device_type qeth_l3_devtype = { + .name = "qeth_layer3", + .groups = qeth_l3_attr_groups, +}; + static int qeth_l3_probe_device(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); int rc; - rc = qeth_l3_create_device_attributes(&gdev->dev); - if (rc) - return rc; + if (gdev->dev.type == &qeth_generic_devtype) { + rc = qeth_l3_create_device_attributes(&gdev->dev); + if (rc) + return rc; + } hash_init(card->ip_htable); hash_init(card->ip_mc_htable); card->options.layer2 = 0; @@ -3024,7 +3031,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) { struct qeth_card *card = dev_get_drvdata(&cgdev->dev); - qeth_l3_remove_device_attributes(&cgdev->dev); + if (cgdev->dev.type == &qeth_generic_devtype) + qeth_l3_remove_device_attributes(&cgdev->dev); qeth_set_allowed_threads(card, 0, 1); wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); @@ -3280,7 +3288,7 @@ static int qeth_l3_control_event(struct qeth_card *card, } struct qeth_discipline qeth_l3_discipline = { - .devtype = &qeth_generic_devtype, + .devtype = &qeth_l3_devtype, .start_poll = qeth_qdio_start_poll, .input_handler = (qdio_handler_t *) qeth_qdio_input_handler, .output_handler = (qdio_handler_t *) qeth_qdio_output_handler, diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index ff29a4b416b4..f2f94f59e0fa 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -1049,3 +1049,14 @@ void qeth_l3_remove_device_attributes(struct device *dev) sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group); } + +const struct attribute_group *qeth_l3_attr_groups[] = { + &qeth_device_attr_group, + &qeth_device_blkt_group, + /* l3 specific, see l3_{create,remove}_device_attributes(): */ + &qeth_l3_device_attr_group, + &qeth_device_ipato_group, + &qeth_device_vipa_group, + &qeth_device_rxip_group, +NULL, +}; -- cgit v1.2.3 From c70eb09dc210b8d6fdd4a93d5bc25d85133fb9d2 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 6 Jun 2017 14:33:50 +0200 Subject: s390/qeth: do early device setup for z/VM IQD NICs qeth currently supports early setup for OSM and OSN devices. This patch adds early setup support for z/VM HiperSockets, since they can only be coupled to L3 networks. Based on an initial version by Dmitriy Lakhvich. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 2 ++ drivers/s390/net/qeth_core_main.c | 44 ++++++++++++++++++++++++++++++--------- drivers/s390/net/qeth_core_sys.c | 2 +- 3 files changed, 37 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 30bc6105aac3..0efc54a4d82f 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -659,6 +659,7 @@ struct qeth_card_info { int max_mtu; int broadcast_capable; int unique_id; + bool layer_enforced; struct qeth_card_blkt blkt; enum qeth_ipa_promisc_modes promisc_mode; __u32 diagass_support; @@ -696,6 +697,7 @@ struct qeth_osn_info { }; enum qeth_discipline_id { + QETH_DISCIPLINE_UNDETERMINED = -1, QETH_DISCIPLINE_LAYER3 = 0, QETH_DISCIPLINE_LAYER2 = 1, }; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3cc802cff9d1..1fb92e870040 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1723,6 +1723,25 @@ static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd) (prcd[0x11] == _ascebc['M'])); } +/* Determine whether the device requires a specific layer discipline */ +static enum qeth_discipline_id qeth_enforce_discipline(struct qeth_card *card) +{ + if (card->info.type == QETH_CARD_TYPE_OSM || + card->info.type == QETH_CARD_TYPE_OSN) { + QETH_DBF_TEXT(SETUP, 3, "force l2"); + return QETH_DISCIPLINE_LAYER2; + } + + /* virtual HiperSocket is L3 only: */ + if (card->info.guestlan && card->info.type == QETH_CARD_TYPE_IQD) { + QETH_DBF_TEXT(SETUP, 3, "force l3"); + return QETH_DISCIPLINE_LAYER3; + } + + QETH_DBF_TEXT(SETUP, 3, "force no"); + return QETH_DISCIPLINE_UNDETERMINED; +} + static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd) { QETH_DBF_TEXT(SETUP, 2, "cfgblkt"); @@ -5485,6 +5504,7 @@ int qeth_core_load_discipline(struct qeth_card *card, enum qeth_discipline_id discipline) { int rc = 0; + mutex_lock(&qeth_mod_mutex); switch (discipline) { case QETH_DISCIPLINE_LAYER3: @@ -5495,7 +5515,10 @@ int qeth_core_load_discipline(struct qeth_card *card, card->discipline = try_then_request_module( symbol_get(qeth_l2_discipline), "qeth_l2"); break; + default: + break; } + if (!card->discipline) { dev_err(&card->gdev->dev, "There is no kernel module to " "support discipline %d\n", discipline); @@ -5598,6 +5621,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) struct qeth_card *card; struct device *dev; int rc; + enum qeth_discipline_id enforced_disc; unsigned long flags; char dbf_name[DBF_NAME_LEN]; @@ -5645,10 +5669,15 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) goto err_card; } - switch (card->info.type) { - case QETH_CARD_TYPE_OSN: - case QETH_CARD_TYPE_OSM: - rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2); + qeth_determine_capabilities(card); + enforced_disc = qeth_enforce_discipline(card); + switch (enforced_disc) { + case QETH_DISCIPLINE_UNDETERMINED: + gdev->dev.type = &qeth_generic_devtype; + break; + default: + card->info.layer_enforced = true; + rc = qeth_core_load_discipline(card, enforced_disc); if (rc) goto err_card; @@ -5659,16 +5688,11 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) if (rc) goto err_disc; break; - default: - gdev->dev.type = &qeth_generic_devtype; - break; } write_lock_irqsave(&qeth_core_card_list.rwlock, flags); list_add_tail(&card->list, &qeth_core_card_list.list); write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); - - qeth_determine_capabilities(card); return 0; err_disc: @@ -5705,7 +5729,7 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); int rc = 0; - int def_discipline; + enum qeth_discipline_id def_discipline; if (!card->discipline) { if (card->info.type == QETH_CARD_TYPE_IQD) diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index db6a285d41e0..6d255c22656d 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -413,7 +413,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, if (card->options.layer2 == newdis) goto out; - if (card->info.type == QETH_CARD_TYPE_OSM) { + if (card->info.layer_enforced) { /* fixed layer, can't switch */ rc = -EOPNOTSUPP; goto out; -- cgit v1.2.3 From f8fe99754673719ab791713a676bf27dae616fbc Mon Sep 17 00:00:00 2001 From: "yuval.shaia@oracle.com" Date: Mon, 5 Jun 2017 10:18:40 +0300 Subject: net: phy: Delete unused function phy_ethtool_gset It's unused, so remove it. Signed-off-by: Yuval Shaia Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 82ab8fb82587..40f4c6a2ef6c 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -484,30 +484,6 @@ int phy_ethtool_ksettings_set(struct phy_device *phydev, } EXPORT_SYMBOL(phy_ethtool_ksettings_set); -int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) -{ - cmd->supported = phydev->supported; - - cmd->advertising = phydev->advertising; - cmd->lp_advertising = phydev->lp_advertising; - - ethtool_cmd_speed_set(cmd, phydev->speed); - cmd->duplex = phydev->duplex; - if (phydev->interface == PHY_INTERFACE_MODE_MOCA) - cmd->port = PORT_BNC; - else - cmd->port = PORT_MII; - cmd->phy_address = phydev->mdio.addr; - cmd->transceiver = phy_is_internal(phydev) ? - XCVR_INTERNAL : XCVR_EXTERNAL; - cmd->autoneg = phydev->autoneg; - cmd->eth_tp_mdix_ctrl = phydev->mdix_ctrl; - cmd->eth_tp_mdix = phydev->mdix; - - return 0; -} -EXPORT_SYMBOL(phy_ethtool_gset); - int phy_ethtool_ksettings_get(struct phy_device *phydev, struct ethtool_link_ksettings *cmd) { -- cgit v1.2.3 From 4f5a98410d29bf87f587b19f5ae4e244b1ed4e18 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 5 Jun 2017 05:22:50 -0700 Subject: ppp: mppe: Use vsnprintf extension %phN Using this extension reduces the object size. $ size drivers/net/ppp/ppp_mppe.o* text data bss dec hex filename 5683 216 8 5907 1713 drivers/net/ppp/ppp_mppe.o.new 5808 216 8 6032 1790 drivers/net/ppp/ppp_mppe.o.old Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ppp/ppp_mppe.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c index f60f7660b451..6c7fd98cb00a 100644 --- a/drivers/net/ppp/ppp_mppe.c +++ b/drivers/net/ppp/ppp_mppe.c @@ -298,21 +298,14 @@ mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug, mppe_rekey(state, 1); if (debug) { - int i; - char mkey[sizeof(state->master_key) * 2 + 1]; - char skey[sizeof(state->session_key) * 2 + 1]; - printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n", debugstr, unit, (state->keylen == 16) ? 128 : 40, (state->stateful) ? "stateful" : "stateless"); - - for (i = 0; i < sizeof(state->master_key); i++) - sprintf(mkey + i * 2, "%02x", state->master_key[i]); - for (i = 0; i < sizeof(state->session_key); i++) - sprintf(skey + i * 2, "%02x", state->session_key[i]); printk(KERN_DEBUG - "%s[%d]: keys: master: %s initial session: %s\n", - debugstr, unit, mkey, skey); + "%s[%d]: keys: master: %*phN initial session: %*phN\n", + debugstr, unit, + (int)sizeof(state->master_key), state->master_key, + (int)sizeof(state->session_key), state->session_key); } /* -- cgit v1.2.3 From 8ea4fae926afd81f4d7fd43444562afc8629f77c Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Mon, 5 Jun 2017 18:34:20 +0530 Subject: cxgb4: implement ndo_set_vf_rate() Implement ndo_set_vf_rate() for mgmt interface to support rate-limiting of VF traffic using 'ip' command. Based on the original work of Kumar Sanghvi Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 106 ++++++++++++++++++++++++ 2 files changed, 107 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 1cf3e2f89fc1..b7a92ebab3cf 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -777,6 +777,7 @@ struct uld_msix_info { struct vf_info { unsigned char vf_mac_addr[ETH_ALEN]; + unsigned int tx_rate; bool pf_set_mac; }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 8c69046be025..64af40662b3e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2563,6 +2563,8 @@ static int cxgb_get_vf_config(struct net_device *dev, if (vf >= adap->num_vfs) return -EINVAL; ivi->vf = vf; + ivi->max_tx_rate = adap->vfinfo[vf].tx_rate; + ivi->min_tx_rate = 0; ether_addr_copy(ivi->mac, adap->vfinfo[vf].vf_mac_addr); return 0; } @@ -2579,6 +2581,109 @@ static int cxgb_get_phys_port_id(struct net_device *dev, return 0; } +static int cxgb_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate, + int max_tx_rate) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct fw_port_cmd port_cmd, port_rpl; + u32 link_status, speed = 0; + u32 fw_pfvf, fw_class; + int class_id = vf; + int link_ok, ret; + u16 pktsize; + + if (vf >= adap->num_vfs) + return -EINVAL; + + if (min_tx_rate) { + dev_err(adap->pdev_dev, + "Min tx rate (%d) (> 0) for VF %d is Invalid.\n", + min_tx_rate, vf); + return -EINVAL; + } + /* Retrieve link details for VF port */ + memset(&port_cmd, 0, sizeof(port_cmd)); + port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_READ_F | + FW_PORT_CMD_PORTID_V(pi->port_id)); + port_cmd.action_to_len16 = + cpu_to_be32(FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) | + FW_LEN16(port_cmd)); + ret = t4_wr_mbox(adap, adap->mbox, &port_cmd, sizeof(port_cmd), + &port_rpl); + if (ret != FW_SUCCESS) { + dev_err(adap->pdev_dev, + "Failed to get link status for VF %d\n", vf); + return -EINVAL; + } + link_status = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype); + link_ok = (link_status & FW_PORT_CMD_LSTATUS_F) != 0; + if (!link_ok) { + dev_err(adap->pdev_dev, "Link down for VF %d\n", vf); + return -EINVAL; + } + /* Determine link speed */ + if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) + speed = 100; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) + speed = 1000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) + speed = 10000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G)) + speed = 25000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) + speed = 40000; + else if (link_status & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G)) + speed = 100000; + + if (max_tx_rate > speed) { + dev_err(adap->pdev_dev, + "Max tx rate %d for VF %d can't be > link-speed %u", + max_tx_rate, vf, speed); + return -EINVAL; + } + pktsize = be16_to_cpu(port_rpl.u.info.mtu); + /* subtract ethhdr size and 4 bytes crc since, f/w appends it */ + pktsize = pktsize - sizeof(struct ethhdr) - 4; + /* subtract ipv4 hdr size, tcp hdr size to get typical IPv4 MSS size */ + pktsize = pktsize - sizeof(struct iphdr) - sizeof(struct tcphdr); + /* configure Traffic Class for rate-limiting */ + ret = t4_sched_params(adap, SCHED_CLASS_TYPE_PACKET, + SCHED_CLASS_LEVEL_CL_RL, + SCHED_CLASS_MODE_CLASS, + SCHED_CLASS_RATEUNIT_BITS, + SCHED_CLASS_RATEMODE_ABS, + pi->port_id, class_id, 0, + max_tx_rate * 1000, 0, pktsize); + if (ret) { + dev_err(adap->pdev_dev, "Err %d for Traffic Class config\n", + ret); + return -EINVAL; + } + dev_info(adap->pdev_dev, + "Class %d with MSS %u configured with rate %u\n", + class_id, pktsize, max_tx_rate); + + /* bind VF to configured Traffic Class */ + fw_pfvf = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH)); + fw_class = class_id; + ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, &fw_pfvf, + &fw_class); + if (ret) { + dev_err(adap->pdev_dev, + "Err %d in binding VF %d to Traffic Class %d\n", + ret, vf, class_id); + return -EINVAL; + } + dev_info(adap->pdev_dev, "PF %d VF %d is bound to Class %d\n", + adap->pf, vf, class_id); + adap->vfinfo[vf].tx_rate = max_tx_rate; + return 0; +} + #endif static int cxgb_set_mac_addr(struct net_device *dev, void *p) @@ -2766,6 +2871,7 @@ static const struct net_device_ops cxgb4_mgmt_netdev_ops = { .ndo_open = dummy_open, .ndo_set_vf_mac = cxgb_set_vf_mac, .ndo_get_vf_config = cxgb_get_vf_config, + .ndo_set_vf_rate = cxgb_set_vf_rate, .ndo_get_phys_port_id = cxgb_get_phys_port_id, }; #endif -- cgit v1.2.3 From 5461bd41fd93829fdd726c01f43799c743aba9a0 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 5 Jun 2017 18:17:16 -0400 Subject: net: dsa: mv88e6xxx: fix 6085 frame mode masking The register bits used for the frame mode were masked with DSA (0x1) instead of the mask value (0x3) in the 6085 implementation of port_set_frame_mode. Fix this. Fixes: 56995cbc3540 ("net: dsa: mv88e6xxx: Refactor CPU and DSA port setup") Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 360c77854f2a..3719ece60c61 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -451,7 +451,7 @@ int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, if (err) return err; - reg &= ~PORT_CONTROL_FRAME_MODE_DSA; + reg &= ~PORT_CONTROL_FRAME_MASK; switch (mode) { case MV88E6XXX_FRAME_MODE_NORMAL: -- cgit v1.2.3 From feec084a7cf49adb4a87bea9867fb2ba99821f48 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 6 Jun 2017 14:09:49 +0800 Subject: tun: use symmetric hash Tun actually expects a symmetric hash for queue selecting to work correctly, otherwise packets belongs to a single flow may be redirected to the wrong queue. So this patch switch to use __skb_get_hash_symmetric(). Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index f8041f9c7e65..fe660e524af9 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -465,7 +465,7 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); numqueues = ACCESS_ONCE(tun->numqueues); - txq = skb_get_hash(skb); + txq = __skb_get_hash_symmetric(skb); if (txq) { e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq); if (e) { @@ -867,7 +867,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) */ __u32 rxhash; - rxhash = skb_get_hash(skb); + rxhash = __skb_get_hash_symmetric(skb); if (rxhash) { struct tun_flow_entry *e; e = tun_flow_find(&tun->flows[tun_hashfn(rxhash)], @@ -1334,7 +1334,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, skb_reset_network_header(skb); skb_probe_transport_header(skb, 0); - rxhash = skb_get_hash(skb); + rxhash = __skb_get_hash_symmetric(skb); #ifndef CONFIG_4KSTACKS tun_rx_batched(tun, tfile, skb, more); #else -- cgit v1.2.3 From 5acde34a5a420ffe7441bb7d3909dc2618025c3c Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 5 Jun 2017 12:22:50 +0100 Subject: net: phy: add 802.3 clause 45 support to phylib Add generic helpers for 802.3 clause 45 PHYs for >= 10Gbps support. Reviewed-by: Andrew Lunn Signed-off-by: Russell King Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/Makefile | 2 +- drivers/net/phy/phy-c45.c | 234 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy_device.c | 20 ++-- 3 files changed, 241 insertions(+), 15 deletions(-) create mode 100644 drivers/net/phy/phy-c45.c (limited to 'drivers') diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index e2fde094f63d..ae58f507aba9 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -1,6 +1,6 @@ # Makefile for Linux PHY drivers and MDIO bus drivers -libphy-y := phy.o phy-core.o phy_device.o +libphy-y := phy.o phy-c45.o phy-core.o phy_device.o mdio-bus-y += mdio_bus.o mdio_device.o ifdef CONFIG_MDIO_DEVICE diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c new file mode 100644 index 000000000000..d311d6e6141c --- /dev/null +++ b/drivers/net/phy/phy-c45.c @@ -0,0 +1,234 @@ +/* + * Clause 45 PHY support + */ +#include +#include +#include +#include +#include + +/** + * genphy_c45_setup_forced - configures a forced speed + * @phydev: target phy_device struct + */ +int genphy_c45_pma_setup_forced(struct phy_device *phydev) +{ + int ctrl1, ctrl2, ret; + + /* Half duplex is not supported */ + if (phydev->duplex != DUPLEX_FULL) + return -EINVAL; + + ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1); + if (ctrl1 < 0) + return ctrl1; + + ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2); + if (ctrl2 < 0) + return ctrl2; + + ctrl1 &= ~MDIO_CTRL1_SPEEDSEL; + /* + * PMA/PMD type selection is 1.7.5:0 not 1.7.3:0. See 45.2.1.6.1 + * in 802.3-2012 and 802.3-2015. + */ + ctrl2 &= ~(MDIO_PMA_CTRL2_TYPE | 0x30); + + switch (phydev->speed) { + case SPEED_10: + ctrl2 |= MDIO_PMA_CTRL2_10BT; + break; + case SPEED_100: + ctrl1 |= MDIO_PMA_CTRL1_SPEED100; + ctrl2 |= MDIO_PMA_CTRL2_100BTX; + break; + case SPEED_1000: + ctrl1 |= MDIO_PMA_CTRL1_SPEED1000; + /* Assume 1000base-T */ + ctrl2 |= MDIO_PMA_CTRL2_1000BT; + break; + case SPEED_10000: + ctrl1 |= MDIO_CTRL1_SPEED10G; + /* Assume 10Gbase-T */ + ctrl2 |= MDIO_PMA_CTRL2_10GBT; + break; + default: + return -EINVAL; + } + + ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, ctrl1); + if (ret < 0) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2, ctrl2); +} +EXPORT_SYMBOL_GPL(genphy_c45_pma_setup_forced); + +/** + * genphy_c45_an_disable_aneg - disable auto-negotiation + * @phydev: target phy_device struct + * + * Disable auto-negotiation in the Clause 45 PHY. The link parameters + * parameters are controlled through the PMA/PMD MMD registers. + * + * Returns zero on success, negative errno code on failure. + */ +int genphy_c45_an_disable_aneg(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); + if (val < 0) + return val; + + val &= ~(MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART); + + return phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, val); +} +EXPORT_SYMBOL_GPL(genphy_c45_an_disable_aneg); + +/** + * genphy_c45_restart_aneg - Enable and restart auto-negotiation + * @phydev: target phy_device struct + * + * This assumes that the auto-negotiation MMD is present. + * + * Enable and restart auto-negotiation. + */ +int genphy_c45_restart_aneg(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); + if (val < 0) + return val; + + val |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART; + + return phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, val); +} +EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg); + +/** + * genphy_c45_aneg_done - return auto-negotiation complete status + * @phydev: target phy_device struct + * + * This assumes that the auto-negotiation MMD is present. + * + * Reads the status register from the auto-negotiation MMD, returning: + * - positive if auto-negotiation is complete + * - negative errno code on error + * - zero otherwise + */ +int genphy_c45_aneg_done(struct phy_device *phydev) +{ + int val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + + return val < 0 ? val : val & MDIO_AN_STAT1_COMPLETE ? 1 : 0; +} +EXPORT_SYMBOL_GPL(genphy_c45_aneg_done); + +/** + * genphy_c45_read_link - read the overall link status from the MMDs + * @phydev: target phy_device struct + * @mmd_mask: MMDs to read status from + * + * Read the link status from the specified MMDs, and if they all indicate + * that the link is up, return positive. If an error is encountered, + * a negative errno will be returned, otherwise zero. + */ +int genphy_c45_read_link(struct phy_device *phydev, u32 mmd_mask) +{ + int val, devad; + bool link = true; + + while (mmd_mask) { + devad = __ffs(mmd_mask); + mmd_mask &= ~BIT(devad); + + /* The link state is latched low so that momentary link + * drops can be detected. Do not double-read the status + * register if the link is down. + */ + val = phy_read_mmd(phydev, devad, MDIO_STAT1); + if (val < 0) + return val; + + if (!(val & MDIO_STAT1_LSTATUS)) + link = false; + } + + return link; +} +EXPORT_SYMBOL_GPL(genphy_c45_read_link); + +/** + * genphy_c45_read_lpa - read the link partner advertisment and pause + * @phydev: target phy_device struct + * + * Read the Clause 45 defined base (7.19) and 10G (7.33) status registers, + * filling in the link partner advertisment, pause and asym_pause members + * in @phydev. This assumes that the auto-negotiation MMD is present, and + * the backplane bit (7.48.0) is clear. Clause 45 PHY drivers are expected + * to fill in the remainder of the link partner advert from vendor registers. + */ +int genphy_c45_read_lpa(struct phy_device *phydev) +{ + int val; + + /* Read the link partner's base page advertisment */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA); + if (val < 0) + return val; + + phydev->lp_advertising = mii_lpa_to_ethtool_lpa_t(val); + phydev->pause = val & LPA_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = val & LPA_PAUSE_ASYM ? 1 : 0; + + /* Read the link partner's 10G advertisment */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); + if (val < 0) + return val; + + if (val & MDIO_AN_10GBT_STAT_LP10G) + phydev->lp_advertising |= ADVERTISED_10000baseT_Full; + + return 0; +} +EXPORT_SYMBOL_GPL(genphy_c45_read_lpa); + +/** + * genphy_c45_read_pma - read link speed etc from PMA + * @phydev: target phy_device struct + */ +int genphy_c45_read_pma(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1); + if (val < 0) + return val; + + switch (val & MDIO_CTRL1_SPEEDSEL) { + case 0: + phydev->speed = SPEED_10; + break; + case MDIO_PMA_CTRL1_SPEED100: + phydev->speed = SPEED_100; + break; + case MDIO_PMA_CTRL1_SPEED1000: + phydev->speed = SPEED_1000; + break; + case MDIO_CTRL1_SPEED10G: + phydev->speed = SPEED_10000; + break; + default: + phydev->speed = SPEED_UNKNOWN; + break; + } + + phydev->duplex = DUPLEX_FULL; + + return 0; +} +EXPORT_SYMBOL_GPL(genphy_c45_read_pma); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 37a1e98908e3..6a79e24fa312 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1508,27 +1508,19 @@ EXPORT_SYMBOL(genphy_read_status); static int gen10g_read_status(struct phy_device *phydev) { - int devad, reg; u32 mmd_mask = phydev->c45_ids.devices_in_package; - - phydev->link = 1; + int ret; /* For now just lie and say it's 10G all the time */ phydev->speed = SPEED_10000; phydev->duplex = DUPLEX_FULL; - for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) { - if (!(mmd_mask & 1)) - continue; + /* Avoid reading the vendor MMDs */ + mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2)); - /* Read twice because link state is latched and a - * read moves the current state into the register - */ - phy_read_mmd(phydev, devad, MDIO_STAT1); - reg = phy_read_mmd(phydev, devad, MDIO_STAT1); - if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) - phydev->link = 0; - } + ret = genphy_c45_read_link(phydev, mmd_mask); + + phydev->link = ret > 0 ? 1 : 0; return 0; } -- cgit v1.2.3 From 41408ad519f7a2a1c5229e61f2a97f4df1b61adc Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 5 Jun 2017 12:22:55 +0100 Subject: net: phy: avoid genphy_aneg_done() for PHYs without clause 22 support Avoid calling genphy_aneg_done() for PHYs that do not implement the Clause 22 register set. Clause 45 PHYs may implement the Clause 22 register set along with the Clause 22 extension MMD. Hence, we can't simply block access to the Clause 22 functions based on the PHY being a Clause 45 PHY. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 40f4c6a2ef6c..c232ee04754b 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -163,6 +163,12 @@ int phy_aneg_done(struct phy_device *phydev) if (phydev->drv && phydev->drv->aneg_done) return phydev->drv->aneg_done(phydev); + /* Avoid genphy_aneg_done() if the Clause 45 PHY does not + * implement Clause 22 registers + */ + if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) + return -EINVAL; + return genphy_aneg_done(phydev); } EXPORT_SYMBOL(phy_aneg_done); -- cgit v1.2.3 From 002ba7058a7f141cf22d37967a4ef78239c50e9e Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 5 Jun 2017 12:23:00 +0100 Subject: net: phy: hook up clause 45 autonegotiation restart genphy_restart_aneg() can only restart autonegotiation on clause 22 PHYs. Add a phy_restart_aneg() function which selects between the clause 22 and clause 45 restart functionality depending on the PHY type and whether the Clause 45 PHY supports the Clause 22 register set. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index c232ee04754b..12548e5b6037 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -149,6 +149,25 @@ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) return 0; } +/** + * phy_restart_aneg - restart auto-negotiation + * @phydev: target phy_device struct + * + * Restart the autonegotiation on @phydev. Returns >= 0 on success or + * negative errno on error. + */ +int phy_restart_aneg(struct phy_device *phydev) +{ + int ret; + + if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) + ret = genphy_c45_restart_aneg(phydev); + else + ret = genphy_restart_aneg(phydev); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_restart_aneg); /** * phy_aneg_done - return auto-negotiation status @@ -1397,7 +1416,7 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) /* Restart autonegotiation so the new modes get sent to the * link partner. */ - ret = genphy_restart_aneg(phydev); + ret = phy_restart_aneg(phydev); if (ret < 0) return ret; } @@ -1456,6 +1475,6 @@ int phy_ethtool_nway_reset(struct net_device *ndev) if (!phydev->drv) return -EIO; - return genphy_restart_aneg(phydev); + return phy_restart_aneg(phydev); } EXPORT_SYMBOL(phy_ethtool_nway_reset); -- cgit v1.2.3 From 921690f2aa8830c5e3923b944a1c72ab6b683afe Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 5 Jun 2017 12:23:05 +0100 Subject: net: phy: split out 10G genphy support Move the old 10G genphy support to sit beside the new clause 45 library functions, so all the 10G phy code is together. Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/phy-c45.c | 64 ++++++++++++++++++++++++++ drivers/net/phy/phy_device.c | 105 ++++++++----------------------------------- 2 files changed, 83 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index d311d6e6141c..dada819c6b78 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -232,3 +232,67 @@ int genphy_c45_read_pma(struct phy_device *phydev) return 0; } EXPORT_SYMBOL_GPL(genphy_c45_read_pma); + +/* The gen10g_* functions are the old Clause 45 stub */ + +static int gen10g_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int gen10g_read_status(struct phy_device *phydev) +{ + u32 mmd_mask = phydev->c45_ids.devices_in_package; + int ret; + + /* For now just lie and say it's 10G all the time */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + /* Avoid reading the vendor MMDs */ + mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2)); + + ret = genphy_c45_read_link(phydev, mmd_mask); + + phydev->link = ret > 0 ? 1 : 0; + + return 0; +} + +static int gen10g_soft_reset(struct phy_device *phydev) +{ + /* Do nothing for now */ + return 0; +} + +static int gen10g_config_init(struct phy_device *phydev) +{ + /* Temporarily just say we support everything */ + phydev->supported = SUPPORTED_10000baseT_Full; + phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + +static int gen10g_suspend(struct phy_device *phydev) +{ + return 0; +} + +static int gen10g_resume(struct phy_device *phydev) +{ + return 0; +} + +struct phy_driver genphy_10g_driver = { + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic 10G PHY", + .soft_reset = gen10g_soft_reset, + .config_init = gen10g_config_init, + .features = 0, + .config_aneg = gen10g_config_aneg, + .read_status = gen10g_read_status, + .suspend = gen10g_suspend, + .resume = gen10g_resume, +}; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 6a79e24fa312..acf00f071c9a 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -69,13 +69,8 @@ static void phy_mdio_device_remove(struct mdio_device *mdiodev) phy_device_remove(phydev); } -enum genphy_driver { - GENPHY_DRV_1G, - GENPHY_DRV_10G, - GENPHY_DRV_MAX -}; - -static struct phy_driver genphy_driver[GENPHY_DRV_MAX]; +static struct phy_driver genphy_driver; +extern struct phy_driver genphy_10g_driver; static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); @@ -928,11 +923,9 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, */ if (!d->driver) { if (phydev->is_c45) - d->driver = - &genphy_driver[GENPHY_DRV_10G].mdiodrv.driver; + d->driver = &genphy_10g_driver.mdiodrv.driver; else - d->driver = - &genphy_driver[GENPHY_DRV_1G].mdiodrv.driver; + d->driver = &genphy_driver.mdiodrv.driver; using_genphy = true; } @@ -1069,7 +1062,6 @@ void phy_detach(struct phy_device *phydev) struct net_device *dev = phydev->attached_dev; struct module *ndev_owner = dev->dev.parent->driver->owner; struct mii_bus *bus; - int i; if (phydev->sysfs_links) { sysfs_remove_link(&dev->dev.kobj, "phydev"); @@ -1088,13 +1080,9 @@ void phy_detach(struct phy_device *phydev) * from the generic driver so that there's a chance a * real driver could be loaded */ - for (i = 0; i < ARRAY_SIZE(genphy_driver); i++) { - if (phydev->mdio.dev.driver == - &genphy_driver[i].mdiodrv.driver) { - device_release_driver(&phydev->mdio.dev); - break; - } - } + if (phydev->mdio.dev.driver == &genphy_10g_driver.mdiodrv.driver || + phydev->mdio.dev.driver == &genphy_driver.mdiodrv.driver) + device_release_driver(&phydev->mdio.dev); /* * The phydev might go away on the put_device() below, so avoid @@ -1368,11 +1356,6 @@ int genphy_aneg_done(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_aneg_done); -static int gen10g_config_aneg(struct phy_device *phydev) -{ - return 0; -} - /** * genphy_update_link - update link status in @phydev * @phydev: target phy_device struct @@ -1506,25 +1489,6 @@ int genphy_read_status(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_read_status); -static int gen10g_read_status(struct phy_device *phydev) -{ - u32 mmd_mask = phydev->c45_ids.devices_in_package; - int ret; - - /* For now just lie and say it's 10G all the time */ - phydev->speed = SPEED_10000; - phydev->duplex = DUPLEX_FULL; - - /* Avoid reading the vendor MMDs */ - mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2)); - - ret = genphy_c45_read_link(phydev, mmd_mask); - - phydev->link = ret > 0 ? 1 : 0; - - return 0; -} - /** * genphy_soft_reset - software reset the PHY via BMCR_RESET bit * @phydev: target phy_device struct @@ -1590,21 +1554,6 @@ int genphy_config_init(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_config_init); -static int gen10g_soft_reset(struct phy_device *phydev) -{ - /* Do nothing for now */ - return 0; -} - -static int gen10g_config_init(struct phy_device *phydev) -{ - /* Temporarily just say we support everything */ - phydev->supported = SUPPORTED_10000baseT_Full; - phydev->advertising = SUPPORTED_10000baseT_Full; - - return 0; -} - int genphy_suspend(struct phy_device *phydev) { int value; @@ -1620,11 +1569,6 @@ int genphy_suspend(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_suspend); -static int gen10g_suspend(struct phy_device *phydev) -{ - return 0; -} - int genphy_resume(struct phy_device *phydev) { int value; @@ -1640,11 +1584,6 @@ int genphy_resume(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_resume); -static int gen10g_resume(struct phy_device *phydev) -{ - return 0; -} - static int __set_phy_supported(struct phy_device *phydev, u32 max_speed) { /* The default values for phydev->supported are provided by the PHY @@ -1876,8 +1815,7 @@ void phy_drivers_unregister(struct phy_driver *drv, int n) } EXPORT_SYMBOL(phy_drivers_unregister); -static struct phy_driver genphy_driver[] = { -{ +static struct phy_driver genphy_driver = { .phy_id = 0xffffffff, .phy_id_mask = 0xffffffff, .name = "Generic PHY", @@ -1891,18 +1829,7 @@ static struct phy_driver genphy_driver[] = { .read_status = genphy_read_status, .suspend = genphy_suspend, .resume = genphy_resume, -}, { - .phy_id = 0xffffffff, - .phy_id_mask = 0xffffffff, - .name = "Generic 10G PHY", - .soft_reset = gen10g_soft_reset, - .config_init = gen10g_config_init, - .features = 0, - .config_aneg = gen10g_config_aneg, - .read_status = gen10g_read_status, - .suspend = gen10g_suspend, - .resume = gen10g_resume, -} }; +}; static int __init phy_init(void) { @@ -1912,18 +1839,24 @@ static int __init phy_init(void) if (rc) return rc; - rc = phy_drivers_register(genphy_driver, - ARRAY_SIZE(genphy_driver), THIS_MODULE); + rc = phy_driver_register(&genphy_10g_driver, THIS_MODULE); if (rc) + goto err_10g; + + rc = phy_driver_register(&genphy_driver, THIS_MODULE); + if (rc) { + phy_driver_unregister(&genphy_10g_driver); +err_10g: mdio_bus_exit(); + } return rc; } static void __exit phy_exit(void) { - phy_drivers_unregister(genphy_driver, - ARRAY_SIZE(genphy_driver)); + phy_driver_unregister(&genphy_10g_driver); + phy_driver_unregister(&genphy_driver); mdio_bus_exit(); } -- cgit v1.2.3 From 20b2af32ff3f0ac74f2bfd0bc2c175b56002d1f1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 5 Jun 2017 12:23:16 +0100 Subject: net: phy: add Marvell Alaska X 88X3310 10Gigabit PHY support Add phylib support for the Marvell Alaska X 10 Gigabit PHY (MV88X3310). This phy is able to operate at 10G, 1G, 100M and 10M speeds, and only supports Clause 45 accesses. The PHY appears (based on the vendor IDs) to be two different vendors IP, with each devad containing several instances. This PHY driver has only been tested with the RJ45 copper port, fiber port and a Marvell Armada 8040-based ethernet interface. It should be noted that to use the full range of speeds, MAC drivers need to also reconfigure the link mode as per phydev->interface, since the PHY automatically changes its interface mode depending on the negotiated speed. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 5 + drivers/net/phy/Makefile | 1 + drivers/net/phy/marvell10g.c | 368 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+) create mode 100644 drivers/net/phy/marvell10g.c (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 0c516d3229d0..65af31f24f01 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -292,6 +292,11 @@ config MARVELL_PHY ---help--- Currently has a driver for the 88E1011S +config MARVELL_10G_PHY + tristate "Marvell Alaska 10Gbit PHYs" + ---help--- + Support for the Marvell Alaska MV88X3310 and compatible PHYs. + config MESON_GXL_PHY tristate "Amlogic Meson GXL Internal PHY" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index ae58f507aba9..8e9b9f349384 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_LXT_PHY) += lxt.o obj-$(CONFIG_MARVELL_PHY) += marvell.o +obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_MICREL_PHY) += micrel.o diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c new file mode 100644 index 000000000000..aebc08beceba --- /dev/null +++ b/drivers/net/phy/marvell10g.c @@ -0,0 +1,368 @@ +/* + * Marvell 10G 88x3310 PHY driver + * + * Based upon the ID registers, this PHY appears to be a mixture of IPs + * from two different companies. + * + * There appears to be several different data paths through the PHY which + * are automatically managed by the PHY. The following has been determined + * via observation and experimentation: + * + * SGMII PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for <= 1G) + * 10GBASE-KR PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for 10G) + * 10GBASE-KR PHYXS -- BASE-R PCS -- Fiber + * + * If both the fiber and copper ports are connected, the first to gain + * link takes priority and the other port is completely locked out. + */ +#include + +enum { + MV_PCS_BASE_T = 0x0000, + MV_PCS_BASE_R = 0x1000, + MV_PCS_1000BASEX = 0x2000, + + /* These registers appear at 0x800X and 0xa00X - the 0xa00X control + * registers appear to set themselves to the 0x800X when AN is + * restarted, but status registers appear readable from either. + */ + MV_AN_CTRL1000 = 0x8000, /* 1000base-T control register */ + MV_AN_STAT1000 = 0x8001, /* 1000base-T status register */ + + /* This register appears to reflect the copper status */ + MV_AN_RESULT = 0xa016, + MV_AN_RESULT_SPD_10 = BIT(12), + MV_AN_RESULT_SPD_100 = BIT(13), + MV_AN_RESULT_SPD_1000 = BIT(14), + MV_AN_RESULT_SPD_10000 = BIT(15), +}; + +static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg, + u16 mask, u16 bits) +{ + int old, val, ret; + + old = phy_read_mmd(phydev, devad, reg); + if (old < 0) + return old; + + val = (old & ~mask) | (bits & mask); + if (val == old) + return 0; + + ret = phy_write_mmd(phydev, devad, reg, val); + + return ret < 0 ? ret : 1; +} + +static int mv3310_probe(struct phy_device *phydev) +{ + u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; + + if (!phydev->is_c45 || + (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) + return -ENODEV; + + return 0; +} + +/* + * Resetting the MV88X3310 causes it to become non-responsive. Avoid + * setting the reset bit(s). + */ +static int mv3310_soft_reset(struct phy_device *phydev) +{ + return 0; +} + +static int mv3310_config_init(struct phy_device *phydev) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; + u32 mask; + int val; + + /* Check that the PHY interface type is compatible */ + if (phydev->interface != PHY_INTERFACE_MODE_SGMII && + phydev->interface != PHY_INTERFACE_MODE_XGMII && + phydev->interface != PHY_INTERFACE_MODE_XAUI && + phydev->interface != PHY_INTERFACE_MODE_RXAUI && + phydev->interface != PHY_INTERFACE_MODE_10GKR) + return -ENODEV; + + __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported); + __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported); + + if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) { + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + if (val < 0) + return val; + + if (val & MDIO_AN_STAT1_ABLE) + __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported); + } + + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2); + if (val < 0) + return val; + + /* Ethtool does not support the WAN mode bits */ + if (val & (MDIO_PMA_STAT2_10GBSR | MDIO_PMA_STAT2_10GBLR | + MDIO_PMA_STAT2_10GBER | MDIO_PMA_STAT2_10GBLX4 | + MDIO_PMA_STAT2_10GBSW | MDIO_PMA_STAT2_10GBLW | + MDIO_PMA_STAT2_10GBEW)) + __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported); + if (val & MDIO_PMA_STAT2_10GBSR) + __set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported); + if (val & MDIO_PMA_STAT2_10GBLR) + __set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported); + if (val & MDIO_PMA_STAT2_10GBER) + __set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported); + + if (val & MDIO_PMA_STAT2_EXTABLE) { + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE); + if (val < 0) + return val; + + if (val & (MDIO_PMA_EXTABLE_10GBT | MDIO_PMA_EXTABLE_1000BT | + MDIO_PMA_EXTABLE_100BTX | MDIO_PMA_EXTABLE_10BT)) + __set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported); + if (val & MDIO_PMA_EXTABLE_10GBLRM) + __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported); + if (val & (MDIO_PMA_EXTABLE_10GBKX4 | MDIO_PMA_EXTABLE_10GBKR | + MDIO_PMA_EXTABLE_1000BKX)) + __set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, supported); + if (val & MDIO_PMA_EXTABLE_10GBLRM) + __set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_10GBT) + __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_10GBKX4) + __set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_10GBKR) + __set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_1000BT) + __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_1000BKX) + __set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_100BTX) + __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, + supported); + if (val & MDIO_PMA_EXTABLE_10BT) + __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, + supported); + } + + if (!ethtool_convert_link_mode_to_legacy_u32(&mask, supported)) + dev_warn(&phydev->mdio.dev, + "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n", + __ETHTOOL_LINK_MODE_MASK_NBITS, supported); + + phydev->supported &= mask; + phydev->advertising &= phydev->supported; + + return 0; +} + +static int mv3310_config_aneg(struct phy_device *phydev) +{ + bool changed = false; + u32 advertising; + int ret; + + if (phydev->autoneg == AUTONEG_DISABLE) { + ret = genphy_c45_pma_setup_forced(phydev); + if (ret < 0) + return ret; + + return genphy_c45_an_disable_aneg(phydev); + } + + phydev->advertising &= phydev->supported; + advertising = phydev->advertising; + + ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_100BASE4 | + ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM, + ethtool_adv_to_mii_adv_t(advertising)); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + ret = mv3310_modify(phydev, MDIO_MMD_AN, MV_AN_CTRL1000, + ADVERTISE_1000FULL | ADVERTISE_1000HALF, + ethtool_adv_to_mii_ctrl1000_t(advertising)); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + /* 10G control register */ + ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV10G, + advertising & ADVERTISED_10000baseT_Full ? + MDIO_AN_10GBT_CTRL_ADV10G : 0); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + if (changed) + ret = genphy_c45_restart_aneg(phydev); + + return ret; +} + +static int mv3310_aneg_done(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1); + if (val < 0) + return val; + + if (val & MDIO_STAT1_LSTATUS) + return 1; + + return genphy_c45_aneg_done(phydev); +} + +/* 10GBASE-ER,LR,LRM,SR do not support autonegotiation. */ +static int mv3310_read_10gbr_status(struct phy_device *phydev) +{ + phydev->link = 1; + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) + phydev->interface = PHY_INTERFACE_MODE_10GKR; + + return 0; +} + +static int mv3310_read_status(struct phy_device *phydev) +{ + u32 mmd_mask = phydev->c45_ids.devices_in_package; + int val; + + /* The vendor devads do not report link status. Avoid the PHYXS + * instance as there are three, and its status depends on the MAC + * being appropriately configured for the negotiated speed. + */ + mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2) | + BIT(MDIO_MMD_PHYXS)); + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->lp_advertising = 0; + phydev->link = 0; + phydev->pause = 0; + phydev->asym_pause = 0; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1); + if (val < 0) + return val; + + if (val & MDIO_STAT1_LSTATUS) + return mv3310_read_10gbr_status(phydev); + + val = genphy_c45_read_link(phydev, mmd_mask); + if (val < 0) + return val; + + phydev->link = val > 0 ? 1 : 0; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + if (val < 0) + return val; + + if (val & MDIO_AN_STAT1_COMPLETE) { + val = genphy_c45_read_lpa(phydev); + if (val < 0) + return val; + + /* Read the link partner's 1G advertisment */ + val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_STAT1000); + if (val < 0) + return val; + + phydev->lp_advertising |= mii_stat1000_to_ethtool_lpa_t(val); + + if (phydev->autoneg == AUTONEG_ENABLE) { + val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_RESULT); + if (val < 0) + return val; + + if (val & MV_AN_RESULT_SPD_10000) + phydev->speed = SPEED_10000; + else if (val & MV_AN_RESULT_SPD_1000) + phydev->speed = SPEED_1000; + else if (val & MV_AN_RESULT_SPD_100) + phydev->speed = SPEED_100; + else if (val & MV_AN_RESULT_SPD_10) + phydev->speed = SPEED_10; + + phydev->duplex = DUPLEX_FULL; + } + } + + if (phydev->autoneg != AUTONEG_ENABLE) { + val = genphy_c45_read_pma(phydev); + if (val < 0) + return val; + } + + if ((phydev->interface == PHY_INTERFACE_MODE_SGMII || + phydev->interface == PHY_INTERFACE_MODE_10GKR) && phydev->link) { + /* The PHY automatically switches its serdes interface (and + * active PHYXS instance) between Cisco SGMII and 10GBase-KR + * modes according to the speed. Florian suggests setting + * phydev->interface to communicate this to the MAC. Only do + * this if we are already in either SGMII or 10GBase-KR mode. + */ + if (phydev->speed == SPEED_10000) + phydev->interface = PHY_INTERFACE_MODE_10GKR; + else if (phydev->speed >= SPEED_10 && + phydev->speed < SPEED_10000) + phydev->interface = PHY_INTERFACE_MODE_SGMII; + } + + return 0; +} + +static struct phy_driver mv3310_drivers[] = { + { + .phy_id = 0x002b09aa, + .phy_id_mask = 0xffffffff, + .name = "mv88x3310", + .features = SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP | + SUPPORTED_FIBRE | + SUPPORTED_10000baseT_Full | + SUPPORTED_Backplane, + .probe = mv3310_probe, + .soft_reset = mv3310_soft_reset, + .config_init = mv3310_config_init, + .config_aneg = mv3310_config_aneg, + .aneg_done = mv3310_aneg_done, + .read_status = mv3310_read_status, + }, +}; + +module_phy_driver(mv3310_drivers); + +static struct mdio_device_id __maybe_unused mv3310_tbl[] = { + { 0x002b09aa, 0xffffffff }, + { }, +}; +MODULE_DEVICE_TABLE(mdio, mv3310_tbl); +MODULE_DESCRIPTION("Marvell Alaska X 10Gigabit Ethernet PHY driver (MV88X3310)"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 2b30842b23b9e6796c7bd5f0916fd2ebf6b7d633 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 7 Jun 2017 03:57:09 +0200 Subject: net: fec: Clear and enable MIB counters on imx51 Both the IMX51 and IMX53 datasheet indicates that the MIB counters should be cleared during setup. Otherwise random numbers are returned via ethtool -S. Add a quirk and a function to do this. Tested on an IMX51. Signed-off-by: Andrew Lunn Reviewed-by: Fabio Estevam Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.h | 4 ++++ drivers/net/ethernet/freescale/fec_main.c | 27 ++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 5ea740b4cf14..38c7b21e5d63 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -446,6 +446,10 @@ struct bufdesc_ex { #define FEC_QUIRK_HAS_COALESCE (1 << 13) /* Interrupt doesn't wake CPU from deep idle */ #define FEC_QUIRK_ERR006687 (1 << 14) +/* The MIB counters should be cleared and enabled during + * initialisation. + */ +#define FEC_QUIRK_MIB_CLEAR (1 << 15) struct bufdesc_prop { int qid; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index f7c8649fd28f..297fd196c879 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -89,10 +89,10 @@ static struct platform_device_id fec_devtype[] = { .driver_data = 0, }, { .name = "imx25-fec", - .driver_data = FEC_QUIRK_USE_GASKET, + .driver_data = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR, }, { .name = "imx27-fec", - .driver_data = 0, + .driver_data = FEC_QUIRK_MIB_CLEAR, }, { .name = "imx28-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME | @@ -184,6 +184,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_RACC_SHIFT16 BIT(7) #define FEC_RACC_OPTIONS (FEC_RACC_IPDIS | FEC_RACC_PRODIS) +/* MIB Control Register */ +#define FEC_MIB_CTRLSTAT_DISABLE BIT(31) + /* * The 5270/5271/5280/5282/532x RX control register also contains maximum frame * size bits. Other FEC hardware does not, so we need to take that into @@ -2356,6 +2359,21 @@ static int fec_enet_get_sset_count(struct net_device *dev, int sset) } } +static void fec_enet_clear_ethtool_stats(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + int i; + + /* Disable MIB statistics counters */ + writel(FEC_MIB_CTRLSTAT_DISABLE, fep->hwp + FEC_MIB_CTRLSTAT); + + for (i = 0; i < ARRAY_SIZE(fec_stats); i++) + writel(0, fep->hwp + fec_stats[i].offset); + + /* Don't disable MIB statistics counters */ + writel(0, fep->hwp + FEC_MIB_CTRLSTAT); +} + #else /* !defined(CONFIG_M5272) */ #define FEC_STATS_SIZE 0 static inline void fec_enet_update_ethtool_stats(struct net_device *dev) @@ -3182,7 +3200,10 @@ static int fec_enet_init(struct net_device *ndev) fec_restart(ndev); - fec_enet_update_ethtool_stats(ndev); + if (fep->quirks & FEC_QUIRK_MIB_CLEAR) + fec_enet_clear_ethtool_stats(ndev); + else + fec_enet_update_ethtool_stats(ndev); return 0; } -- cgit v1.2.3 From d00ca2f3783b97c936f2a3df9dd0fabf4c0a8290 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:42 -0700 Subject: nfp: reorder open and close functions We will soon reuse parts of .ndo_stop() for clean up after errors in .ndo_open(). Reorder the associated functions to make that possible. No functional changes. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 140 ++++++++++----------- 1 file changed, 70 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index c3235d03b8eb..770ef28c0380 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2275,6 +2275,76 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn) return 0; } +/** + * nfp_net_close_stack() - Quiesce the stack (part of close) + * @nn: NFP Net device to reconfigure + */ +static void nfp_net_close_stack(struct nfp_net *nn) +{ + unsigned int r; + + disable_irq(nn->irq_entries[NFP_NET_IRQ_LSC_IDX].vector); + netif_carrier_off(nn->dp.netdev); + nn->link_up = false; + + for (r = 0; r < nn->dp.num_r_vecs; r++) { + disable_irq(nn->r_vecs[r].irq_vector); + napi_disable(&nn->r_vecs[r].napi); + } + + netif_tx_disable(nn->dp.netdev); +} + +/** + * nfp_net_close_free_all() - Free all runtime resources + * @nn: NFP Net device to reconfigure + */ +static void nfp_net_close_free_all(struct nfp_net *nn) +{ + unsigned int r; + + for (r = 0; r < nn->dp.num_rx_rings; r++) { + nfp_net_rx_ring_bufs_free(&nn->dp, &nn->dp.rx_rings[r]); + nfp_net_rx_ring_free(&nn->dp.rx_rings[r]); + } + for (r = 0; r < nn->dp.num_tx_rings; r++) { + nfp_net_tx_ring_bufs_free(&nn->dp, &nn->dp.tx_rings[r]); + nfp_net_tx_ring_free(&nn->dp.tx_rings[r]); + } + for (r = 0; r < nn->dp.num_r_vecs; r++) + nfp_net_cleanup_vector(nn, &nn->r_vecs[r]); + + kfree(nn->dp.rx_rings); + kfree(nn->dp.tx_rings); + + nfp_net_aux_irq_free(nn, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX); + nfp_net_aux_irq_free(nn, NFP_NET_CFG_EXN, NFP_NET_IRQ_EXN_IDX); +} + +/** + * nfp_net_netdev_close() - Called when the device is downed + * @netdev: netdev structure + */ +static int nfp_net_netdev_close(struct net_device *netdev) +{ + struct nfp_net *nn = netdev_priv(netdev); + + /* Step 1: Disable RX and TX rings from the Linux kernel perspective + */ + nfp_net_close_stack(nn); + + /* Step 2: Tell NFP + */ + nfp_net_clear_config_and_disable(nn); + + /* Step 3: Free resources + */ + nfp_net_close_free_all(nn); + + nn_dbg(nn, "%s down", netdev->name); + return 0; +} + /** * nfp_net_open_stack() - Start the device from stack's perspective * @nn: NFP Net device to reconfigure @@ -2377,76 +2447,6 @@ err_free_exn: return err; } -/** - * nfp_net_close_stack() - Quiescent the stack (part of close) - * @nn: NFP Net device to reconfigure - */ -static void nfp_net_close_stack(struct nfp_net *nn) -{ - unsigned int r; - - disable_irq(nn->irq_entries[NFP_NET_IRQ_LSC_IDX].vector); - netif_carrier_off(nn->dp.netdev); - nn->link_up = false; - - for (r = 0; r < nn->dp.num_r_vecs; r++) { - disable_irq(nn->r_vecs[r].irq_vector); - napi_disable(&nn->r_vecs[r].napi); - } - - netif_tx_disable(nn->dp.netdev); -} - -/** - * nfp_net_close_free_all() - Free all runtime resources - * @nn: NFP Net device to reconfigure - */ -static void nfp_net_close_free_all(struct nfp_net *nn) -{ - unsigned int r; - - for (r = 0; r < nn->dp.num_rx_rings; r++) { - nfp_net_rx_ring_bufs_free(&nn->dp, &nn->dp.rx_rings[r]); - nfp_net_rx_ring_free(&nn->dp.rx_rings[r]); - } - for (r = 0; r < nn->dp.num_tx_rings; r++) { - nfp_net_tx_ring_bufs_free(&nn->dp, &nn->dp.tx_rings[r]); - nfp_net_tx_ring_free(&nn->dp.tx_rings[r]); - } - for (r = 0; r < nn->dp.num_r_vecs; r++) - nfp_net_cleanup_vector(nn, &nn->r_vecs[r]); - - kfree(nn->dp.rx_rings); - kfree(nn->dp.tx_rings); - - nfp_net_aux_irq_free(nn, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX); - nfp_net_aux_irq_free(nn, NFP_NET_CFG_EXN, NFP_NET_IRQ_EXN_IDX); -} - -/** - * nfp_net_netdev_close() - Called when the device is downed - * @netdev: netdev structure - */ -static int nfp_net_netdev_close(struct net_device *netdev) -{ - struct nfp_net *nn = netdev_priv(netdev); - - /* Step 1: Disable RX and TX rings from the Linux kernel perspective - */ - nfp_net_close_stack(nn); - - /* Step 2: Tell NFP - */ - nfp_net_clear_config_and_disable(nn); - - /* Step 3: Free resources - */ - nfp_net_close_free_all(nn); - - nn_dbg(nn, "%s down", netdev->name); - return 0; -} - static void nfp_net_set_rx_mode(struct net_device *netdev) { struct nfp_net *nn = netdev_priv(netdev); -- cgit v1.2.3 From ee26756d01cbff9e8b9ef9635f58b05b27492a49 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:43 -0700 Subject: nfp: split out the allocation part of open Our open/close implementations have 3 stages: - allocation/freeing of ring resources, irqs etc., - device config, - device/stack enable (can't fail). Right now all of those stages are placed in separate functions, apart from allocation during open. Fix that. It will make it easier for us to allocate resources for netdev-less vNICs. Because we want to reuse allocation code in netdev-less vNICs leave the netif_set_real_num_[rt]x_queues() calls inside open. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 57 +++++++++++++--------- 1 file changed, 35 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 770ef28c0380..bec51f4a9299 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2364,16 +2364,10 @@ static void nfp_net_open_stack(struct nfp_net *nn) nfp_net_read_link_status(nn); } -static int nfp_net_netdev_open(struct net_device *netdev) +static int nfp_net_open_alloc_all(struct nfp_net *nn) { - struct nfp_net *nn = netdev_priv(netdev); int err, r; - /* Step 1: Allocate resources for rings and the like - * - Request interrupts - * - Allocate RX and TX ring resources - * - Setup initial RSS table - */ err = nfp_net_aux_irq_request(nn, NFP_NET_CFG_EXN, "%s-exn", nn->exn_name, sizeof(nn->exn_name), NFP_NET_IRQ_EXN_IDX, nn->exn_handler); @@ -2403,13 +2397,42 @@ static int nfp_net_netdev_open(struct net_device *netdev) for (r = 0; r < nn->max_r_vecs; r++) nfp_net_vector_assign_rings(&nn->dp, &nn->r_vecs[r], r); + return 0; + +err_free_rx_rings: + nfp_net_rx_rings_free(&nn->dp); +err_cleanup_vec: + r = nn->dp.num_r_vecs; +err_cleanup_vec_p: + while (r--) + nfp_net_cleanup_vector(nn, &nn->r_vecs[r]); + nfp_net_aux_irq_free(nn, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX); +err_free_exn: + nfp_net_aux_irq_free(nn, NFP_NET_CFG_EXN, NFP_NET_IRQ_EXN_IDX); + return err; +} + +static int nfp_net_netdev_open(struct net_device *netdev) +{ + struct nfp_net *nn = netdev_priv(netdev); + int err; + + /* Step 1: Allocate resources for rings and the like + * - Request interrupts + * - Allocate RX and TX ring resources + * - Setup initial RSS table + */ + err = nfp_net_open_alloc_all(nn); + if (err) + return err; + err = netif_set_real_num_tx_queues(netdev, nn->dp.num_stack_tx_rings); if (err) - goto err_free_rings; + goto err_free_all; err = netif_set_real_num_rx_queues(netdev, nn->dp.num_rx_rings); if (err) - goto err_free_rings; + goto err_free_all; /* Step 2: Configure the NFP * - Enable rings from 0 to tx_rings/rx_rings - 1. @@ -2420,7 +2443,7 @@ static int nfp_net_netdev_open(struct net_device *netdev) */ err = nfp_net_set_config_and_enable(nn); if (err) - goto err_free_rings; + goto err_free_all; /* Step 3: Enable for kernel * - put some freelist descriptors on each RX ring @@ -2432,18 +2455,8 @@ static int nfp_net_netdev_open(struct net_device *netdev) return 0; -err_free_rings: - nfp_net_tx_rings_free(&nn->dp); -err_free_rx_rings: - nfp_net_rx_rings_free(&nn->dp); -err_cleanup_vec: - r = nn->dp.num_r_vecs; -err_cleanup_vec_p: - while (r--) - nfp_net_cleanup_vector(nn, &nn->r_vecs[r]); - nfp_net_aux_irq_free(nn, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX); -err_free_exn: - nfp_net_aux_irq_free(nn, NFP_NET_CFG_EXN, NFP_NET_IRQ_EXN_IDX); +err_free_all: + nfp_net_close_free_all(nn); return err; } -- cgit v1.2.3 From 4621199dbfb188e4871520569233f7c7528ab439 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:44 -0700 Subject: nfp: reuse ring free code on close On the close path reuse the ring free helpers introduced for runtime reconfiguration. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index bec51f4a9299..23419883cfd4 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2303,20 +2303,12 @@ static void nfp_net_close_free_all(struct nfp_net *nn) { unsigned int r; - for (r = 0; r < nn->dp.num_rx_rings; r++) { - nfp_net_rx_ring_bufs_free(&nn->dp, &nn->dp.rx_rings[r]); - nfp_net_rx_ring_free(&nn->dp.rx_rings[r]); - } - for (r = 0; r < nn->dp.num_tx_rings; r++) { - nfp_net_tx_ring_bufs_free(&nn->dp, &nn->dp.tx_rings[r]); - nfp_net_tx_ring_free(&nn->dp.tx_rings[r]); - } + nfp_net_tx_rings_free(&nn->dp); + nfp_net_rx_rings_free(&nn->dp); + for (r = 0; r < nn->dp.num_r_vecs; r++) nfp_net_cleanup_vector(nn, &nn->r_vecs[r]); - kfree(nn->dp.rx_rings); - kfree(nn->dp.tx_rings); - nfp_net_aux_irq_free(nn, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX); nfp_net_aux_irq_free(nn, NFP_NET_CFG_EXN, NFP_NET_IRQ_EXN_IDX); } -- cgit v1.2.3 From cd083ce158cf43f8c26ad9a552ba25b222536e1e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:45 -0700 Subject: nfp: move nfp_net_vecs_init() Move nfp_net_vecs_init() after all datapath functions. We will need to init poll() callbacks from this function soon. No functional changes. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 54 +++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 23419883cfd4..f8dba793a8fe 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -503,33 +503,6 @@ nfp_net_rx_ring_init(struct nfp_net_rx_ring *rx_ring, rx_ring->qcp_fl = nn->rx_bar + NFP_QCP_QUEUE_OFF(rx_ring->fl_qcidx); } -/** - * nfp_net_vecs_init() - Assign IRQs and setup rvecs. - * @nn: NFP Network structure - */ -static void nfp_net_vecs_init(struct nfp_net *nn) -{ - struct nfp_net_r_vector *r_vec; - int r; - - nn->lsc_handler = nfp_net_irq_lsc; - nn->exn_handler = nfp_net_irq_exn; - - for (r = 0; r < nn->max_r_vecs; r++) { - struct msix_entry *entry; - - entry = &nn->irq_entries[NFP_NET_NON_Q_VECTORS + r]; - - r_vec = &nn->r_vecs[r]; - r_vec->nfp_net = nn; - r_vec->handler = nfp_net_irq_rxtx; - r_vec->irq_entry = entry->entry; - r_vec->irq_vector = entry->vector; - - cpumask_set_cpu(r, &r_vec->affinity_mask); - } -} - /** * nfp_net_aux_irq_request() - Request an auxiliary interrupt (LSC or EXN) * @nn: NFP Network structure @@ -1772,6 +1745,33 @@ static int nfp_net_poll(struct napi_struct *napi, int budget) /* Setup and Configuration */ +/** + * nfp_net_vecs_init() - Assign IRQs and setup rvecs. + * @nn: NFP Network structure + */ +static void nfp_net_vecs_init(struct nfp_net *nn) +{ + struct nfp_net_r_vector *r_vec; + int r; + + nn->lsc_handler = nfp_net_irq_lsc; + nn->exn_handler = nfp_net_irq_exn; + + for (r = 0; r < nn->max_r_vecs; r++) { + struct msix_entry *entry; + + entry = &nn->irq_entries[NFP_NET_NON_Q_VECTORS + r]; + + r_vec = &nn->r_vecs[r]; + r_vec->nfp_net = nn; + r_vec->handler = nfp_net_irq_rxtx; + r_vec->irq_entry = entry->entry; + r_vec->irq_vector = entry->vector; + + cpumask_set_cpu(r, &r_vec->affinity_mask); + } +} + /** * nfp_net_tx_ring_free() - Free resources allocated to a TX ring * @tx_ring: TX ring to free -- cgit v1.2.3 From c821e617896e99b82fa82777b1ac1263c51eea64 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:46 -0700 Subject: nfp: prepare print macros for use without netdev To be able to reuse print macros easily with control vNICs make the macros check if netdev pointer is populated and use dev_* print functions otherwise. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 33 +++++++++++++++++++++------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 2e526338f678..b14aa31d494a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -50,15 +50,32 @@ #include "nfp_net_ctrl.h" -#define nn_err(nn, fmt, args...) netdev_err((nn)->dp.netdev, fmt, ## args) -#define nn_warn(nn, fmt, args...) netdev_warn((nn)->dp.netdev, fmt, ## args) -#define nn_info(nn, fmt, args...) netdev_info((nn)->dp.netdev, fmt, ## args) -#define nn_dbg(nn, fmt, args...) netdev_dbg((nn)->dp.netdev, fmt, ## args) +#define nn_pr(nn, lvl, fmt, args...) \ + ({ \ + struct nfp_net *__nn = (nn); \ + \ + if (__nn->dp.netdev) \ + netdev_printk(lvl, __nn->dp.netdev, fmt, ## args); \ + else \ + dev_printk(lvl, __nn->dp.dev, "ctrl: " fmt, ## args); \ + }) + +#define nn_err(nn, fmt, args...) nn_pr(nn, KERN_ERR, fmt, ## args) +#define nn_warn(nn, fmt, args...) nn_pr(nn, KERN_WARNING, fmt, ## args) +#define nn_info(nn, fmt, args...) nn_pr(nn, KERN_INFO, fmt, ## args) +#define nn_dbg(nn, fmt, args...) nn_pr(nn, KERN_DEBUG, fmt, ## args) + #define nn_dp_warn(dp, fmt, args...) \ - do { \ - if (unlikely(net_ratelimit())) \ - netdev_warn((dp)->netdev, fmt, ## args); \ - } while (0) + ({ \ + struct nfp_net_dp *__dp = (dp); \ + \ + if (unlikely(net_ratelimit())) { \ + if (__dp->netdev) \ + netdev_warn(__dp->netdev, fmt, ## args); \ + else \ + dev_warn(__dp->dev, fmt, ## args); \ + } \ + }) /* Max time to wait for NFP to respond on updates (in seconds) */ #define NFP_NET_POLL_TIMEOUT 5 -- cgit v1.2.3 From 042f4ba62ff5fbe1428639187578bae39f513e23 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:47 -0700 Subject: nfp: make sure debug accesses don't depend on netdevs We want to be able to inspect the state of descriptor rings of the control vNIC, so it will use the same interface as data vNICs. Make sure the code doesn't use netdevs to determine state of the rings and names things appropriately. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 11 +++++++++++ drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c | 9 ++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index b14aa31d494a..3eec4195c155 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -805,6 +805,17 @@ static inline u32 nfp_qcp_wr_ptr_read(u8 __iomem *q) return _nfp_qcp_read(q, NFP_QCP_WRITE_PTR); } +static inline bool nfp_net_is_data_vnic(struct nfp_net *nn) +{ + WARN_ON_ONCE(!nn->dp.netdev && nn->port); + return !!nn->dp.netdev; +} + +static inline bool nfp_net_running(struct nfp_net *nn) +{ + return nn->dp.ctrl & NFP_NET_CFG_CTRL_ENABLE; +} + /* Globals */ extern const char nfp_driver_version[]; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c index 8c52c0e8379c..40217ece5fcb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c @@ -54,7 +54,7 @@ static int nfp_net_debugfs_rx_q_read(struct seq_file *file, void *data) goto out; nn = r_vec->nfp_net; rx_ring = r_vec->rx_ring; - if (!netif_running(nn->dp.netdev)) + if (!nfp_net_running(nn)) goto out; rxd_cnt = rx_ring->cnt; @@ -138,7 +138,7 @@ static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data) if (!r_vec->nfp_net || !tx_ring) goto out; nn = r_vec->nfp_net; - if (!netif_running(nn->dp.netdev)) + if (!nfp_net_running(nn)) goto out; txd_cnt = tx_ring->cnt; @@ -209,7 +209,10 @@ void nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir, int id) if (IS_ERR_OR_NULL(nfp_dir)) return; - sprintf(name, "vnic%d", id); + if (nfp_net_is_data_vnic(nn)) + sprintf(name, "vnic%d", id); + else + strcpy(name, "ctrl-vnic"); nn->debugfs_dir = debugfs_create_dir(name, ddir); if (IS_ERR_OR_NULL(nn->debugfs_dir)) return; -- cgit v1.2.3 From a7b1ad0875479e7390eb46e1190e50ffc39707b9 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:48 -0700 Subject: nfp: allow allocation and initialization of netdev-less vNICs vNICs used for sending and receiving control messages shouldn't really have a netdev. Add the ability to initialize vNICs for netdev-less operation. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 2 +- .../net/ethernet/netronome/nfp/nfp_net_common.c | 170 ++++++++++++--------- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 7 +- .../net/ethernet/netronome/nfp/nfp_netvf_main.c | 2 +- 4 files changed, 105 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 3eec4195c155..6b21c4d0ccfa 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -831,7 +831,7 @@ void nfp_net_get_fw_version(struct nfp_net_fw_version *fw_ver, void __iomem *ctrl_bar); struct nfp_net * -nfp_net_alloc(struct pci_dev *pdev, +nfp_net_alloc(struct pci_dev *pdev, bool needs_netdev, unsigned int max_tx_rings, unsigned int max_rx_rings); void nfp_net_free(struct nfp_net *nn); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index f8dba793a8fe..1cc7425ffd27 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -61,7 +61,7 @@ #include #include #include - +#include #include #include @@ -1820,7 +1820,7 @@ nfp_net_tx_ring_alloc(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring) if (!tx_ring->txbufs) goto err_alloc; - if (!tx_ring->is_xdp) + if (!tx_ring->is_xdp && dp->netdev) netif_set_xps_queue(dp->netdev, &r_vec->affinity_mask, tx_ring->idx); @@ -3034,30 +3034,39 @@ void nfp_net_info(struct nfp_net *nn) /** * nfp_net_alloc() - Allocate netdev and related structure * @pdev: PCI device + * @needs_netdev: Whether to allocate a netdev for this vNIC * @max_tx_rings: Maximum number of TX rings supported by device * @max_rx_rings: Maximum number of RX rings supported by device * * This function allocates a netdev device and fills in the initial - * part of the @struct nfp_net structure. + * part of the @struct nfp_net structure. In case of control device + * nfp_net structure is allocated without the netdev. * * Return: NFP Net device structure, or ERR_PTR on error. */ -struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, +struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, bool needs_netdev, unsigned int max_tx_rings, unsigned int max_rx_rings) { - struct net_device *netdev; struct nfp_net *nn; - netdev = alloc_etherdev_mqs(sizeof(struct nfp_net), - max_tx_rings, max_rx_rings); - if (!netdev) - return ERR_PTR(-ENOMEM); + if (needs_netdev) { + struct net_device *netdev; - SET_NETDEV_DEV(netdev, &pdev->dev); - nn = netdev_priv(netdev); + netdev = alloc_etherdev_mqs(sizeof(struct nfp_net), + max_tx_rings, max_rx_rings); + if (!netdev) + return ERR_PTR(-ENOMEM); + + SET_NETDEV_DEV(netdev, &pdev->dev); + nn = netdev_priv(netdev); + nn->dp.netdev = netdev; + } else { + nn = vzalloc(sizeof(*nn)); + if (!nn) + return ERR_PTR(-ENOMEM); + } - nn->dp.netdev = netdev; nn->dp.dev = &pdev->dev; nn->pdev = pdev; @@ -3091,7 +3100,10 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, */ void nfp_net_free(struct nfp_net *nn) { - free_netdev(nn->dp.netdev); + if (nn->dp.netdev) + free_netdev(nn->dp.netdev); + else + vfree(nn); } /** @@ -3162,52 +3174,13 @@ static void nfp_net_irqmod_init(struct nfp_net *nn) nn->tx_coalesce_max_frames = 64; } -/** - * nfp_net_init() - Initialise/finalise the nfp_net structure - * @nn: NFP Net device structure - * - * Return: 0 on success or negative errno on error. - */ -int nfp_net_init(struct nfp_net *nn) +static void nfp_net_netdev_init(struct nfp_net *nn) { struct net_device *netdev = nn->dp.netdev; - int err; - - nn->dp.rx_dma_dir = DMA_FROM_DEVICE; - - /* Get some of the read-only fields from the BAR */ - nn->cap = nn_readl(nn, NFP_NET_CFG_CAP); - nn->max_mtu = nn_readl(nn, NFP_NET_CFG_MAX_MTU); - - /* Chained metadata is signalled by capabilities except in version 4 */ - nn->dp.chained_metadata_format = nn->fw_ver.major == 4 || - nn->cap & NFP_NET_CFG_CTRL_CHAIN_META; - if (nn->dp.chained_metadata_format && nn->fw_ver.major != 4) - nn->cap &= ~NFP_NET_CFG_CTRL_RSS; nfp_net_write_mac_addr(nn, nn->dp.netdev->dev_addr); - /* Determine RX packet/metadata boundary offset */ - if (nn->fw_ver.major >= 2) { - u32 reg; - - reg = nn_readl(nn, NFP_NET_CFG_RX_OFFSET); - if (reg > NFP_NET_MAX_PREPEND) { - nn_err(nn, "Invalid rx offset: %d\n", reg); - return -EINVAL; - } - nn->dp.rx_offset = reg; - } else { - nn->dp.rx_offset = NFP_NET_RX_OFFSET; - } - - /* Set default MTU and Freelist buffer size */ - if (nn->max_mtu < NFP_NET_DEFAULT_MTU) - netdev->mtu = nn->max_mtu; - else - netdev->mtu = NFP_NET_DEFAULT_MTU; - nn->dp.mtu = netdev->mtu; - nn->dp.fl_bufsz = nfp_net_calc_fl_bufsz(&nn->dp); + netdev->mtu = nn->dp.mtu; /* Advertise/enable offloads based on capabilities * @@ -3237,12 +3210,8 @@ int nfp_net_init(struct nfp_net *nn) nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_LSO2 ?: NFP_NET_CFG_CTRL_LSO; } - if (nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) { + if (nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) netdev->hw_features |= NETIF_F_RXHASH; - nfp_net_rss_init(nn); - nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_RSS2 ?: - NFP_NET_CFG_CTRL_RSS; - } if (nn->cap & NFP_NET_CFG_CTRL_VXLAN && nn->cap & NFP_NET_CFG_CTRL_NVGRE) { if (nn->cap & NFP_NET_CFG_CTRL_LSO) @@ -3277,6 +3246,68 @@ int nfp_net_init(struct nfp_net *nn) netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY; + /* Finalise the netdev setup */ + netdev->netdev_ops = &nfp_net_netdev_ops; + netdev->watchdog_timeo = msecs_to_jiffies(5 * 1000); + + /* MTU range: 68 - hw-specific max */ + netdev->min_mtu = ETH_MIN_MTU; + netdev->max_mtu = nn->max_mtu; + + netif_carrier_off(netdev); + + nfp_net_set_ethtool_ops(netdev); +} + +/** + * nfp_net_init() - Initialise/finalise the nfp_net structure + * @nn: NFP Net device structure + * + * Return: 0 on success or negative errno on error. + */ +int nfp_net_init(struct nfp_net *nn) +{ + int err; + + nn->dp.rx_dma_dir = DMA_FROM_DEVICE; + + /* Get some of the read-only fields from the BAR */ + nn->cap = nn_readl(nn, NFP_NET_CFG_CAP); + nn->max_mtu = nn_readl(nn, NFP_NET_CFG_MAX_MTU); + + /* Chained metadata is signalled by capabilities except in version 4 */ + nn->dp.chained_metadata_format = nn->fw_ver.major == 4 || + nn->cap & NFP_NET_CFG_CTRL_CHAIN_META; + if (nn->dp.chained_metadata_format && nn->fw_ver.major != 4) + nn->cap &= ~NFP_NET_CFG_CTRL_RSS; + + /* Determine RX packet/metadata boundary offset */ + if (nn->fw_ver.major >= 2) { + u32 reg; + + reg = nn_readl(nn, NFP_NET_CFG_RX_OFFSET); + if (reg > NFP_NET_MAX_PREPEND) { + nn_err(nn, "Invalid rx offset: %d\n", reg); + return -EINVAL; + } + nn->dp.rx_offset = reg; + } else { + nn->dp.rx_offset = NFP_NET_RX_OFFSET; + } + + /* Set default MTU and Freelist buffer size */ + if (nn->max_mtu < NFP_NET_DEFAULT_MTU) + nn->dp.mtu = nn->max_mtu; + else + nn->dp.mtu = NFP_NET_DEFAULT_MTU; + nn->dp.fl_bufsz = nfp_net_calc_fl_bufsz(&nn->dp); + + if (nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) { + nfp_net_rss_init(nn); + nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_RSS2 ?: + NFP_NET_CFG_CTRL_RSS; + } + /* Allow L2 Broadcast and Multicast through by default, if supported */ if (nn->cap & NFP_NET_CFG_CTRL_L2BC) nn->dp.ctrl |= NFP_NET_CFG_CTRL_L2BC; @@ -3289,6 +3320,9 @@ int nfp_net_init(struct nfp_net *nn) nn->dp.ctrl |= NFP_NET_CFG_CTRL_IRQMOD; } + if (nn->dp.netdev) + nfp_net_netdev_init(nn); + /* Stash the re-configuration queue away. First odd queue in TX Bar */ nn->qcp_cfg = nn->tx_bar + NFP_QCP_QUEUE_ADDR_SZ; @@ -3301,20 +3335,11 @@ int nfp_net_init(struct nfp_net *nn) if (err) return err; - /* Finalise the netdev setup */ - netdev->netdev_ops = &nfp_net_netdev_ops; - netdev->watchdog_timeo = msecs_to_jiffies(5 * 1000); - - /* MTU range: 68 - hw-specific max */ - netdev->min_mtu = ETH_MIN_MTU; - netdev->max_mtu = nn->max_mtu; - - netif_carrier_off(netdev); - - nfp_net_set_ethtool_ops(netdev); nfp_net_vecs_init(nn); - return register_netdev(netdev); + if (!nn->dp.netdev) + return 0; + return register_netdev(nn->dp.netdev); } /** @@ -3323,6 +3348,9 @@ int nfp_net_init(struct nfp_net *nn) */ void nfp_net_clean(struct nfp_net *nn) { + if (!nn->dp.netdev) + return; + unregister_netdev(nn->dp.netdev); if (nn->dp.xdp_prog) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 7dd310911d9f..dd2a99fca716 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -303,7 +303,8 @@ static void nfp_net_pf_free_vnics(struct nfp_pf *pf) } static struct nfp_net * -nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, +nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev, + void __iomem *ctrl_bar, void __iomem *tx_bar, void __iomem *rx_bar, int stride, struct nfp_net_fw_version *fw_ver, unsigned int eth_id) @@ -316,7 +317,7 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar, n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS); /* Allocate and initialise the vNIC */ - nn = nfp_net_alloc(pf->pdev, n_tx_rings, n_rx_rings); + nn = nfp_net_alloc(pf->pdev, needs_netdev, n_tx_rings, n_rx_rings); if (IS_ERR(nn)) return nn; @@ -395,7 +396,7 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, prev_tx_base = tgt_tx_base; prev_rx_base = tgt_rx_base; - nn = nfp_net_pf_alloc_vnic(pf, ctrl_bar, tx_bar, rx_bar, + nn = nfp_net_pf_alloc_vnic(pf, true, ctrl_bar, tx_bar, rx_bar, stride, fw_ver, i); if (IS_ERR(nn)) { err = PTR_ERR(nn); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c index 3f1c7f0f392e..0bf3b0febd07 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c @@ -202,7 +202,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, rx_bar_off = NFP_PCIE_QUEUE(startq); /* Allocate and initialise the netdev */ - nn = nfp_net_alloc(pdev, max_tx_rings, max_rx_rings); + nn = nfp_net_alloc(pdev, true, max_tx_rings, max_rx_rings); if (IS_ERR(nn)) { err = PTR_ERR(nn); goto err_ctrl_unmap; -- cgit v1.2.3 From 5c0dbe9ecf02349490794a4205d61c6603390082 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:49 -0700 Subject: nfp: prepare config and enable for working without netdevs Out of the three stages of ifup/ifdown (allocate, configure, start) - this commit prepares the configuration stage for working with control vNICs. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 1cc7425ffd27..c47705861a81 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2236,9 +2236,10 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn) nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, nn->dp.num_rx_rings == 64 ? 0xffffffffffffffffULL : ((u64)1 << nn->dp.num_rx_rings) - 1); - nfp_net_write_mac_addr(nn, nn->dp.netdev->dev_addr); + if (nn->dp.netdev) + nfp_net_write_mac_addr(nn, nn->dp.netdev->dev_addr); - nn_writel(nn, NFP_NET_CFG_MTU, nn->dp.netdev->mtu); + nn_writel(nn, NFP_NET_CFG_MTU, nn->dp.mtu); bufsz = nn->dp.fl_bufsz - nn->dp.rx_dma_off - NFP_NET_RX_BUF_NON_DATA; nn_writel(nn, NFP_NET_CFG_FLBUFSZ, bufsz); -- cgit v1.2.3 From 77ece8d5f1960f82d66b68fbc0c92938cdfa2688 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:50 -0700 Subject: nfp: add control vNIC datapath Since control vNICs don't have a netdev, they can't use napi and queuing stack provides. Add simple tasklet-based data receive and send of control messages with queuing on a skb_list. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_app.h | 11 + drivers/net/ethernet/netronome/nfp/nfp_net.h | 17 +- .../net/ethernet/netronome/nfp/nfp_net_common.c | 323 ++++++++++++++++++++- drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h | 3 + 4 files changed, 345 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index 13efdefffa1a..f6091ad0a9a9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -38,6 +38,7 @@ struct bpf_prog; struct net_device; struct pci_dev; struct tc_to_netdev; +struct sk_buff; struct nfp_app; struct nfp_cpp; struct nfp_pf; @@ -55,6 +56,7 @@ extern const struct nfp_app_type app_bpf; * struct nfp_app_type - application definition * @id: application ID * @name: application name + * @ctrl_has_meta: control messages have prepend of type:5/port:CTRL * * Callbacks * @init: perform basic app checks @@ -69,6 +71,8 @@ struct nfp_app_type { enum nfp_app_id id; const char *name; + bool ctrl_has_meta; + int (*init)(struct nfp_app *app); const char *(*extra_cap)(struct nfp_app *app, struct nfp_net *nn); @@ -99,6 +103,8 @@ struct nfp_app { const struct nfp_app_type *type; }; +bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb); + static inline int nfp_app_init(struct nfp_app *app) { if (!app->type->init) @@ -125,6 +131,11 @@ static inline const char *nfp_app_name(struct nfp_app *app) return app->type->name; } +static inline bool nfp_app_ctrl_has_meta(struct nfp_app *app) +{ + return app->type->ctrl_has_meta; +} + static inline const char *nfp_app_extra_cap(struct nfp_app *app, struct nfp_net *nn) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 6b21c4d0ccfa..eb849d26f4dd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -405,7 +405,14 @@ struct nfp_net_rx_ring { */ struct nfp_net_r_vector { struct nfp_net *nfp_net; - struct napi_struct napi; + union { + struct napi_struct napi; + struct { + struct tasklet_struct tasklet; + struct sk_buff_head queue; + struct spinlock lock; + }; + }; struct nfp_net_tx_ring *tx_ring; struct nfp_net_rx_ring *rx_ring; @@ -816,6 +823,11 @@ static inline bool nfp_net_running(struct nfp_net *nn) return nn->dp.ctrl & NFP_NET_CFG_CTRL_ENABLE; } +static inline const char *nfp_net_name(struct nfp_net *nn) +{ + return nn->dp.netdev ? nn->dp.netdev->name : "ctrl"; +} + /* Globals */ extern const char nfp_driver_version[]; @@ -838,6 +850,9 @@ void nfp_net_free(struct nfp_net *nn); int nfp_net_init(struct nfp_net *nn); void nfp_net_clean(struct nfp_net *nn); +int nfp_ctrl_open(struct nfp_net *nn); +void nfp_ctrl_close(struct nfp_net *nn); + void nfp_net_set_ethtool_ops(struct net_device *netdev); void nfp_net_info(struct nfp_net *nn); int nfp_net_reconfig(struct nfp_net *nn, u32 update); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index c47705861a81..59f1764242a0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -392,6 +392,15 @@ static irqreturn_t nfp_net_irq_rxtx(int irq, void *data) return IRQ_HANDLED; } +static irqreturn_t nfp_ctrl_irq_rxtx(int irq, void *data) +{ + struct nfp_net_r_vector *r_vec = data; + + tasklet_schedule(&r_vec->tasklet); + + return IRQ_HANDLED; +} + /** * nfp_net_read_link_status() - Reread link status from control BAR * @nn: NFP Network structure @@ -523,7 +532,7 @@ nfp_net_aux_irq_request(struct nfp_net *nn, u32 ctrl_offset, entry = &nn->irq_entries[vector_idx]; - snprintf(name, name_sz, format, netdev_name(nn->dp.netdev)); + snprintf(name, name_sz, format, nfp_net_name(nn)); err = request_irq(entry->vector, handler, 0, name, nn); if (err) { nn_err(nn, "Failed to request IRQ %d (err=%d).\n", @@ -943,6 +952,9 @@ static void nfp_net_tx_complete(struct nfp_net_tx_ring *tx_ring) r_vec->tx_pkts += done_pkts; u64_stats_update_end(&r_vec->tx_sync); + if (!dp->netdev) + return; + nd_q = netdev_get_tx_queue(dp->netdev, tx_ring->idx); netdev_tx_completed_queue(nd_q, done_pkts, done_bytes); if (nfp_net_tx_ring_should_wake(tx_ring)) { @@ -1052,7 +1064,7 @@ nfp_net_tx_ring_reset(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring) tx_ring->qcp_rd_p = 0; tx_ring->wr_ptr_add = 0; - if (tx_ring->is_xdp) + if (tx_ring->is_xdp || !dp->netdev) return; nd_q = netdev_get_tx_queue(dp->netdev, tx_ring->idx); @@ -1742,6 +1754,231 @@ static int nfp_net_poll(struct napi_struct *napi, int budget) return pkts_polled; } +/* Control device data path + */ + +static bool +nfp_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, + struct sk_buff *skb, bool old) +{ + unsigned int real_len = skb->len, meta_len = 0; + struct nfp_net_tx_ring *tx_ring; + struct nfp_net_tx_buf *txbuf; + struct nfp_net_tx_desc *txd; + struct nfp_net_dp *dp; + dma_addr_t dma_addr; + int wr_idx; + + dp = &r_vec->nfp_net->dp; + tx_ring = r_vec->tx_ring; + + if (WARN_ON_ONCE(skb_shinfo(skb)->nr_frags)) { + nn_dp_warn(dp, "Driver's CTRL TX does not implement gather\n"); + goto err_free; + } + + if (unlikely(nfp_net_tx_full(tx_ring, 1))) { + u64_stats_update_begin(&r_vec->tx_sync); + r_vec->tx_busy++; + u64_stats_update_end(&r_vec->tx_sync); + if (!old) + __skb_queue_tail(&r_vec->queue, skb); + else + __skb_queue_head(&r_vec->queue, skb); + return true; + } + + if (nfp_app_ctrl_has_meta(nn->app)) { + if (unlikely(skb_headroom(skb) < 8)) { + nn_dp_warn(dp, "CTRL TX on skb without headroom\n"); + goto err_free; + } + meta_len = 8; + put_unaligned_be32(NFP_META_PORT_ID_CTRL, skb_push(skb, 4)); + put_unaligned_be32(NFP_NET_META_PORTID, skb_push(skb, 4)); + } + + /* Start with the head skbuf */ + dma_addr = dma_map_single(dp->dev, skb->data, skb_headlen(skb), + DMA_TO_DEVICE); + if (dma_mapping_error(dp->dev, dma_addr)) + goto err_dma_warn; + + wr_idx = D_IDX(tx_ring, tx_ring->wr_p); + + /* Stash the soft descriptor of the head then initialize it */ + txbuf = &tx_ring->txbufs[wr_idx]; + txbuf->skb = skb; + txbuf->dma_addr = dma_addr; + txbuf->fidx = -1; + txbuf->pkt_cnt = 1; + txbuf->real_len = real_len; + + /* Build TX descriptor */ + txd = &tx_ring->txds[wr_idx]; + txd->offset_eop = meta_len | PCIE_DESC_TX_EOP; + txd->dma_len = cpu_to_le16(skb_headlen(skb)); + nfp_desc_set_dma_addr(txd, dma_addr); + txd->data_len = cpu_to_le16(skb->len); + + txd->flags = 0; + txd->mss = 0; + txd->lso_hdrlen = 0; + + tx_ring->wr_p++; + tx_ring->wr_ptr_add++; + nfp_net_tx_xmit_more_flush(tx_ring); + + return false; + +err_dma_warn: + nn_dp_warn(dp, "Failed to DMA map TX CTRL buffer\n"); +err_free: + u64_stats_update_begin(&r_vec->tx_sync); + r_vec->tx_errors++; + u64_stats_update_end(&r_vec->tx_sync); + dev_kfree_skb_any(skb); + return false; +} + +bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb) +{ + struct nfp_net_r_vector *r_vec = &nn->r_vecs[0]; + bool ret; + + spin_lock_bh(&r_vec->lock); + ret = nfp_ctrl_tx_one(nn, r_vec, skb, false); + spin_unlock_bh(&r_vec->lock); + + return ret; +} + +static void __nfp_ctrl_tx_queued(struct nfp_net_r_vector *r_vec) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(&r_vec->queue))) + if (nfp_ctrl_tx_one(r_vec->nfp_net, r_vec, skb, true)) + return; +} + +static bool +nfp_ctrl_meta_ok(struct nfp_net *nn, void *data, unsigned int meta_len) +{ + u32 meta_type, meta_tag; + + if (!nfp_app_ctrl_has_meta(nn->app)) + return !meta_len; + + if (meta_len != 8) + return false; + + meta_type = get_unaligned_be32(data); + meta_tag = get_unaligned_be32(data + 4); + + return (meta_type == NFP_NET_META_PORTID && + meta_tag == NFP_META_PORT_ID_CTRL); +} + +static bool +nfp_ctrl_rx_one(struct nfp_net *nn, struct nfp_net_dp *dp, + struct nfp_net_r_vector *r_vec, struct nfp_net_rx_ring *rx_ring) +{ + unsigned int meta_len, data_len, meta_off, pkt_len, pkt_off; + struct nfp_net_rx_buf *rxbuf; + struct nfp_net_rx_desc *rxd; + dma_addr_t new_dma_addr; + struct sk_buff *skb; + void *new_frag; + int idx; + + idx = D_IDX(rx_ring, rx_ring->rd_p); + + rxd = &rx_ring->rxds[idx]; + if (!(rxd->rxd.meta_len_dd & PCIE_DESC_RX_DD)) + return false; + + /* Memory barrier to ensure that we won't do other reads + * before the DD bit. + */ + dma_rmb(); + + rx_ring->rd_p++; + + rxbuf = &rx_ring->rxbufs[idx]; + meta_len = rxd->rxd.meta_len_dd & PCIE_DESC_RX_META_LEN_MASK; + data_len = le16_to_cpu(rxd->rxd.data_len); + pkt_len = data_len - meta_len; + + pkt_off = NFP_NET_RX_BUF_HEADROOM + dp->rx_dma_off; + if (dp->rx_offset == NFP_NET_CFG_RX_OFFSET_DYNAMIC) + pkt_off += meta_len; + else + pkt_off += dp->rx_offset; + meta_off = pkt_off - meta_len; + + /* Stats update */ + u64_stats_update_begin(&r_vec->rx_sync); + r_vec->rx_pkts++; + r_vec->rx_bytes += pkt_len; + u64_stats_update_end(&r_vec->rx_sync); + + nfp_net_dma_sync_cpu_rx(dp, rxbuf->dma_addr + meta_off, data_len); + + if (unlikely(!nfp_ctrl_meta_ok(nn, rxbuf->frag + meta_off, meta_len))) { + nn_dp_warn(dp, "incorrect metadata for ctrl packet (%d)\n", + meta_len); + nfp_net_rx_drop(dp, r_vec, rx_ring, rxbuf, NULL); + return true; + } + + skb = build_skb(rxbuf->frag, dp->fl_bufsz); + if (unlikely(!skb)) { + nfp_net_rx_drop(dp, r_vec, rx_ring, rxbuf, NULL); + return true; + } + new_frag = nfp_net_napi_alloc_one(dp, &new_dma_addr); + if (unlikely(!new_frag)) { + nfp_net_rx_drop(dp, r_vec, rx_ring, rxbuf, skb); + return true; + } + + nfp_net_dma_unmap_rx(dp, rxbuf->dma_addr); + + nfp_net_rx_give_one(dp, rx_ring, new_frag, new_dma_addr); + + skb_reserve(skb, pkt_off); + skb_put(skb, pkt_len); + + dev_kfree_skb_any(skb); + + return true; +} + +static void nfp_ctrl_rx(struct nfp_net_r_vector *r_vec) +{ + struct nfp_net_rx_ring *rx_ring = r_vec->rx_ring; + struct nfp_net *nn = r_vec->nfp_net; + struct nfp_net_dp *dp = &nn->dp; + + while (nfp_ctrl_rx_one(nn, dp, r_vec, rx_ring)) + continue; +} + +static void nfp_ctrl_poll(unsigned long arg) +{ + struct nfp_net_r_vector *r_vec = (void *)arg; + + spin_lock_bh(&r_vec->lock); + nfp_net_tx_complete(r_vec->tx_ring); + __nfp_ctrl_tx_queued(r_vec); + spin_unlock_bh(&r_vec->lock); + + nfp_ctrl_rx(r_vec); + + nfp_net_irq_unmask(r_vec->nfp_net, r_vec->irq_entry); +} + /* Setup and Configuration */ @@ -1764,10 +2001,21 @@ static void nfp_net_vecs_init(struct nfp_net *nn) r_vec = &nn->r_vecs[r]; r_vec->nfp_net = nn; - r_vec->handler = nfp_net_irq_rxtx; r_vec->irq_entry = entry->entry; r_vec->irq_vector = entry->vector; + if (nn->dp.netdev) { + r_vec->handler = nfp_net_irq_rxtx; + } else { + r_vec->handler = nfp_ctrl_irq_rxtx; + + __skb_queue_head_init(&r_vec->queue); + spin_lock_init(&r_vec->lock); + tasklet_init(&r_vec->tasklet, nfp_ctrl_poll, + (unsigned long)r_vec); + tasklet_disable(&r_vec->tasklet); + } + cpumask_set_cpu(r, &r_vec->affinity_mask); } } @@ -2034,15 +2282,22 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, int err; /* Setup NAPI */ - netif_napi_add(nn->dp.netdev, &r_vec->napi, - nfp_net_poll, NAPI_POLL_WEIGHT); + if (nn->dp.netdev) + netif_napi_add(nn->dp.netdev, &r_vec->napi, + nfp_net_poll, NAPI_POLL_WEIGHT); + else + tasklet_enable(&r_vec->tasklet); snprintf(r_vec->name, sizeof(r_vec->name), - "%s-rxtx-%d", nn->dp.netdev->name, idx); + "%s-rxtx-%d", nfp_net_name(nn), idx); err = request_irq(r_vec->irq_vector, r_vec->handler, 0, r_vec->name, r_vec); if (err) { - netif_napi_del(&r_vec->napi); + if (nn->dp.netdev) + netif_napi_del(&r_vec->napi); + else + tasklet_disable(&r_vec->tasklet); + nn_err(nn, "Error requesting IRQ %d\n", r_vec->irq_vector); return err; } @@ -2060,7 +2315,11 @@ static void nfp_net_cleanup_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec) { irq_set_affinity_hint(r_vec->irq_vector, NULL); - netif_napi_del(&r_vec->napi); + if (nn->dp.netdev) + netif_napi_del(&r_vec->napi); + else + tasklet_disable(&r_vec->tasklet); + free_irq(r_vec->irq_vector, r_vec); } @@ -2338,6 +2597,24 @@ static int nfp_net_netdev_close(struct net_device *netdev) return 0; } +void nfp_ctrl_close(struct nfp_net *nn) +{ + int r; + + rtnl_lock(); + + for (r = 0; r < nn->dp.num_r_vecs; r++) { + disable_irq(nn->r_vecs[r].irq_vector); + tasklet_disable(&nn->r_vecs[r].tasklet); + } + + nfp_net_clear_config_and_disable(nn); + + nfp_net_close_free_all(nn); + + rtnl_unlock(); +} + /** * nfp_net_open_stack() - Start the device from stack's perspective * @nn: NFP Net device to reconfigure @@ -2453,6 +2730,35 @@ err_free_all: return err; } +int nfp_ctrl_open(struct nfp_net *nn) +{ + int err, r; + + /* ring dumping depends on vNICs being opened/closed under rtnl */ + rtnl_lock(); + + err = nfp_net_open_alloc_all(nn); + if (err) + goto err_unlock; + + err = nfp_net_set_config_and_enable(nn); + if (err) + goto err_free_all; + + for (r = 0; r < nn->dp.num_r_vecs; r++) + enable_irq(nn->r_vecs[r].irq_vector); + + rtnl_unlock(); + + return 0; + +err_free_all: + nfp_net_close_free_all(nn); +err_unlock: + rtnl_unlock(); + return err; +} + static void nfp_net_set_rx_mode(struct net_device *netdev) { struct nfp_net *nn = netdev_priv(netdev); @@ -3278,6 +3584,7 @@ int nfp_net_init(struct nfp_net *nn) /* Chained metadata is signalled by capabilities except in version 4 */ nn->dp.chained_metadata_format = nn->fw_ver.major == 4 || + !nn->dp.netdev || nn->cap & NFP_NET_CFG_CTRL_CHAIN_META; if (nn->dp.chained_metadata_format && nn->fw_ver.major != 4) nn->cap &= ~NFP_NET_CFG_CTRL_RSS; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index c8208bf370e0..48a8bf97645e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -71,8 +71,11 @@ #define NFP_NET_META_FIELD_SIZE 4 #define NFP_NET_META_HASH 1 /* next field carries hash type */ #define NFP_NET_META_MARK 2 +#define NFP_NET_META_PORTID 5 #define NFP_NET_META_CSUM 6 /* checksum complete type */ +#define NFP_META_PORT_ID_CTRL ~0U + /** * Hash type pre-pended when a RSS hash was computed */ -- cgit v1.2.3 From c24ca95ff648dd6477d488bb41b9282b67bd22e9 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:51 -0700 Subject: nfp: make vNIC ctrl memory mapping function reusable We will soon need to map control vNIC PCI memory as well as data vNIC memory. Make the function for mapping areas pointed to by an RTsym reusable. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 55 ++++++++++++----------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index dd2a99fca716..3644b12d93db 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -248,40 +248,37 @@ nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar, return max_qc - min_qc; } -static u8 __iomem *nfp_net_pf_map_ctrl_bar(struct nfp_pf *pf) +static u8 __iomem * +nfp_net_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt, + unsigned int min_size, struct nfp_cpp_area **area) { - const struct nfp_rtsym *ctrl_sym; - u8 __iomem *ctrl_bar; + const struct nfp_rtsym *sym; char pf_symbol[256]; + u8 __iomem *mem; - snprintf(pf_symbol, sizeof(pf_symbol), "_pf%u_net_bar0", + snprintf(pf_symbol, sizeof(pf_symbol), sym_fmt, nfp_cppcore_pcie_unit(pf->cpp)); - ctrl_sym = nfp_rtsym_lookup(pf->cpp, pf_symbol); - if (!ctrl_sym) { - dev_err(&pf->pdev->dev, - "Failed to find PF BAR0 symbol %s\n", pf_symbol); - return NULL; + sym = nfp_rtsym_lookup(pf->cpp, pf_symbol); + if (!sym) { + nfp_err(pf->cpp, "Failed to find PF symbol %s\n", pf_symbol); + return (u8 __iomem *)ERR_PTR(-ENOENT); } - if (ctrl_sym->size < pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE) { - dev_err(&pf->pdev->dev, - "PF BAR0 too small to contain %d vNICs\n", - pf->max_data_vnics); - return NULL; + if (sym->size < min_size) { + nfp_err(pf->cpp, "PF symbol %s too small\n", pf_symbol); + return (u8 __iomem *)ERR_PTR(-EINVAL); } - ctrl_bar = nfp_net_map_area(pf->cpp, "net.ctrl", - ctrl_sym->domain, ctrl_sym->target, - ctrl_sym->addr, ctrl_sym->size, - &pf->data_vnic_bar); - if (IS_ERR(ctrl_bar)) { - dev_err(&pf->pdev->dev, "Failed to map PF BAR0: %ld\n", - PTR_ERR(ctrl_bar)); - return NULL; + mem = nfp_net_map_area(pf->cpp, name, sym->domain, sym->target, + sym->addr, sym->size, area); + if (IS_ERR(mem)) { + nfp_err(pf->cpp, "Failed to map PF symbol %s: %ld\n", + pf_symbol, PTR_ERR(mem)); + return mem; } - return ctrl_bar; + return mem; } static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn) @@ -662,10 +659,10 @@ int nfp_net_refresh_eth_port(struct nfp_port *port) */ int nfp_net_pci_probe(struct nfp_pf *pf) { + u32 ctrl_bar_sz, tx_area_sz, rx_area_sz; u8 __iomem *ctrl_bar, *tx_bar, *rx_bar; u32 total_tx_qcs, total_rx_qcs; struct nfp_net_fw_version fw_ver; - u32 tx_area_sz, rx_area_sz; u32 start_q; int stride; int err; @@ -685,9 +682,13 @@ int nfp_net_pci_probe(struct nfp_pf *pf) goto err_unlock; } - ctrl_bar = nfp_net_pf_map_ctrl_bar(pf); - if (!ctrl_bar) { - err = pf->fw_loaded ? -EINVAL : -EPROBE_DEFER; + ctrl_bar_sz = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE; + ctrl_bar = nfp_net_pf_map_rtsym(pf, "net.ctrl", "_pf%d_net_bar0", + ctrl_bar_sz, &pf->data_vnic_bar); + if (IS_ERR(ctrl_bar)) { + err = PTR_ERR(ctrl_bar); + if (!pf->fw_loaded && err == -ENOENT) + err = -EPROBE_DEFER; goto err_unlock; } -- cgit v1.2.3 From 73e253f0e5d7557650159ecfac5b2653b6d02cf0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:52 -0700 Subject: nfp: map all queue controllers at once RX and TX queue controllers are interleaved. Instead of creating two mappings which map the same area at slightly different offset, create only one mapping. Always map all queue controllers to simplify the code and allow reusing the mapping for non-data vNICs. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.h | 6 +- drivers/net/ethernet/netronome/nfp/nfp_net.h | 1 + drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 122 +++++----------------- 3 files changed, 28 insertions(+), 101 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index c46d00bbf19d..66b1e1490805 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -63,8 +63,7 @@ struct nfp_nsp_identify; * @cpp: Pointer to the CPP handle * @app: Pointer to the APP handle * @data_vnic_bar: Pointer to the CPP area for the data vNICs' BARs - * @tx_area: Pointer to the CPP area for the TX queues - * @rx_area: Pointer to the CPP area for the FL/RX queues + * @qc_area: Pointer to the CPP area for the queues * @irq_entries: Array of MSI-X entries for all vNICs * @limit_vfs: Number of VFs supported by firmware (~0 for PCI limit) * @num_vfs: Number of SR-IOV VFs enabled @@ -88,8 +87,7 @@ struct nfp_pf { struct nfp_app *app; struct nfp_cpp_area *data_vnic_bar; - struct nfp_cpp_area *tx_area; - struct nfp_cpp_area *rx_area; + struct nfp_cpp_area *qc_area; struct msix_entry *irq_entries; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index eb849d26f4dd..02fd8d4e253c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -705,6 +705,7 @@ static inline void nn_pci_flush(struct nfp_net *nn) * either add to a pointer or to read the pointer value. */ #define NFP_QCP_QUEUE_ADDR_SZ 0x800 +#define NFP_QCP_QUEUE_AREA_SZ 0x80000 #define NFP_QCP_QUEUE_OFF(_x) ((_x) * NFP_QCP_QUEUE_ADDR_SZ) #define NFP_QCP_QUEUE_ADD_RPTR 0x0000 #define NFP_QCP_QUEUE_ADD_WPTR 0x0004 diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 3644b12d93db..2a3b6deae607 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -223,31 +223,6 @@ static int nfp_net_pf_get_app_id(struct nfp_pf *pf) NFP_APP_CORE_NIC); } -static unsigned int -nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar, - unsigned int stride, u32 start_off, u32 num_off) -{ - unsigned int i, min_qc, max_qc; - - min_qc = readl(ctrl_bar + start_off); - max_qc = min_qc; - - for (i = 0; i < pf->max_data_vnics; i++) { - /* To make our lives simpler only accept configuration where - * queues are allocated to PFs in order (queues of PFn all have - * indexes lower than PFn+1). - */ - if (max_qc > readl(ctrl_bar + start_off)) - return 0; - - max_qc = readl(ctrl_bar + start_off); - max_qc += readl(ctrl_bar + num_off) * stride; - ctrl_bar += NFP_PF_CSR_SLICE_SIZE; - } - - return max_qc - min_qc; -} - static u8 __iomem * nfp_net_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt, unsigned int min_size, struct nfp_cpp_area **area) @@ -301,15 +276,16 @@ static void nfp_net_pf_free_vnics(struct nfp_pf *pf) static struct nfp_net * nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev, - void __iomem *ctrl_bar, - void __iomem *tx_bar, void __iomem *rx_bar, + void __iomem *ctrl_bar, void __iomem *qc_bar, int stride, struct nfp_net_fw_version *fw_ver, unsigned int eth_id) { - u32 n_tx_rings, n_rx_rings; + u32 tx_base, rx_base, n_tx_rings, n_rx_rings; struct nfp_net *nn; int err; + tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); + rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); n_tx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_TXRINGS); n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS); @@ -321,8 +297,8 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev, nn->app = pf->app; nn->fw_ver = *fw_ver; nn->dp.ctrl_bar = ctrl_bar; - nn->tx_bar = tx_bar; - nn->rx_bar = rx_bar; + nn->tx_bar = qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ; + nn->rx_bar = qc_bar + rx_base * NFP_QCP_QUEUE_ADDR_SZ; nn->dp.is_vf = 0; nn->stride_rx = stride; nn->stride_tx = stride; @@ -374,26 +350,15 @@ err_dfs_clean: static int nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, - void __iomem *tx_bar, void __iomem *rx_bar, - int stride, struct nfp_net_fw_version *fw_ver) + void __iomem *qc_bar, int stride, + struct nfp_net_fw_version *fw_ver) { - u32 prev_tx_base, prev_rx_base, tgt_tx_base, tgt_rx_base; struct nfp_net *nn; unsigned int i; int err; - prev_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); - prev_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); - for (i = 0; i < pf->max_data_vnics; i++) { - tgt_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); - tgt_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); - tx_bar += (tgt_tx_base - prev_tx_base) * NFP_QCP_QUEUE_ADDR_SZ; - rx_bar += (tgt_rx_base - prev_rx_base) * NFP_QCP_QUEUE_ADDR_SZ; - prev_tx_base = tgt_tx_base; - prev_rx_base = tgt_rx_base; - - nn = nfp_net_pf_alloc_vnic(pf, true, ctrl_bar, tx_bar, rx_bar, + nn = nfp_net_pf_alloc_vnic(pf, true, ctrl_bar, qc_bar, stride, fw_ver, i); if (IS_ERR(nn)) { err = PTR_ERR(nn); @@ -430,8 +395,7 @@ static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn) static int nfp_net_pf_spawn_vnics(struct nfp_pf *pf, - void __iomem *ctrl_bar, void __iomem *tx_bar, - void __iomem *rx_bar, int stride, + void __iomem *ctrl_bar, void __iomem *qc_bar, int stride, struct nfp_net_fw_version *fw_ver) { unsigned int id, wanted_irqs, num_irqs, vnics_left, irqs_left; @@ -439,8 +403,7 @@ nfp_net_pf_spawn_vnics(struct nfp_pf *pf, int err; /* Allocate the vnics and do basic init */ - err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, tx_bar, rx_bar, - stride, fw_ver); + err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, qc_bar, stride, fw_ver); if (err) return err; @@ -534,8 +497,7 @@ static void nfp_net_pci_remove_finish(struct nfp_pf *pf) nfp_net_pf_app_clean(pf); - nfp_cpp_area_release_free(pf->rx_area); - nfp_cpp_area_release_free(pf->tx_area); + nfp_cpp_area_release_free(pf->qc_area); nfp_cpp_area_release_free(pf->data_vnic_bar); } @@ -659,11 +621,9 @@ int nfp_net_refresh_eth_port(struct nfp_port *port) */ int nfp_net_pci_probe(struct nfp_pf *pf) { - u32 ctrl_bar_sz, tx_area_sz, rx_area_sz; - u8 __iomem *ctrl_bar, *tx_bar, *rx_bar; - u32 total_tx_qcs, total_rx_qcs; struct nfp_net_fw_version fw_ver; - u32 start_q; + u8 __iomem *ctrl_bar, *qc_bar; + u32 ctrl_bar_sz; int stride; int err; @@ -718,53 +678,23 @@ int nfp_net_pci_probe(struct nfp_pf *pf) } } - /* Find how many QC structs need to be mapped */ - total_tx_qcs = nfp_net_pf_total_qcs(pf, ctrl_bar, stride, - NFP_NET_CFG_START_TXQ, - NFP_NET_CFG_MAX_TXRINGS); - total_rx_qcs = nfp_net_pf_total_qcs(pf, ctrl_bar, stride, - NFP_NET_CFG_START_RXQ, - NFP_NET_CFG_MAX_RXRINGS); - if (!total_tx_qcs || !total_rx_qcs) { - nfp_err(pf->cpp, "Invalid PF QC configuration [%d,%d]\n", - total_tx_qcs, total_rx_qcs); - err = -EINVAL; - goto err_ctrl_unmap; - } - - tx_area_sz = NFP_QCP_QUEUE_ADDR_SZ * total_tx_qcs; - rx_area_sz = NFP_QCP_QUEUE_ADDR_SZ * total_rx_qcs; - - /* Map TX queues */ - start_q = readl(ctrl_bar + NFP_NET_CFG_START_TXQ); - tx_bar = nfp_net_map_area(pf->cpp, "net.tx", 0, 0, - NFP_PCIE_QUEUE(start_q), - tx_area_sz, &pf->tx_area); - if (IS_ERR(tx_bar)) { - nfp_err(pf->cpp, "Failed to map TX area.\n"); - err = PTR_ERR(tx_bar); + /* Map queues */ + qc_bar = nfp_net_map_area(pf->cpp, "net.qc", 0, 0, + NFP_PCIE_QUEUE(0), NFP_QCP_QUEUE_AREA_SZ, + &pf->qc_area); + if (IS_ERR(qc_bar)) { + nfp_err(pf->cpp, "Failed to map Queue Controller area.\n"); + err = PTR_ERR(qc_bar); goto err_ctrl_unmap; } - /* Map RX queues */ - start_q = readl(ctrl_bar + NFP_NET_CFG_START_RXQ); - rx_bar = nfp_net_map_area(pf->cpp, "net.rx", 0, 0, - NFP_PCIE_QUEUE(start_q), - rx_area_sz, &pf->rx_area); - if (IS_ERR(rx_bar)) { - nfp_err(pf->cpp, "Failed to map RX area.\n"); - err = PTR_ERR(rx_bar); - goto err_unmap_tx; - } - err = nfp_net_pf_app_init(pf); if (err) - goto err_unmap_rx; + goto err_unmap_qc; pf->ddir = nfp_net_debugfs_device_add(pf->pdev); - err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, tx_bar, rx_bar, - stride, &fw_ver); + err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, qc_bar, stride, &fw_ver); if (err) goto err_clean_ddir; @@ -775,10 +705,8 @@ int nfp_net_pci_probe(struct nfp_pf *pf) err_clean_ddir: nfp_net_debugfs_dir_clean(&pf->ddir); nfp_net_pf_app_clean(pf); -err_unmap_rx: - nfp_cpp_area_release_free(pf->rx_area); -err_unmap_tx: - nfp_cpp_area_release_free(pf->tx_area); +err_unmap_qc: + nfp_cpp_area_release_free(pf->qc_area); err_ctrl_unmap: nfp_cpp_area_release_free(pf->data_vnic_bar); err_unlock: -- cgit v1.2.3 From 21537bc7019a4dfd5c6f615a235e0b171ef3dda8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:53 -0700 Subject: nfp: don't clutter init code passing fw_ver around Reading fw version from the BAR is trivial. Don't pass it around through layers of init functions, simply read it again where needed. This commit has the side effect of each vNIC having the exact NFD version from its own control memory, rather than all data vNICs assuming the version of the first one. This should not result in user-visible changes, though. Capabilities of data vNICs of trival apps are identical. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 2a3b6deae607..82172665e023 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -277,8 +277,7 @@ static void nfp_net_pf_free_vnics(struct nfp_pf *pf) static struct nfp_net * nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev, void __iomem *ctrl_bar, void __iomem *qc_bar, - int stride, struct nfp_net_fw_version *fw_ver, - unsigned int eth_id) + int stride, unsigned int eth_id) { u32 tx_base, rx_base, n_tx_rings, n_rx_rings; struct nfp_net *nn; @@ -295,7 +294,7 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev, return nn; nn->app = pf->app; - nn->fw_ver = *fw_ver; + nfp_net_get_fw_version(&nn->fw_ver, ctrl_bar); nn->dp.ctrl_bar = ctrl_bar; nn->tx_bar = qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ; nn->rx_bar = qc_bar + rx_base * NFP_QCP_QUEUE_ADDR_SZ; @@ -350,8 +349,7 @@ err_dfs_clean: static int nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, - void __iomem *qc_bar, int stride, - struct nfp_net_fw_version *fw_ver) + void __iomem *qc_bar, int stride) { struct nfp_net *nn; unsigned int i; @@ -359,7 +357,7 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar, for (i = 0; i < pf->max_data_vnics; i++) { nn = nfp_net_pf_alloc_vnic(pf, true, ctrl_bar, qc_bar, - stride, fw_ver, i); + stride, i); if (IS_ERR(nn)) { err = PTR_ERR(nn); goto err_free_prev; @@ -395,15 +393,14 @@ static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn) static int nfp_net_pf_spawn_vnics(struct nfp_pf *pf, - void __iomem *ctrl_bar, void __iomem *qc_bar, int stride, - struct nfp_net_fw_version *fw_ver) + void __iomem *ctrl_bar, void __iomem *qc_bar, int stride) { unsigned int id, wanted_irqs, num_irqs, vnics_left, irqs_left; struct nfp_net *nn; int err; /* Allocate the vnics and do basic init */ - err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, qc_bar, stride, fw_ver); + err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, qc_bar, stride); if (err) return err; @@ -694,7 +691,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf) pf->ddir = nfp_net_debugfs_device_add(pf->pdev); - err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, qc_bar, stride, &fw_ver); + err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, qc_bar, stride); if (err) goto err_clean_ddir; -- cgit v1.2.3 From 6d4b0d8ed6d2f9e1741b9abd0ce64c641f890d6c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:54 -0700 Subject: nfp: slice the netdev spawning function We want to be able to create a special vNIC for control messages. This vNIC should be created before any netdev is registered to allow nfp_app logic to exchange messages with the FW app before any netdev is visible to user space. Unfortunately we can't enable IRQs until we know how many vNICs we will need to spawn. Divide the function which spawns netdevs for vNICs into three parts: - vNIC/memory allocation; - IRQ allocation; - netdev init and register. This will help us insert the initialization of the control channel after IRQ allocation but before netdev init and register. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 62 ++++++++++++++--------- 1 file changed, 37 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 82172665e023..98a99b199674 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -391,18 +391,10 @@ static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn) nfp_app_vnic_clean(pf->app, nn); } -static int -nfp_net_pf_spawn_vnics(struct nfp_pf *pf, - void __iomem *ctrl_bar, void __iomem *qc_bar, int stride) +static int nfp_net_pf_alloc_irqs(struct nfp_pf *pf) { - unsigned int id, wanted_irqs, num_irqs, vnics_left, irqs_left; + unsigned int wanted_irqs, num_irqs, vnics_left, irqs_left; struct nfp_net *nn; - int err; - - /* Allocate the vnics and do basic init */ - err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, qc_bar, stride); - if (err) - return err; /* Get MSI-X vectors */ wanted_irqs = 0; @@ -410,18 +402,16 @@ nfp_net_pf_spawn_vnics(struct nfp_pf *pf, wanted_irqs += NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs; pf->irq_entries = kcalloc(wanted_irqs, sizeof(*pf->irq_entries), GFP_KERNEL); - if (!pf->irq_entries) { - err = -ENOMEM; - goto err_nn_free; - } + if (!pf->irq_entries) + return -ENOMEM; num_irqs = nfp_net_irqs_alloc(pf->pdev, pf->irq_entries, NFP_NET_MIN_VNIC_IRQS * pf->num_vnics, wanted_irqs); if (!num_irqs) { - nn_warn(nn, "Unable to allocate MSI-X Vectors. Exiting\n"); - err = -ENOMEM; - goto err_vec_free; + nfp_warn(pf->cpp, "Unable to allocate MSI-X vectors\n"); + kfree(pf->irq_entries); + return -ENOMEM; } /* Distribute IRQs to vNICs */ @@ -437,6 +427,21 @@ nfp_net_pf_spawn_vnics(struct nfp_pf *pf, vnics_left--; } + return 0; +} + +static void nfp_net_pf_free_irqs(struct nfp_pf *pf) +{ + nfp_net_irqs_disable(pf->pdev); + kfree(pf->irq_entries); +} + +static int nfp_net_pf_init_vnics(struct nfp_pf *pf) +{ + struct nfp_net *nn; + unsigned int id; + int err; + /* Finish vNIC init and register */ id = 0; list_for_each_entry(nn, &pf->vnics, vnic_list) { @@ -452,11 +457,6 @@ nfp_net_pf_spawn_vnics(struct nfp_pf *pf, err_prev_deinit: list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list) nfp_net_pf_clean_vnic(pf, nn); - nfp_net_irqs_disable(pf->pdev); -err_vec_free: - kfree(pf->irq_entries); -err_nn_free: - nfp_net_pf_free_vnics(pf); return err; } @@ -489,8 +489,7 @@ static void nfp_net_pci_remove_finish(struct nfp_pf *pf) { nfp_net_debugfs_dir_clean(&pf->ddir); - nfp_net_irqs_disable(pf->pdev); - kfree(pf->irq_entries); + nfp_net_pf_free_irqs(pf); nfp_net_pf_app_clean(pf); @@ -691,14 +690,27 @@ int nfp_net_pci_probe(struct nfp_pf *pf) pf->ddir = nfp_net_debugfs_device_add(pf->pdev); - err = nfp_net_pf_spawn_vnics(pf, ctrl_bar, qc_bar, stride); + /* Allocate the vnics and do basic init */ + err = nfp_net_pf_alloc_vnics(pf, ctrl_bar, qc_bar, stride); if (err) goto err_clean_ddir; + err = nfp_net_pf_alloc_irqs(pf); + if (err) + goto err_free_vnics; + + err = nfp_net_pf_init_vnics(pf); + if (err) + goto err_free_irqs; + mutex_unlock(&pf->lock); return 0; +err_free_irqs: + nfp_net_pf_free_irqs(pf); +err_free_vnics: + nfp_net_pf_free_vnics(pf); err_clean_ddir: nfp_net_debugfs_dir_clean(&pf->ddir); nfp_net_pf_app_clean(pf); -- cgit v1.2.3 From 2c7e41c0b2f103056f93dd5922c03d6e2021c76d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:55 -0700 Subject: nfp: allow non-equal distribution of IRQs Thus far the code assumed all vNICs will request similar number of IRQs. This will be no longer true with control vNICs (where 1 IRQ will suffice). Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 98a99b199674..362dca38223b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -420,7 +420,8 @@ static int nfp_net_pf_alloc_irqs(struct nfp_pf *pf) list_for_each_entry(nn, &pf->vnics, vnic_list) { unsigned int n; - n = DIV_ROUND_UP(irqs_left, vnics_left); + n = min(NFP_NET_NON_Q_VECTORS + nn->dp.num_r_vecs, + DIV_ROUND_UP(irqs_left, vnics_left)); nfp_net_irqs_assign(nn, &pf->irq_entries[num_irqs - irqs_left], n); irqs_left -= n; -- cgit v1.2.3 From 02082701b974eea3afdb4ac25ab613adabebe41a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:56 -0700 Subject: nfp: create control vNICs and wire up rx/tx When driver encounters an nfp_app which has a control message handler defined, allocate a control vNIC. This control channel will be used to exchange data with the application FW such as flow table programming, statistics and global datapath control. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_app.c | 18 +++ drivers/net/ethernet/netronome/nfp/nfp_app.h | 44 ++++++++ drivers/net/ethernet/netronome/nfp/nfp_main.h | 7 ++ .../net/ethernet/netronome/nfp/nfp_net_common.c | 2 +- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 121 ++++++++++++++++++--- 5 files changed, 177 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index cea2090cf063..de07517da1bd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -31,6 +31,7 @@ * SOFTWARE. */ +#include #include #include "nfpcore/nfp_cpp.h" @@ -42,6 +43,23 @@ static const struct nfp_app_type *apps[] = { &app_bpf, }; +struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size) +{ + struct sk_buff *skb; + + if (nfp_app_ctrl_has_meta(app)) + size += 8; + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) + return NULL; + + if (nfp_app_ctrl_has_meta(app)) + skb_reserve(skb, 8); + + return skb; +} + struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id) { struct nfp_app *app; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index f6091ad0a9a9..3fbf68f8577c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -37,6 +37,7 @@ struct bpf_prog; struct net_device; struct pci_dev; +struct sk_buff; struct tc_to_netdev; struct sk_buff; struct nfp_app; @@ -63,6 +64,9 @@ extern const struct nfp_app_type app_bpf; * @extra_cap: extra capabilities string * @vnic_init: init vNICs (assign port types, etc.) * @vnic_clean: clean up app's vNIC state + * @start: start application logic + * @stop: stop application logic + * @ctrl_msg_rx: control message handler * @setup_tc: setup TC ndo * @tc_busy: TC HW offload busy (rules loaded) * @xdp_offload: offload an XDP program @@ -81,6 +85,11 @@ struct nfp_app_type { unsigned int id); void (*vnic_clean)(struct nfp_app *app, struct nfp_net *nn); + int (*start)(struct nfp_app *app); + void (*stop)(struct nfp_app *app); + + void (*ctrl_msg_rx)(struct nfp_app *app, struct sk_buff *skb); + int (*setup_tc)(struct nfp_app *app, struct net_device *netdev, u32 handle, __be16 proto, struct tc_to_netdev *tc); bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn); @@ -93,6 +102,7 @@ struct nfp_app_type { * @pdev: backpointer to PCI device * @pf: backpointer to NFP PF structure * @cpp: pointer to the CPP handle + * @ctrl: pointer to ctrl vNIC struct * @type: pointer to const application ops and info */ struct nfp_app { @@ -100,6 +110,8 @@ struct nfp_app { struct nfp_pf *pf; struct nfp_cpp *cpp; + struct nfp_net *ctrl; + const struct nfp_app_type *type; }; @@ -124,6 +136,21 @@ static inline void nfp_app_vnic_clean(struct nfp_app *app, struct nfp_net *nn) app->type->vnic_clean(app, nn); } +static inline int nfp_app_start(struct nfp_app *app, struct nfp_net *ctrl) +{ + app->ctrl = ctrl; + if (!app->type->start) + return 0; + return app->type->start(app); +} + +static inline void nfp_app_stop(struct nfp_app *app) +{ + if (!app->type->stop) + return; + app->type->stop(app); +} + static inline const char *nfp_app_name(struct nfp_app *app) { if (!app) @@ -131,6 +158,11 @@ static inline const char *nfp_app_name(struct nfp_app *app) return app->type->name; } +static inline bool nfp_app_needs_ctrl_vnic(struct nfp_app *app) +{ + return app && app->type->ctrl_msg_rx; +} + static inline bool nfp_app_ctrl_has_meta(struct nfp_app *app) { return app->type->ctrl_has_meta; @@ -174,6 +206,18 @@ static inline int nfp_app_xdp_offload(struct nfp_app *app, struct nfp_net *nn, return app->type->xdp_offload(app, nn, prog); } +static inline bool nfp_app_ctrl_tx(struct nfp_app *app, struct sk_buff *skb) +{ + return nfp_ctrl_tx(app->ctrl, skb); +} + +static inline void nfp_app_ctrl_rx(struct nfp_app *app, struct sk_buff *skb) +{ + app->type->ctrl_msg_rx(app, skb); +} + +struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size); + struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id); void nfp_app_free(struct nfp_app *app); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 66b1e1490805..37832853b0b3 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -63,11 +63,13 @@ struct nfp_nsp_identify; * @cpp: Pointer to the CPP handle * @app: Pointer to the APP handle * @data_vnic_bar: Pointer to the CPP area for the data vNICs' BARs + * @ctrl_vnic_bar: Pointer to the CPP area for the ctrl vNIC's BAR * @qc_area: Pointer to the CPP area for the queues * @irq_entries: Array of MSI-X entries for all vNICs * @limit_vfs: Number of VFs supported by firmware (~0 for PCI limit) * @num_vfs: Number of SR-IOV VFs enabled * @fw_loaded: Is the firmware loaded? + * @ctrl_vnic: Pointer to the control vNIC if available * @eth_tbl: NSP ETH table * @nspi: NSP identification info * @hwmon_dev: pointer to hwmon device @@ -87,6 +89,7 @@ struct nfp_pf { struct nfp_app *app; struct nfp_cpp_area *data_vnic_bar; + struct nfp_cpp_area *ctrl_vnic_bar; struct nfp_cpp_area *qc_area; struct msix_entry *irq_entries; @@ -96,6 +99,8 @@ struct nfp_pf { bool fw_loaded; + struct nfp_net *ctrl_vnic; + struct nfp_eth_table *eth_tbl; struct nfp_nsp_identify *nspi; @@ -127,4 +132,6 @@ nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id); void nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id); +bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb); + #endif /* NFP_MAIN_H */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 59f1764242a0..4f0df63de626 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -1950,7 +1950,7 @@ nfp_ctrl_rx_one(struct nfp_net *nn, struct nfp_net_dp *dp, skb_reserve(skb, pkt_off); skb_put(skb, pkt_len); - dev_kfree_skb_any(skb); + nfp_app_ctrl_rx(nn->app, skb); return true; } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 362dca38223b..db12700b5afc 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -266,12 +266,11 @@ static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn) static void nfp_net_pf_free_vnics(struct nfp_pf *pf) { - struct nfp_net *nn; + struct nfp_net *nn, *next; - while (!list_empty(&pf->vnics)) { - nn = list_first_entry(&pf->vnics, struct nfp_net, vnic_list); - nfp_net_pf_free_vnic(pf, nn); - } + list_for_each_entry_safe(nn, next, &pf->vnics, vnic_list) + if (nfp_net_is_data_vnic(nn)) + nfp_net_pf_free_vnic(pf, nn); } static struct nfp_net * @@ -302,10 +301,12 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev, nn->stride_rx = stride; nn->stride_tx = stride; - err = nfp_app_vnic_init(pf->app, nn, eth_id); - if (err) { - nfp_net_free(nn); - return ERR_PTR(err); + if (needs_netdev) { + err = nfp_app_vnic_init(pf->app, nn, eth_id); + if (err) { + nfp_net_free(nn); + return ERR_PTR(err); + } } pf->num_vnics++; @@ -446,6 +447,8 @@ static int nfp_net_pf_init_vnics(struct nfp_pf *pf) /* Finish vNIC init and register */ id = 0; list_for_each_entry(nn, &pf->vnics, vnic_list) { + if (!nfp_net_is_data_vnic(nn)) + continue; err = nfp_net_pf_init_vnic(pf, nn, id); if (err) goto err_prev_deinit; @@ -457,12 +460,15 @@ static int nfp_net_pf_init_vnics(struct nfp_pf *pf) err_prev_deinit: list_for_each_entry_continue_reverse(nn, &pf->vnics, vnic_list) - nfp_net_pf_clean_vnic(pf, nn); + if (nfp_net_is_data_vnic(nn)) + nfp_net_pf_clean_vnic(pf, nn); return err; } -static int nfp_net_pf_app_init(struct nfp_pf *pf) +static int +nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride) { + u8 __iomem *ctrl_bar; int err; pf->app = nfp_app_alloc(pf, nfp_net_pf_get_app_id(pf)); @@ -473,8 +479,28 @@ static int nfp_net_pf_app_init(struct nfp_pf *pf) if (err) goto err_free; + if (!nfp_app_needs_ctrl_vnic(pf->app)) + return 0; + + ctrl_bar = nfp_net_pf_map_rtsym(pf, "net.ctrl", "_pf%u_net_ctrl_bar", + NFP_PF_CSR_SLICE_SIZE, + &pf->ctrl_vnic_bar); + if (IS_ERR(ctrl_bar)) { + err = PTR_ERR(ctrl_bar); + goto err_free; + } + + pf->ctrl_vnic = nfp_net_pf_alloc_vnic(pf, false, ctrl_bar, qc_bar, + stride, 0); + if (IS_ERR(pf->ctrl_vnic)) { + err = PTR_ERR(pf->ctrl_vnic); + goto err_unmap; + } + return 0; +err_unmap: + nfp_cpp_area_release_free(pf->ctrl_vnic_bar); err_free: nfp_app_free(pf->app); return err; @@ -482,12 +508,72 @@ err_free: static void nfp_net_pf_app_clean(struct nfp_pf *pf) { + if (pf->ctrl_vnic) { + nfp_net_pf_free_vnic(pf, pf->ctrl_vnic); + nfp_cpp_area_release_free(pf->ctrl_vnic_bar); + } nfp_app_free(pf->app); pf->app = NULL; } +static int nfp_net_pf_app_start_ctrl(struct nfp_pf *pf) +{ + int err; + + if (!pf->ctrl_vnic) + return 0; + err = nfp_net_pf_init_vnic(pf, pf->ctrl_vnic, 0); + if (err) + return err; + + err = nfp_ctrl_open(pf->ctrl_vnic); + if (err) + goto err_clean_ctrl; + + return 0; + +err_clean_ctrl: + nfp_net_pf_clean_vnic(pf, pf->ctrl_vnic); + return err; +} + +static void nfp_net_pf_app_stop_ctrl(struct nfp_pf *pf) +{ + if (!pf->ctrl_vnic) + return; + nfp_ctrl_close(pf->ctrl_vnic); + nfp_net_pf_clean_vnic(pf, pf->ctrl_vnic); +} + +static int nfp_net_pf_app_start(struct nfp_pf *pf) +{ + int err; + + err = nfp_net_pf_app_start_ctrl(pf); + if (err) + return err; + + err = nfp_app_start(pf->app, pf->ctrl_vnic); + if (err) + goto err_ctrl_stop; + + return 0; + +err_ctrl_stop: + nfp_net_pf_app_stop_ctrl(pf); + return err; +} + +static void nfp_net_pf_app_stop(struct nfp_pf *pf) +{ + nfp_app_stop(pf->app); + nfp_net_pf_app_stop_ctrl(pf); +} + static void nfp_net_pci_remove_finish(struct nfp_pf *pf) { + nfp_net_pf_app_stop(pf); + /* stop app first, to avoid double free of ctrl vNIC's ddir */ nfp_net_debugfs_dir_clean(&pf->ddir); nfp_net_pf_free_irqs(pf); @@ -685,7 +771,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf) goto err_ctrl_unmap; } - err = nfp_net_pf_app_init(pf); + err = nfp_net_pf_app_init(pf, qc_bar, stride); if (err) goto err_unmap_qc; @@ -700,14 +786,20 @@ int nfp_net_pci_probe(struct nfp_pf *pf) if (err) goto err_free_vnics; - err = nfp_net_pf_init_vnics(pf); + err = nfp_net_pf_app_start(pf); if (err) goto err_free_irqs; + err = nfp_net_pf_init_vnics(pf); + if (err) + goto err_stop_app; + mutex_unlock(&pf->lock); return 0; +err_stop_app: + nfp_net_pf_app_stop(pf); err_free_irqs: nfp_net_pf_free_irqs(pf); err_free_vnics: @@ -733,7 +825,8 @@ void nfp_net_pci_remove(struct nfp_pf *pf) goto out; list_for_each_entry(nn, &pf->vnics, vnic_list) - nfp_net_pf_clean_vnic(pf, nn); + if (nfp_net_is_data_vnic(nn)) + nfp_net_pf_clean_vnic(pf, nn); nfp_net_pf_free_vnics(pf); -- cgit v1.2.3 From f9380629fafcf05cb188cbce5e028f0e99f8f49d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2017 17:01:57 -0700 Subject: nfp: advertise support for NFD ABI 0.5 NFD ABI 0.5 is equivalent to NFD ABI 3.0 but requires that the driver checks the APP id symbol and makes sure it can support given app. Most advanced apps will likely require control vNIC (ability to exchange control messages between the driver and app FW). Detailed app version checking and capability exchange is left to app-specific code. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 2 +- drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index db12700b5afc..5f27703060c2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -749,7 +749,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf) nfp_warn(pf->cpp, "OBSOLETE Firmware detected - VF isolation not available\n"); } else { switch (fw_ver.major) { - case 1 ... 4: + case 1 ... 5: stride = 4; break; default: diff --git a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c index 0bf3b0febd07..c879626e035b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c @@ -161,7 +161,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev, dev_warn(&pdev->dev, "OBSOLETE Firmware detected - VF isolation not available\n"); } else { switch (fw_ver.major) { - case 1 ... 4: + case 1 ... 5: stride = 4; tx_bar_no = NFP_NET_Q0_BAR; rx_bar_no = tx_bar_no; -- cgit v1.2.3 From 1dec4cec9ff1cdc2b1b4b68417c04146df93f43d Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Wed, 7 Jun 2017 15:04:51 +0530 Subject: cxgb4: Fix tids count for ipv6 offload connection the adapter consumes two tids for every ipv6 offload connection be it active or passive, calculate tid usage count accordingly. Also change the signatures of relevant functions to get the address family. Signed-off-by: Rizwan Ansari Signed-off-by: Varun Prakash Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/cm.c | 14 +++++--- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 12 +++++-- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 38 +++++++++++++++------- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 24 ++++++++++---- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 8 +++-- drivers/target/iscsi/cxgbit/cxgbit_cm.c | 6 ++-- 6 files changed, 71 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 0910faf3587b..b0ae4f0c8aa7 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -398,7 +398,8 @@ void _c4iw_free_ep(struct kref *kref) (const u32 *)&sin6->sin6_addr.s6_addr, 1); } - cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid); + cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid, + ep->com.local_addr.ss_family); dst_release(ep->dst); cxgb4_l2t_release(ep->l2t); if (ep->mpa_skb) @@ -1199,7 +1200,7 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb) /* setup the hwtid for this connection */ ep->hwtid = tid; - cxgb4_insert_tid(t, ep, tid); + cxgb4_insert_tid(t, ep, tid, ep->com.local_addr.ss_family); insert_ep_tid(ep); ep->snd_seq = be32_to_cpu(req->snd_isn); @@ -2304,7 +2305,8 @@ fail: (const u32 *)&sin6->sin6_addr.s6_addr, 1); } if (status && act_open_has_tid(status)) - cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, GET_TID(rpl)); + cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, GET_TID(rpl), + ep->com.local_addr.ss_family); remove_handle(ep->com.dev, &ep->com.dev->atid_idr, atid); cxgb4_free_atid(t, atid); @@ -2581,7 +2583,8 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) child_ep->tx_chan, child_ep->smac_idx, child_ep->rss_qid); init_timer(&child_ep->timer); - cxgb4_insert_tid(t, child_ep, hwtid); + cxgb4_insert_tid(t, child_ep, hwtid, + child_ep->com.local_addr.ss_family); insert_ep_tid(child_ep); if (accept_cr(child_ep, skb, req)) { c4iw_put_ep(&parent_ep->com); @@ -2849,7 +2852,8 @@ out: 1); } remove_handle(ep->com.dev, &ep->com.dev->hwtid_idr, ep->hwtid); - cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid); + cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid, + ep->com.local_addr.ss_family); dst_release(ep->dst); cxgb4_l2t_release(ep->l2t); c4iw_reconnect(ep); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 1fa34b009891..00044d750139 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2669,6 +2669,8 @@ static int tid_info_show(struct seq_file *seq, void *v) if (t4_read_reg(adap, LE_DB_CONFIG_A) & HASHEN_F) { unsigned int sb; + seq_printf(seq, "Connections in use: %u\n", + atomic_read(&t->conns_in_use)); if (chip <= CHELSIO_T5) sb = t4_read_reg(adap, LE_DB_SERVER_INDEX_A) / 4; @@ -2699,17 +2701,23 @@ static int tid_info_show(struct seq_file *seq, void *v) atomic_read(&t->hash_tids_in_use)); } } else if (t->ntids) { + seq_printf(seq, "Connections in use: %u\n", + atomic_read(&t->conns_in_use)); + seq_printf(seq, "TID range: 0..%u", t->ntids - 1); seq_printf(seq, ", in use: %u\n", atomic_read(&t->tids_in_use)); } if (t->nstids) - seq_printf(seq, "STID range: %u..%u, in use: %u\n", + seq_printf(seq, "STID range: %u..%u, in use-IPv4/IPv6: %u/%u\n", (!t->stid_base && (chip <= CHELSIO_T5)) ? t->stid_base + 1 : t->stid_base, - t->stid_base + t->nstids - 1, t->stids_in_use); + t->stid_base + t->nstids - 1, + t->stids_in_use - t->v6_stids_in_use, + t->v6_stids_in_use); + if (t->natids) seq_printf(seq, "ATID range: 0..%u, in use: %u\n", t->natids - 1, t->atids_in_use); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 6c463703e072..91685bf21878 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1093,10 +1093,12 @@ int cxgb4_alloc_stid(struct tid_info *t, int family, void *data) * This is equivalent to 4 TIDs. With CLIP enabled it * needs 2 TIDs. */ - if (family == PF_INET) - t->stids_in_use++; - else + if (family == PF_INET6) { t->stids_in_use += 2; + t->v6_stids_in_use += 2; + } else { + t->stids_in_use++; + } } spin_unlock_bh(&t->stid_lock); return stid; @@ -1150,13 +1152,16 @@ void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family) bitmap_release_region(t->stid_bmap, stid, 1); t->stid_tab[stid].data = NULL; if (stid < t->nstids) { - if (family == PF_INET) - t->stids_in_use--; - else + if (family == PF_INET6) { t->stids_in_use -= 2; + t->v6_stids_in_use -= 2; + } else { + t->stids_in_use--; + } } else { t->sftids_in_use--; } + spin_unlock_bh(&t->stid_lock); } EXPORT_SYMBOL(cxgb4_free_stid); @@ -1232,7 +1237,8 @@ static void process_tid_release_list(struct work_struct *work) * Release a TID and inform HW. If we are unable to allocate the release * message we defer to a work queue. */ -void cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid) +void cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid, + unsigned short family) { struct sk_buff *skb; struct adapter *adap = container_of(t, struct adapter, tids); @@ -1241,10 +1247,18 @@ void cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid) if (t->tid_tab[tid]) { t->tid_tab[tid] = NULL; - if (t->hash_base && (tid >= t->hash_base)) - atomic_dec(&t->hash_tids_in_use); - else - atomic_dec(&t->tids_in_use); + atomic_dec(&t->conns_in_use); + if (t->hash_base && (tid >= t->hash_base)) { + if (family == AF_INET6) + atomic_sub(2, &t->hash_tids_in_use); + else + atomic_dec(&t->hash_tids_in_use); + } else { + if (family == AF_INET6) + atomic_sub(2, &t->tids_in_use); + else + atomic_dec(&t->tids_in_use); + } } skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); @@ -1292,10 +1306,12 @@ static int tid_init(struct tid_info *t) spin_lock_init(&t->ftid_lock); t->stids_in_use = 0; + t->v6_stids_in_use = 0; t->sftids_in_use = 0; t->afree = NULL; t->atids_in_use = 0; atomic_set(&t->tids_in_use, 0); + atomic_set(&t->conns_in_use, 0); atomic_set(&t->hash_tids_in_use, 0); /* Setup the free list for atid_tab and clear the stid bitmap. */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 6e74040af49a..ce0d9fbf0648 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -123,12 +123,14 @@ struct tid_info { spinlock_t stid_lock; unsigned int stids_in_use; + unsigned int v6_stids_in_use; unsigned int sftids_in_use; /* TIDs in the TCAM */ atomic_t tids_in_use; /* TIDs in the HASH */ atomic_t hash_tids_in_use; + atomic_t conns_in_use; /* lock for setting/clearing filter bitmap */ spinlock_t ftid_lock; }; @@ -157,13 +159,21 @@ static inline void *lookup_stid(const struct tid_info *t, unsigned int stid) } static inline void cxgb4_insert_tid(struct tid_info *t, void *data, - unsigned int tid) + unsigned int tid, unsigned short family) { t->tid_tab[tid] = data; - if (t->hash_base && (tid >= t->hash_base)) - atomic_inc(&t->hash_tids_in_use); - else - atomic_inc(&t->tids_in_use); + if (t->hash_base && (tid >= t->hash_base)) { + if (family == AF_INET6) + atomic_add(2, &t->hash_tids_in_use); + else + atomic_inc(&t->hash_tids_in_use); + } else { + if (family == AF_INET6) + atomic_add(2, &t->tids_in_use); + else + atomic_inc(&t->tids_in_use); + } + atomic_inc(&t->conns_in_use); } int cxgb4_alloc_atid(struct tid_info *t, void *data); @@ -171,8 +181,8 @@ int cxgb4_alloc_stid(struct tid_info *t, int family, void *data); int cxgb4_alloc_sftid(struct tid_info *t, int family, void *data); void cxgb4_free_atid(struct tid_info *t, unsigned int atid); void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family); -void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid); - +void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid, + unsigned short family); struct in6_addr; int cxgb4_create_server(const struct net_device *dev, unsigned int stid, diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 1076c1578322..9a92b5150218 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -806,7 +806,7 @@ static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) cxgbi_sock_get(csk); csk->tid = tid; - cxgb4_insert_tid(lldi->tids, csk, tid); + cxgb4_insert_tid(lldi->tids, csk, tid, csk->csk_family); cxgbi_sock_set_flag(csk, CTPF_HAS_TID); free_atid(csk); @@ -956,7 +956,8 @@ static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) if (status && status != CPL_ERR_TCAM_FULL && status != CPL_ERR_CONN_EXIST && status != CPL_ERR_ARP_MISS) - cxgb4_remove_tid(lldi->tids, csk->port_id, GET_TID(rpl)); + cxgb4_remove_tid(lldi->tids, csk->port_id, GET_TID(rpl), + csk->csk_family); cxgbi_sock_get(csk); spin_lock_bh(&csk->lock); @@ -1590,7 +1591,8 @@ static void release_offload_resources(struct cxgbi_sock *csk) free_atid(csk); else if (cxgbi_sock_flag(csk, CTPF_HAS_TID)) { lldi = cxgbi_cdev_priv(csk->cdev); - cxgb4_remove_tid(lldi->tids, 0, csk->tid); + cxgb4_remove_tid(lldi->tids, 0, csk->tid, + csk->csk_family); cxgbi_sock_clear_flag(csk, CTPF_HAS_TID); cxgbi_sock_put(csk); } diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c index 37a05185dcbe..939c6ec51e4d 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c @@ -752,7 +752,8 @@ void _cxgbit_free_csk(struct kref *kref) &sin6->sin6_addr.s6_addr, 1); } - cxgb4_remove_tid(csk->com.cdev->lldi.tids, 0, csk->tid); + cxgb4_remove_tid(csk->com.cdev->lldi.tids, 0, csk->tid, + csk->com.local_addr.ss_family); dst_release(csk->dst); cxgb4_l2t_release(csk->l2t); @@ -1313,8 +1314,7 @@ cxgbit_pass_accept_req(struct cxgbit_device *cdev, struct sk_buff *skb) spin_lock(&cdev->cskq.lock); list_add_tail(&csk->list, &cdev->cskq.list); spin_unlock(&cdev->cskq.lock); - - cxgb4_insert_tid(t, csk, tid); + cxgb4_insert_tid(t, csk, tid, csk->com.local_addr.ss_family); cxgbit_pass_accept_rpl(csk, req); goto rel_skb; -- cgit v1.2.3 From 57d88182ea3e8763111882671fd7462289272f64 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Wed, 7 Jun 2017 14:36:58 +0300 Subject: vxlan: use a more suitable function when assigning NULL When stopping the vxlan interface we detach it from the socket. Use RCU_INIT_POINTER() and not rcu_assign_pointer() to do so. Suggested-by: Stephen Hemminger Signed-off-by: Mark Bloch Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index a6b5052c1d36..7cb21a088bbc 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1077,10 +1077,10 @@ static void vxlan_sock_release(struct vxlan_dev *vxlan) #if IS_ENABLED(CONFIG_IPV6) struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock); - rcu_assign_pointer(vxlan->vn6_sock, NULL); + RCU_INIT_POINTER(vxlan->vn6_sock, NULL); #endif - rcu_assign_pointer(vxlan->vn4_sock, NULL); + RCU_INIT_POINTER(vxlan->vn4_sock, NULL); synchronize_net(); vxlan_vs_del_dev(vxlan); -- cgit v1.2.3 From 5ebe31d7b20fa6c4b2542f957063e0cdf799b28a Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 7 Jun 2017 15:06:19 +0200 Subject: net: dsa: mv88e6xxx: Have 6161/6123 use EDSA tags The mv88e6161 and mv88e6123 are capable of using EDSA tags when passing frames from the host to the switch and back. Signed-off-by: Andrew Lunn Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 117f275e3fb6..44c87027623b 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3246,7 +3246,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .g1_irqs = 9, .atu_move_port_mask = 0xf, .pvt = true, - .tag_protocol = DSA_TAG_PROTO_DSA, + .tag_protocol = DSA_TAG_PROTO_EDSA, .flags = MV88E6XXX_FLAGS_FAMILY_6165, .ops = &mv88e6123_ops, }, @@ -3298,7 +3298,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .g1_irqs = 9, .atu_move_port_mask = 0xf, .pvt = true, - .tag_protocol = DSA_TAG_PROTO_DSA, + .tag_protocol = DSA_TAG_PROTO_EDSA, .flags = MV88E6XXX_FLAGS_FAMILY_6165, .ops = &mv88e6161_ops, }, -- cgit v1.2.3 From cea2a6d81d214e7f5bdcd3866dbd8a7b05a99c60 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Wed, 7 Jun 2017 16:26:13 +0300 Subject: net/mlx4_core: Bump driver version Remove date and bump version for mlx4_core driver. Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 2 +- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 83aab1e4c8c8..ccae3c6593c4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -119,7 +119,7 @@ MODULE_PARM_DESC(enable_4k_uar, static char mlx4_version[] = DRV_NAME ": Mellanox ConnectX core driver v" - DRV_VERSION " (" DRV_RELDATE ")\n"; + DRV_VERSION "\n"; static struct mlx4_profile default_profile = { .num_qp = 1 << 18, diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index b4f1bc56cc68..6ea2b7a0c34d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -56,8 +56,7 @@ #define DRV_NAME "mlx4_core" #define PFX DRV_NAME ": " -#define DRV_VERSION "2.2-1" -#define DRV_RELDATE "Feb, 2014" +#define DRV_VERSION "4.0-0" #define MLX4_FS_UDP_UC_EN (1 << 1) #define MLX4_FS_TCP_UC_EN (1 << 2) -- cgit v1.2.3 From 808df6a209ab21af158de38031f52dd3e9fb409c Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Wed, 7 Jun 2017 16:26:14 +0300 Subject: net/mlx4_en: Bump driver version Remove date and bump version for mlx4_en driver. Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_main.c | 4 ++-- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index ffbcb27c05e5..e97fbf327594 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -89,7 +89,7 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) struct mlx4_en_dev *mdev = priv->mdev; strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", + strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%d", diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index 36a7a54bbb82..d94f981eafc4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -46,11 +46,11 @@ MODULE_AUTHOR("Liran Liss, Yevgeny Petrilin"); MODULE_DESCRIPTION("Mellanox ConnectX HCA Ethernet driver"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(DRV_VERSION " ("DRV_RELDATE")"); +MODULE_VERSION(DRV_VERSION); static const char mlx4_en_version[] = DRV_NAME ": Mellanox ConnectX HCA Ethernet driver v" - DRV_VERSION " (" DRV_RELDATE ")\n"; + DRV_VERSION "\n"; #define MLX4_EN_PARM_INT(X, def_val, desc) \ static unsigned int X = def_val;\ diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 39f401aa3047..8c4f63946b14 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -58,8 +58,7 @@ #include "mlx4_stats.h" #define DRV_NAME "mlx4_en" -#define DRV_VERSION "2.2-1" -#define DRV_RELDATE "Feb 2014" +#define DRV_VERSION "4.0-0" #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) -- cgit v1.2.3 From 0a528ee9a52007984fa60b0c4ef1f39fdf5edf8d Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Wed, 7 Jun 2017 16:26:15 +0300 Subject: IB/mlx4: Bump driver version Remove date and bump version for mlx4_ib driver. Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 521d0def2d9e..75b2f7d4cd95 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -61,8 +61,7 @@ #include #define DRV_NAME MLX4_IB_DRV_NAME -#define DRV_VERSION "2.2-1" -#define DRV_RELDATE "Feb 2014" +#define DRV_VERSION "4.0-0" #define MLX4_IB_FLOW_MAX_PRIO 0xFFF #define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF @@ -79,7 +78,7 @@ MODULE_PARM_DESC(sm_guid_assign, "Enable SM alias_GUID assignment if sm_guid_ass static const char mlx4_ib_version[] = DRV_NAME ": Mellanox ConnectX InfiniBand driver v" - DRV_VERSION " (" DRV_RELDATE ")\n"; + DRV_VERSION "\n"; static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init); -- cgit v1.2.3 From b476deab8f412bd5441eb161b0fda86a0246de27 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 27 Apr 2017 18:59:11 +0100 Subject: igb: make a few local functions static Clean up a few sparse warnings, these following functions can be made static: drivers/net/ethernet/intel/igb/igb_main.c: warning: symbol 'igb_add_mac_filter' was not declared. Should it be static? drivers/net/ethernet/intel/igb/igb_main.c: warning: symbol 'igb_del_mac_filter' was not declared. Should it be static? drivers/net/ethernet/intel/igb/igb_main.c: warning: symbol 'igb_set_vf_mac_filter' was not declared. Should it be static? Signed-off-by: Colin Ian King Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 7e433344a13c..ec62410b035a 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6469,8 +6469,8 @@ static void igb_set_default_mac_filter(struct igb_adapter *adapter) igb_rar_set_index(adapter, 0); } -int igb_add_mac_filter(struct igb_adapter *adapter, const u8 *addr, - const u8 queue) +static int igb_add_mac_filter(struct igb_adapter *adapter, const u8 *addr, + const u8 queue) { struct e1000_hw *hw = &adapter->hw; int rar_entries = hw->mac.rar_entry_count - @@ -6499,8 +6499,8 @@ int igb_add_mac_filter(struct igb_adapter *adapter, const u8 *addr, return -ENOSPC; } -int igb_del_mac_filter(struct igb_adapter *adapter, const u8 *addr, - const u8 queue) +static int igb_del_mac_filter(struct igb_adapter *adapter, const u8 *addr, + const u8 queue) { struct e1000_hw *hw = &adapter->hw; int rar_entries = hw->mac.rar_entry_count - @@ -6552,8 +6552,8 @@ static int igb_uc_unsync(struct net_device *netdev, const unsigned char *addr) return 0; } -int igb_set_vf_mac_filter(struct igb_adapter *adapter, const int vf, - const u32 info, const u8 *addr) +static int igb_set_vf_mac_filter(struct igb_adapter *adapter, const int vf, + const u32 info, const u8 *addr) { struct pci_dev *pdev = adapter->pdev; struct vf_data_storage *vf_data = &adapter->vf_data[vf]; -- cgit v1.2.3 From 833521ebc65b1c3092e5c0d8a97092f98eec595d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 31 May 2017 18:50:43 +0300 Subject: e1000e: Undo e1000e_pm_freeze if __e1000_shutdown fails An error during suspend (e100e_pm_suspend), [ 429.994338] ACPI : EC: event blocked [ 429.994633] e1000e: EEE TX LPI TIMER: 00000011 [ 430.955451] pci_pm_suspend(): e1000e_pm_suspend+0x0/0x30 [e1000e] returns -2 [ 430.955454] dpm_run_callback(): pci_pm_suspend+0x0/0x140 returns -2 [ 430.955458] PM: Device 0000:00:19.0 failed to suspend async: error -2 [ 430.955581] PM: Some devices failed to suspend, or early wake event detected [ 430.957709] ACPI : EC: event unblocked lead to complete failure: [ 432.585002] ------------[ cut here ]------------ [ 432.585013] WARNING: CPU: 3 PID: 8372 at kernel/irq/manage.c:1478 __free_irq+0x9f/0x280 [ 432.585015] Trying to free already-free IRQ 20 [ 432.585016] Modules linked in: cdc_ncm usbnet x86_pkg_temp_thermal intel_powerclamp coretemp mii crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep lpc_ich snd_hda_core snd_pcm mei_me mei sdhci_pci sdhci i915 mmc_core e1000e ptp pps_core prime_numbers [ 432.585042] CPU: 3 PID: 8372 Comm: kworker/u16:40 Tainted: G U 4.10.0-rc8-CI-Patchwork_3870+ #1 [ 432.585044] Hardware name: LENOVO 2356GCG/2356GCG, BIOS G7ET31WW (1.13 ) 07/02/2012 [ 432.585050] Workqueue: events_unbound async_run_entry_fn [ 432.585051] Call Trace: [ 432.585058] dump_stack+0x67/0x92 [ 432.585062] __warn+0xc6/0xe0 [ 432.585065] warn_slowpath_fmt+0x4a/0x50 [ 432.585070] ? _raw_spin_lock_irqsave+0x49/0x60 [ 432.585072] __free_irq+0x9f/0x280 [ 432.585075] free_irq+0x34/0x80 [ 432.585089] e1000_free_irq+0x65/0x70 [e1000e] [ 432.585098] e1000e_pm_freeze+0x7a/0xb0 [e1000e] [ 432.585106] e1000e_pm_suspend+0x21/0x30 [e1000e] [ 432.585113] pci_pm_suspend+0x71/0x140 [ 432.585118] dpm_run_callback+0x6f/0x330 [ 432.585122] ? pci_pm_freeze+0xe0/0xe0 [ 432.585125] __device_suspend+0xea/0x330 [ 432.585128] async_suspend+0x1a/0x90 [ 432.585132] async_run_entry_fn+0x34/0x160 [ 432.585137] process_one_work+0x1f4/0x6d0 [ 432.585140] ? process_one_work+0x16e/0x6d0 [ 432.585143] worker_thread+0x49/0x4a0 [ 432.585145] kthread+0x107/0x140 [ 432.585148] ? process_one_work+0x6d0/0x6d0 [ 432.585150] ? kthread_create_on_node+0x40/0x40 [ 432.585154] ret_from_fork+0x2e/0x40 [ 432.585156] ---[ end trace 6712df7f8c4b9124 ]--- The unwind failures stems from commit 2800209994f8 ("e1000e: Refactor PM flows"), but it may be a later patch that introduced the non-recoverable behaviour. Fixes: 2800209994f8 ("e1000e: Refactor PM flows") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=99847 Signed-off-by: Chris Wilson Signed-off-by: Jani Nikula Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index e1d46c11cb61..2dcb5463d9b8 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6640,12 +6640,17 @@ static int e1000e_pm_thaw(struct device *dev) static int e1000e_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); + int rc; e1000e_flush_lpic(pdev); e1000e_pm_freeze(dev); - return __e1000_shutdown(pdev, false); + rc = __e1000_shutdown(pdev, false); + if (rc) + e1000e_pm_thaw(dev); + + return rc; } static int e1000e_pm_resume(struct device *dev) -- cgit v1.2.3 From de6ea92382f6d93f73ce1f77b9af5051e3f40798 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 28 Feb 2017 10:48:35 +0200 Subject: net/mlx5e: Remove limitation of single NIC offloaded TC action per rule Remove the limitation that offloaded NIC filters can have only one action. This allows us for example to provide flow tag as a note to upper layers / apps that that HW header re-write was applied. Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 8ec13f9be660..cfb32fe5129d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1194,10 +1194,6 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts, tcf_exts_to_list(exts, &actions); list_for_each_entry(a, &actions, list) { - /* Only support a single action per rule */ - if (attr->action) - return -EINVAL; - if (is_tcf_gact_shot(a)) { attr->action |= MLX5_FLOW_CONTEXT_ACTION_DROP; if (MLX5_CAP_FLOWTABLE(priv->mdev, -- cgit v1.2.3 From 513f8f7fc049361976062c770a1ffb43b01c73d1 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 7 May 2017 11:33:17 +0300 Subject: net/mlx5e: Use short attribute form when adding/deleting offloaded TC flows Instead of going through flow->nic/esw_attr for each usage, assign an attr pointer per the context (nic or esw) and use that. This patch doesn't add any functionality. Signed-off-by: Or Gerlitz Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index cfb32fe5129d..a9feddc31667 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -177,6 +177,7 @@ err_create_mod_hdr_id: static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow) { + struct mlx5_nic_flow_attr *attr = flow->nic_attr; struct mlx5_fc *counter = NULL; counter = mlx5_flow_rule_counter(flow->rule); @@ -188,9 +189,9 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, priv->fs.tc.t = NULL; } - if (flow->nic_attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) mlx5_modify_header_dealloc(priv->mdev, - flow->nic_attr->mod_hdr_id); + attr->mod_hdr_id); } static void mlx5e_detach_encap(struct mlx5e_priv *priv, @@ -231,7 +232,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, return rule; err_add_rule: - if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) mlx5_modify_header_dealloc(priv->mdev, attr->mod_hdr_id); err_mod_hdr: @@ -250,17 +251,17 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) { flow->flags &= ~MLX5E_TC_FLOW_OFFLOADED; - mlx5_eswitch_del_offloaded_rule(esw, flow->rule, flow->esw_attr); + mlx5_eswitch_del_offloaded_rule(esw, flow->rule, attr); } - mlx5_eswitch_del_vlan_action(esw, flow->esw_attr); + mlx5_eswitch_del_vlan_action(esw, attr); - if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) { + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP) { mlx5e_detach_encap(priv, flow); - kvfree(flow->esw_attr->parse_attr); + kvfree(attr->parse_attr); } - if (flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) + if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) mlx5_modify_header_dealloc(priv->mdev, attr->mod_hdr_id); } -- cgit v1.2.3 From 11c9c548ceb31f431facbc51c7081b4957223c47 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 4 May 2017 21:46:11 +0300 Subject: net/mlx5e: Add cache for HW modify header IDs Packets belonging to flows which are different by matching may still need to go through the same header re-write. Add a cache for header re-write IDs keyed by the binary chain of modify header actions. The caching is supported for both eswitch and NIC use-cases, where the actual conversion of the code to use caching comes in next patches, one per use-case. Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 + drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 134 +++++++++++++++++++++- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 1 + drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 1 + 4 files changed, 137 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 2fd044b23875..f4b95dbd1c7f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -623,6 +623,8 @@ struct mlx5e_tc_table { struct rhashtable_params ht_params; struct rhashtable ht; + + DECLARE_HASHTABLE(mod_hdr_tbl, 8); }; struct mlx5e_vlan_table { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index a9feddc31667..e1217c2279ab 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -69,7 +69,8 @@ struct mlx5e_tc_flow { u64 cookie; u8 flags; struct mlx5_flow_handle *rule; - struct list_head encap; /* flows sharing the same encap */ + struct list_head encap; /* flows sharing the same encap ID */ + struct list_head mod_hdr; /* flows sharing the same mod hdr ID */ union { struct mlx5_esw_flow_attr esw_attr[0]; struct mlx5_nic_flow_attr nic_attr[0]; @@ -90,6 +91,135 @@ enum { #define MLX5E_TC_TABLE_NUM_ENTRIES 1024 #define MLX5E_TC_TABLE_NUM_GROUPS 4 +struct mod_hdr_key { + int num_actions; + void *actions; +}; + +struct mlx5e_mod_hdr_entry { + /* a node of a hash table which keeps all the mod_hdr entries */ + struct hlist_node mod_hdr_hlist; + + /* flows sharing the same mod_hdr entry */ + struct list_head flows; + + struct mod_hdr_key key; + + u32 mod_hdr_id; +}; + +#define MLX5_MH_ACT_SZ MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto) + +static inline u32 hash_mod_hdr_info(struct mod_hdr_key *key) +{ + return jhash(key->actions, + key->num_actions * MLX5_MH_ACT_SZ, 0); +} + +static inline int cmp_mod_hdr_info(struct mod_hdr_key *a, + struct mod_hdr_key *b) +{ + if (a->num_actions != b->num_actions) + return 1; + + return memcmp(a->actions, b->actions, a->num_actions * MLX5_MH_ACT_SZ); +} + +static int mlx5e_attach_mod_hdr(struct mlx5e_priv *priv, + struct mlx5e_tc_flow *flow, + struct mlx5e_tc_flow_parse_attr *parse_attr) +{ + struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; + int num_actions, actions_size, namespace, err; + struct mlx5e_mod_hdr_entry *mh; + struct mod_hdr_key key; + bool found = false; + u32 hash_key; + + num_actions = parse_attr->num_mod_hdr_actions; + actions_size = MLX5_MH_ACT_SZ * num_actions; + + key.actions = parse_attr->mod_hdr_actions; + key.num_actions = num_actions; + + hash_key = hash_mod_hdr_info(&key); + + if (flow->flags & MLX5E_TC_FLOW_ESWITCH) { + namespace = MLX5_FLOW_NAMESPACE_FDB; + hash_for_each_possible(esw->offloads.mod_hdr_tbl, mh, + mod_hdr_hlist, hash_key) { + if (!cmp_mod_hdr_info(&mh->key, &key)) { + found = true; + break; + } + } + } else { + namespace = MLX5_FLOW_NAMESPACE_KERNEL; + hash_for_each_possible(priv->fs.tc.mod_hdr_tbl, mh, + mod_hdr_hlist, hash_key) { + if (!cmp_mod_hdr_info(&mh->key, &key)) { + found = true; + break; + } + } + } + + if (found) + goto attach_flow; + + mh = kzalloc(sizeof(*mh) + actions_size, GFP_KERNEL); + if (!mh) + return -ENOMEM; + + mh->key.actions = (void *)mh + sizeof(*mh); + memcpy(mh->key.actions, key.actions, actions_size); + mh->key.num_actions = num_actions; + INIT_LIST_HEAD(&mh->flows); + + err = mlx5_modify_header_alloc(priv->mdev, namespace, + mh->key.num_actions, + mh->key.actions, + &mh->mod_hdr_id); + if (err) + goto out_err; + + if (flow->flags & MLX5E_TC_FLOW_ESWITCH) + hash_add(esw->offloads.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key); + else + hash_add(priv->fs.tc.mod_hdr_tbl, &mh->mod_hdr_hlist, hash_key); + +attach_flow: + list_add(&flow->mod_hdr, &mh->flows); + if (flow->flags & MLX5E_TC_FLOW_ESWITCH) + flow->esw_attr->mod_hdr_id = mh->mod_hdr_id; + else + flow->nic_attr->mod_hdr_id = mh->mod_hdr_id; + + return 0; + +out_err: + kfree(mh); + return err; +} + +static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv, + struct mlx5e_tc_flow *flow) +{ + struct list_head *next = flow->mod_hdr.next; + + list_del(&flow->mod_hdr); + + if (list_empty(next)) { + struct mlx5e_mod_hdr_entry *mh; + + mh = list_entry(next, struct mlx5e_mod_hdr_entry, flows); + + mlx5_modify_header_dealloc(priv->mdev, mh->mod_hdr_id); + hash_del(&mh->mod_hdr_hlist); + kfree(mh); + } +} + static struct mlx5_flow_handle * mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr, @@ -1939,6 +2069,8 @@ int mlx5e_tc_init(struct mlx5e_priv *priv) { struct mlx5e_tc_table *tc = &priv->fs.tc; + hash_init(tc->mod_hdr_tbl); + tc->ht_params = mlx5e_tc_flow_ht_params; return rhashtable_init(&tc->ht, &tc->ht_params); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 81dfcd90b1f5..37927156f258 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1769,6 +1769,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) } hash_init(esw->offloads.encap_tbl); + hash_init(esw->offloads.mod_hdr_tbl); mutex_init(&esw->state_lock); for (vport_num = 0; vport_num < total_vports; vport_num++) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index b746f62c8c79..834a33050969 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -207,6 +207,7 @@ struct mlx5_esw_offload { struct mlx5_flow_group *vport_rx_group; struct mlx5_eswitch_rep *vport_reps; DECLARE_HASHTABLE(encap_tbl, 8); + DECLARE_HASHTABLE(mod_hdr_tbl, 8); u8 inline_mode; u64 num_flows; u8 encap; -- cgit v1.2.3 From 1a9527bb17427a330ef9bd1a65e2c15760095b5f Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 4 May 2017 23:43:10 +0300 Subject: net/mlx5e: Use modify header ID cache for offloaded TC E-Switch flows Use the modify header ID cache for the header re-write part of offloading TC eswitch flows. Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index e1217c2279ab..4625a0e226da 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -344,10 +344,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { - err = mlx5_modify_header_alloc(priv->mdev, MLX5_FLOW_NAMESPACE_FDB, - parse_attr->num_mod_hdr_actions, - parse_attr->mod_hdr_actions, - &attr->mod_hdr_id); + err = mlx5e_attach_mod_hdr(priv, flow, parse_attr); kfree(parse_attr->mod_hdr_actions); if (err) { rule = ERR_PTR(err); @@ -363,8 +360,7 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, err_add_rule: if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) - mlx5_modify_header_dealloc(priv->mdev, - attr->mod_hdr_id); + mlx5e_detach_mod_hdr(priv, flow); err_mod_hdr: mlx5_eswitch_del_vlan_action(esw, attr); err_add_vlan: @@ -392,8 +388,7 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv, } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) - mlx5_modify_header_dealloc(priv->mdev, - attr->mod_hdr_id); + mlx5e_detach_mod_hdr(priv, flow); } void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv, -- cgit v1.2.3 From 3099eb5a8ee2e46d57302932165fe4f86232a812 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 4 May 2017 23:53:03 +0300 Subject: net/mlx5e: Use modify header ID cache for offloaded TC NIC flows Use the modify header ID cache for the header re-write part of offloading TC NIC flows. Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 4625a0e226da..0c7a0872b22b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -251,10 +251,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv, } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { - err = mlx5_modify_header_alloc(dev, MLX5_FLOW_NAMESPACE_KERNEL, - parse_attr->num_mod_hdr_actions, - parse_attr->mod_hdr_actions, - &attr->mod_hdr_id); + err = mlx5e_attach_mod_hdr(priv, flow, parse_attr); flow_act.modify_id = attr->mod_hdr_id; kfree(parse_attr->mod_hdr_actions); if (err) { @@ -296,8 +293,7 @@ err_add_rule: } err_create_ft: if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) - mlx5_modify_header_dealloc(priv->mdev, - attr->mod_hdr_id); + mlx5e_detach_mod_hdr(priv, flow); err_create_mod_hdr_id: mlx5_fc_destroy(dev, counter); @@ -320,8 +316,7 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv, } if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) - mlx5_modify_header_dealloc(priv->mdev, - attr->mod_hdr_id); + mlx5e_detach_mod_hdr(priv, flow); } static void mlx5e_detach_encap(struct mlx5e_priv *priv, -- cgit v1.2.3 From 2b64beba025109f64e688ae675985bbf72196b8c Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Wed, 10 May 2017 20:14:16 +0300 Subject: net/mlx5e: Support header re-write of partial fields in TC pedit offload Using a per field mask field, the TC pedit action supports modifying partial fields. E.g if using the TC tool, the following example would make the kernel to only re-write two bytes of the src ip address: tc filter add dev enp1s0 protocol ip parent ffff: prio 30 flower skip_sw ip_proto udp dst_port 8001 action pedit ex munge ip src set 10.1.0.0 retain 0xffff0000 We add driver support for offload these partial re-writes, by setting the per FW action offset-in-field and length-from-offset attributes. The 1st bit set in the mask specifies both the offset and the right shift to apply on the value such that the 1st bit which needs to be set will reside in bit 0 of the FW data field. Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 28 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 0c7a0872b22b..f5afacfbe914 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1091,12 +1091,14 @@ static int offload_pedit_fields(struct pedit_headers *masks, struct mlx5e_tc_flow_parse_attr *parse_attr) { struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals; - int i, action_size, nactions, max_actions, first, last, first_z; + int i, action_size, nactions, max_actions, first, last, next_z; void *s_masks_p, *a_masks_p, *vals_p; struct mlx5_fields *f; u8 cmd, field_bsize; u32 s_mask, a_mask; unsigned long mask; + __be32 mask_be32; + __be16 mask_be16; void *action; set_masks = &masks[TCA_PEDIT_KEY_EX_CMD_SET]; @@ -1150,11 +1152,19 @@ static int offload_pedit_fields(struct pedit_headers *masks, field_bsize = f->size * BITS_PER_BYTE; - first_z = find_first_zero_bit(&mask, field_bsize); + if (field_bsize == 32) { + mask_be32 = *(__be32 *)&mask; + mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32)); + } else if (field_bsize == 16) { + mask_be16 = *(__be16 *)&mask; + mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16)); + } + first = find_first_bit(&mask, field_bsize); + next_z = find_next_zero_bit(&mask, field_bsize, first); last = find_last_bit(&mask, field_bsize); - if (first > 0 || last != (field_bsize - 1) || first_z < last) { - printk(KERN_WARNING "mlx5: partial rewrite (mask %lx) is currently not offloaded\n", + if (first < next_z && next_z < last) { + printk(KERN_WARNING "mlx5: rewrite of few sub-fields (mask %lx) isn't offloaded\n", mask); return -EOPNOTSUPP; } @@ -1163,17 +1173,17 @@ static int offload_pedit_fields(struct pedit_headers *masks, MLX5_SET(set_action_in, action, field, f->field); if (cmd == MLX5_ACTION_TYPE_SET) { - MLX5_SET(set_action_in, action, offset, 0); + MLX5_SET(set_action_in, action, offset, first); /* length is num of bits to be written, zero means length of 32 */ - MLX5_SET(set_action_in, action, length, field_bsize); + MLX5_SET(set_action_in, action, length, (last - first + 1)); } if (field_bsize == 32) - MLX5_SET(set_action_in, action, data, ntohl(*(__be32 *)vals_p)); + MLX5_SET(set_action_in, action, data, ntohl(*(__be32 *)vals_p) >> first); else if (field_bsize == 16) - MLX5_SET(set_action_in, action, data, ntohs(*(__be16 *)vals_p)); + MLX5_SET(set_action_in, action, data, ntohs(*(__be16 *)vals_p) >> first); else if (field_bsize == 8) - MLX5_SET(set_action_in, action, data, *(u8 *)vals_p); + MLX5_SET(set_action_in, action, data, *(u8 *)vals_p >> first); action += action_size; nactions++; -- cgit v1.2.3 From 0c90e9c6b5549825e410b6589ad6c4478f81ebad Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Sun, 12 Mar 2017 11:35:23 +0200 Subject: net/mlx5: Update flow table commands layout Update struct mlx5_ifc_create(modify)_flow_table_bits according to the last device specification. Signed-off-by: Maor Gottlieb Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 32 +++++++++++++++--------- 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index abb44a268563..e750f07793b8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -78,28 +78,33 @@ int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev, MLX5_CMD_OP_CREATE_FLOW_TABLE); MLX5_SET(create_flow_table_in, in, table_type, type); - MLX5_SET(create_flow_table_in, in, level, level); - MLX5_SET(create_flow_table_in, in, log_size, log_size); + MLX5_SET(create_flow_table_in, in, flow_table_context.level, level); + MLX5_SET(create_flow_table_in, in, flow_table_context.log_size, log_size); if (vport) { MLX5_SET(create_flow_table_in, in, vport_number, vport); MLX5_SET(create_flow_table_in, in, other_vport, 1); } - MLX5_SET(create_flow_table_in, in, decap_en, en_encap_decap); - MLX5_SET(create_flow_table_in, in, encap_en, en_encap_decap); + MLX5_SET(create_flow_table_in, in, flow_table_context.decap_en, + en_encap_decap); + MLX5_SET(create_flow_table_in, in, flow_table_context.encap_en, + en_encap_decap); switch (op_mod) { case FS_FT_OP_MOD_NORMAL: if (next_ft) { - MLX5_SET(create_flow_table_in, in, table_miss_mode, 1); - MLX5_SET(create_flow_table_in, in, table_miss_id, next_ft->id); + MLX5_SET(create_flow_table_in, in, + flow_table_context.table_miss_action, 1); + MLX5_SET(create_flow_table_in, in, + flow_table_context.table_miss_id, next_ft->id); } break; case FS_FT_OP_MOD_LAG_DEMUX: MLX5_SET(create_flow_table_in, in, op_mod, 0x1); if (next_ft) - MLX5_SET(create_flow_table_in, in, lag_master_next_table_id, + MLX5_SET(create_flow_table_in, in, + flow_table_context.lag_master_next_table_id, next_ft->id); break; } @@ -146,10 +151,10 @@ int mlx5_cmd_modify_flow_table(struct mlx5_core_dev *dev, MLX5_MODIFY_FLOW_TABLE_LAG_NEXT_TABLE_ID); if (next_ft) { MLX5_SET(modify_flow_table_in, in, - lag_master_next_table_id, next_ft->id); + flow_table_context.lag_master_next_table_id, next_ft->id); } else { MLX5_SET(modify_flow_table_in, in, - lag_master_next_table_id, 0); + flow_table_context.lag_master_next_table_id, 0); } } else { if (ft->vport) { @@ -160,11 +165,14 @@ int mlx5_cmd_modify_flow_table(struct mlx5_core_dev *dev, MLX5_SET(modify_flow_table_in, in, modify_field_select, MLX5_MODIFY_FLOW_TABLE_MISS_TABLE_ID); if (next_ft) { - MLX5_SET(modify_flow_table_in, in, table_miss_mode, 1); - MLX5_SET(modify_flow_table_in, in, table_miss_id, + MLX5_SET(modify_flow_table_in, in, + flow_table_context.table_miss_action, 1); + MLX5_SET(modify_flow_table_in, in, + flow_table_context.table_miss_id, next_ft->id); } else { - MLX5_SET(modify_flow_table_in, in, table_miss_mode, 0); + MLX5_SET(modify_flow_table_in, in, + flow_table_context.table_miss_action, 0); } } -- cgit v1.2.3 From 5b4793f817452e478442684e6bba85bddb5a9345 Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Mon, 13 Feb 2017 14:00:59 +0200 Subject: net/mlx5e: Add support for reading connector type from PTYS Read port connector type from the firmware instead of caching it in the driver metadata. Signed-off-by: Eran Ben Elisha Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index e9e33fd68279..f03c2d088d0c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -809,8 +809,23 @@ static void get_advertising(u32 eth_proto_cap, u8 tx_pause, ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, Asym_Pause); } -static u8 get_connector_port(u32 eth_proto) +static int ptys2connector_type[MLX5E_CONNECTOR_TYPE_NUMBER] = { + [MLX5E_PORT_UNKNOWN] = PORT_OTHER, + [MLX5E_PORT_NONE] = PORT_NONE, + [MLX5E_PORT_TP] = PORT_TP, + [MLX5E_PORT_AUI] = PORT_AUI, + [MLX5E_PORT_BNC] = PORT_BNC, + [MLX5E_PORT_MII] = PORT_MII, + [MLX5E_PORT_FIBRE] = PORT_FIBRE, + [MLX5E_PORT_DA] = PORT_DA, + [MLX5E_PORT_OTHER] = PORT_OTHER, + }; + +static u8 get_connector_port(u32 eth_proto, u8 connector_type) { + if (connector_type && connector_type < MLX5E_CONNECTOR_TYPE_NUMBER) + return ptys2connector_type[connector_type]; + if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_SR) | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) @@ -856,6 +871,7 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev, u32 eth_proto_oper; u8 an_disable_admin; u8 an_status; + u8 connector_type; int err; err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1); @@ -871,6 +887,7 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev, eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise); an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); an_status = MLX5_GET(ptys_reg, out, an_status); + connector_type = MLX5_GET(ptys_reg, out, connector_type); mlx5_query_port_pause(mdev, &rx_pause, &tx_pause); @@ -883,7 +900,8 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev, eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap; - link_ksettings->base.port = get_connector_port(eth_proto_oper); + link_ksettings->base.port = get_connector_port(eth_proto_oper, + connector_type); get_lp_advertising(eth_proto_lp, link_ksettings); if (an_status == MLX5_AN_COMPLETE) -- cgit v1.2.3 From 46e9d0b61e27a3a9286002311f349f0c33dcb18f Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Sun, 16 Apr 2017 10:03:38 +0300 Subject: net/mlx5e: Fill advertised and supported port data from Hardware info Translate hardware port connector type data into link mode supported and advertised info instead of caching it in driver. Signed-off-by: Eran Ben Elisha Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 90 ++++++++++++++++++---- 1 file changed, 74 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index f03c2d088d0c..b4514f247402 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -723,24 +723,81 @@ static void ptys2ethtool_adver_link(unsigned long *advertising_modes, __ETHTOOL_LINK_MODE_MASK_NBITS); } -static void ptys2ethtool_supported_port(struct ethtool_link_ksettings *link_ksettings, - u32 eth_proto_cap) +static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings *link_ksettings, + u32 eth_proto_cap, + u8 connector_type) { - if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR) - | MLX5E_PROT_MASK(MLX5E_10GBASE_SR) - | MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) - | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) - | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) - | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { - ethtool_link_ksettings_add_link_mode(link_ksettings, supported, FIBRE); + if (!connector_type || connector_type >= MLX5E_CONNECTOR_TYPE_NUMBER) { + if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR) + | MLX5E_PROT_MASK(MLX5E_10GBASE_SR) + | MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) + | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) + | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) + | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { + ethtool_link_ksettings_add_link_mode(link_ksettings, + supported, + FIBRE); + ethtool_link_ksettings_add_link_mode(link_ksettings, + advertising, + FIBRE); + } + + if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_100GBASE_KR4) + | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) + | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) + | MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) + | MLX5E_PROT_MASK(MLX5E_1000BASE_KX))) { + ethtool_link_ksettings_add_link_mode(link_ksettings, + supported, + Backplane); + ethtool_link_ksettings_add_link_mode(link_ksettings, + advertising, + Backplane); + } + return; } - if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_100GBASE_KR4) - | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) - | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) - | MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) - | MLX5E_PROT_MASK(MLX5E_1000BASE_KX))) { - ethtool_link_ksettings_add_link_mode(link_ksettings, supported, Backplane); + switch (connector_type) { + case MLX5E_PORT_TP: + ethtool_link_ksettings_add_link_mode(link_ksettings, + supported, TP); + ethtool_link_ksettings_add_link_mode(link_ksettings, + advertising, TP); + break; + case MLX5E_PORT_AUI: + ethtool_link_ksettings_add_link_mode(link_ksettings, + supported, AUI); + ethtool_link_ksettings_add_link_mode(link_ksettings, + advertising, AUI); + break; + case MLX5E_PORT_BNC: + ethtool_link_ksettings_add_link_mode(link_ksettings, + supported, BNC); + ethtool_link_ksettings_add_link_mode(link_ksettings, + advertising, BNC); + break; + case MLX5E_PORT_MII: + ethtool_link_ksettings_add_link_mode(link_ksettings, + supported, MII); + ethtool_link_ksettings_add_link_mode(link_ksettings, + advertising, MII); + break; + case MLX5E_PORT_FIBRE: + ethtool_link_ksettings_add_link_mode(link_ksettings, + supported, FIBRE); + ethtool_link_ksettings_add_link_mode(link_ksettings, + advertising, FIBRE); + break; + case MLX5E_PORT_DA: + ethtool_link_ksettings_add_link_mode(link_ksettings, + supported, Backplane); + ethtool_link_ksettings_add_link_mode(link_ksettings, + advertising, Backplane); + break; + case MLX5E_PORT_NONE: + case MLX5E_PORT_OTHER: + default: + break; } } @@ -791,7 +848,6 @@ static void get_supported(u32 eth_proto_cap, { unsigned long *supported = link_ksettings->link_modes.supported; - ptys2ethtool_supported_port(link_ksettings, eth_proto_cap); ptys2ethtool_supported_link(supported, eth_proto_cap); ethtool_link_ksettings_add_link_mode(link_ksettings, supported, Pause); } @@ -902,6 +958,8 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev, link_ksettings->base.port = get_connector_port(eth_proto_oper, connector_type); + ptys2ethtool_supported_advertised_port(link_ksettings, eth_proto_admin, + connector_type); get_lp_advertising(eth_proto_lp, link_ksettings); if (an_status == MLX5_AN_COMPLETE) -- cgit v1.2.3 From a5fcf8a6c968ed8e312ff0b2a55d4c62d821eabb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 6 Jun 2017 17:00:16 +0200 Subject: net: propagate tc filter chain index down the ndo_setup_tc call We need to push the chain index down to the drivers, so they have the information to which chain the rule belongs. For now, no driver supports multichain offload, so only chain 0 is supported. This is needed to prevent chain squashes during offload for now. Later this will be used to implement multichain offload. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 3 ++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 ++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 4 ++-- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 4 ++-- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 7 +++++-- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 4 ++-- drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 4 ++-- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 ++- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 7 +++++-- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 6 +++++- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 7 ++++++- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 6 +++++- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 7 +++++-- drivers/net/ethernet/sfc/efx.h | 4 ++-- drivers/net/ethernet/sfc/falcon/efx.h | 4 ++-- drivers/net/ethernet/sfc/falcon/tx.c | 4 ++-- drivers/net/ethernet/sfc/tx.c | 4 ++-- drivers/net/ethernet/ti/netcp_core.c | 4 ++-- 19 files changed, 57 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 5a2ad9c5faab..a934bd5d0507 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1846,7 +1846,8 @@ static void xgbe_poll_controller(struct net_device *netdev) } #endif /* End CONFIG_NET_POLL_CONTROLLER */ -static int xgbe_setup_tc(struct net_device *netdev, u32 handle, __be16 proto, +static int xgbe_setup_tc(struct net_device *netdev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc_to_netdev) { struct xgbe_prv_data *pdata = netdev_priv(netdev); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 5f49334dcad5..ef734675885e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -4273,8 +4273,8 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc) return 0; } -int __bnx2x_setup_tc(struct net_device *dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc) +int __bnx2x_setup_tc(struct net_device *dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc) { if (tc->type != TC_SETUP_MQPRIO) return -EINVAL; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 243cb9748d35..c26688d2f326 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -486,8 +486,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev); /* setup_tc callback */ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc); -int __bnx2x_setup_tc(struct net_device *dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc); +int __bnx2x_setup_tc(struct net_device *dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc); int bnx2x_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c1cd72a5eccf..11e8a866a312 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7103,8 +7103,8 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc) return 0; } -static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto, - struct tc_to_netdev *ntc) +static int bnxt_setup_tc(struct net_device *dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *ntc) { if (ntc->type != TC_SETUP_MQPRIO) return -EINVAL; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 91685bf21878..ff8bcf56bf3f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2823,12 +2823,15 @@ static int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate) return err; } -static int cxgb_setup_tc(struct net_device *dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc) +static int cxgb_setup_tc(struct net_device *dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc) { struct port_info *pi = netdev2pinfo(dev); struct adapter *adap = netdev2adap(dev); + if (chain_index) + return -EOPNOTSUPP; + if (!(adap->flags & FULL_INIT_DONE)) { dev_err(adap->pdev_dev, "Failed to setup tc on port %d. Link Down?\n", diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 9a520e4f0df9..a5501af6db99 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -342,8 +342,8 @@ static void dpaa_get_stats64(struct net_device *net_dev, } } -static int dpaa_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc) +static int dpaa_setup_tc(struct net_device *net_dev, u32 handle, + u32 chain_index, __be16 proto, struct tc_to_netdev *tc) { struct dpaa_priv *priv = netdev_priv(net_dev); u8 num_tc; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 24f2f6f86f5a..5e37387c7082 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -1265,8 +1265,8 @@ err_queueing_scheme: return err; } -static int __fm10k_setup_tc(struct net_device *dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc) +static int __fm10k_setup_tc(struct net_device *dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc) { if (tc->type != TC_SETUP_MQPRIO) return -EINVAL; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5fef27ebfa52..abab7fb7a3fc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5509,7 +5509,8 @@ exit: return ret; } -static int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto, +static int __i40e_setup_tc(struct net_device *netdev, u32 handle, + u32 chain_index, __be16 proto, struct tc_to_netdev *tc) { if (tc->type != TC_SETUP_MQPRIO) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 54463f03b3db..812319ab77db 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -9200,11 +9200,14 @@ free_jump: return err; } -static int __ixgbe_setup_tc(struct net_device *dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc) +static int __ixgbe_setup_tc(struct net_device *dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc) { struct ixgbe_adapter *adapter = netdev_priv(dev); + if (chain_index) + return -EOPNOTSUPP; + if (TC_H_MAJ(handle) == TC_H_MAJ(TC_H_INGRESS) && tc->type == TC_SETUP_CLSU32) { switch (tc->cls_u32->command) { diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 82436742ad75..c1de75fc399a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -86,7 +86,8 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up) return 0; } -static int __mlx4_en_setup_tc(struct net_device *dev, u32 handle, __be16 proto, +static int __mlx4_en_setup_tc(struct net_device *dev, u32 handle, + u32 chain_index, __be16 proto, struct tc_to_netdev *tc) { if (tc->type != TC_SETUP_MQPRIO) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index cdff04b2aea1..5afec0f4a658 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2991,13 +2991,17 @@ out: } static int mlx5e_ndo_setup_tc(struct net_device *dev, u32 handle, - __be16 proto, struct tc_to_netdev *tc) + u32 chain_index, __be16 proto, + struct tc_to_netdev *tc) { struct mlx5e_priv *priv = netdev_priv(dev); if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS)) goto mqprio; + if (chain_index) + return -EOPNOTSUPP; + switch (tc->type) { case TC_SETUP_CLSFLOWER: switch (tc->cls_flower->command) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 79462c0368a0..70c2b8d020bd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -652,7 +652,8 @@ static int mlx5e_rep_get_phys_port_name(struct net_device *dev, } static int mlx5e_rep_ndo_setup_tc(struct net_device *dev, u32 handle, - __be16 proto, struct tc_to_netdev *tc) + u32 chain_index, __be16 proto, + struct tc_to_netdev *tc) { struct mlx5e_priv *priv = netdev_priv(dev); @@ -664,9 +665,13 @@ static int mlx5e_rep_ndo_setup_tc(struct net_device *dev, u32 handle, struct net_device *uplink_dev = mlx5_eswitch_get_uplink_netdev(esw); return uplink_dev->netdev_ops->ndo_setup_tc(uplink_dev, handle, + chain_index, proto, tc); } + if (chain_index) + return -EOPNOTSUPP; + switch (tc->type) { case TC_SETUP_CLSFLOWER: switch (tc->cls_flower->command) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index f60e2ba515d0..a2316d038810 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1699,11 +1699,15 @@ static void mlxsw_sp_port_del_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port, } static int mlxsw_sp_setup_tc(struct net_device *dev, u32 handle, - __be16 proto, struct tc_to_netdev *tc) + u32 chain_index, __be16 proto, + struct tc_to_netdev *tc) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); bool ingress = TC_H_MAJ(handle) == TC_H_MAJ(TC_H_INGRESS); + if (chain_index) + return -EOPNOTSUPP; + switch (tc->type) { case TC_SETUP_MATCHALL: switch (tc->cls_mall->command) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 4f0df63de626..49d1756d6a8e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2994,11 +2994,14 @@ static void nfp_net_stat64(struct net_device *netdev, } static int -nfp_net_setup_tc(struct net_device *netdev, u32 handle, __be16 proto, - struct tc_to_netdev *tc) +nfp_net_setup_tc(struct net_device *netdev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc) { struct nfp_net *nn = netdev_priv(netdev); + if (chain_index) + return -EOPNOTSUPP; + return nfp_app_setup_tc(nn->app, netdev, handle, proto, tc); } diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index a0c52e328102..fcea9371ab7f 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -32,8 +32,8 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); -int efx_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc); +int efx_setup_tc(struct net_device *net_dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc); unsigned int efx_tx_max_skb_descs(struct efx_nic *efx); extern unsigned int efx_piobuf_size; extern bool efx_separate_tx_channels; diff --git a/drivers/net/ethernet/sfc/falcon/efx.h b/drivers/net/ethernet/sfc/falcon/efx.h index c89456fa148c..e5a7a40cc8b6 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.h +++ b/drivers/net/ethernet/sfc/falcon/efx.h @@ -32,8 +32,8 @@ netdev_tx_t ef4_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); netdev_tx_t ef4_enqueue_skb(struct ef4_tx_queue *tx_queue, struct sk_buff *skb); void ef4_xmit_done(struct ef4_tx_queue *tx_queue, unsigned int index); -int ef4_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc); +int ef4_setup_tc(struct net_device *net_dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc); unsigned int ef4_tx_max_skb_descs(struct ef4_nic *efx); extern bool ef4_separate_tx_channels; diff --git a/drivers/net/ethernet/sfc/falcon/tx.c b/drivers/net/ethernet/sfc/falcon/tx.c index f6daf09b8627..f1520a404ac6 100644 --- a/drivers/net/ethernet/sfc/falcon/tx.c +++ b/drivers/net/ethernet/sfc/falcon/tx.c @@ -425,8 +425,8 @@ void ef4_init_tx_queue_core_txq(struct ef4_tx_queue *tx_queue) efx->n_tx_channels : 0)); } -int ef4_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto, - struct tc_to_netdev *ntc) +int ef4_setup_tc(struct net_device *net_dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *ntc) { struct ef4_nic *efx = netdev_priv(net_dev); struct ef4_channel *channel; diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 3bdf87f31087..02d41eb4a8e9 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -653,8 +653,8 @@ void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue) efx->n_tx_channels : 0)); } -int efx_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto, - struct tc_to_netdev *ntc) +int efx_setup_tc(struct net_device *net_dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *ntc) { struct efx_nic *efx = netdev_priv(net_dev); struct efx_channel *channel; diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index e6222e535019..9d52c3a78621 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -1877,8 +1877,8 @@ static u16 netcp_select_queue(struct net_device *dev, struct sk_buff *skb, return 0; } -static int netcp_setup_tc(struct net_device *dev, u32 handle, __be16 proto, - struct tc_to_netdev *tc) +static int netcp_setup_tc(struct net_device *dev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc) { u8 num_tc; int i; -- cgit v1.2.3 From eed29f17f09ad7f400bc245f209acad6a8214fac Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 7 Jun 2017 10:34:36 -0700 Subject: tcp: add a struct net parameter to tcp_parse_options() We want to move some TCP sysctls to net namespaces in the future. tcp_window_scaling, tcp_sack and tcp_timestamps being fetched from tcp_parse_options(), we need to pass an extra parameter. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb4/cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index b0ae4f0c8aa7..2f1136bf7b1f 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -3756,7 +3756,7 @@ static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos) */ memset(&tmp_opt, 0, sizeof(tmp_opt)); tcp_clear_options(&tmp_opt); - tcp_parse_options(skb, &tmp_opt, 0, NULL); + tcp_parse_options(&init_net, skb, &tmp_opt, 0, NULL); req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); -- cgit v1.2.3 From 02417f47875c2a22d2a8c140c5b945c741005938 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 7 Jun 2017 15:15:01 -0500 Subject: mISDN: remove unnecessary variable assignments Remove unnecessary variable assignments. Addresses-Coverity-ID: 1226917 Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/mISDNipac.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index 6742b0dc0821..e240010b93fa 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -364,8 +364,8 @@ afterMONR1: WriteISAC(isac, ISAC_MOCR, isac->mocr); if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { if (isac->monitor) - ret = isac->monitor(isac->dch.hw, - MONITOR_TX_0, NULL, 0); + isac->monitor(isac->dch.hw, + MONITOR_TX_0, NULL, 0); } kfree(isac->mon_tx); isac->mon_tx = NULL; @@ -375,8 +375,8 @@ afterMONR1: } if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { if (isac->monitor) - ret = isac->monitor(isac->dch.hw, - MONITOR_TX_0, NULL, 0); + isac->monitor(isac->dch.hw, + MONITOR_TX_0, NULL, 0); kfree(isac->mon_tx); isac->mon_tx = NULL; isac->mon_txc = 0; @@ -397,8 +397,8 @@ AfterMOX0: WriteISAC(isac, ISAC_MOCR, isac->mocr); if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { if (isac->monitor) - ret = isac->monitor(isac->dch.hw, - MONITOR_TX_1, NULL, 0); + isac->monitor(isac->dch.hw, + MONITOR_TX_1, NULL, 0); } kfree(isac->mon_tx); isac->mon_tx = NULL; @@ -408,8 +408,8 @@ AfterMOX0: } if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) { if (isac->monitor) - ret = isac->monitor(isac->dch.hw, - MONITOR_TX_1, NULL, 0); + isac->monitor(isac->dch.hw, + MONITOR_TX_1, NULL, 0); kfree(isac->mon_tx); isac->mon_tx = NULL; isac->mon_txc = 0; -- cgit v1.2.3 From c91498e15bf2cf27fb2743d01bd105201f33a5cb Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 7 Jun 2017 18:12:13 -0400 Subject: net: dsa: mv88e6xxx: define membership on VLAN add Define the target port membership of the VLAN entry in mv88e6xxx_port_vlan_add where ds is scoped. Allow the DSA core to call later the port_vlan_add operation for CPU or DSA ports, by using the Unmodified membership for these ports, as in the current behavior. Reviewed-by: Florian Fainelli Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 44c87027623b..962b4e873bf9 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1274,7 +1274,7 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, } static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port, - u16 vid, bool untagged) + u16 vid, u8 member) { struct mv88e6xxx_vtu_entry vlan; int err; @@ -1283,9 +1283,7 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port, if (err) return err; - vlan.member[port] = untagged ? - GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED : - GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED; + vlan.member[port] = member; return mv88e6xxx_vtu_loadpurge(chip, &vlan); } @@ -1297,15 +1295,23 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, struct mv88e6xxx_chip *chip = ds->priv; bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + u8 member; u16 vid; if (!chip->info->max_vid) return; + if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) + member = GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED; + else if (untagged) + member = GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED; + else + member = GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED; + mutex_lock(&chip->reg_lock); for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) - if (_mv88e6xxx_port_vlan_add(chip, port, vid, untagged)) + if (_mv88e6xxx_port_vlan_add(chip, port, vid, member)) netdev_err(ds->ports[port].netdev, "failed to add VLAN %d%c\n", vid, untagged ? 'u' : 't'); -- cgit v1.2.3 From 553a768dea1d113f467fb45bb26c4bb3d6b643c4 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 7 Jun 2017 18:12:16 -0400 Subject: net: dsa: mv88e6xxx: exclude all ports in new VLAN Now that the DSA core adds the CPU and DSA ports itself to the new VLAN entry, there is no need to include them as members of this VLAN when initializing a new VTU entry. As of now, initialize a new VTU entry with all ports excluded. Reviewed-by: Florian Fainelli Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 962b4e873bf9..41202b1d6d7f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1159,11 +1159,10 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, entry->valid = true; entry->vid = vid; - /* Include only CPU and DSA ports */ + /* Exclude all ports */ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) - entry->member[i] = dsa_is_normal_port(chip->ds, i) ? - GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER : - GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED; + entry->member[i] = + GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; return mv88e6xxx_atu_new(chip, &entry->fid); } -- cgit v1.2.3 From adc3a9ce853cc4a8563ab2d08351bced8cd7d524 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 7 Jun 2017 18:12:17 -0400 Subject: net: dsa: mv88e6xxx: do not skip ports on VLAN del The mv88e6xxx driver currently tries to be smart and remove by itself a VLAN entry from the VTU when the driven switch sees no user ports as members of the VLAN. This is bad in a multi-chip switch fabric, since a chip in between others may have no bridge port members, but still needs to be aware of the VID in order to correctly pass frames in the data path. Now that the DSA core explicitly manages DSA and CPU ports, do not skip them when checking remaining VLAN members. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 41202b1d6d7f..0534eb706caa 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1325,7 +1325,6 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip, int port, u16 vid) { - struct dsa_switch *ds = chip->ds; struct mv88e6xxx_vtu_entry vlan; int i, err; @@ -1342,9 +1341,6 @@ static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip, /* keep the VLAN unless all ports are excluded */ vlan.valid = false; for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { - if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i)) - continue; - if (vlan.member[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) { vlan.valid = true; break; -- cgit v1.2.3 From 6b26b51b1d13c62a09f55d745b06a8e964900715 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:14 +0200 Subject: net: bridge: Add support for notifying devices about FDB add/del Currently the bridge doesn't notify the underlying devices about new FDBs learned. The FDB sync is placed on the switchdev notifier chain because devices may potentially learn FDB that are not directly related to their ports, for example: 1. Mixed SW/HW bridge - FDBs that point to the ASICs external devices should be offloaded as CPU traps in order to perform forwarding in slow path. 2. EVPN - Externally learned FDBs for the vtep device. Notification is sent only about static FDB add/del. This is done due to fact that currently this is the only scenario supported by switch drivers. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Reviewed-by: Nikolay Aleksandrov Reviewed-by: Ivan Vecera Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 2 +- drivers/net/ethernet/rocker/rocker_ofdpa.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index edcc273d7597..0111a77c36e8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1867,7 +1867,7 @@ static void mlxsw_sp_fdb_call_notifiers(bool learning_sync, bool adding, if (learning_sync) { info.addr = mac; info.vid = vid; - notifier_type = adding ? SWITCHDEV_FDB_ADD : SWITCHDEV_FDB_DEL; + notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; call_switchdev_notifiers(notifier_type, dev, &info.info); } } diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 2ae852454780..f659dad818e2 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -1939,10 +1939,10 @@ static void ofdpa_port_fdb_learn_work(struct work_struct *work) rtnl_lock(); if (learned && removing) - call_switchdev_notifiers(SWITCHDEV_FDB_DEL, + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, lw->ofdpa_port->dev, &info.info); else if (learned && !removing) - call_switchdev_notifiers(SWITCHDEV_FDB_ADD, + call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, lw->ofdpa_port->dev, &info.info); rtnl_unlock(); -- cgit v1.2.3 From a989cdb473c2fd9cd0187fa9f7da8e4a7c989332 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:16 +0200 Subject: mlxsw: spectrum: Remove support for bridge FDB learning sync Currently the mlxsw driver supports an option for disabling syncing the hardware learned FDBs with the software bridge. This behavior breaks the bridge offload model and thus it is removed. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 0111a77c36e8..eb88b721d2f7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1857,19 +1857,17 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port); } -static void mlxsw_sp_fdb_call_notifiers(bool learning_sync, bool adding, +static void mlxsw_sp_fdb_call_notifiers(bool adding, char *mac, u16 vid, struct net_device *dev) { struct switchdev_notifier_fdb_info info; unsigned long notifier_type; - if (learning_sync) { - info.addr = mac; - info.vid = vid; - notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; - call_switchdev_notifiers(notifier_type, dev, &info.info); - } + info.addr = mac; + info.vid = vid; + notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; + call_switchdev_notifiers(notifier_type, dev, &info.info); } static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, @@ -1918,8 +1916,8 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(bridge_port->flags & BR_LEARNING_SYNC, - adding, mac, vid, bridge_port->dev); + mlxsw_sp_fdb_call_notifiers(adding, mac, vid, bridge_port->dev); + return; just_remove: @@ -1976,8 +1974,8 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(bridge_port->flags & BR_LEARNING_SYNC, - adding, mac, vid, bridge_port->dev); + mlxsw_sp_fdb_call_notifiers(adding, mac, vid, bridge_port->dev); + return; just_remove: -- cgit v1.2.3 From c7b566cd2e7433785c8879b004940de3793901e1 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:17 +0200 Subject: mlxsw: spectrum_switchdev: Add support for querying supported bridge flags Add support for querying supported bridge flags. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index eb88b721d2f7..033349364a6d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -456,6 +456,9 @@ static int mlxsw_sp_port_attr_get(struct net_device *dev, mlxsw_sp_port_bridge_flags_get(mlxsw_sp->bridge, attr->orig_dev, &attr->u.brport_flags); break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT: + attr->u.brport_flags_support = BR_LEARNING | BR_FLOOD; + break; default: return -EOPNOTSUPP; } -- cgit v1.2.3 From 10e23eb299fa39c6f343bffc9e3d77c7d9f0492f Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:18 +0200 Subject: mlxsw: spectrum: Remove support for bypass bridge port attributes/vlan set The bridge port attributes/vlan for mlxsw devices should be set only from bridge code. The vlans are synced totally with the bridge so there is no need to special dump support. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 3 -- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 41 ---------------------- 2 files changed, 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index a2316d038810..db7127abce44 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1759,9 +1759,6 @@ static const struct net_device_ops mlxsw_sp_port_netdev_ops = { .ndo_fdb_add = switchdev_port_fdb_add, .ndo_fdb_del = switchdev_port_fdb_del, .ndo_fdb_dump = switchdev_port_fdb_dump, - .ndo_bridge_setlink = switchdev_port_bridge_setlink, - .ndo_bridge_getlink = switchdev_port_bridge_getlink, - .ndo_bridge_dellink = switchdev_port_bridge_dellink, .ndo_get_phys_port_name = mlxsw_sp_port_get_phys_port_name, }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 033349364a6d..6257b0b8c8d1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -102,8 +102,6 @@ struct mlxsw_sp_bridge_vlan { struct list_head list; struct list_head port_vlan_list; u16 vid; - u8 egress_untagged:1, - pvid:1; }; struct mlxsw_sp_bridge_ops { @@ -1003,8 +1001,6 @@ mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port, goto err_port_vlan_bridge_join; bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); - bridge_vlan->egress_untagged = is_untagged; - bridge_vlan->pvid = is_pvid; return 0; @@ -1629,39 +1625,6 @@ out: return stored_err ? stored_err : err; } -static int mlxsw_sp_port_vlan_dump(struct mlxsw_sp_port *mlxsw_sp_port, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct net_device *orig_dev = vlan->obj.orig_dev; - struct mlxsw_sp_bridge_port *bridge_port; - struct mlxsw_sp_bridge_vlan *bridge_vlan; - int err = 0; - - bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); - if (WARN_ON(!bridge_port)) - return -EINVAL; - - if (!bridge_port->bridge_device->vlan_enabled) - return 0; - - list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { - vlan->flags = 0; - if (bridge_vlan->pvid) - vlan->flags |= BRIDGE_VLAN_INFO_PVID; - if (bridge_vlan->egress_untagged) - vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; - vlan->vid_begin = bridge_vlan->vid; - vlan->vid_end = bridge_vlan->vid; - err = cb(&vlan->obj); - if (err) - break; - } - - return err; -} - static int mlxsw_sp_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb) @@ -1670,10 +1633,6 @@ static int mlxsw_sp_port_obj_dump(struct net_device *dev, int err = 0; switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = mlxsw_sp_port_vlan_dump(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_VLAN(obj), cb); - break; case SWITCHDEV_OBJ_ID_PORT_FDB: err = mlxsw_sp_port_fdb_dump(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_FDB(obj), cb); -- cgit v1.2.3 From 1b40dc3d86724c7f1e69d20020ffa4eb21d119ae Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:19 +0200 Subject: mlxsw: spectrum_switchdev: Change switchdev notifier API The current API for sending switchdev notifications implies only FDB add/del. In order to support notification about successful FDB offload the API is changed. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 6257b0b8c8d1..0b50d1d2b517 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1819,17 +1819,16 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port); } -static void mlxsw_sp_fdb_call_notifiers(bool adding, - char *mac, u16 vid, - struct net_device *dev) +static void +mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type, + const char *mac, u16 vid, + struct net_device *dev) { struct switchdev_notifier_fdb_info info; - unsigned long notifier_type; info.addr = mac; info.vid = vid; - notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; - call_switchdev_notifiers(notifier_type, dev, &info.info); + call_switchdev_notifiers(type, dev, &info.info); } static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, @@ -1840,6 +1839,7 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_bridge_device *bridge_device; struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_port *mlxsw_sp_port; + enum switchdev_notifier_type type; char mac[ETH_ALEN]; u8 local_port; u16 vid, fid; @@ -1878,7 +1878,8 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(adding, mac, vid, bridge_port->dev); + type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; + mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev); return; @@ -1896,6 +1897,7 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_bridge_device *bridge_device; struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_port *mlxsw_sp_port; + enum switchdev_notifier_type type; char mac[ETH_ALEN]; u16 lag_vid = 0; u16 lag_id; @@ -1936,7 +1938,8 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(adding, mac, vid, bridge_port->dev); + type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; + mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev); return; -- cgit v1.2.3 From af061378924f6d2f368b3769fd59fd95875dc942 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:20 +0200 Subject: mlxsw: spectrum_switchdev: Add support for learning FDB through notification Add support for learning FDB through notification. The driver defers the hardware update via ordered work queue. Support for stacked devices is also provided. In case of a successful FDB add a notification is sent back to bridge. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 + .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 137 +++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index db7127abce44..581cb99daec6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3706,7 +3706,7 @@ struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev) return mlxsw_sp_port ? mlxsw_sp_port->mlxsw_sp : NULL; } -static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev) +struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev) { struct mlxsw_sp_port *mlxsw_sp_port; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 4a7a39a9f1a1..5ef98d4d0ab6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -361,6 +361,7 @@ struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev); struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev); struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); +struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev); /* spectrum_dcb.c */ #ifdef CONFIG_MLXSW_SPECTRUM_DCB diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 0b50d1d2b517..0297c136d040 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1181,6 +1181,43 @@ mlxsw_sp_port_fdb_static_add(struct mlxsw_sp_port *mlxsw_sp_port, true, false); } +static int +mlxsw_sp_port_fdb_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct switchdev_notifier_fdb_info *fdb_info, bool adding) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct net_device *orig_dev = fdb_info->info.dev; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + struct mlxsw_sp_bridge_device *bridge_device; + struct mlxsw_sp_bridge_port *bridge_port; + u16 fid_index, vid; + + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); + if (!bridge_port) + return -EINVAL; + + bridge_device = bridge_port->bridge_device; + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, + bridge_device, + fdb_info->vid); + if (!mlxsw_sp_port_vlan) + return 0; + + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); + vid = mlxsw_sp_port_vlan->vid; + + if (!bridge_port->lagged) + return mlxsw_sp_port_fdb_uc_op(mlxsw_sp, + bridge_port->system_port, + fdb_info->addr, fid_index, + adding, false); + else + return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, + bridge_port->lag_id, + fdb_info->addr, fid_index, + vid, adding, false); +} + static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, u16 fid, u16 mid, bool adding) { @@ -2013,6 +2050,97 @@ out: mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); } +struct mlxsw_sp_switchdev_event_work { + struct work_struct work; + struct switchdev_notifier_fdb_info fdb_info; + struct net_device *dev; + unsigned long event; +}; + +static void mlxsw_sp_switchdev_event_work(struct work_struct *work) +{ + struct mlxsw_sp_switchdev_event_work *switchdev_work = + container_of(work, struct mlxsw_sp_switchdev_event_work, work); + struct net_device *dev = switchdev_work->dev; + struct switchdev_notifier_fdb_info *fdb_info; + struct mlxsw_sp_port *mlxsw_sp_port; + int err; + + rtnl_lock(); + mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev); + if (!mlxsw_sp_port) + goto out; + + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + fdb_info = &switchdev_work->fdb_info; + err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true); + if (err) + break; + mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, + fdb_info->addr, + fdb_info->vid, dev); + break; + case SWITCHDEV_FDB_DEL_TO_DEVICE: + fdb_info = &switchdev_work->fdb_info; + mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, false); + break; + } + +out: + rtnl_unlock(); + kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); + dev_put(dev); +} + +/* Called under rcu_read_lock() */ +static int mlxsw_sp_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + struct mlxsw_sp_switchdev_event_work *switchdev_work; + struct switchdev_notifier_fdb_info *fdb_info = ptr; + + if (!mlxsw_sp_port_dev_lower_find_rcu(dev)) + return NOTIFY_DONE; + + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (!switchdev_work) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, mlxsw_sp_switchdev_event_work); + switchdev_work->dev = dev; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */ + case SWITCHDEV_FDB_DEL_TO_DEVICE: + memcpy(&switchdev_work->fdb_info, ptr, + sizeof(switchdev_work->fdb_info)); + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, + fdb_info->addr); + /* Take a reference on the device. This can be either + * upper device containig mlxsw_sp_port or just a + * mlxsw_sp_port + */ + dev_hold(dev); + break; + default: + kfree(switchdev_work); + return NOTIFY_DONE; + } + + mlxsw_core_schedule_work(&switchdev_work->work); + + return NOTIFY_DONE; +} + +static struct notifier_block mlxsw_sp_switchdev_notifier = { + .notifier_call = mlxsw_sp_switchdev_event, +}; + static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) { struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge; @@ -2023,6 +2151,13 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n"); return err; } + + err = register_switchdev_notifier(&mlxsw_sp_switchdev_notifier); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Failed to register switchdev notifier\n"); + return err; + } + INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work); bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL; mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); @@ -2032,6 +2167,8 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp) { cancel_delayed_work_sync(&mlxsw_sp->bridge->fdb_notify.dw); + unregister_switchdev_notifier(&mlxsw_sp_switchdev_notifier); + } int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp) -- cgit v1.2.3 From be7432b952bcbe2d7ac27a9f8545cce4cc74a4df Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:21 +0200 Subject: mlxsw: spectrum: Remove support for bridge bypass FDB add/del The FDB add/del are now done through the notification chain. The FDBs are synced with the bridge and there is no need for extra dumping. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 3 - .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 200 --------------------- 2 files changed, 203 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 581cb99daec6..ecc73525529d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1756,9 +1756,6 @@ static const struct net_device_ops mlxsw_sp_port_netdev_ops = { .ndo_get_offload_stats = mlxsw_sp_port_get_offload_stats, .ndo_vlan_rx_add_vid = mlxsw_sp_port_add_vid, .ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid, - .ndo_fdb_add = switchdev_port_fdb_add, - .ndo_fdb_del = switchdev_port_fdb_del, - .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_get_phys_port_name = mlxsw_sp_port_get_phys_port_name, }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 0297c136d040..cd89a3e6cd81 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1140,47 +1140,6 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, return err; } -static int -mlxsw_sp_port_fdb_static_add(struct mlxsw_sp_port *mlxsw_sp_port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct net_device *orig_dev = fdb->obj.orig_dev; - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_bridge_device *bridge_device; - struct mlxsw_sp_bridge_port *bridge_port; - u16 fid_index, vid; - - if (switchdev_trans_ph_prepare(trans)) - return 0; - - bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); - if (WARN_ON(!bridge_port)) - return -EINVAL; - - bridge_device = bridge_port->bridge_device; - mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, - bridge_device, - fdb->vid); - if (!mlxsw_sp_port_vlan) - return 0; - - fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); - vid = mlxsw_sp_port_vlan->vid; - - if (!mlxsw_sp_port->lagged) - return mlxsw_sp_port_fdb_uc_op(mlxsw_sp, - mlxsw_sp_port->local_port, - fdb->addr, fid_index, true, - false); - else - return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, - mlxsw_sp_port->lag_id, - fdb->addr, fid_index, vid, - true, false); -} - static int mlxsw_sp_port_fdb_set(struct mlxsw_sp_port *mlxsw_sp_port, struct switchdev_notifier_fdb_info *fdb_info, bool adding) @@ -1385,11 +1344,6 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, SWITCHDEV_OBJ_PORT_VLAN(obj), trans); break; - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = mlxsw_sp_port_fdb_static_add(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_FDB(obj), - trans); - break; case SWITCHDEV_OBJ_ID_PORT_MDB: err = mlxsw_sp_port_mdb_add(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_MDB(obj), @@ -1441,43 +1395,6 @@ static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, return 0; } -static int -mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port, - const struct switchdev_obj_port_fdb *fdb) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct net_device *orig_dev = fdb->obj.orig_dev; - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_bridge_device *bridge_device; - struct mlxsw_sp_bridge_port *bridge_port; - u16 fid_index, vid; - - bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); - if (WARN_ON(!bridge_port)) - return -EINVAL; - - bridge_device = bridge_port->bridge_device; - mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, - bridge_device, - fdb->vid); - if (!mlxsw_sp_port_vlan) - return 0; - - fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); - vid = mlxsw_sp_port_vlan->vid; - - if (!mlxsw_sp_port->lagged) - return mlxsw_sp_port_fdb_uc_op(mlxsw_sp, - mlxsw_sp_port->local_port, - fdb->addr, fid_index, false, - false); - else - return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, - mlxsw_sp_port->lag_id, - fdb->addr, fid_index, vid, - false, false); -} - static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_mdb *mdb) { @@ -1537,10 +1454,6 @@ static int mlxsw_sp_port_obj_del(struct net_device *dev, err = mlxsw_sp_port_vlans_del(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_VLAN(obj)); break; - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = mlxsw_sp_port_fdb_static_del(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_FDB(obj)); - break; case SWITCHDEV_OBJ_ID_PORT_MDB: err = mlxsw_sp_port_mdb_del(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_MDB(obj)); @@ -1570,124 +1483,11 @@ static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp, return NULL; } -static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct net_device *orig_dev = fdb->obj.orig_dev; - struct mlxsw_sp_bridge_port *bridge_port; - u16 lag_id, fid_index; - char mac[ETH_ALEN]; - int stored_err = 0; - char *sfd_pl; - u8 num_rec; - int err; - - bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); - if (!bridge_port) - return 0; - - sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); - if (!sfd_pl) - return -ENOMEM; - - mlxsw_reg_sfd_pack(sfd_pl, MLXSW_REG_SFD_OP_QUERY_DUMP, 0); - do { - struct mlxsw_sp_port *tmp; - u8 local_port; - int i; - - mlxsw_reg_sfd_num_rec_set(sfd_pl, MLXSW_REG_SFD_REC_MAX_COUNT); - err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); - if (err) - goto out; - - num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); - - /* Even in case of error, we have to run the dump to the end - * so the session in firmware is finished. - */ - if (stored_err) - continue; - - for (i = 0; i < num_rec; i++) { - switch (mlxsw_reg_sfd_rec_type_get(sfd_pl, i)) { - case MLXSW_REG_SFD_REC_TYPE_UNICAST: - mlxsw_reg_sfd_uc_unpack(sfd_pl, i, mac, - &fid_index, - &local_port); - if (bridge_port->lagged) - continue; - if (bridge_port->system_port != local_port) - continue; - if (bridge_port->bridge_device->vlan_enabled) - fdb->vid = fid_index; - else - fdb->vid = 0; - ether_addr_copy(fdb->addr, mac); - fdb->ndm_state = NUD_REACHABLE; - err = cb(&fdb->obj); - if (err) - stored_err = err; - break; - case MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG: - mlxsw_reg_sfd_uc_lag_unpack(sfd_pl, i, - mac, &fid_index, - &lag_id); - if (!bridge_port->lagged) - continue; - if (bridge_port->lag_id != lag_id) - continue; - tmp = mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id); - if (tmp->local_port != - mlxsw_sp_port->local_port) - continue; - if (bridge_port->bridge_device->vlan_enabled) - fdb->vid = fid_index; - else - fdb->vid = 0; - ether_addr_copy(fdb->addr, mac); - fdb->ndm_state = NUD_REACHABLE; - err = cb(&fdb->obj); - if (err) - stored_err = err; - break; - } - } - } while (num_rec == MLXSW_REG_SFD_REC_MAX_COUNT); - -out: - kfree(sfd_pl); - return stored_err ? stored_err : err; -} - -static int mlxsw_sp_port_obj_dump(struct net_device *dev, - struct switchdev_obj *obj, - switchdev_obj_dump_cb_t *cb) -{ - struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); - int err = 0; - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = mlxsw_sp_port_fdb_dump(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_FDB(obj), cb); - break; - default: - err = -EOPNOTSUPP; - break; - } - - return err; -} - static const struct switchdev_ops mlxsw_sp_port_switchdev_ops = { .switchdev_port_attr_get = mlxsw_sp_port_attr_get, .switchdev_port_attr_set = mlxsw_sp_port_attr_set, .switchdev_port_obj_add = mlxsw_sp_port_obj_add, .switchdev_port_obj_del = mlxsw_sp_port_obj_del, - .switchdev_port_obj_dump = mlxsw_sp_port_obj_dump, }; static int -- cgit v1.2.3 From eca59f691566ca4dacfe78714108dd98043e3d0b Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:22 +0200 Subject: net: Remove support for bridge bypass ndos from stacked devices Remove support for bridge bypass ndos from stacked devices. At this point no driver which supports stack device behavior offload supports operation with SELF flag. The case for upper device is already taken care of in both of the following cases: 1. FDB add/del - driver should check at the notification cb if the stacked device contains his ports. 2. Port attribute - calls switchdev code directly which checks for case of stack device. Signed-off-by: Arkadi Sharshevsky Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 6 ------ drivers/net/team/team.c | 6 ------ 2 files changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d4484d1a8164..7d9474352c36 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4175,12 +4175,6 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_add_slave = bond_enslave, .ndo_del_slave = bond_release, .ndo_fix_features = bond_fix_features, - .ndo_bridge_setlink = switchdev_port_bridge_setlink, - .ndo_bridge_getlink = switchdev_port_bridge_getlink, - .ndo_bridge_dellink = switchdev_port_bridge_dellink, - .ndo_fdb_add = switchdev_port_fdb_add, - .ndo_fdb_del = switchdev_port_fdb_del, - .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_features_check = passthru_features_check, }; diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 6c5d5ef46f75..a3ec1892a286 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2005,12 +2005,6 @@ static const struct net_device_ops team_netdev_ops = { .ndo_del_slave = team_del_slave, .ndo_fix_features = team_fix_features, .ndo_change_carrier = team_change_carrier, - .ndo_bridge_setlink = switchdev_port_bridge_setlink, - .ndo_bridge_getlink = switchdev_port_bridge_getlink, - .ndo_bridge_dellink = switchdev_port_bridge_dellink, - .ndo_fdb_add = switchdev_port_fdb_add, - .ndo_fdb_del = switchdev_port_fdb_del, - .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_features_check = passthru_features_check, }; -- cgit v1.2.3 From 8cc186a4856b6ef4e54c3464e67ca2e1b79d20aa Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:23 +0200 Subject: rocker: Remove support for bridge FDB learning sync Currently the rocker driver supports an option for disabling syncing the hardware learned FDBs with the software bridge. This behavior breaks the bridge offload model and thus it is removed. Signed-off-by: Arkadi Sharshevsky Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker_ofdpa.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index f659dad818e2..0b5a58fee9bf 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -1959,7 +1959,6 @@ static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port, u32 out_pport = ofdpa_port->pport; u32 tunnel_id = 0; u32 group_id = ROCKER_GROUP_NONE; - bool syncing = !!(ofdpa_port->brport_flags & BR_LEARNING_SYNC); bool copy_to_cpu = false; int err; @@ -1974,9 +1973,6 @@ static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port, return err; } - if (!syncing) - return 0; - if (!ofdpa_port_is_bridged(ofdpa_port)) return 0; @@ -2550,7 +2546,7 @@ static int ofdpa_port_pre_init(struct rocker_port *rocker_port) ofdpa_port->rocker_port = rocker_port; ofdpa_port->dev = rocker_port->dev; ofdpa_port->pport = rocker_port->pport; - ofdpa_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC; + ofdpa_port->brport_flags = BR_LEARNING; ofdpa_port->ageing_time = BR_DEFAULT_AGEING_TIME; return 0; } -- cgit v1.2.3 From 96673a30440a60559a63a16a6e7eb4ced02d7fe9 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:24 +0200 Subject: rocker: Add support for querying supported bridge flags Add support for querying supported bridge flags. Signed-off-by: Arkadi Sharshevsky Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.h | 4 ++++ drivers/net/ethernet/rocker/rocker_main.c | 18 ++++++++++++++++++ drivers/net/ethernet/rocker/rocker_ofdpa.c | 11 +++++++++++ 3 files changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index ee9675db5bf9..c25e331f2061 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -112,6 +112,10 @@ struct rocker_world_ops { struct switchdev_trans *trans); int (*port_attr_bridge_flags_get)(const struct rocker_port *rocker_port, unsigned long *p_brport_flags); + int (*port_attr_bridge_flags_support_get)(const struct rocker_port * + rocker_port, + unsigned long * + p_brport_flags); int (*port_attr_bridge_ageing_time_set)(struct rocker_port *rocker_port, u32 ageing_time, struct switchdev_trans *trans); diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index bab13613b138..a741e5163d04 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -1584,6 +1584,20 @@ rocker_world_port_attr_bridge_flags_get(const struct rocker_port *rocker_port, return wops->port_attr_bridge_flags_get(rocker_port, p_brport_flags); } +static int +rocker_world_port_attr_bridge_flags_support_get(const struct rocker_port * + rocker_port, + unsigned long * + p_brport_flags_support) +{ + struct rocker_world_ops *wops = rocker_port->rocker->wops; + + if (!wops->port_attr_bridge_flags_support_get) + return -EOPNOTSUPP; + return wops->port_attr_bridge_flags_support_get(rocker_port, + p_brport_flags_support); +} + static int rocker_world_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, u32 ageing_time, @@ -2053,6 +2067,10 @@ static int rocker_port_attr_get(struct net_device *dev, err = rocker_world_port_attr_bridge_flags_get(rocker_port, &attr->u.brport_flags); break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT: + err = rocker_world_port_attr_bridge_flags_support_get(rocker_port, + &attr->u.brport_flags_support); + break; default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 0b5a58fee9bf..7528ee7453f5 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -2642,6 +2642,16 @@ ofdpa_port_attr_bridge_flags_get(const struct rocker_port *rocker_port, return 0; } +static int +ofdpa_port_attr_bridge_flags_support_get(const struct rocker_port * + rocker_port, + unsigned long * + p_brport_flags_support) +{ + *p_brport_flags_support = BR_LEARNING; + return 0; +} + static int ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, u32 ageing_time, @@ -2989,6 +2999,7 @@ struct rocker_world_ops rocker_ofdpa_ops = { .port_attr_stp_state_set = ofdpa_port_attr_stp_state_set, .port_attr_bridge_flags_set = ofdpa_port_attr_bridge_flags_set, .port_attr_bridge_flags_get = ofdpa_port_attr_bridge_flags_get, + .port_attr_bridge_flags_support_get = ofdpa_port_attr_bridge_flags_support_get, .port_attr_bridge_ageing_time_set = ofdpa_port_attr_bridge_ageing_time_set, .port_obj_vlan_add = ofdpa_port_obj_vlan_add, .port_obj_vlan_del = ofdpa_port_obj_vlan_del, -- cgit v1.2.3 From 00fc0c51e35b783f6542d14a30a5de1ce6549887 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:25 +0200 Subject: rocker: Change world_ops API and implementation to be switchdev independant Currently the switchdev_trans struct is embedded in the world_ops API. In order to add support for adding FDB via a notfication chain the API should be switchdev independent. Signed-off-by: Arkadi Sharshevsky Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.h | 11 +- drivers/net/ethernet/rocker/rocker_main.c | 28 +- drivers/net/ethernet/rocker/rocker_ofdpa.c | 535 +++++++++++------------------ 3 files changed, 235 insertions(+), 339 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index c25e331f2061..a0f7782ddfdd 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -105,8 +105,7 @@ struct rocker_world_ops { int (*port_open)(struct rocker_port *rocker_port); void (*port_stop)(struct rocker_port *rocker_port); int (*port_attr_stp_state_set)(struct rocker_port *rocker_port, - u8 state, - struct switchdev_trans *trans); + u8 state); int (*port_attr_bridge_flags_set)(struct rocker_port *rocker_port, unsigned long brport_flags, struct switchdev_trans *trans); @@ -120,18 +119,16 @@ struct rocker_world_ops { u32 ageing_time, struct switchdev_trans *trans); int (*port_obj_vlan_add)(struct rocker_port *rocker_port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans); + const struct switchdev_obj_port_vlan *vlan); int (*port_obj_vlan_del)(struct rocker_port *rocker_port, const struct switchdev_obj_port_vlan *vlan); int (*port_obj_vlan_dump)(const struct rocker_port *rocker_port, struct switchdev_obj_port_vlan *vlan, switchdev_obj_dump_cb_t *cb); int (*port_obj_fdb_add)(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans); + u16 vid, const unsigned char *addr); int (*port_obj_fdb_del)(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb); + u16 vid, const unsigned char *addr); int (*port_obj_fdb_dump)(const struct rocker_port *rocker_port, struct switchdev_obj_port_fdb *fdb, switchdev_obj_dump_cb_t *cb); diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index a741e5163d04..9f0154dc2cf7 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -1557,7 +1557,11 @@ static int rocker_world_port_attr_stp_state_set(struct rocker_port *rocker_port, if (!wops->port_attr_stp_state_set) return -EOPNOTSUPP; - return wops->port_attr_stp_state_set(rocker_port, state, trans); + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + return wops->port_attr_stp_state_set(rocker_port, state); } static int @@ -1569,6 +1573,10 @@ rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port, if (!wops->port_attr_bridge_flags_set) return -EOPNOTSUPP; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + return wops->port_attr_bridge_flags_set(rocker_port, brport_flags, trans); } @@ -1608,6 +1616,10 @@ rocker_world_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, if (!wops->port_attr_bridge_ageing_time_set) return -EOPNOTSUPP; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + return wops->port_attr_bridge_ageing_time_set(rocker_port, ageing_time, trans); } @@ -1621,7 +1633,11 @@ rocker_world_port_obj_vlan_add(struct rocker_port *rocker_port, if (!wops->port_obj_vlan_add) return -EOPNOTSUPP; - return wops->port_obj_vlan_add(rocker_port, vlan, trans); + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + return wops->port_obj_vlan_add(rocker_port, vlan); } static int @@ -1656,7 +1672,11 @@ rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port, if (!wops->port_obj_fdb_add) return -EOPNOTSUPP; - return wops->port_obj_fdb_add(rocker_port, fdb, trans); + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + return wops->port_obj_fdb_add(rocker_port, fdb->vid, fdb->addr); } static int @@ -1667,7 +1687,7 @@ rocker_world_port_obj_fdb_del(struct rocker_port *rocker_port, if (!wops->port_obj_fdb_del) return -EOPNOTSUPP; - return wops->port_obj_fdb_del(rocker_port, fdb); + return wops->port_obj_fdb_del(rocker_port, fdb->vid, fdb->addr); } static int diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 7528ee7453f5..184a478fadab 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -300,64 +300,6 @@ static bool ofdpa_flags_nowait(int flags) return flags & OFDPA_OP_FLAG_NOWAIT; } -static void *__ofdpa_mem_alloc(struct switchdev_trans *trans, int flags, - size_t size) -{ - struct switchdev_trans_item *elem = NULL; - gfp_t gfp_flags = (flags & OFDPA_OP_FLAG_NOWAIT) ? - GFP_ATOMIC : GFP_KERNEL; - - /* If in transaction prepare phase, allocate the memory - * and enqueue it on a transaction. If in transaction - * commit phase, dequeue the memory from the transaction - * rather than re-allocating the memory. The idea is the - * driver code paths for prepare and commit are identical - * so the memory allocated in the prepare phase is the - * memory used in the commit phase. - */ - - if (!trans) { - elem = kzalloc(size + sizeof(*elem), gfp_flags); - } else if (switchdev_trans_ph_prepare(trans)) { - elem = kzalloc(size + sizeof(*elem), gfp_flags); - if (!elem) - return NULL; - switchdev_trans_item_enqueue(trans, elem, kfree, elem); - } else { - elem = switchdev_trans_item_dequeue(trans); - } - - return elem ? elem + 1 : NULL; -} - -static void *ofdpa_kzalloc(struct switchdev_trans *trans, int flags, - size_t size) -{ - return __ofdpa_mem_alloc(trans, flags, size); -} - -static void *ofdpa_kcalloc(struct switchdev_trans *trans, int flags, - size_t n, size_t size) -{ - return __ofdpa_mem_alloc(trans, flags, n * size); -} - -static void ofdpa_kfree(struct switchdev_trans *trans, const void *mem) -{ - struct switchdev_trans_item *elem; - - /* Frees are ignored if in transaction prepare phase. The - * memory remains on the per-port list until freed in the - * commit phase. - */ - - if (switchdev_trans_ph_prepare(trans)) - return; - - elem = (struct switchdev_trans_item *) mem - 1; - kfree(elem); -} - /************************************************************* * Flow, group, FDB, internal VLAN and neigh command prepares *************************************************************/ @@ -815,8 +757,7 @@ ofdpa_flow_tbl_find(const struct ofdpa *ofdpa, } static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - struct ofdpa_flow_tbl_entry *match) + int flags, struct ofdpa_flow_tbl_entry *match) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; struct ofdpa_flow_tbl_entry *found; @@ -831,9 +772,8 @@ static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port, if (found) { match->cookie = found->cookie; - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); - ofdpa_kfree(trans, found); + hash_del(&found->entry); + kfree(found); found = match; found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD; } else { @@ -842,22 +782,18 @@ static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port, found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD; } - if (!switchdev_trans_ph_prepare(trans)) - hash_add(ofdpa->flow_tbl, &found->entry, found->key_crc32); - + hash_add(ofdpa->flow_tbl, &found->entry, found->key_crc32); spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags); - if (!switchdev_trans_ph_prepare(trans)) - return rocker_cmd_exec(ofdpa_port->rocker_port, - ofdpa_flags_nowait(flags), - ofdpa_cmd_flow_tbl_add, - found, NULL, NULL); + return rocker_cmd_exec(ofdpa_port->rocker_port, + ofdpa_flags_nowait(flags), + ofdpa_cmd_flow_tbl_add, + found, NULL, NULL); return 0; } static int ofdpa_flow_tbl_del(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - struct ofdpa_flow_tbl_entry *match) + int flags, struct ofdpa_flow_tbl_entry *match) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; struct ofdpa_flow_tbl_entry *found; @@ -872,45 +808,41 @@ static int ofdpa_flow_tbl_del(struct ofdpa_port *ofdpa_port, found = ofdpa_flow_tbl_find(ofdpa, match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); + hash_del(&found->entry); found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL; } spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags); - ofdpa_kfree(trans, match); + kfree(match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - err = rocker_cmd_exec(ofdpa_port->rocker_port, - ofdpa_flags_nowait(flags), - ofdpa_cmd_flow_tbl_del, - found, NULL, NULL); - ofdpa_kfree(trans, found); + err = rocker_cmd_exec(ofdpa_port->rocker_port, + ofdpa_flags_nowait(flags), + ofdpa_cmd_flow_tbl_del, + found, NULL, NULL); + kfree(found); } return err; } -static int ofdpa_flow_tbl_do(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_flow_tbl_do(struct ofdpa_port *ofdpa_port, int flags, struct ofdpa_flow_tbl_entry *entry) { if (flags & OFDPA_OP_FLAG_REMOVE) - return ofdpa_flow_tbl_del(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_del(ofdpa_port, flags, entry); else - return ofdpa_flow_tbl_add(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_add(ofdpa_port, flags, entry); } -static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port, int flags, u32 in_pport, u32 in_pport_mask, enum rocker_of_dpa_table_id goto_tbl) { struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -920,11 +852,11 @@ static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port, entry->key.ig_port.in_pport_mask = in_pport_mask; entry->key.ig_port.goto_tbl = goto_tbl; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, + int flags, u32 in_pport, __be16 vlan_id, __be16 vlan_id_mask, enum rocker_of_dpa_table_id goto_tbl, @@ -932,7 +864,7 @@ static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port, { struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -946,11 +878,10 @@ static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port, entry->key.vlan.untagged = untagged; entry->key.vlan.new_vlan_id = new_vlan_id; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, u32 in_pport, u32 in_pport_mask, __be16 eth_type, const u8 *eth_dst, const u8 *eth_dst_mask, __be16 vlan_id, @@ -959,7 +890,7 @@ static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port, { struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -983,13 +914,13 @@ static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port, entry->key.term_mac.vlan_id_mask = vlan_id_mask; entry->key.term_mac.copy_to_cpu = copy_to_cpu; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - const u8 *eth_dst, const u8 *eth_dst_mask, - __be16 vlan_id, u32 tunnel_id, + int flags, const u8 *eth_dst, + const u8 *eth_dst_mask, __be16 vlan_id, + u32 tunnel_id, enum rocker_of_dpa_table_id goto_tbl, u32 group_id, bool copy_to_cpu) { @@ -999,7 +930,7 @@ static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port, bool dflt = !eth_dst || (eth_dst && eth_dst_mask); bool wild = false; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) return -ENOMEM; @@ -1037,11 +968,10 @@ static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port, entry->key.bridge.group_id = group_id; entry->key.bridge.copy_to_cpu = copy_to_cpu; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, __be16 eth_type, __be32 dst, __be32 dst_mask, u32 priority, enum rocker_of_dpa_table_id goto_tbl, @@ -1050,7 +980,7 @@ static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port, { struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1065,11 +995,10 @@ static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port, ucast_routing.group_id); entry->fi = fi; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } -static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, int flags, u32 in_pport, u32 in_pport_mask, const u8 *eth_src, const u8 *eth_src_mask, const u8 *eth_dst, const u8 *eth_dst_mask, @@ -1081,7 +1010,7 @@ static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, u32 priority; struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1116,7 +1045,7 @@ static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, entry->key.acl.ip_tos_mask = ip_tos_mask; entry->key.acl.group_id = group_id; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static struct ofdpa_group_tbl_entry * @@ -1134,22 +1063,20 @@ ofdpa_group_tbl_find(const struct ofdpa *ofdpa, return NULL; } -static void ofdpa_group_tbl_entry_free(struct switchdev_trans *trans, - struct ofdpa_group_tbl_entry *entry) +static void ofdpa_group_tbl_entry_free(struct ofdpa_group_tbl_entry *entry) { switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) { case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD: case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST: - ofdpa_kfree(trans, entry->group_ids); + kfree(entry->group_ids); break; default: break; } - ofdpa_kfree(trans, entry); + kfree(entry); } -static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, int flags, struct ofdpa_group_tbl_entry *match) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; @@ -1161,9 +1088,8 @@ static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, found = ofdpa_group_tbl_find(ofdpa, match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); - ofdpa_group_tbl_entry_free(trans, found); + hash_del(&found->entry); + ofdpa_group_tbl_entry_free(found); found = match; found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD; } else { @@ -1171,21 +1097,17 @@ static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD; } - if (!switchdev_trans_ph_prepare(trans)) - hash_add(ofdpa->group_tbl, &found->entry, found->group_id); + hash_add(ofdpa->group_tbl, &found->entry, found->group_id); spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags); - if (!switchdev_trans_ph_prepare(trans)) - return rocker_cmd_exec(ofdpa_port->rocker_port, - ofdpa_flags_nowait(flags), - ofdpa_cmd_group_tbl_add, - found, NULL, NULL); - return 0; + return rocker_cmd_exec(ofdpa_port->rocker_port, + ofdpa_flags_nowait(flags), + ofdpa_cmd_group_tbl_add, + found, NULL, NULL); } -static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port, int flags, struct ofdpa_group_tbl_entry *match) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; @@ -1198,97 +1120,90 @@ static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port, found = ofdpa_group_tbl_find(ofdpa, match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); + hash_del(&found->entry); found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL; } spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags); - ofdpa_group_tbl_entry_free(trans, match); + ofdpa_group_tbl_entry_free(match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - err = rocker_cmd_exec(ofdpa_port->rocker_port, - ofdpa_flags_nowait(flags), - ofdpa_cmd_group_tbl_del, - found, NULL, NULL); - ofdpa_group_tbl_entry_free(trans, found); + err = rocker_cmd_exec(ofdpa_port->rocker_port, + ofdpa_flags_nowait(flags), + ofdpa_cmd_group_tbl_del, + found, NULL, NULL); + ofdpa_group_tbl_entry_free(found); } return err; } -static int ofdpa_group_tbl_do(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_group_tbl_do(struct ofdpa_port *ofdpa_port, int flags, struct ofdpa_group_tbl_entry *entry) { if (flags & OFDPA_OP_FLAG_REMOVE) - return ofdpa_group_tbl_del(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_del(ofdpa_port, flags, entry); else - return ofdpa_group_tbl_add(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_add(ofdpa_port, flags, entry); } static int ofdpa_group_l2_interface(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - __be16 vlan_id, u32 out_pport, - int pop_vlan) + int flags, __be16 vlan_id, + u32 out_pport, int pop_vlan) { struct ofdpa_group_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport); entry->l2_interface.pop_vlan = pop_vlan; - return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_group_l2_fan_out(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, u8 group_count, const u32 *group_ids, u32 group_id) { struct ofdpa_group_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; entry->group_id = group_id; entry->group_count = group_count; - entry->group_ids = ofdpa_kcalloc(trans, flags, - group_count, sizeof(u32)); + entry->group_ids = kcalloc(flags, group_count, sizeof(u32)); if (!entry->group_ids) { - ofdpa_kfree(trans, entry); + kfree(entry); return -ENOMEM; } memcpy(entry->group_ids, group_ids, group_count * sizeof(u32)); - return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_group_l2_flood(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - __be16 vlan_id, u8 group_count, - const u32 *group_ids, u32 group_id) + int flags, __be16 vlan_id, + u8 group_count, const u32 *group_ids, + u32 group_id) { - return ofdpa_group_l2_fan_out(ofdpa_port, trans, flags, + return ofdpa_group_l2_fan_out(ofdpa_port, flags, group_count, group_ids, group_id); } -static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port, int flags, u32 index, const u8 *src_mac, const u8 *dst_mac, __be16 vlan_id, bool ttl_check, u32 pport) { struct ofdpa_group_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1301,7 +1216,7 @@ static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port, entry->l3_unicast.ttl_check = ttl_check; entry->l3_unicast.group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, pport); - return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_do(ofdpa_port, flags, entry); } static struct ofdpa_neigh_tbl_entry * @@ -1318,43 +1233,34 @@ ofdpa_neigh_tbl_find(const struct ofdpa *ofdpa, __be32 ip_addr) } static void ofdpa_neigh_add(struct ofdpa *ofdpa, - struct switchdev_trans *trans, struct ofdpa_neigh_tbl_entry *entry) { - if (!switchdev_trans_ph_commit(trans)) - entry->index = ofdpa->neigh_tbl_next_index++; - if (switchdev_trans_ph_prepare(trans)) - return; + entry->index = ofdpa->neigh_tbl_next_index++; entry->ref_count++; hash_add(ofdpa->neigh_tbl, &entry->entry, be32_to_cpu(entry->ip_addr)); } -static void ofdpa_neigh_del(struct switchdev_trans *trans, - struct ofdpa_neigh_tbl_entry *entry) +static void ofdpa_neigh_del(struct ofdpa_neigh_tbl_entry *entry) { - if (switchdev_trans_ph_prepare(trans)) - return; if (--entry->ref_count == 0) { hash_del(&entry->entry); - ofdpa_kfree(trans, entry); + kfree(entry); } } static void ofdpa_neigh_update(struct ofdpa_neigh_tbl_entry *entry, - struct switchdev_trans *trans, const u8 *eth_dst, bool ttl_check) { if (eth_dst) { ether_addr_copy(entry->eth_dst, eth_dst); entry->ttl_check = ttl_check; - } else if (!switchdev_trans_ph_prepare(trans)) { + } else { entry->ref_count++; } } static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, __be32 ip_addr, const u8 *eth_dst) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; @@ -1371,7 +1277,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, bool removing; int err = 0; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1388,12 +1294,12 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, entry->dev = ofdpa_port->dev; ether_addr_copy(entry->eth_dst, eth_dst); entry->ttl_check = true; - ofdpa_neigh_add(ofdpa, trans, entry); + ofdpa_neigh_add(ofdpa, entry); } else if (removing) { memcpy(entry, found, sizeof(*entry)); - ofdpa_neigh_del(trans, found); + ofdpa_neigh_del(found); } else if (updating) { - ofdpa_neigh_update(found, trans, eth_dst, true); + ofdpa_neigh_update(found, eth_dst, true); memcpy(entry, found, sizeof(*entry)); } else { err = -ENOENT; @@ -1410,7 +1316,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, * other routes' nexthops. */ - err = ofdpa_group_l3_unicast(ofdpa_port, trans, flags, + err = ofdpa_group_l3_unicast(ofdpa_port, flags, entry->index, ofdpa_port->dev->dev_addr, entry->eth_dst, @@ -1425,7 +1331,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, if (adding || removing) { group_id = ROCKER_GROUP_L3_UNICAST(entry->index); - err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans, + err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, eth_type, ip_addr, inet_make_mask(32), priority, goto_tbl, @@ -1438,13 +1344,12 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, err_out: if (!adding) - ofdpa_kfree(trans, entry); + kfree(entry); return err; } static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, __be32 ip_addr) { struct net_device *dev = ofdpa_port->dev; @@ -1463,7 +1368,7 @@ static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port, */ if (n->nud_state & NUD_VALID) - err = ofdpa_port_ipv4_neigh(ofdpa_port, trans, 0, + err = ofdpa_port_ipv4_neigh(ofdpa_port, 0, ip_addr, n->ha); else neigh_event_send(n, NULL); @@ -1473,8 +1378,7 @@ static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port, } static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - __be32 ip_addr, u32 *index) + int flags, __be32 ip_addr, u32 *index) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; struct ofdpa_neigh_tbl_entry *entry; @@ -1486,7 +1390,7 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, bool resolved = true; int err = 0; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1501,14 +1405,14 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, if (adding) { entry->ip_addr = ip_addr; entry->dev = ofdpa_port->dev; - ofdpa_neigh_add(ofdpa, trans, entry); + ofdpa_neigh_add(ofdpa, entry); *index = entry->index; resolved = false; } else if (removing) { - ofdpa_neigh_del(trans, found); + ofdpa_neigh_del(found); *index = found->index; } else if (updating) { - ofdpa_neigh_update(found, trans, NULL, false); + ofdpa_neigh_update(found, NULL, false); resolved = !is_zero_ether_addr(found->eth_dst); *index = found->index; } else { @@ -1518,7 +1422,7 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, lock_flags); if (!adding) - ofdpa_kfree(trans, entry); + kfree(entry); if (err) return err; @@ -1526,7 +1430,7 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, /* Resolved means neigh ip_addr is resolved to neigh mac. */ if (!resolved) - err = ofdpa_port_ipv4_resolve(ofdpa_port, trans, ip_addr); + err = ofdpa_port_ipv4_resolve(ofdpa_port, ip_addr); return err; } @@ -1541,7 +1445,6 @@ static struct ofdpa_port *ofdpa_port_get(const struct ofdpa *ofdpa, } static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, __be16 vlan_id) { struct ofdpa_port *p; @@ -1553,7 +1456,7 @@ static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port, int err = 0; int i; - group_ids = ofdpa_kcalloc(trans, flags, port_count, sizeof(u32)); + group_ids = kcalloc(flags, port_count, sizeof(u32)); if (!group_ids) return -ENOMEM; @@ -1578,18 +1481,17 @@ static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port, if (group_count == 0) goto no_ports_in_vlan; - err = ofdpa_group_l2_flood(ofdpa_port, trans, flags, vlan_id, + err = ofdpa_group_l2_flood(ofdpa_port, flags, vlan_id, group_count, group_ids, group_id); if (err) netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err); no_ports_in_vlan: - ofdpa_kfree(trans, group_ids); + kfree(group_ids); return err; } -static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, int flags, __be16 vlan_id, bool pop_vlan) { const struct ofdpa *ofdpa = ofdpa_port->ofdpa; @@ -1608,7 +1510,7 @@ static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, if (ofdpa_port->stp_state == BR_STATE_LEARNING || ofdpa_port->stp_state == BR_STATE_FORWARDING) { out_pport = ofdpa_port->pport; - err = ofdpa_group_l2_interface(ofdpa_port, trans, flags, + err = ofdpa_group_l2_interface(ofdpa_port, flags, vlan_id, out_pport, pop_vlan); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n", @@ -1632,7 +1534,7 @@ static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, return 0; out_pport = 0; - err = ofdpa_group_l2_interface(ofdpa_port, trans, flags, + err = ofdpa_group_l2_interface(ofdpa_port, flags, vlan_id, out_pport, pop_vlan); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for CPU port\n", err); @@ -1693,8 +1595,7 @@ static struct ofdpa_ctrl { }, }; -static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, int flags, const struct ofdpa_ctrl *ctrl, __be16 vlan_id) { u32 in_pport = ofdpa_port->pport; @@ -1710,7 +1611,7 @@ static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport); int err; - err = ofdpa_flow_tbl_acl(ofdpa_port, trans, flags, + err = ofdpa_flow_tbl_acl(ofdpa_port, flags, in_pport, in_pport_mask, eth_src, eth_src_mask, ctrl->eth_dst, ctrl->eth_dst_mask, @@ -1727,9 +1628,7 @@ static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, } static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, - int flags, - const struct ofdpa_ctrl *ctrl, + int flags, const struct ofdpa_ctrl *ctrl, __be16 vlan_id) { enum rocker_of_dpa_table_id goto_tbl = @@ -1741,7 +1640,7 @@ static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port, if (!ofdpa_port_is_bridged(ofdpa_port)) return 0; - err = ofdpa_flow_tbl_bridge(ofdpa_port, trans, flags, + err = ofdpa_flow_tbl_bridge(ofdpa_port, flags, ctrl->eth_dst, ctrl->eth_dst_mask, vlan_id, tunnel_id, goto_tbl, group_id, ctrl->copy_to_cpu); @@ -1752,8 +1651,7 @@ static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port, return err; } -static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, int flags, const struct ofdpa_ctrl *ctrl, __be16 vlan_id) { u32 in_pport_mask = 0xffffffff; @@ -1763,8 +1661,7 @@ static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, if (ntohs(vlan_id) == 0) vlan_id = ofdpa_port->internal_vlan_id; - err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans, - ofdpa_port->pport, in_pport_mask, + err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport, in_pport_mask, ctrl->eth_type, ctrl->eth_dst, ctrl->eth_dst_mask, vlan_id, vlan_id_mask, ctrl->copy_to_cpu, @@ -1776,26 +1673,24 @@ static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, return err; } -static int ofdpa_port_ctrl_vlan(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl_vlan(struct ofdpa_port *ofdpa_port, int flags, const struct ofdpa_ctrl *ctrl, __be16 vlan_id) { if (ctrl->acl) - return ofdpa_port_ctrl_vlan_acl(ofdpa_port, trans, flags, + return ofdpa_port_ctrl_vlan_acl(ofdpa_port, flags, ctrl, vlan_id); if (ctrl->bridge) - return ofdpa_port_ctrl_vlan_bridge(ofdpa_port, trans, flags, + return ofdpa_port_ctrl_vlan_bridge(ofdpa_port, flags, ctrl, vlan_id); if (ctrl->term) - return ofdpa_port_ctrl_vlan_term(ofdpa_port, trans, flags, + return ofdpa_port_ctrl_vlan_term(ofdpa_port, flags, ctrl, vlan_id); return -EOPNOTSUPP; } -static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, int flags, __be16 vlan_id) { int err = 0; @@ -1803,7 +1698,7 @@ static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, for (i = 0; i < OFDPA_CTRL_MAX; i++) { if (ofdpa_port->ctrls[i]) { - err = ofdpa_port_ctrl_vlan(ofdpa_port, trans, flags, + err = ofdpa_port_ctrl_vlan(ofdpa_port, flags, &ofdpa_ctrls[i], vlan_id); if (err) return err; @@ -1813,8 +1708,7 @@ static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, return err; } -static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, int flags, const struct ofdpa_ctrl *ctrl) { u16 vid; @@ -1823,7 +1717,7 @@ static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, for (vid = 1; vid < VLAN_N_VID; vid++) { if (!test_bit(vid, ofdpa_port->vlan_bitmap)) continue; - err = ofdpa_port_ctrl_vlan(ofdpa_port, trans, flags, + err = ofdpa_port_ctrl_vlan(ofdpa_port, flags, ctrl, htons(vid)); if (err) break; @@ -1832,8 +1726,8 @@ static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, return err; } -static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, u16 vid) +static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port, int flags, + u16 vid) { enum rocker_of_dpa_table_id goto_tbl = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC; @@ -1857,43 +1751,44 @@ static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port, change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap); if (adding) { - err = ofdpa_port_ctrl_vlan_add(ofdpa_port, trans, flags, + err = ofdpa_port_ctrl_vlan_add(ofdpa_port, flags, internal_vlan_id); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port ctrl vlan add\n", err); - goto err_out; + goto err_vlan_add; } } - err = ofdpa_port_vlan_l2_groups(ofdpa_port, trans, flags, + err = ofdpa_port_vlan_l2_groups(ofdpa_port, flags, internal_vlan_id, untagged); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 groups\n", err); - goto err_out; + goto err_vlan_l2_groups; } - err = ofdpa_port_vlan_flood_group(ofdpa_port, trans, flags, + err = ofdpa_port_vlan_flood_group(ofdpa_port, flags, internal_vlan_id); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err); - goto err_out; + goto err_flood_group; } - err = ofdpa_flow_tbl_vlan(ofdpa_port, trans, flags, + err = ofdpa_flow_tbl_vlan(ofdpa_port, flags, in_pport, vlan_id, vlan_id_mask, goto_tbl, untagged, internal_vlan_id); if (err) netdev_err(ofdpa_port->dev, "Error (%d) port VLAN table\n", err); -err_out: - if (switchdev_trans_ph_prepare(trans)) - change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap); + return 0; +err_vlan_add: +err_vlan_l2_groups: +err_flood_group: + change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap); return err; } -static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags) +static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, int flags) { enum rocker_of_dpa_table_id goto_tbl; u32 in_pport; @@ -1908,7 +1803,7 @@ static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, in_pport_mask = 0xffff0000; goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN; - err = ofdpa_flow_tbl_ig_port(ofdpa_port, trans, flags, + err = ofdpa_flow_tbl_ig_port(ofdpa_port, flags, in_pport, in_pport_mask, goto_tbl); if (err) @@ -1920,7 +1815,6 @@ static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, struct ofdpa_fdb_learn_work { struct work_struct work; struct ofdpa_port *ofdpa_port; - struct switchdev_trans *trans; int flags; u8 addr[ETH_ALEN]; u16 vid; @@ -1946,12 +1840,11 @@ static void ofdpa_port_fdb_learn_work(struct work_struct *work) lw->ofdpa_port->dev, &info.info); rtnl_unlock(); - ofdpa_kfree(lw->trans, work); + kfree(work); } static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - const u8 *addr, __be16 vlan_id) + int flags, const u8 *addr, __be16 vlan_id) { struct ofdpa_fdb_learn_work *lw; enum rocker_of_dpa_table_id goto_tbl = @@ -1966,7 +1859,7 @@ static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port, group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport); if (!(flags & OFDPA_OP_FLAG_REFRESH)) { - err = ofdpa_flow_tbl_bridge(ofdpa_port, trans, flags, addr, + err = ofdpa_flow_tbl_bridge(ofdpa_port, flags, addr, NULL, vlan_id, tunnel_id, goto_tbl, group_id, copy_to_cpu); if (err) @@ -1976,23 +1869,18 @@ static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port, if (!ofdpa_port_is_bridged(ofdpa_port)) return 0; - lw = ofdpa_kzalloc(trans, flags, sizeof(*lw)); + lw = kzalloc(sizeof(*lw), GFP_ATOMIC); if (!lw) return -ENOMEM; INIT_WORK(&lw->work, ofdpa_port_fdb_learn_work); lw->ofdpa_port = ofdpa_port; - lw->trans = trans; lw->flags = flags; ether_addr_copy(lw->addr, addr); lw->vid = ofdpa_port_vlan_to_vid(ofdpa_port, vlan_id); - if (switchdev_trans_ph_prepare(trans)) - ofdpa_kfree(trans, lw); - else - schedule_work(&lw->work); - + schedule_work(&lw->work); return 0; } @@ -2010,7 +1898,6 @@ ofdpa_fdb_tbl_find(const struct ofdpa *ofdpa, } static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, const unsigned char *addr, __be16 vlan_id, int flags) { @@ -2020,7 +1907,7 @@ static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port, bool removing = (flags & OFDPA_OP_FLAG_REMOVE); unsigned long lock_flags; - fdb = ofdpa_kzalloc(trans, flags, sizeof(*fdb)); + fdb = kzalloc(sizeof(*fdb), GFP_KERNEL); if (!fdb) return -ENOMEM; @@ -2038,32 +1925,29 @@ static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port, if (found) { found->touched = jiffies; if (removing) { - ofdpa_kfree(trans, fdb); - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); + kfree(fdb); + hash_del(&found->entry); } } else if (!removing) { - if (!switchdev_trans_ph_prepare(trans)) - hash_add(ofdpa->fdb_tbl, &fdb->entry, - fdb->key_crc32); + hash_add(ofdpa->fdb_tbl, &fdb->entry, + fdb->key_crc32); } spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags); /* Check if adding and already exists, or removing and can't find */ if (!found != !removing) { - ofdpa_kfree(trans, fdb); + kfree(fdb); if (!found && removing) return 0; /* Refreshing existing to update aging timers */ flags |= OFDPA_OP_FLAG_REFRESH; } - return ofdpa_port_fdb_learn(ofdpa_port, trans, flags, addr, vlan_id); + return ofdpa_port_fdb_learn(ofdpa_port, flags, addr, vlan_id); } -static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags) +static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port, int flags) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; struct ofdpa_fdb_tbl_entry *found; @@ -2085,13 +1969,12 @@ static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port, continue; if (!found->learned) continue; - err = ofdpa_port_fdb_learn(ofdpa_port, trans, flags, + err = ofdpa_port_fdb_learn(ofdpa_port, flags, found->key.addr, found->key.vlan_id); if (err) goto err_out; - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); + hash_del(&found->entry); } err_out: @@ -2121,8 +2004,8 @@ static void ofdpa_fdb_cleanup(unsigned long data) ofdpa_port = entry->key.ofdpa_port; expires = entry->touched + ofdpa_port->ageing_time; if (time_before_eq(expires, jiffies)) { - ofdpa_port_fdb_learn(ofdpa_port, NULL, - flags, entry->key.addr, + ofdpa_port_fdb_learn(ofdpa_port, flags, + entry->key.addr, entry->key.vlan_id); hash_del(&entry->entry); } else if (time_before(expires, next_timer)) { @@ -2136,8 +2019,7 @@ static void ofdpa_fdb_cleanup(unsigned long data) } static int ofdpa_port_router_mac(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - __be16 vlan_id) + int flags, __be16 vlan_id) { u32 in_pport_mask = 0xffffffff; __be16 eth_type; @@ -2150,26 +2032,25 @@ static int ofdpa_port_router_mac(struct ofdpa_port *ofdpa_port, vlan_id = ofdpa_port->internal_vlan_id; eth_type = htons(ETH_P_IP); - err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans, - ofdpa_port->pport, in_pport_mask, - eth_type, ofdpa_port->dev->dev_addr, + err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport, + in_pport_mask, eth_type, + ofdpa_port->dev->dev_addr, dst_mac_mask, vlan_id, vlan_id_mask, copy_to_cpu, flags); if (err) return err; eth_type = htons(ETH_P_IPV6); - err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans, - ofdpa_port->pport, in_pport_mask, - eth_type, ofdpa_port->dev->dev_addr, + err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport, + in_pport_mask, eth_type, + ofdpa_port->dev->dev_addr, dst_mac_mask, vlan_id, vlan_id_mask, copy_to_cpu, flags); return err; } -static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags) +static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, int flags) { bool pop_vlan; u32 out_pport; @@ -2194,7 +2075,7 @@ static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, continue; vlan_id = htons(vid); pop_vlan = ofdpa_vlan_id_is_internal(vlan_id); - err = ofdpa_group_l2_interface(ofdpa_port, trans, flags, + err = ofdpa_group_l2_interface(ofdpa_port, flags, vlan_id, out_pport, pop_vlan); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n", @@ -2207,7 +2088,6 @@ static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, } static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, u8 state) { bool want[OFDPA_CTRL_MAX] = { 0, }; @@ -2216,11 +2096,12 @@ static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port, int err; int i; + memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls)); prev_state = ofdpa_port->stp_state; - if (prev_state == state) + + if (ofdpa_port->stp_state == state) return 0; - memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls)); ofdpa_port->stp_state = state; switch (state) { @@ -2250,26 +2131,29 @@ static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port, if (want[i] != ofdpa_port->ctrls[i]) { int ctrl_flags = flags | (want[i] ? 0 : OFDPA_OP_FLAG_REMOVE); - err = ofdpa_port_ctrl(ofdpa_port, trans, ctrl_flags, + err = ofdpa_port_ctrl(ofdpa_port, ctrl_flags, &ofdpa_ctrls[i]); if (err) - goto err_out; + goto err_port_ctrl; ofdpa_port->ctrls[i] = want[i]; } } - err = ofdpa_port_fdb_flush(ofdpa_port, trans, flags); + err = ofdpa_port_fdb_flush(ofdpa_port, flags); if (err) - goto err_out; + goto err_fdb_flush; - err = ofdpa_port_fwding(ofdpa_port, trans, flags); + err = ofdpa_port_fwding(ofdpa_port, flags); + if (err) + goto err_port_fwding; -err_out: - if (switchdev_trans_ph_prepare(trans)) { - memcpy(ofdpa_port->ctrls, prev_ctrls, sizeof(prev_ctrls)); - ofdpa_port->stp_state = prev_state; - } + return 0; +err_port_ctrl: +err_fdb_flush: +err_port_fwding: + memcpy(ofdpa_port->ctrls, prev_ctrls, sizeof(prev_ctrls)); + ofdpa_port->stp_state = prev_state; return err; } @@ -2280,7 +2164,7 @@ static int ofdpa_port_fwd_enable(struct ofdpa_port *ofdpa_port, int flags) return 0; /* port is not bridged, so simulate going to FORWARDING state */ - return ofdpa_port_stp_update(ofdpa_port, NULL, flags, + return ofdpa_port_stp_update(ofdpa_port, flags, BR_STATE_FORWARDING); } @@ -2291,25 +2175,24 @@ static int ofdpa_port_fwd_disable(struct ofdpa_port *ofdpa_port, int flags) return 0; /* port is not bridged, so simulate going to DISABLED state */ - return ofdpa_port_stp_update(ofdpa_port, NULL, flags, + return ofdpa_port_stp_update(ofdpa_port, flags, BR_STATE_DISABLED); } static int ofdpa_port_vlan_add(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, u16 vid, u16 flags) { int err; /* XXX deal with flags for PVID and untagged */ - err = ofdpa_port_vlan(ofdpa_port, trans, 0, vid); + err = ofdpa_port_vlan(ofdpa_port, 0, vid); if (err) return err; - err = ofdpa_port_router_mac(ofdpa_port, trans, 0, htons(vid)); + err = ofdpa_port_router_mac(ofdpa_port, 0, htons(vid)); if (err) - ofdpa_port_vlan(ofdpa_port, trans, + ofdpa_port_vlan(ofdpa_port, OFDPA_OP_FLAG_REMOVE, vid); return err; @@ -2320,13 +2203,13 @@ static int ofdpa_port_vlan_del(struct ofdpa_port *ofdpa_port, { int err; - err = ofdpa_port_router_mac(ofdpa_port, NULL, - OFDPA_OP_FLAG_REMOVE, htons(vid)); + err = ofdpa_port_router_mac(ofdpa_port, OFDPA_OP_FLAG_REMOVE, + htons(vid)); if (err) return err; - return ofdpa_port_vlan(ofdpa_port, NULL, - OFDPA_OP_FLAG_REMOVE, vid); + return ofdpa_port_vlan(ofdpa_port, OFDPA_OP_FLAG_REMOVE, + vid); } static struct ofdpa_internal_vlan_tbl_entry * @@ -2385,10 +2268,9 @@ found: return found->vlan_id; } -static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, __be32 dst, - int dst_len, struct fib_info *fi, - u32 tb_id, int flags) +static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, __be32 dst, + int dst_len, struct fib_info *fi, u32 tb_id, + int flags) { const struct fib_nh *nh; __be16 eth_type = htons(ETH_P_IP); @@ -2410,7 +2292,7 @@ static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, has_gw = !!nh->nh_gw; if (has_gw && nh_on_port) { - err = ofdpa_port_ipv4_nh(ofdpa_port, trans, flags, + err = ofdpa_port_ipv4_nh(ofdpa_port, flags, nh->nh_gw, &index); if (err) return err; @@ -2421,7 +2303,7 @@ static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, group_id = ROCKER_GROUP_L2_INTERFACE(internal_vlan_id, 0); } - err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans, eth_type, dst, + err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, eth_type, dst, dst_mask, priority, goto_tbl, group_id, fi, flags); if (err) @@ -2559,7 +2441,7 @@ static int ofdpa_port_init(struct rocker_port *rocker_port) rocker_port_set_learning(rocker_port, !!(ofdpa_port->brport_flags & BR_LEARNING)); - err = ofdpa_port_ig_tbl(ofdpa_port, NULL, 0); + err = ofdpa_port_ig_tbl(ofdpa_port, 0); if (err) { netdev_err(ofdpa_port->dev, "install ig port table failed\n"); return err; @@ -2569,7 +2451,7 @@ static int ofdpa_port_init(struct rocker_port *rocker_port) ofdpa_port_internal_vlan_id_get(ofdpa_port, ofdpa_port->dev->ifindex); - err = ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0); + err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0); if (err) { netdev_err(ofdpa_port->dev, "install untagged VLAN failed\n"); goto err_untagged_vlan; @@ -2577,7 +2459,7 @@ static int ofdpa_port_init(struct rocker_port *rocker_port) return 0; err_untagged_vlan: - ofdpa_port_ig_tbl(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE); + ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE); return err; } @@ -2585,7 +2467,7 @@ static void ofdpa_port_fini(struct rocker_port *rocker_port) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - ofdpa_port_ig_tbl(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE); + ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE); } static int ofdpa_port_open(struct rocker_port *rocker_port) @@ -2603,12 +2485,11 @@ static void ofdpa_port_stop(struct rocker_port *rocker_port) } static int ofdpa_port_attr_stp_state_set(struct rocker_port *rocker_port, - u8 state, - struct switchdev_trans *trans) + u8 state) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - return ofdpa_port_stp_update(ofdpa_port, trans, 0, state); + return ofdpa_port_stp_update(ofdpa_port, 0, state); } static int ofdpa_port_attr_bridge_flags_set(struct rocker_port *rocker_port, @@ -2671,15 +2552,14 @@ ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, } static int ofdpa_port_obj_vlan_add(struct rocker_port *rocker_port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans) + const struct switchdev_obj_port_vlan *vlan) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; u16 vid; int err; for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { - err = ofdpa_port_vlan_add(ofdpa_port, trans, vid, vlan->flags); + err = ofdpa_port_vlan_add(ofdpa_port, vid, vlan->flags); if (err) return err; } @@ -2727,29 +2607,28 @@ static int ofdpa_port_obj_vlan_dump(const struct rocker_port *rocker_port, } static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) + u16 vid, const unsigned char *addr) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, fdb->vid, NULL); + __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL); if (!ofdpa_port_is_bridged(ofdpa_port)) return -EINVAL; - return ofdpa_port_fdb(ofdpa_port, trans, fdb->addr, vlan_id, 0); + return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, 0); } static int ofdpa_port_obj_fdb_del(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb) + u16 vid, const unsigned char *addr) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, fdb->vid, NULL); + __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL); int flags = OFDPA_OP_FLAG_REMOVE; if (!ofdpa_port_is_bridged(ofdpa_port)) return -EINVAL; - return ofdpa_port_fdb(ofdpa_port, NULL, fdb->addr, vlan_id, flags); + return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags); } static int ofdpa_port_obj_fdb_dump(const struct rocker_port *rocker_port, @@ -2803,7 +2682,7 @@ static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port, ofdpa_port->bridge_dev = bridge; - return ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0); + return ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0); } static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port) @@ -2822,7 +2701,7 @@ static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port) ofdpa_port->bridge_dev = NULL; - err = ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0); + err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0); if (err) return err; @@ -2881,7 +2760,7 @@ static int ofdpa_port_neigh_update(struct rocker_port *rocker_port, OFDPA_OP_FLAG_NOWAIT; __be32 ip_addr = *(__be32 *) n->primary_key; - return ofdpa_port_ipv4_neigh(ofdpa_port, NULL, flags, ip_addr, n->ha); + return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha); } static int ofdpa_port_neigh_destroy(struct rocker_port *rocker_port, @@ -2891,7 +2770,7 @@ static int ofdpa_port_neigh_destroy(struct rocker_port *rocker_port, int flags = OFDPA_OP_FLAG_REMOVE | OFDPA_OP_FLAG_NOWAIT; __be32 ip_addr = *(__be32 *) n->primary_key; - return ofdpa_port_ipv4_neigh(ofdpa_port, NULL, flags, ip_addr, n->ha); + return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha); } static int ofdpa_port_ev_mac_vlan_seen(struct rocker_port *rocker_port, @@ -2905,7 +2784,7 @@ static int ofdpa_port_ev_mac_vlan_seen(struct rocker_port *rocker_port, ofdpa_port->stp_state != BR_STATE_FORWARDING) return 0; - return ofdpa_port_fdb(ofdpa_port, NULL, addr, vlan_id, flags); + return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags); } static struct ofdpa_port *ofdpa_port_dev_lower_find(struct net_device *dev, @@ -2929,7 +2808,7 @@ static int ofdpa_fib4_add(struct rocker *rocker, ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker); if (!ofdpa_port) return 0; - err = ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst), + err = ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst), fen_info->dst_len, fen_info->fi, fen_info->tb_id, 0); if (err) @@ -2950,7 +2829,7 @@ static int ofdpa_fib4_del(struct rocker *rocker, if (!ofdpa_port) return 0; fib_info_offload_dec(fen_info->fi); - return ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst), + return ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst), fen_info->dst_len, fen_info->fi, fen_info->tb_id, OFDPA_OP_FLAG_REMOVE); } @@ -2977,7 +2856,7 @@ static void ofdpa_fib4_abort(struct rocker *rocker) if (!ofdpa_port) continue; fib_info_offload_dec(flow_entry->fi); - ofdpa_flow_tbl_del(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE, + ofdpa_flow_tbl_del(ofdpa_port, OFDPA_OP_FLAG_REMOVE, flow_entry); } spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags); -- cgit v1.2.3 From 726fd42fc1e3fe478cf08169f639caf92daeef0d Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:26 +0200 Subject: rocker: Add support for learning FDB through notification Add support for learning FDB through notification. The driver defers the hardware update via ordered work queue. Signed-off-by: Arkadi Sharshevsky Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker_main.c | 140 ++++++++++++++++++++++++++++-- 1 file changed, 135 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 9f0154dc2cf7..72dab7cad24a 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -1690,6 +1690,29 @@ rocker_world_port_obj_fdb_del(struct rocker_port *rocker_port, return wops->port_obj_fdb_del(rocker_port, fdb->vid, fdb->addr); } +static int +rocker_world_port_fdb_add(struct rocker_port *rocker_port, + struct switchdev_notifier_fdb_info *info) +{ + struct rocker_world_ops *wops = rocker_port->rocker->wops; + + if (!wops->port_obj_fdb_add) + return -EOPNOTSUPP; + + return wops->port_obj_fdb_add(rocker_port, info->vid, info->addr); +} + +static int +rocker_world_port_fdb_del(struct rocker_port *rocker_port, + struct switchdev_notifier_fdb_info *info) +{ + struct rocker_world_ops *wops = rocker_port->rocker->wops; + + if (!wops->port_obj_fdb_del) + return -EOPNOTSUPP; + return wops->port_obj_fdb_del(rocker_port, info->vid, info->addr); +} + static int rocker_world_port_obj_fdb_dump(const struct rocker_port *rocker_port, struct switchdev_obj_port_fdb *fdb, @@ -2767,6 +2790,109 @@ static void rocker_msix_fini(const struct rocker *rocker) kfree(rocker->msix_entries); } +static bool rocker_port_dev_check(const struct net_device *dev) +{ + return dev->netdev_ops == &rocker_port_netdev_ops; +} + +struct rocker_switchdev_event_work { + struct work_struct work; + struct switchdev_notifier_fdb_info fdb_info; + struct rocker_port *rocker_port; + unsigned long event; +}; + +static void +rocker_fdb_offload_notify(struct rocker_port *rocker_port, + struct switchdev_notifier_fdb_info *recv_info) +{ + struct switchdev_notifier_fdb_info info; + + info.addr = recv_info->addr; + info.vid = recv_info->vid; + call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, + rocker_port->dev, &info.info); +} + +static void rocker_switchdev_event_work(struct work_struct *work) +{ + struct rocker_switchdev_event_work *switchdev_work = + container_of(work, struct rocker_switchdev_event_work, work); + struct rocker_port *rocker_port = switchdev_work->rocker_port; + struct switchdev_notifier_fdb_info *fdb_info; + int err; + + rtnl_lock(); + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + fdb_info = &switchdev_work->fdb_info; + err = rocker_world_port_fdb_add(rocker_port, fdb_info); + if (err) { + netdev_dbg(rocker_port->dev, "fdb add failed err=%d\n", err); + break; + } + rocker_fdb_offload_notify(rocker_port, fdb_info); + break; + case SWITCHDEV_FDB_DEL_TO_DEVICE: + fdb_info = &switchdev_work->fdb_info; + err = rocker_world_port_fdb_del(rocker_port, fdb_info); + if (err) + netdev_dbg(rocker_port->dev, "fdb add failed err=%d\n", err); + break; + } + rtnl_unlock(); + + kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); + dev_put(rocker_port->dev); +} + +/* called under rcu_read_lock() */ +static int rocker_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + struct rocker_switchdev_event_work *switchdev_work; + struct switchdev_notifier_fdb_info *fdb_info = ptr; + struct rocker_port *rocker_port; + + if (!rocker_port_dev_check(dev)) + return NOTIFY_DONE; + + rocker_port = netdev_priv(dev); + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (WARN_ON(!switchdev_work)) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, rocker_switchdev_event_work); + switchdev_work->rocker_port = rocker_port; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */ + case SWITCHDEV_FDB_DEL_TO_DEVICE: + memcpy(&switchdev_work->fdb_info, ptr, + sizeof(switchdev_work->fdb_info)); + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, + fdb_info->addr); + /* Take a reference on the rocker device */ + dev_hold(dev); + break; + default: + kfree(switchdev_work); + return NOTIFY_DONE; + } + + queue_work(rocker_port->rocker->rocker_owq, + &switchdev_work->work); + return NOTIFY_DONE; +} + +static struct notifier_block rocker_switchdev_notifier = { + .notifier_call = rocker_switchdev_event, +}; + static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct rocker *rocker; @@ -2872,6 +2998,12 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_register_fib_notifier; + err = register_switchdev_notifier(&rocker_switchdev_notifier); + if (err) { + dev_err(&pdev->dev, "Failed to register switchdev notifier\n"); + goto err_register_switchdev_notifier; + } + rocker->hw.id = rocker_read64(rocker, SWITCH_ID); err = rocker_probe_ports(rocker); @@ -2886,6 +3018,8 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; err_probe_ports: + unregister_switchdev_notifier(&rocker_switchdev_notifier); +err_register_switchdev_notifier: unregister_fib_notifier(&rocker->fib_nb); err_register_fib_notifier: destroy_workqueue(rocker->rocker_owq); @@ -2916,6 +3050,7 @@ static void rocker_remove(struct pci_dev *pdev) struct rocker *rocker = pci_get_drvdata(pdev); rocker_remove_ports(rocker); + unregister_switchdev_notifier(&rocker_switchdev_notifier); unregister_fib_notifier(&rocker->fib_nb); rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET); destroy_workqueue(rocker->rocker_owq); @@ -2940,11 +3075,6 @@ static struct pci_driver rocker_pci_driver = { * Net device notifier event handler ************************************/ -static bool rocker_port_dev_check(const struct net_device *dev) -{ - return dev->netdev_ops == &rocker_port_netdev_ops; -} - static bool rocker_port_dev_check_under(const struct net_device *dev, struct rocker *rocker) { -- cgit v1.2.3 From 403caa7afc99bdd24a9382a2948b99ce5e6165e2 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:27 +0200 Subject: rocker: Remove support for bypass bridge port attributes/vlan set The bridge port attributes/vlan for mlxsw devices should be set only from bridge code. The vlans are synced totally with the bridge so there is no need to special dump support. Signed-off-by: Arkadi Sharshevsky Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.h | 3 --- drivers/net/ethernet/rocker/rocker_main.c | 20 -------------------- drivers/net/ethernet/rocker/rocker_ofdpa.c | 24 ------------------------ 3 files changed, 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index a0f7782ddfdd..a0fa3f8240ba 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -122,9 +122,6 @@ struct rocker_world_ops { const struct switchdev_obj_port_vlan *vlan); int (*port_obj_vlan_del)(struct rocker_port *rocker_port, const struct switchdev_obj_port_vlan *vlan); - int (*port_obj_vlan_dump)(const struct rocker_port *rocker_port, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb); int (*port_obj_fdb_add)(struct rocker_port *rocker_port, u16 vid, const unsigned char *addr); int (*port_obj_fdb_del)(struct rocker_port *rocker_port, diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 72dab7cad24a..3e78129a81fe 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -1651,18 +1651,6 @@ rocker_world_port_obj_vlan_del(struct rocker_port *rocker_port, return wops->port_obj_vlan_del(rocker_port, vlan); } -static int -rocker_world_port_obj_vlan_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb) -{ - struct rocker_world_ops *wops = rocker_port->rocker->wops; - - if (!wops->port_obj_vlan_dump) - return -EOPNOTSUPP; - return wops->port_obj_vlan_dump(rocker_port, vlan, cb); -} - static int rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port, const struct switchdev_obj_port_fdb *fdb, @@ -2079,9 +2067,6 @@ static const struct net_device_ops rocker_port_netdev_ops = { .ndo_start_xmit = rocker_port_xmit, .ndo_set_mac_address = rocker_port_set_mac_address, .ndo_change_mtu = rocker_port_change_mtu, - .ndo_bridge_getlink = switchdev_port_bridge_getlink, - .ndo_bridge_setlink = switchdev_port_bridge_setlink, - .ndo_bridge_dellink = switchdev_port_bridge_dellink, .ndo_fdb_add = switchdev_port_fdb_add, .ndo_fdb_del = switchdev_port_fdb_del, .ndo_fdb_dump = switchdev_port_fdb_dump, @@ -2214,11 +2199,6 @@ static int rocker_port_obj_dump(struct net_device *dev, SWITCHDEV_OBJ_PORT_FDB(obj), cb); break; - case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = rocker_world_port_obj_vlan_dump(rocker_port, - SWITCHDEV_OBJ_PORT_VLAN(obj), - cb); - break; default: err = -EOPNOTSUPP; break; diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 184a478fadab..5510ad0fcc3c 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -2583,29 +2583,6 @@ static int ofdpa_port_obj_vlan_del(struct rocker_port *rocker_port, return 0; } -static int ofdpa_port_obj_vlan_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb) -{ - const struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - u16 vid; - int err = 0; - - for (vid = 1; vid < VLAN_N_VID; vid++) { - if (!test_bit(vid, ofdpa_port->vlan_bitmap)) - continue; - vlan->flags = 0; - if (ofdpa_vlan_id_is_internal(htons(vid))) - vlan->flags |= BRIDGE_VLAN_INFO_PVID; - vlan->vid_begin = vlan->vid_end = vid; - err = cb(&vlan->obj); - if (err) - break; - } - - return err; -} - static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port, u16 vid, const unsigned char *addr) { @@ -2882,7 +2859,6 @@ struct rocker_world_ops rocker_ofdpa_ops = { .port_attr_bridge_ageing_time_set = ofdpa_port_attr_bridge_ageing_time_set, .port_obj_vlan_add = ofdpa_port_obj_vlan_add, .port_obj_vlan_del = ofdpa_port_obj_vlan_del, - .port_obj_vlan_dump = ofdpa_port_obj_vlan_dump, .port_obj_fdb_add = ofdpa_port_obj_fdb_add, .port_obj_fdb_del = ofdpa_port_obj_fdb_del, .port_obj_fdb_dump = ofdpa_port_obj_fdb_dump, -- cgit v1.2.3 From abfbf8a0b25e779d0e3533a7d99843982755d61e Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Jun 2017 08:44:28 +0200 Subject: rocker: Remove support bridge bypass FDB The FDB add/delete are now done through the notification chain. The FDBs are synced with the bridge and there is no need for extra dumping. Signed-off-by: Arkadi Sharshevsky Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.h | 3 -- drivers/net/ethernet/rocker/rocker_main.c | 73 ------------------------------ drivers/net/ethernet/rocker/rocker_ofdpa.c | 30 ------------ 3 files changed, 106 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index a0fa3f8240ba..748fb12260a6 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -126,9 +126,6 @@ struct rocker_world_ops { u16 vid, const unsigned char *addr); int (*port_obj_fdb_del)(struct rocker_port *rocker_port, u16 vid, const unsigned char *addr); - int (*port_obj_fdb_dump)(const struct rocker_port *rocker_port, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb); int (*port_master_linked)(struct rocker_port *rocker_port, struct net_device *master); int (*port_master_unlinked)(struct rocker_port *rocker_port, diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 3e78129a81fe..b1e5c07099fa 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -1651,33 +1651,6 @@ rocker_world_port_obj_vlan_del(struct rocker_port *rocker_port, return wops->port_obj_vlan_del(rocker_port, vlan); } -static int -rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) -{ - struct rocker_world_ops *wops = rocker_port->rocker->wops; - - if (!wops->port_obj_fdb_add) - return -EOPNOTSUPP; - - if (switchdev_trans_ph_prepare(trans)) - return 0; - - return wops->port_obj_fdb_add(rocker_port, fdb->vid, fdb->addr); -} - -static int -rocker_world_port_obj_fdb_del(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb) -{ - struct rocker_world_ops *wops = rocker_port->rocker->wops; - - if (!wops->port_obj_fdb_del) - return -EOPNOTSUPP; - return wops->port_obj_fdb_del(rocker_port, fdb->vid, fdb->addr); -} - static int rocker_world_port_fdb_add(struct rocker_port *rocker_port, struct switchdev_notifier_fdb_info *info) @@ -1701,18 +1674,6 @@ rocker_world_port_fdb_del(struct rocker_port *rocker_port, return wops->port_obj_fdb_del(rocker_port, info->vid, info->addr); } -static int -rocker_world_port_obj_fdb_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb) -{ - struct rocker_world_ops *wops = rocker_port->rocker->wops; - - if (!wops->port_obj_fdb_dump) - return -EOPNOTSUPP; - return wops->port_obj_fdb_dump(rocker_port, fdb, cb); -} - static int rocker_world_port_master_linked(struct rocker_port *rocker_port, struct net_device *master) { @@ -2067,9 +2028,6 @@ static const struct net_device_ops rocker_port_netdev_ops = { .ndo_start_xmit = rocker_port_xmit, .ndo_set_mac_address = rocker_port_set_mac_address, .ndo_change_mtu = rocker_port_change_mtu, - .ndo_fdb_add = switchdev_port_fdb_add, - .ndo_fdb_del = switchdev_port_fdb_del, - .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_get_phys_port_name = rocker_port_get_phys_port_name, .ndo_change_proto_down = rocker_port_change_proto_down, .ndo_neigh_destroy = rocker_port_neigh_destroy, @@ -2150,11 +2108,6 @@ static int rocker_port_obj_add(struct net_device *dev, SWITCHDEV_OBJ_PORT_VLAN(obj), trans); break; - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = rocker_world_port_obj_fdb_add(rocker_port, - SWITCHDEV_OBJ_PORT_FDB(obj), - trans); - break; default: err = -EOPNOTSUPP; break; @@ -2174,31 +2127,6 @@ static int rocker_port_obj_del(struct net_device *dev, err = rocker_world_port_obj_vlan_del(rocker_port, SWITCHDEV_OBJ_PORT_VLAN(obj)); break; - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = rocker_world_port_obj_fdb_del(rocker_port, - SWITCHDEV_OBJ_PORT_FDB(obj)); - break; - default: - err = -EOPNOTSUPP; - break; - } - - return err; -} - -static int rocker_port_obj_dump(struct net_device *dev, - struct switchdev_obj *obj, - switchdev_obj_dump_cb_t *cb) -{ - const struct rocker_port *rocker_port = netdev_priv(dev); - int err = 0; - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = rocker_world_port_obj_fdb_dump(rocker_port, - SWITCHDEV_OBJ_PORT_FDB(obj), - cb); - break; default: err = -EOPNOTSUPP; break; @@ -2212,7 +2140,6 @@ static const struct switchdev_ops rocker_port_switchdev_ops = { .switchdev_port_attr_set = rocker_port_attr_set, .switchdev_port_obj_add = rocker_port_obj_add, .switchdev_port_obj_del = rocker_port_obj_del, - .switchdev_port_obj_dump = rocker_port_obj_dump, }; struct rocker_fib_event_work { diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 5510ad0fcc3c..bd0e3f157e9e 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -2608,35 +2608,6 @@ static int ofdpa_port_obj_fdb_del(struct rocker_port *rocker_port, return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags); } -static int ofdpa_port_obj_fdb_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb) -{ - const struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - struct ofdpa *ofdpa = ofdpa_port->ofdpa; - struct ofdpa_fdb_tbl_entry *found; - struct hlist_node *tmp; - unsigned long lock_flags; - int bkt; - int err = 0; - - spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags); - hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, found, entry) { - if (found->key.ofdpa_port != ofdpa_port) - continue; - ether_addr_copy(fdb->addr, found->key.addr); - fdb->ndm_state = NUD_REACHABLE; - fdb->vid = ofdpa_port_vlan_to_vid(ofdpa_port, - found->key.vlan_id); - err = cb(&fdb->obj); - if (err) - break; - } - spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags); - - return err; -} - static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port, struct net_device *bridge) { @@ -2861,7 +2832,6 @@ struct rocker_world_ops rocker_ofdpa_ops = { .port_obj_vlan_del = ofdpa_port_obj_vlan_del, .port_obj_fdb_add = ofdpa_port_obj_fdb_add, .port_obj_fdb_del = ofdpa_port_obj_fdb_del, - .port_obj_fdb_dump = ofdpa_port_obj_fdb_dump, .port_master_linked = ofdpa_port_master_linked, .port_master_unlinked = ofdpa_port_master_unlinked, .port_neigh_update = ofdpa_port_neigh_update, -- cgit v1.2.3 From d7a60306c6812801ccc0a7d12aa0975121b9aa58 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 8 Jun 2017 08:47:43 +0200 Subject: mlxsw: spectrum_router: Mark only first LPM tree as reserved In new firmware versions (that we can now enforce via request_firmware()), only the first LPM tree is reserved and not the first two as in older versions. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 20061058801e..700cc8c6aa5b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -591,7 +591,7 @@ static int mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp, return 0; } -#define MLXSW_SP_LPM_TREE_MIN 2 /* trees 0 and 1 are reserved */ +#define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp) { -- cgit v1.2.3 From 5b15385964fab67953df706e1448e1a45db92adf Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 8 Jun 2017 08:47:44 +0200 Subject: mlxsw: spectrum: Simplify port split flow In commit be94535f9531 ("mlxsw: spectrum: Make split flow match firmware requirements") we had to modify the port split flow to overcome quirks in the device's firmware. This resulted in asymmetrical code with regards to port creation and removal. The problem in the firmware is long gone and since we can now enforce a minimal firmware version, we can simplify the code and make it symmetric again. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 103 +++++++------------------ 1 file changed, 28 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index ecc73525529d..39e57c858258 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -860,21 +860,13 @@ static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu) return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl); } -static int __mlxsw_sp_port_swid_set(struct mlxsw_sp *mlxsw_sp, u8 local_port, - u8 swid) -{ - char pspa_pl[MLXSW_REG_PSPA_LEN]; - - mlxsw_reg_pspa_pack(pspa_pl, swid, local_port); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl); -} - static int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + char pspa_pl[MLXSW_REG_PSPA_LEN]; - return __mlxsw_sp_port_swid_set(mlxsw_sp, mlxsw_sp_port->local_port, - swid); + mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sp_port->local_port); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl); } int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) @@ -2655,17 +2647,26 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) return 0; } -static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, - bool split, u8 module, u8 width, u8 lane) +static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, + bool split, u8 module, u8 width, u8 lane) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_port *mlxsw_sp_port; struct net_device *dev; int err; + err = mlxsw_core_port_init(mlxsw_sp->core, local_port); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to init core port\n", + local_port); + return err; + } + dev = alloc_etherdev(sizeof(struct mlxsw_sp_port)); - if (!dev) - return -ENOMEM; + if (!dev) { + err = -ENOMEM; + goto err_alloc_etherdev; + } SET_NETDEV_DEV(dev, mlxsw_sp->bus_info->dev); mlxsw_sp_port = netdev_priv(dev); mlxsw_sp_port->dev = dev; @@ -2707,6 +2708,14 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, dev->netdev_ops = &mlxsw_sp_port_netdev_ops; dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops; + err = mlxsw_sp_port_module_map(mlxsw_sp, local_port, module, width, + lane); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n", + mlxsw_sp_port->local_port); + goto err_port_module_map; + } + err = mlxsw_sp_port_swid_set(mlxsw_sp_port, 0); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n", @@ -2829,6 +2838,8 @@ err_port_system_port_mapping_set: err_dev_addr_init: mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); err_port_swid_set: + mlxsw_sp_port_module_unmap(mlxsw_sp, local_port); +err_port_module_map: kfree(mlxsw_sp_port->hw_stats.cache); err_alloc_hw_stats: kfree(mlxsw_sp_port->sample); @@ -2836,32 +2847,12 @@ err_alloc_sample: free_percpu(mlxsw_sp_port->pcpu_stats); err_alloc_stats: free_netdev(dev); - return err; -} - -static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, - bool split, u8 module, u8 width, u8 lane) -{ - int err; - - err = mlxsw_core_port_init(mlxsw_sp->core, local_port); - if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to init core port\n", - local_port); - return err; - } - err = __mlxsw_sp_port_create(mlxsw_sp, local_port, split, - module, width, lane); - if (err) - goto err_port_create; - return 0; - -err_port_create: +err_alloc_etherdev: mlxsw_core_port_fini(mlxsw_sp->core, local_port); return err; } -static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) +static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port]; @@ -2880,11 +2871,6 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) free_percpu(mlxsw_sp_port->pcpu_stats); WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list)); free_netdev(mlxsw_sp_port->dev); -} - -static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) -{ - __mlxsw_sp_port_remove(mlxsw_sp, local_port); mlxsw_core_port_fini(mlxsw_sp->core, local_port); } @@ -2962,19 +2948,6 @@ static int mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, u8 width = MLXSW_PORT_MODULE_MAX_WIDTH / count; int err, i; - for (i = 0; i < count; i++) { - err = mlxsw_sp_port_module_map(mlxsw_sp, base_port + i, module, - width, i * width); - if (err) - goto err_port_module_map; - } - - for (i = 0; i < count; i++) { - err = __mlxsw_sp_port_swid_set(mlxsw_sp, base_port + i, 0); - if (err) - goto err_port_swid_set; - } - for (i = 0; i < count; i++) { err = mlxsw_sp_port_create(mlxsw_sp, base_port + i, true, module, width, i * width); @@ -2988,15 +2961,6 @@ err_port_create: for (i--; i >= 0; i--) if (mlxsw_sp_port_created(mlxsw_sp, base_port + i)) mlxsw_sp_port_remove(mlxsw_sp, base_port + i); - i = count; -err_port_swid_set: - for (i--; i >= 0; i--) - __mlxsw_sp_port_swid_set(mlxsw_sp, base_port + i, - MLXSW_PORT_SWID_DISABLED_PORT); - i = count; -err_port_module_map: - for (i--; i >= 0; i--) - mlxsw_sp_port_module_unmap(mlxsw_sp, base_port + i); return err; } @@ -3011,17 +2975,6 @@ static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, */ count = count / 2; - for (i = 0; i < count; i++) { - local_port = base_port + i * 2; - module = mlxsw_sp->port_to_module[local_port]; - - mlxsw_sp_port_module_map(mlxsw_sp, local_port, module, width, - 0); - } - - for (i = 0; i < count; i++) - __mlxsw_sp_port_swid_set(mlxsw_sp, base_port + i * 2, 0); - for (i = 0; i < count; i++) { local_port = base_port + i * 2; module = mlxsw_sp->port_to_module[local_port]; -- cgit v1.2.3 From 2e915e0b68c9213ed16493c8a28aa973d38d0353 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 8 Jun 2017 08:47:45 +0200 Subject: mlxsw: spectrum: Pass port argument to module mapping functions Previous patch made it unnecessary to map ports to modules before we allocate their struct. We can now therefore pass the port struct to these functions, thereby making them consistent with other functions that operate on ports. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 39e57c858258..0e51c3693243 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -967,13 +967,14 @@ static int mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, return 0; } -static int mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u8 local_port, +static int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port, u8 module, u8 width, u8 lane) { + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; char pmlp_pl[MLXSW_REG_PMLP_LEN]; int i; - mlxsw_reg_pmlp_pack(pmlp_pl, local_port); + mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port); mlxsw_reg_pmlp_width_set(pmlp_pl, width); for (i = 0; i < width; i++) { mlxsw_reg_pmlp_module_set(pmlp_pl, i, module); @@ -983,11 +984,12 @@ static int mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u8 local_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); } -static int mlxsw_sp_port_module_unmap(struct mlxsw_sp *mlxsw_sp, u8 local_port) +static int mlxsw_sp_port_module_unmap(struct mlxsw_sp_port *mlxsw_sp_port) { + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; char pmlp_pl[MLXSW_REG_PMLP_LEN]; - mlxsw_reg_pmlp_pack(pmlp_pl, local_port); + mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port); mlxsw_reg_pmlp_width_set(pmlp_pl, 0); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); } @@ -2708,8 +2710,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, dev->netdev_ops = &mlxsw_sp_port_netdev_ops; dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops; - err = mlxsw_sp_port_module_map(mlxsw_sp, local_port, module, width, - lane); + err = mlxsw_sp_port_module_map(mlxsw_sp_port, module, width, lane); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n", mlxsw_sp_port->local_port); @@ -2838,7 +2839,7 @@ err_port_system_port_mapping_set: err_dev_addr_init: mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); err_port_swid_set: - mlxsw_sp_port_module_unmap(mlxsw_sp, local_port); + mlxsw_sp_port_module_unmap(mlxsw_sp_port); err_port_module_map: kfree(mlxsw_sp_port->hw_stats.cache); err_alloc_hw_stats: @@ -2865,7 +2866,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) mlxsw_sp_port_fids_fini(mlxsw_sp_port); mlxsw_sp_port_dcb_fini(mlxsw_sp_port); mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); - mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port); + mlxsw_sp_port_module_unmap(mlxsw_sp_port); kfree(mlxsw_sp_port->hw_stats.cache); kfree(mlxsw_sp_port->sample); free_percpu(mlxsw_sp_port->pcpu_stats); -- cgit v1.2.3 From b3fd82207e2723247aac478e8756451fe85b1ac2 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 8 Jun 2017 10:52:11 +0530 Subject: cxgb4: fix to bring link down after adapter crash Use PORT_REG for T4 and T5_PORT_REG for > T4 to write to correct register to bring down link during shutdown after adapter crash. Signed-off-by: Rahul Lakkireddy Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 4618185d6bc2..da1322da4925 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -7688,10 +7688,9 @@ int t4_shutdown_adapter(struct adapter *adapter) t4_intr_disable(adapter); t4_write_reg(adapter, DBG_GPIO_EN_A, 0); for_each_port(adapter, port) { - u32 a_port_cfg = PORT_REG(port, - is_t4(adapter->params.chip) - ? XGMAC_PORT_CFG_A - : MAC_PORT_CFG_A); + u32 a_port_cfg = is_t4(adapter->params.chip) ? + PORT_REG(port, XGMAC_PORT_CFG_A) : + T5_PORT_REG(port, MAC_PORT_CFG_A); t4_write_reg(adapter, a_port_cfg, t4_read_reg(adapter, a_port_cfg) -- cgit v1.2.3 From 7cb6e01de3c4721de0f5411a6eae95a4f74cc5d7 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Thu, 8 Jun 2017 11:30:57 +0530 Subject: drivers/net/sungem: add const to mii_phy_ops structures The object references of mii_phy_ops structures are only stored in the ops field of a mii_phy_def structure. This ops field is of type const. So, mii_phy_ops structures having similar properties can be declared as const. Signed-off-by: Bhumika Goyal Signed-off-by: David S. Miller --- drivers/net/sungem_phy.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index 92578d72e4ee..63a8ff816e59 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -886,7 +886,7 @@ static int marvell_read_link(struct mii_phy *phy) SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full) /* Broadcom BCM 5201 */ -static struct mii_phy_ops bcm5201_phy_ops = { +static const struct mii_phy_ops bcm5201_phy_ops = { .init = bcm5201_init, .suspend = bcm5201_suspend, .setup_aneg = genmii_setup_aneg, @@ -905,7 +905,7 @@ static struct mii_phy_def bcm5201_phy_def = { }; /* Broadcom BCM 5221 */ -static struct mii_phy_ops bcm5221_phy_ops = { +static const struct mii_phy_ops bcm5221_phy_ops = { .suspend = bcm5221_suspend, .init = bcm5221_init, .setup_aneg = genmii_setup_aneg, @@ -924,7 +924,7 @@ static struct mii_phy_def bcm5221_phy_def = { }; /* Broadcom BCM 5241 */ -static struct mii_phy_ops bcm5241_phy_ops = { +static const struct mii_phy_ops bcm5241_phy_ops = { .suspend = bcm5241_suspend, .init = bcm5241_init, .setup_aneg = genmii_setup_aneg, @@ -942,7 +942,7 @@ static struct mii_phy_def bcm5241_phy_def = { }; /* Broadcom BCM 5400 */ -static struct mii_phy_ops bcm5400_phy_ops = { +static const struct mii_phy_ops bcm5400_phy_ops = { .init = bcm5400_init, .suspend = bcm5400_suspend, .setup_aneg = bcm54xx_setup_aneg, @@ -961,7 +961,7 @@ static struct mii_phy_def bcm5400_phy_def = { }; /* Broadcom BCM 5401 */ -static struct mii_phy_ops bcm5401_phy_ops = { +static const struct mii_phy_ops bcm5401_phy_ops = { .init = bcm5401_init, .suspend = bcm5401_suspend, .setup_aneg = bcm54xx_setup_aneg, @@ -980,7 +980,7 @@ static struct mii_phy_def bcm5401_phy_def = { }; /* Broadcom BCM 5411 */ -static struct mii_phy_ops bcm5411_phy_ops = { +static const struct mii_phy_ops bcm5411_phy_ops = { .init = bcm5411_init, .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, @@ -999,7 +999,7 @@ static struct mii_phy_def bcm5411_phy_def = { }; /* Broadcom BCM 5421 */ -static struct mii_phy_ops bcm5421_phy_ops = { +static const struct mii_phy_ops bcm5421_phy_ops = { .init = bcm5421_init, .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, @@ -1019,7 +1019,7 @@ static struct mii_phy_def bcm5421_phy_def = { }; /* Broadcom BCM 5421 built-in K2 */ -static struct mii_phy_ops bcm5421k2_phy_ops = { +static const struct mii_phy_ops bcm5421k2_phy_ops = { .init = bcm5421_init, .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, @@ -1037,7 +1037,7 @@ static struct mii_phy_def bcm5421k2_phy_def = { .ops = &bcm5421k2_phy_ops }; -static struct mii_phy_ops bcm5461_phy_ops = { +static const struct mii_phy_ops bcm5461_phy_ops = { .init = bcm5421_init, .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, @@ -1057,7 +1057,7 @@ static struct mii_phy_def bcm5461_phy_def = { }; /* Broadcom BCM 5462 built-in Vesta */ -static struct mii_phy_ops bcm5462V_phy_ops = { +static const struct mii_phy_ops bcm5462V_phy_ops = { .init = bcm5421_init, .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, @@ -1076,7 +1076,7 @@ static struct mii_phy_def bcm5462V_phy_def = { }; /* Marvell 88E1101 amd 88E1111 */ -static struct mii_phy_ops marvell88e1101_phy_ops = { +static const struct mii_phy_ops marvell88e1101_phy_ops = { .suspend = generic_suspend, .setup_aneg = marvell_setup_aneg, .setup_forced = marvell_setup_forced, @@ -1084,7 +1084,7 @@ static struct mii_phy_ops marvell88e1101_phy_ops = { .read_link = marvell_read_link }; -static struct mii_phy_ops marvell88e1111_phy_ops = { +static const struct mii_phy_ops marvell88e1111_phy_ops = { .init = marvell88e1111_init, .suspend = generic_suspend, .setup_aneg = marvell_setup_aneg, @@ -1122,7 +1122,7 @@ static struct mii_phy_def marvell88e1111_phy_def = { }; /* Generic implementation for most 10/100 PHYs */ -static struct mii_phy_ops generic_phy_ops = { +static const struct mii_phy_ops generic_phy_ops = { .setup_aneg = genmii_setup_aneg, .setup_forced = genmii_setup_forced, .poll_link = genmii_poll_link, -- cgit v1.2.3 From d193d53c1c1818f53cae0176d1f6a1509d80f449 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Thu, 8 Jun 2017 11:30:58 +0530 Subject: drivers: net: emac: add const to mii_phy_ops structures The object references of mii_phy_ops structures are only stored in the ops field of a mii_phy_def structure. This ops field is of type const. So, mii_phy_ops structures having similar properties can be declared as const. Signed-off-by: Bhumika Goyal Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/emac/phy.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/emac/phy.c b/drivers/net/ethernet/ibm/emac/phy.c index 5b88cc690c22..35865d05fccd 100644 --- a/drivers/net/ethernet/ibm/emac/phy.c +++ b/drivers/net/ethernet/ibm/emac/phy.c @@ -276,7 +276,7 @@ static int genmii_read_link(struct mii_phy *phy) } /* Generic implementation for most 10/100/1000 PHYs */ -static struct mii_phy_ops generic_phy_ops = { +static const struct mii_phy_ops generic_phy_ops = { .setup_aneg = genmii_setup_aneg, .setup_forced = genmii_setup_forced, .poll_link = genmii_poll_link, @@ -340,7 +340,7 @@ static int cis8201_init(struct mii_phy *phy) return 0; } -static struct mii_phy_ops cis8201_phy_ops = { +static const struct mii_phy_ops cis8201_phy_ops = { .init = cis8201_init, .setup_aneg = genmii_setup_aneg, .setup_forced = genmii_setup_forced, @@ -420,7 +420,7 @@ static int et1011c_init(struct mii_phy *phy) return 0; } -static struct mii_phy_ops et1011c_phy_ops = { +static const struct mii_phy_ops et1011c_phy_ops = { .init = et1011c_init, .setup_aneg = genmii_setup_aneg, .setup_forced = genmii_setup_forced, @@ -439,7 +439,7 @@ static struct mii_phy_def et1011c_phy_def = { -static struct mii_phy_ops m88e1111_phy_ops = { +static const struct mii_phy_ops m88e1111_phy_ops = { .init = m88e1111_init, .setup_aneg = genmii_setup_aneg, .setup_forced = genmii_setup_forced, @@ -455,7 +455,7 @@ static struct mii_phy_def m88e1111_phy_def = { .ops = &m88e1111_phy_ops, }; -static struct mii_phy_ops m88e1112_phy_ops = { +static const struct mii_phy_ops m88e1112_phy_ops = { .init = m88e1112_init, .setup_aneg = genmii_setup_aneg, .setup_forced = genmii_setup_forced, @@ -480,7 +480,7 @@ static int ar8035_init(struct mii_phy *phy) return 0; } -static struct mii_phy_ops ar8035_phy_ops = { +static const struct mii_phy_ops ar8035_phy_ops = { .init = ar8035_init, .setup_aneg = genmii_setup_aneg, .setup_forced = genmii_setup_forced, -- cgit v1.2.3 From c127a871357b8d59cda9c8b96cb65c2e24a72c46 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 8 Jun 2017 22:58:45 +0200 Subject: Bluetooth: hci_ll: Add compatible values for more WL chips Add compatible values for WiLink chips from 128x and 180x series. Also the DT binding already contained compatible values for the 127x series, but the driver did not. This brings the list on par with the list from wlcore (the wifi driver). Signed-off-by: Sebastian Reichel Reviewed-by: Rob Herring Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_ll.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 200288c87fc4..1b0487310117 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -741,6 +741,14 @@ static void hci_ti_remove(struct serdev_device *serdev) } static const struct of_device_id hci_ti_of_match[] = { + { .compatible = "ti,wl1271-st" }, + { .compatible = "ti,wl1273-st" }, + { .compatible = "ti,wl1281-st" }, + { .compatible = "ti,wl1283-st" }, + { .compatible = "ti,wl1285-st" }, + { .compatible = "ti,wl1801-st" }, + { .compatible = "ti,wl1805-st" }, + { .compatible = "ti,wl1807-st" }, { .compatible = "ti,wl1831-st" }, { .compatible = "ti,wl1835-st" }, { .compatible = "ti,wl1837-st" }, -- cgit v1.2.3 From 43d3d092c7cbd1685e1c8ff25ae0b89b5b729388 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 7 Jun 2017 11:08:21 +0200 Subject: Bluetooth: hci_ll: Add support for the external clock Add support to manage the external clock provided to the WiLink combo chip as it's needed for any of the transport interfaces. To avoid breaking platforms not yet specifying the external clock, we make it optional. In case the clock is successfully fetched during ->probe(), let's manage it via the ->open|close() callbacks, to make sure the device get properly powered on/off. Fixes: ea452678734e ("arm64: dts: hikey: Fix WiFi support") Signed-off-by: Ulf Hansson Tested-by: John Stultz Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_ll.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 1b0487310117..2b16d48d82ee 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -84,6 +85,7 @@ struct ll_device { struct hci_uart hu; struct serdev_device *serdev; struct gpio_desc *enable_gpio; + struct clk *ext_clk; }; struct ll_struct { @@ -146,8 +148,12 @@ static int ll_open(struct hci_uart *hu) hu->priv = ll; - if (hu->serdev) + if (hu->serdev) { + struct ll_device *lldev = serdev_device_get_drvdata(hu->serdev); serdev_device_open(hu->serdev); + if (!IS_ERR(lldev->ext_clk)) + clk_prepare_enable(lldev->ext_clk); + } return 0; } @@ -181,6 +187,8 @@ static int ll_close(struct hci_uart *hu) struct ll_device *lldev = serdev_device_get_drvdata(hu->serdev); gpiod_set_value_cansleep(lldev->enable_gpio, 0); + clk_disable_unprepare(lldev->ext_clk); + serdev_device_close(hu->serdev); } @@ -721,6 +729,10 @@ static int hci_ti_probe(struct serdev_device *serdev) if (IS_ERR(lldev->enable_gpio)) return PTR_ERR(lldev->enable_gpio); + lldev->ext_clk = devm_clk_get(&serdev->dev, "ext_clock"); + if (IS_ERR(lldev->ext_clk) && PTR_ERR(lldev->ext_clk) != -ENOENT) + return PTR_ERR(lldev->ext_clk); + of_property_read_u32(serdev->dev.of_node, "max-speed", &max_speed); hci_uart_set_speeds(hu, 115200, max_speed); -- cgit v1.2.3 From 774439e532bfe9dba83a5f499fcdfd8eea961919 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 8 Jun 2017 18:34:08 -0400 Subject: net: dsa: mv888e6xxx: do not use netdev printing The mv888e6xxx driver accesses a port's netdev mostly for printing. This is bad for 2 reasons: DSA and CPU ports do not have a netdev pointer; it doesn't give us a correct picture of why a DSA driver might need to access a port's netdev. Instead simply use dev_* printing functions with chip->dev (or ds->dev depending on the scope, both guaranteed to exist), with a p%d prefix for the target port. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 31 +++++++++++++++---------------- drivers/net/dsa/mv88e6xxx/port.c | 39 ++++++++++++++++++--------------------- 2 files changed, 33 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 0534eb706caa..bf7ad2e8b4d7 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -489,8 +489,7 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, err = 0; restore_link: if (chip->info->ops->port_set_link(chip, port, link)) - netdev_err(chip->ds->ports[port].netdev, - "failed to restore MAC's link\n"); + dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port); return err; } @@ -514,7 +513,7 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, mutex_unlock(&chip->reg_lock); if (err && err != -EOPNOTSUPP) - netdev_err(ds->ports[port].netdev, "failed to configure MAC\n"); + dev_err(ds->dev, "p%d: failed to configure MAC\n", port); } static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port) @@ -941,7 +940,7 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, mutex_unlock(&chip->reg_lock); if (err) - netdev_err(ds->ports[port].netdev, "failed to update state\n"); + dev_err(ds->dev, "p%d: failed to update state\n", port); } static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) @@ -1009,7 +1008,7 @@ static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port) mutex_unlock(&chip->reg_lock); if (err) - netdev_err(ds->ports[port].netdev, "failed to flush ATU\n"); + dev_err(ds->dev, "p%d: failed to flush ATU\n", port); } static int mv88e6xxx_vtu_setup(struct mv88e6xxx_chip *chip) @@ -1214,10 +1213,9 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, if (!ds->ports[i].bridge_dev) continue; - netdev_warn(ds->ports[port].netdev, - "hardware VLAN %d already used by %s\n", - vlan.vid, - netdev_name(ds->ports[i].bridge_dev)); + dev_err(ds->dev, "p%d: hw VLAN %d already used by %s\n", + port, vlan.vid, + netdev_name(ds->ports[i].bridge_dev)); err = -EOPNOTSUPP; goto unlock; } @@ -1311,13 +1309,12 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) if (_mv88e6xxx_port_vlan_add(chip, port, vid, member)) - netdev_err(ds->ports[port].netdev, - "failed to add VLAN %d%c\n", - vid, untagged ? 'u' : 't'); + dev_err(ds->dev, "p%d: failed to add VLAN %d%c\n", port, + vid, untagged ? 'u' : 't'); if (pvid && mv88e6xxx_port_set_pvid(chip, port, vlan->vid_end)) - netdev_err(ds->ports[port].netdev, "failed to set PVID %d\n", - vlan->vid_end); + dev_err(ds->dev, "p%d: failed to set PVID %d\n", port, + vlan->vid_end); mutex_unlock(&chip->reg_lock); } @@ -1451,7 +1448,8 @@ static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, mutex_lock(&chip->reg_lock); if (mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid, GLOBAL_ATU_DATA_STATE_UC_STATIC)) - netdev_err(ds->ports[port].netdev, "failed to load unicast MAC address\n"); + dev_err(ds->dev, "p%d: failed to load unicast MAC address\n", + port); mutex_unlock(&chip->reg_lock); } @@ -3793,7 +3791,8 @@ static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, mutex_lock(&chip->reg_lock); if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, GLOBAL_ATU_DATA_STATE_MC_STATIC)) - netdev_err(ds->ports[port].netdev, "failed to load multicast MAC address\n"); + dev_err(ds->dev, "p%d: failed to load multicast MAC address\n", + port); mutex_unlock(&chip->reg_lock); } diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 3719ece60c61..fc09b26f9b49 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -76,9 +76,9 @@ static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, if (err) return err; - netdev_dbg(chip->ds->ports[port].netdev, "delay RXCLK %s, TXCLK %s\n", - reg & PORT_PCS_CTRL_RGMII_DELAY_RXCLK ? "yes" : "no", - reg & PORT_PCS_CTRL_RGMII_DELAY_TXCLK ? "yes" : "no"); + dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port, + reg & PORT_PCS_CTRL_RGMII_DELAY_RXCLK ? "yes" : "no", + reg & PORT_PCS_CTRL_RGMII_DELAY_TXCLK ? "yes" : "no"); return 0; } @@ -130,9 +130,9 @@ int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) if (err) return err; - netdev_dbg(chip->ds->ports[port].netdev, "%s link %s\n", - reg & PORT_PCS_CTRL_FORCE_LINK ? "Force" : "Unforce", - reg & PORT_PCS_CTRL_LINK_UP ? "up" : "down"); + dev_dbg(chip->dev, "p%d: %s link %s\n", port, + reg & PORT_PCS_CTRL_FORCE_LINK ? "Force" : "Unforce", + reg & PORT_PCS_CTRL_LINK_UP ? "up" : "down"); return 0; } @@ -166,9 +166,9 @@ int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup) if (err) return err; - netdev_dbg(chip->ds->ports[port].netdev, "%s %s duplex\n", - reg & PORT_PCS_CTRL_FORCE_DUPLEX ? "Force" : "Unforce", - reg & PORT_PCS_CTRL_DUPLEX_FULL ? "full" : "half"); + dev_dbg(chip->dev, "p%d: %s %s duplex\n", port, + reg & PORT_PCS_CTRL_FORCE_DUPLEX ? "Force" : "Unforce", + reg & PORT_PCS_CTRL_DUPLEX_FULL ? "full" : "half"); return 0; } @@ -226,10 +226,9 @@ static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port, return err; if (speed) - netdev_dbg(chip->ds->ports[port].netdev, - "Speed set to %d Mbps\n", speed); + dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed); else - netdev_dbg(chip->ds->ports[port].netdev, "Speed unforced\n"); + dev_dbg(chip->dev, "p%d: Speed unforced\n", port); return 0; } @@ -419,8 +418,8 @@ int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) if (err) return err; - netdev_dbg(chip->ds->ports[port].netdev, "PortState set to %s\n", - mv88e6xxx_port_state_names[state]); + dev_dbg(chip->dev, "p%d: PortState set to %s\n", port, + mv88e6xxx_port_state_names[state]); return 0; } @@ -580,8 +579,7 @@ int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map) if (err) return err; - netdev_dbg(chip->ds->ports[port].netdev, "VLANTable set to %.3x\n", - map); + dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map); return 0; } @@ -646,7 +644,7 @@ int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid) return err; } - netdev_dbg(chip->ds->ports[port].netdev, "FID set to %u\n", fid); + dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid); return 0; } @@ -683,8 +681,7 @@ int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid) if (err) return err; - netdev_dbg(chip->ds->ports[port].netdev, "DefaultVID set to %u\n", - pvid); + dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid); return 0; } @@ -761,8 +758,8 @@ int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, if (err) return err; - netdev_dbg(chip->ds->ports[port].netdev, "802.1QMode set to %s\n", - mv88e6xxx_port_8021q_mode_names[mode]); + dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port, + mv88e6xxx_port_8021q_mode_names[mode]); return 0; } -- cgit v1.2.3 From 31bef4e90cf761eaa16298461bcb4c101044baea Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 8 Jun 2017 18:34:09 -0400 Subject: net: dsa: mv88e6xxx: add egress mode enumeration As for the frame mode, add a mv88e6xxx_egress_mode enumeration instead of a 16-bit register mask. Reviewed-by: Andrew Lunn Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 11 ++++++----- drivers/net/dsa/mv88e6xxx/chip.h | 7 +++++++ drivers/net/dsa/mv88e6xxx/port.c | 20 ++++++++++++++++++-- drivers/net/dsa/mv88e6xxx/port.h | 2 +- 4 files changed, 32 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index bf7ad2e8b4d7..b610429f7516 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1722,8 +1722,8 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip) } static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, - enum mv88e6xxx_frame_mode frame, u16 egress, - u16 etype) + enum mv88e6xxx_frame_mode frame, + enum mv88e6xxx_egress_mode egress, u16 etype) { int err; @@ -1747,14 +1747,14 @@ static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port, static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) { return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, - PORT_CONTROL_EGRESS_UNMODIFIED, + MV88E6XXX_EGRESS_MODE_UNMODIFIED, PORT_ETH_TYPE_DEFAULT); } static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) { return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, - PORT_CONTROL_EGRESS_UNMODIFIED, + MV88E6XXX_EGRESS_MODE_UNMODIFIED, PORT_ETH_TYPE_DEFAULT); } @@ -1762,7 +1762,8 @@ static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) { return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_ETHERTYPE, - PORT_CONTROL_EGRESS_ADD_TAG, ETH_P_EDSA); + MV88E6XXX_EGRESS_MODE_ETHERTYPE, + ETH_P_EDSA); } static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port) diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 98c24af977fd..fb7dea33a44a 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -39,6 +39,13 @@ #define MV88E6XXX_MAX_PVT_SWITCHES 32 #define MV88E6XXX_MAX_PVT_PORTS 16 +enum mv88e6xxx_egress_mode { + MV88E6XXX_EGRESS_MODE_UNMODIFIED, + MV88E6XXX_EGRESS_MODE_UNTAGGED, + MV88E6XXX_EGRESS_MODE_TAGGED, + MV88E6XXX_EGRESS_MODE_ETHERTYPE, +}; + enum mv88e6xxx_frame_mode { MV88E6XXX_FRAME_MODE_NORMAL, MV88E6XXX_FRAME_MODE_DSA, diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index fc09b26f9b49..09e17131a6bd 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -425,7 +425,7 @@ int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) } int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port, - u16 mode) + enum mv88e6xxx_egress_mode mode) { int err; u16 reg; @@ -435,7 +435,23 @@ int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port, return err; reg &= ~PORT_CONTROL_EGRESS_MASK; - reg |= mode; + + switch (mode) { + case MV88E6XXX_EGRESS_MODE_UNMODIFIED: + reg |= PORT_CONTROL_EGRESS_UNMODIFIED; + break; + case MV88E6XXX_EGRESS_MODE_UNTAGGED: + reg |= PORT_CONTROL_EGRESS_UNTAGGED; + break; + case MV88E6XXX_EGRESS_MODE_TAGGED: + reg |= PORT_CONTROL_EGRESS_TAGGED; + break; + case MV88E6XXX_EGRESS_MODE_ETHERTYPE: + reg |= PORT_CONTROL_EGRESS_ADD_TAG; + break; + default: + return -EINVAL; + } return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); } diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 4f5e1ccfadc6..1de200074e21 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -212,7 +212,7 @@ int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port); int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port); int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port, - u16 mode); + enum mv88e6xxx_egress_mode mode); int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, enum mv88e6xxx_frame_mode mode); int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, -- cgit v1.2.3 From f894c29c3561bb9e1da7441146f1db585aae8e97 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 8 Jun 2017 18:34:10 -0400 Subject: net: dsa: mv88e6xxx: use bridge state values Reuse the BR_STATE_* values to abstract a port STP state value. This provides shorter names and better control over the DSA switch operation call. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 23 ++--------------------- drivers/net/dsa/mv88e6xxx/port.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index b610429f7516..e25d48ecf880 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -915,28 +915,10 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) { struct mv88e6xxx_chip *chip = ds->priv; - int stp_state; int err; - switch (state) { - case BR_STATE_DISABLED: - stp_state = PORT_CONTROL_STATE_DISABLED; - break; - case BR_STATE_BLOCKING: - case BR_STATE_LISTENING: - stp_state = PORT_CONTROL_STATE_BLOCKING; - break; - case BR_STATE_LEARNING: - stp_state = PORT_CONTROL_STATE_LEARNING; - break; - case BR_STATE_FORWARDING: - default: - stp_state = PORT_CONTROL_STATE_FORWARDING; - break; - } - mutex_lock(&chip->reg_lock); - err = mv88e6xxx_port_set_state(chip, port, stp_state); + err = mv88e6xxx_port_set_state(chip, port, state); mutex_unlock(&chip->reg_lock); if (err) @@ -1694,8 +1676,7 @@ static int mv88e6xxx_disable_ports(struct mv88e6xxx_chip *chip) /* Set all ports to the Disabled state */ for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { - err = mv88e6xxx_port_set_state(chip, i, - PORT_CONTROL_STATE_DISABLED); + err = mv88e6xxx_port_set_state(chip, i, BR_STATE_DISABLED); if (err) return err; } diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 09e17131a6bd..46e73ca0ac4d 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -12,6 +12,7 @@ * (at your option) any later version. */ +#include #include #include "chip.h" @@ -412,6 +413,25 @@ int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) return err; reg &= ~PORT_CONTROL_STATE_MASK; + + switch (state) { + case BR_STATE_DISABLED: + state = PORT_CONTROL_STATE_DISABLED; + break; + case BR_STATE_BLOCKING: + case BR_STATE_LISTENING: + state = PORT_CONTROL_STATE_BLOCKING; + break; + case BR_STATE_LEARNING: + state = PORT_CONTROL_STATE_LEARNING; + break; + case BR_STATE_FORWARDING: + state = PORT_CONTROL_STATE_FORWARDING; + break; + default: + return -EINVAL; + } + reg |= state; err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); -- cgit v1.2.3 From fa8d117960809879f949fb9768d78e0518c4964e Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 8 Jun 2017 18:34:11 -0400 Subject: net: dsa: mv88e6xxx: do not prefix ops with g1 The mv88e6xxx_ops describe functionalities, regardless their locations (which can be Global1, Global2, or whatever register set.) Rename the g1_set_cpu_port and g1_set_egress_port ops to set_cpu_port and set_egress_port. No functional changes. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 108 +++++++++++++++++++-------------------- drivers/net/dsa/mv88e6xxx/chip.h | 4 +- 2 files changed, 56 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index e25d48ecf880..f33b83bf3ee8 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2015,14 +2015,14 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) u32 upstream_port = dsa_upstream_port(ds); int err; - if (chip->info->ops->g1_set_cpu_port) { - err = chip->info->ops->g1_set_cpu_port(chip, upstream_port); + if (chip->info->ops->set_cpu_port) { + err = chip->info->ops->set_cpu_port(chip, upstream_port); if (err) return err; } - if (chip->info->ops->g1_set_egress_port) { - err = chip->info->ops->g1_set_egress_port(chip, upstream_port); + if (chip->info->ops->set_egress_port) { + err = chip->info->ops->set_egress_port(chip, upstream_port); if (err) return err; } @@ -2369,8 +2369,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .ppu_enable = mv88e6185_g1_ppu_enable, @@ -2424,8 +2424,8 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2449,8 +2449,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2478,8 +2478,8 @@ static const struct mv88e6xxx_ops mv88e6131_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .ppu_enable = mv88e6185_g1_ppu_enable, @@ -2513,8 +2513,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6390_stats_get_stats, - .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, - .g1_set_egress_port = mv88e6390_g1_set_egress_port, + .set_cpu_port = mv88e6390_g1_set_cpu_port, + .set_egress_port = mv88e6390_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2543,8 +2543,8 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2566,8 +2566,8 @@ static const struct mv88e6xxx_ops mv88e6165_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2597,8 +2597,8 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2630,8 +2630,8 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2662,8 +2662,8 @@ static const struct mv88e6xxx_ops mv88e6175_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2695,8 +2695,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2721,8 +2721,8 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .ppu_enable = mv88e6185_g1_ppu_enable, @@ -2755,8 +2755,8 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6390_stats_get_stats, - .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, - .g1_set_egress_port = mv88e6390_g1_set_egress_port, + .set_cpu_port = mv88e6390_g1_set_cpu_port, + .set_egress_port = mv88e6390_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2788,8 +2788,8 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6390_stats_get_stats, - .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, - .g1_set_egress_port = mv88e6390_g1_set_egress_port, + .set_cpu_port = mv88e6390_g1_set_cpu_port, + .set_egress_port = mv88e6390_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2821,8 +2821,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6390_stats_get_stats, - .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, - .g1_set_egress_port = mv88e6390_g1_set_egress_port, + .set_cpu_port = mv88e6390_g1_set_cpu_port, + .set_egress_port = mv88e6390_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2855,8 +2855,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2889,8 +2889,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6390_stats_get_stats, - .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, - .g1_set_egress_port = mv88e6390_g1_set_egress_port, + .set_cpu_port = mv88e6390_g1_set_cpu_port, + .set_egress_port = mv88e6390_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -2922,8 +2922,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6320_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, @@ -2953,8 +2953,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6320_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .reset = mv88e6352_g1_reset, .vtu_getnext = mv88e6185_g1_vtu_getnext, .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge, @@ -2984,8 +2984,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6390_stats_get_stats, - .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, - .g1_set_egress_port = mv88e6390_g1_set_egress_port, + .set_cpu_port = mv88e6390_g1_set_cpu_port, + .set_egress_port = mv88e6390_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -3015,8 +3015,8 @@ static const struct mv88e6xxx_ops mv88e6350_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -3046,8 +3046,8 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -3079,8 +3079,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, .stats_get_stats = mv88e6095_stats_get_stats, - .g1_set_cpu_port = mv88e6095_g1_set_cpu_port, - .g1_set_egress_port = mv88e6095_g1_set_egress_port, + .set_cpu_port = mv88e6095_g1_set_cpu_port, + .set_egress_port = mv88e6095_g1_set_egress_port, .watchdog_ops = &mv88e6097_watchdog_ops, .mgmt_rsvd2cpu = mv88e6095_g2_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -3115,8 +3115,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6390_stats_get_stats, - .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, - .g1_set_egress_port = mv88e6390_g1_set_egress_port, + .set_cpu_port = mv88e6390_g1_set_cpu_port, + .set_egress_port = mv88e6390_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, @@ -3150,8 +3150,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .stats_get_sset_count = mv88e6320_stats_get_sset_count, .stats_get_strings = mv88e6320_stats_get_strings, .stats_get_stats = mv88e6390_stats_get_stats, - .g1_set_cpu_port = mv88e6390_g1_set_cpu_port, - .g1_set_egress_port = mv88e6390_g1_set_egress_port, + .set_cpu_port = mv88e6390_g1_set_cpu_port, + .set_egress_port = mv88e6390_g1_set_egress_port, .watchdog_ops = &mv88e6390_watchdog_ops, .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, .reset = mv88e6352_g1_reset, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index fb7dea33a44a..07b35cccb0c4 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -456,8 +456,8 @@ struct mv88e6xxx_ops { void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data); void (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port, uint64_t *data); - int (*g1_set_cpu_port)(struct mv88e6xxx_chip *chip, int port); - int (*g1_set_egress_port)(struct mv88e6xxx_chip *chip, int port); + int (*set_cpu_port)(struct mv88e6xxx_chip *chip, int port); + int (*set_egress_port)(struct mv88e6xxx_chip *chip, int port); const struct mv88e6xxx_irq_ops *watchdog_ops; /* Can be either in g1 or g2, so don't use a prefix */ -- cgit v1.2.3 From 0898432cc296cc27cee6647f6748f2add37e09b6 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 8 Jun 2017 18:34:12 -0400 Subject: net: dsa: mv88e6xxx: rework pause limit operation All Marvell chips supporting Pause frames limiting use 1-byte value for input and output. Old chips have both bytes adjacent in a 16-bit register. New ones have an indirect table using 8-bit data. The mv88e6xxx library functions (such as in port.c) must not contain driver logic, but only generic helpers. This patch changes the port_pause_config operation for port_pause_limit taking two u8 arguments for input and output limits. There is no functional changes. Reviewed-by: Andrew Lunn Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 48 ++++++++++++++++++++-------------------- drivers/net/dsa/mv88e6xxx/chip.h | 3 ++- drivers/net/dsa/mv88e6xxx/port.c | 12 +++++----- drivers/net/dsa/mv88e6xxx/port.h | 6 +++-- 4 files changed, 37 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index f33b83bf3ee8..a0f450cb45fb 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1901,8 +1901,8 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) if (err) return err; - if (chip->info->ops->port_pause_config) { - err = chip->info->ops->port_pause_config(chip, port); + if (chip->info->ops->port_pause_limit) { + err = chip->info->ops->port_pause_limit(chip, port, 0, 0); if (err) return err; } @@ -2362,7 +2362,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, @@ -2417,7 +2417,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, @@ -2473,7 +2473,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = { .port_set_upstream_port = mv88e6095_port_set_upstream_port, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, .stats_get_sset_count = mv88e6095_stats_get_sset_count, .stats_get_strings = mv88e6095_stats_get_strings, @@ -2506,7 +2506,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6390_g1_stats_snapshot, @@ -2536,7 +2536,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -2590,7 +2590,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -2623,7 +2623,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -2655,7 +2655,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -2688,7 +2688,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -2747,7 +2747,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_pause_config = mv88e6390_port_pause_config, + .port_pause_limit = mv88e6390_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6390_g1_stats_snapshot, @@ -2780,7 +2780,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_pause_config = mv88e6390_port_pause_config, + .port_pause_limit = mv88e6390_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6390_g1_stats_snapshot, @@ -2813,7 +2813,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_pause_config = mv88e6390_port_pause_config, + .port_pause_limit = mv88e6390_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6390_g1_stats_snapshot, @@ -2848,7 +2848,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -2880,7 +2880,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_pause_config = mv88e6390_port_pause_config, + .port_pause_limit = mv88e6390_port_pause_limit, .port_set_cmode = mv88e6390x_port_set_cmode, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, @@ -2915,7 +2915,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -2946,7 +2946,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -2977,7 +2977,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6390_g1_stats_snapshot, @@ -3008,7 +3008,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -3039,7 +3039,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -3072,7 +3072,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6097_port_pause_config, + .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6320_g1_stats_snapshot, @@ -3106,7 +3106,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6390_port_pause_config, + .port_pause_limit = mv88e6390_port_pause_limit, .port_set_cmode = mv88e6390x_port_set_cmode, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, @@ -3142,7 +3142,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .port_set_ether_type = mv88e6351_port_set_ether_type, .port_jumbo_config = mv88e6165_port_jumbo_config, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, - .port_pause_config = mv88e6390_port_pause_config, + .port_pause_limit = mv88e6390_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .stats_snapshot = mv88e6390_g1_stats_snapshot, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 07b35cccb0c4..d5f55c28f613 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -425,7 +425,8 @@ struct mv88e6xxx_ops { int (*port_jumbo_config)(struct mv88e6xxx_chip *chip, int port); int (*port_egress_rate_limiting)(struct mv88e6xxx_chip *chip, int port); - int (*port_pause_config)(struct mv88e6xxx_chip *chip, int port); + int (*port_pause_limit)(struct mv88e6xxx_chip *chip, int port, u8 in, + u8 out); int (*port_disable_learn_limit)(struct mv88e6xxx_chip *chip, int port); int (*port_disable_pri_override)(struct mv88e6xxx_chip *chip, int port); diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 46e73ca0ac4d..ee94d16789a2 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -376,22 +376,24 @@ int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) * the remote end or the period of time that this port can pause the * remote end. */ -int mv88e6097_port_pause_config(struct mv88e6xxx_chip *chip, int port) +int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, + u8 out) { - return mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, 0x0000); + return mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, out << 8 | in); } -int mv88e6390_port_pause_config(struct mv88e6xxx_chip *chip, int port) +int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, + u8 out) { int err; err = mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, - PORT_FLOW_CTRL_LIMIT_IN | 0); + PORT_FLOW_CTRL_LIMIT_IN | in); if (err) return err; return mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, - PORT_FLOW_CTRL_LIMIT_OUT | 0); + PORT_FLOW_CTRL_LIMIT_OUT | out); } /* Offset 0x04: Port Control Register */ diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 1de200074e21..7be66f5b4c31 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -228,8 +228,10 @@ int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, int mv88e6165_port_jumbo_config(struct mv88e6xxx_chip *chip, int port); int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port); int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port); -int mv88e6097_port_pause_config(struct mv88e6xxx_chip *chip, int port); -int mv88e6390_port_pause_config(struct mv88e6xxx_chip *chip, int port); +int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, + u8 out); +int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, + u8 out); int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, phy_interface_t mode); int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode); -- cgit v1.2.3 From cd782656da9037150502a16bbbc46272e00f9b1b Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 8 Jun 2017 18:34:13 -0400 Subject: net: dsa: mv88e6xxx: rework jumbo size operation Marvell chips have a Jumbo Mode to set the maximum frame size (MTU). The mv88e6xxx_ops structure is meant to contain generic functionalities, no driver logic. Change port_jumbo_config to port_set_jumbo_size setting the mode from a given maximum size value. There is no functional changes since we still use 10240 bytes. At the same time, correctly clear all Jumbo Mode bits before writing. Reviewed-by: Andrew Lunn Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 38 +++++++++++++++++++------------------- drivers/net/dsa/mv88e6xxx/chip.h | 3 ++- drivers/net/dsa/mv88e6xxx/port.c | 14 ++++++++++++-- drivers/net/dsa/mv88e6xxx/port.h | 4 +++- 4 files changed, 36 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index a0f450cb45fb..a4cf0366765f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1876,8 +1876,8 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) if (err) return err; - if (chip->info->ops->port_jumbo_config) { - err = chip->info->ops->port_jumbo_config(chip, port); + if (chip->info->ops->port_set_jumbo_size) { + err = chip->info->ops->port_set_jumbo_size(chip, port, 10240); if (err) return err; } @@ -2415,7 +2415,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2471,7 +2471,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = { .port_set_egress_floods = mv88e6185_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_upstream_port = mv88e6095_port_set_upstream_port, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .stats_snapshot = mv88e6xxx_g1_stats_snapshot, @@ -2504,7 +2504,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2534,7 +2534,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2588,7 +2588,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2621,7 +2621,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2653,7 +2653,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2686,7 +2686,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2846,7 +2846,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2913,7 +2913,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2944,7 +2944,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -2975,7 +2975,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -3006,7 +3006,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -3037,7 +3037,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -3070,7 +3070,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -3104,7 +3104,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6390_port_pause_limit, .port_set_cmode = mv88e6390x_port_set_cmode, @@ -3140,7 +3140,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, - .port_jumbo_config = mv88e6165_port_jumbo_config, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6390_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index d5f55c28f613..d70873498501 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -422,7 +422,8 @@ struct mv88e6xxx_ops { bool unicast, bool multicast); int (*port_set_ether_type)(struct mv88e6xxx_chip *chip, int port, u16 etype); - int (*port_jumbo_config)(struct mv88e6xxx_chip *chip, int port); + int (*port_set_jumbo_size)(struct mv88e6xxx_chip *chip, int port, + size_t size); int (*port_egress_rate_limiting)(struct mv88e6xxx_chip *chip, int port); int (*port_pause_limit)(struct mv88e6xxx_chip *chip, int port, u8 in, diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index ee94d16789a2..efeb8d6b02e6 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -816,7 +816,8 @@ int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port) return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); } -int mv88e6165_port_jumbo_config(struct mv88e6xxx_chip *chip, int port) +int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port, + size_t size) { u16 reg; int err; @@ -825,7 +826,16 @@ int mv88e6165_port_jumbo_config(struct mv88e6xxx_chip *chip, int port) if (err) return err; - reg |= PORT_CONTROL_2_JUMBO_10240; + reg &= ~PORT_CONTROL_2_JUMBO_MASK; + + if (size <= 1522) + reg |= PORT_CONTROL_2_JUMBO_1522; + else if (size <= 2048) + reg |= PORT_CONTROL_2_JUMBO_2048; + else if (size <= 10240) + reg |= PORT_CONTROL_2_JUMBO_10240; + else + return -ERANGE; return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); } diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 7be66f5b4c31..8a59cabc20fa 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -133,6 +133,7 @@ #define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14) #define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13) #define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12) +#define PORT_CONTROL_2_JUMBO_MASK (0x03 << 12) #define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12) #define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12) #define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12) @@ -225,7 +226,8 @@ int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, u16 etype); int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, bool message_port); -int mv88e6165_port_jumbo_config(struct mv88e6xxx_chip *chip, int port); +int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port, + size_t size); int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port); int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port); int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, -- cgit v1.2.3 From bec90b6d96776a679965efe45778e28ff38c49b0 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 8 Jun 2017 18:34:14 -0400 Subject: net: dsa: mv88e6xxx: prefix PHY macros Prefix the PHY_* macros with a Marvell specific MV88E6XXX_ prefix. There is no functional changes. Reviewed-by: Andrew Lunn Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/phy.c | 11 ++++++----- drivers/net/dsa/mv88e6xxx/phy.h | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c index 0db624f0993c..3500ac0ea848 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.c +++ b/drivers/net/dsa/mv88e6xxx/phy.c @@ -62,7 +62,7 @@ int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, int reg, u16 val) static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page) { - return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); + return mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE, page); } static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy) @@ -72,7 +72,8 @@ static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy) /* Restore PHY page Copper 0x0 for access via the registered * MDIO bus */ - err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER); + err = mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE, + MV88E6XXX_PHY_PAGE_COPPER); if (unlikely(err)) { dev_err(chip->dev, "failed to restore PHY %d page Copper (%d)\n", @@ -86,7 +87,7 @@ int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy, int err; /* There is no paging for registers 22 */ - if (reg == PHY_PAGE) + if (reg == MV88E6XXX_PHY_PAGE) return -EINVAL; err = mv88e6xxx_phy_page_get(chip, phy, page); @@ -104,12 +105,12 @@ int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy, int err; /* There is no paging for registers 22 */ - if (reg == PHY_PAGE) + if (reg == MV88E6XXX_PHY_PAGE) return -EINVAL; err = mv88e6xxx_phy_page_get(chip, phy, page); if (!err) { - err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page); + err = mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE, page); mv88e6xxx_phy_page_put(chip, phy); } diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h index 4131a4e8206a..556b74a0502a 100644 --- a/drivers/net/dsa/mv88e6xxx/phy.h +++ b/drivers/net/dsa/mv88e6xxx/phy.h @@ -14,8 +14,8 @@ #ifndef _MV88E6XXX_PHY_H #define _MV88E6XXX_PHY_H -#define PHY_PAGE 0x16 -#define PHY_PAGE_COPPER 0x00 +#define MV88E6XXX_PHY_PAGE 0x16 +#define MV88E6XXX_PHY_PAGE_COPPER 0x00 /* PHY Registers accesses implementations */ int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, -- cgit v1.2.3 From 60b86665af0dfbeebda8aae43f0ba451cd2dcfe5 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 8 Jun 2017 16:21:18 -0700 Subject: netvsc: optimize calculation of number of slots Speed up transmit check for fragmented packets by using existing macros to compute number of pages, and eliminate loop since skb fragments each take a page. Number of slots is also unsigned. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 43 ++++++++++------------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 2564ac83eb64..df6d8e28949e 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -345,34 +345,14 @@ static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, return slots_used; } -static int count_skb_frag_slots(struct sk_buff *skb) -{ - int i, frags = skb_shinfo(skb)->nr_frags; - int pages = 0; - - for (i = 0; i < frags; i++) { - skb_frag_t *frag = skb_shinfo(skb)->frags + i; - unsigned long size = skb_frag_size(frag); - unsigned long offset = frag->page_offset; - - /* Skip unused frames from start of page */ - offset &= ~PAGE_MASK; - pages += PFN_UP(offset + size); - } - return pages; -} - -static int netvsc_get_slots(struct sk_buff *skb) +/* Estimate number of page buffers neede to transmit + * Need at most 2 for RNDIS header plus skb body and fragments. + */ +static unsigned int netvsc_get_slots(const struct sk_buff *skb) { - char *data = skb->data; - unsigned int offset = offset_in_page(data); - unsigned int len = skb_headlen(skb); - int slots; - int frag_slots; - - slots = DIV_ROUND_UP(offset + len, PAGE_SIZE); - frag_slots = count_skb_frag_slots(skb); - return slots + frag_slots; + return PFN_UP(offset_in_page(skb->data) + skb_headlen(skb)) + + skb_shinfo(skb)->nr_frags + + 2; } static u32 net_checksum_info(struct sk_buff *skb) @@ -410,21 +390,18 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT]; struct hv_page_buffer *pb = page_buf; - /* We will atmost need two pages to describe the rndis - * header. We can only transmit MAX_PAGE_BUFFER_COUNT number + /* We can only transmit MAX_PAGE_BUFFER_COUNT number * of pages in a single packet. If skb is scattered around * more pages we try linearizing it. */ - - num_data_pgs = netvsc_get_slots(skb) + 2; - + num_data_pgs = netvsc_get_slots(skb); if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) { ++net_device_ctx->eth_stats.tx_scattered; if (skb_linearize(skb)) goto no_memory; - num_data_pgs = netvsc_get_slots(skb) + 2; + num_data_pgs = netvsc_get_slots(skb); if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) { ++net_device_ctx->eth_stats.tx_too_big; goto drop; -- cgit v1.2.3 From 40975962788ef5b796ab0f36bfd7051064c915d3 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 8 Jun 2017 16:21:19 -0700 Subject: netvsc: use hv_get_bytes_to_read Don't need need to look at write space in netvsc_close. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index df6d8e28949e..436a3ad55cfd 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -120,7 +120,7 @@ static int netvsc_close(struct net_device *net) struct net_device_context *net_device_ctx = netdev_priv(net); struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); int ret; - u32 aread, awrite, i, msec = 10, retry = 0, retry_max = 20; + u32 aread, i, msec = 10, retry = 0, retry_max = 20; struct vmbus_channel *chn; netif_tx_disable(net); @@ -141,15 +141,11 @@ static int netvsc_close(struct net_device *net) if (!chn) continue; - hv_get_ringbuffer_availbytes(&chn->inbound, &aread, - &awrite); - + aread = hv_get_bytes_to_read(&chn->inbound); if (aread) break; - hv_get_ringbuffer_availbytes(&chn->outbound, &aread, - &awrite); - + aread = hv_get_bytes_to_read(&chn->outbound); if (aread) break; } -- cgit v1.2.3 From 2d05b56097664e1d8b7fd690e6eac03cc6a82cc3 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 8 Jun 2017 16:21:20 -0700 Subject: netvsc: use typed pointer for internal state The element netvsc_device:extension is always a pointer to RNDIS information. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 262b2ea576a3..f82d54e0208c 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -763,8 +763,7 @@ struct netvsc_device { refcount_t sc_offered; - /* Holds rndis device info */ - void *extension; + struct rndis_device *extension; int ring_size; -- cgit v1.2.3 From 2d694d2abe83c552dca156982ff378beb3ef0f1e Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 8 Jun 2017 16:21:21 -0700 Subject: netvsc: mark error cases as unlikely Mark if() statements used for error handling only as unlikely() Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 652453d9fb08..caf89a245ba6 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -855,14 +855,14 @@ int netvsc_send(struct hv_device *device, bool xmit_more = (skb != NULL) ? skb->xmit_more : false; net_device = get_outbound_net_device(device); - if (!net_device) + if (unlikely(!net_device)) return -ENODEV; /* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get * here before the negotiation with the host is finished and * send_section_map may not be allocated yet. */ - if (!net_device->send_section_map) + if (unlikely(!net_device->send_section_map)) return -EAGAIN; nvchan = &net_device->chan_table[packet->q_idx]; -- cgit v1.2.3 From 9579083732ce44313545d02de4b2ca168d0a9526 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 8 Jun 2017 16:21:22 -0700 Subject: netvsc: pass net_device to netvsc_init_buf and netvsc_connect_vsp Don't need to find netvsc_device structure, caller already had it. Also rearrange declarations. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index caf89a245ba6..4d4fde0c7974 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -243,18 +243,15 @@ static void netvsc_destroy_buf(struct hv_device *device) kfree(net_device->send_section_map); } -static int netvsc_init_buf(struct hv_device *device) +static int netvsc_init_buf(struct hv_device *device, + struct netvsc_device *net_device) { int ret = 0; - struct netvsc_device *net_device; struct nvsp_message *init_packet; struct net_device *ndev; size_t map_words; int node; - net_device = get_outbound_net_device(device); - if (!net_device) - return -ENODEV; ndev = hv_get_drvdata(device); node = cpu_to_node(device->channel->target_cpu); @@ -285,9 +282,7 @@ static int netvsc_init_buf(struct hv_device *device) /* Notify the NetVsp of the gpadl handle */ init_packet = &net_device->channel_init_pkt; - memset(init_packet, 0, sizeof(struct nvsp_message)); - init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF; init_packet->msg.v1_msg.send_recv_buf. gpadl_handle = net_device->recv_buf_gpadl_handle; @@ -486,20 +481,15 @@ static int negotiate_nvsp_ver(struct hv_device *device, return ret; } -static int netvsc_connect_vsp(struct hv_device *device) +static int netvsc_connect_vsp(struct hv_device *device, + struct netvsc_device *net_device) { - int ret; - struct netvsc_device *net_device; - struct nvsp_message *init_packet; - int ndis_version; const u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2, - NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 }; - int i; - - net_device = get_outbound_net_device(device); - if (!net_device) - return -ENODEV; + NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 + }; + struct nvsp_message *init_packet; + int ndis_version, i, ret; init_packet = &net_device->channel_init_pkt; @@ -549,7 +539,7 @@ static int netvsc_connect_vsp(struct hv_device *device) net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; net_device->send_buf_size = NETVSC_SEND_BUFFER_SIZE; - ret = netvsc_init_buf(device); + ret = netvsc_init_buf(device, net_device); cleanup: return ret; @@ -1349,7 +1339,7 @@ int netvsc_device_add(struct hv_device *device, rcu_assign_pointer(net_device_ctx->nvdev, net_device); /* Connect with the NetVsp */ - ret = netvsc_connect_vsp(device); + ret = netvsc_connect_vsp(device, net_device); if (ret != 0) { netdev_err(ndev, "unable to connect to NetVSP - %d\n", ret); @@ -1368,4 +1358,5 @@ cleanup: free_netvsc_device(&net_device->rcu); return ret; + } -- cgit v1.2.3 From 592b4fe895c03315d9917bf0227a165be401ec33 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 8 Jun 2017 16:21:23 -0700 Subject: netvsc: fold in get_outbound_net_device No longer need common code to find get_outbound_net_device. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 4d4fde0c7974..7c5ed8fe7a4f 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -97,16 +97,6 @@ static void free_netvsc_device_rcu(struct netvsc_device *nvdev) call_rcu(&nvdev->rcu, free_netvsc_device); } -static struct netvsc_device *get_outbound_net_device(struct hv_device *device) -{ - struct netvsc_device *net_device = hv_device_to_netvsc_device(device); - - if (net_device && net_device->destroy) - net_device = NULL; - - return net_device; -} - static void netvsc_destroy_buf(struct hv_device *device) { struct nvsp_message *revoke_packet; @@ -833,7 +823,7 @@ int netvsc_send(struct hv_device *device, struct hv_page_buffer **pb, struct sk_buff *skb) { - struct netvsc_device *net_device; + struct netvsc_device *net_device = hv_device_to_netvsc_device(device); int ret = 0; struct netvsc_channel *nvchan; u32 pktlen = packet->total_data_buflen, msd_len = 0; @@ -844,8 +834,8 @@ int netvsc_send(struct hv_device *device, bool try_batch; bool xmit_more = (skb != NULL) ? skb->xmit_more : false; - net_device = get_outbound_net_device(device); - if (unlikely(!net_device)) + /* If device is rescinded, return error and packet will get dropped. */ + if (unlikely(net_device->destroy)) return -ENODEV; /* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get -- cgit v1.2.3 From 3ad7d2468f79fc13215eb941f766a692d34b1381 Mon Sep 17 00:00:00 2001 From: Krister Johansen Date: Thu, 8 Jun 2017 13:12:14 -0700 Subject: Ipvlan should return an error when an address is already in use. The ipvlan code already knows how to detect when a duplicate address is about to be assigned to an ipvlan device. However, that failure is not propogated outward and leads to a silent failure. Introduce a validation step at ip address creation time and allow device drivers to register to validate the incoming ip addresses. The ipvlan code is the first consumer. If it detects an address in use, we can return an error to the user before beginning to commit the new ifa in the networking code. This can be especially useful if it is necessary to provision many ipvlans in containers. The provisioning software (or operator) can use this to detect situations where an ip address is unexpectedly in use. Signed-off-by: Krister Johansen Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_main.c | 69 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 618ed88fad0f..e4141d62b5c3 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -824,6 +824,33 @@ static int ipvlan_addr6_event(struct notifier_block *unused, return NOTIFY_OK; } +static int ipvlan_addr6_validator_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct in6_validator_info *i6vi = (struct in6_validator_info *)ptr; + struct net_device *dev = (struct net_device *)i6vi->i6vi_dev->dev; + struct ipvl_dev *ipvlan = netdev_priv(dev); + + /* FIXME IPv6 autoconf calls us from bh without RTNL */ + if (in_softirq()) + return NOTIFY_DONE; + + if (!netif_is_ipvlan(dev)) + return NOTIFY_DONE; + + if (!ipvlan || !ipvlan->port) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + if (ipvlan_addr_busy(ipvlan->port, &i6vi->i6vi_addr, true)) + return notifier_from_errno(-EADDRINUSE); + break; + } + + return NOTIFY_OK; +} + static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) { if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) { @@ -871,10 +898,37 @@ static int ipvlan_addr4_event(struct notifier_block *unused, return NOTIFY_OK; } +static int ipvlan_addr4_validator_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct in_validator_info *ivi = (struct in_validator_info *)ptr; + struct net_device *dev = (struct net_device *)ivi->ivi_dev->dev; + struct ipvl_dev *ipvlan = netdev_priv(dev); + + if (!netif_is_ipvlan(dev)) + return NOTIFY_DONE; + + if (!ipvlan || !ipvlan->port) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + if (ipvlan_addr_busy(ipvlan->port, &ivi->ivi_addr, false)) + return notifier_from_errno(-EADDRINUSE); + break; + } + + return NOTIFY_OK; +} + static struct notifier_block ipvlan_addr4_notifier_block __read_mostly = { .notifier_call = ipvlan_addr4_event, }; +static struct notifier_block ipvlan_addr4_vtor_notifier_block __read_mostly = { + .notifier_call = ipvlan_addr4_validator_event, +}; + static struct notifier_block ipvlan_notifier_block __read_mostly = { .notifier_call = ipvlan_device_event, }; @@ -883,6 +937,10 @@ static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = { .notifier_call = ipvlan_addr6_event, }; +static struct notifier_block ipvlan_addr6_vtor_notifier_block __read_mostly = { + .notifier_call = ipvlan_addr6_validator_event, +}; + static void ipvlan_ns_exit(struct net *net) { struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid); @@ -907,7 +965,10 @@ static int __init ipvlan_init_module(void) ipvlan_init_secret(); register_netdevice_notifier(&ipvlan_notifier_block); register_inet6addr_notifier(&ipvlan_addr6_notifier_block); + register_inet6addr_validator_notifier( + &ipvlan_addr6_vtor_notifier_block); register_inetaddr_notifier(&ipvlan_addr4_notifier_block); + register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block); err = register_pernet_subsys(&ipvlan_net_ops); if (err < 0) @@ -922,7 +983,11 @@ static int __init ipvlan_init_module(void) return 0; error: unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); + unregister_inetaddr_validator_notifier( + &ipvlan_addr4_vtor_notifier_block); unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); + unregister_inet6addr_validator_notifier( + &ipvlan_addr6_vtor_notifier_block); unregister_netdevice_notifier(&ipvlan_notifier_block); return err; } @@ -933,7 +998,11 @@ static void __exit ipvlan_cleanup_module(void) unregister_pernet_subsys(&ipvlan_net_ops); unregister_netdevice_notifier(&ipvlan_notifier_block); unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); + unregister_inetaddr_validator_notifier( + &ipvlan_addr4_vtor_notifier_block); unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); + unregister_inet6addr_validator_notifier( + &ipvlan_addr6_vtor_notifier_block); } module_init(ipvlan_init_module); -- cgit v1.2.3 From fda7057f4b5356d40d321f339f4ac6b3f94076ec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 6 Jun 2017 17:47:17 +0300 Subject: Bluetooth: hci_bcm: Switch to devm_acpi_dev_add_driver_gpios() Switch to use managed variant of acpi_dev_add_driver_gpios() to simplify error path and fix potentially wrong assingment if ->probe() fails. Signed-off-by: Andy Shevchenko Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_bcm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index f87bfdfee4ff..e2096c7803b3 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -762,8 +762,7 @@ static int bcm_acpi_probe(struct bcm_device *dev) if (id) gpio_mapping = (const struct acpi_gpio_mapping *) id->driver_data; - ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev), - gpio_mapping); + ret = devm_acpi_dev_add_driver_gpios(&pdev->dev, gpio_mapping); if (ret) return ret; @@ -834,8 +833,6 @@ static int bcm_remove(struct platform_device *pdev) list_del(&dev->list); mutex_unlock(&bcm_device_lock); - acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev)); - dev_info(&pdev->dev, "%s device unregistered.\n", dev->name); return 0; -- cgit v1.2.3 From 4a59d433c98bcd9e1032009abbd43415405cd763 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 6 Jun 2017 17:47:18 +0300 Subject: Bluetooth: hci_intel: Add GPIO ACPI mapping table In order to make GPIO ACPI library stricter prepare users of gpiod_get_index() to correctly behave when there no mapping is provided by firmware. Here we add explicit mapping between _CRS GpioIo() resources and their names used in the driver. Signed-off-by: Andy Shevchenko Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_intel.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index fa5099986f1b..851bee82df2a 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -1205,9 +1205,19 @@ static const struct dev_pm_ops intel_pm_ops = { SET_RUNTIME_PM_OPS(intel_suspend_device, intel_resume_device, NULL) }; +static const struct acpi_gpio_params reset_gpios = { 0, 0, false }; +static const struct acpi_gpio_params host_wake_gpios = { 1, 0, false }; + +static const struct acpi_gpio_mapping acpi_hci_intel_gpios[] = { + { "reset-gpios", &reset_gpios, 1 }, + { "host-wake-gpios", &host_wake_gpios, 1 }, + { }, +}; + static int intel_probe(struct platform_device *pdev) { struct intel_device *idev; + int ret; idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL); if (!idev) @@ -1217,6 +1227,10 @@ static int intel_probe(struct platform_device *pdev) idev->pdev = pdev; + ret = devm_acpi_dev_add_driver_gpios(&pdev->dev, acpi_hci_intel_gpios); + if (ret) + dev_dbg(&pdev->dev, "Unable to add GPIO mapping table\n"); + idev->reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(idev->reset)) { dev_err(&pdev->dev, "Unable to retrieve gpio\n"); -- cgit v1.2.3 From fe741e2362f33bbea813bcc3a921de356c6653db Mon Sep 17 00:00:00 2001 From: Girish Moodalbail Date: Thu, 8 Jun 2017 17:07:48 -0700 Subject: geneve: add missing rx stats accounting There are few places on the receive path where packet drops and packet errors were not accounted for. This patch fixes that issue. Signed-off-by: Girish Moodalbail Signed-off-by: David S. Miller --- drivers/net/geneve.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 6ebb0f559a42..ff626dbde23f 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -212,6 +212,7 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, struct genevehdr *gnvh = geneve_hdr(skb); struct metadata_dst *tun_dst = NULL; struct pcpu_sw_netstats *stats; + unsigned int len; int err = 0; void *oiph; @@ -225,8 +226,10 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags, vni_to_tunnel_id(gnvh->vni), gnvh->opt_len * 4); - if (!tun_dst) + if (!tun_dst) { + geneve->dev->stats.rx_dropped++; goto drop; + } /* Update tunnel dst according to Geneve options. */ ip_tunnel_info_opts_set(&tun_dst->u.tun_info, gnvh->options, gnvh->opt_len * 4); @@ -234,8 +237,11 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, /* Drop packets w/ critical options, * since we don't support any... */ - if (gnvh->critical) + if (gnvh->critical) { + geneve->dev->stats.rx_frame_errors++; + geneve->dev->stats.rx_errors++; goto drop; + } } skb_reset_mac_header(skb); @@ -246,8 +252,10 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, skb_dst_set(skb, &tun_dst->dst); /* Ignore packet loops (and multicast echo) */ - if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) + if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) { + geneve->dev->stats.rx_errors++; goto drop; + } oiph = skb_network_header(skb); skb_reset_network_header(skb); @@ -279,13 +287,15 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, } } - stats = this_cpu_ptr(geneve->dev->tstats); - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += skb->len; - u64_stats_update_end(&stats->syncp); - - gro_cells_receive(&geneve->gro_cells, skb); + len = skb->len; + err = gro_cells_receive(&geneve->gro_cells, skb); + if (likely(err == NET_RX_SUCCESS)) { + stats = this_cpu_ptr(geneve->dev->tstats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += len; + u64_stats_update_end(&stats->syncp); + } return; drop: /* Consume bad packet */ @@ -334,7 +344,7 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) struct geneve_sock *gs; int opts_len; - /* Need Geneve and inner Ethernet header to be present */ + /* Need UDP and Geneve header to be present */ if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN))) goto drop; @@ -357,8 +367,10 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) opts_len = geneveh->opt_len * 4; if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, htons(ETH_P_TEB), - !net_eq(geneve->net, dev_net(geneve->dev)))) + !net_eq(geneve->net, dev_net(geneve->dev)))) { + geneve->dev->stats.rx_dropped++; goto drop; + } geneve_rx(geneve, gs, skb); return 0; -- cgit v1.2.3 From 7fa136531e646b0608b08a6afa85030a57a7ff33 Mon Sep 17 00:00:00 2001 From: Derek Chickles Date: Thu, 8 Jun 2017 19:20:36 -0700 Subject: liquidio: disallow enabling firmware debug from a VF Disallow enabling firmware debug from a VF. Only PF is allowed to do that. Signed-off-by: Derek Chickles Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_ethtool.c | 9 ++++++++- drivers/net/ethernet/cavium/liquidio/lio_vf_main.c | 4 ---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index 2e253061460b..53856af07d46 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -700,6 +700,13 @@ static void lio_set_msglevel(struct net_device *netdev, u32 msglvl) lio->msg_enable = msglvl; } +static void lio_vf_set_msglevel(struct net_device *netdev, u32 msglvl) +{ + struct lio *lio = GET_LIO(netdev); + + lio->msg_enable = msglvl; +} + static void lio_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { @@ -2611,7 +2618,7 @@ static const struct ethtool_ops lio_vf_ethtool_ops = { .get_regs_len = lio_get_regs_len, .get_regs = lio_get_regs, .get_msglevel = lio_get_msglevel, - .set_msglevel = lio_set_msglevel, + .set_msglevel = lio_vf_set_msglevel, .get_sset_count = lio_vf_get_sset_count, .get_coalesce = lio_get_intr_coalesce, .set_coalesce = lio_set_intr_coalesce, diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 07124096db48..1f7032614ae5 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -2997,10 +2997,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE, OCTNIC_LROIPV4 | OCTNIC_LROIPV6); - if ((debug != -1) && (debug & NETIF_MSG_HW)) - liquidio_set_feature(netdev, OCTNET_CMD_VERBOSE_ENABLE, - 0); - if (setup_link_status_change_wq(netdev)) goto setup_nic_dev_fail; -- cgit v1.2.3 From ab832b8de405c640d407b4473c6875210c326255 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2017 20:56:10 -0700 Subject: nfp: make sure to cancel port refresh on the error path If very last stages of netdev registering and init fail some other netdevs and devlink ports may have been visible to user space before we torn them back down. In this case there is a slight chance user may have triggered port refresh. We need to make sure the async work is cancelled. We have to cancel after releasing pf->lock, so we will always try to cancel, regardless of which part of probe has failed. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 5f27703060c2..cdd25dc5988d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -813,6 +813,7 @@ err_ctrl_unmap: nfp_cpp_area_release_free(pf->data_vnic_bar); err_unlock: mutex_unlock(&pf->lock); + cancel_work_sync(&pf->port_refresh_work); return err; } -- cgit v1.2.3 From af4fa7eac770720d5edb9337ab0bccb843936364 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2017 20:56:11 -0700 Subject: nfp: remove automatic caching of RTsym table The fact that RTsym table is cached inside nfp_cpp handle is a relic of old times when nfpcore was a library module. All the nfp_cpp "caches" are awkward to deal with because of concurrency and prone to keeping stale information. Make the run time symbol table be an object read out from the device and managed by whoever requested it. Since the driver loads FW at ->probe() and never reloads, we can hold onto the table for ever. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 6 +- drivers/net/ethernet/netronome/nfp/nfp_main.h | 3 + drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 4 +- .../net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 4 - .../ethernet/netronome/nfp/nfpcore/nfp_cppcore.c | 26 ----- .../net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h | 13 ++- .../net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c | 8 +- .../net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c | 111 ++++++++------------- 8 files changed, 63 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 0c2e64d217b5..51fe8de34b67 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -77,7 +77,7 @@ static int nfp_pcie_sriov_read_nfd_limit(struct nfp_pf *pf) { int err; - pf->limit_vfs = nfp_rtsym_read_le(pf->cpp, "nfd_vf_cfg_max_vfs", &err); + pf->limit_vfs = nfp_rtsym_read_le(pf->rtbl, "nfd_vf_cfg_max_vfs", &err); if (!err) return pci_sriov_set_totalvfs(pf->pdev, pf->limit_vfs); @@ -373,6 +373,8 @@ static int nfp_pci_probe(struct pci_dev *pdev, if (err) goto err_devlink_unreg; + pf->rtbl = nfp_rtsym_table_read(pf->cpp); + err = nfp_pcie_sriov_read_nfd_limit(pf); if (err) goto err_fw_unload; @@ -394,6 +396,7 @@ err_net_remove: err_sriov_unlimit: pci_sriov_set_totalvfs(pf->pdev, 0); err_fw_unload: + kfree(pf->rtbl); if (pf->fw_loaded) nfp_fw_unload(pf); kfree(pf->eth_tbl); @@ -430,6 +433,7 @@ static void nfp_pci_remove(struct pci_dev *pdev) devlink_unregister(devlink); + kfree(pf->rtbl); if (pf->fw_loaded) nfp_fw_unload(pf); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 37832853b0b3..907852f00423 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -56,6 +56,7 @@ struct nfp_cpp_area; struct nfp_eth_table; struct nfp_net; struct nfp_nsp_identify; +struct nfp_rtsym_table; /** * struct nfp_pf - NFP PF-specific device structure @@ -70,6 +71,7 @@ struct nfp_nsp_identify; * @num_vfs: Number of SR-IOV VFs enabled * @fw_loaded: Is the firmware loaded? * @ctrl_vnic: Pointer to the control vNIC if available + * @rtbl: RTsym table * @eth_tbl: NSP ETH table * @nspi: NSP identification info * @hwmon_dev: pointer to hwmon device @@ -101,6 +103,7 @@ struct nfp_pf { struct nfp_net *ctrl_vnic; + struct nfp_rtsym_table *rtbl; struct nfp_eth_table *eth_tbl; struct nfp_nsp_identify *nspi; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index cdd25dc5988d..c845049fcff2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -201,7 +201,7 @@ nfp_net_pf_rtsym_read_optional(struct nfp_pf *pf, const char *format, snprintf(name, sizeof(name), format, nfp_cppcore_pcie_unit(pf->cpp)); - val = nfp_rtsym_read_le(pf->cpp, name, &err); + val = nfp_rtsym_read_le(pf->rtbl, name, &err); if (err) { if (err == -ENOENT) return default_val; @@ -234,7 +234,7 @@ nfp_net_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt, snprintf(pf_symbol, sizeof(pf_symbol), sym_fmt, nfp_cppcore_pcie_unit(pf->cpp)); - sym = nfp_rtsym_lookup(pf->cpp, pf_symbol); + sym = nfp_rtsym_lookup(pf->rtbl, pf_symbol); if (!sym) { nfp_err(pf->cpp, "Failed to find PF symbol %s\n", pf_symbol); return (u8 __iomem *)ERR_PTR(-ENOENT); diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index 0a46c0984e68..e3a2201eb658 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -224,10 +224,6 @@ int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial); void *nfp_hwinfo_cache(struct nfp_cpp *cpp); void nfp_hwinfo_cache_set(struct nfp_cpp *cpp, void *val); -void *nfp_rtsym_cache(struct nfp_cpp *cpp); -void nfp_rtsym_cache_set(struct nfp_cpp *cpp, void *val); - -void nfp_nffw_cache_flush(struct nfp_cpp *cpp); struct nfp_cpp_area *nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp, u32 cpp_id, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c index 5672d309d07d..f477186558bd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c @@ -78,7 +78,6 @@ struct nfp_cpp_resource { * * Following fields can be used only in probe() or with rtnl held: * @hwinfo: HWInfo database fetched from the device - * @rtsym: firmware run time symbols * * Following fields use explicit locking: * @resource_list: NFP CPP resource list @@ -109,7 +108,6 @@ struct nfp_cpp { struct list_head area_cache_list; void *hwinfo; - void *rtsym; }; /* Element of the area_cache_list */ @@ -234,7 +232,6 @@ void nfp_cpp_free(struct nfp_cpp *cpp) cpp->op->free(cpp); kfree(cpp->hwinfo); - kfree(cpp->rtsym); device_unregister(&cpp->dev); @@ -286,29 +283,6 @@ void nfp_hwinfo_cache_set(struct nfp_cpp *cpp, void *val) cpp->hwinfo = val; } -void *nfp_rtsym_cache(struct nfp_cpp *cpp) -{ - return cpp->rtsym; -} - -void nfp_rtsym_cache_set(struct nfp_cpp *cpp, void *val) -{ - cpp->rtsym = val; -} - -/** - * nfp_nffw_cache_flush() - Flush cached firmware information - * @cpp: NFP CPP handle - * - * Flush cached firmware information. This function should be called - * every time firmware is loaded on unloaded. - */ -void nfp_nffw_cache_flush(struct nfp_cpp *cpp) -{ - kfree(nfp_rtsym_cache(cpp)); - nfp_rtsym_cache_set(cpp, NULL); -} - /** * nfp_cpp_area_alloc_with_name() - allocate a new CPP area * @cpp: CPP device handle diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h index 988badd230d1..f845cf5dd762 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h @@ -87,9 +87,14 @@ struct nfp_rtsym { int domain; }; -int nfp_rtsym_count(struct nfp_cpp *cpp); -const struct nfp_rtsym *nfp_rtsym_get(struct nfp_cpp *cpp, int idx); -const struct nfp_rtsym *nfp_rtsym_lookup(struct nfp_cpp *cpp, const char *name); -u64 nfp_rtsym_read_le(struct nfp_cpp *cpp, const char *name, int *error); +struct nfp_rtsym_table; + +struct nfp_rtsym_table *nfp_rtsym_table_read(struct nfp_cpp *cpp); +int nfp_rtsym_count(struct nfp_rtsym_table *rtbl); +const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx); +const struct nfp_rtsym * +nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name); +u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, + int *error); #endif /* NFP_NFFW_H */ diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index eefdb756d74e..37364555c42b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -474,13 +474,7 @@ int nfp_nsp_wait(struct nfp_nsp *state) int nfp_nsp_device_soft_reset(struct nfp_nsp *state) { - int err; - - err = nfp_nsp_command(state, SPCODE_SOFT_RESET, 0, 0, 0); - - nfp_nffw_cache_flush(state->cpp); - - return err; + return nfp_nsp_command(state, SPCODE_SOFT_RESET, 0, 0, 0); } int nfp_nsp_load_fw(struct nfp_nsp *state, const struct firmware *fw) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 0e3870ecfb8c..ef3566163cb0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -65,7 +65,8 @@ struct nfp_rtsym_entry { __le32 size_lo; }; -struct nfp_rtsym_cache { +struct nfp_rtsym_table { + struct nfp_cpp *cpp; int num; char *strtab; struct nfp_rtsym symtab[]; @@ -78,7 +79,7 @@ static int nfp_meid(u8 island_id, u8 menum) } static void -nfp_rtsym_sw_entry_init(struct nfp_rtsym_cache *cache, u32 strtab_size, +nfp_rtsym_sw_entry_init(struct nfp_rtsym_table *cache, u32 strtab_size, struct nfp_rtsym *sw, struct nfp_rtsym_entry *fw) { sw->type = fw->type; @@ -106,26 +107,26 @@ nfp_rtsym_sw_entry_init(struct nfp_rtsym_cache *cache, u32 strtab_size, sw->domain = -1; } -static int nfp_rtsymtab_probe(struct nfp_cpp *cpp) +struct nfp_rtsym_table *nfp_rtsym_table_read(struct nfp_cpp *cpp) { const u32 dram = NFP_CPP_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0) | NFP_ISL_EMEM0; u32 strtab_addr, symtab_addr, strtab_size, symtab_size; struct nfp_rtsym_entry *rtsymtab; - struct nfp_rtsym_cache *cache; + struct nfp_rtsym_table *cache; const struct nfp_mip *mip; int err, n, size; mip = nfp_mip_open(cpp); if (!mip) - return -EIO; + return NULL; nfp_mip_strtab(mip, &strtab_addr, &strtab_size); nfp_mip_symtab(mip, &symtab_addr, &symtab_size); nfp_mip_close(mip); if (!symtab_size || !strtab_size || symtab_size % sizeof(*rtsymtab)) - return -ENXIO; + return NULL; /* Align to 64 bits */ symtab_size = round_up(symtab_size, 8); @@ -133,27 +134,26 @@ static int nfp_rtsymtab_probe(struct nfp_cpp *cpp) rtsymtab = kmalloc(symtab_size, GFP_KERNEL); if (!rtsymtab) - return -ENOMEM; + return NULL; size = sizeof(*cache); size += symtab_size / sizeof(*rtsymtab) * sizeof(struct nfp_rtsym); size += strtab_size + 1; cache = kmalloc(size, GFP_KERNEL); - if (!cache) { - err = -ENOMEM; - goto err_free_rtsym_raw; - } + if (!cache) + goto exit_free_rtsym_raw; + cache->cpp = cpp; cache->num = symtab_size / sizeof(*rtsymtab); cache->strtab = (void *)&cache->symtab[cache->num]; err = nfp_cpp_read(cpp, dram, symtab_addr, rtsymtab, symtab_size); if (err != symtab_size) - goto err_free_cache; + goto exit_free_cache; err = nfp_cpp_read(cpp, dram, strtab_addr, cache->strtab, strtab_size); if (err != strtab_size) - goto err_free_cache; + goto exit_free_cache; cache->strtab[strtab_size] = '\0'; for (n = 0; n < cache->num; n++) @@ -161,97 +161,71 @@ static int nfp_rtsymtab_probe(struct nfp_cpp *cpp) &cache->symtab[n], &rtsymtab[n]); kfree(rtsymtab); - nfp_rtsym_cache_set(cpp, cache); - return 0; -err_free_cache: + return cache; + +exit_free_cache: kfree(cache); -err_free_rtsym_raw: +exit_free_rtsym_raw: kfree(rtsymtab); - return err; -} - -static struct nfp_rtsym_cache *nfp_rtsym(struct nfp_cpp *cpp) -{ - struct nfp_rtsym_cache *cache; - int err; - - cache = nfp_rtsym_cache(cpp); - if (cache) - return cache; - - err = nfp_rtsymtab_probe(cpp); - if (err < 0) - return ERR_PTR(err); - - return nfp_rtsym_cache(cpp); + return NULL; } /** * nfp_rtsym_count() - Get the number of RTSYM descriptors - * @cpp: NFP CPP handle + * @rtbl: NFP RTsym table * - * Return: Number of RTSYM descriptors, or -ERRNO + * Return: Number of RTSYM descriptors */ -int nfp_rtsym_count(struct nfp_cpp *cpp) +int nfp_rtsym_count(struct nfp_rtsym_table *rtbl) { - struct nfp_rtsym_cache *cache; - - cache = nfp_rtsym(cpp); - if (IS_ERR(cache)) - return PTR_ERR(cache); - - return cache->num; + if (!rtbl) + return -EINVAL; + return rtbl->num; } /** * nfp_rtsym_get() - Get the Nth RTSYM descriptor - * @cpp: NFP CPP handle + * @rtbl: NFP RTsym table * @idx: Index (0-based) of the RTSYM descriptor * * Return: const pointer to a struct nfp_rtsym descriptor, or NULL */ -const struct nfp_rtsym *nfp_rtsym_get(struct nfp_cpp *cpp, int idx) +const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx) { - struct nfp_rtsym_cache *cache; - - cache = nfp_rtsym(cpp); - if (IS_ERR(cache)) + if (!rtbl) return NULL; - - if (idx >= cache->num) + if (idx >= rtbl->num) return NULL; - return &cache->symtab[idx]; + return &rtbl->symtab[idx]; } /** * nfp_rtsym_lookup() - Return the RTSYM descriptor for a symbol name - * @cpp: NFP CPP handle + * @rtbl: NFP RTsym table * @name: Symbol name * * Return: const pointer to a struct nfp_rtsym descriptor, or NULL */ -const struct nfp_rtsym *nfp_rtsym_lookup(struct nfp_cpp *cpp, const char *name) +const struct nfp_rtsym * +nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name) { - struct nfp_rtsym_cache *cache; int n; - cache = nfp_rtsym(cpp); - if (IS_ERR(cache)) + if (!rtbl) return NULL; - for (n = 0; n < cache->num; n++) { - if (strcmp(name, cache->symtab[n].name) == 0) - return &cache->symtab[n]; - } + for (n = 0; n < rtbl->num; n++) + if (strcmp(name, rtbl->symtab[n].name) == 0) + return &rtbl->symtab[n]; return NULL; } /** * nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol - * @cpp: NFP CPP handle + * @rtbl: NFP RTsym table * @name: Symbol name * @error: Poniter to error code (optional) * @@ -261,14 +235,15 @@ const struct nfp_rtsym *nfp_rtsym_lookup(struct nfp_cpp *cpp, const char *name) * * Return: value read, on error sets the error and returns ~0ULL. */ -u64 nfp_rtsym_read_le(struct nfp_cpp *cpp, const char *name, int *error) +u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, + int *error) { const struct nfp_rtsym *sym; u32 val32, id; u64 val; int err; - sym = nfp_rtsym_lookup(cpp, name); + sym = nfp_rtsym_lookup(rtbl, name); if (!sym) { err = -ENOENT; goto exit; @@ -278,14 +253,14 @@ u64 nfp_rtsym_read_le(struct nfp_cpp *cpp, const char *name, int *error) switch (sym->size) { case 4: - err = nfp_cpp_readl(cpp, id, sym->addr, &val32); + err = nfp_cpp_readl(rtbl->cpp, id, sym->addr, &val32); val = val32; break; case 8: - err = nfp_cpp_readq(cpp, id, sym->addr, &val); + err = nfp_cpp_readq(rtbl->cpp, id, sym->addr, &val); break; default: - nfp_err(cpp, + nfp_err(rtbl->cpp, "rtsym '%s' unsupported or non-scalar size: %lld\n", name, sym->size); err = -EINVAL; -- cgit v1.2.3 From 9baa48859bd31f06b9170e86afd92585ff0bbb1f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2017 20:56:12 -0700 Subject: nfp: remove automatic caching of HWInfo Make callers take care of managing life time of HWInfo. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_app_nic.c | 2 +- drivers/net/ethernet/netronome/nfp/nfp_main.c | 20 ++++--- drivers/net/ethernet/netronome/nfp/nfp_main.h | 5 +- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 12 ++-- drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h | 4 +- .../net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 3 - .../ethernet/netronome/nfp/nfpcore/nfp_cppcore.c | 17 ------ .../ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c | 70 +++++++++------------- 8 files changed, 54 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c index 1a33ad9f4170..83c65e6291ee 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c @@ -80,7 +80,7 @@ int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn, if (err) return err < 0 ? err : 0; - nfp_net_get_mac_addr(nn, app->cpp, id); + nfp_net_get_mac_addr(app->pf, nn, id); return 0; } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 51fe8de34b67..94211e245257 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -170,7 +170,7 @@ nfp_net_fw_find(struct pci_dev *pdev, struct nfp_pf *pf) return NULL; } - fw_model = nfp_hwinfo_lookup(pf->cpp, "assembly.partno"); + fw_model = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno"); if (!fw_model) { dev_err(&pdev->dev, "Error: can't read part number\n"); return NULL; @@ -358,16 +358,18 @@ static int nfp_pci_probe(struct pci_dev *pdev, goto err_disable_msix; } + pf->hwinfo = nfp_hwinfo_read(pf->cpp); + dev_info(&pdev->dev, "Assembly: %s%s%s-%s CPLD: %s\n", - nfp_hwinfo_lookup(pf->cpp, "assembly.vendor"), - nfp_hwinfo_lookup(pf->cpp, "assembly.partno"), - nfp_hwinfo_lookup(pf->cpp, "assembly.serial"), - nfp_hwinfo_lookup(pf->cpp, "assembly.revision"), - nfp_hwinfo_lookup(pf->cpp, "cpld.version")); + nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor"), + nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno"), + nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial"), + nfp_hwinfo_lookup(pf->hwinfo, "assembly.revision"), + nfp_hwinfo_lookup(pf->hwinfo, "cpld.version")); err = devlink_register(devlink, &pdev->dev); if (err) - goto err_cpp_free; + goto err_hwinfo_free; err = nfp_nsp_init(pdev, pf); if (err) @@ -403,7 +405,8 @@ err_fw_unload: kfree(pf->nspi); err_devlink_unreg: devlink_unregister(devlink); -err_cpp_free: +err_hwinfo_free: + kfree(pf->hwinfo); nfp_cpp_free(pf->cpp); err_disable_msix: pci_set_drvdata(pdev, NULL); @@ -438,6 +441,7 @@ static void nfp_pci_remove(struct pci_dev *pdev) nfp_fw_unload(pf); pci_set_drvdata(pdev, NULL); + kfree(pf->hwinfo); nfp_cpp_free(pf->cpp); kfree(pf->eth_tbl); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 907852f00423..041643807f7e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -54,6 +54,7 @@ struct pci_dev; struct nfp_cpp; struct nfp_cpp_area; struct nfp_eth_table; +struct nfp_hwinfo; struct nfp_net; struct nfp_nsp_identify; struct nfp_rtsym_table; @@ -72,6 +73,7 @@ struct nfp_rtsym_table; * @fw_loaded: Is the firmware loaded? * @ctrl_vnic: Pointer to the control vNIC if available * @rtbl: RTsym table + * @hwinfo: HWInfo table * @eth_tbl: NSP ETH table * @nspi: NSP identification info * @hwmon_dev: pointer to hwmon device @@ -104,6 +106,7 @@ struct nfp_pf { struct nfp_net *ctrl_vnic; struct nfp_rtsym_table *rtbl; + struct nfp_hwinfo *hwinfo; struct nfp_eth_table *eth_tbl; struct nfp_nsp_identify *nspi; @@ -133,7 +136,7 @@ void nfp_hwmon_unregister(struct nfp_pf *pf); struct nfp_eth_table_port * nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id); void -nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id); +nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id); bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index c845049fcff2..bc2bc0886176 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -63,13 +63,13 @@ #define NFP_PF_CSR_SLICE_SIZE (32 * 1024) -static int nfp_is_ready(struct nfp_cpp *cpp) +static int nfp_is_ready(struct nfp_pf *pf) { const char *cp; long state; int err; - cp = nfp_hwinfo_lookup(cpp, "board.state"); + cp = nfp_hwinfo_lookup(pf->hwinfo, "board.state"); if (!cp) return 0; @@ -134,15 +134,15 @@ err_area: /** * nfp_net_get_mac_addr() - Get the MAC address. + * @pf: NFP PF handle * @nn: NFP Network structure - * @cpp: NFP CPP handle * @id: NFP port id * * First try to get the MAC address from NSP ETH table. If that * fails try HWInfo. As a last resort generate a random address. */ void -nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id) +nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id) { struct nfp_eth_table_port *eth_port; struct nfp_net_dp *dp = &nn->dp; @@ -159,7 +159,7 @@ nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id) snprintf(name, sizeof(name), "eth%d.mac", id); - mac_str = nfp_hwinfo_lookup(cpp, name); + mac_str = nfp_hwinfo_lookup(pf->hwinfo, name); if (!mac_str) { dev_warn(dp->dev, "Can't lookup MAC address. Generate\n"); eth_hw_addr_random(dp->netdev); @@ -713,7 +713,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf) INIT_WORK(&pf->port_refresh_work, nfp_net_refresh_vnics); /* Verify that the board has completed initialization */ - if (!nfp_is_ready(pf->cpp)) { + if (!nfp_is_ready(pf)) { nfp_err(pf->cpp, "NFP is not ready for NIC operation.\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h index 94641b4c2c55..1a8d04a1e113 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp.h @@ -46,7 +46,9 @@ /* Implemented in nfp_hwinfo.c */ -const char *nfp_hwinfo_lookup(struct nfp_cpp *cpp, const char *lookup); +struct nfp_hwinfo; +struct nfp_hwinfo *nfp_hwinfo_read(struct nfp_cpp *cpp); +const char *nfp_hwinfo_lookup(struct nfp_hwinfo *hwinfo, const char *lookup); /* Implemented in nfp_nsp.c, low level functions */ diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index e3a2201eb658..25a967158ce9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -222,9 +222,6 @@ u32 nfp_cpp_model(struct nfp_cpp *cpp); u16 nfp_cpp_interface(struct nfp_cpp *cpp); int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial); -void *nfp_hwinfo_cache(struct nfp_cpp *cpp); -void nfp_hwinfo_cache_set(struct nfp_cpp *cpp, void *val); - struct nfp_cpp_area *nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp, u32 cpp_id, const char *name, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c index f477186558bd..9b69dcf87be9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c @@ -76,9 +76,6 @@ struct nfp_cpp_resource { * @serial: chip serial number * @imb_cat_table: CPP Mapping Table * - * Following fields can be used only in probe() or with rtnl held: - * @hwinfo: HWInfo database fetched from the device - * * Following fields use explicit locking: * @resource_list: NFP CPP resource list * @resource_lock: protects @resource_list @@ -106,8 +103,6 @@ struct nfp_cpp { struct mutex area_cache_mutex; struct list_head area_cache_list; - - void *hwinfo; }; /* Element of the area_cache_list */ @@ -231,8 +226,6 @@ void nfp_cpp_free(struct nfp_cpp *cpp) if (cpp->op->free) cpp->op->free(cpp); - kfree(cpp->hwinfo); - device_unregister(&cpp->dev); kfree(cpp); @@ -273,16 +266,6 @@ int nfp_cpp_serial(struct nfp_cpp *cpp, const u8 **serial) return sizeof(cpp->serial); } -void *nfp_hwinfo_cache(struct nfp_cpp *cpp) -{ - return cpp->hwinfo; -} - -void nfp_hwinfo_cache_set(struct nfp_cpp *cpp, void *val) -{ - cpp->hwinfo = val; -} - /** * nfp_cpp_area_alloc_with_name() - allocate a new CPP area * @cpp: CPP device handle diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c index 8d8f311ffa6e..4f24aff1e772 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_hwinfo.c @@ -178,7 +178,8 @@ hwinfo_db_validate(struct nfp_cpp *cpp, struct nfp_hwinfo *db, u32 len) return hwinfo_db_walk(cpp, db, size); } -static int hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size) +static struct nfp_hwinfo * +hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size) { struct nfp_hwinfo *header; struct nfp_resource *res; @@ -196,7 +197,7 @@ static int hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size) nfp_resource_release(res); if (*cpp_size < HWINFO_SIZE_MIN) - return -ENOENT; + return NULL; } else if (PTR_ERR(res) == -ENOENT) { /* Try getting the HWInfo table from the 'classic' location */ cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, @@ -204,101 +205,86 @@ static int hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size) cpp_addr = 0x30000; *cpp_size = 0x0e000; } else { - return PTR_ERR(res); + return NULL; } db = kmalloc(*cpp_size + 1, GFP_KERNEL); if (!db) - return -ENOMEM; + return NULL; err = nfp_cpp_read(cpp, cpp_id, cpp_addr, db, *cpp_size); - if (err != *cpp_size) { - kfree(db); - return err < 0 ? err : -EIO; - } + if (err != *cpp_size) + goto exit_free; header = (void *)db; - if (nfp_hwinfo_is_updating(header)) { - kfree(db); - return -EBUSY; - } + if (nfp_hwinfo_is_updating(header)) + goto exit_free; if (le32_to_cpu(header->version) != NFP_HWINFO_VERSION_2) { nfp_err(cpp, "Unknown HWInfo version: 0x%08x\n", le32_to_cpu(header->version)); - kfree(db); - return -EINVAL; + goto exit_free; } /* NULL-terminate for safety */ db[*cpp_size] = '\0'; - nfp_hwinfo_cache_set(cpp, db); - - return 0; + return (void *)db; +exit_free: + kfree(db); + return NULL; } -static int hwinfo_fetch(struct nfp_cpp *cpp, size_t *hwdb_size) +static struct nfp_hwinfo *hwinfo_fetch(struct nfp_cpp *cpp, size_t *hwdb_size) { const unsigned long wait_until = jiffies + HWINFO_WAIT * HZ; + struct nfp_hwinfo *db; int err; for (;;) { const unsigned long start_time = jiffies; - err = hwinfo_try_fetch(cpp, hwdb_size); - if (!err) - return 0; + db = hwinfo_try_fetch(cpp, hwdb_size); + if (db) + return db; err = msleep_interruptible(100); if (err || time_after(start_time, wait_until)) { nfp_err(cpp, "NFP access error\n"); - return -EIO; + return NULL; } } } -static int nfp_hwinfo_load(struct nfp_cpp *cpp) +struct nfp_hwinfo *nfp_hwinfo_read(struct nfp_cpp *cpp) { struct nfp_hwinfo *db; size_t hwdb_size = 0; int err; - err = hwinfo_fetch(cpp, &hwdb_size); - if (err) - return err; + db = hwinfo_fetch(cpp, &hwdb_size); + if (!db) + return NULL; - db = nfp_hwinfo_cache(cpp); err = hwinfo_db_validate(cpp, db, hwdb_size); if (err) { kfree(db); - nfp_hwinfo_cache_set(cpp, NULL); - return err; + return NULL; } - return 0; + return db; } /** * nfp_hwinfo_lookup() - Find a value in the HWInfo table by name - * @cpp: NFP CPP handle + * @hwinfo: NFP HWinfo table * @lookup: HWInfo name to search for * * Return: Value of the HWInfo name, or NULL */ -const char *nfp_hwinfo_lookup(struct nfp_cpp *cpp, const char *lookup) +const char *nfp_hwinfo_lookup(struct nfp_hwinfo *hwinfo, const char *lookup) { const char *key, *val, *end; - struct nfp_hwinfo *hwinfo; - int err; - - hwinfo = nfp_hwinfo_cache(cpp); - if (!hwinfo) { - err = nfp_hwinfo_load(cpp); - if (err) - return NULL; - hwinfo = nfp_hwinfo_cache(cpp); - } if (!hwinfo || !lookup) return NULL; -- cgit v1.2.3 From 0be40e66e72a544e2d4a5bca9328463ebf2c55df Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2017 20:56:13 -0700 Subject: nfp: keep MIP object around Microcode Information Page contains some useful information, like application firmware build name. Keep it around, similar to RTSym and HWInfo. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 5 ++++- drivers/net/ethernet/netronome/nfp/nfp_main.h | 3 +++ drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h | 2 ++ drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c | 16 +++++++++++++--- 4 files changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 94211e245257..4e59dcb78c36 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -375,7 +375,8 @@ static int nfp_pci_probe(struct pci_dev *pdev, if (err) goto err_devlink_unreg; - pf->rtbl = nfp_rtsym_table_read(pf->cpp); + pf->mip = nfp_mip_open(pf->cpp); + pf->rtbl = __nfp_rtsym_table_read(pf->cpp, pf->mip); err = nfp_pcie_sriov_read_nfd_limit(pf); if (err) @@ -399,6 +400,7 @@ err_sriov_unlimit: pci_sriov_set_totalvfs(pf->pdev, 0); err_fw_unload: kfree(pf->rtbl); + nfp_mip_close(pf->mip); if (pf->fw_loaded) nfp_fw_unload(pf); kfree(pf->eth_tbl); @@ -437,6 +439,7 @@ static void nfp_pci_remove(struct pci_dev *pdev) devlink_unregister(devlink); kfree(pf->rtbl); + nfp_mip_close(pf->mip); if (pf->fw_loaded) nfp_fw_unload(pf); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 041643807f7e..88724f8d0dcd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -55,6 +55,7 @@ struct nfp_cpp; struct nfp_cpp_area; struct nfp_eth_table; struct nfp_hwinfo; +struct nfp_mip; struct nfp_net; struct nfp_nsp_identify; struct nfp_rtsym_table; @@ -72,6 +73,7 @@ struct nfp_rtsym_table; * @num_vfs: Number of SR-IOV VFs enabled * @fw_loaded: Is the firmware loaded? * @ctrl_vnic: Pointer to the control vNIC if available + * @mip: MIP handle * @rtbl: RTsym table * @hwinfo: HWInfo table * @eth_tbl: NSP ETH table @@ -105,6 +107,7 @@ struct nfp_pf { struct nfp_net *ctrl_vnic; + const struct nfp_mip *mip; struct nfp_rtsym_table *rtbl; struct nfp_hwinfo *hwinfo; struct nfp_eth_table *eth_tbl; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h index f845cf5dd762..c7266baec0eb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h @@ -90,6 +90,8 @@ struct nfp_rtsym { struct nfp_rtsym_table; struct nfp_rtsym_table *nfp_rtsym_table_read(struct nfp_cpp *cpp); +struct nfp_rtsym_table * +__nfp_rtsym_table_read(struct nfp_cpp *cpp, const struct nfp_mip *mip); int nfp_rtsym_count(struct nfp_rtsym_table *rtbl); const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx); const struct nfp_rtsym * diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index ef3566163cb0..203f9cbae0fb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -108,22 +108,32 @@ nfp_rtsym_sw_entry_init(struct nfp_rtsym_table *cache, u32 strtab_size, } struct nfp_rtsym_table *nfp_rtsym_table_read(struct nfp_cpp *cpp) +{ + struct nfp_rtsym_table *rtbl; + const struct nfp_mip *mip; + + mip = nfp_mip_open(cpp); + rtbl = __nfp_rtsym_table_read(cpp, mip); + nfp_mip_close(mip); + + return rtbl; +} + +struct nfp_rtsym_table * +__nfp_rtsym_table_read(struct nfp_cpp *cpp, const struct nfp_mip *mip) { const u32 dram = NFP_CPP_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0) | NFP_ISL_EMEM0; u32 strtab_addr, symtab_addr, strtab_size, symtab_size; struct nfp_rtsym_entry *rtsymtab; struct nfp_rtsym_table *cache; - const struct nfp_mip *mip; int err, n, size; - mip = nfp_mip_open(cpp); if (!mip) return NULL; nfp_mip_strtab(mip, &strtab_addr, &strtab_size); nfp_mip_symtab(mip, &symtab_addr, &symtab_size); - nfp_mip_close(mip); if (!symtab_size || !strtab_size || symtab_size % sizeof(*rtsymtab)) return NULL; -- cgit v1.2.3 From 76abc0f620549d7fdf960bb8c99e502e9b61faae Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2017 20:56:14 -0700 Subject: nfp: report application FW build name in ethtool -i Make sure application FW build name is NULL-terminated and print it as a part of ethtool's firmware version string. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_app.c | 8 ++++++++ drivers/net/ethernet/netronome/nfp/nfp_app.h | 1 + drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 4 ++-- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c | 7 +++++++ drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h | 1 + 5 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index de07517da1bd..396b93f54823 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -35,6 +35,7 @@ #include #include "nfpcore/nfp_cpp.h" +#include "nfpcore/nfp_nffw.h" #include "nfp_app.h" #include "nfp_main.h" @@ -43,6 +44,13 @@ static const struct nfp_app_type *apps[] = { &app_bpf, }; +const char *nfp_app_mip_name(struct nfp_app *app) +{ + if (!app || !app->pf->mip) + return ""; + return nfp_mip_name(app->pf->mip); +} + struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size) { struct sk_buff *skb; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index 3fbf68f8577c..f5e373fa8c3b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -216,6 +216,7 @@ static inline void nfp_app_ctrl_rx(struct nfp_app *app, struct sk_buff *skb) app->type->ctrl_msg_rx(app, skb); } +const char *nfp_app_mip_name(struct nfp_app *app); struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size); struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index 83664ca25213..6e31355c3567 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -166,10 +166,10 @@ static void nfp_net_get_drvinfo(struct net_device *netdev, nfp_net_get_nspinfo(nn->app, nsp_version); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), - "%d.%d.%d.%d %s %s", + "%d.%d.%d.%d %s %s %s", nn->fw_ver.resv, nn->fw_ver.class, nn->fw_ver.major, nn->fw_ver.minor, nsp_version, - nfp_app_name(nn->app)); + nfp_app_mip_name(nn->app), nfp_app_name(nn->app)); strlcpy(drvinfo->bus_info, pci_name(nn->pdev), sizeof(drvinfo->bus_info)); diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c index 3d15dd03647e..5f193fe2d69e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_mip.c @@ -141,6 +141,8 @@ const struct nfp_mip *nfp_mip_open(struct nfp_cpp *cpp) return NULL; } + mip->name[sizeof(mip->name) - 1] = 0; + return mip; } @@ -149,6 +151,11 @@ void nfp_mip_close(const struct nfp_mip *mip) kfree(mip); } +const char *nfp_mip_name(const struct nfp_mip *mip) +{ + return mip->name; +} + /** * nfp_mip_symtab() - Get the address and size of the MIP symbol table * @mip: MIP handle diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h index c7266baec0eb..d27d29782a12 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h @@ -55,6 +55,7 @@ struct nfp_mip; const struct nfp_mip *nfp_mip_open(struct nfp_cpp *cpp); void nfp_mip_close(const struct nfp_mip *mip); +const char *nfp_mip_name(const struct nfp_mip *mip); void nfp_mip_symtab(const struct nfp_mip *mip, u32 *addr, u32 *size); void nfp_mip_strtab(const struct nfp_mip *mip, u32 *addr, u32 *size); -- cgit v1.2.3 From d86cc04e22ead660eeb362b28119c7cb1fbd9d06 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Fri, 9 Jun 2017 11:12:35 +0530 Subject: cxgb4: handle interrupt raised when FW crashes Handle TIMER0INT when FW crashes. Check for PCIE_FW[FW_EVAL] and if it says "Device FW Crashed", then treat it as fatal. Else, non-fatal. Signed-off-by: Rahul Lakkireddy Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 19 ++++++++++++++++++- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 4 ++++ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 4 ++++ 3 files changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index da1322da4925..16af646a7fe4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4040,6 +4040,7 @@ static void cim_intr_handler(struct adapter *adapter) { MBHOSTPARERR_F, "CIM mailbox host parity error", -1, 1 }, { TIEQINPARERRINT_F, "CIM TIEQ outgoing parity error", -1, 1 }, { TIEQOUTPARERRINT_F, "CIM TIEQ incoming parity error", -1, 1 }, + { TIMER0INT_F, "CIM TIMER0 interrupt", -1, 1 }, { 0 } }; static const struct intr_info cim_upintr_info[] = { @@ -4074,11 +4075,27 @@ static void cim_intr_handler(struct adapter *adapter) { 0 } }; + u32 val, fw_err; int fat; - if (t4_read_reg(adapter, PCIE_FW_A) & PCIE_FW_ERR_F) + fw_err = t4_read_reg(adapter, PCIE_FW_A); + if (fw_err & PCIE_FW_ERR_F) t4_report_fw_error(adapter); + /* When the Firmware detects an internal error which normally + * wouldn't raise a Host Interrupt, it forces a CIM Timer0 interrupt + * in order to make sure the Host sees the Firmware Crash. So + * if we have a Timer0 interrupt and don't see a Firmware Crash, + * ignore the Timer0 interrupt. + */ + + val = t4_read_reg(adapter, CIM_HOST_INT_CAUSE_A); + if (val & TIMER0INT_F) + if (!(fw_err & PCIE_FW_ERR_F) || + (PCIE_FW_EVAL_G(fw_err) != PCIE_FW_EVAL_CRASH)) + t4_write_reg(adapter, CIM_HOST_INT_CAUSE_A, + TIMER0INT_F); + fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE_A, cim_intr_info) + t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE_A, diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 3348d33c36fa..3884336ce23c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1077,6 +1077,10 @@ #define TIEQINPARERRINT_V(x) ((x) << TIEQINPARERRINT_S) #define TIEQINPARERRINT_F TIEQINPARERRINT_V(1U) +#define TIMER0INT_S 2 +#define TIMER0INT_V(x) ((x) << TIMER0INT_S) +#define TIMER0INT_F TIMER0INT_V(1U) + #define PREFDROPINT_S 1 #define PREFDROPINT_V(x) ((x) << PREFDROPINT_S) #define PREFDROPINT_F PREFDROPINT_V(1U) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index c65c33c03bcb..f47461aa658b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -3088,6 +3088,10 @@ struct fw_debug_cmd { #define FW_DEBUG_CMD_TYPE_G(x) \ (((x) >> FW_DEBUG_CMD_TYPE_S) & FW_DEBUG_CMD_TYPE_M) +enum pcie_fw_eval { + PCIE_FW_EVAL_CRASH = 0, +}; + #define PCIE_FW_ERR_S 31 #define PCIE_FW_ERR_V(x) ((x) << PCIE_FW_ERR_S) #define PCIE_FW_ERR_F PCIE_FW_ERR_V(1U) -- cgit v1.2.3 From c564b871d53bced9520a3f76e01636e83a6bcd19 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:38 +0800 Subject: r8152: add r8153_phy_status function Use r8153_phy_status() to check phy status of RTL8153. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index fd31fab2a9da..9239dfb829b3 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -394,6 +394,7 @@ /* OCP_PHY_STATUS */ #define PHY_STAT_MASK 0x0007 +#define PHY_STAT_EXT_INIT 2 #define PHY_STAT_LAN_ON 3 #define PHY_STAT_PWRDN 5 @@ -2452,6 +2453,28 @@ static void r8153_u2p3en(struct r8152 *tp, bool enable) ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); } +static u16 r8153_phy_status(struct r8152 *tp, u16 desired) +{ + u16 data; + int i; + + for (i = 0; i < 500; i++) { + data = ocp_reg_read(tp, OCP_PHY_STATUS); + data &= PHY_STAT_MASK; + if (desired) { + if (data == desired) + break; + } else if (data == PHY_STAT_LAN_ON || data == PHY_STAT_PWRDN || + data == PHY_STAT_EXT_INIT) { + break; + } + + msleep(20); + } + + return data; +} + static void r8153_power_cut_en(struct r8152 *tp, bool enable) { u32 ocp_data; @@ -3420,12 +3443,7 @@ static void r8153_init(struct r8152 *tp) msleep(20); } - for (i = 0; i < 500; i++) { - ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK; - if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN) - break; - msleep(20); - } + data = r8153_phy_status(tp, 0); if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 || tp->version == RTL_VER_05) @@ -3437,12 +3455,7 @@ static void r8153_init(struct r8152 *tp) r8152_mdio_write(tp, MII_BMCR, data); } - for (i = 0; i < 500; i++) { - ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK; - if (ocp_data == PHY_STAT_LAN_ON) - break; - msleep(20); - } + data = r8153_phy_status(tp, PHY_STAT_LAN_ON); usb_disable_lpm(tp->udev); r8153_u2p3en(tp, false); -- cgit v1.2.3 From ee4761c16cbbca1f0a0b522a2926c5c5b8747c5c Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:39 +0800 Subject: r8152: adjust lpm settings for RTL8153 Enable lpm after r8153_init() and remove other enable/disable lpm. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 9239dfb829b3..b8c904f8955e 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2263,7 +2263,6 @@ static int rtl8153_enable(struct r8152 *tp) if (test_bit(RTL8152_UNPLUG, &tp->flags)) return -ENODEV; - usb_disable_lpm(tp->udev); set_tx_qlen(tp); rtl_set_eee_plus(tp); r8153_set_rx_early_timeout(tp); @@ -3003,7 +3002,6 @@ static void rtl8153_disable(struct r8152 *tp) rtl_disable(tp); rtl_reset_bmu(tp); r8153_aldps_en(tp, true); - usb_enable_lpm(tp->udev); } static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) @@ -3127,7 +3125,6 @@ static void rtl8153_up(struct r8152 *tp) r8153_aldps_en(tp, true); r8153_u2p3en(tp, true); r8153_u1u2en(tp, true); - usb_enable_lpm(tp->udev); } static void rtl8153_down(struct r8152 *tp) @@ -3457,7 +3454,6 @@ static void r8153_init(struct r8152 *tp) data = r8153_phy_status(tp, PHY_STAT_LAN_ON); - usb_disable_lpm(tp->udev); r8153_u2p3en(tp, false); if (tp->version == RTL_VER_04) { @@ -3517,6 +3513,7 @@ static void r8153_init(struct r8152 *tp) r8153_power_cut_en(tp, false); r8153_u1u2en(tp, true); + usb_enable_lpm(tp->udev); /* MAC clock speed down */ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0); -- cgit v1.2.3 From 134f98bcf1b898fb9d6f2b91bc85dd2e5478b4b8 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:40 +0800 Subject: r8152: adjust the settings about MAC clock speed down for RTL8153 The MAC clock speed down could be enabled if the U1/U2 is disabled. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index b8c904f8955e..9a794dbf94e9 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2428,6 +2428,29 @@ static void __rtl_set_wol(struct r8152 *tp, u32 wolopts) device_set_wakeup_enable(&tp->udev->dev, false); } +static void r8153_mac_clk_spd(struct r8152 *tp, bool enable) +{ + /* MAC clock speed down */ + if (enable) { + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, + ALDPS_SPDWN_RATIO); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, + EEE_SPDWN_RATIO); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, + PKT_AVAIL_SPDWN_EN | SUSPEND_SPDWN_EN | + U1U2_SPDWN_EN | L1_SPDWN_EN); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, + PWRSAVE_SPDWN_EN | RXDV_SPDWN_EN | TX10MIDLE_EN | + TP100_SPDWN_EN | TP500_SPDWN_EN | EEE_SPDWN_EN | + TP1000_SPDWN_EN); + } else { + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0); + } +} + static void r8153_u1u2en(struct r8152 *tp, bool enable) { u8 u1u2[8]; @@ -2533,7 +2556,9 @@ static void rtl8153_runtime_enable(struct r8152 *tp, bool enable) if (enable) { r8153_u1u2en(tp, false); r8153_u2p3en(tp, false); + r8153_mac_clk_spd(tp, true); } else { + r8153_mac_clk_spd(tp, false); r8153_u2p3en(tp, true); r8153_u1u2en(tp, true); } @@ -2881,6 +2906,7 @@ static void r8153_first_init(struct r8152 *tp) u32 ocp_data; int i; + r8153_mac_clk_spd(tp, false); rxdy_gated_en(tp, true); r8153_teredo_off(tp); @@ -2947,6 +2973,8 @@ static void r8153_enter_oob(struct r8152 *tp) u32 ocp_data; int i; + r8153_mac_clk_spd(tp, true); + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); ocp_data &= ~NOW_IS_OOB; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); @@ -3513,13 +3541,9 @@ static void r8153_init(struct r8152 *tp) r8153_power_cut_en(tp, false); r8153_u1u2en(tp, true); + r8153_mac_clk_spd(tp, false); usb_enable_lpm(tp->udev); - /* MAC clock speed down */ - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0); rtl_tally_reset(tp); r8153_u2p3en(tp, true); -- cgit v1.2.3 From e31f636721ac13814250289c9f15b4f52af95e3c Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:41 +0800 Subject: r8152: move the setting of rx aggregation Move the setting from r8153_first_init() to r8153_init(). It only needs to be set once. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 9a794dbf94e9..e569c488a6b9 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2961,11 +2961,6 @@ static void r8153_first_init(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL); /* TX share fifo free credit full threshold */ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2); - - /* rx aggregation */ - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); - ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); - ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); } static void r8153_enter_oob(struct r8152 *tp) @@ -3544,6 +3539,10 @@ static void r8153_init(struct r8152 *tp) r8153_mac_clk_spd(tp, false); usb_enable_lpm(tp->udev); + /* rx aggregation */ + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); + ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); + ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); rtl_tally_reset(tp); r8153_u2p3en(tp, true); -- cgit v1.2.3 From 02552754a7aca1756b1b229b48d2a547880ac95a Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:42 +0800 Subject: r8152: adjust rtl8153_runtime_enable function Adjust the order of rtl8153_runtime_enable() according to the suggestion from the engineer. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index e569c488a6b9..32e83fd8b159 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2551,13 +2551,13 @@ static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable) static void rtl8153_runtime_enable(struct r8152 *tp, bool enable) { - rtl_runtime_suspend_enable(tp, enable); - if (enable) { r8153_u1u2en(tp, false); r8153_u2p3en(tp, false); r8153_mac_clk_spd(tp, true); + rtl_runtime_suspend_enable(tp, true); } else { + rtl_runtime_suspend_enable(tp, false); r8153_mac_clk_spd(tp, false); r8153_u2p3en(tp, true); r8153_u1u2en(tp, true); -- cgit v1.2.3 From 3cb3234eed89c10d706d23f5355596efc07dc83c Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:43 +0800 Subject: r8152: adjust U2P3 for RTL8153 Use another way to keep disabling the U2P3 for both RTL_VER_03 and RTL_VER_04. Move enabling U2P3 from r8153_init() to r8153_hw_phy_cfg(). The engineer ask the setting should be done after PHY settings. Disable U2P3 first in rtl8153_up(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 32e83fd8b159..565ac5b8b9ca 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2468,7 +2468,7 @@ static void r8153_u2p3en(struct r8152 *tp, bool enable) u32 ocp_data; ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL); - if (enable && tp->version != RTL_VER_03 && tp->version != RTL_VER_04) + if (enable) ocp_data |= U2P3_ENABLE; else ocp_data &= ~U2P3_ENABLE; @@ -2559,7 +2559,18 @@ static void rtl8153_runtime_enable(struct r8152 *tp, bool enable) } else { rtl_runtime_suspend_enable(tp, false); r8153_mac_clk_spd(tp, false); - r8153_u2p3en(tp, true); + + switch (tp->version) { + case RTL_VER_03: + case RTL_VER_04: + break; + case RTL_VER_05: + case RTL_VER_06: + default: + r8153_u2p3en(tp, true); + break; + } + r8153_u1u2en(tp, true); } } @@ -2898,6 +2909,17 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) r8153_aldps_en(tp, true); r8152b_enable_fc(tp); + switch (tp->version) { + case RTL_VER_03: + case RTL_VER_04: + break; + case RTL_VER_05: + case RTL_VER_06: + default: + r8153_u2p3en(tp, true); + break; + } + set_bit(PHY_RESET, &tp->flags); } @@ -3143,10 +3165,22 @@ static void rtl8153_up(struct r8152 *tp) return; r8153_u1u2en(tp, false); + r8153_u2p3en(tp, false); r8153_aldps_en(tp, false); r8153_first_init(tp); r8153_aldps_en(tp, true); - r8153_u2p3en(tp, true); + + switch (tp->version) { + case RTL_VER_03: + case RTL_VER_04: + break; + case RTL_VER_05: + case RTL_VER_06: + default: + r8153_u2p3en(tp, true); + break; + } + r8153_u1u2en(tp, true); } @@ -3545,7 +3579,6 @@ static void r8153_init(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); rtl_tally_reset(tp); - r8153_u2p3en(tp, true); } static int rtl8152_pre_reset(struct usb_interface *intf) -- cgit v1.2.3 From 49d10347d445f003cdd3a3c2c4f36d11aa67e6e1 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:44 +0800 Subject: r8152: move the default coalesce setting for RTL8153 Only RTL8153 could set coalesce, so move the default setting for rtl8152_probe() to r8153_init(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 565ac5b8b9ca..f78111c1ae40 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3579,6 +3579,19 @@ static void r8153_init(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); rtl_tally_reset(tp); + + switch (tp->udev->speed) { + case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: + tp->coalesce = COALESCE_SUPER; + break; + case USB_SPEED_HIGH: + tp->coalesce = COALESCE_HIGH; + break; + default: + tp->coalesce = COALESCE_SLOW; + break; + } } static int rtl8152_pre_reset(struct usb_interface *intf) @@ -4524,19 +4537,6 @@ static int rtl8152_probe(struct usb_interface *intf, tp->mii.reg_num_mask = 0x1f; tp->mii.phy_id = R8152_PHY_ID; - switch (udev->speed) { - case USB_SPEED_SUPER: - case USB_SPEED_SUPER_PLUS: - tp->coalesce = COALESCE_SUPER; - break; - case USB_SPEED_HIGH: - tp->coalesce = COALESCE_HIGH; - break; - default: - tp->coalesce = COALESCE_SLOW; - break; - } - tp->autoneg = AUTONEG_ENABLE; tp->speed = tp->mii.supports_gmii ? SPEED_1000 : SPEED_100; tp->duplex = DUPLEX_FULL; -- cgit v1.2.3 From befb2de18195d1ab6b843dd6ca921a222a32a588 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:45 +0800 Subject: r8152: move the initialization to reset_resume function Move tp->rtl_ops.init() from rtl8152_resume() to rtl8152_reset_resume(). The initialization is only necessary for reset_resume(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index f78111c1ae40..f43b7a8ecfff 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3776,11 +3776,8 @@ static int rtl8152_resume(struct usb_interface *intf) mutex_lock(&tp->control); - if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - tp->rtl_ops.init(tp); - queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); + if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) netif_device_attach(netdev); - } if (netif_running(netdev) && netdev->flags & IFF_UP) { if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { @@ -3826,6 +3823,10 @@ static int rtl8152_reset_resume(struct usb_interface *intf) struct r8152 *tp = usb_get_intfdata(intf); clear_bit(SELECTIVE_SUSPEND, &tp->flags); + mutex_lock(&tp->control); + tp->rtl_ops.init(tp); + queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); + mutex_unlock(&tp->control); return rtl8152_resume(intf); } -- cgit v1.2.3 From 4214cc550bf9d986699a072988503e33d3d3155d Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:46 +0800 Subject: r8152: check if disabling ALDPS is finished Use PLA 0xe000 bit 8 to check if disabling ALDPS is finished. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index f43b7a8ecfff..204f4b2155ae 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2836,9 +2836,15 @@ static void r8153_aldps_en(struct r8152 *tp, bool enable) data |= EN_ALDPS; ocp_reg_write(tp, OCP_POWER_CFG, data); } else { + int i; + data &= ~EN_ALDPS; ocp_reg_write(tp, OCP_POWER_CFG, data); - msleep(20); + for (i = 0; i < 20; i++) { + usleep_range(1000, 2000); + if (ocp_read_word(tp, MCU_TYPE_PLA, 0xe000) & 0x0100) + break; + } } } -- cgit v1.2.3 From 745444583ab5c322def99907efa591860e38c75d Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:47 +0800 Subject: r8152: avoid rx queue more than 1000 packets Stop queuing rx packets if it is more than 1000. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 204f4b2155ae..fa2958393730 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1813,6 +1813,10 @@ static int rx_bottom(struct r8152 *tp, int budget) unsigned int pkt_len; struct sk_buff *skb; + /* limite the skb numbers for rx_queue */ + if (unlikely(skb_queue_len(&tp->rx_queue) >= 1000)) + break; + pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK; if (pkt_len < ETH_ZLEN) break; -- cgit v1.2.3 From a3307f9b1b3611e925123f8b052cc6f49e51d1bb Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 9 Jun 2017 17:11:48 +0800 Subject: r8152: replace napi_complete with napi_complete_done Change from using napi_complete to napi_complete_done to allow for the use of gro_flush_timeout in tuning network processing. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index fa2958393730..5a02053181d1 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1938,7 +1938,8 @@ static int r8152_poll(struct napi_struct *napi, int budget) bottom_half(tp); if (work_done < budget) { - napi_complete(napi); + if (!napi_complete_done(napi, work_done)) + goto out; if (!list_empty(&tp->rx_done)) napi_schedule(napi); else if (!skb_queue_empty(&tp->tx_queue) && @@ -1946,6 +1947,7 @@ static int r8152_poll(struct napi_struct *napi, int budget) napi_schedule(napi); } +out: return work_done; } -- cgit v1.2.3 From 7c7973b2ae277c6e89dceda2246fff2472c8ffdb Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 9 Jun 2017 17:13:18 +0300 Subject: qed: LL2 to use packed information for tx First step in revising the LL2 interface, this declares qed_ll2_tx_pkt_info as part of the ll2 interface, and uses it for transmission instead of receiving lots of parameters. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 127 +++++++++++++---------------- drivers/net/ethernet/qlogic/qed/qed_ll2.h | 41 ++-------- drivers/net/ethernet/qlogic/qed/qed_roce.c | 18 ++-- 3 files changed, 75 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index f67ed6d39dfd..0b75f5dd25f8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -740,12 +740,13 @@ static void qed_ooo_submit_tx_buffers(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_conn) { + struct qed_ll2_tx_pkt_info tx_pkt; struct qed_ooo_buffer *p_buffer; - int rc; u16 l4_hdr_offset_w; dma_addr_t first_frag; u16 parse_flags; u8 bd_flags; + int rc; /* Submit Tx buffers here */ while ((p_buffer = qed_ooo_get_ready_buffer(p_hwfn, @@ -760,13 +761,18 @@ qed_ooo_submit_tx_buffers(struct qed_hwfn *p_hwfn, SET_FIELD(bd_flags, CORE_TX_BD_DATA_FORCE_VLAN_MODE, 1); SET_FIELD(bd_flags, CORE_TX_BD_DATA_L4_PROTOCOL, 1); - rc = qed_ll2_prepare_tx_packet(p_hwfn, p_ll2_conn->my_id, 1, - p_buffer->vlan, bd_flags, - l4_hdr_offset_w, - p_ll2_conn->conn.tx_dest, 0, - first_frag, - p_buffer->packet_length, - p_buffer, true); + memset(&tx_pkt, 0, sizeof(tx_pkt)); + tx_pkt.num_of_bds = 1; + tx_pkt.vlan = p_buffer->vlan; + tx_pkt.bd_flags = bd_flags; + tx_pkt.l4_hdr_offset_w = l4_hdr_offset_w; + tx_pkt.tx_dest = p_ll2_conn->conn.tx_dest; + tx_pkt.first_frag = first_frag; + tx_pkt.first_frag_len = p_buffer->packet_length; + tx_pkt.cookie = p_buffer; + + rc = qed_ll2_prepare_tx_packet(p_hwfn, p_ll2_conn->my_id, + &tx_pkt, true); if (rc) { qed_ooo_put_ready_buffer(p_hwfn, p_hwfn->p_ooo_info, p_buffer, false); @@ -1593,20 +1599,18 @@ out: static void qed_ll2_prepare_tx_packet_set(struct qed_hwfn *p_hwfn, struct qed_ll2_tx_queue *p_tx, struct qed_ll2_tx_packet *p_curp, - u8 num_of_bds, - dma_addr_t first_frag, - u16 first_frag_len, void *p_cookie, + struct qed_ll2_tx_pkt_info *pkt, u8 notify_fw) { list_del(&p_curp->list_entry); - p_curp->cookie = p_cookie; - p_curp->bd_used = num_of_bds; + p_curp->cookie = pkt->cookie; + p_curp->bd_used = pkt->num_of_bds; p_curp->notify_fw = notify_fw; p_tx->cur_send_packet = p_curp; p_tx->cur_send_frag_num = 0; - p_curp->bds_set[p_tx->cur_send_frag_num].tx_frag = first_frag; - p_curp->bds_set[p_tx->cur_send_frag_num].frag_len = first_frag_len; + p_curp->bds_set[p_tx->cur_send_frag_num].tx_frag = pkt->first_frag; + p_curp->bds_set[p_tx->cur_send_frag_num].frag_len = pkt->first_frag_len; p_tx->cur_send_frag_num++; } @@ -1614,32 +1618,33 @@ static void qed_ll2_prepare_tx_packet_set_bd(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2, struct qed_ll2_tx_packet *p_curp, - u8 num_of_bds, - enum core_tx_dest tx_dest, - u16 vlan, - u8 bd_flags, - u16 l4_hdr_offset_w, - enum core_roce_flavor_type roce_flavor, - dma_addr_t first_frag, - u16 first_frag_len) + struct qed_ll2_tx_pkt_info *pkt) { struct qed_chain *p_tx_chain = &p_ll2->tx_queue.txq_chain; u16 prod_idx = qed_chain_get_prod_idx(p_tx_chain); struct core_tx_bd *start_bd = NULL; + enum core_roce_flavor_type roce_flavor; + enum core_tx_dest tx_dest; u16 bd_data = 0, frag_idx; + roce_flavor = (pkt->qed_roce_flavor == QED_LL2_ROCE) ? CORE_ROCE + : CORE_RROCE; + + tx_dest = (pkt->tx_dest == QED_LL2_TX_DEST_NW) ? CORE_TX_DEST_NW + : CORE_TX_DEST_LB; + start_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain); - start_bd->nw_vlan_or_lb_echo = cpu_to_le16(vlan); + start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan); SET_FIELD(start_bd->bitfield1, CORE_TX_BD_L4_HDR_OFFSET_W, - cpu_to_le16(l4_hdr_offset_w)); + cpu_to_le16(pkt->l4_hdr_offset_w)); SET_FIELD(start_bd->bitfield1, CORE_TX_BD_TX_DST, tx_dest); - bd_data |= bd_flags; + bd_data |= pkt->bd_flags; SET_FIELD(bd_data, CORE_TX_BD_DATA_START_BD, 0x1); - SET_FIELD(bd_data, CORE_TX_BD_DATA_NBDS, num_of_bds); + SET_FIELD(bd_data, CORE_TX_BD_DATA_NBDS, pkt->num_of_bds); SET_FIELD(bd_data, CORE_TX_BD_DATA_ROCE_FLAV, roce_flavor); start_bd->bd_data.as_bitfield = cpu_to_le16(bd_data); - DMA_REGPAIR_LE(start_bd->addr, first_frag); - start_bd->nbytes = cpu_to_le16(first_frag_len); + DMA_REGPAIR_LE(start_bd->addr, pkt->first_frag); + start_bd->nbytes = cpu_to_le16(pkt->first_frag_len); DP_VERBOSE(p_hwfn, (NETIF_MSG_TX_QUEUED | QED_MSG_LL2), @@ -1648,17 +1653,17 @@ qed_ll2_prepare_tx_packet_set_bd(struct qed_hwfn *p_hwfn, p_ll2->cid, p_ll2->conn.conn_type, prod_idx, - first_frag_len, - num_of_bds, + pkt->first_frag_len, + pkt->num_of_bds, le32_to_cpu(start_bd->addr.hi), le32_to_cpu(start_bd->addr.lo)); - if (p_ll2->tx_queue.cur_send_frag_num == num_of_bds) + if (p_ll2->tx_queue.cur_send_frag_num == pkt->num_of_bds) return; /* Need to provide the packet with additional BDs for frags */ for (frag_idx = p_ll2->tx_queue.cur_send_frag_num; - frag_idx < num_of_bds; frag_idx++) { + frag_idx < pkt->num_of_bds; frag_idx++) { struct core_tx_bd **p_bd = &p_curp->bds_set[frag_idx].txq_bd; *p_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain); @@ -1726,21 +1731,13 @@ static void qed_ll2_tx_packet_notify(struct qed_hwfn *p_hwfn, int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, u8 connection_handle, - u8 num_of_bds, - u16 vlan, - u8 bd_flags, - u16 l4_hdr_offset_w, - enum qed_ll2_tx_dest e_tx_dest, - enum qed_ll2_roce_flavor_type qed_roce_flavor, - dma_addr_t first_frag, - u16 first_frag_len, void *cookie, u8 notify_fw) + struct qed_ll2_tx_pkt_info *pkt, + bool notify_fw) { struct qed_ll2_tx_packet *p_curp = NULL; struct qed_ll2_info *p_ll2_conn = NULL; - enum core_roce_flavor_type roce_flavor; struct qed_ll2_tx_queue *p_tx; struct qed_chain *p_tx_chain; - enum core_tx_dest tx_dest; unsigned long flags; int rc = 0; @@ -1750,7 +1747,7 @@ int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, p_tx = &p_ll2_conn->tx_queue; p_tx_chain = &p_tx->txq_chain; - if (num_of_bds > CORE_LL2_TX_MAX_BDS_PER_PACKET) + if (pkt->num_of_bds > CORE_LL2_TX_MAX_BDS_PER_PACKET) return -EIO; spin_lock_irqsave(&p_tx->lock, flags); @@ -1763,7 +1760,7 @@ int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, if (!list_empty(&p_tx->free_descq)) p_curp = list_first_entry(&p_tx->free_descq, struct qed_ll2_tx_packet, list_entry); - if (p_curp && qed_chain_get_elem_left(p_tx_chain) < num_of_bds) + if (p_curp && qed_chain_get_elem_left(p_tx_chain) < pkt->num_of_bds) p_curp = NULL; if (!p_curp) { @@ -1771,26 +1768,10 @@ int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, goto out; } - tx_dest = e_tx_dest == QED_LL2_TX_DEST_NW ? CORE_TX_DEST_NW : - CORE_TX_DEST_LB; - if (qed_roce_flavor == QED_LL2_ROCE) { - roce_flavor = CORE_ROCE; - } else if (qed_roce_flavor == QED_LL2_RROCE) { - roce_flavor = CORE_RROCE; - } else { - rc = -EINVAL; - goto out; - } - /* Prepare packet and BD, and perhaps send a doorbell to FW */ - qed_ll2_prepare_tx_packet_set(p_hwfn, p_tx, p_curp, - num_of_bds, first_frag, - first_frag_len, cookie, notify_fw); - qed_ll2_prepare_tx_packet_set_bd(p_hwfn, p_ll2_conn, p_curp, - num_of_bds, tx_dest, - vlan, bd_flags, l4_hdr_offset_w, - roce_flavor, - first_frag, first_frag_len); + qed_ll2_prepare_tx_packet_set(p_hwfn, p_tx, p_curp, pkt, notify_fw); + + qed_ll2_prepare_tx_packet_set_bd(p_hwfn, p_ll2_conn, p_curp, pkt); qed_ll2_tx_packet_notify(p_hwfn, p_ll2_conn); @@ -2245,6 +2226,7 @@ fail: static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb) { + struct qed_ll2_tx_pkt_info pkt; const skb_frag_t *frag; int rc = -EINVAL, i; dma_addr_t mapping; @@ -2279,12 +2261,17 @@ static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb) flags |= BIT(CORE_TX_BD_DATA_VLAN_INSERTION_SHIFT); } - rc = qed_ll2_prepare_tx_packet(QED_LEADING_HWFN(cdev), - cdev->ll2->handle, - 1 + skb_shinfo(skb)->nr_frags, - vlan, flags, 0, QED_LL2_TX_DEST_NW, - 0 /* RoCE FLAVOR */, - mapping, skb->len, skb, 1); + memset(&pkt, 0, sizeof(pkt)); + pkt.num_of_bds = 1 + skb_shinfo(skb)->nr_frags; + pkt.vlan = vlan; + pkt.bd_flags = flags; + pkt.tx_dest = QED_LL2_TX_DEST_NW; + pkt.first_frag = mapping; + pkt.first_frag_len = skb->len; + pkt.cookie = skb; + + rc = qed_ll2_prepare_tx_packet(&cdev->hwfns[0], cdev->ll2->handle, + &pkt, 1); if (rc) goto err; diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h index 2c07d0ed971a..96af50b733e8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h @@ -47,12 +47,6 @@ #define QED_MAX_NUM_OF_LL2_CONNECTIONS (4) -enum qed_ll2_roce_flavor_type { - QED_LL2_ROCE, - QED_LL2_RROCE, - MAX_QED_LL2_ROCE_FLAVOR_TYPE -}; - enum qed_ll2_conn_type { QED_LL2_TYPE_FCOE, QED_LL2_TYPE_ISCSI, @@ -64,12 +58,6 @@ enum qed_ll2_conn_type { MAX_QED_LL2_RX_CONN_TYPE }; -enum qed_ll2_tx_dest { - QED_LL2_TX_DEST_NW, /* Light L2 TX Destination to the Network */ - QED_LL2_TX_DEST_LB, /* Light L2 TX Destination to the Loopback */ - QED_LL2_TX_DEST_MAX -}; - struct qed_ll2_rx_packet { struct list_head list_entry; struct core_rx_bd_with_buff_len *rxq_bd; @@ -216,35 +204,16 @@ int qed_ll2_post_rx_buffer(struct qed_hwfn *p_hwfn, * to prepare Tx packet submission to FW. * * @param p_hwfn - * @param connection_handle LL2 connection's handle obtained from - * qed_ll2_require_connection - * @param num_of_bds a number of requested BD equals a number of - * fragments in Tx packet - * @param vlan VLAN to insert to packet (if insertion set) - * @param bd_flags - * @param l4_hdr_offset_w L4 Header Offset from start of packet - * (in words). This is needed if both l4_csum - * and ipv6_ext are set - * @param e_tx_dest indicates if the packet is to be transmitted via - * loopback or to the network - * @param first_frag - * @param first_frag_len - * @param cookie - * - * @param notify_fw + * @param connection_handle + * @param pkt - info regarding the tx packet + * @param notify_fw - issue doorbell to fw for this packet * * @return 0 on success, failure otherwise */ int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, u8 connection_handle, - u8 num_of_bds, - u16 vlan, - u8 bd_flags, - u16 l4_hdr_offset_w, - enum qed_ll2_tx_dest e_tx_dest, - enum qed_ll2_roce_flavor_type qed_roce_flavor, - dma_addr_t first_frag, - u16 first_frag_len, void *cookie, u8 notify_fw); + struct qed_ll2_tx_pkt_info *pkt, + bool notify_fw); /** * @brief qed_ll2_release_connection - releases resources diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index b9434b707b08..afc63c0e7c44 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -2937,6 +2937,7 @@ static int qed_roce_ll2_tx(struct qed_dev *cdev, struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); struct qed_roce_ll2_info *roce_ll2 = hwfn->ll2; enum qed_ll2_roce_flavor_type qed_roce_flavor; + struct qed_ll2_tx_pkt_info ll2_pkt; u8 flags = 0; int rc; int i; @@ -2955,11 +2956,18 @@ static int qed_roce_ll2_tx(struct qed_dev *cdev, flags |= BIT(CORE_TX_BD_DATA_IP_CSUM_SHIFT); /* Tx header */ - rc = qed_ll2_prepare_tx_packet(QED_LEADING_HWFN(cdev), roce_ll2->handle, - 1 + pkt->n_seg, 0, flags, 0, - QED_LL2_TX_DEST_NW, - qed_roce_flavor, pkt->header.baddr, - pkt->header.len, pkt, 1); + memset(&ll2_pkt, 0, sizeof(ll2_pkt)); + ll2_pkt.num_of_bds = 1 + pkt->n_seg; + ll2_pkt.bd_flags = flags; + ll2_pkt.tx_dest = QED_LL2_TX_DEST_NW; + ll2_pkt.qed_roce_flavor = qed_roce_flavor; + ll2_pkt.first_frag = pkt->header.baddr; + ll2_pkt.first_frag_len = pkt->header.len; + ll2_pkt.cookie = pkt; + + rc = qed_ll2_prepare_tx_packet(QED_LEADING_HWFN(cdev), + roce_ll2->handle, + &ll2_pkt, 1); if (rc) { DP_ERR(cdev, "roce ll2 tx: header failed (rc=%d)\n", rc); return QED_ROCE_TX_HEAD_FAILURE; -- cgit v1.2.3 From 68be910cd2fa3f58587438af7ce3def6e03731fa Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 9 Jun 2017 17:13:19 +0300 Subject: qed: Revise ll2 Rx completion This introduces qed_ll2_comp_rx_data as a public struct and moves handling of Rx packets in LL2 into using it. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 84 ++++++++++++++++++------------- 1 file changed, 50 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 0b75f5dd25f8..46b71a668892 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -165,41 +165,33 @@ static void qed_ll2_kill_buffers(struct qed_dev *cdev) } static void qed_ll2b_complete_rx_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - struct qed_ll2_rx_packet *p_pkt, - struct core_rx_fast_path_cqe *p_cqe, - bool b_last_packet) + struct qed_ll2_comp_rx_data *data) { - u16 packet_length = le16_to_cpu(p_cqe->packet_length); - struct qed_ll2_buffer *buffer = p_pkt->cookie; + struct qed_ll2_buffer *buffer = data->cookie; struct qed_dev *cdev = p_hwfn->cdev; - u16 vlan = le16_to_cpu(p_cqe->vlan); - u32 opaque_data_0, opaque_data_1; - u8 pad = p_cqe->placement_offset; dma_addr_t new_phys_addr; struct sk_buff *skb; bool reuse = false; int rc = -EINVAL; u8 *new_data; - opaque_data_0 = le32_to_cpu(p_cqe->opaque_data.data[0]); - opaque_data_1 = le32_to_cpu(p_cqe->opaque_data.data[1]); - DP_VERBOSE(p_hwfn, (NETIF_MSG_RX_STATUS | QED_MSG_STORAGE | NETIF_MSG_PKTDATA), "Got an LL2 Rx completion: [Buffer at phys 0x%llx, offset 0x%02x] Length 0x%04x Parse_flags 0x%04x vlan 0x%04x Opaque data [0x%08x:0x%08x]\n", - (u64)p_pkt->rx_buf_addr, pad, packet_length, - le16_to_cpu(p_cqe->parse_flags.flags), vlan, - opaque_data_0, opaque_data_1); + (u64)data->rx_buf_addr, + data->u.placement_offset, + data->length.packet_length, + data->parse_flags, + data->vlan, data->opaque_data_0, data->opaque_data_1); if ((cdev->dp_module & NETIF_MSG_PKTDATA) && buffer->data) { print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, - buffer->data, packet_length, false); + buffer->data, data->length.packet_length, false); } /* Determine if data is valid */ - if (packet_length < ETH_HLEN) + if (data->length.packet_length < ETH_HLEN) reuse = true; /* Allocate a replacement for buffer; Reuse upon failure */ @@ -219,9 +211,9 @@ static void qed_ll2b_complete_rx_packet(struct qed_hwfn *p_hwfn, goto out_post; } - pad += NET_SKB_PAD; - skb_reserve(skb, pad); - skb_put(skb, packet_length); + data->u.placement_offset += NET_SKB_PAD; + skb_reserve(skb, data->u.placement_offset); + skb_put(skb, data->length.packet_length); skb_checksum_none_assert(skb); /* Get parital ethernet information instead of eth_type_trans(), @@ -232,10 +224,12 @@ static void qed_ll2b_complete_rx_packet(struct qed_hwfn *p_hwfn, /* Pass SKB onward */ if (cdev->ll2->cbs && cdev->ll2->cbs->rx_cb) { - if (vlan) - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); + if (data->vlan) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + data->vlan); cdev->ll2->cbs->rx_cb(cdev->ll2->cb_cookie, skb, - opaque_data_0, opaque_data_1); + data->opaque_data_0, + data->opaque_data_1); } /* Update Buffer information and update FW producer */ @@ -472,33 +466,55 @@ qed_ll2_rxq_completion_gsi(struct qed_hwfn *p_hwfn, return 0; } -static int qed_ll2_rxq_completion_reg(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_conn, - union core_rx_cqe_union *p_cqe, - unsigned long *p_lock_flags, - bool b_last_cqe) +static void qed_ll2_rxq_parse_reg(struct qed_hwfn *p_hwfn, + union core_rx_cqe_union *p_cqe, + struct qed_ll2_comp_rx_data *data) +{ + data->parse_flags = le16_to_cpu(p_cqe->rx_cqe_fp.parse_flags.flags); + data->length.packet_length = + le16_to_cpu(p_cqe->rx_cqe_fp.packet_length); + data->vlan = le16_to_cpu(p_cqe->rx_cqe_fp.vlan); + data->opaque_data_0 = le32_to_cpu(p_cqe->rx_cqe_fp.opaque_data.data[0]); + data->opaque_data_1 = le32_to_cpu(p_cqe->rx_cqe_fp.opaque_data.data[1]); + data->u.placement_offset = p_cqe->rx_cqe_fp.placement_offset; +} + +static int +qed_ll2_rxq_handle_completion(struct qed_hwfn *p_hwfn, + struct qed_ll2_info *p_ll2_conn, + union core_rx_cqe_union *p_cqe, + unsigned long *p_lock_flags, bool b_last_cqe) { struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue; struct qed_ll2_rx_packet *p_pkt = NULL; + struct qed_ll2_comp_rx_data data; if (!list_empty(&p_rx->active_descq)) p_pkt = list_first_entry(&p_rx->active_descq, struct qed_ll2_rx_packet, list_entry); if (!p_pkt) { DP_NOTICE(p_hwfn, - "LL2 Rx completion but active_descq is empty\n"); + "[%d] LL2 Rx completion but active_descq is empty\n", + p_ll2_conn->conn.conn_type); + return -EIO; } list_del(&p_pkt->list_entry); + qed_ll2_rxq_parse_reg(p_hwfn, p_cqe, &data); if (qed_chain_consume(&p_rx->rxq_chain) != p_pkt->rxq_bd) DP_NOTICE(p_hwfn, "Mismatch between active_descq and the LL2 Rx chain\n"); + list_add_tail(&p_pkt->list_entry, &p_rx->free_descq); + data.connection_handle = p_ll2_conn->my_id; + data.cookie = p_pkt->cookie; + data.rx_buf_addr = p_pkt->rx_buf_addr; + data.b_last_packet = b_last_cqe; + spin_unlock_irqrestore(&p_rx->lock, *p_lock_flags); - qed_ll2b_complete_rx_packet(p_hwfn, p_ll2_conn->my_id, - p_pkt, &p_cqe->rx_cqe_fp, b_last_cqe); + qed_ll2b_complete_rx_packet(p_hwfn, &data); spin_lock_irqsave(&p_rx->lock, *p_lock_flags); return 0; @@ -538,9 +554,9 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, void *cookie) cqe, flags, b_last_cqe); break; case CORE_RX_CQE_TYPE_REGULAR: - rc = qed_ll2_rxq_completion_reg(p_hwfn, p_ll2_conn, - cqe, &flags, - b_last_cqe); + rc = qed_ll2_rxq_handle_completion(p_hwfn, p_ll2_conn, + cqe, &flags, + b_last_cqe); break; default: rc = -EIO; -- cgit v1.2.3 From 13c547717231aad7e1635004ae3f698e5e78d6d1 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 9 Jun 2017 17:13:20 +0300 Subject: qed: Cleaner seperation of LL2 inputs A LL2 connection [qed_ll2_info] has a sub-structure of type qed_ll2_conn that contain various inputs for ll2 acquisition, but the connection also utilizes a couple of other inputs. Restructure the input structure to include all the inputs and refactor the code necessary to populate those. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 379 +++++++++++++++-------------- drivers/net/ethernet/qlogic/qed/qed_ll2.h | 42 +--- drivers/net/ethernet/qlogic/qed/qed_roce.c | 31 +-- 3 files changed, 223 insertions(+), 229 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 46b71a668892..fcf4ea98e0bf 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -315,7 +315,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) list_del(&p_pkt->list_entry); b_last_packet = list_empty(&p_tx->active_descq); list_add_tail(&p_pkt->list_entry, &p_tx->free_descq); - if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) { + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) { struct qed_ooo_buffer *p_buffer; p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; @@ -327,7 +327,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used; tx_frag = p_pkt->bds_set[0].tx_frag; - if (p_ll2_conn->conn.gsi_enable) + if (p_ll2_conn->input.gsi_enable) qed_ll2b_release_tx_gsi_packet(p_hwfn, p_ll2_conn-> my_id, @@ -396,7 +396,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) spin_unlock_irqrestore(&p_tx->lock, flags); tx_frag = p_pkt->bds_set[0].tx_frag; - if (p_ll2_conn->conn.gsi_enable) + if (p_ll2_conn->input.gsi_enable) qed_ll2b_complete_tx_gsi_packet(p_hwfn, p_ll2_conn->my_id, p_pkt->cookie, @@ -495,7 +495,7 @@ qed_ll2_rxq_handle_completion(struct qed_hwfn *p_hwfn, if (!p_pkt) { DP_NOTICE(p_hwfn, "[%d] LL2 Rx completion but active_descq is empty\n", - p_ll2_conn->conn.conn_type); + p_ll2_conn->input.conn_type); return -EIO; } @@ -522,7 +522,7 @@ qed_ll2_rxq_handle_completion(struct qed_hwfn *p_hwfn, static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, void *cookie) { - struct qed_ll2_info *p_ll2_conn = cookie; + struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)cookie; struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue; union core_rx_cqe_union *cqe = NULL; u16 cq_new_idx = 0, cq_old_idx = 0; @@ -536,7 +536,9 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, void *cookie) while (cq_new_idx != cq_old_idx) { bool b_last_cqe = (cq_new_idx == cq_old_idx); - cqe = qed_chain_consume(&p_rx->rcq_chain); + cqe = + (union core_rx_cqe_union *) + qed_chain_consume(&p_rx->rcq_chain); cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain); DP_VERBOSE(p_hwfn, @@ -591,7 +593,7 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) list_move_tail(&p_pkt->list_entry, &p_rx->free_descq); - if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) { + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) { struct qed_ooo_buffer *p_buffer; p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; @@ -606,7 +608,6 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) } } -#if IS_ENABLED(CONFIG_QED_ISCSI) static u8 qed_ll2_convert_rx_parse_to_tx_flags(u16 parse_flags) { u8 bd_flags = 0; @@ -782,7 +783,7 @@ qed_ooo_submit_tx_buffers(struct qed_hwfn *p_hwfn, tx_pkt.vlan = p_buffer->vlan; tx_pkt.bd_flags = bd_flags; tx_pkt.l4_hdr_offset_w = l4_hdr_offset_w; - tx_pkt.tx_dest = p_ll2_conn->conn.tx_dest; + tx_pkt.tx_dest = p_ll2_conn->tx_dest; tx_pkt.first_frag = first_frag; tx_pkt.first_frag_len = p_buffer->packet_length; tx_pkt.cookie = p_buffer; @@ -895,60 +896,11 @@ static int qed_ll2_lb_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) return 0; } -static int -qed_ll2_acquire_connection_ooo(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_info, - u16 rx_num_ooo_buffers, u16 mtu) -{ - struct qed_ooo_buffer *p_buf = NULL; - void *p_virt; - u16 buf_idx; - int rc = 0; - - if (p_ll2_info->conn.conn_type != QED_LL2_TYPE_ISCSI_OOO) - return rc; - - if (!rx_num_ooo_buffers) - return -EINVAL; - - for (buf_idx = 0; buf_idx < rx_num_ooo_buffers; buf_idx++) { - p_buf = kzalloc(sizeof(*p_buf), GFP_KERNEL); - if (!p_buf) { - rc = -ENOMEM; - goto out; - } - - p_buf->rx_buffer_size = mtu + 26 + ETH_CACHE_LINE_SIZE; - p_buf->rx_buffer_size = (p_buf->rx_buffer_size + - ETH_CACHE_LINE_SIZE - 1) & - ~(ETH_CACHE_LINE_SIZE - 1); - p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, - p_buf->rx_buffer_size, - &p_buf->rx_buffer_phys_addr, - GFP_KERNEL); - if (!p_virt) { - kfree(p_buf); - rc = -ENOMEM; - goto out; - } - - p_buf->rx_buffer_virt_addr = p_virt; - qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info, p_buf); - } - - DP_VERBOSE(p_hwfn, QED_MSG_LL2, - "Allocated [%04x] LL2 OOO buffers [each of size 0x%08x]\n", - rx_num_ooo_buffers, p_buf->rx_buffer_size); - -out: - return rc; -} - static void qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_conn) { - if (p_ll2_conn->conn.conn_type != QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) return; qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); @@ -960,7 +912,7 @@ static void qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn, { struct qed_ooo_buffer *p_buffer; - if (p_ll2_conn->conn.conn_type != QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) return; qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); @@ -987,69 +939,11 @@ static void qed_ll2_stop_ooo(struct qed_dev *cdev) *handle = QED_LL2_UNUSED_HANDLE; } -static int qed_ll2_start_ooo(struct qed_dev *cdev, - struct qed_ll2_params *params) -{ - struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); - u8 *handle = &hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id; - struct qed_ll2_conn ll2_info = { 0 }; - int rc; - - ll2_info.conn_type = QED_LL2_TYPE_ISCSI_OOO; - ll2_info.mtu = params->mtu; - ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets; - ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping; - ll2_info.tx_tc = OOO_LB_TC; - ll2_info.tx_dest = CORE_TX_DEST_LB; - - rc = qed_ll2_acquire_connection(hwfn, &ll2_info, - QED_LL2_RX_SIZE, QED_LL2_TX_SIZE, - handle); - if (rc) { - DP_INFO(cdev, "Failed to acquire LL2 OOO connection\n"); - goto out; - } - - rc = qed_ll2_establish_connection(hwfn, *handle); - if (rc) { - DP_INFO(cdev, "Failed to establist LL2 OOO connection\n"); - goto fail; - } - - return 0; - -fail: - qed_ll2_release_connection(hwfn, *handle); -out: - *handle = QED_LL2_UNUSED_HANDLE; - return rc; -} -#else /* IS_ENABLED(CONFIG_QED_ISCSI) */ -static int qed_ll2_lb_rxq_completion(struct qed_hwfn *p_hwfn, - void *p_cookie) { return -EINVAL; } -static int qed_ll2_lb_txq_completion(struct qed_hwfn *p_hwfn, - void *p_cookie) { return -EINVAL; } -static inline int -qed_ll2_acquire_connection_ooo(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_info, - u16 rx_num_ooo_buffers, u16 mtu) { return 0; } -static inline void -qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_conn) { return; } -static inline void -qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_conn) { return; } -static inline void qed_ll2_stop_ooo(struct qed_dev *cdev) { return; } -static inline int qed_ll2_start_ooo(struct qed_dev *cdev, - struct qed_ll2_params *params) - { return -EINVAL; } -#endif /* IS_ENABLED(CONFIG_QED_ISCSI) */ - static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_conn, u8 action_on_error) { - enum qed_ll2_conn_type conn_type = p_ll2_conn->conn.conn_type; + enum qed_ll2_conn_type conn_type = p_ll2_conn->input.conn_type; struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue; struct core_rx_start_ramrod_data *p_ramrod = NULL; struct qed_spq_entry *p_ent = NULL; @@ -1075,16 +969,15 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->sb_index = p_rx->rx_sb_index; p_ramrod->complete_event_flg = 1; - p_ramrod->mtu = cpu_to_le16(p_ll2_conn->conn.mtu); - DMA_REGPAIR_LE(p_ramrod->bd_base, - p_rx->rxq_chain.p_phys_addr); + p_ramrod->mtu = cpu_to_le16(p_ll2_conn->input.mtu); + DMA_REGPAIR_LE(p_ramrod->bd_base, p_rx->rxq_chain.p_phys_addr); cqe_pbl_size = (u16)qed_chain_get_page_cnt(&p_rx->rcq_chain); p_ramrod->num_of_pbl_pages = cpu_to_le16(cqe_pbl_size); DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr, qed_chain_get_pbl_phys(&p_rx->rcq_chain)); - p_ramrod->drop_ttl0_flg = p_ll2_conn->conn.rx_drop_ttl0_flg; - p_ramrod->inner_vlan_removal_en = p_ll2_conn->conn.rx_vlan_removal_en; + p_ramrod->drop_ttl0_flg = p_ll2_conn->input.rx_drop_ttl0_flg; + p_ramrod->inner_vlan_removal_en = p_ll2_conn->input.rx_vlan_removal_en; p_ramrod->queue_id = p_ll2_conn->queue_id; p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_ISCSI_OOO) ? 0 : 1; @@ -1099,14 +992,14 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, } p_ramrod->action_on_error.error_type = action_on_error; - p_ramrod->gsi_offload_flag = p_ll2_conn->conn.gsi_enable; + p_ramrod->gsi_offload_flag = p_ll2_conn->input.gsi_enable; return qed_spq_post(p_hwfn, p_ent, NULL); } static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_conn) { - enum qed_ll2_conn_type conn_type = p_ll2_conn->conn.conn_type; + enum qed_ll2_conn_type conn_type = p_ll2_conn->input.conn_type; struct qed_ll2_tx_queue *p_tx = &p_ll2_conn->tx_queue; struct core_tx_start_ramrod_data *p_ramrod = NULL; struct qed_spq_entry *p_ent = NULL; @@ -1117,7 +1010,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, if (!QED_LL2_TX_REGISTERED(p_ll2_conn)) return 0; - if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) p_ll2_conn->tx_stats_en = 0; else p_ll2_conn->tx_stats_en = 1; @@ -1138,7 +1031,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->sb_id = cpu_to_le16(qed_int_get_sp_sb_id(p_hwfn)); p_ramrod->sb_index = p_tx->tx_sb_index; - p_ramrod->mtu = cpu_to_le16(p_ll2_conn->conn.mtu); + p_ramrod->mtu = cpu_to_le16(p_ll2_conn->input.mtu); p_ramrod->stats_en = p_ll2_conn->tx_stats_en; p_ramrod->stats_id = p_ll2_conn->tx_stats_id; @@ -1147,7 +1040,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, pbl_size = qed_chain_get_page_cnt(&p_tx->txq_chain); p_ramrod->pbl_size = cpu_to_le16(pbl_size); - switch (p_ll2_conn->conn.tx_tc) { + switch (p_ll2_conn->input.tx_tc) { case LB_TC: pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LB); break; @@ -1177,7 +1070,8 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, DP_NOTICE(p_hwfn, "Unknown connection type: %d\n", conn_type); } - p_ramrod->gsi_offload_flag = p_ll2_conn->conn.gsi_enable; + p_ramrod->gsi_offload_flag = p_ll2_conn->input.gsi_enable; + return qed_spq_post(p_hwfn, p_ent, NULL); } @@ -1233,20 +1127,20 @@ static int qed_sp_ll2_tx_queue_stop(struct qed_hwfn *p_hwfn, static int qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_info, u16 rx_num_desc) + struct qed_ll2_info *p_ll2_info) { struct qed_ll2_rx_packet *p_descq; u32 capacity; int rc = 0; - if (!rx_num_desc) + if (!p_ll2_info->input.rx_num_desc) goto out; rc = qed_chain_alloc(p_hwfn->cdev, QED_CHAIN_USE_TO_CONSUME_PRODUCE, QED_CHAIN_MODE_NEXT_PTR, QED_CHAIN_CNT_TYPE_U16, - rx_num_desc, + p_ll2_info->input.rx_num_desc, sizeof(struct core_rx_bd), &p_ll2_info->rx_queue.rxq_chain); if (rc) { @@ -1268,7 +1162,7 @@ qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn, QED_CHAIN_USE_TO_CONSUME_PRODUCE, QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, - rx_num_desc, + p_ll2_info->input.rx_num_desc, sizeof(struct core_rx_fast_path_cqe), &p_ll2_info->rx_queue.rcq_chain); if (rc) { @@ -1278,28 +1172,27 @@ qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn, DP_VERBOSE(p_hwfn, QED_MSG_LL2, "Allocated LL2 Rxq [Type %08x] with 0x%08x buffers\n", - p_ll2_info->conn.conn_type, rx_num_desc); + p_ll2_info->input.conn_type, p_ll2_info->input.rx_num_desc); out: return rc; } static int qed_ll2_acquire_connection_tx(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_info, - u16 tx_num_desc) + struct qed_ll2_info *p_ll2_info) { struct qed_ll2_tx_packet *p_descq; u32 capacity; int rc = 0; - if (!tx_num_desc) + if (!p_ll2_info->input.tx_num_desc) goto out; rc = qed_chain_alloc(p_hwfn->cdev, QED_CHAIN_USE_TO_CONSUME_PRODUCE, QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, - tx_num_desc, + p_ll2_info->input.tx_num_desc, sizeof(struct core_tx_bd), &p_ll2_info->tx_queue.txq_chain); if (rc) @@ -1316,28 +1209,95 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn *p_hwfn, DP_VERBOSE(p_hwfn, QED_MSG_LL2, "Allocated LL2 Txq [Type %08x] with 0x%08x buffers\n", - p_ll2_info->conn.conn_type, tx_num_desc); + p_ll2_info->input.conn_type, p_ll2_info->input.tx_num_desc); out: if (rc) DP_NOTICE(p_hwfn, "Can't allocate memory for Tx LL2 with 0x%08x buffers\n", - tx_num_desc); + p_ll2_info->input.tx_num_desc); + return rc; +} + +static int +qed_ll2_acquire_connection_ooo(struct qed_hwfn *p_hwfn, + struct qed_ll2_info *p_ll2_info, u16 mtu) +{ + struct qed_ooo_buffer *p_buf = NULL; + void *p_virt; + u16 buf_idx; + int rc = 0; + + if (p_ll2_info->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) + return rc; + + /* Correct number of requested OOO buffers if needed */ + if (!p_ll2_info->input.rx_num_ooo_buffers) { + u16 num_desc = p_ll2_info->input.rx_num_desc; + + if (!num_desc) + return -EINVAL; + p_ll2_info->input.rx_num_ooo_buffers = num_desc * 2; + } + + for (buf_idx = 0; buf_idx < p_ll2_info->input.rx_num_ooo_buffers; + buf_idx++) { + p_buf = kzalloc(sizeof(*p_buf), GFP_KERNEL); + if (!p_buf) { + rc = -ENOMEM; + goto out; + } + + p_buf->rx_buffer_size = mtu + 26 + ETH_CACHE_LINE_SIZE; + p_buf->rx_buffer_size = (p_buf->rx_buffer_size + + ETH_CACHE_LINE_SIZE - 1) & + ~(ETH_CACHE_LINE_SIZE - 1); + p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + p_buf->rx_buffer_size, + &p_buf->rx_buffer_phys_addr, + GFP_KERNEL); + if (!p_virt) { + kfree(p_buf); + rc = -ENOMEM; + goto out; + } + + p_buf->rx_buffer_virt_addr = p_virt; + qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info, p_buf); + } + + DP_VERBOSE(p_hwfn, QED_MSG_LL2, + "Allocated [%04x] LL2 OOO buffers [each of size 0x%08x]\n", + p_ll2_info->input.rx_num_ooo_buffers, p_buf->rx_buffer_size); + +out: return rc; } +static enum core_error_handle +qed_ll2_get_error_choice(enum qed_ll2_error_handle err) +{ + switch (err) { + case QED_LL2_DROP_PACKET: + return LL2_DROP_PACKET; + case QED_LL2_DO_NOTHING: + return LL2_DO_NOTHING; + case QED_LL2_ASSERT: + return LL2_ASSERT; + default: + return LL2_DO_NOTHING; + } +} + int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, - struct qed_ll2_conn *p_params, - u16 rx_num_desc, - u16 tx_num_desc, - u8 *p_connection_handle) + struct qed_ll2_acquire_data *data) { qed_int_comp_cb_t comp_rx_cb, comp_tx_cb; struct qed_ll2_info *p_ll2_info = NULL; + u8 i, *p_tx_max; int rc; - u8 i; - if (!p_connection_handle || !p_hwfn->p_ll2_info) + if (!data->p_connection_handle || !p_hwfn->p_ll2_info) return -EINVAL; /* Find a free connection to be used */ @@ -1356,23 +1316,33 @@ int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, if (!p_ll2_info) return -EBUSY; - p_ll2_info->conn = *p_params; + memcpy(&p_ll2_info->input, &data->input, sizeof(p_ll2_info->input)); - rc = qed_ll2_acquire_connection_rx(p_hwfn, p_ll2_info, rx_num_desc); + p_ll2_info->tx_dest = (data->input.tx_dest == QED_LL2_TX_DEST_NW) ? + CORE_TX_DEST_NW : CORE_TX_DEST_LB; + + /* Correct maximum number of Tx BDs */ + p_tx_max = &p_ll2_info->input.tx_max_bds_per_packet; + if (*p_tx_max == 0) + *p_tx_max = CORE_LL2_TX_MAX_BDS_PER_PACKET; + else + *p_tx_max = min_t(u8, *p_tx_max, + CORE_LL2_TX_MAX_BDS_PER_PACKET); + rc = qed_ll2_acquire_connection_rx(p_hwfn, p_ll2_info); if (rc) goto q_allocate_fail; - rc = qed_ll2_acquire_connection_tx(p_hwfn, p_ll2_info, tx_num_desc); + rc = qed_ll2_acquire_connection_tx(p_hwfn, p_ll2_info); if (rc) goto q_allocate_fail; rc = qed_ll2_acquire_connection_ooo(p_hwfn, p_ll2_info, - rx_num_desc * 2, p_params->mtu); + data->input.mtu); if (rc) goto q_allocate_fail; /* Register callbacks for the Rx/Tx queues */ - if (p_params->conn_type == QED_LL2_TYPE_ISCSI_OOO) { + if (data->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) { comp_rx_cb = qed_ll2_lb_rxq_completion; comp_tx_cb = qed_ll2_lb_txq_completion; } else { @@ -1380,7 +1350,7 @@ int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, comp_tx_cb = qed_ll2_txq_completion; } - if (rx_num_desc) { + if (data->input.rx_num_desc) { qed_int_register_cb(p_hwfn, comp_rx_cb, &p_hwfn->p_ll2_info[i], &p_ll2_info->rx_queue.rx_sb_index, @@ -1388,7 +1358,7 @@ int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, p_ll2_info->rx_queue.b_cb_registred = true; } - if (tx_num_desc) { + if (data->input.tx_num_desc) { qed_int_register_cb(p_hwfn, comp_tx_cb, &p_hwfn->p_ll2_info[i], @@ -1397,7 +1367,7 @@ int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, p_ll2_info->tx_queue.b_cb_registred = true; } - *p_connection_handle = i; + *data->p_connection_handle = i; return rc; q_allocate_fail: @@ -1408,18 +1378,21 @@ q_allocate_fail: static int qed_ll2_establish_connection_rx(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_conn) { + enum qed_ll2_error_handle error_input; + enum core_error_handle error_mode; u8 action_on_error = 0; if (!QED_LL2_RX_REGISTERED(p_ll2_conn)) return 0; DIRECT_REG_WR(p_ll2_conn->rx_queue.set_prod_addr, 0x0); - + error_input = p_ll2_conn->input.ai_err_packet_too_big; + error_mode = qed_ll2_get_error_choice(error_input); SET_FIELD(action_on_error, - CORE_RX_ACTION_ON_ERROR_PACKET_TOO_BIG, - p_ll2_conn->conn.ai_err_packet_too_big); - SET_FIELD(action_on_error, - CORE_RX_ACTION_ON_ERROR_NO_BUFF, p_ll2_conn->conn.ai_err_no_buf); + CORE_RX_ACTION_ON_ERROR_PACKET_TOO_BIG, error_mode); + error_input = p_ll2_conn->input.ai_err_no_buf; + error_mode = qed_ll2_get_error_choice(error_input); + SET_FIELD(action_on_error, CORE_RX_ACTION_ON_ERROR_NO_BUFF, error_mode); return qed_sp_ll2_rx_queue_start(p_hwfn, p_ll2_conn, action_on_error); } @@ -1503,7 +1476,7 @@ int qed_ll2_establish_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) qed_ll2_establish_connection_ooo(p_hwfn, p_ll2_conn); - if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_FCOE) { + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_FCOE) { qed_llh_add_protocol_filter(p_hwfn, p_ptt, 0x8906, 0, QED_LLH_FILTER_ETHERTYPE); @@ -1667,7 +1640,7 @@ qed_ll2_prepare_tx_packet_set_bd(struct qed_hwfn *p_hwfn, "LL2 [q 0x%02x cid 0x%08x type 0x%08x] Tx Producer at [0x%04x] - set with a %04x bytes %02x BDs buffer at %08x:%08x\n", p_ll2->queue_id, p_ll2->cid, - p_ll2->conn.conn_type, + p_ll2->input.conn_type, prod_idx, pkt->first_frag_len, pkt->num_of_bds, @@ -1742,7 +1715,8 @@ static void qed_ll2_tx_packet_notify(struct qed_hwfn *p_hwfn, (NETIF_MSG_TX_QUEUED | QED_MSG_LL2), "LL2 [q 0x%02x cid 0x%08x type 0x%08x] Doorbelled [producer 0x%04x]\n", p_ll2_conn->queue_id, - p_ll2_conn->cid, p_ll2_conn->conn.conn_type, db_msg.spq_prod); + p_ll2_conn->cid, + p_ll2_conn->input.conn_type, db_msg.spq_prod); } int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, @@ -1866,10 +1840,10 @@ int qed_ll2_terminate_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) qed_ll2_rxq_flush(p_hwfn, connection_handle); } - if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); - if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_FCOE) { + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_FCOE) { qed_llh_remove_protocol_filter(p_hwfn, p_ptt, 0x8906, 0, QED_LLH_FILTER_ETHERTYPE); @@ -2054,11 +2028,68 @@ static void qed_ll2_register_cb_ops(struct qed_dev *cdev, cdev->ll2->cb_cookie = cookie; } +static void qed_ll2_set_conn_data(struct qed_dev *cdev, + struct qed_ll2_acquire_data *data, + struct qed_ll2_params *params, + enum qed_ll2_conn_type conn_type, + u8 *handle, bool lb, u8 gsi_enable) +{ + memset(data, 0, sizeof(*data)); + + data->input.conn_type = conn_type; + data->input.mtu = params->mtu; + data->input.rx_num_desc = QED_LL2_RX_SIZE; + data->input.rx_drop_ttl0_flg = params->drop_ttl0_packets; + data->input.rx_vlan_removal_en = params->rx_vlan_stripping; + data->input.tx_num_desc = QED_LL2_TX_SIZE; + data->input.gsi_enable = gsi_enable; + data->p_connection_handle = handle; + if (lb) { + data->input.tx_tc = OOO_LB_TC; + data->input.tx_dest = QED_LL2_TX_DEST_LB; + } else { + data->input.tx_tc = 0; + data->input.tx_dest = QED_LL2_TX_DEST_NW; + } +} + +static int qed_ll2_start_ooo(struct qed_dev *cdev, + struct qed_ll2_params *params) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + u8 *handle = &hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id; + struct qed_ll2_acquire_data data; + int rc; + + qed_ll2_set_conn_data(cdev, &data, params, + QED_LL2_TYPE_ISCSI_OOO, handle, true, 0); + + rc = qed_ll2_acquire_connection(hwfn, &data); + if (rc) { + DP_INFO(cdev, "Failed to acquire LL2 OOO connection\n"); + goto out; + } + + rc = qed_ll2_establish_connection(hwfn, *handle); + if (rc) { + DP_INFO(cdev, "Failed to establist LL2 OOO connection\n"); + goto fail; + } + + return 0; + +fail: + qed_ll2_release_connection(hwfn, *handle); +out: + *handle = QED_LL2_UNUSED_HANDLE; + return rc; +} + static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) { - struct qed_ll2_conn ll2_info; struct qed_ll2_buffer *buffer, *tmp_buffer; enum qed_ll2_conn_type conn_type; + struct qed_ll2_acquire_data data; struct qed_ptt *p_ptt; int rc, i; u8 gsi_enable = 1; @@ -2106,20 +2137,10 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) conn_type = QED_LL2_TYPE_TEST; } - /* Prepare the temporary ll2 information */ - memset(&ll2_info, 0, sizeof(ll2_info)); - - ll2_info.conn_type = conn_type; - ll2_info.mtu = params->mtu; - ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets; - ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping; - ll2_info.tx_tc = 0; - ll2_info.tx_dest = CORE_TX_DEST_NW; - ll2_info.gsi_enable = gsi_enable; + qed_ll2_set_conn_data(cdev, &data, params, conn_type, + &cdev->ll2->handle, false, gsi_enable); - rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &ll2_info, - QED_LL2_RX_SIZE, QED_LL2_TX_SIZE, - &cdev->ll2->handle); + rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &data); if (rc) { DP_INFO(cdev, "Failed to acquire LL2 connection\n"); goto fail; diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h index 96af50b733e8..3caaad53c958 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h @@ -47,17 +47,6 @@ #define QED_MAX_NUM_OF_LL2_CONNECTIONS (4) -enum qed_ll2_conn_type { - QED_LL2_TYPE_FCOE, - QED_LL2_TYPE_ISCSI, - QED_LL2_TYPE_TEST, - QED_LL2_TYPE_ISCSI_OOO, - QED_LL2_TYPE_RESERVED2, - QED_LL2_TYPE_ROCE, - QED_LL2_TYPE_RESERVED3, - MAX_QED_LL2_RX_CONN_TYPE -}; - struct qed_ll2_rx_packet { struct list_head list_entry; struct core_rx_bd_with_buff_len *rxq_bd; @@ -123,27 +112,17 @@ struct qed_ll2_tx_queue { bool b_completing_packet; }; -struct qed_ll2_conn { - enum qed_ll2_conn_type conn_type; - u16 mtu; - u8 rx_drop_ttl0_flg; - u8 rx_vlan_removal_en; - u8 tx_tc; - enum core_tx_dest tx_dest; - enum core_error_handle ai_err_packet_too_big; - enum core_error_handle ai_err_no_buf; - u8 gsi_enable; -}; - struct qed_ll2_info { /* Lock protecting the state of LL2 */ struct mutex mutex; - struct qed_ll2_conn conn; + + struct qed_ll2_acquire_data_inputs input; u32 cid; u8 my_id; u8 queue_id; u8 tx_stats_id; bool b_active; + enum core_tx_dest tx_dest; u8 tx_stats_en; struct qed_ll2_rx_queue rx_queue; struct qed_ll2_tx_queue tx_queue; @@ -154,20 +133,13 @@ struct qed_ll2_info { * starts rx & tx (if relevant) queues pair. Provides * connecion handler as output parameter. * - * @param p_hwfn - * @param p_params Contain various configuration properties - * @param rx_num_desc - * @param tx_num_desc - * - * @param p_connection_handle Output container for LL2 connection's handle * - * @return 0 on success, failure otherwise + * @param p_hwfn + * @param data - describes connection parameters + * @return int */ int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, - struct qed_ll2_conn *p_params, - u16 rx_num_desc, - u16 tx_num_desc, - u8 *p_connection_handle); + struct qed_ll2_acquire_data *data); /** * @brief qed_ll2_establish_connection - start previously diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index afc63c0e7c44..33abcf110260 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -2818,7 +2818,7 @@ static int qed_roce_ll2_start(struct qed_dev *cdev, { struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); struct qed_roce_ll2_info *roce_ll2; - struct qed_ll2_conn ll2_params; + struct qed_ll2_acquire_data data; int rc; if (!params) { @@ -2844,25 +2844,26 @@ static int qed_roce_ll2_start(struct qed_dev *cdev, DP_ERR(cdev, "qed roce ll2 start: failed memory allocation\n"); return -ENOMEM; } + roce_ll2->handle = QED_LL2_UNUSED_HANDLE; roce_ll2->cbs = params->cbs; roce_ll2->cb_cookie = params->cb_cookie; mutex_init(&roce_ll2->lock); - memset(&ll2_params, 0, sizeof(ll2_params)); - ll2_params.conn_type = QED_LL2_TYPE_ROCE; - ll2_params.mtu = params->mtu; - ll2_params.rx_drop_ttl0_flg = true; - ll2_params.rx_vlan_removal_en = false; - ll2_params.tx_dest = CORE_TX_DEST_NW; - ll2_params.ai_err_packet_too_big = LL2_DROP_PACKET; - ll2_params.ai_err_no_buf = LL2_DROP_PACKET; - ll2_params.gsi_enable = true; - - rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &ll2_params, - params->max_rx_buffers, - params->max_tx_buffers, - &roce_ll2->handle); + memset(&data, 0, sizeof(data)); + data.input.conn_type = QED_LL2_TYPE_ROCE; + data.input.mtu = params->mtu; + data.input.rx_num_desc = params->max_rx_buffers; + data.input.tx_num_desc = params->max_tx_buffers; + data.input.rx_drop_ttl0_flg = true; + data.input.rx_vlan_removal_en = false; + data.input.tx_dest = QED_LL2_TX_DEST_NW; + data.input.ai_err_packet_too_big = LL2_DROP_PACKET; + data.input.ai_err_no_buf = LL2_DROP_PACKET; + data.p_connection_handle = &roce_ll2->handle; + data.input.gsi_enable = true; + + rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &data); if (rc) { DP_ERR(cdev, "qed roce ll2 start: failed to acquire LL2 connection (rc=%d)\n", -- cgit v1.2.3 From 58de289807f02122ef7eca96e50365d2c1440902 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 9 Jun 2017 17:13:21 +0300 Subject: qed: LL2 code relocations Instead of having the OOO logic packetd, divide it with rest of code according to establish/release flows. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 58 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index fcf4ea98e0bf..f3aad61e6394 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -896,36 +896,6 @@ static int qed_ll2_lb_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) return 0; } -static void -qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_conn) -{ - if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) - return; - - qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); - qed_ooo_submit_rx_buffers(p_hwfn, p_ll2_conn); -} - -static void qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_conn) -{ - struct qed_ooo_buffer *p_buffer; - - if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) - return; - - qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); - while ((p_buffer = qed_ooo_get_free_buffer(p_hwfn, - p_hwfn->p_ooo_info))) { - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - p_buffer->rx_buffer_size, - p_buffer->rx_buffer_virt_addr, - p_buffer->rx_buffer_phys_addr); - kfree(p_buffer); - } -} - static void qed_ll2_stop_ooo(struct qed_dev *cdev) { struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); @@ -1397,6 +1367,16 @@ static int qed_ll2_establish_connection_rx(struct qed_hwfn *p_hwfn, return qed_sp_ll2_rx_queue_start(p_hwfn, p_ll2_conn, action_on_error); } +static void +qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn, + struct qed_ll2_info *p_ll2_conn) +{ + if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) + return; + + qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); + qed_ooo_submit_rx_buffers(p_hwfn, p_ll2_conn); +} int qed_ll2_establish_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) { struct qed_ll2_info *p_ll2_conn; @@ -1857,6 +1837,24 @@ out: return rc; } +static void qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn, + struct qed_ll2_info *p_ll2_conn) +{ + struct qed_ooo_buffer *p_buffer; + + if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) + return; + + qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); + while ((p_buffer = qed_ooo_get_free_buffer(p_hwfn, + p_hwfn->p_ooo_info))) { + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + p_buffer->rx_buffer_size, + p_buffer->rx_buffer_virt_addr, + p_buffer->rx_buffer_phys_addr); + kfree(p_buffer); + } +} void qed_ll2_release_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) { struct qed_ll2_info *p_ll2_conn = NULL; -- cgit v1.2.3 From 0518c12f1f79dc2f2020836974c577404e42ae89 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Fri, 9 Jun 2017 17:13:22 +0300 Subject: qed*: LL2 callback operations LL2 today is interrupt driven - when tx/rx completion arrives [or any other indication], qed needs to operate on the connection and pass the information to the protocol-driver [or internal qed consumer]. Since we have several flavors of ll2 employeed by the driver, each handler needs to do an if-else to determine the right functionality to use based on the connection type. In order to make things more scalable [given that we're going to add additional types of ll2 flavors] move the infrastrucutre into using a callback-based approach - the callbacks would be provided as part of the connection's initialization parameters. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/infiniband/hw/qedr/main.c | 6 +- drivers/infiniband/hw/qedr/qedr.h | 2 + drivers/infiniband/hw/qedr/qedr_cm.c | 238 ++++++++++++++++------ drivers/net/ethernet/qlogic/qed/qed.h | 1 - drivers/net/ethernet/qlogic/qed/qed_ll2.c | 197 +++++++++---------- drivers/net/ethernet/qlogic/qed/qed_ll2.h | 34 ++-- drivers/net/ethernet/qlogic/qed/qed_roce.c | 304 ++--------------------------- drivers/net/ethernet/qlogic/qed/qed_roce.h | 43 ---- 8 files changed, 320 insertions(+), 505 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 6a72095d6c7a..485c1fef238b 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -886,9 +886,9 @@ static void qedr_mac_address_change(struct qedr_dev *dev) memcpy(&sgid->raw[8], guid, sizeof(guid)); /* Update LL2 */ - rc = dev->ops->roce_ll2_set_mac_filter(dev->cdev, - dev->gsi_ll2_mac_address, - dev->ndev->dev_addr); + rc = dev->ops->ll2_set_mac_filter(dev->cdev, + dev->gsi_ll2_mac_address, + dev->ndev->dev_addr); ether_addr_copy(dev->gsi_ll2_mac_address, dev->ndev->dev_addr); diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index aa08c76a4245..80333ec2c8b6 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -150,6 +150,8 @@ struct qedr_dev { u32 dp_module; u8 dp_level; u8 num_hwfns; + u8 gsi_ll2_handle; + uint wq_multiplier; u8 gsi_ll2_mac_address[ETH_ALEN]; int gsi_qp_created; diff --git a/drivers/infiniband/hw/qedr/qedr_cm.c b/drivers/infiniband/hw/qedr/qedr_cm.c index d86dbe814d98..eb3dce72fc21 100644 --- a/drivers/infiniband/hw/qedr/qedr_cm.c +++ b/drivers/infiniband/hw/qedr/qedr_cm.c @@ -64,9 +64,14 @@ void qedr_store_gsi_qp_cq(struct qedr_dev *dev, struct qedr_qp *qp, dev->gsi_qp = qp; } -void qedr_ll2_tx_cb(void *_qdev, struct qed_roce_ll2_packet *pkt) +void qedr_ll2_complete_tx_packet(void *cxt, + u8 connection_handle, + void *cookie, + dma_addr_t first_frag_addr, + bool b_last_fragment, bool b_last_packet) { - struct qedr_dev *dev = (struct qedr_dev *)_qdev; + struct qedr_dev *dev = (struct qedr_dev *)cxt; + struct qed_roce_ll2_packet *pkt = cookie; struct qedr_cq *cq = dev->gsi_sqcq; struct qedr_qp *qp = dev->gsi_qp; unsigned long flags; @@ -88,20 +93,26 @@ void qedr_ll2_tx_cb(void *_qdev, struct qed_roce_ll2_packet *pkt) (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); } -void qedr_ll2_rx_cb(void *_dev, struct qed_roce_ll2_packet *pkt, - struct qed_roce_ll2_rx_params *params) +void qedr_ll2_complete_rx_packet(void *cxt, + struct qed_ll2_comp_rx_data *data) { - struct qedr_dev *dev = (struct qedr_dev *)_dev; + struct qedr_dev *dev = (struct qedr_dev *)cxt; struct qedr_cq *cq = dev->gsi_rqcq; struct qedr_qp *qp = dev->gsi_qp; unsigned long flags; spin_lock_irqsave(&qp->q_lock, flags); - qp->rqe_wr_id[qp->rq.gsi_cons].rc = params->rc; - qp->rqe_wr_id[qp->rq.gsi_cons].vlan_id = params->vlan_id; - qp->rqe_wr_id[qp->rq.gsi_cons].sg_list[0].length = pkt->payload[0].len; - ether_addr_copy(qp->rqe_wr_id[qp->rq.gsi_cons].smac, params->smac); + qp->rqe_wr_id[qp->rq.gsi_cons].rc = data->u.data_length_error ? + -EINVAL : 0; + qp->rqe_wr_id[qp->rq.gsi_cons].vlan_id = data->vlan; + /* note: length stands for data length i.e. GRH is excluded */ + qp->rqe_wr_id[qp->rq.gsi_cons].sg_list[0].length = + data->length.data_length; + *((u32 *)&qp->rqe_wr_id[qp->rq.gsi_cons].smac[0]) = + ntohl(data->opaque_data_0); + *((u16 *)&qp->rqe_wr_id[qp->rq.gsi_cons].smac[4]) = + ntohs((u16)data->opaque_data_1); qedr_inc_sw_gsi_cons(&qp->rq); @@ -111,6 +122,14 @@ void qedr_ll2_rx_cb(void *_dev, struct qed_roce_ll2_packet *pkt, (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); } +void qedr_ll2_release_rx_packet(void *cxt, + u8 connection_handle, + void *cookie, + dma_addr_t rx_buf_addr, bool b_last_packet) +{ + /* Do nothing... */ +} + static void qedr_destroy_gsi_cq(struct qedr_dev *dev, struct ib_qp_init_attr *attrs) { @@ -159,27 +178,159 @@ static inline int qedr_check_gsi_qp_attrs(struct qedr_dev *dev, return 0; } +static int qedr_ll2_post_tx(struct qedr_dev *dev, + struct qed_roce_ll2_packet *pkt) +{ + enum qed_ll2_roce_flavor_type roce_flavor; + struct qed_ll2_tx_pkt_info ll2_tx_pkt; + int rc; + int i; + + memset(&ll2_tx_pkt, 0, sizeof(ll2_tx_pkt)); + + roce_flavor = (pkt->roce_mode == ROCE_V1) ? + QED_LL2_ROCE : QED_LL2_RROCE; + + if (pkt->roce_mode == ROCE_V2_IPV4) + ll2_tx_pkt.enable_ip_cksum = 1; + + ll2_tx_pkt.num_of_bds = 1 /* hdr */ + pkt->n_seg; + ll2_tx_pkt.vlan = 0; + ll2_tx_pkt.tx_dest = pkt->tx_dest; + ll2_tx_pkt.qed_roce_flavor = roce_flavor; + ll2_tx_pkt.first_frag = pkt->header.baddr; + ll2_tx_pkt.first_frag_len = pkt->header.len; + ll2_tx_pkt.cookie = pkt; + + /* tx header */ + rc = dev->ops->ll2_prepare_tx_packet(dev->rdma_ctx, + dev->gsi_ll2_handle, + &ll2_tx_pkt, 1); + if (rc) { + /* TX failed while posting header - release resources */ + dma_free_coherent(&dev->pdev->dev, pkt->header.len, + pkt->header.vaddr, pkt->header.baddr); + kfree(pkt); + + DP_ERR(dev, "roce ll2 tx: header failed (rc=%d)\n", rc); + return rc; + } + + /* tx payload */ + for (i = 0; i < pkt->n_seg; i++) { + rc = dev->ops->ll2_set_fragment_of_tx_packet( + dev->rdma_ctx, + dev->gsi_ll2_handle, + pkt->payload[i].baddr, + pkt->payload[i].len); + + if (rc) { + /* if failed not much to do here, partial packet has + * been posted we can't free memory, will need to wait + * for completion + */ + DP_ERR(dev, "ll2 tx: payload failed (rc=%d)\n", rc); + return rc; + } + } + + return 0; +} + +int qedr_ll2_stop(struct qedr_dev *dev) +{ + int rc; + + if (dev->gsi_ll2_handle == QED_LL2_UNUSED_HANDLE) + return 0; + + /* remove LL2 MAC address filter */ + rc = dev->ops->ll2_set_mac_filter(dev->cdev, + dev->gsi_ll2_mac_address, NULL); + + rc = dev->ops->ll2_terminate_connection(dev->rdma_ctx, + dev->gsi_ll2_handle); + if (rc) + DP_ERR(dev, "Failed to terminate LL2 connection (rc=%d)\n", rc); + + dev->ops->ll2_release_connection(dev->rdma_ctx, dev->gsi_ll2_handle); + + dev->gsi_ll2_handle = QED_LL2_UNUSED_HANDLE; + + return rc; +} + +int qedr_ll2_start(struct qedr_dev *dev, + struct ib_qp_init_attr *attrs, struct qedr_qp *qp) +{ + struct qed_ll2_acquire_data data; + struct qed_ll2_cbs cbs; + int rc; + + /* configure and start LL2 */ + cbs.rx_comp_cb = qedr_ll2_complete_rx_packet; + cbs.tx_comp_cb = qedr_ll2_complete_tx_packet; + cbs.rx_release_cb = qedr_ll2_release_rx_packet; + cbs.tx_release_cb = qedr_ll2_complete_tx_packet; + cbs.cookie = dev; + + memset(&data, 0, sizeof(data)); + data.input.conn_type = QED_LL2_TYPE_ROCE; + data.input.mtu = dev->ndev->mtu; + data.input.rx_num_desc = attrs->cap.max_recv_wr; + data.input.rx_drop_ttl0_flg = true; + data.input.rx_vlan_removal_en = false; + data.input.tx_num_desc = attrs->cap.max_send_wr; + data.input.tx_tc = 0; + data.input.tx_dest = QED_LL2_TX_DEST_NW; + data.input.ai_err_packet_too_big = QED_LL2_DROP_PACKET; + data.input.ai_err_no_buf = QED_LL2_DROP_PACKET; + data.input.gsi_enable = 1; + data.p_connection_handle = &dev->gsi_ll2_handle; + data.cbs = &cbs; + + rc = dev->ops->ll2_acquire_connection(dev->rdma_ctx, &data); + if (rc) { + DP_ERR(dev, + "ll2 start: failed to acquire LL2 connection (rc=%d)\n", + rc); + return rc; + } + + rc = dev->ops->ll2_establish_connection(dev->rdma_ctx, + dev->gsi_ll2_handle); + if (rc) { + DP_ERR(dev, + "ll2 start: failed to establish LL2 connection (rc=%d)\n", + rc); + goto err1; + } + + rc = dev->ops->ll2_set_mac_filter(dev->cdev, NULL, dev->ndev->dev_addr); + if (rc) + goto err2; + + return 0; + +err2: + dev->ops->ll2_terminate_connection(dev->rdma_ctx, dev->gsi_ll2_handle); +err1: + dev->ops->ll2_release_connection(dev->rdma_ctx, dev->gsi_ll2_handle); + + return rc; +} + struct ib_qp *qedr_create_gsi_qp(struct qedr_dev *dev, struct ib_qp_init_attr *attrs, struct qedr_qp *qp) { - struct qed_roce_ll2_params ll2_params; int rc; rc = qedr_check_gsi_qp_attrs(dev, attrs); if (rc) return ERR_PTR(rc); - /* configure and start LL2 */ - memset(&ll2_params, 0, sizeof(ll2_params)); - ll2_params.max_tx_buffers = attrs->cap.max_send_wr; - ll2_params.max_rx_buffers = attrs->cap.max_recv_wr; - ll2_params.cbs.tx_cb = qedr_ll2_tx_cb; - ll2_params.cbs.rx_cb = qedr_ll2_rx_cb; - ll2_params.cb_cookie = (void *)dev; - ll2_params.mtu = dev->ndev->mtu; - ether_addr_copy(ll2_params.mac_address, dev->ndev->dev_addr); - rc = dev->ops->roce_ll2_start(dev->cdev, &ll2_params); + rc = qedr_ll2_start(dev, attrs, qp); if (rc) { DP_ERR(dev, "create gsi qp: failed on ll2 start. rc=%d\n", rc); return ERR_PTR(rc); @@ -214,7 +365,7 @@ struct ib_qp *qedr_create_gsi_qp(struct qedr_dev *dev, err: kfree(qp->rqe_wr_id); - rc = dev->ops->roce_ll2_stop(dev->cdev); + rc = qedr_ll2_stop(dev); if (rc) DP_ERR(dev, "create gsi qp: failed destroy on create\n"); @@ -223,15 +374,7 @@ err: int qedr_destroy_gsi_qp(struct qedr_dev *dev) { - int rc; - - rc = dev->ops->roce_ll2_stop(dev->cdev); - if (rc) - DP_ERR(dev, "destroy gsi qp: failed (rc=%d)\n", rc); - else - DP_DEBUG(dev, QEDR_MSG_GSI, "destroy gsi qp: success\n"); - - return rc; + return qedr_ll2_stop(dev); } #define QEDR_MAX_UD_HEADER_SIZE (100) @@ -421,7 +564,6 @@ int qedr_gsi_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, { struct qed_roce_ll2_packet *pkt = NULL; struct qedr_qp *qp = get_qedr_qp(ibqp); - struct qed_roce_ll2_tx_params params; struct qedr_dev *dev = qp->dev; unsigned long flags; int rc; @@ -449,8 +591,6 @@ int qedr_gsi_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, goto err; } - memset(¶ms, 0, sizeof(params)); - spin_lock_irqsave(&qp->q_lock, flags); rc = qedr_gsi_build_packet(dev, qp, wr, &pkt); @@ -459,7 +599,8 @@ int qedr_gsi_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, goto err; } - rc = dev->ops->roce_ll2_tx(dev->cdev, pkt, ¶ms); + rc = qedr_ll2_post_tx(dev, pkt); + if (!rc) { qp->wqe_wr_id[qp->sq.prod].wr_id = wr->wr_id; qedr_inc_sw_prod(&qp->sq); @@ -467,17 +608,6 @@ int qedr_gsi_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, "gsi post send: opcode=%d, in_irq=%ld, irqs_disabled=%d, wr_id=%llx\n", wr->opcode, in_irq(), irqs_disabled(), wr->wr_id); } else { - if (rc == QED_ROCE_TX_HEAD_FAILURE) { - /* TX failed while posting header - release resources */ - dma_free_coherent(&dev->pdev->dev, pkt->header.len, - pkt->header.vaddr, pkt->header.baddr); - kfree(pkt); - } else if (rc == QED_ROCE_TX_FRAG_FAILURE) { - /* NTD since TX failed while posting a fragment. We will - * release the resources on TX callback - */ - } - DP_ERR(dev, "gsi post send: failed to transmit (rc=%d)\n", rc); rc = -EAGAIN; *bad_wr = wr; @@ -504,10 +634,8 @@ int qedr_gsi_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, { struct qedr_dev *dev = get_qedr_dev(ibqp->device); struct qedr_qp *qp = get_qedr_qp(ibqp); - struct qed_roce_ll2_buffer buf; unsigned long flags; - int status = 0; - int rc; + int rc = 0; if ((qp->state != QED_ROCE_QP_STATE_RTR) && (qp->state != QED_ROCE_QP_STATE_RTS)) { @@ -518,8 +646,6 @@ int qedr_gsi_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, return -EINVAL; } - memset(&buf, 0, sizeof(buf)); - spin_lock_irqsave(&qp->q_lock, flags); while (wr) { @@ -530,10 +656,12 @@ int qedr_gsi_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, goto err; } - buf.baddr = wr->sg_list[0].addr; - buf.len = wr->sg_list[0].length; - - rc = dev->ops->roce_ll2_post_rx_buffer(dev->cdev, &buf, 0, 1); + rc = dev->ops->ll2_post_rx_buffer(dev->rdma_ctx, + dev->gsi_ll2_handle, + wr->sg_list[0].addr, + wr->sg_list[0].length, + 0 /* cookie */, + 1 /* notify_fw */); if (rc) { DP_ERR(dev, "gsi post recv: failed to post rx buffer (rc=%d)\n", @@ -553,7 +681,7 @@ int qedr_gsi_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, spin_unlock_irqrestore(&qp->q_lock, flags); - return status; + return rc; err: spin_unlock_irqrestore(&qp->q_lock, flags); *bad_wr = wr; diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index d7afc42f766c..14b08ee9e3ad 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -552,7 +552,6 @@ struct qed_hwfn { #endif struct z_stream_s *stream; - struct qed_roce_ll2_info *ll2; }; struct pci_params { diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index f3aad61e6394..b222b2b471e8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -89,13 +89,14 @@ struct qed_ll2_buffer { dma_addr_t phys_addr; }; -static void qed_ll2b_complete_tx_packet(struct qed_hwfn *p_hwfn, +static void qed_ll2b_complete_tx_packet(void *cxt, u8 connection_handle, void *cookie, dma_addr_t first_frag_addr, bool b_last_fragment, bool b_last_packet) { + struct qed_hwfn *p_hwfn = cxt; struct qed_dev *cdev = p_hwfn->cdev; struct sk_buff *skb = cookie; @@ -164,9 +165,9 @@ static void qed_ll2_kill_buffers(struct qed_dev *cdev) qed_ll2_dealloc_buffer(cdev, buffer); } -static void qed_ll2b_complete_rx_packet(struct qed_hwfn *p_hwfn, - struct qed_ll2_comp_rx_data *data) +void qed_ll2b_complete_rx_packet(void *cxt, struct qed_ll2_comp_rx_data *data) { + struct qed_hwfn *p_hwfn = cxt; struct qed_ll2_buffer *buffer = data->cookie; struct qed_dev *cdev = p_hwfn->cdev; dma_addr_t new_phys_addr; @@ -327,21 +328,12 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used; tx_frag = p_pkt->bds_set[0].tx_frag; - if (p_ll2_conn->input.gsi_enable) - qed_ll2b_release_tx_gsi_packet(p_hwfn, - p_ll2_conn-> - my_id, - p_pkt->cookie, - tx_frag, - b_last_frag, - b_last_packet); - else - qed_ll2b_complete_tx_packet(p_hwfn, - p_ll2_conn->my_id, - p_pkt->cookie, - tx_frag, - b_last_frag, - b_last_packet); + p_ll2_conn->cbs.tx_release_cb(p_ll2_conn->cbs.cookie, + p_ll2_conn->my_id, + p_pkt->cookie, + tx_frag, + b_last_frag, + b_last_packet); } } } @@ -354,7 +346,6 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) struct qed_ll2_tx_packet *p_pkt; bool b_last_frag = false; unsigned long flags; - dma_addr_t tx_frag; int rc = -EINVAL; spin_lock_irqsave(&p_tx->lock, flags); @@ -395,19 +386,13 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) list_add_tail(&p_pkt->list_entry, &p_tx->free_descq); spin_unlock_irqrestore(&p_tx->lock, flags); - tx_frag = p_pkt->bds_set[0].tx_frag; - if (p_ll2_conn->input.gsi_enable) - qed_ll2b_complete_tx_gsi_packet(p_hwfn, - p_ll2_conn->my_id, - p_pkt->cookie, - tx_frag, - b_last_frag, !num_bds); - else - qed_ll2b_complete_tx_packet(p_hwfn, - p_ll2_conn->my_id, - p_pkt->cookie, - tx_frag, - b_last_frag, !num_bds); + + p_ll2_conn->cbs.tx_comp_cb(p_ll2_conn->cbs.cookie, + p_ll2_conn->my_id, + p_pkt->cookie, + p_pkt->bds_set[0].tx_frag, + b_last_frag, !num_bds); + spin_lock_irqsave(&p_tx->lock, flags); } @@ -418,52 +403,16 @@ out: return rc; } -static int -qed_ll2_rxq_completion_gsi(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_ll2_info, - union core_rx_cqe_union *p_cqe, - unsigned long lock_flags, bool b_last_cqe) +static void qed_ll2_rxq_parse_gsi(struct qed_hwfn *p_hwfn, + union core_rx_cqe_union *p_cqe, + struct qed_ll2_comp_rx_data *data) { - struct qed_ll2_rx_queue *p_rx = &p_ll2_info->rx_queue; - struct qed_ll2_rx_packet *p_pkt = NULL; - u16 packet_length, parse_flags, vlan; - u32 src_mac_addrhi; - u16 src_mac_addrlo; - - if (!list_empty(&p_rx->active_descq)) - p_pkt = list_first_entry(&p_rx->active_descq, - struct qed_ll2_rx_packet, list_entry); - if (!p_pkt) { - DP_NOTICE(p_hwfn, - "GSI Rx completion but active_descq is empty\n"); - return -EIO; - } - - list_del(&p_pkt->list_entry); - parse_flags = le16_to_cpu(p_cqe->rx_cqe_gsi.parse_flags.flags); - packet_length = le16_to_cpu(p_cqe->rx_cqe_gsi.data_length); - vlan = le16_to_cpu(p_cqe->rx_cqe_gsi.vlan); - src_mac_addrhi = le32_to_cpu(p_cqe->rx_cqe_gsi.src_mac_addrhi); - src_mac_addrlo = le16_to_cpu(p_cqe->rx_cqe_gsi.src_mac_addrlo); - if (qed_chain_consume(&p_rx->rxq_chain) != p_pkt->rxq_bd) - DP_NOTICE(p_hwfn, - "Mismatch between active_descq and the LL2 Rx chain\n"); - list_add_tail(&p_pkt->list_entry, &p_rx->free_descq); - - spin_unlock_irqrestore(&p_rx->lock, lock_flags); - qed_ll2b_complete_rx_gsi_packet(p_hwfn, - p_ll2_info->my_id, - p_pkt->cookie, - p_pkt->rx_buf_addr, - packet_length, - p_cqe->rx_cqe_gsi.data_length_error, - parse_flags, - vlan, - src_mac_addrhi, - src_mac_addrlo, b_last_cqe); - spin_lock_irqsave(&p_rx->lock, lock_flags); - - return 0; + data->parse_flags = le16_to_cpu(p_cqe->rx_cqe_gsi.parse_flags.flags); + data->length.data_length = le16_to_cpu(p_cqe->rx_cqe_gsi.data_length); + data->vlan = le16_to_cpu(p_cqe->rx_cqe_gsi.vlan); + data->opaque_data_0 = le32_to_cpu(p_cqe->rx_cqe_gsi.src_mac_addrhi); + data->opaque_data_1 = le16_to_cpu(p_cqe->rx_cqe_gsi.src_mac_addrlo); + data->u.data_length_error = p_cqe->rx_cqe_gsi.data_length_error; } static void qed_ll2_rxq_parse_reg(struct qed_hwfn *p_hwfn, @@ -501,7 +450,10 @@ qed_ll2_rxq_handle_completion(struct qed_hwfn *p_hwfn, } list_del(&p_pkt->list_entry); - qed_ll2_rxq_parse_reg(p_hwfn, p_cqe, &data); + if (p_cqe->rx_cqe_sp.type == CORE_RX_CQE_TYPE_REGULAR) + qed_ll2_rxq_parse_reg(p_hwfn, p_cqe, &data); + else + qed_ll2_rxq_parse_gsi(p_hwfn, p_cqe, &data); if (qed_chain_consume(&p_rx->rxq_chain) != p_pkt->rxq_bd) DP_NOTICE(p_hwfn, "Mismatch between active_descq and the LL2 Rx chain\n"); @@ -514,7 +466,8 @@ qed_ll2_rxq_handle_completion(struct qed_hwfn *p_hwfn, data.b_last_packet = b_last_cqe; spin_unlock_irqrestore(&p_rx->lock, *p_lock_flags); - qed_ll2b_complete_rx_packet(p_hwfn, &data); + p_ll2_conn->cbs.rx_comp_cb(p_ll2_conn->cbs.cookie, &data); + spin_lock_irqsave(&p_rx->lock, *p_lock_flags); return 0; @@ -552,9 +505,6 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, void *cookie) rc = -EINVAL; break; case CORE_RX_CQE_TYPE_GSI_OFFLOAD: - rc = qed_ll2_rxq_completion_gsi(p_hwfn, p_ll2_conn, - cqe, flags, b_last_cqe); - break; case CORE_RX_CQE_TYPE_REGULAR: rc = qed_ll2_rxq_handle_completion(p_hwfn, p_ll2_conn, cqe, &flags, @@ -1244,6 +1194,23 @@ out: return rc; } +static int +qed_ll2_set_cbs(struct qed_ll2_info *p_ll2_info, const struct qed_ll2_cbs *cbs) +{ + if (!cbs || (!cbs->rx_comp_cb || + !cbs->rx_release_cb || + !cbs->tx_comp_cb || !cbs->tx_release_cb || !cbs->cookie)) + return -EINVAL; + + p_ll2_info->cbs.rx_comp_cb = cbs->rx_comp_cb; + p_ll2_info->cbs.rx_release_cb = cbs->rx_release_cb; + p_ll2_info->cbs.tx_comp_cb = cbs->tx_comp_cb; + p_ll2_info->cbs.tx_release_cb = cbs->tx_release_cb; + p_ll2_info->cbs.cookie = cbs->cookie; + + return 0; +} + static enum core_error_handle qed_ll2_get_error_choice(enum qed_ll2_error_handle err) { @@ -1259,9 +1226,9 @@ qed_ll2_get_error_choice(enum qed_ll2_error_handle err) } } -int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, - struct qed_ll2_acquire_data *data) +int qed_ll2_acquire_connection(void *cxt, struct qed_ll2_acquire_data *data) { + struct qed_hwfn *p_hwfn = cxt; qed_int_comp_cb_t comp_rx_cb, comp_tx_cb; struct qed_ll2_info *p_ll2_info = NULL; u8 i, *p_tx_max; @@ -1298,6 +1265,13 @@ int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, else *p_tx_max = min_t(u8, *p_tx_max, CORE_LL2_TX_MAX_BDS_PER_PACKET); + + rc = qed_ll2_set_cbs(p_ll2_info, data->cbs); + if (rc) { + DP_NOTICE(p_hwfn, "Invalid callback functions\n"); + goto q_allocate_fail; + } + rc = qed_ll2_acquire_connection_rx(p_hwfn, p_ll2_info); if (rc) goto q_allocate_fail; @@ -1377,8 +1351,10 @@ qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn, qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); qed_ooo_submit_rx_buffers(p_hwfn, p_ll2_conn); } -int qed_ll2_establish_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) + +int qed_ll2_establish_connection(void *cxt, u8 connection_handle) { + struct qed_hwfn *p_hwfn = cxt; struct qed_ll2_info *p_ll2_conn; struct qed_ll2_rx_queue *p_rx; struct qed_ll2_tx_queue *p_tx; @@ -1505,11 +1481,12 @@ static void qed_ll2_post_rx_buffer_notify_fw(struct qed_hwfn *p_hwfn, DIRECT_REG_WR(p_rx->set_prod_addr, *((u32 *)&rx_prod)); } -int qed_ll2_post_rx_buffer(struct qed_hwfn *p_hwfn, +int qed_ll2_post_rx_buffer(void *cxt, u8 connection_handle, dma_addr_t addr, u16 buf_len, void *cookie, u8 notify_fw) { + struct qed_hwfn *p_hwfn = cxt; struct core_rx_bd_with_buff_len *p_curb = NULL; struct qed_ll2_rx_packet *p_curp = NULL; struct qed_ll2_info *p_ll2_conn; @@ -1699,11 +1676,12 @@ static void qed_ll2_tx_packet_notify(struct qed_hwfn *p_hwfn, p_ll2_conn->input.conn_type, db_msg.spq_prod); } -int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, +int qed_ll2_prepare_tx_packet(void *cxt, u8 connection_handle, struct qed_ll2_tx_pkt_info *pkt, bool notify_fw) { + struct qed_hwfn *p_hwfn = cxt; struct qed_ll2_tx_packet *p_curp = NULL; struct qed_ll2_info *p_ll2_conn = NULL; struct qed_ll2_tx_queue *p_tx; @@ -1750,11 +1728,12 @@ out: return rc; } -int qed_ll2_set_fragment_of_tx_packet(struct qed_hwfn *p_hwfn, +int qed_ll2_set_fragment_of_tx_packet(void *cxt, u8 connection_handle, dma_addr_t addr, u16 nbytes) { struct qed_ll2_tx_packet *p_cur_send_packet = NULL; + struct qed_hwfn *p_hwfn = cxt; struct qed_ll2_info *p_ll2_conn = NULL; u16 cur_send_frag_num = 0; struct core_tx_bd *p_bd; @@ -1789,8 +1768,9 @@ int qed_ll2_set_fragment_of_tx_packet(struct qed_hwfn *p_hwfn, return 0; } -int qed_ll2_terminate_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) +int qed_ll2_terminate_connection(void *cxt, u8 connection_handle) { + struct qed_hwfn *p_hwfn = cxt; struct qed_ll2_info *p_ll2_conn = NULL; int rc = -EINVAL; struct qed_ptt *p_ptt; @@ -1855,8 +1835,10 @@ static void qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn, kfree(p_buffer); } } -void qed_ll2_release_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) + +void qed_ll2_release_connection(void *cxt, u8 connection_handle) { + struct qed_hwfn *p_hwfn = cxt; struct qed_ll2_info *p_ll2_conn = NULL; p_ll2_conn = qed_ll2_handle_sanity(p_hwfn, connection_handle); @@ -1989,9 +1971,10 @@ static void _qed_ll2_get_pstats(struct qed_hwfn *p_hwfn, p_stats->sent_bcast_pkts = HILO_64_REGPAIR(pstats.sent_bcast_pkts); } -int qed_ll2_get_stats(struct qed_hwfn *p_hwfn, +int qed_ll2_get_stats(void *cxt, u8 connection_handle, struct qed_ll2_stats *p_stats) { + struct qed_hwfn *p_hwfn = cxt; struct qed_ll2_info *p_ll2_conn = NULL; struct qed_ptt *p_ptt; @@ -2018,6 +2001,17 @@ int qed_ll2_get_stats(struct qed_hwfn *p_hwfn, return 0; } +static void qed_ll2b_release_rx_packet(void *cxt, + u8 connection_handle, + void *cookie, + dma_addr_t rx_buf_addr, + bool b_last_packet) +{ + struct qed_hwfn *p_hwfn = cxt; + + qed_ll2_dealloc_buffer(p_hwfn->cdev, cookie); +} + static void qed_ll2_register_cb_ops(struct qed_dev *cdev, const struct qed_ll2_cb_ops *ops, void *cookie) @@ -2026,11 +2020,18 @@ static void qed_ll2_register_cb_ops(struct qed_dev *cdev, cdev->ll2->cb_cookie = cookie; } +struct qed_ll2_cbs ll2_cbs = { + .rx_comp_cb = &qed_ll2b_complete_rx_packet, + .rx_release_cb = &qed_ll2b_release_rx_packet, + .tx_comp_cb = &qed_ll2b_complete_tx_packet, + .tx_release_cb = &qed_ll2b_complete_tx_packet, +}; + static void qed_ll2_set_conn_data(struct qed_dev *cdev, struct qed_ll2_acquire_data *data, struct qed_ll2_params *params, enum qed_ll2_conn_type conn_type, - u8 *handle, bool lb, u8 gsi_enable) + u8 *handle, bool lb) { memset(data, 0, sizeof(*data)); @@ -2040,8 +2041,10 @@ static void qed_ll2_set_conn_data(struct qed_dev *cdev, data->input.rx_drop_ttl0_flg = params->drop_ttl0_packets; data->input.rx_vlan_removal_en = params->rx_vlan_stripping; data->input.tx_num_desc = QED_LL2_TX_SIZE; - data->input.gsi_enable = gsi_enable; data->p_connection_handle = handle; + data->cbs = &ll2_cbs; + ll2_cbs.cookie = QED_LEADING_HWFN(cdev); + if (lb) { data->input.tx_tc = OOO_LB_TC; data->input.tx_dest = QED_LL2_TX_DEST_LB; @@ -2060,7 +2063,7 @@ static int qed_ll2_start_ooo(struct qed_dev *cdev, int rc; qed_ll2_set_conn_data(cdev, &data, params, - QED_LL2_TYPE_ISCSI_OOO, handle, true, 0); + QED_LL2_TYPE_ISCSI_OOO, handle, true); rc = qed_ll2_acquire_connection(hwfn, &data); if (rc) { @@ -2090,7 +2093,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) struct qed_ll2_acquire_data data; struct qed_ptt *p_ptt; int rc, i; - u8 gsi_enable = 1; + /* Initialize LL2 locks & lists */ INIT_LIST_HEAD(&cdev->ll2->list); @@ -2122,11 +2125,9 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) switch (QED_LEADING_HWFN(cdev)->hw_info.personality) { case QED_PCI_FCOE: conn_type = QED_LL2_TYPE_FCOE; - gsi_enable = 0; break; case QED_PCI_ISCSI: conn_type = QED_LL2_TYPE_ISCSI; - gsi_enable = 0; break; case QED_PCI_ETH_ROCE: conn_type = QED_LL2_TYPE_ROCE; @@ -2136,7 +2137,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) } qed_ll2_set_conn_data(cdev, &data, params, conn_type, - &cdev->ll2->handle, false, gsi_enable); + &cdev->ll2->handle, false); rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &data); if (rc) { diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h index 3caaad53c958..a822528e9c63 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h @@ -126,6 +126,7 @@ struct qed_ll2_info { u8 tx_stats_en; struct qed_ll2_rx_queue rx_queue; struct qed_ll2_tx_queue tx_queue; + struct qed_ll2_cbs cbs; }; /** @@ -134,30 +135,29 @@ struct qed_ll2_info { * connecion handler as output parameter. * * - * @param p_hwfn + * @param cxt - pointer to the hw-function [opaque to some] * @param data - describes connection parameters * @return int */ -int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, - struct qed_ll2_acquire_data *data); +int qed_ll2_acquire_connection(void *cxt, struct qed_ll2_acquire_data *data); /** * @brief qed_ll2_establish_connection - start previously * allocated LL2 queues pair * - * @param p_hwfn + * @param cxt - pointer to the hw-function [opaque to some] * @param p_ptt * @param connection_handle LL2 connection's handle obtained from * qed_ll2_require_connection * * @return 0 on success, failure otherwise */ -int qed_ll2_establish_connection(struct qed_hwfn *p_hwfn, u8 connection_handle); +int qed_ll2_establish_connection(void *cxt, u8 connection_handle); /** * @brief qed_ll2_post_rx_buffers - submit buffers to LL2 Rx queue. * - * @param p_hwfn + * @param cxt - pointer to the hw-function [opaque to some] * @param connection_handle LL2 connection's handle obtained from * qed_ll2_require_connection * @param addr rx (physical address) buffers to submit @@ -166,7 +166,7 @@ int qed_ll2_establish_connection(struct qed_hwfn *p_hwfn, u8 connection_handle); * * @return 0 on success, failure otherwise */ -int qed_ll2_post_rx_buffer(struct qed_hwfn *p_hwfn, +int qed_ll2_post_rx_buffer(void *cxt, u8 connection_handle, dma_addr_t addr, u16 buf_len, void *cookie, u8 notify_fw); @@ -175,14 +175,14 @@ int qed_ll2_post_rx_buffer(struct qed_hwfn *p_hwfn, * @brief qed_ll2_prepare_tx_packet - request for start Tx BD * to prepare Tx packet submission to FW. * - * @param p_hwfn + * @param cxt - pointer to the hw-function [opaque to some] * @param connection_handle * @param pkt - info regarding the tx packet * @param notify_fw - issue doorbell to fw for this packet * * @return 0 on success, failure otherwise */ -int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, +int qed_ll2_prepare_tx_packet(void *cxt, u8 connection_handle, struct qed_ll2_tx_pkt_info *pkt, bool notify_fw); @@ -191,18 +191,18 @@ int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, * @brief qed_ll2_release_connection - releases resources * allocated for LL2 connection * - * @param p_hwfn + * @param cxt - pointer to the hw-function [opaque to some] * @param connection_handle LL2 connection's handle obtained from * qed_ll2_require_connection */ -void qed_ll2_release_connection(struct qed_hwfn *p_hwfn, u8 connection_handle); +void qed_ll2_release_connection(void *cxt, u8 connection_handle); /** * @brief qed_ll2_set_fragment_of_tx_packet - provides fragments to fill * Tx BD of BDs requested by * qed_ll2_prepare_tx_packet * - * @param p_hwfn + * @param cxt - pointer to the hw-function [opaque to some] * @param connection_handle LL2 connection's handle * obtained from * qed_ll2_require_connection @@ -211,7 +211,7 @@ void qed_ll2_release_connection(struct qed_hwfn *p_hwfn, u8 connection_handle); * * @return 0 on success, failure otherwise */ -int qed_ll2_set_fragment_of_tx_packet(struct qed_hwfn *p_hwfn, +int qed_ll2_set_fragment_of_tx_packet(void *cxt, u8 connection_handle, dma_addr_t addr, u16 nbytes); @@ -219,27 +219,27 @@ int qed_ll2_set_fragment_of_tx_packet(struct qed_hwfn *p_hwfn, * @brief qed_ll2_terminate_connection - stops Tx/Rx queues * * - * @param p_hwfn + * @param cxt - pointer to the hw-function [opaque to some] * @param connection_handle LL2 connection's handle * obtained from * qed_ll2_require_connection * * @return 0 on success, failure otherwise */ -int qed_ll2_terminate_connection(struct qed_hwfn *p_hwfn, u8 connection_handle); +int qed_ll2_terminate_connection(void *cxt, u8 connection_handle); /** * @brief qed_ll2_get_stats - get LL2 queue's statistics * * - * @param p_hwfn + * @param cxt - pointer to the hw-function [opaque to some] * @param connection_handle LL2 connection's handle obtained from * qed_ll2_require_connection * @param p_stats * * @return 0 on success, failure otherwise */ -int qed_ll2_get_stats(struct qed_hwfn *p_hwfn, +int qed_ll2_get_stats(void *cxt, u8 connection_handle, struct qed_ll2_stats *p_stats); /** diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 33abcf110260..4bc2f6c47f69 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -65,6 +64,7 @@ #include "qed_sp.h" #include "qed_roce.h" #include "qed_ll2.h" +#include static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid); @@ -2709,310 +2709,35 @@ static void qed_rdma_remove_user(void *rdma_cxt, u16 dpi) spin_unlock_bh(&p_hwfn->p_rdma_info->lock); } -void qed_ll2b_complete_tx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t first_frag_addr, - bool b_last_fragment, bool b_last_packet) -{ - struct qed_roce_ll2_packet *packet = cookie; - struct qed_roce_ll2_info *roce_ll2 = p_hwfn->ll2; - - roce_ll2->cbs.tx_cb(roce_ll2->cb_cookie, packet); -} - -void qed_ll2b_release_tx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t first_frag_addr, - bool b_last_fragment, bool b_last_packet) -{ - qed_ll2b_complete_tx_gsi_packet(p_hwfn, connection_handle, - cookie, first_frag_addr, - b_last_fragment, b_last_packet); -} - -void qed_ll2b_complete_rx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t rx_buf_addr, - u16 data_length, - u8 data_length_error, - u16 parse_flags, - u16 vlan, - u32 src_mac_addr_hi, - u16 src_mac_addr_lo, bool b_last_packet) -{ - struct qed_roce_ll2_info *roce_ll2 = p_hwfn->ll2; - struct qed_roce_ll2_rx_params params; - struct qed_dev *cdev = p_hwfn->cdev; - struct qed_roce_ll2_packet pkt; - - DP_VERBOSE(cdev, - QED_MSG_LL2, - "roce ll2 rx complete: bus_addr=%p, len=%d, data_len_err=%d\n", - (void *)(uintptr_t)rx_buf_addr, - data_length, data_length_error); - - memset(&pkt, 0, sizeof(pkt)); - pkt.n_seg = 1; - pkt.payload[0].baddr = rx_buf_addr; - pkt.payload[0].len = data_length; - - memset(¶ms, 0, sizeof(params)); - params.vlan_id = vlan; - *((u32 *)¶ms.smac[0]) = ntohl(src_mac_addr_hi); - *((u16 *)¶ms.smac[4]) = ntohs(src_mac_addr_lo); - - if (data_length_error) { - DP_ERR(cdev, - "roce ll2 rx complete: data length error %d, length=%d\n", - data_length_error, data_length); - params.rc = -EINVAL; - } - - roce_ll2->cbs.rx_cb(roce_ll2->cb_cookie, &pkt, ¶ms); -} - static int qed_roce_ll2_set_mac_filter(struct qed_dev *cdev, u8 *old_mac_address, u8 *new_mac_address) { - struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); struct qed_ptt *p_ptt; int rc = 0; - if (!hwfn->ll2 || hwfn->ll2->handle == QED_LL2_UNUSED_HANDLE) { - DP_ERR(cdev, - "qed roce mac filter failed - roce_info/ll2 NULL\n"); - return -EINVAL; - } - - p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); + p_ptt = qed_ptt_acquire(p_hwfn); if (!p_ptt) { DP_ERR(cdev, "qed roce ll2 mac filter set: failed to acquire PTT\n"); return -EINVAL; } - mutex_lock(&hwfn->ll2->lock); if (old_mac_address) - qed_llh_remove_mac_filter(QED_LEADING_HWFN(cdev), p_ptt, - old_mac_address); + qed_llh_remove_mac_filter(p_hwfn, p_ptt, old_mac_address); if (new_mac_address) - rc = qed_llh_add_mac_filter(QED_LEADING_HWFN(cdev), p_ptt, - new_mac_address); - mutex_unlock(&hwfn->ll2->lock); - - qed_ptt_release(QED_LEADING_HWFN(cdev), p_ptt); - - if (rc) - DP_ERR(cdev, - "qed roce ll2 mac filter set: failed to add mac filter\n"); - - return rc; -} - -static int qed_roce_ll2_start(struct qed_dev *cdev, - struct qed_roce_ll2_params *params) -{ - struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); - struct qed_roce_ll2_info *roce_ll2; - struct qed_ll2_acquire_data data; - int rc; - - if (!params) { - DP_ERR(cdev, "qed roce ll2 start: failed due to NULL params\n"); - return -EINVAL; - } - if (!params->cbs.tx_cb || !params->cbs.rx_cb) { - DP_ERR(cdev, - "qed roce ll2 start: failed due to NULL tx/rx. tx_cb=%p, rx_cb=%p\n", - params->cbs.tx_cb, params->cbs.rx_cb); - return -EINVAL; - } - if (!is_valid_ether_addr(params->mac_address)) { - DP_ERR(cdev, - "qed roce ll2 start: failed due to invalid Ethernet address %pM\n", - params->mac_address); - return -EINVAL; - } - - /* Initialize */ - roce_ll2 = kzalloc(sizeof(*roce_ll2), GFP_ATOMIC); - if (!roce_ll2) { - DP_ERR(cdev, "qed roce ll2 start: failed memory allocation\n"); - return -ENOMEM; - } + rc = qed_llh_add_mac_filter(p_hwfn, p_ptt, new_mac_address); - roce_ll2->handle = QED_LL2_UNUSED_HANDLE; - roce_ll2->cbs = params->cbs; - roce_ll2->cb_cookie = params->cb_cookie; - mutex_init(&roce_ll2->lock); - - memset(&data, 0, sizeof(data)); - data.input.conn_type = QED_LL2_TYPE_ROCE; - data.input.mtu = params->mtu; - data.input.rx_num_desc = params->max_rx_buffers; - data.input.tx_num_desc = params->max_tx_buffers; - data.input.rx_drop_ttl0_flg = true; - data.input.rx_vlan_removal_en = false; - data.input.tx_dest = QED_LL2_TX_DEST_NW; - data.input.ai_err_packet_too_big = LL2_DROP_PACKET; - data.input.ai_err_no_buf = LL2_DROP_PACKET; - data.p_connection_handle = &roce_ll2->handle; - data.input.gsi_enable = true; - - rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &data); - if (rc) { - DP_ERR(cdev, - "qed roce ll2 start: failed to acquire LL2 connection (rc=%d)\n", - rc); - goto err; - } - - rc = qed_ll2_establish_connection(QED_LEADING_HWFN(cdev), - roce_ll2->handle); - if (rc) { - DP_ERR(cdev, - "qed roce ll2 start: failed to establish LL2 connection (rc=%d)\n", - rc); - goto err1; - } - - hwfn->ll2 = roce_ll2; - - rc = qed_roce_ll2_set_mac_filter(cdev, NULL, params->mac_address); - if (rc) { - hwfn->ll2 = NULL; - goto err2; - } - ether_addr_copy(roce_ll2->mac_address, params->mac_address); - - return 0; - -err2: - qed_ll2_terminate_connection(QED_LEADING_HWFN(cdev), roce_ll2->handle); -err1: - qed_ll2_release_connection(QED_LEADING_HWFN(cdev), roce_ll2->handle); -err: - kfree(roce_ll2); - return rc; -} - -static int qed_roce_ll2_stop(struct qed_dev *cdev) -{ - struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); - struct qed_roce_ll2_info *roce_ll2 = hwfn->ll2; - int rc; - - if (roce_ll2->handle == QED_LL2_UNUSED_HANDLE) { - DP_ERR(cdev, "qed roce ll2 stop: cannot stop an unused LL2\n"); - return -EINVAL; - } - - /* remove LL2 MAC address filter */ - rc = qed_roce_ll2_set_mac_filter(cdev, roce_ll2->mac_address, NULL); - eth_zero_addr(roce_ll2->mac_address); + qed_ptt_release(p_hwfn, p_ptt); - rc = qed_ll2_terminate_connection(QED_LEADING_HWFN(cdev), - roce_ll2->handle); if (rc) DP_ERR(cdev, - "qed roce ll2 stop: failed to terminate LL2 connection (rc=%d)\n", - rc); - - qed_ll2_release_connection(QED_LEADING_HWFN(cdev), roce_ll2->handle); - - roce_ll2->handle = QED_LL2_UNUSED_HANDLE; - - kfree(roce_ll2); + "qed roce ll2 mac filter set: failed to add MAC filter\n"); return rc; } -static int qed_roce_ll2_tx(struct qed_dev *cdev, - struct qed_roce_ll2_packet *pkt, - struct qed_roce_ll2_tx_params *params) -{ - struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); - struct qed_roce_ll2_info *roce_ll2 = hwfn->ll2; - enum qed_ll2_roce_flavor_type qed_roce_flavor; - struct qed_ll2_tx_pkt_info ll2_pkt; - u8 flags = 0; - int rc; - int i; - - if (!pkt || !params) { - DP_ERR(cdev, - "roce ll2 tx: failed tx because one of the following is NULL - drv=%p, pkt=%p, params=%p\n", - cdev, pkt, params); - return -EINVAL; - } - - qed_roce_flavor = (pkt->roce_mode == ROCE_V1) ? QED_LL2_ROCE - : QED_LL2_RROCE; - - if (pkt->roce_mode == ROCE_V2_IPV4) - flags |= BIT(CORE_TX_BD_DATA_IP_CSUM_SHIFT); - - /* Tx header */ - memset(&ll2_pkt, 0, sizeof(ll2_pkt)); - ll2_pkt.num_of_bds = 1 + pkt->n_seg; - ll2_pkt.bd_flags = flags; - ll2_pkt.tx_dest = QED_LL2_TX_DEST_NW; - ll2_pkt.qed_roce_flavor = qed_roce_flavor; - ll2_pkt.first_frag = pkt->header.baddr; - ll2_pkt.first_frag_len = pkt->header.len; - ll2_pkt.cookie = pkt; - - rc = qed_ll2_prepare_tx_packet(QED_LEADING_HWFN(cdev), - roce_ll2->handle, - &ll2_pkt, 1); - if (rc) { - DP_ERR(cdev, "roce ll2 tx: header failed (rc=%d)\n", rc); - return QED_ROCE_TX_HEAD_FAILURE; - } - - /* Tx payload */ - for (i = 0; i < pkt->n_seg; i++) { - rc = qed_ll2_set_fragment_of_tx_packet(QED_LEADING_HWFN(cdev), - roce_ll2->handle, - pkt->payload[i].baddr, - pkt->payload[i].len); - if (rc) { - /* If failed not much to do here, partial packet has - * been posted * we can't free memory, will need to wait - * for completion - */ - DP_ERR(cdev, - "roce ll2 tx: payload failed (rc=%d)\n", rc); - return QED_ROCE_TX_FRAG_FAILURE; - } - } - - return 0; -} - -static int qed_roce_ll2_post_rx_buffer(struct qed_dev *cdev, - struct qed_roce_ll2_buffer *buf, - u64 cookie, u8 notify_fw) -{ - return qed_ll2_post_rx_buffer(QED_LEADING_HWFN(cdev), - QED_LEADING_HWFN(cdev)->ll2->handle, - buf->baddr, buf->len, - (void *)(uintptr_t)cookie, notify_fw); -} - -static int qed_roce_ll2_stats(struct qed_dev *cdev, struct qed_ll2_stats *stats) -{ - struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); - struct qed_roce_ll2_info *roce_ll2 = hwfn->ll2; - - return qed_ll2_get_stats(QED_LEADING_HWFN(cdev), - roce_ll2->handle, stats); -} - static const struct qed_rdma_ops qed_rdma_ops_pass = { .common = &qed_common_ops_pass, .fill_dev_info = &qed_fill_rdma_dev_info, @@ -3040,12 +2765,15 @@ static const struct qed_rdma_ops qed_rdma_ops_pass = { .rdma_free_tid = &qed_rdma_free_tid, .rdma_register_tid = &qed_rdma_register_tid, .rdma_deregister_tid = &qed_rdma_deregister_tid, - .roce_ll2_start = &qed_roce_ll2_start, - .roce_ll2_stop = &qed_roce_ll2_stop, - .roce_ll2_tx = &qed_roce_ll2_tx, - .roce_ll2_post_rx_buffer = &qed_roce_ll2_post_rx_buffer, - .roce_ll2_set_mac_filter = &qed_roce_ll2_set_mac_filter, - .roce_ll2_stats = &qed_roce_ll2_stats, + .ll2_acquire_connection = &qed_ll2_acquire_connection, + .ll2_establish_connection = &qed_ll2_establish_connection, + .ll2_terminate_connection = &qed_ll2_terminate_connection, + .ll2_release_connection = &qed_ll2_release_connection, + .ll2_post_rx_buffer = &qed_ll2_post_rx_buffer, + .ll2_prepare_tx_packet = &qed_ll2_prepare_tx_packet, + .ll2_set_fragment_of_tx_packet = &qed_ll2_set_fragment_of_tx_packet, + .ll2_set_mac_filter = &qed_roce_ll2_set_mac_filter, + .ll2_get_stats = &qed_ll2_get_stats, }; const struct qed_rdma_ops *qed_get_rdma_ops(void) diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.h b/drivers/net/ethernet/qlogic/qed/qed_roce.h index 9742af516183..94be3b5a39c4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.h +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.h @@ -170,53 +170,10 @@ struct qed_rdma_qp { void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); void qed_roce_async_event(struct qed_hwfn *p_hwfn, u8 fw_event_code, union rdma_eqe_data *rdma_data); -void qed_ll2b_complete_tx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t first_frag_addr, - bool b_last_fragment, bool b_last_packet); -void qed_ll2b_release_tx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t first_frag_addr, - bool b_last_fragment, bool b_last_packet); -void qed_ll2b_complete_rx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t rx_buf_addr, - u16 data_length, - u8 data_length_error, - u16 parse_flags, - u16 vlan, - u32 src_mac_addr_hi, - u16 src_mac_addr_lo, bool b_last_packet); #else static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} static inline void qed_roce_async_event(struct qed_hwfn *p_hwfn, u8 fw_event_code, union rdma_eqe_data *rdma_data) {} -static inline void qed_ll2b_complete_tx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t first_frag_addr, - bool b_last_fragment, - bool b_last_packet) {} -static inline void qed_ll2b_release_tx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t first_frag_addr, - bool b_last_fragment, - bool b_last_packet) {} -static inline void qed_ll2b_complete_rx_gsi_packet(struct qed_hwfn *p_hwfn, - u8 connection_handle, - void *cookie, - dma_addr_t rx_buf_addr, - u16 data_length, - u8 data_length_error, - u16 parse_flags, - u16 vlan, - u32 src_mac_addr_hi, - u16 src_mac_addr_lo, - bool b_last_packet) {} #endif #endif -- cgit v1.2.3 From d2201a21598aa6ad47e23272119bc29e48201670 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 9 Jun 2017 17:13:23 +0300 Subject: qed: No need for LL2 frags indication This is a legacy leftover; There's no current flow where 'frags_mapped' would be set. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index b222b2b471e8..2a68fb9d8299 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -73,7 +73,6 @@ struct qed_cb_ll2_info { int rx_cnt; u32 rx_size; u8 handle; - bool frags_mapped; /* Lock protecting LL2 buffer lists in sleepless context */ spinlock_t lock; @@ -108,12 +107,6 @@ static void qed_ll2b_complete_tx_packet(void *cxt, cdev->ll2->cbs->tx_cb(cdev->ll2->cb_cookie, skb, b_last_fragment); - if (cdev->ll2->frags_mapped) - /* Case where mapped frags were received, need to - * free skb with nr_frags marked as 0 - */ - skb_shinfo(skb)->nr_frags = 0; - dev_kfree_skb_any(skb); } @@ -2100,7 +2093,6 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) spin_lock_init(&cdev->ll2->lock); cdev->ll2->rx_size = NET_SKB_PAD + ETH_HLEN + L1_CACHE_BYTES + params->mtu; - cdev->ll2->frags_mapped = params->frags_mapped; /*Allocate memory for LL2 */ DP_INFO(cdev, "Allocating LL2 buffers of size %08x bytes\n", @@ -2313,21 +2305,14 @@ static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb) for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { frag = &skb_shinfo(skb)->frags[i]; - if (!cdev->ll2->frags_mapped) { - mapping = skb_frag_dma_map(&cdev->pdev->dev, frag, 0, - skb_frag_size(frag), - DMA_TO_DEVICE); - - if (unlikely(dma_mapping_error(&cdev->pdev->dev, - mapping))) { - DP_NOTICE(cdev, - "Unable to map frag - dropping packet\n"); - rc = -ENOMEM; - goto err; - } - } else { - mapping = page_to_phys(skb_frag_page(frag)) | - frag->page_offset; + + mapping = skb_frag_dma_map(&cdev->pdev->dev, frag, 0, + skb_frag_size(frag), DMA_TO_DEVICE); + + if (unlikely(dma_mapping_error(&cdev->pdev->dev, mapping))) { + DP_NOTICE(cdev, + "Unable to map frag - dropping packet\n"); + goto err; } rc = qed_ll2_set_fragment_of_tx_packet(QED_LEADING_HWFN(cdev), -- cgit v1.2.3 From 54f19f07acb6f9a0e90a183a2fb347ed3856b154 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 9 Jun 2017 17:13:24 +0300 Subject: qed: Call rx_release_cb() when flushing LL2 Driver to inform the connection owner that the its buffers are being released as part of a flush. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 2a68fb9d8299..c6172a77e97d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -525,10 +525,6 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) p_rx = &p_ll2_conn->rx_queue; while (!list_empty(&p_rx->active_descq)) { - dma_addr_t rx_buf_addr; - void *cookie; - bool b_last; - p_pkt = list_first_entry(&p_rx->active_descq, struct qed_ll2_rx_packet, list_entry); if (!p_pkt) @@ -543,10 +539,15 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info, p_buffer); } else { - rx_buf_addr = p_pkt->rx_buf_addr; - cookie = p_pkt->cookie; + dma_addr_t rx_buf_addr = p_pkt->rx_buf_addr; + void *cookie = p_pkt->cookie; + bool b_last; b_last = list_empty(&p_rx->active_descq); + p_ll2_conn->cbs.rx_release_cb(p_ll2_conn->cbs.cookie, + p_ll2_conn->my_id, + cookie, + rx_buf_addr, b_last); } } } -- cgit v1.2.3 From fef1c3f7ac119217f49c72d4cc5413b4c87c1774 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 9 Jun 2017 17:13:25 +0300 Subject: qed: collect GSI port statistics The LL2 statistics already have place holders for these, but haven't populated them so far. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index c6172a77e97d..0e26193156e4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -1902,6 +1902,27 @@ void qed_ll2_free(struct qed_hwfn *p_hwfn) p_hwfn->p_ll2_info = NULL; } +static void _qed_ll2_get_port_stats(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_ll2_stats *p_stats) +{ + struct core_ll2_port_stats port_stats; + + memset(&port_stats, 0, sizeof(port_stats)); + qed_memcpy_from(p_hwfn, p_ptt, &port_stats, + BAR0_MAP_REG_TSDM_RAM + + TSTORM_LL2_PORT_STAT_OFFSET(MFW_PORT(p_hwfn)), + sizeof(port_stats)); + + p_stats->gsi_invalid_hdr = HILO_64_REGPAIR(port_stats.gsi_invalid_hdr); + p_stats->gsi_invalid_pkt_length = + HILO_64_REGPAIR(port_stats.gsi_invalid_pkt_length); + p_stats->gsi_unsupported_pkt_typ = + HILO_64_REGPAIR(port_stats.gsi_unsupported_pkt_typ); + p_stats->gsi_crcchksm_error = + HILO_64_REGPAIR(port_stats.gsi_crcchksm_error); +} + static void _qed_ll2_get_tstats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_ll2_info *p_ll2_conn, @@ -1986,6 +2007,8 @@ int qed_ll2_get_stats(void *cxt, return -EINVAL; } + if (p_ll2_conn->input.gsi_enable) + _qed_ll2_get_port_stats(p_hwfn, p_ptt, p_stats); _qed_ll2_get_tstats(p_hwfn, p_ptt, p_ll2_conn, p_stats); _qed_ll2_get_ustats(p_hwfn, p_ptt, p_ll2_conn, p_stats); if (p_ll2_conn->tx_stats_en) -- cgit v1.2.3 From 2f3ca449a4f9a54d2bf39c873269e68ad5f34acb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Jun 2017 12:37:35 +0200 Subject: qed: add qed_int_sb_init() stub function When CONFIG_QED_SRIOV is disabled, we get a build error: drivers/net/ethernet/qlogic/qed/qed_int.c: In function 'qed_int_sb_init': drivers/net/ethernet/qlogic/qed/qed_int.c:1499:4: error: implicit declaration of function 'qed_vf_set_sb_info'; did you mean 'qed_mcp_get_resc_info'? [-Werror=implicit-function-declaration] All the other declarations have a 'static inline' stub as an alternative here, so this adds one more for qed_int_sb_init. Fixes: 50a207147fce ("qed: Hold a single array for SBs") Signed-off-by: Arnd Bergmann Acked-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_vf.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index b65bbc54a097..34d9b882a780 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h @@ -1105,6 +1105,11 @@ static inline u16 qed_vf_get_igu_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id) return 0; } +static inline void qed_vf_set_sb_info(struct qed_hwfn *p_hwfn, u16 sb_id, + struct qed_sb_info *p_sb) +{ +} + static inline int qed_vf_pf_vport_start(struct qed_hwfn *p_hwfn, u8 vport_id, u16 mtu, -- cgit v1.2.3 From d0417849152cb5ae08407bcc32b85b55b5b9f591 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Fri, 9 Jun 2017 19:26:24 +0530 Subject: cxgb4: fix memory leak in init_one() Free up mbox_log allocated for PF0 to PF3. Fixes: 7829451c695e ("cxgb4: Add control net_device for configuring PCIe VF") Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index ff8bcf56bf3f..01c9710fc62e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -5169,13 +5169,15 @@ sriov: &v, &port_vec); if (err < 0) { dev_err(adapter->pdev_dev, "Could not fetch port params\n"); - goto free_adapter; + goto free_mbox_log; } adapter->params.nports = hweight32(port_vec); pci_set_drvdata(pdev, adapter); return 0; +free_mbox_log: + kfree(adapter->mbox_log); free_adapter: kfree(adapter); free_pci_region: @@ -5275,6 +5277,7 @@ static void remove_one(struct pci_dev *pdev) unregister_netdev(adapter->port[0]); iounmap(adapter->regs); kfree(adapter->vfinfo); + kfree(adapter->mbox_log); kfree(adapter); pci_disable_sriov(pdev); pci_release_regions(pdev); @@ -5321,6 +5324,7 @@ static void shutdown_one(struct pci_dev *pdev) unregister_netdev(adapter->port[0]); iounmap(adapter->regs); kfree(adapter->vfinfo); + kfree(adapter->mbox_log); kfree(adapter); pci_disable_sriov(pdev); pci_release_regions(pdev); -- cgit v1.2.3 From cd99c3776351e1b90ac05ff527553f8a29c03583 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 9 Jun 2017 17:58:08 +0200 Subject: bonding: warn user when 802.3ad speed is unknown Goal is to advertise the user when ethtool speeds and 802.3ad speeds are desynchronized. When this case happens, the kernel needs to be patched. Suggested-by: Andrew Lunn Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index b44a6aeb346d..165a8009c640 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -322,6 +322,11 @@ static u16 __get_link_speed(struct port *port) default: /* unknown speed value from ethtool. shouldn't happen */ + if (slave->speed != SPEED_UNKNOWN) + pr_warn_once("%s: unknown ethtool speed (%d) for port %d (set it to 0)\n", + slave->bond->dev->name, + slave->speed, + port->actor_port_number); speed = 0; break; } -- cgit v1.2.3 From 41e8e40458a417bbbabfbec5362b8747601e6a3a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 9 Jun 2017 22:37:22 -0300 Subject: net: fec: Add a fec_enet_clear_ethtool_stats() stub for CONFIG_M5272 Commit 2b30842b23b9 ("net: fec: Clear and enable MIB counters on imx51") introduced fec_enet_clear_ethtool_stats(), but missed to add a stub for the CONFIG_M5272=y case, causing build failure for the m5272c3_defconfig. Add the missing empty stub to fix the build failure. Fixes: Commit 2b30842b23b9 ("net: fec: Clear and enable MIB counters on imx51") Reported-by: Paul Gortmaker Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 297fd196c879..a6e323f15637 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2379,6 +2379,10 @@ static void fec_enet_clear_ethtool_stats(struct net_device *dev) static inline void fec_enet_update_ethtool_stats(struct net_device *dev) { } + +static inline void fec_enet_clear_ethtool_stats(struct net_device *dev) +{ +} #endif /* !defined(CONFIG_M5272) */ /* ITR clock source is enet system clock (clk_ahb). -- cgit v1.2.3 From e9523a5a32a1ce3acfe875cddd8ac8ad8a9ed270 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 8 Jun 2017 13:51:31 -0500 Subject: net: ethernet: ti: cpsw: enable HWTSTAMP_FILTER_PTP_V1_L4_EVENT filter CPSW driver supports PTP v1 messages, but for unknown reasons this filter is not advertised. As result, ./tools/testing/selftests/networking/timestamping/timestamping utility can't be used for testing of CPSW RX timestamping with option SOF_TIMESTAMPING_RX_HARDWARE, because it uses HWTSTAMP_FILTER_PTP_V1_L4_SYNC filter. Hence, fix it by advertising HWTSTAMP_FILTER_PTP_V1_L4_XXX filters in CPSW driver. Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 37fc16521143..b6a0d92dd637 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1731,11 +1731,14 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) cpts_rx_enable(cpts, 0); break; case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_NTP_ALL: + return -ERANGE; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: - case HWTSTAMP_FILTER_NTP_ALL: - return -ERANGE; + cpts_rx_enable(cpts, HWTSTAMP_FILTER_PTP_V1_L4_EVENT); + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + break; case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: @@ -1745,7 +1748,7 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - cpts_rx_enable(cpts, 1); + cpts_rx_enable(cpts, HWTSTAMP_FILTER_PTP_V2_EVENT); cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; default: @@ -1784,7 +1787,7 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) cfg.tx_type = cpts_is_tx_enabled(cpts) ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; cfg.rx_filter = (cpts_is_rx_enabled(cpts) ? - HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE); + cpts->rx_enable : HWTSTAMP_FILTER_NONE); return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } @@ -2141,6 +2144,7 @@ static int cpsw_get_ts_info(struct net_device *ndev, (1 << HWTSTAMP_TX_ON); info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); return 0; } -- cgit v1.2.3 From 6d307f6b099cbe828cd7595408caebce3088c8f3 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 8 Jun 2017 13:51:52 -0500 Subject: net: ethernet: ti: cpdma: do not enable host error misc irq CPSW driver does not handle this interrupt, so there are no reasons to enable it in hardware. Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_cpdma.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index 7ecc6b70e7e8..e4d6edf387b3 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -645,7 +645,7 @@ EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy); int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable) { unsigned long flags; - int i, reg; + int i; spin_lock_irqsave(&ctlr->lock, flags); if (ctlr->state != CPDMA_STATE_ACTIVE) { @@ -653,9 +653,6 @@ int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable) return -EINVAL; } - reg = enable ? CPDMA_DMAINTMASKSET : CPDMA_DMAINTMASKCLEAR; - dma_reg_write(ctlr, reg, CPDMA_DMAINT_HOSTERR); - for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) { if (ctlr->channels[i]) cpdma_chan_int_ctrl(ctlr->channels[i], enable); -- cgit v1.2.3 From 4284ecbeda81083f4c7a3ce325b4a9d675657e61 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 10 Jun 2017 14:33:16 +0200 Subject: Bluetooth: btbcm: Read controller features during configuration Read the Broadcom specific controller features during configuration and print them for informational purposes. < HCI Command: Broadcom Read Controller Features (0x3f|0x006e) plen 0 > HCI Event: Command Complete (0x0e) plen 12 Broadcom Read Controller Features (0x3f|0x006e) ncmd 1 Status: Success (0x00) Features: 0x07 0x00 0x00 0x00 0x00 0x00 0x00 0x00 Multi-AV transport bandwidth reducer WBS SBC FW LC-PLC Signed-off-by: Marcel Holtmann Signed-off-by: Szymon Janc --- drivers/bluetooth/btbcm.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index ba3dd2eafc09..24f8c4e93f4e 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -246,6 +246,27 @@ static struct sk_buff *btbcm_read_verbose_config(struct hci_dev *hdev) return skb; } +static struct sk_buff *btbcm_read_controller_features(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, 0xfc6e, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: BCM: Read controller features failed (%ld)", + hdev->name, PTR_ERR(skb)); + return skb; + } + + if (skb->len != 9) { + BT_ERR("%s: BCM: Controller features length mismatch", + hdev->name); + kfree_skb(skb); + return ERR_PTR(-EIO); + } + + return skb; +} + static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev) { struct sk_buff *skb; @@ -417,6 +438,14 @@ int btbcm_setup_patchram(struct hci_dev *hdev) BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]); kfree_skb(skb); + /* Read Controller Features */ + skb = btbcm_read_controller_features(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + BT_INFO("%s: BCM: features 0x%2.2x", hdev->name, skb->data[1]); + kfree_skb(skb); + /* Read Local Name */ skb = btbcm_read_local_name(hdev); if (IS_ERR(skb)) @@ -540,6 +569,13 @@ int btbcm_setup_apple(struct hci_dev *hdev) kfree_skb(skb); } + /* Read Controller Features */ + skb = btbcm_read_controller_features(hdev); + if (!IS_ERR(skb)) { + BT_INFO("%s: BCM: features 0x%2.2x", hdev->name, skb->data[1]); + kfree_skb(skb); + } + /* Read Local Name */ skb = btbcm_read_local_name(hdev); if (!IS_ERR(skb)) { -- cgit v1.2.3 From 78d6102256fe46fcd0c78798a9391cf1f112f117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Mon, 12 Jun 2017 10:39:03 +0200 Subject: sh_eth: add support for changing MTU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardware supports the MTU to be changed and the driver it self is somewhat prepared to support this. This patch hooks up the callbacks to be able to change the MTU from user-space. Signed-off-by: Niklas Söderlund Acked-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 2d686ccf971b..48b66df88294 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -2558,6 +2558,17 @@ static int sh_eth_do_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) return phy_mii_ioctl(phydev, rq, cmd); } +static int sh_eth_change_mtu(struct net_device *ndev, int new_mtu) +{ + if (netif_running(ndev)) + return -EBUSY; + + ndev->mtu = new_mtu; + netdev_update_features(ndev); + + return 0; +} + /* For TSU_POSTn. Please refer to the manual about this (strange) bitfields */ static void *sh_eth_tsu_get_post_reg_offset(struct sh_eth_private *mdp, int entry) @@ -3029,6 +3040,7 @@ static const struct net_device_ops sh_eth_netdev_ops = { .ndo_set_rx_mode = sh_eth_set_rx_mode, .ndo_tx_timeout = sh_eth_tx_timeout, .ndo_do_ioctl = sh_eth_do_ioctl, + .ndo_change_mtu = sh_eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, }; @@ -3043,6 +3055,7 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = { .ndo_vlan_rx_kill_vid = sh_eth_vlan_rx_kill_vid, .ndo_tx_timeout = sh_eth_tx_timeout, .ndo_do_ioctl = sh_eth_do_ioctl, + .ndo_change_mtu = sh_eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, }; @@ -3171,6 +3184,13 @@ static int sh_eth_drv_probe(struct platform_device *pdev) } sh_eth_set_default_cpu_data(mdp->cd); + /* User's manual states max MTU should be 2048 but due to the + * alignment calculations in sh_eth_ring_init() the practical + * MTU is a bit less. Maybe this can be optimized some more. + */ + ndev->max_mtu = 2000 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); + ndev->min_mtu = ETH_MIN_MTU; + /* set function */ if (mdp->cd->tsu) ndev->netdev_ops = &sh_eth_netdev_ops_tsu; -- cgit v1.2.3 From e0090a9e979de5202c7d16c635dea2f005221073 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sun, 11 Jun 2017 16:32:50 -0700 Subject: vxlan: dont migrate permanent fdb entries during learn This patch fixes vxlan_snoop to not move permanent fdb entries on learn events. This is consistent with the bridge fdb handling of permanent entries. Fixes: 26a41ae60438 ("vxlan: only migrate dynamic FDB entries") Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 7cb21a088bbc..e045c34ffbeb 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -970,7 +970,7 @@ static bool vxlan_snoop(struct net_device *dev, return false; /* Don't migrate static entries, drop packets */ - if (f->state & NUD_NOARP) + if (f->state & (NUD_PERMANENT | NUD_NOARP)) return true; if (net_ratelimit()) -- cgit v1.2.3 From a1fa1a00b31c9155501d81f5396b2f6d76871fbe Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Mon, 12 Jun 2017 14:54:57 +0200 Subject: net: phy: marvell: Show complete link partner advertising Give back all modes advertised by the link partner. This change brings the marvell phy driver in line with all other phy drivers. Signed-off-by: Thomas Bogendoerfer Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 4c5246fed69b..8400403b3f62 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1139,7 +1139,6 @@ static int marvell_read_status_page_an(struct phy_device *phydev, int status; int lpa; int lpagb; - int adv; status = phy_read(phydev, MII_M1011_PHY_STATUS); if (status < 0) @@ -1153,12 +1152,6 @@ static int marvell_read_status_page_an(struct phy_device *phydev, if (lpagb < 0) return lpagb; - adv = phy_read(phydev, MII_ADVERTISE); - if (adv < 0) - return adv; - - lpa &= adv; - if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) phydev->duplex = DUPLEX_FULL; else -- cgit v1.2.3 From efc2c1fa8e145b60a7805fa9b6c92ac0746fccc3 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Fri, 9 Jun 2017 12:19:20 +0100 Subject: brcmfmac: add support multi-scheduled scan This change adds support for multi-scheduled scan in the driver. It currently relies on g-scan support in firmware and will set struct wiphy::max_sched_scan_reqs accordingly. This is limited to 16 concurrent requests. The firmware currently has a limit of 64 channels that can be configured for all requests in total regardless whether there are duplicates. So if a request uses 35 channels there are 29 channels left for another request. When user-space does not specify any channels cfg80211 will add all channels defined by the wiphy instance to the request, which makes reaching the limit rather easy for dual-band devices. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 67 +++- .../broadcom/brcm80211/brcmfmac/cfg80211.h | 6 +- .../wireless/broadcom/brcm80211/brcmfmac/core.c | 1 + .../wireless/broadcom/brcm80211/brcmfmac/debug.h | 2 + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 32 +- .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 397 ++++++++++++++++++--- .../net/wireless/broadcom/brcm80211/brcmfmac/pno.h | 47 ++- 7 files changed, 463 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index a2bf11fc8ecc..b3180b152a2f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -719,6 +719,8 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, { struct brcmf_scan_params_le params_le; struct cfg80211_scan_request *scan_request; + u64 reqid; + u32 bucket; s32 err = 0; brcmf_dbg(SCAN, "Enter\n"); @@ -749,7 +751,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN, ¶ms_le, sizeof(params_le)); if (err) - brcmf_err("Scan abort failed\n"); + brcmf_err("Scan abort failed\n"); } brcmf_scan_config_mpc(ifp, 1); @@ -758,11 +760,21 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, * e-scan can be initiated internally * which takes precedence. */ - if (cfg->internal_escan) { - brcmf_dbg(SCAN, "scheduled scan completed\n"); - cfg->internal_escan = false; - if (!aborted) - cfg80211_sched_scan_results(cfg_to_wiphy(cfg), 0); + if (cfg->int_escan_map) { + brcmf_dbg(SCAN, "scheduled scan completed (%x)\n", + cfg->int_escan_map); + while (cfg->int_escan_map) { + bucket = __ffs(cfg->int_escan_map); + cfg->int_escan_map &= ~BIT(bucket); + reqid = brcmf_pno_find_reqid_by_bucket(cfg->pno, + bucket); + if (!aborted) { + brcmf_dbg(SCAN, "report results: reqid=%llu\n", + reqid); + cfg80211_sched_scan_results(cfg_to_wiphy(cfg), + reqid); + } + } } else if (scan_request) { struct cfg80211_scan_info info = { .aborted = aborted, @@ -1011,7 +1023,7 @@ static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg, if (!ssid_le.SSID_len) brcmf_dbg(SCAN, "%d: Broadcast scan\n", i); else - brcmf_dbg(SCAN, "%d: scan for %s size =%d\n", + brcmf_dbg(SCAN, "%d: scan for %.32s size=%d\n", i, ssid_le.SSID, ssid_le.SSID_len); memcpy(ptr, &ssid_le, sizeof(ssid_le)); ptr += sizeof(ssid_le); @@ -3011,7 +3023,7 @@ void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) struct escan_info *escan = &cfg->escan_info; set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status); - if (cfg->internal_escan || cfg->scan_request) { + if (cfg->int_escan_map || cfg->scan_request) { escan->escan_state = WL_ESCAN_STATE_IDLE; brcmf_notify_escan_complete(cfg, escan->ifp, true, true); } @@ -3034,7 +3046,7 @@ static void brcmf_escan_timeout(unsigned long data) struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)data; - if (cfg->internal_escan || cfg->scan_request) { + if (cfg->int_escan_map || cfg->scan_request) { brcmf_err("timer expired\n"); schedule_work(&cfg->escan_timeout_work); } @@ -3120,7 +3132,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le)) goto exit; - if (!cfg->internal_escan && !cfg->scan_request) { + if (!cfg->int_escan_map && !cfg->scan_request) { brcmf_dbg(SCAN, "result without cfg80211 request\n"); goto exit; } @@ -3166,7 +3178,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; if (brcmf_p2p_scan_finding_common_channel(cfg, NULL)) goto exit; - if (cfg->internal_escan || cfg->scan_request) { + if (cfg->int_escan_map || cfg->scan_request) { brcmf_inform_bss(cfg); aborted = status != BRCMF_E_STATUS_SUCCESS; brcmf_notify_escan_complete(cfg, ifp, aborted, false); @@ -3248,17 +3260,21 @@ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req, return 0; } -static int brcmf_start_internal_escan(struct brcmf_if *ifp, +static int brcmf_start_internal_escan(struct brcmf_if *ifp, u32 fwmap, struct cfg80211_scan_request *request) { struct brcmf_cfg80211_info *cfg = ifp->drvr->config; int err; if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { + if (cfg->int_escan_map) + brcmf_dbg(SCAN, "aborting internal scan: map=%u\n", + cfg->int_escan_map); /* Abort any on-going scan */ brcmf_abort_scanning(cfg); } + brcmf_dbg(SCAN, "start internal scan: map=%u\n", fwmap); set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); cfg->escan_info.run = brcmf_run_escan; err = brcmf_do_escan(ifp, request); @@ -3266,7 +3282,7 @@ static int brcmf_start_internal_escan(struct brcmf_if *ifp, clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); return err; } - cfg->internal_escan = true; + cfg->int_escan_map = fwmap; return 0; } @@ -3308,6 +3324,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, struct wiphy *wiphy = cfg_to_wiphy(cfg); int i, err = 0; struct brcmf_pno_scanresults_le *pfn_result; + u32 bucket_map; u32 result_count; u32 status; u32 datalen; @@ -3352,6 +3369,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, goto out_err; } + bucket_map = 0; for (i = 0; i < result_count; i++) { netinfo = &netinfo_start[i]; @@ -3359,6 +3377,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, netinfo->SSID_len = IEEE80211_MAX_SSID_LEN; brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n", netinfo->SSID, netinfo->channel); + bucket_map |= brcmf_pno_get_bucket_map(cfg->pno, netinfo); err = brcmf_internal_escan_add_info(request, netinfo->SSID, netinfo->SSID_len, @@ -3367,7 +3386,10 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, goto out_err; } - err = brcmf_start_internal_escan(ifp, request); + if (!bucket_map) + goto free_req; + + err = brcmf_start_internal_escan(ifp, bucket_map, request); if (!err) goto free_req; @@ -3386,11 +3408,11 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); - brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n", + brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n", req->n_match_sets, req->n_ssids); if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) { - brcmf_err("Scanning suppressed: status (%lu)\n", + brcmf_err("Scanning suppressed: status=%lu\n", cfg->scan_status); return -EAGAIN; } @@ -3411,8 +3433,8 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct brcmf_if *ifp = netdev_priv(ndev); brcmf_dbg(SCAN, "enter\n"); - brcmf_pno_clean(ifp); - if (cfg->internal_escan) + brcmf_pno_stop_sched_scan(ifp, reqid); + if (cfg->int_escan_map) brcmf_notify_escan_complete(cfg, ifp, true, true); return 0; } @@ -6941,6 +6963,13 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, brcmf_p2p_detach(&cfg->p2p); goto wiphy_unreg_out; } + err = brcmf_pno_attach(cfg); + if (err) { + brcmf_err("PNO initialisation failed (%d)\n", err); + brcmf_btcoex_detach(cfg); + brcmf_p2p_detach(&cfg->p2p); + goto wiphy_unreg_out; + } if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_TDLS)) { err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1); @@ -6973,6 +7002,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, return cfg; detach: + brcmf_pno_detach(cfg); brcmf_btcoex_detach(cfg); brcmf_p2p_detach(&cfg->p2p); wiphy_unreg_out: @@ -6992,6 +7022,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) if (!cfg) return; + brcmf_pno_detach(cfg); brcmf_btcoex_detach(cfg); wiphy_unregister(cfg->wiphy); kfree(cfg->ops); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index a1c2e0af1774..12ff15446c6c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -273,7 +273,7 @@ struct brcmf_cfg80211_wowl { * @pub: common driver information. * @channel: current channel. * @active_scan: current scan mode. - * @internal_escan: indicates internally initiated e-scan is running. + * @int_escan_map: bucket map for which internal e-scan is done. * @ibss_starter: indicates this sta is ibss starter. * @pwr_save: indicate whether dongle to support power save mode. * @dongle_up: indicate whether dongle up or not. @@ -289,6 +289,7 @@ struct brcmf_cfg80211_wowl { * @vif_cnt: number of vif instances. * @vif_event: vif event signalling. * @wowl: wowl related information. + * @pno: information of pno module. */ struct brcmf_cfg80211_info { struct wiphy *wiphy; @@ -305,7 +306,7 @@ struct brcmf_cfg80211_info { struct brcmf_pub *pub; u32 channel; bool active_scan; - bool internal_escan; + u32 int_escan_map; bool ibss_starter; bool pwr_save; bool dongle_up; @@ -322,6 +323,7 @@ struct brcmf_cfg80211_info { struct brcmu_d11inf d11inf; struct brcmf_assoclist_le assoclist; struct brcmf_cfg80211_wowl wowl; + struct brcmf_pno_info *pno; }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index a3d82368f1a9..a88da5ae66c2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -30,6 +30,7 @@ #include "debug.h" #include "fwil_types.h" #include "p2p.h" +#include "pno.h" #include "cfg80211.h" #include "fwil.h" #include "feature.h" diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h index fe264a5798f1..35919d9e8e13 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h @@ -78,6 +78,7 @@ do { \ #define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL) #define BRCMF_FIL_ON() (brcmf_msg_level & BRCMF_FIL_VAL) #define BRCMF_FWCON_ON() (brcmf_msg_level & BRCMF_FWCON_VAL) +#define BRCMF_SCAN_ON() (brcmf_msg_level & BRCMF_SCAN_VAL) #else /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */ @@ -96,6 +97,7 @@ do { \ #define BRCMF_EVENT_ON() 0 #define BRCMF_FIL_ON() 0 #define BRCMF_FWCON_ON() 0 +#define BRCMF_SCAN_ON() 0 #endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 8c18fad3edc9..45aaae85c97a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -835,15 +835,18 @@ struct brcmf_gtk_keyinfo_le { u8 replay_counter[BRCMF_RSN_REPLAY_LEN]; }; +#define BRCMF_PNO_REPORT_NO_BATCH BIT(2) + /** * struct brcmf_gscan_bucket_config - configuration data for channel bucket. * - * @bucket_end_index: !unknown! - * @bucket_freq_multiple: !unknown! - * @flag: !unknown! - * @reserved: !unknown! - * @repeat: !unknown! - * @max_freq_multiple: !unknown! + * @bucket_end_index: last channel index in @channel_list in + * @struct brcmf_pno_config_le. + * @bucket_freq_multiple: scan interval expressed in N * @scan_freq. + * @flag: channel bucket report flags. + * @reserved: for future use. + * @repeat: number of scan at interval for exponential scan. + * @max_freq_multiple: maximum scan interval for exponential scan. */ struct brcmf_gscan_bucket_config { u8 bucket_end_index; @@ -855,16 +858,19 @@ struct brcmf_gscan_bucket_config { }; /* version supported which must match firmware */ -#define BRCMF_GSCAN_CFG_VERSION 1 +#define BRCMF_GSCAN_CFG_VERSION 2 /** * enum brcmf_gscan_cfg_flags - bit values for gscan flags. * * @BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS: send probe responses/beacons to host. + * @BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN: all buckets will be included in + * first scan cycle. * @BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY: indicated only flags member is changed. */ enum brcmf_gscan_cfg_flags { BRCMF_GSCAN_CFG_FLAGS_ALL_RESULTS = BIT(0), + BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN = BIT(3), BRCMF_GSCAN_CFG_FLAGS_CHANGE_ONLY = BIT(7), }; @@ -884,12 +890,12 @@ enum brcmf_gscan_cfg_flags { */ struct brcmf_gscan_config { __le16 version; - u8 flags; - u8 buffer_threshold; - u8 swc_nbssid_threshold; - u8 swc_rssi_window_size; - u8 count_of_channel_buckets; - u8 retry_threshold; + u8 flags; + u8 buffer_threshold; + u8 swc_nbssid_threshold; + u8 swc_rssi_window_size; + u8 count_of_channel_buckets; + u8 retry_threshold; __le16 lost_ap_window; struct brcmf_gscan_bucket_config bucket[1]; }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c index a473445ed7c4..a4207754075b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -14,6 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include +#include #include #include "core.h" @@ -35,6 +36,58 @@ #define BRCMF_PNO_HIDDEN_BIT 2 #define BRCMF_PNO_SCHED_SCAN_PERIOD 30 +#define BRCMF_PNO_MAX_BUCKETS 16 +#define GSCAN_BATCH_NO_THR_SET 101 +#define GSCAN_RETRY_THRESHOLD 3 + +struct brcmf_pno_info { + int n_reqs; + struct cfg80211_sched_scan_request *reqs[BRCMF_PNO_MAX_BUCKETS]; +}; + +#define ifp_to_pno(_ifp) ((_ifp)->drvr->config->pno) + +static int brcmf_pno_store_request(struct brcmf_pno_info *pi, + struct cfg80211_sched_scan_request *req) +{ + if (WARN(pi->n_reqs == BRCMF_PNO_MAX_BUCKETS, + "pno request storage full\n")) + return -ENOSPC; + + brcmf_dbg(SCAN, "reqid=%llu\n", req->reqid); + pi->reqs[pi->n_reqs++] = req; + return 0; +} + +static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid) +{ + int i; + + /* find request */ + for (i = 0; i < pi->n_reqs; i++) { + if (pi->reqs[i]->reqid == reqid) + break; + } + /* request not found */ + if (WARN(i == pi->n_reqs, "reqid not found\n")) { + return -ENOENT; + } + + brcmf_dbg(SCAN, "reqid=%llu\n", reqid); + pi->n_reqs--; + + /* if last we are done */ + if (!pi->n_reqs || i == pi->n_reqs) + return 0; + + /* fill the gap with remaining requests */ + while (i <= pi->n_reqs - 1) { + pi->reqs[i] = pi->reqs[i + 1]; + i++; + } + return 0; +} + static int brcmf_pno_channel_config(struct brcmf_if *ifp, struct brcmf_pno_config_le *cfg) { @@ -63,10 +116,6 @@ static int brcmf_pno_config(struct brcmf_if *ifp, u32 scan_freq, pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; /* set up pno scan fr */ - if (scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) { - brcmf_dbg(SCAN, "scan period too small, using minimum\n"); - scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD; - } pfn_param.scan_freq = cpu_to_le32(scan_freq); if (mscan) { @@ -101,12 +150,24 @@ exit: return err; } -static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr, - u8 *mac_mask) +static int brcmf_pno_set_random(struct brcmf_if *ifp, struct brcmf_pno_info *pi) { struct brcmf_pno_macaddr_le pfn_mac; + u8 *mac_addr = NULL; + u8 *mac_mask = NULL; int err, i; + for (i = 0; i < pi->n_reqs; i++) + if (pi->reqs[i]->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + mac_addr = pi->reqs[i]->mac_addr; + mac_mask = pi->reqs[i]->mac_addr_mask; + break; + } + + /* no random mac requested */ + if (!mac_addr) + return 0; + pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC; @@ -120,6 +181,8 @@ static int brcmf_pno_set_random(struct brcmf_if *ifp, u8 *mac_addr, /* Set locally administered */ pfn_mac.mac[0] |= 0x02; + brcmf_dbg(SCAN, "enabling random mac: reqid=%llu mac=%pM\n", + pi->reqs[i]->reqid, pfn_mac.mac); err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac, sizeof(pfn_mac)); if (err) @@ -163,7 +226,7 @@ static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid, return false; } -int brcmf_pno_clean(struct brcmf_if *ifp) +static int brcmf_pno_clean(struct brcmf_if *ifp) { int ret; @@ -179,73 +242,307 @@ int brcmf_pno_clean(struct brcmf_if *ifp) return ret; } -int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, - struct cfg80211_sched_scan_request *req) +static int brcmf_pno_get_bucket_channels(struct cfg80211_sched_scan_request *r, + struct brcmf_pno_config_le *pno_cfg) { - struct brcmf_pno_config_le pno_cfg; - struct cfg80211_ssid *ssid; + u32 n_chan = le32_to_cpu(pno_cfg->channel_num); u16 chan; - int i, ret; + int i, err = 0; - /* clean up everything */ - ret = brcmf_pno_clean(ifp); - if (ret < 0) { - brcmf_err("failed error=%d\n", ret); - return ret; + for (i = 0; i < r->n_channels; i++) { + if (n_chan >= BRCMF_NUMCHANNELS) { + err = -ENOSPC; + goto done; + } + chan = r->channels[i]->hw_value; + brcmf_dbg(SCAN, "[%d] Chan : %u\n", n_chan, chan); + pno_cfg->channel_list[n_chan++] = cpu_to_le16(chan); } + /* return number of channels */ + err = n_chan; +done: + pno_cfg->channel_num = cpu_to_le32(n_chan); + return err; +} - /* configure pno */ - ret = brcmf_pno_config(ifp, req->scan_plans[0].interval, 0, 0); - if (ret < 0) - return ret; - - /* configure random mac */ - if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { - ret = brcmf_pno_set_random(ifp, req->mac_addr, - req->mac_addr_mask); - if (ret < 0) - return ret; +static int brcmf_pno_prep_fwconfig(struct brcmf_pno_info *pi, + struct brcmf_pno_config_le *pno_cfg, + struct brcmf_gscan_bucket_config **buckets, + u32 *scan_freq) +{ + struct cfg80211_sched_scan_request *sr; + struct brcmf_gscan_bucket_config *fw_buckets; + int i, err, chidx; + + brcmf_dbg(SCAN, "n_reqs=%d\n", pi->n_reqs); + if (WARN_ON(!pi->n_reqs)) + return -ENODATA; + + /* + * actual scan period is determined using gcd() for each + * scheduled scan period. + */ + *scan_freq = pi->reqs[0]->scan_plans[0].interval; + for (i = 1; i < pi->n_reqs; i++) { + sr = pi->reqs[i]; + *scan_freq = gcd(sr->scan_plans[0].interval, *scan_freq); + } + if (*scan_freq < BRCMF_PNO_SCHED_SCAN_MIN_PERIOD) { + brcmf_dbg(SCAN, "scan period too small, using minimum\n"); + *scan_freq = BRCMF_PNO_SCHED_SCAN_MIN_PERIOD; } - /* configure channels to use */ - for (i = 0; i < req->n_channels; i++) { - chan = req->channels[i]->hw_value; - pno_cfg.channel_list[i] = cpu_to_le16(chan); + *buckets = NULL; + fw_buckets = kcalloc(pi->n_reqs, sizeof(*fw_buckets), GFP_KERNEL); + if (!fw_buckets) + return -ENOMEM; + + memset(pno_cfg, 0, sizeof(*pno_cfg)); + for (i = 0; i < pi->n_reqs; i++) { + sr = pi->reqs[i]; + chidx = brcmf_pno_get_bucket_channels(sr, pno_cfg); + if (chidx < 0) { + err = chidx; + goto fail; + } + fw_buckets[i].bucket_end_index = chidx - 1; + fw_buckets[i].bucket_freq_multiple = + sr->scan_plans[0].interval / *scan_freq; + /* assure period is non-zero */ + if (!fw_buckets[i].bucket_freq_multiple) + fw_buckets[i].bucket_freq_multiple = 1; + fw_buckets[i].flag = BRCMF_PNO_REPORT_NO_BATCH; } - if (req->n_channels) { - pno_cfg.channel_num = cpu_to_le32(req->n_channels); - brcmf_pno_channel_config(ifp, &pno_cfg); + + if (BRCMF_SCAN_ON()) { + brcmf_err("base period=%u\n", *scan_freq); + for (i = 0; i < pi->n_reqs; i++) { + brcmf_err("[%d] period %u max %u repeat %u flag %x idx %u\n", + i, fw_buckets[i].bucket_freq_multiple, + le16_to_cpu(fw_buckets[i].max_freq_multiple), + fw_buckets[i].repeat, fw_buckets[i].flag, + fw_buckets[i].bucket_end_index); + } } + *buckets = fw_buckets; + return pi->n_reqs; - /* configure each match set */ - for (i = 0; i < req->n_match_sets; i++) { - ssid = &req->match_sets[i].ssid; - if (!ssid->ssid_len) { - brcmf_err("skip broadcast ssid\n"); - continue; +fail: + kfree(fw_buckets); + return err; +} + +static int brcmf_pno_config_ssids(struct brcmf_if *ifp, + struct brcmf_pno_info *pi) +{ + struct cfg80211_sched_scan_request *r; + struct cfg80211_match_set *ms; + bool active; + int i, j, err; + + for (i = 0; i < pi->n_reqs; i++) { + r = pi->reqs[i]; + + for (j = 0; j < r->n_match_sets; j++) { + ms = &r->match_sets[j]; + if (!ms->ssid.ssid_len) + continue; + active = brcmf_is_ssid_active(&ms->ssid, r); + brcmf_dbg(SCAN, "adding %.32s (active=%d)\n", + ms->ssid.ssid, active); + err = brcmf_pno_add_ssid(ifp, &ms->ssid, active); + if (err < 0) { + brcmf_err("adding failed: err=%d\n", err); + return err; + } } + } + return 0; +} + +static int brcmf_pno_config_sched_scans(struct brcmf_if *ifp) +{ + struct brcmf_pno_info *pi; + struct brcmf_gscan_config *gscan_cfg; + struct brcmf_gscan_bucket_config *buckets; + struct brcmf_pno_config_le pno_cfg; + size_t gsz; + u32 scan_freq; + int err, n_buckets; + + pi = ifp_to_pno(ifp); + n_buckets = brcmf_pno_prep_fwconfig(pi, &pno_cfg, &buckets, + &scan_freq); + if (n_buckets < 0) + return n_buckets; + + gsz = sizeof(*gscan_cfg) + (n_buckets - 1) * sizeof(*buckets); + gscan_cfg = kzalloc(gsz, GFP_KERNEL); + if (!gscan_cfg) { + err = -ENOMEM; + goto free_buckets; + } - ret = brcmf_pno_add_ssid(ifp, ssid, - brcmf_is_ssid_active(ssid, req)); - if (ret < 0) - brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n", - ret == 0 ? "set" : "failed", ssid->ssid); + /* clean up everything */ + err = brcmf_pno_clean(ifp); + if (err < 0) { + brcmf_err("failed error=%d\n", err); + goto free_gscan; } + + /* configure pno */ + err = brcmf_pno_config(ifp, scan_freq, 0, 0); + if (err < 0) + goto free_gscan; + + err = brcmf_pno_channel_config(ifp, &pno_cfg); + if (err < 0) + goto clean; + + gscan_cfg->version = cpu_to_le16(BRCMF_GSCAN_CFG_VERSION); + gscan_cfg->retry_threshold = GSCAN_RETRY_THRESHOLD; + gscan_cfg->buffer_threshold = GSCAN_BATCH_NO_THR_SET; + gscan_cfg->flags = BRCMF_GSCAN_CFG_ALL_BUCKETS_IN_1ST_SCAN; + + gscan_cfg->count_of_channel_buckets = n_buckets; + memcpy(&gscan_cfg->bucket[0], buckets, + n_buckets * sizeof(*buckets)); + + err = brcmf_fil_iovar_data_set(ifp, "pfn_gscan_cfg", gscan_cfg, gsz); + + if (err < 0) + goto clean; + + /* configure random mac */ + err = brcmf_pno_set_random(ifp, pi); + if (err < 0) + goto clean; + + err = brcmf_pno_config_ssids(ifp, pi); + if (err < 0) + goto clean; + /* Enable the PNO */ - ret = brcmf_fil_iovar_int_set(ifp, "pfn", 1); + err = brcmf_fil_iovar_int_set(ifp, "pfn", 1); + +clean: + if (err < 0) + brcmf_pno_clean(ifp); +free_gscan: + kfree(gscan_cfg); +free_buckets: + kfree(buckets); + return err; +} + +int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, + struct cfg80211_sched_scan_request *req) +{ + struct brcmf_pno_info *pi; + int ret; + + brcmf_dbg(TRACE, "reqid=%llu\n", req->reqid); + + pi = ifp_to_pno(ifp); + ret = brcmf_pno_store_request(pi, req); if (ret < 0) - brcmf_err("PNO enable failed!! ret=%d\n", ret); + return ret; - return ret; + ret = brcmf_pno_config_sched_scans(ifp); + if (ret < 0) { + brcmf_pno_remove_request(pi, req->reqid); + if (pi->n_reqs) + (void)brcmf_pno_config_sched_scans(ifp); + return ret; + } + return 0; +} + +int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid) +{ + struct brcmf_pno_info *pi; + int err; + + brcmf_dbg(TRACE, "reqid=%llu\n", reqid); + + pi = ifp_to_pno(ifp); + err = brcmf_pno_remove_request(pi, reqid); + if (err) + return err; + + brcmf_pno_clean(ifp); + + if (pi->n_reqs) + (void)brcmf_pno_config_sched_scans(ifp); + + return 0; +} + +int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_pno_info *pi; + + brcmf_dbg(TRACE, "enter\n"); + pi = kzalloc(sizeof(*pi), GFP_KERNEL); + if (!pi) + return -ENOMEM; + + cfg->pno = pi; + return 0; +} + +void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_pno_info *pi; + + brcmf_dbg(TRACE, "enter\n"); + pi = cfg->pno; + cfg->pno = NULL; + + WARN_ON(pi->n_reqs); + kfree(pi); } void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan) { /* scheduled scan settings */ - wiphy->max_sched_scan_reqs = gscan ? 2 : 1; + wiphy->max_sched_scan_reqs = gscan ? BRCMF_PNO_MAX_BUCKETS : 1; wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT; wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT; wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD; } +u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket) +{ + /* bucket appears to be gone */ + if (bucket >= pi->n_reqs) + return 0; + + return pi->reqs[bucket]->reqid; +} + +u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi, + struct brcmf_pno_net_info_le *ni) +{ + struct cfg80211_sched_scan_request *req; + struct cfg80211_match_set *ms; + u32 bucket_map = 0; + int i, j; + + for (i = 0; i < pi->n_reqs; i++) { + req = pi->reqs[i]; + + if (!req->n_match_sets) + continue; + for (j = 0; j < req->n_match_sets; j++) { + ms = &req->match_sets[j]; + if (ms->ssid.ssid_len == ni->SSID_len && + !strncmp(ms->ssid.ssid, ni->SSID, ni->SSID_len)) { + bucket_map |= BIT(i); + break; + } + } + } + return bucket_map; +} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h index 07ec51f6bec1..cd9e35ae3b21 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.h @@ -21,12 +21,8 @@ #define BRCMF_PNO_SCHED_SCAN_MIN_PERIOD 10 #define BRCMF_PNO_SCHED_SCAN_MAX_PERIOD 508 -/** - * brcmf_pno_clean - disable and clear pno in firmware. - * - * @ifp: interface object used. - */ -int brcmf_pno_clean(struct brcmf_if *ifp); +/* forward declaration */ +struct brcmf_pno_info; /** * brcmf_pno_start_sched_scan - initiate scheduled scan on device. @@ -37,6 +33,14 @@ int brcmf_pno_clean(struct brcmf_if *ifp); int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, struct cfg80211_sched_scan_request *req); +/** + * brcmf_pno_stop_sched_scan - terminate scheduled scan on device. + * + * @ifp: interface object used. + * @reqid: unique identifier of scan to be stopped. + */ +int brcmf_pno_stop_sched_scan(struct brcmf_if *ifp, u64 reqid); + /** * brcmf_pno_wiphy_params - fill scheduled scan parameters in wiphy instance. * @@ -45,4 +49,35 @@ int brcmf_pno_start_sched_scan(struct brcmf_if *ifp, */ void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan); +/** + * brcmf_pno_attach - allocate and attach module information. + * + * @cfg: cfg80211 context used. + */ +int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg); + +/** + * brcmf_pno_detach - detach and free module information. + * + * @cfg: cfg80211 context used. + */ +void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg); + +/** + * brcmf_pno_find_reqid_by_bucket - find request id for given bucket index. + * + * @pi: pno instance used. + * @bucket: index of firmware bucket. + */ +u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket); + +/** + * brcmf_pno_get_bucket_map - determine bucket map for given netinfo. + * + * @pi: pno instance used. + * @netinfo: netinfo to compare with bucket configuration. + */ +u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi, + struct brcmf_pno_net_info_le *netinfo); + #endif /* _BRCMF_PNO_H */ -- cgit v1.2.3 From 42596f761449595e3f0f18ce57c88472ad2d6160 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Fri, 9 Jun 2017 12:19:21 +0100 Subject: brcmfmac: add mutex to protect pno requests The request references kept in pno are accessed in user-space context and in firmware event handler context. As such we need to protect it with a lock. As both context allow sleep a mutex seems appropriate. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 33 ++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c index a4207754075b..e488bebd01e1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -43,6 +43,7 @@ struct brcmf_pno_info { int n_reqs; struct cfg80211_sched_scan_request *reqs[BRCMF_PNO_MAX_BUCKETS]; + struct mutex req_lock; }; #define ifp_to_pno(_ifp) ((_ifp)->drvr->config->pno) @@ -55,13 +56,17 @@ static int brcmf_pno_store_request(struct brcmf_pno_info *pi, return -ENOSPC; brcmf_dbg(SCAN, "reqid=%llu\n", req->reqid); + mutex_lock(&pi->req_lock); pi->reqs[pi->n_reqs++] = req; + mutex_unlock(&pi->req_lock); return 0; } static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid) { - int i; + int i, err = 0; + + mutex_lock(&pi->req_lock); /* find request */ for (i = 0; i < pi->n_reqs; i++) { @@ -70,7 +75,8 @@ static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid) } /* request not found */ if (WARN(i == pi->n_reqs, "reqid not found\n")) { - return -ENOENT; + err = -ENOENT; + goto done; } brcmf_dbg(SCAN, "reqid=%llu\n", reqid); @@ -78,14 +84,17 @@ static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid) /* if last we are done */ if (!pi->n_reqs || i == pi->n_reqs) - return 0; + goto done; /* fill the gap with remaining requests */ while (i <= pi->n_reqs - 1) { pi->reqs[i] = pi->reqs[i + 1]; i++; } - return 0; + +done: + mutex_unlock(&pi->req_lock); + return err; } static int brcmf_pno_channel_config(struct brcmf_if *ifp, @@ -488,6 +497,7 @@ int brcmf_pno_attach(struct brcmf_cfg80211_info *cfg) return -ENOMEM; cfg->pno = pi; + mutex_init(&pi->req_lock); return 0; } @@ -500,6 +510,7 @@ void brcmf_pno_detach(struct brcmf_cfg80211_info *cfg) cfg->pno = NULL; WARN_ON(pi->n_reqs); + mutex_destroy(&pi->req_lock); kfree(pi); } @@ -515,11 +526,15 @@ void brcmf_pno_wiphy_params(struct wiphy *wiphy, bool gscan) u64 brcmf_pno_find_reqid_by_bucket(struct brcmf_pno_info *pi, u32 bucket) { - /* bucket appears to be gone */ - if (bucket >= pi->n_reqs) - return 0; + u64 reqid = 0; + + mutex_lock(&pi->req_lock); + + if (bucket < pi->n_reqs) + reqid = pi->reqs[bucket]->reqid; - return pi->reqs[bucket]->reqid; + mutex_unlock(&pi->req_lock); + return reqid; } u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi, @@ -530,6 +545,7 @@ u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi, u32 bucket_map = 0; int i, j; + mutex_lock(&pi->req_lock); for (i = 0; i < pi->n_reqs; i++) { req = pi->reqs[i]; @@ -544,5 +560,6 @@ u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi, } } } + mutex_unlock(&pi->req_lock); return bucket_map; } -- cgit v1.2.3 From 69897f390b006948ca4cfa37174fa653a0ef7223 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Fri, 9 Jun 2017 12:19:22 +0100 Subject: brcmfmac: add scheduled scan support for specified BSSIDs Add support to handle scheduled scan request containing BSSID in the matchsets. The firmware can send event upon finding BSSIDs and SSIDs. To get these in one event the bit REPORT_SEPARATELY needed to be removed from the flags in brcmf_pno_config(). Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/fwil_types.h | 11 ++++ .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 58 ++++++++++++++++------ 2 files changed, 53 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 45aaae85c97a..b857d539b9ac 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -805,6 +805,17 @@ struct brcmf_pno_macaddr_le { u8 mac[ETH_ALEN]; }; +/** + * struct brcmf_pno_bssid_le - bssid configuration for PNO scan. + * + * @bssid: BSS network identifier. + * @flags: flags for this BSSID. + */ +struct brcmf_pno_bssid_le { + u8 bssid[ETH_ALEN]; + __le16 flags; +}; + /** * struct brcmf_pktcnt_le - packet counters. * diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c index e488bebd01e1..ffa243e2e2d0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -119,7 +119,6 @@ static int brcmf_pno_config(struct brcmf_if *ifp, u32 scan_freq, /* set extra pno params */ flags = BIT(BRCMF_PNO_IMMEDIATE_SCAN_BIT) | - BIT(BRCMF_PNO_REPORT_SEPARATELY_BIT) | BIT(BRCMF_PNO_ENABLE_ADAPTSCAN_BIT); pfn_param.repeat = BRCMF_PNO_REPEAT; pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; @@ -204,6 +203,7 @@ static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid, bool active) { struct brcmf_pno_net_param_le pfn; + int err; pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN); pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); @@ -214,7 +214,28 @@ static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid, pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); pfn.ssid.SSID_len = cpu_to_le32(ssid->ssid_len); memcpy(pfn.ssid.SSID, ssid->ssid, ssid->ssid_len); - return brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn)); + + brcmf_dbg(SCAN, "adding ssid=%.32s (active=%d)\n", ssid->ssid, active); + err = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn, sizeof(pfn)); + if (err < 0) + brcmf_err("adding failed: err=%d\n", err); + return err; +} + +static int brcmf_pno_add_bssid(struct brcmf_if *ifp, const u8 *bssid) +{ + struct brcmf_pno_bssid_le bssid_cfg; + int err; + + memcpy(bssid_cfg.bssid, bssid, ETH_ALEN); + bssid_cfg.flags = 0; + + brcmf_dbg(SCAN, "adding bssid=%pM\n", bssid); + err = brcmf_fil_iovar_data_set(ifp, "pfn_add_bssid", &bssid_cfg, + sizeof(bssid_cfg)); + if (err < 0) + brcmf_err("adding failed: err=%d\n", err); + return err; } static bool brcmf_is_ssid_active(struct cfg80211_ssid *ssid, @@ -341,29 +362,29 @@ fail: return err; } -static int brcmf_pno_config_ssids(struct brcmf_if *ifp, - struct brcmf_pno_info *pi) +static int brcmf_pno_config_networks(struct brcmf_if *ifp, + struct brcmf_pno_info *pi) { struct cfg80211_sched_scan_request *r; struct cfg80211_match_set *ms; bool active; - int i, j, err; + int i, j, err = 0; for (i = 0; i < pi->n_reqs; i++) { r = pi->reqs[i]; for (j = 0; j < r->n_match_sets; j++) { ms = &r->match_sets[j]; - if (!ms->ssid.ssid_len) - continue; - active = brcmf_is_ssid_active(&ms->ssid, r); - brcmf_dbg(SCAN, "adding %.32s (active=%d)\n", - ms->ssid.ssid, active); - err = brcmf_pno_add_ssid(ifp, &ms->ssid, active); - if (err < 0) { - brcmf_err("adding failed: err=%d\n", err); - return err; + if (ms->ssid.ssid_len) { + active = brcmf_is_ssid_active(&ms->ssid, r); + err = brcmf_pno_add_ssid(ifp, &ms->ssid, + active); } + if (!err && is_valid_ether_addr(ms->bssid)) + err = brcmf_pno_add_bssid(ifp, ms->bssid); + + if (err < 0) + return err; } } return 0; @@ -427,7 +448,7 @@ static int brcmf_pno_config_sched_scans(struct brcmf_if *ifp) if (err < 0) goto clean; - err = brcmf_pno_config_ssids(ifp, pi); + err = brcmf_pno_config_networks(ifp, pi); if (err < 0) goto clean; @@ -554,7 +575,12 @@ u32 brcmf_pno_get_bucket_map(struct brcmf_pno_info *pi, for (j = 0; j < req->n_match_sets; j++) { ms = &req->match_sets[j]; if (ms->ssid.ssid_len == ni->SSID_len && - !strncmp(ms->ssid.ssid, ni->SSID, ni->SSID_len)) { + !memcmp(ms->ssid.ssid, ni->SSID, ni->SSID_len)) { + bucket_map |= BIT(i); + break; + } + if (is_valid_ether_addr(ms->bssid) && + !memcmp(ms->bssid, ni->bssid, ETH_ALEN)) { bucket_map |= BIT(i); break; } -- cgit v1.2.3 From a9507d5cfd5225cb6ee68e8de0cf7ffd0d49cdda Mon Sep 17 00:00:00 2001 From: Martin Michlmayr Date: Sat, 10 Jun 2017 11:40:04 +0200 Subject: brcmfmac: Fix grammar issue in error message Fix grammar issue in error message about ISO3166. Signed-off-by: Martin Michlmayr Acked-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index b3180b152a2f..ac07e6030a05 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6778,7 +6778,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, /* ignore non-ISO3166 country codes */ for (i = 0; i < sizeof(req->alpha2); i++) if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { - brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n", + brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n", req->alpha2[0], req->alpha2[1]); return; } -- cgit v1.2.3 From 5ea59db8a375216e6c915c5586f556766673b5a7 Mon Sep 17 00:00:00 2001 From: "Peter S. Housel" Date: Mon, 12 Jun 2017 11:46:22 +0100 Subject: brcmfmac: Fix glom_skb leak in brcmf_sdiod_recv_chain An earlier change to this function (3bdae810721b) fixed a leak in the case of an unsuccessful call to brcmf_sdiod_buffrw(). However, the glom_skb buffer, used for emulating a scattering read, is never used or referenced after its contents are copied into the destination buffers, and therefore always needs to be freed by the end of the function. Fixes: 3bdae810721b ("brcmfmac: Fix glob_skb leak in brcmf_sdiod_recv_chain") Fixes: a413e39a38573 ("brcmfmac: fix brcmf_sdcard_recv_chain() for host without sg support") Cc: stable@vger.kernel.org # 4.9.x- Signed-off-by: Peter S. Housel Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 9b970dc2b922..844c1e68ec03 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -706,7 +706,7 @@ done: int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, struct sk_buff_head *pktq, uint totlen) { - struct sk_buff *glom_skb; + struct sk_buff *glom_skb = NULL; struct sk_buff *skb; u32 addr = sdiodev->sbwad; int err = 0; @@ -727,10 +727,8 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, return -ENOMEM; err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, glom_skb); - if (err) { - brcmu_pkt_buf_free_skb(glom_skb); + if (err) goto done; - } skb_queue_walk(pktq, skb) { memcpy(skb->data, glom_skb->data, skb->len); @@ -741,6 +739,7 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, pktq); done: + brcmu_pkt_buf_free_skb(glom_skb); return err; } -- cgit v1.2.3 From 292c333300ec2a412902fa59aad5b365024384a5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 2 Jun 2017 09:56:39 +0100 Subject: mwifiex: make function mwifiex_ret_pkt_aggr_ctrl static function mwifiex_ret_pkt_aggr_ctrl can be made static as it does not need to be in global scope. Cleans up sparse warning: "symbol 'mwifiex_ret_pkt_aggr_ctrl' was not declared. Should it be static?" Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index 3348fb3a7514..2945775e83c5 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -1154,8 +1154,8 @@ static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv, return 0; } -int mwifiex_ret_pkt_aggr_ctrl(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp) +static int mwifiex_ret_pkt_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) { struct host_cmd_ds_pkt_aggr_ctrl *pkt_aggr_ctrl = &resp->params.pkt_aggr_ctrl; -- cgit v1.2.3 From bc0384eedb66555f6b4662102675f9bf4a3d12b7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 2 Jun 2017 16:40:45 +0100 Subject: qtnfmac: check band before allocating cmd_skb to avoid resource leak The current code allocates cmd_skb and then will leak this if band->band is an illegal value. It is simpler to sanity check the band first before allocating cmd_skb so that we don't have to free cmd_skb if an invalid band occurs. Detected by CoverityScan, CID#1437561 ("Resource Leak") Signed-off-by: Colin Ian King Reviewed-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index f0a0cfa7d8a1..cce62f39edaf 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -1300,12 +1300,6 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac, int ret = 0; u8 qband; - cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, - QLINK_CMD_CHANS_INFO_GET, - sizeof(*cmd)); - if (!cmd_skb) - return -ENOMEM; - switch (band->band) { case NL80211_BAND_2GHZ: qband = QLINK_BAND_2GHZ; @@ -1320,6 +1314,12 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac, return -EINVAL; } + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, + QLINK_CMD_CHANS_INFO_GET, + sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + cmd = (struct qlink_cmd_chans_info_get *)cmd_skb->data; cmd->band = qband; ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, -- cgit v1.2.3 From d178b1321e494c5928cc135814bc303ec9de2282 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 5 Jun 2017 10:29:51 -0500 Subject: rtlwifi: btcoex: add macros to check chip type For some external functions that have hardware dependency, we need to know the type of the hardware before invoking them. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Ping-Ke Shih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbt_precomp.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h index 39b9a3309cfd..2ac989a4b2bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h @@ -37,6 +37,28 @@ #include "halbtcoutsrc.h" +/* Interface type */ +#define RT_PCI_INTERFACE 1 +#define RT_USB_INTERFACE 2 +#define RT_SDIO_INTERFACE 3 +#define DEV_BUS_TYPE RT_PCI_INTERFACE + +/* IC type */ +#define RTL_HW_TYPE(adapter) (rtl_hal((struct rtl_priv *)adapter)->hw_type) + +#define IS_NEW_GENERATION_IC(adapter) \ + (RTL_HW_TYPE(adapter) >= HARDWARE_TYPE_RTL8192EE) +#define IS_HARDWARE_TYPE_8812(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8812AE) +#define IS_HARDWARE_TYPE_8821(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8821AE) +#define IS_HARDWARE_TYPE_8723A(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8723AE) +#define IS_HARDWARE_TYPE_8723B(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8723BE) +#define IS_HARDWARE_TYPE_8192E(adapter) \ + (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8192EE) + #include "halbtc8192e2ant.h" #include "halbtc8723b1ant.h" #include "halbtc8723b2ant.h" -- cgit v1.2.3 From 753c953bae5d2bb1d8786b78b9b8a6d5cfe677b4 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 5 Jun 2017 10:29:52 -0500 Subject: rtlwifi: btcoex: rename ex_halbtc*ant to ex_btc*ant These external functions are for BT-coexistence, so remove the "hal" prefix for consistancy. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Ping-Ke Shih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8192e2ant.h | 32 ++++++------- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 52 +++++++++++----------- .../realtek/rtlwifi/btcoexist/halbtc8723b1ant.h | 41 ++++++++--------- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.h | 38 ++++++++-------- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.h | 24 +++++----- 5 files changed, 95 insertions(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h index a57d6947eaf7..65502acee52c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.h @@ -164,20 +164,20 @@ struct coex_sta_8192e_2ant { /**************************************************************** * The following is interface which will notify coex module. ****************************************************************/ -void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist); -void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist); -void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, +void ex_btc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_btc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmpbuf, u8 length); -void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist); -void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist); -void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_halt_notify(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_periodical(struct btc_coexist *btcoexist); +void ex_btc8192e2ant_display_coex_info(struct btc_coexist *btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index a0f3a18add25..03998d2e9eb8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2390,9 +2390,9 @@ static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist, } /************************************************************** - * extern function start with ex_halbtc8723b1ant_ + * extern function start with ex_btc8723b1ant_ **************************************************************/ -void ex_halbtc8723b1ant_power_on_setting(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_power_on_setting(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; struct btc_board_info *board_info = &btcoexist->board_info; @@ -2462,14 +2462,14 @@ void ex_halbtc8723b1ant_power_on_setting(struct btc_coexist *btcoexist) } -void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, - bool wifi_only) +void ex_btc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, + bool wifi_only) { halbtc8723b1ant_init_hw_config(btcoexist, true, wifi_only); btcoexist->stop_coex_dm = false; } -void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -2483,7 +2483,7 @@ void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) halbtc8723b1ant_query_bt_info(btcoexist); } -void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) { struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; @@ -2758,7 +2758,7 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } -void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -2787,7 +2787,7 @@ void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) } } -void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -2805,7 +2805,7 @@ void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) } } -void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; bool wifi_connected = false, bt_hs_on = false; @@ -2891,7 +2891,7 @@ void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) } } -void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; bool wifi_connected = false, bt_hs_on = false; @@ -2961,8 +2961,8 @@ void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) } } -void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, - u8 type) +void ex_btc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 h2c_parameter[3] = {0}; @@ -3042,8 +3042,8 @@ void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); } -void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type) +void ex_btc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; bool bt_hs_on = false; @@ -3119,8 +3119,8 @@ void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, } } -void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmp_buf, u8 length) +void ex_btc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 bt_info = 0; @@ -3211,11 +3211,11 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); if (wifi_connected) - ex_halbtc8723b1ant_media_status_notify(btcoexist, - BTC_MEDIA_CONNECT); + ex_btc8723b1ant_media_status_notify(btcoexist, + BTC_MEDIA_CONNECT); else - ex_halbtc8723b1ant_media_status_notify(btcoexist, - BTC_MEDIA_DISCONNECT); + ex_btc8723b1ant_media_status_notify(btcoexist, + BTC_MEDIA_DISCONNECT); } if (coex_sta->bt_info_ext & BIT3) { @@ -3364,7 +3364,7 @@ void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, halbtc8723b1ant_run_coexist_mechanism(btcoexist); } -void ex_halbtc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; u32 u32tmp; @@ -3401,7 +3401,7 @@ void ex_halbtc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type) } } -void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_halt_notify(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -3418,12 +3418,12 @@ void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) 0x0, 0x0); halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); - ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + ex_btc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); btcoexist->stop_coex_dm = true; } -void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -3458,7 +3458,7 @@ void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) } } -void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -3469,7 +3469,7 @@ void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) halbtc8723b1ant_init_coex_dm(btcoexist); } -void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist) +void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 506961a1ca56..8d4fde235e11 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -200,24 +200,25 @@ struct coex_sta_8723b_1ant { /************************************************************************* * The following is interface which will notify coex module. *************************************************************************/ -void ex_halbtc8723b1ant_power_on_setting(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, - bool wifi_only); -void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmpbuf, u8 length); -void ex_halbtc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, +void ex_btc8723b1ant_power_on_setting(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist, + bool wifi_only); +void ex_btc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); -void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist); -void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_btc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8723b1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); +void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h index cb32e7a64ae6..b0a6626fbb66 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h @@ -170,21 +170,23 @@ struct coex_sta_8821a_1ant { * The following is interface which will notify coex module. *=========================================== */ -void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmpbuf, u8 length); -void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); -void ex_halbtc8821a1ant_periodical(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist); -void ex_halbtc8821a1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code, - u8 op_len, u8 *data); +void ex_btc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist, + bool wifi_only); +void ex_btc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_btc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_btc8821a1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_btc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); +void ex_btc8821a1ant_periodical(struct btc_coexist *btcoexist); +void ex_btc8821a1ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8821a1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code, + u8 op_len, u8 *data); +void ex_btc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index a1603e2d44e3..1d6e3e9abd91 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -173,58 +173,58 @@ struct coex_sta_8821a_2ant { *=========================================== */ void -ex_halbtc8821a2ant_init_hwconfig( +ex_btc8821a2ant_init_hwconfig( struct btc_coexist *btcoexist ); void -ex_halbtc8821a2ant_init_coex_dm( +ex_btc8821a2ant_init_coex_dm( struct btc_coexist *btcoexist ); void -ex_halbtc8821a2ant_ips_notify( +ex_btc8821a2ant_ips_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_lps_notify( +ex_btc8821a2ant_lps_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_scan_notify( +ex_btc8821a2ant_scan_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_connect_notify( +ex_btc8821a2ant_connect_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_media_status_notify( +ex_btc8821a2ant_media_status_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_special_packet_notify( +ex_btc8821a2ant_special_packet_notify( struct btc_coexist *btcoexist, u8 type ); void -ex_halbtc8821a2ant_bt_info_notify( +ex_btc8821a2ant_bt_info_notify( struct btc_coexist *btcoexist, u8 *tmp_buf, u8 length ); void -ex_halbtc8821a2ant_halt_notify( +ex_btc8821a2ant_halt_notify( struct btc_coexist *btcoexist ); void -ex_halbtc8821a2ant_periodical( +ex_btc8821a2ant_periodical( struct btc_coexist *btcoexist ); void -ex_halbtc8821a2ant_display_coex_info( +ex_btc8821a2ant_display_coex_info( struct btc_coexist *btcoexist ); -- cgit v1.2.3 From 6fbbc82adfb29fc1c76d4d5ca529ba7c8891a2e7 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 5 Jun 2017 10:29:53 -0500 Subject: rtlwifi: btcoex: settings before firmware is downloaded The btcoex is sometimes unstable because there are some unexpected behaviors before the firmware has been downloaded successfully. Therefore we force the antenna path settings to avoid this, then let the firmware control the btcoexistence when the firmware is ready. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Ping-Ke Shih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h | 1 + .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h | 2 ++ .../net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 13 +++++++++++++ .../net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 1 + 4 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index 50726beaeead..a98b9548c3c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -196,5 +196,6 @@ void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist); void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist); void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_pre_load_firmware(struct btc_coexist *btcoexist); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index 1d6e3e9abd91..a839d5574422 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -228,3 +228,5 @@ void ex_btc8821a2ant_display_coex_info( struct btc_coexist *btcoexist ); +void ex_btc8821a2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void ex_btc8821a2ant_pre_load_firmware(struct btc_coexist *btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index f13000612913..0cd4926c1ed7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -690,6 +690,19 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) return true; } +void exhalbtc_pre_load_firmware(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_pre_load_firmware++; + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_pre_load_firmware(btcoexist); + } +} + void exhalbtc_init_hw_config(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index c5c360e011a9..eca0e5a78ada 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -486,6 +486,7 @@ struct btc_statistics { u32 cnt_coex_dm_switch; u32 cnt_stack_operation_notify; u32 cnt_dbg_ctrl; + u32 cnt_pre_load_firmware; }; struct btc_bt_link_info { -- cgit v1.2.3 From 86f9ab2ef4bdf0c9763d18ae2755ba75b4004725 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 5 Jun 2017 10:29:54 -0500 Subject: rtlwifi: btcoex: hook external PnP notify by chip for wifi driver Hook the chip-specific PnP notify functions for the wifi driver to notify btcoexistence. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Ping-Ke Shih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b2ant.h | 1 + .../wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index a98b9548c3c7..ae3e450c5966 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -196,6 +196,7 @@ void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist); void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist); void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); void ex_btc8723b2ant_pre_load_firmware(struct btc_coexist *btcoexist); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 0cd4926c1ed7..5e6e14fd8c85 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -916,6 +916,24 @@ void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) { if (!halbtc_is_bt_coexist_available(btcoexist)) return; + + /* currently only 1ant we have to do the notification, + * once pnp is notified to sleep state, we have to leave LPS that + * we can sleep normally. + */ + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_pnp_notify(btcoexist, pnp_state); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_pnp_notify(btcoexist, pnp_state); + } else if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_pnp_notify(btcoexist, pnp_state); + else if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_pnp_notify(btcoexist, pnp_state); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + } } void exhalbtc_periodical(struct btc_coexist *btcoexist) -- cgit v1.2.3 From 60f44100eee785b5bdb475d05760ff15707fd1b7 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 5 Jun 2017 10:29:55 -0500 Subject: rtlwifi: btcoex: add settings before the hardware is ready When the hardware is turned on and in the initialization stage, the PTA circuit is unstable. Hence we need to force some hardware settings to make sure the PTA circuit work correctly, otherwise it may affect the user's experience. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Ping-Ke Shih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h | 1 + .../net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 15 +++++++++++++++ .../net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 1 + 3 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index ae3e450c5966..bc1e3042e271 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -198,5 +198,6 @@ void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist); void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist); void ex_btc8723b2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); void ex_btc8723b2ant_pre_load_firmware(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_power_on_setting(struct btc_coexist *btcoexist); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 5e6e14fd8c85..8b015e64af49 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -690,6 +690,21 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) return true; } +void exhalbtc_power_on_setting(struct btc_coexist *btcoexist) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + btcoexist->statistics.cnt_power_on++; + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_power_on_setting(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_power_on_setting(btcoexist); + } +} + void exhalbtc_pre_load_firmware(struct btc_coexist *btcoexist) { if (!halbtc_is_bt_coexist_available(btcoexist)) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index eca0e5a78ada..9b0a6e9c5b20 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -487,6 +487,7 @@ struct btc_statistics { u32 cnt_stack_operation_notify; u32 cnt_dbg_ctrl; u32 cnt_pre_load_firmware; + u32 cnt_power_on; }; struct btc_bt_link_info { -- cgit v1.2.3 From 7937f02d1953952a6eaf626b175ea9db5541e699 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 5 Jun 2017 10:29:56 -0500 Subject: rtlwifi: btcoex: hook external functions for newer chips Hook the external functions for newer ICs such as 8821a and 8192e. Rename ex_halbtc8192e2ant_halt_notify to ex_btc8192e2ant_halt_notify. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Ping-Ke Shih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8192e2ant.c | 2 +- .../realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 340 +++++++++++++++++---- 2 files changed, 280 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c index 9015512ed647..44c25724529e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c @@ -3194,7 +3194,7 @@ void ex_btc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, btc8192e2ant_run_coexist_mechanism(btcoexist); } -void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist) +void ex_btc8192e2ant_halt_notify(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 8b015e64af49..9832405c5e26 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -225,11 +225,11 @@ static void halbtc_normal_lps(struct btc_coexist *btcoexist) } } -static void halbtc_leave_low_power(void) +static void halbtc_leave_low_power(struct btc_coexist *btcoexist) { } -static void halbtc_nomal_low_power(void) +static void halbtc_normal_low_power(struct btc_coexist *btcoexist) { } @@ -640,6 +640,24 @@ static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type) } } +bool halbtc_under_ips(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); + enum rf_pwrstate rtstate; + + if (ppsc->inactiveps) { + rtstate = ppsc->rfpwr_state; + + if (rtstate != ERFON && + ppsc->rfoff_reason == RF_CHANGE_BY_IPS) { + return true; + } + } + + return false; +} + /***************************************************************** * Extern functions called by other module *****************************************************************/ @@ -720,38 +738,58 @@ void exhalbtc_pre_load_firmware(struct btc_coexist *btcoexist) void exhalbtc_init_hw_config(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + bool wifi_only = true; if (!halbtc_is_bt_coexist_available(btcoexist)) return; btcoexist->statistics.cnt_init_hw_config++; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_init_hwconfig(btcoexist); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_init_hwconfig(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_init_hwconfig(btcoexist, wifi_only); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_init_hwconfig(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_init_hwconfig(btcoexist, wifi_only); + } else if (IS_HARDWARE_TYPE_8723A(btcoexist->adapter)) { + /* 8723A has no this function */ + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_init_hwconfig(btcoexist); + } } void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); - if (!halbtc_is_bt_coexist_available(btcoexist)) return; btcoexist->statistics.cnt_init_coex_dm++; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_init_coex_dm(btcoexist); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_init_coex_dm(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_init_coex_dm(btcoexist); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_init_coex_dm(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_init_coex_dm(btcoexist); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_init_coex_dm(btcoexist); + } btcoexist->initilized = true; } void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 ips_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -765,18 +803,28 @@ void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type) else ips_type = BTC_IPS_LEAVE; - halbtc_leave_low_power(); + halbtc_leave_low_power(btcoexist); - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_ips_notify(btcoexist, ips_type); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_ips_notify(btcoexist, ips_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_ips_notify(btcoexist, ips_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_ips_notify(btcoexist, ips_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_ips_notify(btcoexist, ips_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_ips_notify(btcoexist, ips_type); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 lps_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -790,14 +838,24 @@ void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type) else lps_type = BTC_LPS_ENABLE; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_lps_notify(btcoexist, lps_type); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_lps_notify(btcoexist, lps_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_lps_notify(btcoexist, lps_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_lps_notify(btcoexist, lps_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_lps_notify(btcoexist, lps_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_lps_notify(btcoexist, lps_type); + } } void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 scan_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -811,18 +869,28 @@ void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) else scan_type = BTC_SCAN_FINISH; - halbtc_leave_low_power(); + halbtc_leave_low_power(btcoexist); - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_scan_notify(btcoexist, scan_type); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_scan_notify(btcoexist, scan_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_scan_notify(btcoexist, scan_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_scan_notify(btcoexist, scan_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_scan_notify(btcoexist, scan_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_scan_notify(btcoexist, scan_type); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 asso_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -836,10 +904,24 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) else asso_type = BTC_ASSOCIATE_FINISH; - halbtc_leave_low_power(); + halbtc_leave_low_power(btcoexist); - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_connect_notify(btcoexist, asso_type); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_connect_notify(btcoexist, asso_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_connect_notify(btcoexist, asso_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_connect_notify(btcoexist, asso_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_connect_notify(btcoexist, asso_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_connect_notify(btcoexist, asso_type); + } + + halbtc_normal_low_power(btcoexist); } void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, @@ -858,15 +940,28 @@ void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, else status = BTC_MEDIA_DISCONNECT; - halbtc_leave_low_power(); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_media_status_notify(btcoexist, status); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_media_status_notify(btcoexist, status); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_media_status_notify(btcoexist, status); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_media_status_notify(btcoexist, status); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_media_status_notify(btcoexist, status); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 packet_type; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -875,28 +970,85 @@ void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type) if (btcoexist->manual_control) return; - packet_type = BTC_PACKET_DHCP; + if (pkt_type == PACKET_DHCP) { + packet_type = BTC_PACKET_DHCP; + } else if (pkt_type == PACKET_EAPOL) { + packet_type = BTC_PACKET_EAPOL; + } else if (pkt_type == PACKET_ARP) { + packet_type = BTC_PACKET_ARP; + } else { + packet_type = BTC_PACKET_UNKNOWN; + return; + } - halbtc_leave_low_power(); + halbtc_leave_low_power(btcoexist); - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_special_packet_notify(btcoexist, - packet_type); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_special_packet_notify(btcoexist, + packet_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_special_packet_notify(btcoexist, + packet_type); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_special_packet_notify(btcoexist, + packet_type); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_special_packet_notify(btcoexist, + packet_type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_special_packet_notify(btcoexist, + packet_type); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, u8 length) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); if (!halbtc_is_bt_coexist_available(btcoexist)) return; btcoexist->statistics.cnt_bt_info_notify++; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_bt_info_notify(btcoexist, tmp_buf, + length); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_bt_info_notify(btcoexist, tmp_buf, + length); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_bt_info_notify(btcoexist, tmp_buf, + length); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_bt_info_notify(btcoexist, tmp_buf, + length); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_bt_info_notify(btcoexist, tmp_buf, + length); + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_rf_status_notify(btcoexist, type); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + } } void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) @@ -909,22 +1061,41 @@ void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) if (btcoexist->manual_control) return; - stack_op_type = BTC_STACK_OP_NONE; - - halbtc_leave_low_power(); - - halbtc_nomal_low_power(); + if ((type == HCI_BT_OP_INQUIRY_START) || + (type == HCI_BT_OP_PAGING_START) || + (type == HCI_BT_OP_PAIRING_START)) { + stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_START; + } else if ((type == HCI_BT_OP_INQUIRY_FINISH) || + (type == HCI_BT_OP_PAGING_SUCCESS) || + (type == HCI_BT_OP_PAGING_UNSUCCESS) || + (type == HCI_BT_OP_PAIRING_FINISH)) { + stack_op_type = BTC_STACK_OP_INQ_PAGE_PAIR_FINISH; + } else { + stack_op_type = BTC_STACK_OP_NONE; + } } void exhalbtc_halt_notify(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); if (!halbtc_is_bt_coexist_available(btcoexist)) return; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_halt_notify(btcoexist); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_halt_notify(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_halt_notify(btcoexist); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_halt_notify(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_halt_notify(btcoexist); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_halt_notify(btcoexist); + } + + btcoexist->binded = false; } void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) @@ -951,20 +1122,56 @@ void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) } } -void exhalbtc_periodical(struct btc_coexist *btcoexist) +void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; + btcoexist->statistics.cnt_coex_dm_switch++; + + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 1) { + btcoexist->stop_coex_dm = true; + ex_btc8723b1ant_coex_dm_reset(btcoexist); + exhalbtc_set_ant_num(rtlpriv, + BT_COEX_ANT_TYPE_DETECTED, 2); + ex_btc8723b2ant_init_hwconfig(btcoexist); + ex_btc8723b2ant_init_coex_dm(btcoexist); + btcoexist->stop_coex_dm = false; + } + } + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_periodical(struct btc_coexist *btcoexist) +{ if (!halbtc_is_bt_coexist_available(btcoexist)) return; btcoexist->statistics.cnt_periodical++; - halbtc_leave_low_power(); + halbtc_leave_low_power(btcoexist); - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_periodical(btcoexist); + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_periodical(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + if (!halbtc_under_ips(btcoexist)) + ex_btc8821a1ant_periodical(btcoexist); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_periodical(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_periodical(btcoexist); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_periodical(btcoexist); + } - halbtc_nomal_low_power(); + halbtc_normal_low_power(btcoexist); } void exhalbtc_dbg_control(struct btc_coexist *btcoexist, @@ -973,6 +1180,17 @@ void exhalbtc_dbg_control(struct btc_coexist *btcoexist, if (!halbtc_is_bt_coexist_available(btcoexist)) return; btcoexist->statistics.cnt_dbg_ctrl++; + + halbtc_leave_low_power(btcoexist); + + halbtc_normal_low_power(btcoexist); +} + +void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq, + u32 offset, u32 span, u32 seconds) +{ + if (!halbtc_is_bt_coexist_available(btcoexist)) + return; } void exhalbtc_stack_update_profile_info(void) -- cgit v1.2.3 From 0199103ea7ec2e5ae7233ffa43fe6f08088dfb5d Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 5 Jun 2017 10:29:57 -0500 Subject: rtlwifi: btcoex: bind BT coex information with wifi driver When initializing, gather BT information in struct btcoexist and provide them to wifi driver. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Ping-Ke Shih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 56 ++++++++++++++++++++++ .../realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 8 ++++ .../wireless/realtek/rtlwifi/btcoexist/rtl_btc.c | 29 ++++------- 3 files changed, 72 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 9832405c5e26..5ad9c180bc28 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -708,6 +708,56 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) return true; } +bool exhalbtc_bind_bt_coex_withadapter(void *adapter) +{ + struct btc_coexist *btcoexist = &gl_bt_coexist; + struct rtl_priv *rtlpriv = adapter; + u8 ant_num = 2, chip_type, single_ant_path = 0; + + if (btcoexist->binded) + return false; + + btcoexist->binded = true; + btcoexist->statistics.cnt_bind++; + + btcoexist->adapter = adapter; + + btcoexist->stack_info.profile_notified = false; + + btcoexist->bt_info.bt_ctrl_agg_buf_size = false; + btcoexist->bt_info.agg_buf_size = 5; + + btcoexist->bt_info.increase_scan_dev_num = false; + btcoexist->bt_info.miracast_plus_bt = false; + + chip_type = rtl_get_hwpg_bt_type(rtlpriv); + exhalbtc_set_chip_type(chip_type); + ant_num = rtl_get_hwpg_ant_num(rtlpriv); + exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_PG, ant_num); + + /* set default antenna position to main port */ + btcoexist->board_info.btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + single_ant_path = rtl_get_hwpg_single_ant_path(rtlpriv); + exhalbtc_set_single_ant_path(single_ant_path); + + if (rtl_get_hwpg_package_type(rtlpriv) == 0) + btcoexist->board_info.tfbga_package = false; + else if (rtl_get_hwpg_package_type(rtlpriv) == 1) + btcoexist->board_info.tfbga_package = false; + else + btcoexist->board_info.tfbga_package = true; + + if (btcoexist->board_info.tfbga_package) + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Package Type = TFBGA\n"); + else + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Package Type = Non-TFBGA\n"); + + return true; +} + void exhalbtc_power_on_setting(struct btc_coexist *btcoexist) { if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -1296,6 +1346,12 @@ void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num) } } +/* Currently used by 8723b only, S0 or S1 */ +void exhalbtc_set_single_ant_path(u8 single_ant_path) +{ + gl_bt_coexist.board_info.single_ant_path = single_ant_path; +} + void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 9b0a6e9c5b20..3d34cf83d7fc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -153,6 +153,7 @@ struct btc_board_info { u8 btdm_ant_pos; u8 single_ant_path; /* current used for 8723b only, 1=>s0, 0=>s1 */ bool bt_exist; + bool tfbga_package; }; enum btc_dbg_opcode { @@ -433,12 +434,18 @@ struct btc_bt_info { bool bt_disabled; u8 rssi_adjust_for_agc_table_on; u8 rssi_adjust_for_1ant_coex_type; + bool pre_bt_ctrl_agg_buf_size; bool bt_busy; + u8 pre_agg_buf_size; u8 agg_buf_size; bool limited_dig; + bool pre_reject_agg_pkt; bool reject_agg_pkt; bool bt_ctrl_buf_size; bool increase_scan_dev_num; + bool miracast_plus_bt; + bool bt_ctrl_agg_buf_size; + bool bt_tx_rx_mask; u16 bt_hci_ver; u16 bt_real_fw_ver; u8 bt_fw_ver; @@ -593,5 +600,6 @@ void exhalbtc_signal_compensation(struct btc_coexist *btcoexist, u8 *rssi_wifi, u8 *rssi_bt); void exhalbtc_lps_leave(struct btc_coexist *btcoexist); void exhalbtc_low_wifi_traffic_notify(struct btc_coexist *btcoexist); +void exhalbtc_set_single_ant_path(u8 single_ant_path); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index 46e0fa6be273..dec9d83f87af 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -54,32 +54,19 @@ void rtl_btc_init_variables(struct rtl_priv *rtlpriv) void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv) { - u8 ant_num; - u8 bt_exist; - u8 bt_type; + /* move ant_num, bt_type and single_ant_path to + * exhalbtc_bind_bt_coex_withadapter() + */ +} - ant_num = rtl_get_hwpg_ant_num(rtlpriv); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "%s, antNum is %d\n", __func__, ant_num); +void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv) +{ + u8 bt_exist; bt_exist = rtl_get_hwpg_bt_exist(rtlpriv); RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - "%s, bt_exist is %d\n", __func__, bt_exist); - exhalbtc_set_bt_exist(bt_exist); + "%s, bt_exist is %d\n", __func__, bt_exist); - bt_type = rtl_get_hwpg_bt_type(rtlpriv); - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%s, bt_type is %d\n", - __func__, bt_type); - exhalbtc_set_chip_type(bt_type); - - if (rtlpriv->cfg->mod_params->ant_sel == 1) - exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_DETECTED, 1); - else - exhalbtc_set_ant_num(rtlpriv, BT_COEX_ANT_TYPE_PG, ant_num); -} - -void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv) -{ exhalbtc_init_hw_config(&gl_bt_coexist); exhalbtc_init_coex_dm(&gl_bt_coexist); } -- cgit v1.2.3 From 6aafa230741484b2d6101219d606b8739a074855 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 5 Jun 2017 10:29:58 -0500 Subject: rtlwifi: btcoex: remove unused display functions These display functions are useless and will not be called in the future. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Ping-Ke Shih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 38 ---------------------- 1 file changed, 38 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 5ad9c180bc28..53a43dfdecba 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -485,22 +485,6 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) return true; } -static void halbtc_display_coex_statistics(struct btc_coexist *btcoexist) -{ -} - -static void halbtc_display_bt_link_info(struct btc_coexist *btcoexist) -{ -} - -static void halbtc_display_bt_fw_info(struct btc_coexist *btcoexist) -{ -} - -static void halbtc_display_fw_pwr_mode_cmd(struct btc_coexist *btcoexist) -{ -} - /************************************************************ * IO related function ************************************************************/ @@ -619,27 +603,6 @@ static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id, cmd_len, cmd_buf); } -static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type) -{ - struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; - switch (disp_type) { - case BTC_DBG_DISP_COEX_STATISTICS: - halbtc_display_coex_statistics(btcoexist); - break; - case BTC_DBG_DISP_BT_LINK_INFO: - halbtc_display_bt_link_info(btcoexist); - break; - case BTC_DBG_DISP_BT_FW_VER: - halbtc_display_bt_fw_info(btcoexist); - break; - case BTC_DBG_DISP_FW_PWR_MODE_CMD: - halbtc_display_fw_pwr_mode_cmd(btcoexist); - break; - default: - break; - } -} - bool halbtc_under_ips(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -696,7 +659,6 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) btcoexist->btc_get_rf_reg = halbtc_get_rfreg; btcoexist->btc_fill_h2c = halbtc_fill_h2c_cmd; - btcoexist->btc_disp_dbg_msg = halbtc_display_dbg_msg; btcoexist->btc_get = halbtc_get; btcoexist->btc_set = halbtc_set; -- cgit v1.2.3 From c42ea613353cd28f741d9389f52b4b42a9ce2eb9 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 5 Jun 2017 10:29:59 -0500 Subject: rtlwifi: btcoex: let btcoex get wifi rssi and link status Instead of rssi status, the btcoex also needs to get the link status of the wifi. In addition, some of the rssi status can be merged into link status. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Ping-Ke Shih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 358 +++++++++++++++------ .../realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 32 +- .../wireless/realtek/rtlwifi/btcoexist/rtl_btc.c | 6 +- 3 files changed, 292 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 53a43dfdecba..f00d6e6ab69b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -36,6 +36,20 @@ u32 btc_dbg_type[BTC_MSG_MAX]; /*************************************************** * Debug related function ***************************************************/ + +const char *const gl_btc_wifi_bw_string[] = { + "11bg", + "HT20", + "HT40", + "HT80", + "HT160" +}; + +const char *const gl_btc_wifi_freq_string[] = { + "2.4G", + "5G" +}; + static bool halbtc_is_bt_coexist_available(struct btc_coexist *btcoexist) { if (!btcoexist->binded || NULL == btcoexist->adapter) @@ -54,28 +68,39 @@ static bool halbtc_is_wifi_busy(struct rtl_priv *rtlpriv) static void halbtc_dbg_init(void) { - u8 i; - - for (i = 0; i < BTC_MSG_MAX; i++) - btc_dbg_type[i] = 0; - - btc_dbg_type[BTC_MSG_INTERFACE] = -/* INTF_INIT | */ -/* INTF_NOTIFY | */ - 0; +} - btc_dbg_type[BTC_MSG_ALGORITHM] = -/* ALGO_BT_RSSI_STATE | */ -/* ALGO_WIFI_RSSI_STATE | */ -/* ALGO_BT_MONITOR | */ -/* ALGO_TRACE | */ -/* ALGO_TRACE_FW | */ -/* ALGO_TRACE_FW_DETAIL | */ -/* ALGO_TRACE_FW_EXEC | */ -/* ALGO_TRACE_SW | */ -/* ALGO_TRACE_SW_DETAIL | */ -/* ALGO_TRACE_SW_EXEC | */ - 0; +/*************************************************** + * helper function + ***************************************************/ +static bool is_any_client_connect_to_ap(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + struct rtl_sta_info *drv_priv; + u8 cnt = 0; + + if (mac->opmode == NL80211_IFTYPE_ADHOC || + mac->opmode == NL80211_IFTYPE_MESH_POINT || + mac->opmode == NL80211_IFTYPE_AP) { + if (in_interrupt() > 0) { + list_for_each_entry(drv_priv, &rtlpriv->entry_list, + list) { + cnt++; + } + } else { + spin_lock_bh(&rtlpriv->locks.entry_list_lock); + list_for_each_entry(drv_priv, &rtlpriv->entry_list, + list) { + cnt++; + } + spin_unlock_bh(&rtlpriv->locks.entry_list_lock); + } + } + if (cnt > 0) + return true; + else + return false; } static bool halbtc_is_bt40(struct rtl_priv *adapter) @@ -188,12 +213,14 @@ static void halbtc_leave_lps(struct btc_coexist *btcoexist) &ap_enable); if (ap_enable) { - pr_info("halbtc_leave_lps()<--dont leave lps under AP mode\n"); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "%s()<--dont leave lps under AP mode\n", __func__); return; } btcoexist->bt_info.bt_ctrl_lps = true; btcoexist->bt_info.bt_lps_on = false; + rtl_lps_leave(rtlpriv->mac80211.hw); } static void halbtc_enter_lps(struct btc_coexist *btcoexist) @@ -209,12 +236,14 @@ static void halbtc_enter_lps(struct btc_coexist *btcoexist) &ap_enable); if (ap_enable) { - pr_info("halbtc_enter_lps()<--dont enter lps under AP mode\n"); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "%s()<--dont enter lps under AP mode\n", __func__); return; } btcoexist->bt_info.bt_ctrl_lps = true; btcoexist->bt_info.bt_lps_on = false; + rtl_lps_enter(rtlpriv->mac80211.hw); } static void halbtc_normal_lps(struct btc_coexist *btcoexist) @@ -233,12 +262,50 @@ static void halbtc_normal_low_power(struct btc_coexist *btcoexist) { } -static void halbtc_disable_low_power(void) +static void halbtc_disable_low_power(struct btc_coexist *btcoexist, + bool low_pwr_disable) { + /* TODO: original/leave 32k low power */ + btcoexist->bt_info.bt_disable_low_pwr = low_pwr_disable; } -static void halbtc_aggregation_check(void) +static void halbtc_aggregation_check(struct btc_coexist *btcoexist) { + bool need_to_act = false; + + /* To void continuous deleteBA=>addBA=>deleteBA=>addBA + * This function is not allowed to continuous called + * It can only be called after 8 seconds + */ + + if (btcoexist->bt_info.reject_agg_pkt) { + ;/* TODO: reject */ + btcoexist->bt_info.pre_reject_agg_pkt = + btcoexist->bt_info.reject_agg_pkt; + } else { + if (btcoexist->bt_info.pre_reject_agg_pkt) { + need_to_act = true; + btcoexist->bt_info.pre_reject_agg_pkt = + btcoexist->bt_info.reject_agg_pkt; + } + + if (btcoexist->bt_info.pre_bt_ctrl_agg_buf_size != + btcoexist->bt_info.bt_ctrl_agg_buf_size) { + need_to_act = true; + btcoexist->bt_info.pre_bt_ctrl_agg_buf_size = + btcoexist->bt_info.bt_ctrl_agg_buf_size; + } + + if (btcoexist->bt_info.bt_ctrl_agg_buf_size) { + if (btcoexist->bt_info.pre_agg_buf_size != + btcoexist->bt_info.agg_buf_size) { + need_to_act = true; + } + btcoexist->bt_info.pre_agg_buf_size = + btcoexist->bt_info.agg_buf_size; + } + } + } static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) @@ -246,10 +313,37 @@ static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) return 0; } -static s32 halbtc_get_wifi_rssi(struct rtl_priv *adapter) +u32 halbtc_get_wifi_link_status(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = adapter; - s32 undec_sm_pwdb = 0; + /* return value: + * [31:16] => connected port number + * [15:0] => port connected bit define + */ + struct rtl_priv *rtlpriv = btcoexist->adapter; + struct rtl_mac *mac = rtl_mac(rtlpriv); + u32 ret_val = 0; + u32 port_connected_status = 0, num_of_connected_port = 0; + + if (mac->opmode == NL80211_IFTYPE_STATION && + mac->link_state >= MAC80211_LINKED) { + port_connected_status |= WIFI_STA_CONNECTED; + num_of_connected_port++; + } + /* AP & ADHOC & MESH */ + if (is_any_client_connect_to_ap(btcoexist)) { + port_connected_status |= WIFI_AP_CONNECTED; + num_of_connected_port++; + } + /* TODO: P2P Connected Status */ + + ret_val = (num_of_connected_port << 16) | port_connected_status; + + return ret_val; +} + +static s32 halbtc_get_wifi_rssi(struct rtl_priv *rtlpriv) +{ + int undec_sm_pwdb = 0; if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb; @@ -282,7 +376,10 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *bool_tmp = false; break; case BTC_GET_BL_WIFI_CONNECTED: - if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION && + rtlpriv->mac80211.link_state >= MAC80211_LINKED) + tmp = true; + if (is_any_client_connect_to_ap(btcoexist)) tmp = true; *bool_tmp = tmp; break; @@ -304,28 +401,18 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) else *bool_tmp = false; break; - case BTC_GET_BL_WIFI_ROAM: /*TODO*/ + case BTC_GET_BL_WIFI_ROAM: if (mac->link_state == MAC80211_LINKING) *bool_tmp = true; else *bool_tmp = false; break; - case BTC_GET_BL_WIFI_4_WAY_PROGRESS: /*TODO*/ - *bool_tmp = false; - - break; - case BTC_GET_BL_WIFI_UNDER_5G: - *bool_tmp = false; /*TODO*/ - - case BTC_GET_BL_WIFI_DHCP: /*TODO*/ - break; - case BTC_GET_BL_WIFI_SOFTAP_IDLE: - *bool_tmp = true; - break; - case BTC_GET_BL_WIFI_SOFTAP_LINKING: + case BTC_GET_BL_WIFI_4_WAY_PROGRESS: + /* TODO */ *bool_tmp = false; break; - case BTC_GET_BL_WIFI_IN_EARLY_SUSPEND: + case BTC_GET_BL_WIFI_UNDER_5G: + /* TODO */ *bool_tmp = false; break; case BTC_GET_BL_WIFI_AP_MODE_ENABLE: @@ -338,15 +425,25 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *bool_tmp = true; break; case BTC_GET_BL_WIFI_UNDER_B_MODE: - *bool_tmp = false; /*TODO*/ + if (rtlpriv->mac80211.mode == WIRELESS_MODE_B) + *bool_tmp = true; + else + *bool_tmp = false; break; case BTC_GET_BL_EXT_SWITCH: *bool_tmp = false; break; + case BTC_GET_BL_WIFI_IS_IN_MP_MODE: + *bool_tmp = false; + break; + case BTC_GET_BL_IS_ASUS_8723B: + *bool_tmp = false; + break; case BTC_GET_S4_WIFI_RSSI: *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); break; - case BTC_GET_S4_HS_RSSI: /*TODO*/ + case BTC_GET_S4_HS_RSSI: + /* TODO */ *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); break; case BTC_GET_U4_WIFI_BW: @@ -359,7 +456,10 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *u32_tmp = BTC_WIFI_TRAFFIC_RX; break; case BTC_GET_U4_WIFI_FW_VER: - *u32_tmp = rtlhal->fw_version; + *u32_tmp = (rtlhal->fw_version << 16) | rtlhal->fw_subversion; + break; + case BTC_GET_U4_WIFI_LINK_STATUS: + *u32_tmp = halbtc_get_wifi_link_status(btcoexist); break; case BTC_GET_U4_BT_PATCH_VER: *u32_tmp = halbtc_get_bt_patch_version(btcoexist); @@ -374,10 +474,19 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *u8_tmp = halbtc_get_wifi_central_chnl(btcoexist); break; case BTC_GET_U1_WIFI_HS_CHNL: - *u8_tmp = 1;/*BT_OperateChnl(rtlpriv);*/ + *u8_tmp = 1; break; - case BTC_GET_U1_MAC_PHY_MODE: - *u8_tmp = BTC_MP_UNKNOWN; + case BTC_GET_U1_AP_NUM: + /* driver do not know AP num, + * so the return value here is not right + */ + *u8_tmp = 1; + break; + case BTC_GET_U1_ANT_TYPE: + *u8_tmp = (u8)BTC_ANT_TYPE_0; + break; + case BTC_GET_U1_IOT_PEER: + *u8_tmp = 0; break; /************* 1Ant **************/ @@ -420,11 +529,17 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) btcoexist->bt_info.reject_agg_pkt = *bool_tmp; break; case BTC_SET_BL_BT_CTRL_AGG_SIZE: - btcoexist->bt_info.bt_ctrl_buf_size = *bool_tmp; + btcoexist->bt_info.bt_ctrl_agg_buf_size = *bool_tmp; break; case BTC_SET_BL_INC_SCAN_DEV_NUM: btcoexist->bt_info.increase_scan_dev_num = *bool_tmp; break; + case BTC_SET_BL_BT_TX_RX_MASK: + btcoexist->bt_info.bt_tx_rx_mask = *bool_tmp; + break; + case BTC_SET_BL_MIRACAST_PLUS_BT: + btcoexist->bt_info.miracast_plus_bt = *bool_tmp; + break; /* set some u1Byte type variables. */ case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON: btcoexist->bt_info.rssi_adjust_for_agc_table_on = *u8_tmp; @@ -432,25 +547,24 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) case BTC_SET_U1_AGG_BUF_SIZE: btcoexist->bt_info.agg_buf_size = *u8_tmp; break; - /* the following are some action which will be triggered */ + + /* the following are some action which will be triggered */ case BTC_SET_ACT_GET_BT_RSSI: - /*BTHCI_SendGetBtRssiEvent(rtlpriv);*/ break; case BTC_SET_ACT_AGGREGATE_CTRL: - halbtc_aggregation_check(); + halbtc_aggregation_check(btcoexist); break; - /* 1Ant */ + /* 1Ant */ case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE: btcoexist->bt_info.rssi_adjust_for_1ant_coex_type = *u8_tmp; break; case BTC_SET_UI_SCAN_SIG_COMPENSATION: - /* rtlpriv->mlmepriv.scan_compensation = *u8_tmp; */ break; - case BTC_SET_U1_1ANT_LPS: + case BTC_SET_U1_LPS_VAL: btcoexist->bt_info.lps_val = *u8_tmp; break; - case BTC_SET_U1_1ANT_RPWM: + case BTC_SET_U1_RPWM_VAL: btcoexist->bt_info.rpwm_val = *u8_tmp; break; /* the following are some action which will be triggered */ @@ -464,20 +578,19 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) halbtc_normal_lps(btcoexist); break; case BTC_SET_ACT_DISABLE_LOW_POWER: - halbtc_disable_low_power(); + halbtc_disable_low_power(btcoexist, *bool_tmp); break; case BTC_SET_ACT_UPDATE_RAMASK: btcoexist->bt_info.ra_mask = *u32_tmp; break; case BTC_SET_ACT_SEND_MIMO_PS: break; - case BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT: - btcoexist->bt_info.force_exec_pwr_cmd_cnt++; - break; case BTC_SET_ACT_CTRL_BT_INFO: /*wait for 8812/8821*/ break; case BTC_SET_ACT_CTRL_BT_COEX: break; + case BTC_SET_ACT_CTRL_8723B_ANT: + break; default: break; } @@ -558,6 +671,35 @@ static void halbtc_write_4byte(void *bt_context, u32 reg_addr, u32 data) rtl_write_dword(rtlpriv, reg_addr, data); } +void halbtc_write_local_reg_1byte(void *btc_context, u32 reg_addr, u8 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + if (btcoexist->chip_interface == BTC_INTF_SDIO) + ; + else if (btcoexist->chip_interface == BTC_INTF_PCI) + rtl_write_byte(rtlpriv, reg_addr, data); + else if (btcoexist->chip_interface == BTC_INTF_USB) + rtl_write_byte(rtlpriv, reg_addr, data); +} + +void halbtc_set_macreg(void *btc_context, u32 reg_addr, u32 bit_mask, u32 data) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + rtl_set_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask, data); +} + +u32 halbtc_get_macreg(void *btc_context, u32 reg_addr, u32 bit_mask) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + + return rtl_get_bbreg(rtlpriv->mac80211.hw, reg_addr, bit_mask); +} + static void halbtc_set_bbreg(void *bt_context, u32 reg_addr, u32 bit_mask, u32 data) { @@ -603,6 +745,37 @@ static void halbtc_fill_h2c_cmd(void *bt_context, u8 element_id, cmd_len, cmd_buf); } +void halbtc_set_bt_reg(void *btc_context, u8 reg_type, u32 offset, u32 set_val) +{ + struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 cmd_buffer1[4] = {0}; + u8 cmd_buffer2[4] = {0}; + u8 *addr_to_set = (u8 *)&offset; + u8 *value_to_set = (u8 *)&set_val; + u8 oper_ver = 0; + u8 req_num = 0; + + if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + cmd_buffer1[0] |= (oper_ver & 0x0f); /* Set OperVer */ + cmd_buffer1[0] |= ((req_num << 4) & 0xf0); /* Set ReqNum */ + cmd_buffer1[1] = 0x0d; /* OpCode: BT_LO_OP_WRITE_REG_VALUE */ + cmd_buffer1[2] = value_to_set[0]; /* Set WriteRegValue */ + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, 0x67, 4, + &cmd_buffer1[0]); + + msleep(200); + req_num++; + + cmd_buffer2[0] |= (oper_ver & 0x0f); /* Set OperVer */ + cmd_buffer2[0] |= ((req_num << 4) & 0xf0); /* Set ReqNum */ + cmd_buffer2[1] = 0x0c; /* OpCode: BT_LO_OP_WRITE_REG_ADDR */ + cmd_buffer2[3] = addr_to_set[0]; /* Set WriteRegAddr */ + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, 0x67, 4, + &cmd_buffer2[0]); + } +} + bool halbtc_under_ips(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -624,26 +797,14 @@ bool halbtc_under_ips(struct btc_coexist *btcoexist) /***************************************************************** * Extern functions called by other module *****************************************************************/ -bool exhalbtc_initlize_variables(struct rtl_priv *adapter) +bool exhalbtc_initlize_variables(void) { struct btc_coexist *btcoexist = &gl_bt_coexist; - btcoexist->statistics.cnt_bind++; - halbtc_dbg_init(); - if (btcoexist->binded) - return false; - else - btcoexist->binded = true; - btcoexist->chip_interface = BTC_INTF_UNKNOWN; - if (NULL == btcoexist->adapter) - btcoexist->adapter = adapter; - - btcoexist->stack_info.profile_notified = false; - btcoexist->btc_read_1byte = halbtc_read_1byte; btcoexist->btc_write_1byte = halbtc_write_1byte; btcoexist->btc_write_1byte_bitmask = halbtc_bitmask_write_1byte; @@ -651,6 +812,7 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) btcoexist->btc_write_2byte = halbtc_write_2byte; btcoexist->btc_read_4byte = halbtc_read_4byte; btcoexist->btc_write_4byte = halbtc_write_4byte; + btcoexist->btc_write_local_reg_1byte = halbtc_write_local_reg_1byte; btcoexist->btc_set_bb_reg = halbtc_set_bbreg; btcoexist->btc_get_bb_reg = halbtc_get_bbreg; @@ -662,6 +824,8 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) btcoexist->btc_get = halbtc_get; btcoexist->btc_set = halbtc_set; + btcoexist->btc_set_bt_reg = halbtc_set_bt_reg; + btcoexist->bt_info.bt_ctrl_buf_size = false; btcoexist->bt_info.agg_buf_size = 5; @@ -1240,11 +1404,6 @@ void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version) btcoexist->bt_info.bt_hci_ver = bt_hci_version; } -void exhalbtc_set_bt_exist(bool bt_exist) -{ - gl_bt_coexist.board_info.bt_exist = bt_exist; -} - void exhalbtc_set_chip_type(u8 chip_type) { switch (chip_type) { @@ -1278,25 +1437,8 @@ void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num) if (BT_COEX_ANT_TYPE_PG == type) { gl_bt_coexist.board_info.pg_ant_num = ant_num; gl_bt_coexist.board_info.btdm_ant_num = ant_num; - /* The antenna position: - * Main (default) or Aux for pgAntNum=2 && btdmAntNum =1. - * The antenna position should be determined by - * auto-detect mechanism. - * The following is assumed to main, - * and those must be modified - * if y auto-detect mechanism is ready - */ - if ((gl_bt_coexist.board_info.pg_ant_num == 2) && - (gl_bt_coexist.board_info.btdm_ant_num == 1)) - gl_bt_coexist.board_info.btdm_ant_pos = - BTC_ANTENNA_AT_MAIN_PORT; - else - gl_bt_coexist.board_info.btdm_ant_pos = - BTC_ANTENNA_AT_MAIN_PORT; } else if (BT_COEX_ANT_TYPE_ANTDIV == type) { gl_bt_coexist.board_info.btdm_ant_num = ant_num; - gl_bt_coexist.board_info.btdm_ant_pos = - BTC_ANTENNA_AT_MAIN_PORT; } else if (type == BT_COEX_ANT_TYPE_DETECTED) { gl_bt_coexist.board_info.btdm_ant_num = ant_num; if (rtlpriv->cfg->mod_params->ant_sel == 1) @@ -1316,11 +1458,25 @@ void exhalbtc_set_single_ant_path(u8 single_ant_path) void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); if (!halbtc_is_bt_coexist_available(btcoexist)) return; - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_btc8723b2ant_display_coex_info(btcoexist); + halbtc_leave_low_power(btcoexist); + + if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8821a2ant_display_coex_info(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8821a1ant_display_coex_info(btcoexist); + } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8723b2ant_display_coex_info(btcoexist); + else if (btcoexist->board_info.btdm_ant_num == 1) + ex_btc8723b1ant_display_coex_info(btcoexist); + } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { + if (btcoexist->board_info.btdm_ant_num == 2) + ex_btc8192e2ant_display_coex_info(btcoexist); + } + + halbtc_normal_low_power(btcoexist); } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 3d34cf83d7fc..32cbbd0595ed 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -218,6 +218,26 @@ enum btc_iot_peer { BTC_IOT_PEER_MAX, }; +/* for 8723b-d cut large current issue */ +enum bt_wifi_coex_state { + BTC_WIFI_STAT_INIT, + BTC_WIFI_STAT_IQK, + BTC_WIFI_STAT_NORMAL_OFF, + BTC_WIFI_STAT_MP_OFF, + BTC_WIFI_STAT_NORMAL, + BTC_WIFI_STAT_ANT_DIV, + BTC_WIFI_STAT_MAX +}; + +enum bt_ant_type { + BTC_ANT_TYPE_0, + BTC_ANT_TYPE_1, + BTC_ANT_TYPE_2, + BTC_ANT_TYPE_3, + BTC_ANT_TYPE_4, + BTC_ANT_TYPE_MAX +}; + enum btc_get_type { /* type bool */ BTC_GET_BL_HS_OPERATION, @@ -238,6 +258,9 @@ enum btc_get_type { BTC_GET_BL_WIFI_UNDER_B_MODE, BTC_GET_BL_EXT_SWITCH, BTC_GET_BL_WIFI_IS_IN_MP_MODE, + BTC_GET_BL_IS_ASUS_8723B, + BTC_GET_BL_FW_READY, + BTC_GET_BL_RF4CE_CONNECTED, /* type s4Byte */ BTC_GET_S4_WIFI_RSSI, @@ -250,6 +273,11 @@ enum btc_get_type { BTC_GET_U4_WIFI_LINK_STATUS, BTC_GET_U4_BT_PATCH_VER, BTC_GET_U4_VENDOR, + BTC_GET_U4_SUPPORTED_VERSION, + BTC_GET_U4_SUPPORTED_FEATURE, + BTC_GET_U4_WIFI_IQK_TOTAL, + BTC_GET_U4_WIFI_IQK_OK, + BTC_GET_U4_WIFI_IQK_FAIL, /* type u1Byte */ BTC_GET_U1_WIFI_DOT11_CHNL, @@ -257,6 +285,7 @@ enum btc_get_type { BTC_GET_U1_WIFI_HS_CHNL, BTC_GET_U1_MAC_PHY_MODE, BTC_GET_U1_AP_NUM, + BTC_GET_U1_ANT_TYPE, BTC_GET_U1_IOT_PEER, /* for 1Ant */ @@ -316,6 +345,7 @@ enum btc_set_type { /* BT Coex related */ BTC_SET_ACT_CTRL_BT_INFO, BTC_SET_ACT_CTRL_BT_COEX, + BTC_SET_ACT_CTRL_8723B_ANT, /***************************/ BTC_SET_MAX }; @@ -569,7 +599,7 @@ bool halbtc_is_wifi_uplink(struct rtl_priv *adapter); extern struct btc_coexist gl_bt_coexist; -bool exhalbtc_initlize_variables(struct rtl_priv *adapter); +bool exhalbtc_initlize_variables(void); void exhalbtc_init_hw_config(struct btc_coexist *btcoexist); void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist); void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index dec9d83f87af..3ab0cfe26513 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -49,7 +49,7 @@ static struct rtl_btc_ops rtl_btc_operation = { void rtl_btc_init_variables(struct rtl_priv *rtlpriv) { - exhalbtc_initlize_variables(rtlpriv); + exhalbtc_initlize_variables(); } void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv) @@ -105,7 +105,9 @@ void rtl_btc_periodical(struct rtl_priv *rtlpriv) void rtl_btc_halt_notify(void) { - exhalbtc_halt_notify(&gl_bt_coexist); + struct btc_coexist *btcoexist = &gl_bt_coexist; + + exhalbtc_halt_notify(btcoexist); } void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length) -- cgit v1.2.3 From 1abf9ae719f6de71fb90d3169d575630be612619 Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Thu, 8 Jun 2017 15:33:03 +0530 Subject: mwifiex: Replace semaphore async_sem with mutex The semaphore 'async_sem' is used as a simple mutex, so it should be written as one. Semaphores are going away in the future. Signed-off-by: Binoy Jayan Reviewed-by: Arnd Bergmann Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 2 +- drivers/net/wireless/marvell/mwifiex/main.h | 2 +- drivers/net/wireless/marvell/mwifiex/scan.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 025bc06a19d6..feb2ce3082d8 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -3033,7 +3033,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, INIT_DELAYED_WORK(&priv->dfs_chan_sw_work, mwifiex_dfs_chan_sw_work_queue); - sema_init(&priv->async_sem, 1); + mutex_init(&priv->async_mutex); /* Register network device */ if (register_netdevice(dev)) { diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index c37fb2606502..f8cf3079ac7d 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -629,7 +629,7 @@ struct mwifiex_private { struct dentry *dfs_dev_dir; #endif u16 current_key_index; - struct semaphore async_sem; + struct mutex async_mutex; struct cfg80211_scan_request *scan_request; u8 cfg_bssid[6]; struct wps wps; diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index ce6936d0c5c0..ae9630b49342 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -2809,7 +2809,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv, { int ret; - if (down_interruptible(&priv->async_sem)) { + if (mutex_lock_interruptible(&priv->async_mutex)) { mwifiex_dbg(priv->adapter, ERROR, "%s: acquire semaphore fail\n", __func__); @@ -2825,7 +2825,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv, /* Normal scan */ ret = mwifiex_scan_networks(priv, NULL); - up(&priv->async_sem); + mutex_unlock(&priv->async_mutex); return ret; } -- cgit v1.2.3 From 078b30da3f074f2e9ebcf1a18e993b27e22eb3ba Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 8 Jun 2017 22:50:00 +0200 Subject: wlcore: add wl1285 compatible Motorola Droid 4 uses a WL 1285C. With differences between chips not being public let's add explicit binding for wl1285 instead of relying on wl1283 being very similar. Reviewed-by: Rob Herring Acked-by: Kalle Valo Acked-by: Tony Lindgren Signed-off-by: Sebastian Reichel Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/sdio.c | 1 + drivers/net/wireless/ti/wlcore/spi.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 287023ef4a78..2fb38717346f 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -237,6 +237,7 @@ static const struct of_device_id wlcore_sdio_of_match_table[] = { { .compatible = "ti,wl1273", .data = &wl127x_data }, { .compatible = "ti,wl1281", .data = &wl128x_data }, { .compatible = "ti,wl1283", .data = &wl128x_data }, + { .compatible = "ti,wl1285", .data = &wl128x_data }, { .compatible = "ti,wl1801", .data = &wl18xx_data }, { .compatible = "ti,wl1805", .data = &wl18xx_data }, { .compatible = "ti,wl1807", .data = &wl18xx_data }, diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index fa3547e06424..698bfa99cfa2 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -433,6 +433,7 @@ static const struct of_device_id wlcore_spi_of_match_table[] = { { .compatible = "ti,wl1273", .data = &wl127x_data}, { .compatible = "ti,wl1281", .data = &wl128x_data}, { .compatible = "ti,wl1283", .data = &wl128x_data}, + { .compatible = "ti,wl1285", .data = &wl128x_data}, { .compatible = "ti,wl1801", .data = &wl18xx_data}, { .compatible = "ti,wl1805", .data = &wl18xx_data}, { .compatible = "ti,wl1807", .data = &wl18xx_data}, -- cgit v1.2.3 From c48c281e7236fc8769dd62e6b13ba090a546027d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 8 Jun 2017 22:24:30 -0500 Subject: wlcore: spi: remove unnecessary variable Remove unnecessary variable and refactor the code. Addresses-Coverity-ID: 1365000 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/spi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 698bfa99cfa2..fdabb9242cca 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -366,17 +366,14 @@ static int __wl12xx_spi_raw_write(struct device *child, int addr, static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, void *buf, size_t len, bool fixed) { - int ret; - /* The ELP wakeup write may fail the first time due to internal * hardware latency. It is safer to send the wakeup command twice to * avoid unexpected failures. */ if (addr == HW_ACCESS_ELP_CTRL_REG) - ret = __wl12xx_spi_raw_write(child, addr, buf, len, fixed); - ret = __wl12xx_spi_raw_write(child, addr, buf, len, fixed); + __wl12xx_spi_raw_write(child, addr, buf, len, fixed); - return ret; + return __wl12xx_spi_raw_write(child, addr, buf, len, fixed); } /** -- cgit v1.2.3 From 5f83dc93b242e16bf45bbea785ace4268828ce01 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:33 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Status macros For implicit namespacing and clarity, prefix the common Port Status Register macros with MV88E6XXX_PORT_STS and the ones which differ between implementations with a chosen reference model (e.g. MV88E6352_PORT_STS_EEE.) Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 4 ++-- drivers/net/dsa/mv88e6xxx/port.c | 20 ++++++++-------- drivers/net/dsa/mv88e6xxx/port.h | 48 ++++++++++++++++++++------------------ drivers/net/dsa/mv88e6xxx/serdes.c | 38 +++++++++++++++--------------- 4 files changed, 56 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index a4cf0366765f..0a2bac1cde44 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -828,11 +828,11 @@ static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, e->eee_enabled = !!(reg & 0x0200); e->tx_lpi_enabled = !!(reg & 0x0100); - err = mv88e6xxx_port_read(chip, port, PORT_STATUS, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); if (err) goto out; - e->eee_active = !!(reg & PORT_STATUS_EEE); + e->eee_active = !!(reg & MV88E6352_PORT_STS_EEE); out: mutex_unlock(&chip->reg_lock); diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index efeb8d6b02e6..906b9112e28c 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -322,33 +322,33 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, switch (mode) { case PHY_INTERFACE_MODE_1000BASEX: - cmode = PORT_STATUS_CMODE_1000BASE_X; + cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X; break; case PHY_INTERFACE_MODE_SGMII: - cmode = PORT_STATUS_CMODE_SGMII; + cmode = MV88E6XXX_PORT_STS_CMODE_SGMII; break; case PHY_INTERFACE_MODE_2500BASEX: - cmode = PORT_STATUS_CMODE_2500BASEX; + cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX; break; case PHY_INTERFACE_MODE_XGMII: - cmode = PORT_STATUS_CMODE_XAUI; + cmode = MV88E6XXX_PORT_STS_CMODE_XAUI; break; case PHY_INTERFACE_MODE_RXAUI: - cmode = PORT_STATUS_CMODE_RXAUI; + cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI; break; default: cmode = 0; } if (cmode) { - err = mv88e6xxx_port_read(chip, port, PORT_STATUS, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); if (err) return err; - reg &= ~PORT_STATUS_CMODE_MASK; + reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK; reg |= cmode; - err = mv88e6xxx_port_write(chip, port, PORT_STATUS, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg); if (err) return err; } @@ -361,11 +361,11 @@ int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) int err; u16 reg; - err = mv88e6xxx_port_read(chip, port, PORT_STATUS, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); if (err) return err; - *cmode = reg & PORT_STATUS_CMODE_MASK; + *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK; return 0; } diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 8a59cabc20fa..be7cfd979e49 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -17,29 +17,31 @@ #include "chip.h" -#define PORT_STATUS 0x00 -#define PORT_STATUS_PAUSE_EN BIT(15) -#define PORT_STATUS_MY_PAUSE BIT(14) -#define PORT_STATUS_HD_FLOW BIT(13) -#define PORT_STATUS_PHY_DETECT BIT(12) -#define PORT_STATUS_LINK BIT(11) -#define PORT_STATUS_DUPLEX BIT(10) -#define PORT_STATUS_SPEED_MASK 0x0300 -#define PORT_STATUS_SPEED_10 0x0000 -#define PORT_STATUS_SPEED_100 0x0100 -#define PORT_STATUS_SPEED_1000 0x0200 -#define PORT_STATUS_EEE BIT(6) /* 6352 */ -#define PORT_STATUS_AM_DIS BIT(6) /* 6165 */ -#define PORT_STATUS_MGMII BIT(6) /* 6185 */ -#define PORT_STATUS_TX_PAUSED BIT(5) -#define PORT_STATUS_FLOW_CTRL BIT(4) -#define PORT_STATUS_CMODE_MASK 0x0f -#define PORT_STATUS_CMODE_100BASE_X 0x8 -#define PORT_STATUS_CMODE_1000BASE_X 0x9 -#define PORT_STATUS_CMODE_SGMII 0xa -#define PORT_STATUS_CMODE_2500BASEX 0xb -#define PORT_STATUS_CMODE_XAUI 0xc -#define PORT_STATUS_CMODE_RXAUI 0xd +/* Offset 0x00: Port Status Register */ +#define MV88E6XXX_PORT_STS 0x00 +#define MV88E6XXX_PORT_STS_PAUSE_EN 0x8000 +#define MV88E6XXX_PORT_STS_MY_PAUSE 0x4000 +#define MV88E6XXX_PORT_STS_HD_FLOW 0x2000 +#define MV88E6XXX_PORT_STS_PHY_DETECT 0x1000 +#define MV88E6XXX_PORT_STS_LINK 0x0800 +#define MV88E6XXX_PORT_STS_DUPLEX 0x0400 +#define MV88E6XXX_PORT_STS_SPEED_MASK 0x0300 +#define MV88E6XXX_PORT_STS_SPEED_10 0x0000 +#define MV88E6XXX_PORT_STS_SPEED_100 0x0100 +#define MV88E6XXX_PORT_STS_SPEED_1000 0x0200 +#define MV88E6352_PORT_STS_EEE 0x0040 +#define MV88E6165_PORT_STS_AM_DIS 0x0040 +#define MV88E6185_PORT_STS_MGMII 0x0040 +#define MV88E6XXX_PORT_STS_TX_PAUSED 0x0020 +#define MV88E6XXX_PORT_STS_FLOW_CTL 0x0010 +#define MV88E6XXX_PORT_STS_CMODE_MASK 0x000f +#define MV88E6XXX_PORT_STS_CMODE_100BASE_X 0x0008 +#define MV88E6XXX_PORT_STS_CMODE_1000BASE_X 0x0009 +#define MV88E6XXX_PORT_STS_CMODE_SGMII 0x000a +#define MV88E6XXX_PORT_STS_CMODE_2500BASEX 0x000b +#define MV88E6XXX_PORT_STS_CMODE_XAUI 0x000c +#define MV88E6XXX_PORT_STS_CMODE_RXAUI 0x000d + #define PORT_PCS_CTRL 0x01 #define PORT_PCS_CTRL_RGMII_DELAY_RXCLK BIT(15) #define PORT_PCS_CTRL_RGMII_DELAY_TXCLK BIT(14) diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 78f5b1eb44ea..411b4f522792 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -64,9 +64,9 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) if (err) return err; - if ((cmode == PORT_STATUS_CMODE_100BASE_X) || - (cmode == PORT_STATUS_CMODE_1000BASE_X) || - (cmode == PORT_STATUS_CMODE_SGMII)) { + if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASE_X) || + (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) || + (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)) { err = mv88e6352_serdes_power_set(chip, on); if (err < 0) return err; @@ -139,15 +139,15 @@ static int mv88e6390_serdes_lower(struct mv88e6xxx_chip *chip, u8 cmode, return err; switch (cmode_donor) { - case PORT_STATUS_CMODE_RXAUI: + case MV88E6XXX_PORT_STS_CMODE_RXAUI: if (!rxaui) break; /* Fall through */ - case PORT_STATUS_CMODE_1000BASE_X: - case PORT_STATUS_CMODE_SGMII: - case PORT_STATUS_CMODE_2500BASEX: - if (cmode == PORT_STATUS_CMODE_1000BASE_X || - cmode == PORT_STATUS_CMODE_SGMII) + case MV88E6XXX_PORT_STS_CMODE_1000BASE_X: + case MV88E6XXX_PORT_STS_CMODE_SGMII: + case MV88E6XXX_PORT_STS_CMODE_2500BASEX: + if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || + cmode == MV88E6XXX_PORT_STS_CMODE_SGMII) return mv88e6390_serdes_sgmii(chip, lane, on); } return 0; @@ -157,12 +157,12 @@ static int mv88e6390_serdes_port9(struct mv88e6xxx_chip *chip, u8 cmode, bool on) { switch (cmode) { - case PORT_STATUS_CMODE_1000BASE_X: - case PORT_STATUS_CMODE_SGMII: + case MV88E6XXX_PORT_STS_CMODE_1000BASE_X: + case MV88E6XXX_PORT_STS_CMODE_SGMII: return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT9_LANE0, on); - case PORT_STATUS_CMODE_XAUI: - case PORT_STATUS_CMODE_RXAUI: - case PORT_STATUS_CMODE_2500BASEX: + case MV88E6XXX_PORT_STS_CMODE_XAUI: + case MV88E6XXX_PORT_STS_CMODE_RXAUI: + case MV88E6XXX_PORT_STS_CMODE_2500BASEX: return mv88e6390_serdes_10g(chip, MV88E6390_PORT9_LANE0, on); } @@ -173,12 +173,12 @@ static int mv88e6390_serdes_port10(struct mv88e6xxx_chip *chip, u8 cmode, bool on) { switch (cmode) { - case PORT_STATUS_CMODE_SGMII: + case MV88E6XXX_PORT_STS_CMODE_SGMII: return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT10_LANE0, on); - case PORT_STATUS_CMODE_XAUI: - case PORT_STATUS_CMODE_RXAUI: - case PORT_STATUS_CMODE_1000BASE_X: - case PORT_STATUS_CMODE_2500BASEX: + case MV88E6XXX_PORT_STS_CMODE_XAUI: + case MV88E6XXX_PORT_STS_CMODE_RXAUI: + case MV88E6XXX_PORT_STS_CMODE_1000BASE_X: + case MV88E6XXX_PORT_STS_CMODE_2500BASEX: return mv88e6390_serdes_10g(chip, MV88E6390_PORT10_LANE0, on); } -- cgit v1.2.3 From 5ee55577cfe4a3ef6ae34d804806b1c6c9ae159a Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:34 -0400 Subject: net: dsa: mv88e6xxx: prefix Port MAC Control macros For implicit namespacing and clarity, prefix the common MAC Control Register macros with MV88E6XXX_PORT_MAC_CTL and the ones which differ between implementations with a chosen reference model (e.g. MV88E6065_PORT_MAC_CTL_SPEED_200.) Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/port.c | 80 +++++++++++++++++++++------------------- drivers/net/dsa/mv88e6xxx/port.h | 40 ++++++++++---------- 2 files changed, 64 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 906b9112e28c..60c31b6c2f47 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -49,23 +49,23 @@ static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); if (err) return err; - reg &= ~(PORT_PCS_CTRL_RGMII_DELAY_RXCLK | - PORT_PCS_CTRL_RGMII_DELAY_TXCLK); + reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK | + MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK); switch (mode) { case PHY_INTERFACE_MODE_RGMII_RXID: - reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK; + reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK; break; case PHY_INTERFACE_MODE_RGMII_TXID: - reg |= PORT_PCS_CTRL_RGMII_DELAY_TXCLK; + reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK; break; case PHY_INTERFACE_MODE_RGMII_ID: - reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK | - PORT_PCS_CTRL_RGMII_DELAY_TXCLK; + reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK | + MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK; break; case PHY_INTERFACE_MODE_RGMII: break; @@ -73,13 +73,13 @@ static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, return 0; } - err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); if (err) return err; dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port, - reg & PORT_PCS_CTRL_RGMII_DELAY_RXCLK ? "yes" : "no", - reg & PORT_PCS_CTRL_RGMII_DELAY_TXCLK ? "yes" : "no"); + reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no", + reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no"); return 0; } @@ -107,18 +107,20 @@ int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); if (err) return err; - reg &= ~(PORT_PCS_CTRL_FORCE_LINK | PORT_PCS_CTRL_LINK_UP); + reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK | + MV88E6XXX_PORT_MAC_CTL_LINK_UP); switch (link) { case LINK_FORCED_DOWN: - reg |= PORT_PCS_CTRL_FORCE_LINK; + reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK; break; case LINK_FORCED_UP: - reg |= PORT_PCS_CTRL_FORCE_LINK | PORT_PCS_CTRL_LINK_UP; + reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK | + MV88E6XXX_PORT_MAC_CTL_LINK_UP; break; case LINK_UNFORCED: /* normal link detection */ @@ -127,13 +129,13 @@ int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) return -EINVAL; } - err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); if (err) return err; dev_dbg(chip->dev, "p%d: %s link %s\n", port, - reg & PORT_PCS_CTRL_FORCE_LINK ? "Force" : "Unforce", - reg & PORT_PCS_CTRL_LINK_UP ? "up" : "down"); + reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce", + reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down"); return 0; } @@ -143,18 +145,20 @@ int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup) u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); if (err) return err; - reg &= ~(PORT_PCS_CTRL_FORCE_DUPLEX | PORT_PCS_CTRL_DUPLEX_FULL); + reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | + MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL); switch (dup) { case DUPLEX_HALF: - reg |= PORT_PCS_CTRL_FORCE_DUPLEX; + reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX; break; case DUPLEX_FULL: - reg |= PORT_PCS_CTRL_FORCE_DUPLEX | PORT_PCS_CTRL_DUPLEX_FULL; + reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | + MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL; break; case DUPLEX_UNFORCED: /* normal duplex detection */ @@ -163,13 +167,13 @@ int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup) return -EINVAL; } - err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); if (err) return err; dev_dbg(chip->dev, "p%d: %s %s duplex\n", port, - reg & PORT_PCS_CTRL_FORCE_DUPLEX ? "Force" : "Unforce", - reg & PORT_PCS_CTRL_DUPLEX_FULL ? "full" : "half"); + reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce", + reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half"); return 0; } @@ -182,47 +186,49 @@ static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port, switch (speed) { case 10: - ctrl = PORT_PCS_CTRL_SPEED_10; + ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10; break; case 100: - ctrl = PORT_PCS_CTRL_SPEED_100; + ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100; break; case 200: if (alt_bit) - ctrl = PORT_PCS_CTRL_SPEED_100 | PORT_PCS_CTRL_ALTSPEED; + ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 | + MV88E6390_PORT_MAC_CTL_ALTSPEED; else - ctrl = PORT_PCS_CTRL_SPEED_200; + ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200; break; case 1000: - ctrl = PORT_PCS_CTRL_SPEED_1000; + ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000; break; case 2500: - ctrl = PORT_PCS_CTRL_SPEED_10000 | PORT_PCS_CTRL_ALTSPEED; + ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 | + MV88E6390_PORT_MAC_CTL_ALTSPEED; break; case 10000: /* all bits set, fall through... */ case SPEED_UNFORCED: - ctrl = PORT_PCS_CTRL_SPEED_UNFORCED; + ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED; break; default: return -EOPNOTSUPP; } - err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); if (err) return err; - reg &= ~PORT_PCS_CTRL_SPEED_MASK; + reg &= ~MV88E6XXX_PORT_MAC_CTL_SPEED_MASK; if (alt_bit) - reg &= ~PORT_PCS_CTRL_ALTSPEED; + reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED; if (force_bit) { - reg &= ~PORT_PCS_CTRL_FORCE_SPEED; + reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED; if (speed != SPEED_UNFORCED) - ctrl |= PORT_PCS_CTRL_FORCE_SPEED; + ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED; } reg |= ctrl; - err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index be7cfd979e49..260096b34d2b 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -42,25 +42,27 @@ #define MV88E6XXX_PORT_STS_CMODE_XAUI 0x000c #define MV88E6XXX_PORT_STS_CMODE_RXAUI 0x000d -#define PORT_PCS_CTRL 0x01 -#define PORT_PCS_CTRL_RGMII_DELAY_RXCLK BIT(15) -#define PORT_PCS_CTRL_RGMII_DELAY_TXCLK BIT(14) -#define PORT_PCS_CTRL_FORCE_SPEED BIT(13) /* 6390 */ -#define PORT_PCS_CTRL_ALTSPEED BIT(12) /* 6390 */ -#define PORT_PCS_CTRL_200BASE BIT(12) /* 6352 */ -#define PORT_PCS_CTRL_FC BIT(7) -#define PORT_PCS_CTRL_FORCE_FC BIT(6) -#define PORT_PCS_CTRL_LINK_UP BIT(5) -#define PORT_PCS_CTRL_FORCE_LINK BIT(4) -#define PORT_PCS_CTRL_DUPLEX_FULL BIT(3) -#define PORT_PCS_CTRL_FORCE_DUPLEX BIT(2) -#define PORT_PCS_CTRL_SPEED_MASK (0x03) -#define PORT_PCS_CTRL_SPEED_10 (0x00) -#define PORT_PCS_CTRL_SPEED_100 (0x01) -#define PORT_PCS_CTRL_SPEED_200 (0x02) /* 6065 and non Gb chips */ -#define PORT_PCS_CTRL_SPEED_1000 (0x02) -#define PORT_PCS_CTRL_SPEED_10000 (0x03) /* 6390X */ -#define PORT_PCS_CTRL_SPEED_UNFORCED (0x03) +/* Offset 0x01: MAC (or PCS or Physical) Control Register */ +#define MV88E6XXX_PORT_MAC_CTL 0x01 +#define MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK 0x8000 +#define MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK 0x4000 +#define MV88E6390_PORT_MAC_CTL_FORCE_SPEED 0x2000 +#define MV88E6390_PORT_MAC_CTL_ALTSPEED 0x1000 +#define MV88E6352_PORT_MAC_CTL_200BASE 0x1000 +#define MV88E6XXX_PORT_MAC_CTL_FC 0x0080 +#define MV88E6XXX_PORT_MAC_CTL_FORCE_FC 0x0040 +#define MV88E6XXX_PORT_MAC_CTL_LINK_UP 0x0020 +#define MV88E6XXX_PORT_MAC_CTL_FORCE_LINK 0x0010 +#define MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL 0x0008 +#define MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX 0x0004 +#define MV88E6XXX_PORT_MAC_CTL_SPEED_MASK 0x0003 +#define MV88E6XXX_PORT_MAC_CTL_SPEED_10 0x0000 +#define MV88E6XXX_PORT_MAC_CTL_SPEED_100 0x0001 +#define MV88E6065_PORT_MAC_CTL_SPEED_200 0x0002 +#define MV88E6XXX_PORT_MAC_CTL_SPEED_1000 0x0002 +#define MV88E6390_PORT_MAC_CTL_SPEED_10000 0x0003 +#define MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED 0x0003 + #define PORT_PAUSE_CTRL 0x02 #define PORT_FLOW_CTRL_LIMIT_IN ((0x00 << 8) | BIT(15)) #define PORT_FLOW_CTRL_LIMIT_OUT ((0x01 << 8) | BIT(15)) -- cgit v1.2.3 From 6c96bbfdd08d422395c06516617e006833f7b540 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:35 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Jamming macros For implicit namespacing and clarity, prefix the common Port Jamming Control Register macros with MV88E6XXX_PORT_JAM_CTL and the ones which differ between implementations with a chosen reference model (e.g. MV88E6097_PORT_JAM_CTL.) The 88E6390 family renamed the register to Flow Control and turned it into an indirect table. Document that as well. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/port.c | 15 +++++++++------ drivers/net/dsa/mv88e6xxx/port.h | 16 +++++++++++++--- 2 files changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 60c31b6c2f47..615b8843ad8e 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -376,7 +376,7 @@ int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) return 0; } -/* Offset 0x02: Pause Control +/* Offset 0x02: Jamming Control * * Do not limit the period of time that this port can be paused for by * the remote end or the period of time that this port can pause the @@ -385,7 +385,8 @@ int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, u8 out) { - return mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, out << 8 | in); + return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL, + out << 8 | in); } int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, @@ -393,13 +394,15 @@ int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, { int err; - err = mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, - PORT_FLOW_CTRL_LIMIT_IN | in); + err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL, + MV88E6390_PORT_FLOW_CTL_UPDATE | + MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in); if (err) return err; - return mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, - PORT_FLOW_CTRL_LIMIT_OUT | out); + return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL, + MV88E6390_PORT_FLOW_CTL_UPDATE | + MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out); } /* Offset 0x04: Port Control Register */ diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 260096b34d2b..5226a0651d8e 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -63,9 +63,19 @@ #define MV88E6390_PORT_MAC_CTL_SPEED_10000 0x0003 #define MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED 0x0003 -#define PORT_PAUSE_CTRL 0x02 -#define PORT_FLOW_CTRL_LIMIT_IN ((0x00 << 8) | BIT(15)) -#define PORT_FLOW_CTRL_LIMIT_OUT ((0x01 << 8) | BIT(15)) +/* Offset 0x02: Jamming Control Register */ +#define MV88E6097_PORT_JAM_CTL 0x02 +#define MV88E6097_PORT_JAM_CTL_LIMIT_OUT_MASK 0xff00 +#define MV88E6097_PORT_JAM_CTL_LIMIT_IN_MASK 0x00ff + +/* Offset 0x02: Flow Control Register */ +#define MV88E6390_PORT_FLOW_CTL 0x02 +#define MV88E6390_PORT_FLOW_CTL_UPDATE 0x8000 +#define MV88E6390_PORT_FLOW_CTL_PTR_MASK 0x7f00 +#define MV88E6390_PORT_FLOW_CTL_LIMIT_IN 0x0000 +#define MV88E6390_PORT_FLOW_CTL_LIMIT_OUT 0x0100 +#define MV88E6390_PORT_FLOW_CTL_DATA_MASK 0x00ff + #define PORT_SWITCH_ID 0x03 #define PORT_SWITCH_ID_PROD_NUM_6085 0x04a #define PORT_SWITCH_ID_PROD_NUM_6095 0x095 -- cgit v1.2.3 From 107fcc10e810be24631bf54d35970071b110ad10 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:36 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Switch ID macros For implicit namespacing and clarity, prefix the common Switch ID Register macros with MV88E6XXX_PORT_SWITCH_ID. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers, this means shifting their values by 4. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 60 ++++++++++++++++++++-------------------- drivers/net/dsa/mv88e6xxx/port.h | 58 ++++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 0a2bac1cde44..7d0868a45cdc 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2181,7 +2181,7 @@ static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) * the mv88e6390 family model number instead. */ if (!(val & 0x3f0)) - val |= PORT_SWITCH_ID_PROD_NUM_6390; + val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4; } return err ? err : val; @@ -3162,7 +3162,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { static const struct mv88e6xxx_info mv88e6xxx_table[] = { [MV88E6085] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6085, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, .family = MV88E6XXX_FAMILY_6097, .name = "Marvell 88E6085", .num_databases = 4096, @@ -3180,7 +3180,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6095] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6095, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095, .family = MV88E6XXX_FAMILY_6095, .name = "Marvell 88E6095/88E6095F", .num_databases = 256, @@ -3197,7 +3197,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6097] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6097, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097, .family = MV88E6XXX_FAMILY_6097, .name = "Marvell 88E6097/88E6097F", .num_databases = 4096, @@ -3215,7 +3215,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6123] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6123, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123, .family = MV88E6XXX_FAMILY_6165, .name = "Marvell 88E6123", .num_databases = 4096, @@ -3233,7 +3233,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6131] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6131, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131, .family = MV88E6XXX_FAMILY_6185, .name = "Marvell 88E6131", .num_databases = 256, @@ -3250,7 +3250,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6141] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6141, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141, .family = MV88E6XXX_FAMILY_6341, .name = "Marvell 88E6341", .num_databases = 4096, @@ -3267,7 +3267,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6161] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6161, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161, .family = MV88E6XXX_FAMILY_6165, .name = "Marvell 88E6161", .num_databases = 4096, @@ -3285,7 +3285,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6165] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6165, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165, .family = MV88E6XXX_FAMILY_6165, .name = "Marvell 88E6165", .num_databases = 4096, @@ -3303,7 +3303,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6171] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6171, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171, .family = MV88E6XXX_FAMILY_6351, .name = "Marvell 88E6171", .num_databases = 4096, @@ -3321,7 +3321,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6172] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6172, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172, .family = MV88E6XXX_FAMILY_6352, .name = "Marvell 88E6172", .num_databases = 4096, @@ -3339,7 +3339,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6175] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6175, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175, .family = MV88E6XXX_FAMILY_6351, .name = "Marvell 88E6175", .num_databases = 4096, @@ -3357,7 +3357,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6176] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6176, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176, .family = MV88E6XXX_FAMILY_6352, .name = "Marvell 88E6176", .num_databases = 4096, @@ -3375,7 +3375,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6185] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6185, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185, .family = MV88E6XXX_FAMILY_6185, .name = "Marvell 88E6185", .num_databases = 256, @@ -3392,7 +3392,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6190] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6190, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190, .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6190", .num_databases = 4096, @@ -3410,7 +3410,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6190X] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6190X, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X, .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6190X", .num_databases = 4096, @@ -3428,7 +3428,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6191] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6191, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191, .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6191", .num_databases = 4096, @@ -3446,7 +3446,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6240] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6240, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240, .family = MV88E6XXX_FAMILY_6352, .name = "Marvell 88E6240", .num_databases = 4096, @@ -3464,7 +3464,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6290] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6290, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290, .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6290", .num_databases = 4096, @@ -3482,7 +3482,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6320] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6320, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320, .family = MV88E6XXX_FAMILY_6320, .name = "Marvell 88E6320", .num_databases = 4096, @@ -3500,7 +3500,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6321] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6321, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321, .family = MV88E6XXX_FAMILY_6320, .name = "Marvell 88E6321", .num_databases = 4096, @@ -3517,7 +3517,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6341] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6341, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, .family = MV88E6XXX_FAMILY_6341, .name = "Marvell 88E6341", .num_databases = 4096, @@ -3534,7 +3534,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6350] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6350, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350, .family = MV88E6XXX_FAMILY_6351, .name = "Marvell 88E6350", .num_databases = 4096, @@ -3552,7 +3552,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6351] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6351, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351, .family = MV88E6XXX_FAMILY_6351, .name = "Marvell 88E6351", .num_databases = 4096, @@ -3570,7 +3570,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, [MV88E6352] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6352, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352, .family = MV88E6XXX_FAMILY_6352, .name = "Marvell 88E6352", .num_databases = 4096, @@ -3587,7 +3587,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .ops = &mv88e6352_ops, }, [MV88E6390] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6390, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6390", .num_databases = 4096, @@ -3604,7 +3604,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .ops = &mv88e6390_ops, }, [MV88E6390X] = { - .prod_num = PORT_SWITCH_ID_PROD_NUM_6390X, + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X, .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6390X", .num_databases = 4096, @@ -3641,13 +3641,13 @@ static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip) int err; mutex_lock(&chip->reg_lock); - err = mv88e6xxx_port_read(chip, 0, PORT_SWITCH_ID, &id); + err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id); mutex_unlock(&chip->reg_lock); if (err) return err; - prod_num = (id & 0xfff0) >> 4; - rev = id & 0x000f; + prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK; + rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK; info = mv88e6xxx_lookup_info(prod_num); if (!info) diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 5226a0651d8e..dc99c3159038 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -76,33 +76,37 @@ #define MV88E6390_PORT_FLOW_CTL_LIMIT_OUT 0x0100 #define MV88E6390_PORT_FLOW_CTL_DATA_MASK 0x00ff -#define PORT_SWITCH_ID 0x03 -#define PORT_SWITCH_ID_PROD_NUM_6085 0x04a -#define PORT_SWITCH_ID_PROD_NUM_6095 0x095 -#define PORT_SWITCH_ID_PROD_NUM_6097 0x099 -#define PORT_SWITCH_ID_PROD_NUM_6131 0x106 -#define PORT_SWITCH_ID_PROD_NUM_6320 0x115 -#define PORT_SWITCH_ID_PROD_NUM_6123 0x121 -#define PORT_SWITCH_ID_PROD_NUM_6141 0x340 -#define PORT_SWITCH_ID_PROD_NUM_6161 0x161 -#define PORT_SWITCH_ID_PROD_NUM_6165 0x165 -#define PORT_SWITCH_ID_PROD_NUM_6171 0x171 -#define PORT_SWITCH_ID_PROD_NUM_6172 0x172 -#define PORT_SWITCH_ID_PROD_NUM_6175 0x175 -#define PORT_SWITCH_ID_PROD_NUM_6176 0x176 -#define PORT_SWITCH_ID_PROD_NUM_6185 0x1a7 -#define PORT_SWITCH_ID_PROD_NUM_6190 0x190 -#define PORT_SWITCH_ID_PROD_NUM_6190X 0x0a0 -#define PORT_SWITCH_ID_PROD_NUM_6191 0x191 -#define PORT_SWITCH_ID_PROD_NUM_6240 0x240 -#define PORT_SWITCH_ID_PROD_NUM_6290 0x290 -#define PORT_SWITCH_ID_PROD_NUM_6321 0x310 -#define PORT_SWITCH_ID_PROD_NUM_6341 0x341 -#define PORT_SWITCH_ID_PROD_NUM_6352 0x352 -#define PORT_SWITCH_ID_PROD_NUM_6350 0x371 -#define PORT_SWITCH_ID_PROD_NUM_6351 0x375 -#define PORT_SWITCH_ID_PROD_NUM_6390 0x390 -#define PORT_SWITCH_ID_PROD_NUM_6390X 0x0a1 +/* Offset 0x03: Switch Identifier Register */ +#define MV88E6XXX_PORT_SWITCH_ID 0x03 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_MASK 0xfff0 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6085 0x04a0 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6095 0x0950 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6097 0x0990 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6190X 0x0a00 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6390X 0x0a10 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6131 0x1060 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6320 0x1150 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6123 0x1210 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6161 0x1610 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6165 0x1650 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6171 0x1710 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6172 0x1720 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6175 0x1750 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6176 0x1760 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6190 0x1900 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6191 0x1910 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6185 0x1a70 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6290 0x2900 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6321 0x3100 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6141 0x3400 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6341 0x3410 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6352 0x3520 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6350 0x3710 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6351 0x3750 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6390 0x3900 +#define MV88E6XXX_PORT_SWITCH_ID_REV_MASK 0x000f + #define PORT_CONTROL 0x04 #define PORT_CONTROL_USE_CORE_TAG BIT(15) #define PORT_CONTROL_DROP_ON_LOCK BIT(14) -- cgit v1.2.3 From a89b433bee684aeb5535b186d88bac17516380e8 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:37 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Control macros For implicit namespacing and clarity, prefix the common Port Control Register macros with MV88E6XXX_PORT_CTL0 and the ones which differ between implementations with a chosen reference model (e.g. MV88E6185_PORT_CTL0_USE_TAG.) The reason for CTL0 is to make it clear between the badly named "Port Control", "Port Control 1" and "Port Control 2" registers. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 8 ++-- drivers/net/dsa/mv88e6xxx/port.c | 82 ++++++++++++++++++++-------------------- drivers/net/dsa/mv88e6xxx/port.h | 66 ++++++++++++++++---------------- 3 files changed, 79 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 7d0868a45cdc..b1a8cbe1c215 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1828,10 +1828,10 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) * If this is the upstream port for this switch, enable * forwarding of unknown unicasts and multicasts. */ - reg = PORT_CONTROL_IGMP_MLD_SNOOP | - PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP | - PORT_CONTROL_STATE_FORWARDING; - err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); + reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | + MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | + MV88E6XXX_PORT_CTL0_STATE_FORWARDING; + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 615b8843ad8e..a51d766b3c76 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -408,10 +408,10 @@ int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, /* Offset 0x04: Port Control Register */ static const char * const mv88e6xxx_port_state_names[] = { - [PORT_CONTROL_STATE_DISABLED] = "Disabled", - [PORT_CONTROL_STATE_BLOCKING] = "Blocking/Listening", - [PORT_CONTROL_STATE_LEARNING] = "Learning", - [PORT_CONTROL_STATE_FORWARDING] = "Forwarding", + [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled", + [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening", + [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning", + [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding", }; int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) @@ -419,25 +419,25 @@ int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); if (err) return err; - reg &= ~PORT_CONTROL_STATE_MASK; + reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK; switch (state) { case BR_STATE_DISABLED: - state = PORT_CONTROL_STATE_DISABLED; + state = MV88E6XXX_PORT_CTL0_STATE_DISABLED; break; case BR_STATE_BLOCKING: case BR_STATE_LISTENING: - state = PORT_CONTROL_STATE_BLOCKING; + state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING; break; case BR_STATE_LEARNING: - state = PORT_CONTROL_STATE_LEARNING; + state = MV88E6XXX_PORT_CTL0_STATE_LEARNING; break; case BR_STATE_FORWARDING: - state = PORT_CONTROL_STATE_FORWARDING; + state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING; break; default: return -EINVAL; @@ -445,7 +445,7 @@ int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) reg |= state; - err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); if (err) return err; @@ -461,30 +461,30 @@ int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port, int err; u16 reg; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); if (err) return err; - reg &= ~PORT_CONTROL_EGRESS_MASK; + reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK; switch (mode) { case MV88E6XXX_EGRESS_MODE_UNMODIFIED: - reg |= PORT_CONTROL_EGRESS_UNMODIFIED; + reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED; break; case MV88E6XXX_EGRESS_MODE_UNTAGGED: - reg |= PORT_CONTROL_EGRESS_UNTAGGED; + reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED; break; case MV88E6XXX_EGRESS_MODE_TAGGED: - reg |= PORT_CONTROL_EGRESS_TAGGED; + reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED; break; case MV88E6XXX_EGRESS_MODE_ETHERTYPE: - reg |= PORT_CONTROL_EGRESS_ADD_TAG; + reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA; break; default: return -EINVAL; } - return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); } int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, @@ -493,24 +493,24 @@ int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, int err; u16 reg; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); if (err) return err; - reg &= ~PORT_CONTROL_FRAME_MASK; + reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK; switch (mode) { case MV88E6XXX_FRAME_MODE_NORMAL: - reg |= PORT_CONTROL_FRAME_MODE_NORMAL; + reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL; break; case MV88E6XXX_FRAME_MODE_DSA: - reg |= PORT_CONTROL_FRAME_MODE_DSA; + reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA; break; default: return -EINVAL; } - return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); } int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, @@ -519,30 +519,30 @@ int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, int err; u16 reg; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); if (err) return err; - reg &= ~PORT_CONTROL_FRAME_MASK; + reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK; switch (mode) { case MV88E6XXX_FRAME_MODE_NORMAL: - reg |= PORT_CONTROL_FRAME_MODE_NORMAL; + reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL; break; case MV88E6XXX_FRAME_MODE_DSA: - reg |= PORT_CONTROL_FRAME_MODE_DSA; + reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA; break; case MV88E6XXX_FRAME_MODE_PROVIDER: - reg |= PORT_CONTROL_FRAME_MODE_PROVIDER; + reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER; break; case MV88E6XXX_FRAME_MODE_ETHERTYPE: - reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA; + reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA; break; default: return -EINVAL; } - return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); } static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, @@ -551,16 +551,16 @@ static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, int err; u16 reg; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); if (err) return err; if (unicast) - reg |= PORT_CONTROL_FORWARD_UNKNOWN; + reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN; else - reg &= ~PORT_CONTROL_FORWARD_UNKNOWN; + reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN; - return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); } int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, @@ -569,22 +569,22 @@ int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, int err; u16 reg; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); if (err) return err; - reg &= ~PORT_CONTROL_EGRESS_FLOODS_MASK; + reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK; if (unicast && multicast) - reg |= PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA; + reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA; else if (unicast) - reg |= PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA; + reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA; else if (multicast) - reg |= PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA; + reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA; else - reg |= PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA; + reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA; - return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); } /* Offset 0x05: Port Control 1 */ diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index dc99c3159038..880f1b117248 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -107,38 +107,40 @@ #define MV88E6XXX_PORT_SWITCH_ID_PROD_6390 0x3900 #define MV88E6XXX_PORT_SWITCH_ID_REV_MASK 0x000f -#define PORT_CONTROL 0x04 -#define PORT_CONTROL_USE_CORE_TAG BIT(15) -#define PORT_CONTROL_DROP_ON_LOCK BIT(14) -#define PORT_CONTROL_EGRESS_UNMODIFIED (0x0 << 12) -#define PORT_CONTROL_EGRESS_UNTAGGED (0x1 << 12) -#define PORT_CONTROL_EGRESS_TAGGED (0x2 << 12) -#define PORT_CONTROL_EGRESS_ADD_TAG (0x3 << 12) -#define PORT_CONTROL_EGRESS_MASK (0x3 << 12) -#define PORT_CONTROL_HEADER BIT(11) -#define PORT_CONTROL_IGMP_MLD_SNOOP BIT(10) -#define PORT_CONTROL_DOUBLE_TAG BIT(9) -#define PORT_CONTROL_FRAME_MODE_NORMAL (0x0 << 8) -#define PORT_CONTROL_FRAME_MODE_DSA (0x1 << 8) -#define PORT_CONTROL_FRAME_MODE_PROVIDER (0x2 << 8) -#define PORT_CONTROL_FRAME_ETHER_TYPE_DSA (0x3 << 8) -#define PORT_CONTROL_FRAME_MASK (0x3 << 8) -#define PORT_CONTROL_DSA_TAG BIT(8) -#define PORT_CONTROL_VLAN_TUNNEL BIT(7) -#define PORT_CONTROL_TAG_IF_BOTH BIT(6) -#define PORT_CONTROL_USE_IP BIT(5) -#define PORT_CONTROL_USE_TAG BIT(4) -#define PORT_CONTROL_FORWARD_UNKNOWN BIT(2) -#define PORT_CONTROL_EGRESS_FLOODS_MASK (0x3 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA (0x0 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA (0x1 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA (0x2 << 2) -#define PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA (0x3 << 2) -#define PORT_CONTROL_STATE_MASK 0x03 -#define PORT_CONTROL_STATE_DISABLED 0x00 -#define PORT_CONTROL_STATE_BLOCKING 0x01 -#define PORT_CONTROL_STATE_LEARNING 0x02 -#define PORT_CONTROL_STATE_FORWARDING 0x03 +/* Offset 0x04: Port Control Register */ +#define MV88E6XXX_PORT_CTL0 0x04 +#define MV88E6XXX_PORT_CTL0_USE_CORE_TAG 0x8000 +#define MV88E6XXX_PORT_CTL0_DROP_ON_LOCK 0x4000 +#define MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK 0x3000 +#define MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED 0x0000 +#define MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED 0x1000 +#define MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED 0x2000 +#define MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA 0x3000 +#define MV88E6XXX_PORT_CTL0_HEADER 0x0800 +#define MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP 0x0400 +#define MV88E6XXX_PORT_CTL0_DOUBLE_TAG 0x0200 +#define MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK 0x0300 +#define MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL 0x0000 +#define MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA 0x0100 +#define MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER 0x0200 +#define MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA 0x0300 +#define MV88E6XXX_PORT_CTL0_DSA_TAG 0x0100 +#define MV88E6XXX_PORT_CTL0_VLAN_TUNNEL 0x0080 +#define MV88E6XXX_PORT_CTL0_TAG_IF_BOTH 0x0040 +#define MV88E6185_PORT_CTL0_USE_IP 0x0020 +#define MV88E6185_PORT_CTL0_USE_TAG 0x0010 +#define MV88E6185_PORT_CTL0_FORWARD_UNKNOWN 0x0004 +#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK 0x000c +#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA 0x0000 +#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA 0x0004 +#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA 0x0008 +#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA 0x000c +#define MV88E6XXX_PORT_CTL0_STATE_MASK 0x0003 +#define MV88E6XXX_PORT_CTL0_STATE_DISABLED 0x0000 +#define MV88E6XXX_PORT_CTL0_STATE_BLOCKING 0x0001 +#define MV88E6XXX_PORT_CTL0_STATE_LEARNING 0x0002 +#define MV88E6XXX_PORT_CTL0_STATE_FORWARDING 0x0003 + #define PORT_CONTROL_1 0x05 #define PORT_CONTROL_1_MESSAGE_PORT BIT(15) #define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) -- cgit v1.2.3 From cd985bbf9a30ed58ff7d56b236144d98ff64e89d Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:38 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Control 1 macros For implicit namespacing and clarity, prefix the common Port Control 1 Register macros with MV88E6XXX_PORT_CTL1. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/port.c | 17 ++++++++++------- drivers/net/dsa/mv88e6xxx/port.h | 8 +++++--- 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index a51d766b3c76..6b972626f326 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -595,16 +595,16 @@ int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, u16 val; int err; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, &val); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val); if (err) return err; if (message_port) - val |= PORT_CONTROL_1_MESSAGE_PORT; + val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT; else - val &= ~PORT_CONTROL_1_MESSAGE_PORT; + val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT; - return mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, val); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val); } /* Offset 0x06: Port Based VLAN Map */ @@ -646,7 +646,8 @@ int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid) /* Port's default FID upper bits are located in reg 0x05, offset 0 */ if (upper_mask) { - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, + ®); if (err) return err; @@ -679,14 +680,16 @@ int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid) /* Port's default FID upper bits are located in reg 0x05, offset 0 */ if (upper_mask) { - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, + ®); if (err) return err; reg &= ~upper_mask; reg |= (fid >> 4) & upper_mask; - err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, + reg); if (err) return err; } diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 880f1b117248..451f99fd81cf 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -141,9 +141,11 @@ #define MV88E6XXX_PORT_CTL0_STATE_LEARNING 0x0002 #define MV88E6XXX_PORT_CTL0_STATE_FORWARDING 0x0003 -#define PORT_CONTROL_1 0x05 -#define PORT_CONTROL_1_MESSAGE_PORT BIT(15) -#define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) +/* Offset 0x05: Port Control 1 */ +#define MV88E6XXX_PORT_CTL1 0x05 +#define MV88E6XXX_PORT_CTL1_MESSAGE_PORT 0x8000 +#define MV88E6XXX_PORT_CTL1_FID_11_4_MASK 0x00ff + #define PORT_BASE_VLAN 0x06 #define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12) #define PORT_DEFAULT_VLAN 0x07 -- cgit v1.2.3 From 7e5cc5f1b5a556fce48d9bbcf6fc4d97b993d2ba Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:39 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Based VLAN macros For implicit namespacing and clarity, prefix the common Port Based VLAN Register macros with MV88E6XXX_PORT_BASE_VLAN. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/port.c | 10 +++++----- drivers/net/dsa/mv88e6xxx/port.h | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 6b972626f326..3cd3b4b7c944 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -615,14 +615,14 @@ int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map) u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); if (err) return err; reg &= ~mask; reg |= map & mask; - err = mv88e6xxx_port_write(chip, port, PORT_BASE_VLAN, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg); if (err) return err; @@ -638,7 +638,7 @@ int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid) int err; /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ - err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); if (err) return err; @@ -667,14 +667,14 @@ int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid) return -EINVAL; /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ - err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); if (err) return err; reg &= 0x0fff; reg |= (fid & 0x000f) << 12; - err = mv88e6xxx_port_write(chip, port, PORT_BASE_VLAN, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 451f99fd81cf..23d94f61cac7 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -146,8 +146,10 @@ #define MV88E6XXX_PORT_CTL1_MESSAGE_PORT 0x8000 #define MV88E6XXX_PORT_CTL1_FID_11_4_MASK 0x00ff -#define PORT_BASE_VLAN 0x06 -#define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12) +/* Offset 0x06: Port Based VLAN Map */ +#define MV88E6XXX_PORT_BASE_VLAN 0x06 +#define MV88E6XXX_PORT_BASE_VLAN_FID_3_0_MASK 0xf000 + #define PORT_DEFAULT_VLAN 0x07 #define PORT_DEFAULT_VLAN_MASK 0xfff #define PORT_CONTROL_2 0x08 -- cgit v1.2.3 From b7929fb36d11d95ddffd70da033dc538265178f7 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:40 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Default VLAN macros For implicit namespacing and clarity, prefix the common Port Default VLAN Register macros with MV88E6XXX_PORT_DEFAULT_VLAN. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- drivers/net/dsa/mv88e6xxx/port.c | 15 +++++++++------ drivers/net/dsa/mv88e6xxx/port.h | 6 ++++-- 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index b1a8cbe1c215..937a43d37f37 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1950,7 +1950,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) /* Default VLAN ID and priority: don't set a default VLAN * ID, and set the default packet priority to zero. */ - return mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, 0x0000); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 0); } static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 3cd3b4b7c944..77e4048962d1 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -706,11 +706,12 @@ int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid) u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_DEFAULT_VLAN, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, + ®); if (err) return err; - *pvid = reg & PORT_DEFAULT_VLAN_MASK; + *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK; return 0; } @@ -720,14 +721,16 @@ int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid) u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_DEFAULT_VLAN, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, + ®); if (err) return err; - reg &= ~PORT_DEFAULT_VLAN_MASK; - reg |= pvid & PORT_DEFAULT_VLAN_MASK; + reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK; + reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK; - err = mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, + reg); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 23d94f61cac7..44ac1327e9a2 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -150,8 +150,10 @@ #define MV88E6XXX_PORT_BASE_VLAN 0x06 #define MV88E6XXX_PORT_BASE_VLAN_FID_3_0_MASK 0xf000 -#define PORT_DEFAULT_VLAN 0x07 -#define PORT_DEFAULT_VLAN_MASK 0xfff +/* Offset 0x07: Default Port VLAN ID & Priority */ +#define MV88E6XXX_PORT_DEFAULT_VLAN 0x07 +#define MV88E6XXX_PORT_DEFAULT_VLAN_MASK 0x0fff + #define PORT_CONTROL_2 0x08 #define PORT_CONTROL_2_IGNORE_FCS BIT(15) #define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14) -- cgit v1.2.3 From 81c6edb23b61a4dec5e0a8954f69a151baeb55f4 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:41 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Control 2 macros For implicit namespacing and clarity, prefix the common Port Control 2 Register macros with MV88E6XXX_PORT_CTL2 and the ones which differ between implementations with a chosen reference model (e.g. MV88E6095_PORT_CTL2_CPU_PORT_MASK.) Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 6 ++--- drivers/net/dsa/mv88e6xxx/port.c | 48 ++++++++++++++++++++-------------------- drivers/net/dsa/mv88e6xxx/port.h | 44 ++++++++++++++++++------------------ 3 files changed, 50 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 937a43d37f37..efc57003b9ee 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1213,8 +1213,8 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) { struct mv88e6xxx_chip *chip = ds->priv; - u16 mode = vlan_filtering ? PORT_CONTROL_2_8021Q_SECURE : - PORT_CONTROL_2_8021Q_DISABLED; + u16 mode = vlan_filtering ? MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE : + MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED; int err; if (!chip->info->max_vid) @@ -1872,7 +1872,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) } err = mv88e6xxx_port_set_8021q_mode(chip, port, - PORT_CONTROL_2_8021Q_DISABLED); + MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 77e4048962d1..ad86b2e30ac5 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -742,10 +742,10 @@ int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid) /* Offset 0x08: Port Control 2 Register */ static const char * const mv88e6xxx_port_8021q_mode_names[] = { - [PORT_CONTROL_2_8021Q_DISABLED] = "Disabled", - [PORT_CONTROL_2_8021Q_FALLBACK] = "Fallback", - [PORT_CONTROL_2_8021Q_CHECK] = "Check", - [PORT_CONTROL_2_8021Q_SECURE] = "Secure", + [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled", + [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback", + [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check", + [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure", }; static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, @@ -754,16 +754,16 @@ static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, int err; u16 reg; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); if (err) return err; if (multicast) - reg |= PORT_CONTROL_2_DEFAULT_FORWARD; + reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD; else - reg &= ~PORT_CONTROL_2_DEFAULT_FORWARD; + reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD; - return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); } int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, @@ -784,14 +784,14 @@ int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, int err; u16 reg; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); if (err) return err; - reg &= ~PORT_CONTROL_2_UPSTREAM_MASK; + reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK; reg |= upstream_port; - return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); } int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, @@ -800,14 +800,14 @@ int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); if (err) return err; - reg &= ~PORT_CONTROL_2_8021Q_MASK; - reg |= mode & PORT_CONTROL_2_8021Q_MASK; + reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK; + reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK; - err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); if (err) return err; @@ -822,13 +822,13 @@ int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port) u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); if (err) return err; - reg |= PORT_CONTROL_2_MAP_DA; + reg |= MV88E6XXX_PORT_CTL2_MAP_DA; - return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); } int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port, @@ -837,22 +837,22 @@ int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port, u16 reg; int err; - err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); if (err) return err; - reg &= ~PORT_CONTROL_2_JUMBO_MASK; + reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK; if (size <= 1522) - reg |= PORT_CONTROL_2_JUMBO_1522; + reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522; else if (size <= 2048) - reg |= PORT_CONTROL_2_JUMBO_2048; + reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048; else if (size <= 10240) - reg |= PORT_CONTROL_2_JUMBO_10240; + reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240; else return -ERANGE; - return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); } /* Offset 0x09: Port Rate Control */ diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 44ac1327e9a2..ce236f06db6d 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -154,27 +154,29 @@ #define MV88E6XXX_PORT_DEFAULT_VLAN 0x07 #define MV88E6XXX_PORT_DEFAULT_VLAN_MASK 0x0fff -#define PORT_CONTROL_2 0x08 -#define PORT_CONTROL_2_IGNORE_FCS BIT(15) -#define PORT_CONTROL_2_VTU_PRI_OVERRIDE BIT(14) -#define PORT_CONTROL_2_SA_PRIO_OVERRIDE BIT(13) -#define PORT_CONTROL_2_DA_PRIO_OVERRIDE BIT(12) -#define PORT_CONTROL_2_JUMBO_MASK (0x03 << 12) -#define PORT_CONTROL_2_JUMBO_1522 (0x00 << 12) -#define PORT_CONTROL_2_JUMBO_2048 (0x01 << 12) -#define PORT_CONTROL_2_JUMBO_10240 (0x02 << 12) -#define PORT_CONTROL_2_8021Q_MASK (0x03 << 10) -#define PORT_CONTROL_2_8021Q_DISABLED (0x00 << 10) -#define PORT_CONTROL_2_8021Q_FALLBACK (0x01 << 10) -#define PORT_CONTROL_2_8021Q_CHECK (0x02 << 10) -#define PORT_CONTROL_2_8021Q_SECURE (0x03 << 10) -#define PORT_CONTROL_2_DISCARD_TAGGED BIT(9) -#define PORT_CONTROL_2_DISCARD_UNTAGGED BIT(8) -#define PORT_CONTROL_2_MAP_DA BIT(7) -#define PORT_CONTROL_2_DEFAULT_FORWARD BIT(6) -#define PORT_CONTROL_2_EGRESS_MONITOR BIT(5) -#define PORT_CONTROL_2_INGRESS_MONITOR BIT(4) -#define PORT_CONTROL_2_UPSTREAM_MASK 0x0f +/* Offset 0x08: Port Control 2 Register */ +#define MV88E6XXX_PORT_CTL2 0x08 +#define MV88E6XXX_PORT_CTL2_IGNORE_FCS 0x8000 +#define MV88E6XXX_PORT_CTL2_VTU_PRI_OVERRIDE 0x4000 +#define MV88E6XXX_PORT_CTL2_SA_PRIO_OVERRIDE 0x2000 +#define MV88E6XXX_PORT_CTL2_DA_PRIO_OVERRIDE 0x1000 +#define MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK 0x3000 +#define MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522 0x0000 +#define MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048 0x1000 +#define MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240 0x2000 +#define MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK 0x0c00 +#define MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED 0x0000 +#define MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK 0x0400 +#define MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK 0x0800 +#define MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE 0x0c00 +#define MV88E6XXX_PORT_CTL2_DISCARD_TAGGED 0x0200 +#define MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED 0x0100 +#define MV88E6XXX_PORT_CTL2_MAP_DA 0x0080 +#define MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD 0x0040 +#define MV88E6XXX_PORT_CTL2_EGRESS_MONITOR 0x0020 +#define MV88E6XXX_PORT_CTL2_INGRESS_MONITOR 0x0010 +#define MV88E6095_PORT_CTL2_CPU_PORT_MASK 0x000f + #define PORT_RATE_CONTROL 0x09 #define PORT_RATE_CONTROL_2 0x0a #define PORT_ASSOC_VECTOR 0x0b -- cgit v1.2.3 From 2cb8cb144eef6b3175e95504eae7f385bdb35c69 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:42 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Egress Rate Control macros For implicit namespacing and clarity, prefix the common Port Egress Rate Control and Port Egress Rate Control 2 registers macros with MV88E6XXX_PORT_EGRESS_RATE_CTL1 and MV88E6XXX_PORT_EGRESS_RATE_CTL2. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 3 ++- drivers/net/dsa/mv88e6xxx/port.c | 6 ++++-- drivers/net/dsa/mv88e6xxx/port.h | 8 ++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index efc57003b9ee..8146c94e394d 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1897,7 +1897,8 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) return err; /* Egress rate control 2: disable egress rate control. */ - err = mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL_2, 0x0000); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL2, + 0x0000); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index ad86b2e30ac5..595f842c955b 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -859,12 +859,14 @@ int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port, int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) { - return mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL, 0x0000); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1, + 0x0000); } int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) { - return mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL, 0x0001); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1, + 0x0001); } /* Offset 0x0C: Port ATU Control */ diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index ce236f06db6d..5bcba657a111 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -177,8 +177,12 @@ #define MV88E6XXX_PORT_CTL2_INGRESS_MONITOR 0x0010 #define MV88E6095_PORT_CTL2_CPU_PORT_MASK 0x000f -#define PORT_RATE_CONTROL 0x09 -#define PORT_RATE_CONTROL_2 0x0a +/* Offset 0x09: Egress Rate Control */ +#define MV88E6XXX_PORT_EGRESS_RATE_CTL1 0x09 + +/* Offset 0x0A: Egress Rate Control 2 */ +#define MV88E6XXX_PORT_EGRESS_RATE_CTL2 0x0a + #define PORT_ASSOC_VECTOR 0x0b #define PORT_ASSOC_VECTOR_HOLD_AT_1 BIT(15) #define PORT_ASSOC_VECTOR_INT_AGE_OUT BIT(14) -- cgit v1.2.3 From 2a4614e4ef0bef05a3f06f1a4481c9887e418e13 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:43 -0400 Subject: net: dsa: mv88e6xxx: prefix Port Association Vector macros For implicit namespacing and clarity, prefix the common Port Association Vector Register macros with MV88E6XXX_PORT_ASSOC_VECTOR. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 3 ++- drivers/net/dsa/mv88e6xxx/port.h | 14 ++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 8146c94e394d..e04e780ffe90 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1892,7 +1892,8 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) if (dsa_is_cpu_port(ds, port)) reg = 0; - err = mv88e6xxx_port_write(chip, port, PORT_ASSOC_VECTOR, reg); + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, + reg); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 5bcba657a111..a855409789c3 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -183,12 +183,14 @@ /* Offset 0x0A: Egress Rate Control 2 */ #define MV88E6XXX_PORT_EGRESS_RATE_CTL2 0x0a -#define PORT_ASSOC_VECTOR 0x0b -#define PORT_ASSOC_VECTOR_HOLD_AT_1 BIT(15) -#define PORT_ASSOC_VECTOR_INT_AGE_OUT BIT(14) -#define PORT_ASSOC_VECTOR_LOCKED_PORT BIT(13) -#define PORT_ASSOC_VECTOR_IGNORE_WRONG BIT(12) -#define PORT_ASSOC_VECTOR_REFRESH_LOCKED BIT(11) +/* Offset 0x0B: Port Association Vector */ +#define MV88E6XXX_PORT_ASSOC_VECTOR 0x0b +#define MV88E6XXX_PORT_ASSOC_VECTOR_HOLD_AT_1 0x8000 +#define MV88E6XXX_PORT_ASSOC_VECTOR_INT_AGE_OUT 0x4000 +#define MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT 0x2000 +#define MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG 0x1000 +#define MV88E6XXX_PORT_ASSOC_VECTOR_REFRESH_LOCKED 0x0800 + #define PORT_ATU_CONTROL 0x0c #define PORT_PRI_OVERRIDE 0x0d #define PORT_ETH_TYPE 0x0f -- cgit v1.2.3 From 8009df9e70330d185e02f0c447a7d19b6d3a4432 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:44 -0400 Subject: net: dsa: mv88e6xxx: prefix Port IEEE Priority mapping macros For implicit namespacing and clarity, prefix the common Port IEEE Priority Remapping registers macros with MV88E6095_PORT_IEEE_PRIO. The 88E6390 family turned the 0x18 register into a single indirect table, document that at the same time. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Also fix the following checkpatch checks with a temporary variable: CHECK: Alignment should match open parenthesis #65: FILE: drivers/net/dsa/mv88e6xxx/port.c:932: + err = mv88e6xxx_port_ieeepmt_write(chip, port, + MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP, Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/port.c | 37 ++++++++++++++++++++----------------- drivers/net/dsa/mv88e6xxx/port.h | 30 ++++++++++++++++++------------ 2 files changed, 38 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 595f842c955b..166208f062e3 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -900,11 +900,15 @@ int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port) int err; /* Use a direct priority mapping for all IEEE tagged frames */ - err = mv88e6xxx_port_write(chip, port, PORT_TAG_REGMAP_0123, 0x3210); + err = mv88e6xxx_port_write(chip, port, + MV88E6095_PORT_IEEE_PRIO_REMAP_0123, + 0x3210); if (err) return err; - return mv88e6xxx_port_write(chip, port, PORT_TAG_REGMAP_4567, 0x7654); + return mv88e6xxx_port_write(chip, port, + MV88E6095_PORT_IEEE_PRIO_REMAP_4567, + 0x7654); } static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip, @@ -913,40 +917,39 @@ static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip, { u16 reg; - reg = PORT_IEEE_PRIO_MAP_TABLE_UPDATE | + reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table | - (pointer << PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT) | + (pointer << MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT) | data; - return mv88e6xxx_port_write(chip, port, PORT_IEEE_PRIO_MAP_TABLE, reg); + return mv88e6xxx_port_write(chip, port, + MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg); } int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port) { int err, i; + u16 table; for (i = 0; i <= 7; i++) { - err = mv88e6xxx_port_ieeepmt_write( - chip, port, PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP, - i, (i | i << 4)); + table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP; + err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, + (i | i << 4)); if (err) return err; - err = mv88e6xxx_port_ieeepmt_write( - chip, port, PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP, - i, i); + table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP; + err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); if (err) return err; - err = mv88e6xxx_port_ieeepmt_write( - chip, port, PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP, - i, i); + table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP; + err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); if (err) return err; - err = mv88e6xxx_port_ieeepmt_write( - chip, port, PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP, - i, i); + table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP; + err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); if (err) return err; } diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index a855409789c3..5144941cb0db 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -199,18 +199,24 @@ #define PORT_IN_DISCARD_HI 0x11 #define PORT_IN_FILTERED 0x12 #define PORT_OUT_FILTERED 0x13 -#define PORT_TAG_REGMAP_0123 0x18 -#define PORT_TAG_REGMAP_4567 0x19 -#define PORT_IEEE_PRIO_MAP_TABLE 0x18 /* 6390 */ -#define PORT_IEEE_PRIO_MAP_TABLE_UPDATE BIT(15) -#define PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP (0x0 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP (0x1 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP (0x2 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP (0x3 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP (0x5 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP (0x6 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP (0x7 << 12) -#define PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9 + +/* Offset 0x18: IEEE Priority Mapping Table */ +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP 0x0000 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP 0x1000 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP 0x2000 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP 0x3000 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP 0x5000 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP 0x6000 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP 0x7000 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9 + +/* Offset 0x18: Port IEEE Priority Remapping Registers (0-3) */ +#define MV88E6095_PORT_IEEE_PRIO_REMAP_0123 0x18 + +/* Offset 0x19: Port IEEE Priority Remapping Registers (4-7) */ +#define MV88E6095_PORT_IEEE_PRIO_REMAP_4567 0x19 int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, u16 *val); -- cgit v1.2.3 From b81095947e1b2816ca5ccd87b8ac0e209e798ee0 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 12 Jun 2017 12:37:45 -0400 Subject: net: dsa: mv88e6xxx: prefix remaining port macros For implicit namespacing and clarity, prefix the remaining common Port Registers macros with MV88E6XXX_PORT. Document the register and prefer ordered hex masks values for all Marvell 16-bit registers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 4 ++-- drivers/net/dsa/mv88e6xxx/port.c | 6 +++--- drivers/net/dsa/mv88e6xxx/port.h | 35 +++++++++++++++++++++++++++-------- 3 files changed, 32 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index e04e780ffe90..fb950ca29081 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1729,14 +1729,14 @@ static int mv88e6xxx_set_port_mode_normal(struct mv88e6xxx_chip *chip, int port) { return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_NORMAL, MV88E6XXX_EGRESS_MODE_UNMODIFIED, - PORT_ETH_TYPE_DEFAULT); + MV88E6XXX_PORT_ETH_TYPE_DEFAULT); } static int mv88e6xxx_set_port_mode_dsa(struct mv88e6xxx_chip *chip, int port) { return mv88e6xxx_set_port_mode(chip, port, MV88E6XXX_FRAME_MODE_DSA, MV88E6XXX_EGRESS_MODE_UNMODIFIED, - PORT_ETH_TYPE_DEFAULT); + MV88E6XXX_PORT_ETH_TYPE_DEFAULT); } static int mv88e6xxx_set_port_mode_edsa(struct mv88e6xxx_chip *chip, int port) diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 166208f062e3..73d825e08be3 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -873,14 +873,14 @@ int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port) { - return mv88e6xxx_port_write(chip, port, PORT_ATU_CONTROL, 0); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0); } /* Offset 0x0D: (Priority) Override Register */ int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port) { - return mv88e6xxx_port_write(chip, port, PORT_PRI_OVERRIDE, 0); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0); } /* Offset 0x0f: Port Ether type */ @@ -888,7 +888,7 @@ int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port) int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, u16 etype) { - return mv88e6xxx_port_write(chip, port, PORT_ETH_TYPE, etype); + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype); } /* Offset 0x18: Port IEEE Priority Remapping Registers [0-3] diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 5144941cb0db..8a34ea7c868a 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -191,14 +191,33 @@ #define MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG 0x1000 #define MV88E6XXX_PORT_ASSOC_VECTOR_REFRESH_LOCKED 0x0800 -#define PORT_ATU_CONTROL 0x0c -#define PORT_PRI_OVERRIDE 0x0d -#define PORT_ETH_TYPE 0x0f -#define PORT_ETH_TYPE_DEFAULT 0x9100 -#define PORT_IN_DISCARD_LO 0x10 -#define PORT_IN_DISCARD_HI 0x11 -#define PORT_IN_FILTERED 0x12 -#define PORT_OUT_FILTERED 0x13 +/* Offset 0x0C: Port ATU Control */ +#define MV88E6XXX_PORT_ATU_CTL 0x0c + +/* Offset 0x0D: Priority Override Register */ +#define MV88E6XXX_PORT_PRI_OVERRIDE 0x0d + +/* Offset 0x0E: Policy Control Register */ +#define MV88E6XXX_PORT_POLICY_CTL 0x0e + +/* Offset 0x0F: Port Special Ether Type */ +#define MV88E6XXX_PORT_ETH_TYPE 0x0f +#define MV88E6XXX_PORT_ETH_TYPE_DEFAULT 0x9100 + +/* Offset 0x10: InDiscards Low Counter */ +#define MV88E6XXX_PORT_IN_DISCARD_LO 0x10 + +/* Offset 0x11: InDiscards High Counter */ +#define MV88E6XXX_PORT_IN_DISCARD_HI 0x11 + +/* Offset 0x12: InFiltered Counter */ +#define MV88E6XXX_PORT_IN_FILTERED 0x12 + +/* Offset 0x13: OutFiltered Counter */ +#define MV88E6XXX_PORT_OUT_FILTERED 0x13 + +/* Offset 0x16: LED Control */ +#define MV88E6XXX_PORT_LED_CONTROL 0x16 /* Offset 0x18: IEEE Priority Mapping Table */ #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18 -- cgit v1.2.3 From 725757aee05e51914b72f25ba2a89c43c3779574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Mon, 12 Jun 2017 16:01:39 +0200 Subject: net: mvpp2: enable basic 10G support On GOP port 0 two MAC modes are available: GMAC and XLG. The XLG MAC is used for 10G connectivity. This patch adds a basic 10G support by allowing to use the XLG MAC on port 0 and by reworking the port_enable/disable functions so that the XLG MAC is configured when using 10G. Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 49 ++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 9b875d776b29..fe1458450e44 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -345,9 +345,15 @@ /* Per-port XGMAC registers. PPv2.2 only, only for GOP port 0, * relative to port->base. */ +#define MVPP22_XLG_CTRL0_REG 0x100 +#define MVPP22_XLG_CTRL0_PORT_EN BIT(0) +#define MVPP22_XLG_CTRL0_MAC_RESET_DIS BIT(1) +#define MVPP22_XLG_CTRL0_MIB_CNT_DIS BIT(14) + #define MVPP22_XLG_CTRL3_REG 0x11c #define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13) #define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13) +#define MVPP22_XLG_CTRL3_MACMODESELECT_10G (1 << 13) /* SMI registers. PPv2.2 only, relative to priv->iface_base. */ #define MVPP22_SMI_MISC_CFG_REG 0x1204 @@ -4192,7 +4198,13 @@ static void mvpp22_port_mii_set(struct mvpp2_port *port) if (port->gop_id == 0) { val = readl(port->base + MVPP22_XLG_CTRL3_REG); val &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK; - val |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC; + + if (port->phy_interface == PHY_INTERFACE_MODE_XAUI || + port->phy_interface == PHY_INTERFACE_MODE_10GKR) + val |= MVPP22_XLG_CTRL3_MACMODESELECT_10G; + else + val |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC; + writel(val, port->base + MVPP22_XLG_CTRL3_REG); } @@ -4242,19 +4254,40 @@ static void mvpp2_port_enable(struct mvpp2_port *port) { u32 val; - val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); - val |= MVPP2_GMAC_PORT_EN_MASK; - val |= MVPP2_GMAC_MIB_CNTR_EN_MASK; - writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); + /* Only GOP port 0 has an XLG MAC */ + if (port->gop_id == 0 && + (port->phy_interface == PHY_INTERFACE_MODE_XAUI || + port->phy_interface == PHY_INTERFACE_MODE_10GKR)) { + val = readl(port->base + MVPP22_XLG_CTRL0_REG); + val |= MVPP22_XLG_CTRL0_PORT_EN | + MVPP22_XLG_CTRL0_MAC_RESET_DIS; + val &= ~MVPP22_XLG_CTRL0_MIB_CNT_DIS; + writel(val, port->base + MVPP22_XLG_CTRL0_REG); + } else { + val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); + val |= MVPP2_GMAC_PORT_EN_MASK; + val |= MVPP2_GMAC_MIB_CNTR_EN_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); + } } static void mvpp2_port_disable(struct mvpp2_port *port) { u32 val; - val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); - val &= ~(MVPP2_GMAC_PORT_EN_MASK); - writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); + /* Only GOP port 0 has an XLG MAC */ + if (port->gop_id == 0 && + (port->phy_interface == PHY_INTERFACE_MODE_XAUI || + port->phy_interface == PHY_INTERFACE_MODE_10GKR)) { + val = readl(port->base + MVPP22_XLG_CTRL0_REG); + val &= ~(MVPP22_XLG_CTRL0_PORT_EN | + MVPP22_XLG_CTRL0_MAC_RESET_DIS); + writel(val, port->base + MVPP22_XLG_CTRL0_REG); + } else { + val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); + val &= ~(MVPP2_GMAC_PORT_EN_MASK); + writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); + } } /* Set IEEE 802.3x Flow Control Xon Packet Transmission Mode */ -- cgit v1.2.3 From 40c9db8ad8b4b7f87e2f4a5e80cf1732f2825e6b Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Mon, 12 Jun 2017 12:35:04 -0500 Subject: ibmvnic: Client-initiated failover The IBM vNIC protocol provides support for the user to initiate a failover from the client LPAR in case the current backing infrastructure is deemed inadequate or in an error state. Support for two H_VIOCTL sub-commands for vNIC devices are required to implement this function. These commands are H_GET_SESSION_TOKEN and H_SESSION_ERR_DETECTED. "[H_GET_SESSION_TOKEN] is used to obtain a session token from a VNIC client adapter. This token is opaque to the caller and is intended to be used in tandem with the SESSION_ERROR_DETECTED vioctl subfunction." "[H_SESSION_ERR_DETECTED] is used to report that the currently active backing device for a VNIC client adapter is behaving poorly, and that the hypervisor should attempt to fail over to a different backing device, if one is available." To provide tools access to this functionality the vNIC driver creates a sysfs file that, when written to, will send a request to pHyp to failover to a different backing device. Signed-off-by: Thomas Falcon Reviewed-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 7d84e20b4887..fd3ef3005fb0 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3656,6 +3656,8 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) return rc; } +static struct device_attribute dev_attr_failover; + static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) { struct ibmvnic_adapter *adapter; @@ -3712,9 +3714,16 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) netdev->mtu = adapter->req_mtu - ETH_HLEN; + rc = device_create_file(&dev->dev, &dev_attr_failover); + if (rc) { + free_netdev(netdev); + return rc; + } + rc = register_netdev(netdev); if (rc) { dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc); + device_remove_file(&dev->dev, &dev_attr_failover); free_netdev(netdev); return rc; } @@ -3740,12 +3749,49 @@ static int ibmvnic_remove(struct vio_dev *dev) adapter->state = VNIC_REMOVED; mutex_unlock(&adapter->reset_lock); + device_remove_file(&dev->dev, &dev_attr_failover); free_netdev(netdev); dev_set_drvdata(&dev->dev, NULL); return 0; } +static ssize_t failover_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct net_device *netdev = dev_get_drvdata(dev); + struct ibmvnic_adapter *adapter = netdev_priv(netdev); + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + __be64 session_token; + long rc; + + if (!sysfs_streq(buf, "1")) + return -EINVAL; + + rc = plpar_hcall(H_VIOCTL, retbuf, adapter->vdev->unit_address, + H_GET_SESSION_TOKEN, 0, 0, 0); + if (rc) { + netdev_err(netdev, "Couldn't retrieve session token, rc %ld\n", + rc); + return -EINVAL; + } + + session_token = (__be64)retbuf[0]; + netdev_dbg(netdev, "Initiating client failover, session id %llx\n", + be64_to_cpu(session_token)); + rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address, + H_SESSION_ERR_DETECTED, session_token, 0, 0); + if (rc) { + netdev_err(netdev, "Client initiated failover failed, rc %ld\n", + rc); + return -EINVAL; + } + + return count; +} + +static DEVICE_ATTR(failover, 0200, NULL, failover_store); + static unsigned long ibmvnic_get_desired_dma(struct vio_dev *vdev) { struct net_device *netdev = dev_get_drvdata(&vdev->dev); -- cgit v1.2.3 From 61d3e1d9bc2a1910d773cbf4ed6f587a7a6166b5 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Mon, 12 Jun 2017 20:47:45 -0400 Subject: ibmvnic: Remove netdev notify for failover resets When handling a driver reset due to a failover of the backing server on the vios, doing the netdev_notify_peers() can cause network traffic to stall or halt. Remove the netdev notify call for failover resets. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index fd3ef3005fb0..59ea7a5ae776 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1364,7 +1364,9 @@ static int do_reset(struct ibmvnic_adapter *adapter, for (i = 0; i < adapter->req_rx_queues; i++) napi_schedule(&adapter->napi[i]); - netdev_notify_peers(netdev); + if (adapter->reset_reason != VNIC_RESET_FAILOVER) + netdev_notify_peers(netdev); + return 0; } -- cgit v1.2.3 From d396e84c56047b303cac378dde4b2e5cc430b336 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Mon, 12 Jun 2017 23:55:38 +0300 Subject: mdio_bus: handle only single PHY reset GPIO Commit 4c5e7a2c0501 ("dt-bindings: mdio: Clarify binding document") declared that a MDIO reset GPIO property should have only a single GPIO reference/specifier, however the supporting code was left intact, still burdening the kernel with now apparently useless loops -- get rid of them. Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 53 +++++++++++++++++----------------------------- drivers/of/of_mdio.c | 1 - 2 files changed, 19 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 4c169dbf9138..5d37716e7796 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -353,33 +353,22 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner) mutex_init(&bus->mdio_lock); - /* de-assert bus level PHY GPIO resets */ - if (bus->num_reset_gpios > 0) { - bus->reset_gpiod = devm_kcalloc(&bus->dev, - bus->num_reset_gpios, - sizeof(struct gpio_desc *), - GFP_KERNEL); - if (!bus->reset_gpiod) - return -ENOMEM; - } - - for (i = 0; i < bus->num_reset_gpios; i++) { - gpiod = devm_gpiod_get_index(&bus->dev, "reset", i, - GPIOD_OUT_LOW); - if (IS_ERR(gpiod)) { - err = PTR_ERR(gpiod); - if (err != -ENOENT) { - dev_err(&bus->dev, - "mii_bus %s couldn't get reset GPIO\n", - bus->id); - return err; - } - } else { - bus->reset_gpiod[i] = gpiod; - gpiod_set_value_cansleep(gpiod, 1); - udelay(bus->reset_delay_us); - gpiod_set_value_cansleep(gpiod, 0); + /* de-assert bus level PHY GPIO reset */ + gpiod = devm_gpiod_get(&bus->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + err = PTR_ERR(gpiod); + if (err != -ENOENT) { + dev_err(&bus->dev, + "mii_bus %s couldn't get reset GPIO\n", + bus->id); + return err; } + } else { + bus->reset_gpiod = gpiod; + + gpiod_set_value_cansleep(gpiod, 1); + udelay(bus->reset_delay_us); + gpiod_set_value_cansleep(gpiod, 0); } if (bus->reset) @@ -414,10 +403,8 @@ error: } /* Put PHYs in RESET to save power */ - for (i = 0; i < bus->num_reset_gpios; i++) { - if (bus->reset_gpiod[i]) - gpiod_set_value_cansleep(bus->reset_gpiod[i], 1); - } + if (bus->reset_gpiod) + gpiod_set_value_cansleep(bus->reset_gpiod, 1); device_del(&bus->dev); return err; @@ -442,10 +429,8 @@ void mdiobus_unregister(struct mii_bus *bus) } /* Put PHYs in RESET to save power */ - for (i = 0; i < bus->num_reset_gpios; i++) { - if (bus->reset_gpiod[i]) - gpiod_set_value_cansleep(bus->reset_gpiod[i], 1); - } + if (bus->reset_gpiod) + gpiod_set_value_cansleep(bus->reset_gpiod, 1); device_del(&bus->dev); } diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 7e4c80f9b6cd..9596be9a49d0 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -226,7 +226,6 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) /* Get bus level PHY reset GPIO details */ mdio->reset_delay_us = DEFAULT_GPIO_RESET_DELAY; of_property_read_u32(np, "reset-delay-us", &mdio->reset_delay_us); - mdio->num_reset_gpios = of_gpio_named_count(np, "reset-gpios"); /* Register the MDIO bus */ rc = mdiobus_register(mdio); -- cgit v1.2.3 From fe0e4052fb11d5c713961ab7e136520be40052a3 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Mon, 12 Jun 2017 23:55:39 +0300 Subject: mdio_bus: use devm_gpiod_get_optional() The MDIO reset GPIO is really a classical optional GPIO property case, so devm_gpiod_get_optional() should have been used, not devm_gpiod_get(). Doing this saves several LoCs... Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 5d37716e7796..2df7b62c1a36 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -354,16 +354,12 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner) mutex_init(&bus->mdio_lock); /* de-assert bus level PHY GPIO reset */ - gpiod = devm_gpiod_get(&bus->dev, "reset", GPIOD_OUT_LOW); + gpiod = devm_gpiod_get_optional(&bus->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(gpiod)) { - err = PTR_ERR(gpiod); - if (err != -ENOENT) { - dev_err(&bus->dev, - "mii_bus %s couldn't get reset GPIO\n", - bus->id); - return err; - } - } else { + dev_err(&bus->dev, "mii_bus %s couldn't get reset GPIO\n", + bus->id); + return PTR_ERR(gpiod); + } else if (gpiod) { bus->reset_gpiod = gpiod; gpiod_set_value_cansleep(gpiod, 1); -- cgit v1.2.3 From 5514174fe9c61c83bd8781c1e048ea6b4bf16a14 Mon Sep 17 00:00:00 2001 From: "yuval.shaia@oracle.com" Date: Tue, 13 Jun 2017 10:09:46 +0300 Subject: net: phy: Make phy_ethtool_ksettings_get return void Make return value void since function never return meaningfull value Signed-off-by: Yuval Shaia Acked-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene-v2/ethtool.c | 4 +++- drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c | 8 ++++++-- drivers/net/ethernet/broadcom/b44.c | 4 +++- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 5 ++++- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 4 +++- drivers/net/ethernet/broadcom/tg3.c | 4 +++- drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c | 6 ++---- drivers/net/ethernet/freescale/ucc_geth_ethtool.c | 4 +++- drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 2 +- drivers/net/ethernet/marvell/mv643xx_eth.c | 5 ++--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 +++- drivers/net/ethernet/renesas/ravb_main.c | 14 +++++++------- drivers/net/ethernet/renesas/sh_eth.c | 5 ++--- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 5 ++--- drivers/net/ethernet/ti/cpsw.c | 8 ++++---- drivers/net/ethernet/ti/netcp_ethss.c | 8 +++----- drivers/net/phy/phy.c | 10 +++++----- drivers/net/usb/lan78xx.c | 2 +- drivers/staging/netlogic/xlr_net.c | 5 ++++- 19 files changed, 61 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apm/xgene-v2/ethtool.c b/drivers/net/ethernet/apm/xgene-v2/ethtool.c index b6666e418e79..d31ad8270d93 100644 --- a/drivers/net/ethernet/apm/xgene-v2/ethtool.c +++ b/drivers/net/ethernet/apm/xgene-v2/ethtool.c @@ -157,7 +157,9 @@ static int xge_get_link_ksettings(struct net_device *ndev, if (!phydev) return -ENODEV; - return phy_ethtool_ksettings_get(phydev, cmd); + phy_ethtool_ksettings_get(phydev, cmd); + + return 0; } static int xge_set_link_ksettings(struct net_device *ndev, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 559963b1aa32..4f50f11718f4 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c @@ -131,13 +131,17 @@ static int xgene_get_link_ksettings(struct net_device *ndev, if (phydev == NULL) return -ENODEV; - return phy_ethtool_ksettings_get(phydev, cmd); + phy_ethtool_ksettings_get(phydev, cmd); + + return 0; } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { if (pdata->mdio_driver) { if (!phydev) return -ENODEV; - return phy_ethtool_ksettings_get(phydev, cmd); + phy_ethtool_ksettings_get(phydev, cmd); + + return 0; } supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 5b95bb48ce97..f411936b744c 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -1836,7 +1836,9 @@ static int b44_get_link_ksettings(struct net_device *dev, if (bp->flags & B44_FLAG_EXTERNAL_PHY) { BUG_ON(!dev->phydev); - return phy_ethtool_ksettings_get(dev->phydev, cmd); + phy_ethtool_ksettings_get(dev->phydev, cmd); + + return 0; } supported = (SUPPORTED_Autoneg); diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 50d88d3e03b6..ea3c906fa0e4 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1453,7 +1453,10 @@ static int bcm_enet_get_link_ksettings(struct net_device *dev, if (priv->has_phy) { if (!dev->phydev) return -ENODEV; - return phy_ethtool_ksettings_get(dev->phydev, cmd); + + phy_ethtool_ksettings_get(dev->phydev, cmd); + + return 0; } else { cmd->base.autoneg = 0; cmd->base.speed = (priv->force_speed_100) ? diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index a205a9ff9e17..daca1c9d254b 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -477,7 +477,9 @@ static int bcmgenet_get_link_ksettings(struct net_device *dev, if (!priv->phydev) return -ENODEV; - return phy_ethtool_ksettings_get(priv->phydev, cmd); + phy_ethtool_ksettings_get(priv->phydev, cmd); + + return 0; } static int bcmgenet_set_link_ksettings(struct net_device *dev, diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 537d571ee601..d600c41fb1dc 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -12097,7 +12097,9 @@ static int tg3_get_link_ksettings(struct net_device *dev, if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) return -EAGAIN; phydev = mdiobus_get_phy(tp->mdio_bus, tp->phy_addr); - return phy_ethtool_ksettings_get(phydev, cmd); + phy_ethtool_ksettings_get(phydev, cmd); + + return 0; } supported = (SUPPORTED_Autoneg); diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index 15571e251fb9..aad825088357 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -75,16 +75,14 @@ static char dpaa_stats_global[][ETH_GSTRING_LEN] = { static int dpaa_get_link_ksettings(struct net_device *net_dev, struct ethtool_link_ksettings *cmd) { - int err; - if (!net_dev->phydev) { netdev_dbg(net_dev, "phy device not initialized\n"); return 0; } - err = phy_ethtool_ksettings_get(net_dev->phydev, cmd); + phy_ethtool_ksettings_get(net_dev->phydev, cmd); - return err; + return 0; } static int dpaa_set_link_ksettings(struct net_device *net_dev, diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c index b642990b549c..4df282ed22c7 100644 --- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c +++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c @@ -113,7 +113,9 @@ uec_get_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) if (!phydev) return -ENODEV; - return phy_ethtool_ksettings_get(phydev, cmd); + phy_ethtool_ksettings_get(phydev, cmd); + + return 0; } static int diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index b8fab149690f..af1b15cc6a7f 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -150,7 +150,7 @@ static int hns_nic_get_link_ksettings(struct net_device *net_dev, cmd->base.duplex = duplex; if (net_dev->phydev) - (void)phy_ethtool_ksettings_get(net_dev->phydev, cmd); + phy_ethtool_ksettings_get(net_dev->phydev, cmd); link_stat = hns_nic_get_link(net_dev); if (!link_stat) { diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 25642dee49d3..5794d98d946f 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -1501,10 +1501,9 @@ mv643xx_eth_get_link_ksettings_phy(struct mv643xx_eth_private *mp, struct ethtool_link_ksettings *cmd) { struct net_device *dev = mp->dev; - int err; u32 supported, advertising; - err = phy_ethtool_ksettings_get(dev->phydev, cmd); + phy_ethtool_ksettings_get(dev->phydev, cmd); /* * The MAC does not support 1000baseT_Half. @@ -1520,7 +1519,7 @@ mv643xx_eth_get_link_ksettings_phy(struct mv643xx_eth_private *mp, ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, advertising); - return err; + return 0; } static int diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 16f97552ae98..962975d192d1 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2056,7 +2056,9 @@ static int mtk_get_link_ksettings(struct net_device *ndev, if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) return -EBUSY; - return phy_ethtool_ksettings_get(ndev->phydev, cmd); + phy_ethtool_ksettings_get(ndev->phydev, cmd); + + return 0; } static int mtk_set_link_ksettings(struct net_device *ndev, diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 784782da3a85..5931e859876c 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1076,16 +1076,16 @@ static int ravb_get_link_ksettings(struct net_device *ndev, struct ethtool_link_ksettings *cmd) { struct ravb_private *priv = netdev_priv(ndev); - int error = -ENODEV; unsigned long flags; - if (ndev->phydev) { - spin_lock_irqsave(&priv->lock, flags); - error = phy_ethtool_ksettings_get(ndev->phydev, cmd); - spin_unlock_irqrestore(&priv->lock, flags); - } + if (!ndev->phydev) + return -ENODEV; - return error; + spin_lock_irqsave(&priv->lock, flags); + phy_ethtool_ksettings_get(ndev->phydev, cmd); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; } static int ravb_set_link_ksettings(struct net_device *ndev, diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 48b66df88294..d2dc0a8ef305 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1915,16 +1915,15 @@ static int sh_eth_get_link_ksettings(struct net_device *ndev, { struct sh_eth_private *mdp = netdev_priv(ndev); unsigned long flags; - int ret; if (!ndev->phydev) return -ENODEV; spin_lock_irqsave(&mdp->lock, flags); - ret = phy_ethtool_ksettings_get(ndev->phydev, cmd); + phy_ethtool_ksettings_get(ndev->phydev, cmd); spin_unlock_irqrestore(&mdp->lock, flags); - return ret; + return 0; } static int sh_eth_set_link_ksettings(struct net_device *ndev, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 16808e48ca1c..743170d57f62 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -273,7 +273,6 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); struct phy_device *phy = dev->phydev; - int rc; if (priv->hw->pcs & STMMAC_PCS_RGMII || priv->hw->pcs & STMMAC_PCS_SGMII) { @@ -364,8 +363,8 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev, "link speed / duplex setting\n", dev->name); return -EBUSY; } - rc = phy_ethtool_ksettings_get(phy, cmd); - return rc; + phy_ethtool_ksettings_get(phy, cmd); + return 0; } static int diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index b6a0d92dd637..b7a0f5eeab62 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -2170,11 +2170,11 @@ static int cpsw_get_link_ksettings(struct net_device *ndev, struct cpsw_common *cpsw = priv->cpsw; int slave_no = cpsw_slave_index(cpsw, priv); - if (cpsw->slaves[slave_no].phy) - return phy_ethtool_ksettings_get(cpsw->slaves[slave_no].phy, - ecmd); - else + if (!cpsw->slaves[slave_no].phy) return -EOPNOTSUPP; + + phy_ethtool_ksettings_get(cpsw->slaves[slave_no].phy, ecmd); + return 0; } static int cpsw_set_link_ksettings(struct net_device *ndev, diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index dd92950a4615..0847a8f48cfe 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -1927,7 +1927,6 @@ static int keystone_get_link_ksettings(struct net_device *ndev, struct netcp_intf *netcp = netdev_priv(ndev); struct phy_device *phy = ndev->phydev; struct gbe_intf *gbe_intf; - int ret; if (!phy) return -EINVAL; @@ -1939,11 +1938,10 @@ static int keystone_get_link_ksettings(struct net_device *ndev, if (!gbe_intf->slave) return -EINVAL; - ret = phy_ethtool_ksettings_get(phy, cmd); - if (!ret) - cmd->base.port = gbe_intf->slave->phy_port_t; + phy_ethtool_ksettings_get(phy, cmd); + cmd->base.port = gbe_intf->slave->phy_port_t; - return ret; + return 0; } static int keystone_set_link_ksettings(struct net_device *ndev, diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 14fc5bc75cd1..edcdf0d872ed 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -509,8 +509,8 @@ int phy_ethtool_ksettings_set(struct phy_device *phydev, } EXPORT_SYMBOL(phy_ethtool_ksettings_set); -int phy_ethtool_ksettings_get(struct phy_device *phydev, - struct ethtool_link_ksettings *cmd) +void phy_ethtool_ksettings_get(struct phy_device *phydev, + struct ethtool_link_ksettings *cmd) { ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, phydev->supported); @@ -532,8 +532,6 @@ int phy_ethtool_ksettings_get(struct phy_device *phydev, cmd->base.autoneg = phydev->autoneg; cmd->base.eth_tp_mdix_ctrl = phydev->mdix_ctrl; cmd->base.eth_tp_mdix = phydev->mdix; - - return 0; } EXPORT_SYMBOL(phy_ethtool_ksettings_get); @@ -1449,7 +1447,9 @@ int phy_ethtool_get_link_ksettings(struct net_device *ndev, if (!phydev) return -ENODEV; - return phy_ethtool_ksettings_get(phydev, cmd); + phy_ethtool_ksettings_get(phydev, cmd); + + return 0; } EXPORT_SYMBOL(phy_ethtool_get_link_ksettings); diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 9eff97a650ae..5833f7e2a127 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1490,7 +1490,7 @@ static int lan78xx_get_link_ksettings(struct net_device *net, if (ret < 0) return ret; - ret = phy_ethtool_ksettings_get(phydev, cmd); + phy_ethtool_ksettings_get(phydev, cmd); usb_autopm_put_interface(dev->intf); diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c index 781ef623233e..e05ae4645d91 100644 --- a/drivers/staging/netlogic/xlr_net.c +++ b/drivers/staging/netlogic/xlr_net.c @@ -179,7 +179,10 @@ static int xlr_get_link_ksettings(struct net_device *ndev, if (!phydev) return -ENODEV; - return phy_ethtool_ksettings_get(phydev, ecmd); + + phy_ethtool_ksettings_get(phydev, ecmd); + + return 0; } static int xlr_set_link_ksettings(struct net_device *ndev, -- cgit v1.2.3 From aa9f979c41043d9fcf7957c99948e20bbddefc7f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Jun 2017 14:28:18 +0200 Subject: networking: use skb_put_zero() Use the recently introduced helper to replace the pattern of skb_put() && memset(), this transformation was done with the following spatch: @@ identifier p; expression len; expression skb; @@ -p = skb_put(skb, len); -memset(p, 0, len); +p = skb_put_zero(skb, len); Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/ethernet/apple/bmac.c | 3 +-- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 3 +-- drivers/net/ethernet/qualcomm/qca_spi.c | 3 +-- drivers/net/wireless/marvell/mwifiex/tdls.c | 4 ++-- drivers/nfc/pn533/pn533.c | 3 +-- 5 files changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/apple/bmac.c b/drivers/net/ethernet/apple/bmac.c index 2b2d87089987..eac740c476ce 100644 --- a/drivers/net/ethernet/apple/bmac.c +++ b/drivers/net/ethernet/apple/bmac.c @@ -1218,8 +1218,7 @@ static void bmac_reset_and_enable(struct net_device *dev) */ skb = netdev_alloc_skb(dev, ETHERMINPACKET); if (skb != NULL) { - data = skb_put(skb, ETHERMINPACKET); - memset(data, 0, ETHERMINPACKET); + data = skb_put_zero(skb, ETHERMINPACKET); memcpy(data, dev->dev_addr, ETH_ALEN); memcpy(data + ETH_ALEN, dev->dev_addr, ETH_ALEN); bmac_transmit_packet(skb, dev); diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index ea3c906fa0e4..61a88b64bd39 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -609,8 +609,7 @@ static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); skb = nskb; } - data = skb_put(skb, needed); - memset(data, 0, needed); + data = skb_put_zero(skb, needed); } /* point to the next available desc */ diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index de78f60309a0..9c236298fe21 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -719,8 +719,7 @@ qcaspi_netdev_xmit(struct sk_buff *skb, struct net_device *dev) qcafrm_create_header(ptmp, frame_len); if (pad_len) { - ptmp = skb_put(skb, pad_len); - memset(ptmp, 0, pad_len); + ptmp = skb_put_zero(skb, pad_len); } ptmp = skb_put(skb, QCAFRM_FOOTER_LEN); diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index d76ce8797de1..b7d124dbef0c 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -853,8 +853,8 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, pkt_type = PKT_TYPE_MGMT; tx_control = 0; - pos = skb_put(skb, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); - memset(pos, 0, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); + pos = skb_put_zero(skb, + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); memcpy(pos, &pkt_type, sizeof(pkt_type)); memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control)); diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index 65bbaa5fcdda..70c304504a29 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -1043,8 +1043,7 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) get_random_bytes(felica + 2, 6); /* NFCID3 */ - nfcid3 = skb_put(skb, 10); - memset(nfcid3, 0, 10); + nfcid3 = skb_put_zero(skb, 10); memcpy(nfcid3, felica, 8); /* General bytes */ -- cgit v1.2.3 From fb34a368592aa842549b9637739bae000e84ff81 Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Tue, 13 Jun 2017 20:49:49 +0800 Subject: fjes: remove duplicate set of flag IFF_BROADCAST Remove unnecessary setting of flag IFF_BROADCAST, since ether_setup already does this. Signed-off-by: Zhang Shengju Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index ae48c809bac9..b56e07fa44a8 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -1348,7 +1348,6 @@ static void fjes_netdev_setup(struct net_device *netdev) netdev->mtu = fjes_support_mtu[3]; netdev->min_mtu = fjes_support_mtu[0]; netdev->max_mtu = fjes_support_mtu[3]; - netdev->flags |= IFF_BROADCAST; netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; } -- cgit v1.2.3 From 4798a714d6a78171d7df48c921dddd0dc004f0a0 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Tue, 13 Jun 2017 10:56:08 -0400 Subject: of_mdio: move of_mdio_parse_addr to header file The of_mdio_parse_addr() helper function is useful to other code, but the module dependency chain causes issues. To work around this, we can move of_mdio_parse_addr() to be an inline function in the header file. This gets rid of the dependencies and still allows for the reuse of code. Reported-by: Liviu Dudau Signed-off-by: Jon Mason Fixes: 342fa1964439 ("mdio: mux: make child bus walking more permissive and errors more verbose") Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/of/of_mdio.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 9596be9a49d0..e0dbd6e48a98 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -119,28 +119,6 @@ static void of_mdiobus_register_device(struct mii_bus *mdio, child->name, addr); } -int of_mdio_parse_addr(struct device *dev, const struct device_node *np) -{ - u32 addr; - int ret; - - ret = of_property_read_u32(np, "reg", &addr); - if (ret < 0) { - dev_err(dev, "%s has invalid PHY address\n", np->full_name); - return ret; - } - - /* A PHY must have a reg property in the range [0-31] */ - if (addr >= PHY_MAX_ADDR) { - dev_err(dev, "%s PHY address %i is too large\n", - np->full_name, addr); - return -EINVAL; - } - - return addr; -} -EXPORT_SYMBOL(of_mdio_parse_addr); - /* The following is a list of PHY compatible strings which appear in * some DTBs. The compatible string is never matched against a PHY * driver, so is pointless. We only expect devices which are not PHYs -- cgit v1.2.3 From 38b6ec5008bb7019a705b576df345509f39d3f4b Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Wed, 14 Jun 2017 00:45:43 +0530 Subject: cxgb4: handle serial flash interrupt If SF bit is not cleared in PL_INT_CAUSE, subsequent non-data interrupts are not raised. Enable SF bit in Global Interrupt Mask and handle it as non-fatal and hence eventually clear it. Signed-off-by: Rahul Lakkireddy Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 16af646a7fe4..d5e316d5481e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4462,7 +4462,7 @@ static void pl_intr_handler(struct adapter *adap) #define PF_INTR_MASK (PFSW_F) #define GLBL_INTR_MASK (CIM_F | MPS_F | PL_F | PCIE_F | MC_F | EDC0_F | \ EDC1_F | LE_F | TP_F | MA_F | PM_TX_F | PM_RX_F | ULP_RX_F | \ - CPL_SWITCH_F | SGE_F | ULP_TX_F) + CPL_SWITCH_F | SGE_F | ULP_TX_F | SF_F) /** * t4_slow_intr_handler - control path interrupt handler -- cgit v1.2.3 From 6d3c8c0dd88a5ffc7e3695997641e4b6d4c11065 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 13 Jun 2017 13:27:19 -0700 Subject: net: dsa: Remove master_netdev and use dst->cpu_dp->netdev In preparation for supporting multiple CPU ports, remove dst->master_netdev and ds->master_netdev and replace them with only one instance of the common object we have for a port: struct dsa_port::netdev. ds->master_netdev is currently write only and would be helpful in the case where we have two switches, both with CPU ports, and also connected within each other, which the multi-CPU port patch series would address. While at it, introduce a helper function used in net/dsa/slave.c to immediately get a reference on the master network device called dsa_master_netdev(). Reviewed-by: Vivien Didelot Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 4 ++-- drivers/net/dsa/mt7530.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 687a8bae5d73..76e98e8ed315 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -806,7 +806,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = ds->dst[ds->index].master_netdev; + struct net_device *p = ds->dst[ds->index].cpu_dp->netdev; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); struct ethtool_wolinfo pwol; @@ -829,7 +829,7 @@ static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = ds->dst[ds->index].master_netdev; + struct net_device *p = ds->dst[ds->index].cpu_dp->netdev; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); s8 cpu_port = ds->dst->cpu_dp->index; struct ethtool_wolinfo pwol; diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 25e00d5e0eec..1e46418a3b74 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -912,11 +912,11 @@ mt7530_setup(struct dsa_switch *ds) struct device_node *dn; struct mt7530_dummy_poll p; - /* The parent node of master_netdev which holds the common system + /* The parent node of cpu_dp->netdev which holds the common system * controller also is the container for two GMACs nodes representing * as two netdev instances. */ - dn = ds->master_netdev->dev.of_node->parent; + dn = ds->dst->cpu_dp->netdev->dev.of_node->parent; priv->ethernet = syscon_node_to_regmap(dn); if (IS_ERR(priv->ethernet)) return PTR_ERR(priv->ethernet); -- cgit v1.2.3 From aaebaf50b502648b1d4d8c93b4be133944c2bbd0 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:53 -0700 Subject: ixgbe: fix race condition with PTP_TX_IN_PROGRESS bits Hardware related to the ixgbe driver is limited to handling a single Tx timestamp request at a time. Thus, the driver ignores requests for Tx timestamp while waiting for the current request to finish. It uses a state bit lock which enforces that only one timestamp request is honored at a time. Unfortunately this suffers from a simple race condition. The bit lock is not cleared until after skb_tstamp_tx() is called notifying applications of a new Tx timestamp. Even a well behaved application sending only one packet at a time and waiting for a response can wake up and send a new packet before the bit lock is cleared. This results in needlessly dropping some Tx timestamp requests. We can fix this by unlocking the state bit as soon as we read the Timestamp register, as this is the first point at which it is safe to unlock. To avoid issues with the skb pointer, we'll use a copy of the pointer and set the global variable in the driver structure to NULL first. This ensures that the next timestamp request does not modify our local copy of the skb pointer. This ensures that well behaved applications do not accidentally race with the unlock bit. Obviously an application which sends multiple Tx timestamp requests at once will still only timestamp one packet at a time. Unfortunately there is nothing we can do about this. Reported-by: David Mirabito Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index d44c728fdc0b..4a2000bfd4ae 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -672,17 +672,26 @@ static void ixgbe_ptp_clear_tx_timestamp(struct ixgbe_adapter *adapter) */ static void ixgbe_ptp_tx_hwtstamp(struct ixgbe_adapter *adapter) { + struct sk_buff *skb = adapter->ptp_tx_skb; struct ixgbe_hw *hw = &adapter->hw; struct skb_shared_hwtstamps shhwtstamps; u64 regval = 0; regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPL); regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPH) << 32; - ixgbe_ptp_convert_to_hwtstamp(adapter, &shhwtstamps, regval); - skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps); - ixgbe_ptp_clear_tx_timestamp(adapter); + /* Handle cleanup of the ptp_tx_skb ourselves, and unlock the state + * bit prior to notifying the stack via skb_tstamp_tx(). This prevents + * well behaved applications from attempting to timestamp again prior + * to the lock bit being clear. + */ + adapter->ptp_tx_skb = NULL; + clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state); + + /* Notify the stack and then free the skb after we've unlocked */ + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } /** -- cgit v1.2.3 From 5fef124d9c75942dc5c2445a3faa8ad37cbf4c82 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:56 -0700 Subject: ixgbe: avoid permanent lock of *_PTP_TX_IN_PROGRESS The ixgbe driver uses a state bit lock to avoid handling more than one Tx timestamp request at once. This is required because hardware is limited to a single set of registers for Tx timestamps. The state bit lock is not properly cleaned up during ixgbe_xmit_frame_ring() if the transmit fails such as due to DMA or TSO failure. In some hardware this results in blocking timestamps until the service task times out. In other hardware this results in a permanent lock of the timestamp bit because we never receive an interrupt indicating the timestamp occurred, since indeed the packet was never transmitted. Fix this by checking for DMA and TSO errors in ixgbe_xmit_frame_ring() and properly cleaning up after ourselves when these occur. Reported-by: Reported-by: David Mirabito Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 812319ab77db..5773df248360 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7875,9 +7875,9 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size) #define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \ IXGBE_TXD_CMD_RS) -static void ixgbe_tx_map(struct ixgbe_ring *tx_ring, - struct ixgbe_tx_buffer *first, - const u8 hdr_len) +static int ixgbe_tx_map(struct ixgbe_ring *tx_ring, + struct ixgbe_tx_buffer *first, + const u8 hdr_len) { struct sk_buff *skb = first->skb; struct ixgbe_tx_buffer *tx_buffer; @@ -8004,7 +8004,7 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring, mmiowb(); } - return; + return 0; dma_error: dev_err(tx_ring->dev, "TX DMA map failed\n"); tx_buffer = &tx_ring->tx_buffer_info[i]; @@ -8034,6 +8034,8 @@ dma_error: first->skb = NULL; tx_ring->next_to_use = i; + + return -1; } static void ixgbe_atr(struct ixgbe_ring *ring, @@ -8407,13 +8409,21 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, #ifdef IXGBE_FCOE xmit_fcoe: #endif /* IXGBE_FCOE */ - ixgbe_tx_map(tx_ring, first, hdr_len); + if (ixgbe_tx_map(tx_ring, first, hdr_len)) + goto cleanup_tx_timestamp; return NETDEV_TX_OK; out_drop: dev_kfree_skb_any(first->skb); first->skb = NULL; +cleanup_tx_timestamp: + if (unlikely(tx_flags & IXGBE_TX_FLAGS_TSTAMP)) { + dev_kfree_skb_any(adapter->ptp_tx_skb); + adapter->ptp_tx_skb = NULL; + cancel_work_sync(&adapter->ptp_tx_work); + clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state); + } return NETDEV_TX_OK; } -- cgit v1.2.3 From 4cc74c01ef8bb59fae98aeda359e8bcf6148943a Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:29:00 -0700 Subject: ixgbe: add statistic indicating number of skipped Tx timestamps The ixgbe driver can only handle one Tx timestamp request at a time. This means it is possible for an application timestamp request to be ignored. There is no easy way for an administrator to determine if this occurred. Add a new statistic which tracks this, tx_hwtstamp_skipped. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 3 +++ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 23 +++++++++++++---------- 3 files changed, 17 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 76263762bea1..eb36106218ad 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -733,6 +733,7 @@ struct ixgbe_adapter { struct timecounter hw_tc; u32 base_incval; u32 tx_hwtstamp_timeouts; + u32 tx_hwtstamp_skipped; u32 rx_hwtstamp_cleared; void (*ptp_setup_sdp)(struct ixgbe_adapter *); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 9113e8099b03..2890e926b498 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -111,6 +111,9 @@ static const struct ixgbe_stats ixgbe_gstrings_stats[] = { {"os2bmc_tx_by_bmc", IXGBE_STAT(stats.b2ospc)}, {"os2bmc_tx_by_host", IXGBE_STAT(stats.o2bspc)}, {"os2bmc_rx_by_host", IXGBE_STAT(stats.b2ogprc)}, + {"tx_hwtstamp_timeouts", IXGBE_STAT(tx_hwtstamp_timeouts)}, + {"tx_hwtstamp_skipped", IXGBE_STAT(tx_hwtstamp_skipped)}, + {"rx_hwtstamp_cleared", IXGBE_STAT(rx_hwtstamp_cleared)}, #ifdef IXGBE_FCOE {"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)}, {"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)}, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 5773df248360..4ea1137ea23f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8337,16 +8337,19 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, protocol = vlan_get_protocol(skb); if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - adapter->ptp_clock && - !test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS, - &adapter->state)) { - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - tx_flags |= IXGBE_TX_FLAGS_TSTAMP; - - /* schedule check for Tx timestamp */ - adapter->ptp_tx_skb = skb_get(skb); - adapter->ptp_tx_start = jiffies; - schedule_work(&adapter->ptp_tx_work); + adapter->ptp_clock) { + if (!test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS, + &adapter->state)) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + tx_flags |= IXGBE_TX_FLAGS_TSTAMP; + + /* schedule check for Tx timestamp */ + adapter->ptp_tx_skb = skb_get(skb); + adapter->ptp_tx_start = jiffies; + schedule_work(&adapter->ptp_tx_work); + } else { + adapter->tx_hwtstamp_skipped++; + } } skb_tx_timestamp(skb); -- cgit v1.2.3 From 622a2ef538fb3ca8eccf49716aba8267d6e95a47 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:29:04 -0700 Subject: ixgbe: check for Tx timestamp timeouts during watchdog The ixgbe driver has logic to handle only one Tx timestamp at a time, using a state bit lock to avoid multiple requests at once. It may be possible, if incredibly unlikely, that a Tx timestamp event is requested but never completes. Since we use an interrupt scheme to determine when the Tx timestamp occurred we would never clear the state bit in this case. Add an ixgbe_ptp_tx_hang() function similar to the already existing ixgbe_ptp_rx_hang() function. This function runs in the watchdog routine and makes sure we eventually recover from this case instead of permanently disabling Tx timestamps. Note: there is no currently known way to cause this without hacking the driver code to force it. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index eb36106218ad..dd5578756ae0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -961,6 +961,7 @@ void ixgbe_ptp_suspend(struct ixgbe_adapter *adapter); void ixgbe_ptp_stop(struct ixgbe_adapter *adapter); void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter); void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter); +void ixgbe_ptp_tx_hang(struct ixgbe_adapter *adapter); void ixgbe_ptp_rx_pktstamp(struct ixgbe_q_vector *, struct sk_buff *); void ixgbe_ptp_rx_rgtstamp(struct ixgbe_q_vector *, struct sk_buff *skb); static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 4ea1137ea23f..3ed212f5a43e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7635,6 +7635,7 @@ static void ixgbe_service_task(struct work_struct *work) if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state)) { ixgbe_ptp_overflow_check(adapter); ixgbe_ptp_rx_hang(adapter); + ixgbe_ptp_tx_hang(adapter); } ixgbe_service_event_complete(adapter); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 4a2000bfd4ae..86d6924a2b71 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -662,6 +662,33 @@ static void ixgbe_ptp_clear_tx_timestamp(struct ixgbe_adapter *adapter) clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state); } +/** + * ixgbe_ptp_tx_hang - detect error case where Tx timestamp never finishes + * @adapter: private network adapter structure + */ +void ixgbe_ptp_tx_hang(struct ixgbe_adapter *adapter) +{ + bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + + IXGBE_PTP_TX_TIMEOUT); + + if (!adapter->ptp_tx_skb) + return; + + if (!test_bit(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state)) + return; + + /* If we haven't received a timestamp within the timeout, it is + * reasonable to assume that it will never occur, so we can unlock the + * timestamp bit when this occurs. + */ + if (timeout) { + cancel_work_sync(&adapter->ptp_tx_work); + ixgbe_ptp_clear_tx_timestamp(adapter); + adapter->tx_hwtstamp_timeouts++; + e_warn(drv, "clearing Tx timestamp hang\n"); + } +} + /** * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp * @adapter: the private adapter struct -- cgit v1.2.3 From 01ec5525fc2a0fcc8f4b796b9bb4ee1c6a5d9415 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Thu, 18 May 2017 14:55:07 -0700 Subject: ixgbe: Bump version number Update ixgbe version number. Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 3ed212f5a43e..c17c8317e001 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -76,7 +76,7 @@ char ixgbe_default_device_descr[] = static char ixgbe_default_device_descr[] = "Intel(R) 10 Gigabit Network Connection"; #endif -#define DRV_VERSION "5.0.0-k" +#define DRV_VERSION "5.1.0-k" const char ixgbe_driver_version[] = DRV_VERSION; static const char ixgbe_copyright[] = "Copyright (c) 1999-2016 Intel Corporation."; -- cgit v1.2.3 From adc2c83e2b317de39220e0004b6556b5ea2bf412 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Thu, 18 May 2017 14:55:23 -0700 Subject: ixgbevf: Bump version number Update ixgbevf version number. Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index aced91c9c034..084c53582793 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -57,7 +57,7 @@ const char ixgbevf_driver_name[] = "ixgbevf"; static const char ixgbevf_driver_string[] = "Intel(R) 10 Gigabit PCI Express Virtual Function Network Driver"; -#define DRV_VERSION "3.2.2-k" +#define DRV_VERSION "4.1.0-k" const char ixgbevf_driver_version[] = DRV_VERSION; static char ixgbevf_copyright[] = "Copyright (c) 2009 - 2015 Intel Corporation."; -- cgit v1.2.3 From d28b194955a9b6e6ccf4383f1baba78bb5a528db Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Tue, 23 May 2017 14:02:23 -0700 Subject: ixgbe: fix writes to PFQDE ixgbe_write_qde() was ignoring the qde parameter which resulted in PFQDE.HIDE_VLAN not being set for X550. Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index e2766da5fe02..0760bd7eeb01 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -818,7 +818,7 @@ static inline void ixgbe_write_qde(struct ixgbe_adapter *adapter, u32 vf, IXGBE_WRITE_FLUSH(hw); /* indicate to hardware that we want to set drop enable */ - reg = IXGBE_QDE_WRITE | IXGBE_QDE_ENABLE; + reg = IXGBE_QDE_WRITE | qde; reg |= i << IXGBE_QDE_IDX_SHIFT; IXGBE_WRITE_REG(hw, IXGBE_QDE, reg); } -- cgit v1.2.3 From 4ebdf8af3017ce242f37be2ae5e5f655dc9846ef Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Thu, 1 Jun 2017 12:06:05 -0700 Subject: ixgbe: Resolve cppcheck format string warning cppcheck warns that the format string is incorrect in the function ixgbe_get_strings(). Since the value cannot be negative, change the variable to unsigned which matches the format specifier. Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 2890e926b498..72c565712a5f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -1277,7 +1277,7 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { char *p = (char *)data; - int i; + unsigned int i; switch (stringset) { case ETH_SS_TEST: -- cgit v1.2.3 From a09c0fc3f5d775231f1884e0e66c495065a461ee Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Sat, 3 Jun 2017 18:01:17 -0400 Subject: ixgbe: pci_set_drvdata must be called before register_netdev We call pci_set_drvdata immediately after calling register_netdev, which leaves a window where tasks writing to the sriov_numvfs sysfs attribute can sneak in and crash the kernel. register_netdev cleans up after itself so placing pci_set_drvdata immediately before it should preserve the intent of commit 0fb6a55cc31f ("ixgbe: fix crash on rmmod after probe fail"). Fixes: 0fb6a55cc31f ("ixgbe: fix crash on rmmod after probe fail") Signed-off-by: Jeff Mahoney Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index c17c8317e001..f3dc5dea9300 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -10372,11 +10372,11 @@ skip_sriov: "hardware.\n"); } strcpy(netdev->name, "eth%d"); + pci_set_drvdata(pdev, adapter); err = register_netdev(netdev); if (err) goto err_register; - pci_set_drvdata(pdev, adapter); /* power down the optics for 82599 SFP+ fiber */ if (hw->mac.ops.disable_tx_laser) -- cgit v1.2.3 From 06e41d8a36689f465006f017bbcd8a73edb98109 Mon Sep 17 00:00:00 2001 From: "Shih-Yuan Lee (FourDollars)" Date: Wed, 14 Jun 2017 14:42:00 +0800 Subject: Bluetooth: btusb: Add support for 0489:e0a2 QCA_ROME device T: Bus=01 Lev=01 Prnt=01 Port=06 Cnt=03 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0489 ProdID=e0a2 Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Shih-Yuan Lee (FourDollars) Suggested-by: Owen Lin Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 278e81186150..bfd5f4bdec80 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -266,6 +266,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME }, + { USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME }, /* Broadcom BCM2035 */ -- cgit v1.2.3 From a88e2676a6cd3352c2f590f872233d83d8db289c Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Tue, 13 Jun 2017 22:45:11 +0800 Subject: macvlan: propagate the mac address change status for lowerdev The macvlan dev should propagate the return value of mac address change for lower device in the passthru mode, instead of always return 0. Signed-off-by: Zhang Shengju Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 346ad2ff3998..ade1213e8a87 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -703,10 +703,8 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - if (vlan->mode == MACVLAN_MODE_PASSTHRU) { - dev_set_mac_address(vlan->lowerdev, addr); - return 0; - } + if (vlan->mode == MACVLAN_MODE_PASSTHRU) + return dev_set_mac_address(vlan->lowerdev, addr); return macvlan_sync_address(dev, addr->sa_data); } -- cgit v1.2.3 From 7ca36994a3479e6d9d81baba34a426c47691ea08 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Wed, 14 Jun 2017 09:27:39 +0200 Subject: mlxsw: reg: Add MCIA register for cable info access The MCIA register is used to access the SFP+ and QSFP connector's EPROM. It will be used to query the cable info. Signed-off-by: Arkadi Sharshevsky Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 76 +++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 157b9b6f8485..1bd34d9a7b9e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -5491,6 +5491,81 @@ static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name); } +/* MCIA - Management Cable Info Access + * ----------------------------------- + * MCIA register is used to access the SFP+ and QSFP connector's EPROM. + */ + +#define MLXSW_REG_MCIA_ID 0x9014 +#define MLXSW_REG_MCIA_LEN 0x40 + +MLXSW_REG_DEFINE(mcia, MLXSW_REG_MCIA_ID, MLXSW_REG_MCIA_LEN); + +/* reg_mcia_l + * Lock bit. Setting this bit will lock the access to the specific + * cable. Used for updating a full page in a cable EPROM. Any access + * other then subsequence writes will fail while the port is locked. + * Access: RW + */ +MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1); + +/* reg_mcia_module + * Module number. + * Access: Index + */ +MLXSW_ITEM32(reg, mcia, module, 0x00, 16, 8); + +/* reg_mcia_status + * Module status. + * Access: RO + */ +MLXSW_ITEM32(reg, mcia, status, 0x00, 0, 8); + +/* reg_mcia_i2c_device_address + * I2C device address. + * Access: RW + */ +MLXSW_ITEM32(reg, mcia, i2c_device_address, 0x04, 24, 8); + +/* reg_mcia_page_number + * Page number. + * Access: RW + */ +MLXSW_ITEM32(reg, mcia, page_number, 0x04, 16, 8); + +/* reg_mcia_device_address + * Device address. + * Access: RW + */ +MLXSW_ITEM32(reg, mcia, device_address, 0x04, 0, 16); + +/* reg_mcia_size + * Number of bytes to read/write (up to 48 bytes). + * Access: RW + */ +MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); + +#define MLXSW_SP_REG_MCIA_EEPROM_SIZE 48 + +/* reg_mcia_eeprom + * Bytes to read/write. + * Access: RW + */ +MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_SP_REG_MCIA_EEPROM_SIZE); + +static inline void mlxsw_reg_mcia_pack(char *payload, u8 module, u8 lock, + u8 page_number, u16 device_addr, + u8 size, u8 i2c_device_addr) +{ + MLXSW_REG_ZERO(mcia, payload); + mlxsw_reg_mcia_module_set(payload, module); + mlxsw_reg_mcia_l_set(payload, lock); + mlxsw_reg_mcia_page_number_set(payload, page_number); + mlxsw_reg_mcia_device_address_set(payload, device_addr); + mlxsw_reg_mcia_size_set(payload, size); + mlxsw_reg_mcia_i2c_device_address_set(payload, i2c_device_addr); +} + /* MPAT - Monitoring Port Analyzer Table * ------------------------------------- * MPAT Register is used to query and configure the Switch PortAnalyzer Table. @@ -6433,6 +6508,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(mfsl), MLXSW_REG(mtcap), MLXSW_REG(mtmp), + MLXSW_REG(mcia), MLXSW_REG(mpat), MLXSW_REG(mpar), MLXSW_REG(mlcr), -- cgit v1.2.3 From 2ea109039cd39a253a70c49394d05081580e9e3b Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Wed, 14 Jun 2017 09:27:40 +0200 Subject: mlxsw: spectrum: Add support for access cable info via ethtool Add support for access cable info via ethtool. Signed-off-by: Arkadi Sharshevsky Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 131 +++++++++++++++++++++++++ 1 file changed, 131 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 0e51c3693243..60bf8f27cc00 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2519,6 +2519,135 @@ out: return err; } +#define MLXSW_SP_QSFP_I2C_ADDR 0x50 + +static int mlxsw_sp_query_module_eeprom(struct mlxsw_sp_port *mlxsw_sp_port, + u16 offset, u16 size, void *data, + unsigned int *p_read_size) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + char eeprom_tmp[MLXSW_SP_REG_MCIA_EEPROM_SIZE]; + char mcia_pl[MLXSW_REG_MCIA_LEN]; + int status; + int err; + + size = min_t(u16, size, MLXSW_SP_REG_MCIA_EEPROM_SIZE); + mlxsw_reg_mcia_pack(mcia_pl, mlxsw_sp_port->mapping.module, + 0, 0, offset, size, MLXSW_SP_QSFP_I2C_ADDR); + + err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mcia), mcia_pl); + if (err) + return err; + + status = mlxsw_reg_mcia_status_get(mcia_pl); + if (status) + return -EIO; + + mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp); + memcpy(data, eeprom_tmp, size); + *p_read_size = size; + + return 0; +} + +enum mlxsw_sp_eeprom_module_info_rev_id { + MLXSW_SP_EEPROM_MODULE_INFO_REV_ID_UNSPC = 0x00, + MLXSW_SP_EEPROM_MODULE_INFO_REV_ID_8436 = 0x01, + MLXSW_SP_EEPROM_MODULE_INFO_REV_ID_8636 = 0x03, +}; + +enum mlxsw_sp_eeprom_module_info_id { + MLXSW_SP_EEPROM_MODULE_INFO_ID_SFP = 0x03, + MLXSW_SP_EEPROM_MODULE_INFO_ID_QSFP = 0x0C, + MLXSW_SP_EEPROM_MODULE_INFO_ID_QSFP_PLUS = 0x0D, + MLXSW_SP_EEPROM_MODULE_INFO_ID_QSFP28 = 0x11, +}; + +enum mlxsw_sp_eeprom_module_info { + MLXSW_SP_EEPROM_MODULE_INFO_ID, + MLXSW_SP_EEPROM_MODULE_INFO_REV_ID, + MLXSW_SP_EEPROM_MODULE_INFO_SIZE, +}; + +static int mlxsw_sp_get_module_info(struct net_device *netdev, + struct ethtool_modinfo *modinfo) +{ + struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev); + u8 module_info[MLXSW_SP_EEPROM_MODULE_INFO_SIZE]; + u8 module_rev_id, module_id; + unsigned int read_size; + int err; + + err = mlxsw_sp_query_module_eeprom(mlxsw_sp_port, 0, + MLXSW_SP_EEPROM_MODULE_INFO_SIZE, + module_info, &read_size); + if (err) + return err; + + if (read_size < MLXSW_SP_EEPROM_MODULE_INFO_SIZE) + return -EIO; + + module_rev_id = module_info[MLXSW_SP_EEPROM_MODULE_INFO_REV_ID]; + module_id = module_info[MLXSW_SP_EEPROM_MODULE_INFO_ID]; + + switch (module_id) { + case MLXSW_SP_EEPROM_MODULE_INFO_ID_QSFP: + modinfo->type = ETH_MODULE_SFF_8436; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + break; + case MLXSW_SP_EEPROM_MODULE_INFO_ID_QSFP_PLUS: + case MLXSW_SP_EEPROM_MODULE_INFO_ID_QSFP28: + if (module_id == MLXSW_SP_EEPROM_MODULE_INFO_ID_QSFP28 || + module_rev_id >= MLXSW_SP_EEPROM_MODULE_INFO_REV_ID_8636) { + modinfo->type = ETH_MODULE_SFF_8636; + modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; + } else { + modinfo->type = ETH_MODULE_SFF_8436; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + } + break; + case MLXSW_SP_EEPROM_MODULE_INFO_ID_SFP: + modinfo->type = ETH_MODULE_SFF_8472; + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mlxsw_sp_get_module_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, + u8 *data) +{ + struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev); + int offset = ee->offset; + unsigned int read_size; + int i = 0; + int err; + + if (!ee->len) + return -EINVAL; + + memset(data, 0, ee->len); + + while (i < ee->len) { + err = mlxsw_sp_query_module_eeprom(mlxsw_sp_port, offset, + ee->len - i, data + i, + &read_size); + if (err) { + netdev_err(mlxsw_sp_port->dev, "Eeprom query failed\n"); + return err; + } + + i += read_size; + offset += read_size; + } + + return 0; +} + static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { .get_drvinfo = mlxsw_sp_port_get_drvinfo, .get_link = ethtool_op_get_link, @@ -2531,6 +2660,8 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { .get_link_ksettings = mlxsw_sp_port_get_link_ksettings, .set_link_ksettings = mlxsw_sp_port_set_link_ksettings, .flash_device = mlxsw_sp_flash_device, + .get_module_info = mlxsw_sp_get_module_info, + .get_module_eeprom = mlxsw_sp_get_module_eeprom, }; static int -- cgit v1.2.3 From 0331402aeaefe858709b0a4d44ade15f82d3a119 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 14 Jun 2017 12:10:10 +0300 Subject: qed: Fix an off by one bug The p_l2_info->pp_qid_usage[] array has "p_l2_info->queues" elements so the > here should be a >= or we write beyond the end of the array. Fixes: bbe3f233ec5e ("qed: Assign a unique per-queue index to queue-cid") Signed-off-by: Dan Carpenter Acked-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index cb8b05dbfc6e..e57699bfbdfa 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -161,7 +161,7 @@ static bool qed_eth_queue_qid_usage_add(struct qed_hwfn *p_hwfn, mutex_lock(&p_l2_info->lock); - if (queue_id > p_l2_info->queues) { + if (queue_id >= p_l2_info->queues) { DP_NOTICE(p_hwfn, "Requested to increase usage for qzone %04x out of %08x\n", queue_id, p_l2_info->queues); -- cgit v1.2.3 From f5165a5492237d33239176e7e171c7a8991583cb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 14 Jun 2017 13:41:52 +0300 Subject: net/mlxfw: fix a NULL dereference If we hit this error path we end up returning ERR_PTR(0) which is NULL. The caller is not expecting that so it results in a NULL dereference. Fixes: 410ed13cae39 ("Add the mlxfw module for Mellanox firmware flash process") Signed-off-by: Dan Carpenter Acked-by: Yotam Gigi Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c index 628150d28061..993cb5ba934e 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c @@ -594,6 +594,7 @@ mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file, if (memcmp(comp_data->buff, mlxfw_mfa2_comp_magic, mlxfw_mfa2_comp_magic_len) != 0) { pr_err("Component has wrong magic\n"); + err = -EINVAL; goto err_out; } -- cgit v1.2.3 From 0430a26054733de6e7884a4d2872613f9d8b9a66 Mon Sep 17 00:00:00 2001 From: Weilin Chang Date: Wed, 14 Jun 2017 09:11:31 -0700 Subject: liquidio: fix VF driver off-by-one bug when setting ethtool -C ethX rx-frames Signed-off-by: Weilin Chang Signed-off-by: Derek Chickles Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index 53856af07d46..28ecda3d3404 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -1808,7 +1808,7 @@ oct_cfg_rx_intrcnt(struct lio *lio, (octeon_read_csr64( oct, CN23XX_VF_SLI_OQ_PKT_INT_LEVELS(q_no)) & (0x3fffff00000000UL)) | - rx_max_coalesced_frames); + (rx_max_coalesced_frames - 1)); /*consider writing to resend bit here*/ } intrmod->rx_frames = rx_max_coalesced_frames; -- cgit v1.2.3 From 8a56aa107f1e812347cc1209aa674e1361375af8 Mon Sep 17 00:00:00 2001 From: Arun Parameswaran Date: Mon, 12 Jun 2017 13:26:01 -0700 Subject: ptp: Add a ptp clock driver for Broadcom DTE This patch adds a ptp clock driver for the Broadcom SoCs using the Digital timing Engine (DTE) nco. Signed-off-by: Arun Parameswaran Signed-off-by: David S. Miller --- drivers/ptp/Kconfig | 16 +++ drivers/ptp/Makefile | 1 + drivers/ptp/ptp_dte.c | 353 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 370 insertions(+) create mode 100644 drivers/ptp/ptp_dte.c (limited to 'drivers') diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 384f661a6496..a21ad10d613c 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -25,6 +25,22 @@ config PTP_1588_CLOCK To compile this driver as a module, choose M here: the module will be called ptp. +config PTP_1588_CLOCK_DTE + tristate "Broadcom DTE as PTP clock" + depends on PTP_1588_CLOCK + depends on NET && HAS_IOMEM + depends on ARCH_BCM_MOBILE || (ARCH_BCM_IPROC && !(ARCH_BCM_NSP || ARCH_BCM_5301X)) || COMPILE_TEST + default y + help + This driver adds support for using the Digital timing engine + (DTE) in the Broadcom SoC's as a PTP clock. + + The clock can be used in both wired and wireless networks + for PTP purposes. + + To compile this driver as a module, choose M here: the module + will be called ptp_dte. + config PTP_1588_CLOCK_GIANFAR tristate "Freescale eTSEC as PTP clock" depends on GIANFAR diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile index 530736161a8b..d1f2fb19c980 100644 --- a/drivers/ptp/Makefile +++ b/drivers/ptp/Makefile @@ -4,6 +4,7 @@ ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o +obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o obj-$(CONFIG_PTP_1588_CLOCK_PCH) += ptp_pch.o obj-$(CONFIG_PTP_1588_CLOCK_KVM) += ptp_kvm.o diff --git a/drivers/ptp/ptp_dte.c b/drivers/ptp/ptp_dte.c new file mode 100644 index 000000000000..00145a3f1e70 --- /dev/null +++ b/drivers/ptp/ptp_dte.c @@ -0,0 +1,353 @@ +/* + * Copyright 2017 Broadcom + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#define DTE_NCO_LOW_TIME_REG 0x00 +#define DTE_NCO_TIME_REG 0x04 +#define DTE_NCO_OVERFLOW_REG 0x08 +#define DTE_NCO_INC_REG 0x0c + +#define DTE_NCO_SUM2_MASK 0xffffffff +#define DTE_NCO_SUM2_SHIFT 4ULL + +#define DTE_NCO_SUM3_MASK 0xff +#define DTE_NCO_SUM3_SHIFT 36ULL +#define DTE_NCO_SUM3_WR_SHIFT 8 + +#define DTE_NCO_TS_WRAP_MASK 0xfff +#define DTE_NCO_TS_WRAP_LSHIFT 32 + +#define DTE_NCO_INC_DEFAULT 0x80000000 +#define DTE_NUM_REGS_TO_RESTORE 4 + +/* Full wrap around is 44bits in ns (~4.887 hrs) */ +#define DTE_WRAP_AROUND_NSEC_SHIFT 44 + +/* 44 bits NCO */ +#define DTE_NCO_MAX_NS 0xFFFFFFFFFFF + +/* 125MHz with 3.29 reg cfg */ +#define DTE_PPB_ADJ(ppb) (u32)(div64_u64((((u64)abs(ppb) * BIT(28)) +\ + 62500000ULL), 125000000ULL)) + +/* ptp dte priv structure */ +struct ptp_dte { + void __iomem *regs; + struct ptp_clock *ptp_clk; + struct ptp_clock_info caps; + struct device *dev; + u32 ts_ovf_last; + u32 ts_wrap_cnt; + spinlock_t lock; + u32 reg_val[DTE_NUM_REGS_TO_RESTORE]; +}; + +static void dte_write_nco(void __iomem *regs, s64 ns) +{ + u32 sum2, sum3; + + sum2 = (u32)((ns >> DTE_NCO_SUM2_SHIFT) & DTE_NCO_SUM2_MASK); + /* compensate for ignoring sum1 */ + if (sum2 != DTE_NCO_SUM2_MASK) + sum2++; + + /* to write sum3, bits [15:8] needs to be written */ + sum3 = (u32)(((ns >> DTE_NCO_SUM3_SHIFT) & DTE_NCO_SUM3_MASK) << + DTE_NCO_SUM3_WR_SHIFT); + + writel(0, (regs + DTE_NCO_LOW_TIME_REG)); + writel(sum2, (regs + DTE_NCO_TIME_REG)); + writel(sum3, (regs + DTE_NCO_OVERFLOW_REG)); +} + +static s64 dte_read_nco(void __iomem *regs) +{ + u32 sum2, sum3; + s64 ns; + + /* + * ignoring sum1 (4 bits) gives a 16ns resolution, which + * works due to the async register read. + */ + sum3 = readl(regs + DTE_NCO_OVERFLOW_REG) & DTE_NCO_SUM3_MASK; + sum2 = readl(regs + DTE_NCO_TIME_REG); + ns = ((s64)sum3 << DTE_NCO_SUM3_SHIFT) | + ((s64)sum2 << DTE_NCO_SUM2_SHIFT); + + return ns; +} + +static void dte_write_nco_delta(struct ptp_dte *ptp_dte, s64 delta) +{ + s64 ns; + + ns = dte_read_nco(ptp_dte->regs); + + /* handle wraparound conditions */ + if ((delta < 0) && (abs(delta) > ns)) { + if (ptp_dte->ts_wrap_cnt) { + ns += DTE_NCO_MAX_NS + delta; + ptp_dte->ts_wrap_cnt--; + } else { + ns = 0; + } + } else { + ns += delta; + if (ns > DTE_NCO_MAX_NS) { + ptp_dte->ts_wrap_cnt++; + ns -= DTE_NCO_MAX_NS; + } + } + + dte_write_nco(ptp_dte->regs, ns); + + ptp_dte->ts_ovf_last = (ns >> DTE_NCO_TS_WRAP_LSHIFT) & + DTE_NCO_TS_WRAP_MASK; +} + +static s64 dte_read_nco_with_ovf(struct ptp_dte *ptp_dte) +{ + u32 ts_ovf; + s64 ns = 0; + + ns = dte_read_nco(ptp_dte->regs); + + /*Timestamp overflow: 8 LSB bits of sum3, 4 MSB bits of sum2 */ + ts_ovf = (ns >> DTE_NCO_TS_WRAP_LSHIFT) & DTE_NCO_TS_WRAP_MASK; + + /* Check for wrap around */ + if (ts_ovf < ptp_dte->ts_ovf_last) + ptp_dte->ts_wrap_cnt++; + + ptp_dte->ts_ovf_last = ts_ovf; + + /* adjust for wraparounds */ + ns += (s64)(BIT_ULL(DTE_WRAP_AROUND_NSEC_SHIFT) * ptp_dte->ts_wrap_cnt); + + return ns; +} + +static int ptp_dte_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + u32 nco_incr; + unsigned long flags; + struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps); + + if (abs(ppb) > ptp_dte->caps.max_adj) { + dev_err(ptp_dte->dev, "ppb adj too big\n"); + return -EINVAL; + } + + if (ppb < 0) + nco_incr = DTE_NCO_INC_DEFAULT - DTE_PPB_ADJ(ppb); + else + nco_incr = DTE_NCO_INC_DEFAULT + DTE_PPB_ADJ(ppb); + + spin_lock_irqsave(&ptp_dte->lock, flags); + writel(nco_incr, ptp_dte->regs + DTE_NCO_INC_REG); + spin_unlock_irqrestore(&ptp_dte->lock, flags); + + return 0; +} + +static int ptp_dte_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + unsigned long flags; + struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps); + + spin_lock_irqsave(&ptp_dte->lock, flags); + dte_write_nco_delta(ptp_dte, delta); + spin_unlock_irqrestore(&ptp_dte->lock, flags); + + return 0; +} + +static int ptp_dte_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + unsigned long flags; + struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps); + + spin_lock_irqsave(&ptp_dte->lock, flags); + *ts = ns_to_timespec64(dte_read_nco_with_ovf(ptp_dte)); + spin_unlock_irqrestore(&ptp_dte->lock, flags); + + return 0; +} + +static int ptp_dte_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + unsigned long flags; + struct ptp_dte *ptp_dte = container_of(ptp, struct ptp_dte, caps); + + spin_lock_irqsave(&ptp_dte->lock, flags); + + /* Disable nco increment */ + writel(0, ptp_dte->regs + DTE_NCO_INC_REG); + + dte_write_nco(ptp_dte->regs, timespec64_to_ns(ts)); + + /* reset overflow and wrap counter */ + ptp_dte->ts_ovf_last = 0; + ptp_dte->ts_wrap_cnt = 0; + + /* Enable nco increment */ + writel(DTE_NCO_INC_DEFAULT, ptp_dte->regs + DTE_NCO_INC_REG); + + spin_unlock_irqrestore(&ptp_dte->lock, flags); + + return 0; +} + +static int ptp_dte_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + return -EOPNOTSUPP; +} + +static struct ptp_clock_info ptp_dte_caps = { + .owner = THIS_MODULE, + .name = "DTE PTP timer", + .max_adj = 50000000, + .n_ext_ts = 0, + .n_pins = 0, + .pps = 0, + .adjfreq = ptp_dte_adjfreq, + .adjtime = ptp_dte_adjtime, + .gettime64 = ptp_dte_gettime, + .settime64 = ptp_dte_settime, + .enable = ptp_dte_enable, +}; + +static int ptp_dte_probe(struct platform_device *pdev) +{ + struct ptp_dte *ptp_dte; + struct device *dev = &pdev->dev; + struct resource *res; + + ptp_dte = devm_kzalloc(dev, sizeof(struct ptp_dte), GFP_KERNEL); + if (!ptp_dte) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ptp_dte->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(ptp_dte->regs)) { + dev_err(dev, + "%s: io remap failed\n", __func__); + return PTR_ERR(ptp_dte->regs); + } + + spin_lock_init(&ptp_dte->lock); + + ptp_dte->dev = dev; + ptp_dte->caps = ptp_dte_caps; + ptp_dte->ptp_clk = ptp_clock_register(&ptp_dte->caps, &pdev->dev); + if (IS_ERR(ptp_dte->ptp_clk)) { + dev_err(dev, + "%s: Failed to register ptp clock\n", __func__); + return PTR_ERR(ptp_dte->ptp_clk); + } + + platform_set_drvdata(pdev, ptp_dte); + + dev_info(dev, "ptp clk probe done\n"); + + return 0; +} + +static int ptp_dte_remove(struct platform_device *pdev) +{ + struct ptp_dte *ptp_dte = platform_get_drvdata(pdev); + u8 i; + + ptp_clock_unregister(ptp_dte->ptp_clk); + + for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) + writel(0, ptp_dte->regs + (i * sizeof(u32))); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int ptp_dte_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ptp_dte *ptp_dte = platform_get_drvdata(pdev); + u8 i; + + for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) { + ptp_dte->reg_val[i] = + readl(ptp_dte->regs + (i * sizeof(u32))); + } + + /* disable the nco */ + writel(0, ptp_dte->regs + DTE_NCO_INC_REG); + + return 0; +} + +static int ptp_dte_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ptp_dte *ptp_dte = platform_get_drvdata(pdev); + u8 i; + + for (i = 0; i < DTE_NUM_REGS_TO_RESTORE; i++) { + if ((i * sizeof(u32)) != DTE_NCO_OVERFLOW_REG) + writel(ptp_dte->reg_val[i], + (ptp_dte->regs + (i * sizeof(u32)))); + else + writel(((ptp_dte->reg_val[i] & + DTE_NCO_SUM3_MASK) << DTE_NCO_SUM3_WR_SHIFT), + (ptp_dte->regs + (i * sizeof(u32)))); + } + + return 0; +} + +static const struct dev_pm_ops ptp_dte_pm_ops = { + .suspend = ptp_dte_suspend, + .resume = ptp_dte_resume +}; + +#define PTP_DTE_PM_OPS (&ptp_dte_pm_ops) +#else +#define PTP_DTE_PM_OPS NULL +#endif + +static const struct of_device_id ptp_dte_of_match[] = { + { .compatible = "brcm,ptp-dte", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ptp_dte_of_match); + +static struct platform_driver ptp_dte_driver = { + .driver = { + .name = "ptp-dte", + .pm = PTP_DTE_PM_OPS, + .of_match_table = ptp_dte_of_match, + }, + .probe = ptp_dte_probe, + .remove = ptp_dte_remove, +}; +module_platform_driver(ptp_dte_driver); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("Broadcom DTE PTP Clock driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 824669218226a71300ef31862ae49b9465614513 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 15 Jun 2017 12:13:59 -0400 Subject: net: dsa: mv88e6xxx: prefix Global Status macros Prefix and document the Global Status Register macros and give clear 16-bit register representation. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 4 ++-- drivers/net/dsa/mv88e6xxx/global1.c | 20 ++++++++++---------- drivers/net/dsa/mv88e6xxx/global1.h | 36 +++++++++++++++++++----------------- drivers/net/dsa/mv88e6xxx/global2.c | 4 ++-- 4 files changed, 33 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index fb950ca29081..9cc10dadf17c 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -261,7 +261,7 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_fn(int irq, void *dev_id) int err; mutex_lock(&chip->reg_lock); - err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, ®); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); mutex_unlock(&chip->reg_lock); if (err) @@ -381,7 +381,7 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) goto out_disable; /* Reading the interrupt status clears (most of) them */ - err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, ®); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, ®); if (err) goto out_disable; diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 4081ff0d38a0..84559d22bf4e 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -42,13 +42,13 @@ static int mv88e6185_g1_wait_ppu_disabled(struct mv88e6xxx_chip *chip) int i, err; for (i = 0; i < 16; i++) { - err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state); if (err) return err; /* Check the value of the PPUState bits 15:14 */ - state &= GLOBAL_STATUS_PPU_STATE_MASK; - if (state != GLOBAL_STATUS_PPU_STATE_POLLING) + state &= MV88E6185_G1_STS_PPU_STATE_MASK; + if (state != MV88E6185_G1_STS_PPU_STATE_POLLING) return 0; usleep_range(1000, 2000); @@ -63,13 +63,13 @@ static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip) int i, err; for (i = 0; i < 16; ++i) { - err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state); if (err) return err; /* Check the value of the PPUState bits 15:14 */ - state &= GLOBAL_STATUS_PPU_STATE_MASK; - if (state == GLOBAL_STATUS_PPU_STATE_POLLING) + state &= MV88E6185_G1_STS_PPU_STATE_MASK; + if (state == MV88E6185_G1_STS_PPU_STATE_POLLING) return 0; usleep_range(1000, 2000); @@ -84,12 +84,12 @@ static int mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip) int i, err; for (i = 0; i < 16; ++i) { - err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &state); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state); if (err) return err; /* Check the value of the PPUState (or InitState) bit 15 */ - if (state & GLOBAL_STATUS_PPU_STATE) + if (state & MV88E6352_G1_STS_PPU_STATE) return 0; usleep_range(1000, 2000); @@ -109,11 +109,11 @@ static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip) * have finished their initialization and are ready to accept frames. */ while (time_before(jiffies, timeout)) { - err = mv88e6xxx_g1_read(chip, GLOBAL_STATUS, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &val); if (err) return err; - if (val & GLOBAL_STATUS_INIT_READY) + if (val & MV88E6XXX_G1_STS_INIT_READY) break; usleep_range(1000, 2000); diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 3e2765c53f89..7ad63a049249 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -17,23 +17,25 @@ #include "chip.h" -#define GLOBAL_STATUS 0x00 -#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ -#define GLOBAL_STATUS_PPU_STATE_MASK (0x3 << 14) /* 6165 6185 */ -#define GLOBAL_STATUS_PPU_STATE_DISABLED_RST (0x0 << 14) -#define GLOBAL_STATUS_PPU_STATE_INITIALIZING (0x1 << 14) -#define GLOBAL_STATUS_PPU_STATE_DISABLED (0x2 << 14) -#define GLOBAL_STATUS_PPU_STATE_POLLING (0x3 << 14) -#define GLOBAL_STATUS_INIT_READY BIT(11) -#define GLOBAL_STATUS_IRQ_AVB 8 -#define GLOBAL_STATUS_IRQ_DEVICE 7 -#define GLOBAL_STATUS_IRQ_STATS 6 -#define GLOBAL_STATUS_IRQ_VTU_PROBLEM 5 -#define GLOBAL_STATUS_IRQ_VTU_DONE 4 -#define GLOBAL_STATUS_IRQ_ATU_PROBLEM 3 -#define GLOBAL_STATUS_IRQ_ATU_DONE 2 -#define GLOBAL_STATUS_IRQ_TCAM_DONE 1 -#define GLOBAL_STATUS_IRQ_EEPROM_DONE 0 +/* Offset 0x00: Switch Global Status Register */ +#define MV88E6XXX_G1_STS 0x00 +#define MV88E6352_G1_STS_PPU_STATE 0x8000 +#define MV88E6185_G1_STS_PPU_STATE_MASK 0xc000 +#define MV88E6185_G1_STS_PPU_STATE_DISABLED_RST 0x0000 +#define MV88E6185_G1_STS_PPU_STATE_INITIALIZING 0x4000 +#define MV88E6185_G1_STS_PPU_STATE_DISABLED 0x8000 +#define MV88E6185_G1_STS_PPU_STATE_POLLING 0xc000 +#define MV88E6XXX_G1_STS_INIT_READY 0x0800 +#define MV88E6XXX_G1_STS_IRQ_AVB 8 +#define MV88E6XXX_G1_STS_IRQ_DEVICE 7 +#define MV88E6XXX_G1_STS_IRQ_STATS 6 +#define MV88E6XXX_G1_STS_IRQ_VTU_PROBLEM 5 +#define MV88E6XXX_G1_STS_IRQ_VTU_DONE 4 +#define MV88E6XXX_G1_STS_IRQ_ATU_PROBLEM 3 +#define MV88E6XXX_G1_STS_IRQ_ATU_DONE 2 +#define MV88E6XXX_G1_STS_IRQ_TCAM_DONE 1 +#define MV88E6XXX_G1_STS_IRQ_EEPROM_DONE 0 + #define GLOBAL_MAC_01 0x01 #define GLOBAL_MAC_23 0x02 #define GLOBAL_MAC_45 0x03 diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index d63af31e7840..8e8bc4ee464f 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -17,7 +17,7 @@ #include #include "chip.h" -#include "global1.h" /* for GLOBAL_STATUS_IRQ_DEVICE */ +#include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */ #include "global2.h" static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) @@ -977,7 +977,7 @@ int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip) chip->g2_irq.masked = ~0; chip->device_irq = irq_find_mapping(chip->g1_irq.domain, - GLOBAL_STATUS_IRQ_DEVICE); + MV88E6XXX_G1_STS_IRQ_DEVICE); if (chip->device_irq < 0) { err = chip->device_irq; goto out; -- cgit v1.2.3 From 4b0c481717b9896fa7a778dfd0b197ce8325bd1a Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 15 Jun 2017 12:14:00 -0400 Subject: net: dsa: mv88e6xxx: prefix Global Switch MAC macros Prefix and document the Global Switch MAC Address Register macros and give clear 16-bit register representation. At the same time, move mv88e6xxx_g1_set_switch_mac in global1.c, where it belongs. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 19 ------------------- drivers/net/dsa/mv88e6xxx/global1.c | 27 +++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/global1.h | 13 ++++++++++--- 3 files changed, 37 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 9cc10dadf17c..b048f851786a 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1979,25 +1979,6 @@ static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port, mutex_unlock(&chip->reg_lock); } -static int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) -{ - int err; - - err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]); - if (err) - return err; - - err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]); - if (err) - return err; - - err = mv88e6xxx_g1_write(chip, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]); - if (err) - return err; - - return 0; -} - static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds, unsigned int ageing_time) { diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 84559d22bf4e..0ddf1021442b 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -125,6 +125,33 @@ static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip) return 0; } +/* Offset 0x01: Switch MAC Address Register Bytes 0 & 1 + * Offset 0x02: Switch MAC Address Register Bytes 2 & 3 + * Offset 0x03: Switch MAC Address Register Bytes 4 & 5 + */ +int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) +{ + u16 reg; + int err; + + reg = (addr[0] << 8) | addr[1]; + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_01, reg); + if (err) + return err; + + reg = (addr[2] << 8) | addr[3]; + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_23, reg); + if (err) + return err; + + reg = (addr[4] << 8) | addr[5]; + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_45, reg); + if (err) + return err; + + return 0; +} + /* Offset 0x04: Switch Global Control Register */ int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip) diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 7ad63a049249..267233d40cb3 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -36,9 +36,14 @@ #define MV88E6XXX_G1_STS_IRQ_TCAM_DONE 1 #define MV88E6XXX_G1_STS_IRQ_EEPROM_DONE 0 -#define GLOBAL_MAC_01 0x01 -#define GLOBAL_MAC_23 0x02 -#define GLOBAL_MAC_45 0x03 +/* Offset 0x01: Switch MAC Address Register Bytes 0 & 1 + * Offset 0x02: Switch MAC Address Register Bytes 2 & 3 + * Offset 0x03: Switch MAC Address Register Bytes 4 & 5 + */ +#define MV88E6XXX_G1_MAC_01 0x01 +#define MV88E6XXX_G1_MAC_23 0x02 +#define MV88E6XXX_G1_MAC_45 0x03 + #define GLOBAL_ATU_FID 0x01 #define GLOBAL_VTU_FID 0x02 #define GLOBAL_VTU_FID_MASK 0xfff @@ -164,6 +169,8 @@ int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val); int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val); int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask); +int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr); + int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip); int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip); -- cgit v1.2.3 From 27c0e60097a55a1831de2ea8121f048b833b9d9a Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 15 Jun 2017 12:14:01 -0400 Subject: net: dsa: mv88e6xxx: prefix Global ATU macros Prefix and document the Global ATU Registers macros and give clear 16-bit registers representation. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 22 +++++----- drivers/net/dsa/mv88e6xxx/global1.h | 75 +++++++++++++++++++-------------- drivers/net/dsa/mv88e6xxx/global1_atu.c | 56 ++++++++++++------------ 3 files changed, 85 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index b048f851786a..066fa63c6b6e 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1383,7 +1383,7 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, if (err) return err; - entry.state = GLOBAL_ATU_DATA_STATE_UNUSED; + entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; ether_addr_copy(entry.mac, addr); eth_addr_dec(entry.mac); @@ -1392,17 +1392,17 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port, return err; /* Initialize a fresh ATU entry if it isn't found */ - if (entry.state == GLOBAL_ATU_DATA_STATE_UNUSED || + if (entry.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED || !ether_addr_equal(entry.mac, addr)) { memset(&entry, 0, sizeof(entry)); ether_addr_copy(entry.mac, addr); } /* Purge the ATU entry only if no port is using it anymore */ - if (state == GLOBAL_ATU_DATA_STATE_UNUSED) { + if (state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) { entry.portvec &= ~BIT(port); if (!entry.portvec) - entry.state = GLOBAL_ATU_DATA_STATE_UNUSED; + entry.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; } else { entry.portvec |= BIT(port); entry.state = state; @@ -1429,7 +1429,7 @@ static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, mutex_lock(&chip->reg_lock); if (mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid, - GLOBAL_ATU_DATA_STATE_UC_STATIC)) + MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC)) dev_err(ds->dev, "p%d: failed to load unicast MAC address\n", port); mutex_unlock(&chip->reg_lock); @@ -1443,7 +1443,7 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, mutex_lock(&chip->reg_lock); err = mv88e6xxx_port_db_load_purge(chip, port, fdb->addr, fdb->vid, - GLOBAL_ATU_DATA_STATE_UNUSED); + MV88E6XXX_G1_ATU_DATA_STATE_UNUSED); mutex_unlock(&chip->reg_lock); return err; @@ -1457,7 +1457,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, struct mv88e6xxx_atu_entry addr; int err; - addr.state = GLOBAL_ATU_DATA_STATE_UNUSED; + addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED; eth_broadcast_addr(addr.mac); do { @@ -1465,7 +1465,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, if (err) return err; - if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED) + if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) break; if (addr.trunk || (addr.portvec & BIT(port)) == 0) @@ -1480,7 +1480,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip, fdb = SWITCHDEV_OBJ_PORT_FDB(obj); fdb->vid = vid; ether_addr_copy(fdb->addr, addr.mac); - if (addr.state == GLOBAL_ATU_DATA_STATE_UC_STATIC) + if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC) fdb->ndm_state = NUD_NOARP; else fdb->ndm_state = NUD_REACHABLE; @@ -3755,7 +3755,7 @@ static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port, mutex_lock(&chip->reg_lock); if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, - GLOBAL_ATU_DATA_STATE_MC_STATIC)) + MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC)) dev_err(ds->dev, "p%d: failed to load multicast MAC address\n", port); mutex_unlock(&chip->reg_lock); @@ -3769,7 +3769,7 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, mutex_lock(&chip->reg_lock); err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid, - GLOBAL_ATU_DATA_STATE_UNUSED); + MV88E6XXX_G1_ATU_DATA_STATE_UNUSED); mutex_unlock(&chip->reg_lock); return err; diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 267233d40cb3..126515532d53 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -44,7 +44,9 @@ #define MV88E6XXX_G1_MAC_23 0x02 #define MV88E6XXX_G1_MAC_45 0x03 -#define GLOBAL_ATU_FID 0x01 +/* Offset 0x01: ATU FID Register */ +#define MV88E6352_G1_ATU_FID 0x01 + #define GLOBAL_VTU_FID 0x02 #define GLOBAL_VTU_FID_MASK 0xfff #define GLOBAL_VTU_SID 0x03 /* 6097 6165 6351 6352 */ @@ -87,36 +89,47 @@ #define GLOBAL_STU_DATA_PORT_STATE_BLOCKING 0x01 #define GLOBAL_STU_DATA_PORT_STATE_LEARNING 0x02 #define GLOBAL_STU_DATA_PORT_STATE_FORWARDING 0x03 -#define GLOBAL_ATU_CONTROL 0x0a -#define GLOBAL_ATU_CONTROL_LEARN2ALL BIT(3) -#define GLOBAL_ATU_OP 0x0b -#define GLOBAL_ATU_OP_BUSY BIT(15) -#define GLOBAL_ATU_OP_NOP (0 << 12) -#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC ((2 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) -#define GLOBAL_ATU_DATA 0x0c -#define GLOBAL_ATU_DATA_TRUNK BIT(15) -#define GLOBAL_ATU_DATA_TRUNK_ID_MASK 0x00f0 -#define GLOBAL_ATU_DATA_TRUNK_ID_SHIFT 4 -#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 -#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4 -#define GLOBAL_ATU_DATA_STATE_MASK 0x0f -#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 -#define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d -#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e -#define GLOBAL_ATU_DATA_STATE_UC_PRIO_OVER 0x0f -#define GLOBAL_ATU_DATA_STATE_MC_NONE_RATE 0x05 -#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 -#define GLOBAL_ATU_DATA_STATE_MC_MGMT 0x0e -#define GLOBAL_ATU_DATA_STATE_MC_PRIO_OVER 0x0f -#define GLOBAL_ATU_MAC_01 0x0d -#define GLOBAL_ATU_MAC_23 0x0e -#define GLOBAL_ATU_MAC_45 0x0f + +/* Offset 0x0A: ATU Control Register */ +#define MV88E6XXX_G1_ATU_CTL 0x0a +#define MV88E6XXX_G1_ATU_CTL_LEARN2ALL 0x0008 + +/* Offset 0x0B: ATU Operation Register */ +#define MV88E6XXX_G1_ATU_OP 0x0b +#define MV88E6XXX_G1_ATU_OP_BUSY 0x8000 +#define MV88E6XXX_G1_ATU_OP_MASK 0x7000 +#define MV88E6XXX_G1_ATU_OP_NOOP 0x0000 +#define MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL 0x1000 +#define MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC 0x2000 +#define MV88E6XXX_G1_ATU_OP_LOAD_DB 0x3000 +#define MV88E6XXX_G1_ATU_OP_GET_NEXT_DB 0x4000 +#define MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL_DB 0x5000 +#define MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC_DB 0x6000 +#define MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION 0x7000 + +/* Offset 0x0C: ATU Data Register */ +#define MV88E6XXX_G1_ATU_DATA 0x0c +#define MV88E6XXX_G1_ATU_DATA_TRUNK 0x8000 +#define MV88E6XXX_G1_ATU_DATA_TRUNK_ID_MASK 0x00f0 +#define MV88E6XXX_G1_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 +#define MV88E6XXX_G1_ATU_DATA_STATE_MASK 0x000f +#define MV88E6XXX_G1_ATU_DATA_STATE_UNUSED 0x0000 +#define MV88E6XXX_G1_ATU_DATA_STATE_UC_MGMT 0x000d +#define MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC 0x000e +#define MV88E6XXX_G1_ATU_DATA_STATE_UC_PRIO_OVER 0x000f +#define MV88E6XXX_G1_ATU_DATA_STATE_MC_NONE_RATE 0x0005 +#define MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC 0x0007 +#define MV88E6XXX_G1_ATU_DATA_STATE_MC_MGMT 0x000e +#define MV88E6XXX_G1_ATU_DATA_STATE_MC_PRIO_OVER 0x000f + +/* Offset 0x0D: ATU MAC Address Register Bytes 0 & 1 + * Offset 0x0E: ATU MAC Address Register Bytes 2 & 3 + * Offset 0x0F: ATU MAC Address Register Bytes 4 & 5 + */ +#define MV88E6XXX_G1_ATU_MAC01 0x0d +#define MV88E6XXX_G1_ATU_MAC23 0x0e +#define MV88E6XXX_G1_ATU_MAC45 0x0f + #define GLOBAL_IP_PRI_0 0x10 #define GLOBAL_IP_PRI_1 0x11 #define GLOBAL_IP_PRI_2 0x12 diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index 6b0cf44dc07d..efeef4b01442 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -17,7 +17,7 @@ static int mv88e6xxx_g1_atu_fid_write(struct mv88e6xxx_chip *chip, u16 fid) { - return mv88e6xxx_g1_write(chip, GLOBAL_ATU_FID, fid & 0xfff); + return mv88e6xxx_g1_write(chip, MV88E6352_G1_ATU_FID, fid & 0xfff); } /* Offset 0x0A: ATU Control Register */ @@ -27,16 +27,16 @@ int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all) u16 val; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); if (err) return err; if (learn2all) - val |= GLOBAL_ATU_CONTROL_LEARN2ALL; + val |= MV88E6XXX_G1_ATU_CTL_LEARN2ALL; else - val &= ~GLOBAL_ATU_CONTROL_LEARN2ALL; + val &= ~MV88E6XXX_G1_ATU_CTL_LEARN2ALL; - return mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val); + return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val); } int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, @@ -55,7 +55,7 @@ int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, /* Round to nearest multiple of coeff */ age_time = (msecs + coeff / 2) / coeff; - err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); if (err) return err; @@ -63,7 +63,7 @@ int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, val &= ~0xff0; val |= age_time << 4; - err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val); if (err) return err; @@ -77,7 +77,8 @@ int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip) { - return mv88e6xxx_g1_wait(chip, GLOBAL_ATU_OP, GLOBAL_ATU_OP_BUSY); + return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_ATU_OP, + MV88E6XXX_G1_ATU_OP_BUSY); } static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) @@ -93,12 +94,14 @@ static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) } else { if (mv88e6xxx_num_databases(chip) > 16) { /* ATU DBNum[7:4] are located in ATU Control 15:12 */ - err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_CONTROL, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, + &val); if (err) return err; val = (val & 0x0fff) | ((fid << 8) & 0xf000); - err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_CONTROL, val); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, + val); if (err) return err; } @@ -107,7 +110,8 @@ static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) op |= fid & 0xf; } - err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_OP, op); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP, + MV88E6XXX_G1_ATU_OP_BUSY | op); if (err) return err; @@ -122,13 +126,13 @@ static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip, u16 val; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_DATA, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &val); if (err) return err; entry->state = val & 0xf; - if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) { - entry->trunk = !!(val & GLOBAL_ATU_DATA_TRUNK); + if (entry->state != MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) { + entry->trunk = !!(val & MV88E6XXX_G1_ATU_DATA_TRUNK); entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip); } @@ -140,14 +144,14 @@ static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip, { u16 data = entry->state & 0xf; - if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) { + if (entry->state != MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) { if (entry->trunk) - data |= GLOBAL_ATU_DATA_TRUNK; + data |= MV88E6XXX_G1_ATU_DATA_TRUNK; data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4; } - return mv88e6xxx_g1_write(chip, GLOBAL_ATU_DATA, data); + return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_DATA, data); } /* Offset 0x0D: ATU MAC Address Register Bytes 0 & 1 @@ -162,7 +166,7 @@ static int mv88e6xxx_g1_atu_mac_read(struct mv88e6xxx_chip *chip, int i, err; for (i = 0; i < 3; i++) { - err = mv88e6xxx_g1_read(chip, GLOBAL_ATU_MAC_01 + i, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01 + i, &val); if (err) return err; @@ -181,7 +185,7 @@ static int mv88e6xxx_g1_atu_mac_write(struct mv88e6xxx_chip *chip, for (i = 0; i < 3; i++) { val = (entry->mac[i * 2] << 8) | entry->mac[i * 2 + 1]; - err = mv88e6xxx_g1_write(chip, GLOBAL_ATU_MAC_01 + i, val); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_MAC01 + i, val); if (err) return err; } @@ -201,13 +205,13 @@ int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid, return err; /* Write the MAC address to iterate from only once */ - if (entry->state == GLOBAL_ATU_DATA_STATE_UNUSED) { + if (entry->state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED) { err = mv88e6xxx_g1_atu_mac_write(chip, entry); if (err) return err; } - err = mv88e6xxx_g1_atu_op(chip, fid, GLOBAL_ATU_OP_GET_NEXT_DB); + err = mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB); if (err) return err; @@ -235,7 +239,7 @@ int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid, if (err) return err; - return mv88e6xxx_g1_atu_op(chip, fid, GLOBAL_ATU_OP_LOAD_DB); + return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_LOAD_DB); } static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid, @@ -255,13 +259,13 @@ static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid, /* Flush/Move all or non-static entries from all or a given database */ if (all && fid) - op = GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB; + op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL_DB; else if (fid) - op = GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB; + op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC_DB; else if (all) - op = GLOBAL_ATU_OP_FLUSH_MOVE_ALL; + op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL; else - op = GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC; + op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC; return mv88e6xxx_g1_atu_op(chip, fid, op); } -- cgit v1.2.3 From 7ec60d6e2c400700c740849c9c980aa46499aab4 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 15 Jun 2017 12:14:02 -0400 Subject: net: dsa: mv88e6xxx: prefix Global VTU macros Prefix and document the Global VTU registers macros and give a clear 16-bit registers representation. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 23 ++++++----- drivers/net/dsa/mv88e6xxx/chip.h | 4 +- drivers/net/dsa/mv88e6xxx/global1.h | 69 ++++++++++++++++++++------------- drivers/net/dsa/mv88e6xxx/global1_vtu.c | 62 +++++++++++++++-------------- 4 files changed, 90 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 066fa63c6b6e..f2ce054913e4 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1047,7 +1047,8 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, if (!next.valid) break; - if (next.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) + if (next.member[port] == + MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) continue; /* reinit and dump this VLAN obj */ @@ -1055,7 +1056,8 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, vlan->vid_end = next.vid; vlan->flags = 0; - if (next.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED) + if (next.member[port] == + MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED) vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; if (next.vid == pvid) @@ -1143,7 +1145,7 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid, /* Exclude all ports */ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) entry->member[i] = - GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; + MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; return mv88e6xxx_atu_new(chip, &entry->fid); } @@ -1185,7 +1187,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, continue; if (vlan.member[i] == - GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) + MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) continue; if (ds->ports[i].bridge_dev == @@ -1281,11 +1283,11 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, return; if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) - member = GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED; + member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; else if (untagged) - member = GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED; + member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; else - member = GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED; + member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; mutex_lock(&chip->reg_lock); @@ -1312,15 +1314,16 @@ static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip, return err; /* Tell switchdev if this VLAN is handled in software */ - if (vlan.member[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) + if (vlan.member[port] == MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) return -EOPNOTSUPP; - vlan.member[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER; + vlan.member[port] = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; /* keep the VLAN unless all ports are excluded */ vlan.valid = false; for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { - if (vlan.member[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) { + if (vlan.member[i] != + MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER) { vlan.valid = true; break; } diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index d70873498501..409452ebc4b9 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -127,12 +127,12 @@ enum mv88e6xxx_cap { /* Per VLAN Spanning Tree Unit (STU). * The Port State database, if present, is accessed through VTU - * operations and dedicated SID registers. See GLOBAL_VTU_SID. + * operations and dedicated SID registers. See MV88E6352_G1_VTU_SID. */ MV88E6XXX_CAP_STU, /* VLAN Table Unit. - * The VTU is used to program 802.1Q VLANs. See GLOBAL_VTU_OP. + * The VTU is used to program 802.1Q VLANs. See MV88E6XXX_G1_VTU_OP. */ MV88E6XXX_CAP_VTU, }; diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 126515532d53..56ba709628c7 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -47,10 +47,14 @@ /* Offset 0x01: ATU FID Register */ #define MV88E6352_G1_ATU_FID 0x01 -#define GLOBAL_VTU_FID 0x02 -#define GLOBAL_VTU_FID_MASK 0xfff -#define GLOBAL_VTU_SID 0x03 /* 6097 6165 6351 6352 */ -#define GLOBAL_VTU_SID_MASK 0x3f +/* Offset 0x02: VTU FID Register */ +#define MV88E6352_G1_VTU_FID 0x02 +#define MV88E6352_G1_VTU_FID_MASK 0x0fff + +/* Offset 0x03: VTU SID Register */ +#define MV88E6352_G1_VTU_SID 0x03 +#define MV88E6352_G1_VTU_SID_MASK 0x3f + #define GLOBAL_CONTROL 0x04 #define GLOBAL_CONTROL_SW_RESET BIT(15) #define GLOBAL_CONTROL_PPU_ENABLE BIT(14) @@ -66,29 +70,40 @@ #define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) #define GLOBAL_CONTROL_TCAM_EN BIT(1) #define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) -#define GLOBAL_VTU_OP 0x05 -#define GLOBAL_VTU_OP_BUSY BIT(15) -#define GLOBAL_VTU_OP_FLUSH_ALL ((0x01 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_VTU_LOAD_PURGE ((0x03 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_VTU_GET_NEXT ((0x04 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_STU_LOAD_PURGE ((0x05 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_OP_STU_GET_NEXT ((0x06 << 12) | GLOBAL_VTU_OP_BUSY) -#define GLOBAL_VTU_VID 0x06 -#define GLOBAL_VTU_VID_MASK 0xfff -#define GLOBAL_VTU_VID_PAGE BIT(13) -#define GLOBAL_VTU_VID_VALID BIT(12) -#define GLOBAL_VTU_DATA_0_3 0x07 -#define GLOBAL_VTU_DATA_4_7 0x08 -#define GLOBAL_VTU_DATA_8_11 0x09 -#define GLOBAL_VTU_STU_DATA_MASK 0x03 -#define GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED 0x00 -#define GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED 0x01 -#define GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED 0x02 -#define GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER 0x03 -#define GLOBAL_STU_DATA_PORT_STATE_DISABLED 0x00 -#define GLOBAL_STU_DATA_PORT_STATE_BLOCKING 0x01 -#define GLOBAL_STU_DATA_PORT_STATE_LEARNING 0x02 -#define GLOBAL_STU_DATA_PORT_STATE_FORWARDING 0x03 + +/* Offset 0x05: VTU Operation Register */ +#define MV88E6XXX_G1_VTU_OP 0x05 +#define MV88E6XXX_G1_VTU_OP_BUSY 0x8000 +#define MV88E6XXX_G1_VTU_OP_MASK 0x7000 +#define MV88E6XXX_G1_VTU_OP_FLUSH_ALL 0x1000 +#define MV88E6XXX_G1_VTU_OP_NOOP 0x2000 +#define MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE 0x3000 +#define MV88E6XXX_G1_VTU_OP_VTU_GET_NEXT 0x4000 +#define MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE 0x5000 +#define MV88E6XXX_G1_VTU_OP_STU_GET_NEXT 0x6000 + +/* Offset 0x06: VTU VID Register */ +#define MV88E6XXX_G1_VTU_VID 0x06 +#define MV88E6XXX_G1_VTU_VID_MASK 0x0fff +#define MV88E6390_G1_VTU_VID_PAGE 0x2000 +#define MV88E6XXX_G1_VTU_VID_VALID 0x1000 + +/* Offset 0x07: VTU/STU Data Register 1 + * Offset 0x08: VTU/STU Data Register 2 + * Offset 0x09: VTU/STU Data Register 3 + */ +#define MV88E6XXX_G1_VTU_DATA1 0x07 +#define MV88E6XXX_G1_VTU_DATA2 0x08 +#define MV88E6XXX_G1_VTU_DATA3 0x09 +#define MV88E6XXX_G1_VTU_STU_DATA_MASK 0x0003 +#define MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED 0x0000 +#define MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED 0x0001 +#define MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED 0x0002 +#define MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER 0x0003 +#define MV88E6XXX_G1_STU_DATA_PORT_STATE_DISABLED 0x0000 +#define MV88E6XXX_G1_STU_DATA_PORT_STATE_BLOCKING 0x0001 +#define MV88E6XXX_G1_STU_DATA_PORT_STATE_LEARNING 0x0002 +#define MV88E6XXX_G1_STU_DATA_PORT_STATE_FORWARDING 0x0003 /* Offset 0x0A: ATU Control Register */ #define MV88E6XXX_G1_ATU_CTL 0x0a diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c index bf593c7aaa9b..8c8a0ec3d6e9 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c @@ -22,11 +22,11 @@ static int mv88e6xxx_g1_vtu_fid_read(struct mv88e6xxx_chip *chip, u16 val; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_FID, &val); + err = mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID, &val); if (err) return err; - entry->fid = val & GLOBAL_VTU_FID_MASK; + entry->fid = val & MV88E6352_G1_VTU_FID_MASK; return 0; } @@ -34,9 +34,9 @@ static int mv88e6xxx_g1_vtu_fid_read(struct mv88e6xxx_chip *chip, static int mv88e6xxx_g1_vtu_fid_write(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry) { - u16 val = entry->fid & GLOBAL_VTU_FID_MASK; + u16 val = entry->fid & MV88E6352_G1_VTU_FID_MASK; - return mv88e6xxx_g1_write(chip, GLOBAL_VTU_FID, val); + return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_FID, val); } /* Offset 0x03: VTU SID Register */ @@ -47,11 +47,11 @@ static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip, u16 val; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_SID, &val); + err = mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID, &val); if (err) return err; - entry->sid = val & GLOBAL_VTU_SID_MASK; + entry->sid = val & MV88E6352_G1_VTU_SID_MASK; return 0; } @@ -59,23 +59,25 @@ static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip, static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry) { - u16 val = entry->sid & GLOBAL_VTU_SID_MASK; + u16 val = entry->sid & MV88E6352_G1_VTU_SID_MASK; - return mv88e6xxx_g1_write(chip, GLOBAL_VTU_SID, val); + return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_SID, val); } /* Offset 0x05: VTU Operation Register */ static int mv88e6xxx_g1_vtu_op_wait(struct mv88e6xxx_chip *chip) { - return mv88e6xxx_g1_wait(chip, GLOBAL_VTU_OP, GLOBAL_VTU_OP_BUSY); + return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_VTU_OP, + MV88E6XXX_G1_VTU_OP_BUSY); } static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chip, u16 op) { int err; - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_OP, op); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_OP, + MV88E6XXX_G1_VTU_OP_BUSY | op); if (err) return err; @@ -90,16 +92,16 @@ static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip *chip, u16 val; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_VID, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID, &val); if (err) return err; entry->vid = val & 0xfff; - if (val & GLOBAL_VTU_VID_PAGE) + if (val & MV88E6390_G1_VTU_VID_PAGE) entry->vid |= 0x1000; - entry->valid = !!(val & GLOBAL_VTU_VID_VALID); + entry->valid = !!(val & MV88E6XXX_G1_VTU_VID_VALID); return 0; } @@ -110,12 +112,12 @@ static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip, u16 val = entry->vid & 0xfff; if (entry->vid & 0x1000) - val |= GLOBAL_VTU_VID_PAGE; + val |= MV88E6390_G1_VTU_VID_PAGE; if (entry->valid) - val |= GLOBAL_VTU_VID_VALID; + val |= MV88E6XXX_G1_VTU_VID_VALID; - return mv88e6xxx_g1_write(chip, GLOBAL_VTU_VID, val); + return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_VID, val); } /* Offset 0x07: VTU/STU Data Register 1 @@ -134,7 +136,7 @@ static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip, u16 *reg = ®s[i]; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg); if (err) return err; } @@ -171,7 +173,7 @@ static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u16 reg = regs[i]; int err; - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg); if (err) return err; } @@ -189,7 +191,7 @@ static int mv88e6390_g1_vtu_data_read(struct mv88e6xxx_chip *chip, u8 *data) u16 *reg = ®s[i]; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_DATA_0_3 + i, reg); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg); if (err) return err; } @@ -221,7 +223,7 @@ static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u8 *data) u16 reg = regs[i]; int err; - err = mv88e6xxx_g1_write(chip, GLOBAL_VTU_DATA_0_3 + i, reg); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_DATA1 + i, reg); if (err) return err; } @@ -240,7 +242,7 @@ static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip, if (err) return err; - err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_GET_NEXT); + err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT); if (err) return err; @@ -295,7 +297,7 @@ static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip, return err; } - err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_GET_NEXT); + err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_GET_NEXT); if (err) return err; @@ -320,7 +322,7 @@ int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, /* VTU DBNum[3:0] are located in VTU Operation 3:0 * VTU DBNum[7:4] are located in VTU Operation 11:8 */ - err = mv88e6xxx_g1_read(chip, GLOBAL_VTU_OP, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val); if (err) return err; @@ -394,7 +396,7 @@ int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip, int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry) { - u16 op = GLOBAL_VTU_OP_VTU_LOAD_PURGE; + u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE; int err; err = mv88e6xxx_g1_vtu_op_wait(chip); @@ -444,7 +446,8 @@ int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, return err; /* Load STU entry */ - err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE); + err = mv88e6xxx_g1_vtu_op(chip, + MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); if (err) return err; @@ -454,7 +457,7 @@ int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, } /* Load/Purge VTU entry */ - return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_LOAD_PURGE); + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); } int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, @@ -481,7 +484,8 @@ int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, return err; /* Load STU entry */ - err = mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_STU_LOAD_PURGE); + err = mv88e6xxx_g1_vtu_op(chip, + MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); if (err) return err; @@ -496,7 +500,7 @@ int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, } /* Load/Purge VTU entry */ - return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_VTU_LOAD_PURGE); + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); } int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) @@ -507,5 +511,5 @@ int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) if (err) return err; - return mv88e6xxx_g1_vtu_op(chip, GLOBAL_VTU_OP_FLUSH_ALL); + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL); } -- cgit v1.2.3 From d77f4321fa5cbe393930855763adaa87046394c6 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 15 Jun 2017 12:14:03 -0400 Subject: net: dsa: mv88e6xxx: prefix Global Control macros Prefix and document the Global Control and Control 2 registers macros and give a clear 16-bit registers representation. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 18 +++++++-------- drivers/net/dsa/mv88e6xxx/global1.c | 32 +++++++++++++------------- drivers/net/dsa/mv88e6xxx/global1.h | 46 ++++++++++++++++++++----------------- 3 files changed, 50 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index f2ce054913e4..c31ad01c7f96 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -292,14 +292,14 @@ static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d) u16 reg; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, ®); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, ®); if (err) goto out; reg &= ~mask; reg |= (~chip->g1_irq.masked & mask); - err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, reg); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, reg); if (err) goto out; @@ -338,9 +338,9 @@ static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip) int irq, virq; u16 mask; - mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask); + mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); mask |= GENMASK(chip->g1_irq.nirqs, 0); - mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask); + mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); free_irq(chip->irq, chip); @@ -370,13 +370,13 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) chip->g1_irq.chip = mv88e6xxx_g1_irq_chip; chip->g1_irq.masked = ~0; - err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &mask); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &mask); if (err) goto out_mapping; mask &= ~GENMASK(chip->g1_irq.nirqs, 0); - err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); if (err) goto out_disable; @@ -396,7 +396,7 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) out_disable: mask |= GENMASK(chip->g1_irq.nirqs, 0); - mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, mask); + mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, mask); out_mapping: for (irq = 0; irq < 16; irq++) { @@ -2014,8 +2014,8 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) } /* Disable remote management, and set the switch's DSA device number. */ - err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, - GLOBAL_CONTROL_2_MULTIPLE_CASCADE | + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL2, + MV88E6XXX_G1_CTL2_MULTIPLE_CASCADE | (ds->index & 0x1f)); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 0ddf1021442b..63e3ad1ba52a 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -162,14 +162,14 @@ int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip) /* Set the SWReset bit 15 along with the PPUEn bit 14, to also restart * the PPU, including re-doing PHY detection and initialization */ - err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); if (err) return err; - val |= GLOBAL_CONTROL_SW_RESET; - val |= GLOBAL_CONTROL_PPU_ENABLE; + val |= MV88E6XXX_G1_CTL1_SW_RESET; + val |= MV88E6XXX_G1_CTL1_PPU_ENABLE; - err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); if (err) return err; @@ -186,13 +186,13 @@ int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip) int err; /* Set the SWReset bit 15 */ - err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); if (err) return err; - val |= GLOBAL_CONTROL_SW_RESET; + val |= MV88E6XXX_G1_CTL1_SW_RESET; - err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); if (err) return err; @@ -208,13 +208,13 @@ int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip) u16 val; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); if (err) return err; - val |= GLOBAL_CONTROL_PPU_ENABLE; + val |= MV88E6XXX_G1_CTL1_PPU_ENABLE; - err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); if (err) return err; @@ -226,13 +226,13 @@ int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip) u16 val; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); if (err) return err; - val &= ~GLOBAL_CONTROL_PPU_ENABLE; + val &= ~MV88E6XXX_G1_CTL1_PPU_ENABLE; - err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); if (err) return err; @@ -342,13 +342,13 @@ int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip) u16 val; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL2, &val); if (err) return err; - val |= GLOBAL_CONTROL_2_HIST_RX_TX; + val |= MV88E6XXX_G1_CTL2_HIST_RX_TX; - err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL2, val); return err; } diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 56ba709628c7..af1a510f7a45 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -55,21 +55,22 @@ #define MV88E6352_G1_VTU_SID 0x03 #define MV88E6352_G1_VTU_SID_MASK 0x3f -#define GLOBAL_CONTROL 0x04 -#define GLOBAL_CONTROL_SW_RESET BIT(15) -#define GLOBAL_CONTROL_PPU_ENABLE BIT(14) -#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */ -#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */ -#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */ -#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */ -#define GLOBAL_CONTROL_DEVICE_EN BIT(7) -#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6) -#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5) -#define GLOBAL_CONTROL_VTU_DONE_EN BIT(4) -#define GLOBAL_CONTROL_ATU_PROBLEM_EN BIT(3) -#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) -#define GLOBAL_CONTROL_TCAM_EN BIT(1) -#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) +/* Offset 0x04: Switch Global Control Register */ +#define MV88E6XXX_G1_CTL1 0x04 +#define MV88E6XXX_G1_CTL1_SW_RESET 0x8000 +#define MV88E6XXX_G1_CTL1_PPU_ENABLE 0x4000 +#define MV88E6352_G1_CTL1_DISCARD_EXCESS 0x2000 +#define MV88E6185_G1_CTL1_SCHED_PRIO 0x0800 +#define MV88E6185_G1_CTL1_MAX_FRAME_1632 0x0400 +#define MV88E6185_G1_CTL1_RELOAD_EEPROM 0x0200 +#define MV88E6XXX_G1_CTL1_DEVICE_EN 0x0080 +#define MV88E6XXX_G1_CTL1_STATS_DONE_EN 0x0040 +#define MV88E6XXX_G1_CTL1_VTU_PROBLEM_EN 0x0020 +#define MV88E6XXX_G1_CTL1_VTU_DONE_EN 0x0010 +#define MV88E6XXX_G1_CTL1_ATU_PROBLEM_EN 0x0008 +#define MV88E6XXX_G1_CTL1_ATU_DONE_EN 0x0004 +#define MV88E6XXX_G1_CTL1_TCAM_EN 0x0002 +#define MV88E6XXX_G1_CTL1_EEPROM_DONE_EN 0x0001 /* Offset 0x05: VTU Operation Register */ #define MV88E6XXX_G1_VTU_OP 0x05 @@ -172,12 +173,15 @@ #define GLOBAL_MONITOR_CONTROL_INGRESS (0x20 << 8) #define GLOBAL_MONITOR_CONTROL_EGRESS (0x21 << 8) #define GLOBAL_MONITOR_CONTROL_CPU_DEST (0x30 << 8) -#define GLOBAL_CONTROL_2 0x1c -#define GLOBAL_CONTROL_2_NO_CASCADE 0xe000 -#define GLOBAL_CONTROL_2_MULTIPLE_CASCADE 0xf000 -#define GLOBAL_CONTROL_2_HIST_RX (0x1 << 6) -#define GLOBAL_CONTROL_2_HIST_TX (0x2 << 6) -#define GLOBAL_CONTROL_2_HIST_RX_TX (0x3 << 6) + +/* Offset 0x1C: Global Control 2 */ +#define MV88E6XXX_G1_CTL2 0x1c +#define MV88E6XXX_G1_CTL2_NO_CASCADE 0xe000 +#define MV88E6XXX_G1_CTL2_MULTIPLE_CASCADE 0xf000 +#define MV88E6XXX_G1_CTL2_HIST_RX 0x0040 +#define MV88E6XXX_G1_CTL2_HIST_TX 0x0080 +#define MV88E6XXX_G1_CTL2_HIST_RX_TX 0x00c0 + #define GLOBAL_STATS_OP 0x1d #define GLOBAL_STATS_OP_BUSY BIT(15) #define GLOBAL_STATS_OP_NOP (0 << 12) -- cgit v1.2.3 From 101515c8c51fced79407984d4765d5db23f04029 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 15 Jun 2017 12:14:04 -0400 Subject: net: dsa: mv88e6xxx: prefix Global Monitor Control macros Prefix and document the Global Monitor Control Register macros (which became the Global Monitor & MGMT Control Register with 88E6390) and give a clear 16-bit registers representation. Use __bf_shf to get the shift value at compile time instead of adding new defined macros for it. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global1.c | 65 ++++++++++++++++++++++--------------- drivers/net/dsa/mv88e6xxx/global1.h | 38 ++++++++++++---------- 2 files changed, 60 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 63e3ad1ba52a..ee77840d5271 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -12,6 +12,8 @@ * (at your option) any later version. */ +#include + #include "chip.h" #include "global1.h" @@ -247,17 +249,17 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) u16 reg; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, ®); + err = mv88e6xxx_g1_read(chip, MV88E6185_G1_MONITOR_CTL, ®); if (err) return err; - reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK | - GLOBAL_MONITOR_CONTROL_EGRESS_MASK); + reg &= ~(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK | + MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); - reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT | - port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT; + reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK) | + port << __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); - return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg); + return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); } /* Older generations also call this the ARP destination. It has been @@ -269,14 +271,14 @@ int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) u16 reg; int err; - err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, ®); + err = mv88e6xxx_g1_read(chip, MV88E6185_G1_MONITOR_CTL, ®); if (err) return err; - reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK; - reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT; + reg &= ~MV88E6185_G1_MONITOR_CTL_ARP_DEST_MASK; + reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_ARP_DEST_MASK); - return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg); + return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); } static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip, @@ -284,55 +286,66 @@ static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip, { u16 reg; - reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data; + reg = MV88E6390_G1_MONITOR_MGMT_CTL_UPDATE | pointer | data; - return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg); + return mv88e6xxx_g1_write(chip, MV88E6390_G1_MONITOR_MGMT_CTL, reg); } int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) { + u16 ptr; int err; - err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS, - port); + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST; + err = mv88e6390_g1_monitor_write(chip, ptr, port); if (err) return err; - return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS, - port); + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST; + err = mv88e6390_g1_monitor_write(chip, ptr, port); + if (err) + return err; + + return 0; } int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) { - return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST, - port); + u16 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST; + + return mv88e6390_g1_monitor_write(chip, ptr, port); } int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip) { + u16 ptr; int err; /* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */ - err = mv88e6390_g1_monitor_write( - chip, GLOBAL_MONITOR_CONTROL_0180C280000000XLO, 0xff); + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XLO; + err = mv88e6390_g1_monitor_write(chip, ptr, 0xff); if (err) return err; /* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */ - err = mv88e6390_g1_monitor_write( - chip, GLOBAL_MONITOR_CONTROL_0180C280000000XHI, 0xff); + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XHI; + err = mv88e6390_g1_monitor_write(chip, ptr, 0xff); if (err) return err; /* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */ - err = mv88e6390_g1_monitor_write( - chip, GLOBAL_MONITOR_CONTROL_0180C280000002XLO, 0xff); + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XLO; + err = mv88e6390_g1_monitor_write(chip, ptr, 0xff); if (err) return err; /* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */ - return mv88e6390_g1_monitor_write( - chip, GLOBAL_MONITOR_CONTROL_0180C280000002XHI, 0xff); + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XHI; + err = mv88e6390_g1_monitor_write(chip, ptr, 0xff); + if (err) + return err; + + return 0; } /* Offset 0x1c: Global Control 2 */ diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index af1a510f7a45..020b21c0c9c3 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -156,23 +156,27 @@ #define GLOBAL_IP_PRI_7 0x17 #define GLOBAL_IEEE_PRI 0x18 #define GLOBAL_CORE_TAG_TYPE 0x19 -#define GLOBAL_MONITOR_CONTROL 0x1a -#define GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT 12 -#define GLOBAL_MONITOR_CONTROL_INGRESS_MASK (0xf << 12) -#define GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT 8 -#define GLOBAL_MONITOR_CONTROL_EGRESS_MASK (0xf << 8) -#define GLOBAL_MONITOR_CONTROL_ARP_SHIFT 4 -#define GLOBAL_MONITOR_CONTROL_ARP_MASK (0xf << 4) -#define GLOBAL_MONITOR_CONTROL_MIRROR_SHIFT 0 -#define GLOBAL_MONITOR_CONTROL_ARP_DISABLED (0xf0) -#define GLOBAL_MONITOR_CONTROL_UPDATE BIT(15) -#define GLOBAL_MONITOR_CONTROL_0180C280000000XLO (0x00 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000000XHI (0x01 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000002XLO (0x02 << 8) -#define GLOBAL_MONITOR_CONTROL_0180C280000002XHI (0x03 << 8) -#define GLOBAL_MONITOR_CONTROL_INGRESS (0x20 << 8) -#define GLOBAL_MONITOR_CONTROL_EGRESS (0x21 << 8) -#define GLOBAL_MONITOR_CONTROL_CPU_DEST (0x30 << 8) + +/* Offset 0x1A: Monitor Control */ +#define MV88E6185_G1_MONITOR_CTL 0x1a +#define MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK 0xf000 +#define MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK 0x0f00 +#define MV88E6185_G1_MONITOR_CTL_ARP_DEST_MASK 0x00f0 +#define MV88E6352_G1_MONITOR_CTL_CPU_DEST_MASK 0x00f0 +#define MV88E6352_G1_MONITOR_CTL_MIRROR_DEST_MASK 0x000f + +/* Offset 0x1A: Monitor & MGMT Control Register */ +#define MV88E6390_G1_MONITOR_MGMT_CTL 0x1a +#define MV88E6390_G1_MONITOR_MGMT_CTL_UPDATE 0x8000 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_MASK 0x3f00 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XLO 0x0000 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XHI 0x0100 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XLO 0x0200 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XHI 0x0300 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST 0x2000 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST 0x2100 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST 0x3000 +#define MV88E6390_G1_MONITOR_MGMT_CTL_DATA_MASK 0x00ff /* Offset 0x1C: Global Control 2 */ #define MV88E6XXX_G1_CTL2 0x1c -- cgit v1.2.3 From 57d1ef389c96b5ae192767ae16843e839b1eff74 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 15 Jun 2017 12:14:05 -0400 Subject: net: dsa: mv88e6xxx: prefix Global Stats macros Prefix and document the Global Stats Operation and Counter registers and give them a clear 16-bit registers representation. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 14 ++++++++------ drivers/net/dsa/mv88e6xxx/global1.c | 24 ++++++++++++++---------- drivers/net/dsa/mv88e6xxx/global1.h | 33 +++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index c31ad01c7f96..46e8d1871847 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -725,7 +725,7 @@ static void mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port, { return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0 | STATS_TYPE_PORT, - 0, GLOBAL_STATS_OP_HIST_RX_TX); + 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX); } static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, @@ -733,8 +733,8 @@ static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port, { return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0 | STATS_TYPE_BANK1, - GLOBAL_STATS_OP_BANK_1_BIT_9, - GLOBAL_STATS_OP_HIST_RX_TX); + MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9, + MV88E6XXX_G1_STATS_OP_HIST_RX_TX); } static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, @@ -742,7 +742,8 @@ static void mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port, { return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0 | STATS_TYPE_BANK1, - GLOBAL_STATS_OP_BANK_1_BIT_10, 0); + MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10, + 0); } static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port, @@ -2057,8 +2058,9 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) return err; /* Clear the statistics counters for all ports */ - err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, - GLOBAL_STATS_OP_FLUSH_ALL); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, + MV88E6XXX_G1_STATS_OP_BUSY | + MV88E6XXX_G1_STATS_OP_FLUSH_ALL); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index ee77840d5271..d76d7c7ea819 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -370,7 +370,8 @@ int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip) int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip) { - return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY); + return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_STATS_OP, + MV88E6XXX_G1_STATS_OP_BUSY); } int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) @@ -378,9 +379,10 @@ int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) int err; /* Snapshot the hardware statistics counters for this port. */ - err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, - GLOBAL_STATS_OP_CAPTURE_PORT | - GLOBAL_STATS_OP_HIST_RX_TX | port); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, + MV88E6XXX_G1_STATS_OP_BUSY | + MV88E6XXX_G1_STATS_OP_CAPTURE_PORT | + MV88E6XXX_G1_STATS_OP_HIST_RX_TX | port); if (err) return err; @@ -402,8 +404,9 @@ int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) port = (port + 1) << 5; /* Snapshot the hardware statistics counters for this port. */ - err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, - GLOBAL_STATS_OP_CAPTURE_PORT | port); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, + MV88E6XXX_G1_STATS_OP_BUSY | + MV88E6XXX_G1_STATS_OP_CAPTURE_PORT | port); if (err) return err; @@ -419,8 +422,9 @@ void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val) *val = 0; - err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, - GLOBAL_STATS_OP_READ_CAPTURED | stat); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, + MV88E6XXX_G1_STATS_OP_BUSY | + MV88E6XXX_G1_STATS_OP_READ_CAPTURED | stat); if (err) return; @@ -428,13 +432,13 @@ void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val) if (err) return; - err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, ®); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_COUNTER_32, ®); if (err) return; value = reg << 16; - err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, ®); + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_COUNTER_01, ®); if (err) return; diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 020b21c0c9c3..16c21bd671c5 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -186,20 +186,25 @@ #define MV88E6XXX_G1_CTL2_HIST_TX 0x0080 #define MV88E6XXX_G1_CTL2_HIST_RX_TX 0x00c0 -#define GLOBAL_STATS_OP 0x1d -#define GLOBAL_STATS_OP_BUSY BIT(15) -#define GLOBAL_STATS_OP_NOP (0 << 12) -#define GLOBAL_STATS_OP_FLUSH_ALL ((1 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_FLUSH_PORT ((2 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_READ_CAPTURED ((4 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_CAPTURE_PORT ((5 << 12) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY) -#define GLOBAL_STATS_OP_BANK_1_BIT_9 BIT(9) -#define GLOBAL_STATS_OP_BANK_1_BIT_10 BIT(10) -#define GLOBAL_STATS_COUNTER_32 0x1e -#define GLOBAL_STATS_COUNTER_01 0x1f +/* Offset 0x1D: Stats Operation Register */ +#define MV88E6XXX_G1_STATS_OP 0x1d +#define MV88E6XXX_G1_STATS_OP_BUSY 0x8000 +#define MV88E6XXX_G1_STATS_OP_NOP 0x0000 +#define MV88E6XXX_G1_STATS_OP_FLUSH_ALL 0x1000 +#define MV88E6XXX_G1_STATS_OP_FLUSH_PORT 0x2000 +#define MV88E6XXX_G1_STATS_OP_READ_CAPTURED 0x4000 +#define MV88E6XXX_G1_STATS_OP_CAPTURE_PORT 0x5000 +#define MV88E6XXX_G1_STATS_OP_HIST_RX 0x0400 +#define MV88E6XXX_G1_STATS_OP_HIST_TX 0x0800 +#define MV88E6XXX_G1_STATS_OP_HIST_RX_TX 0x0c00 +#define MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9 0x0200 +#define MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10 0x0400 + +/* Offset 0x1E: Stats Counter Register Bytes 3 & 2 + * Offset 0x1F: Stats Counter Register Bytes 1 & 0 + */ +#define MV88E6XXX_G1_STATS_COUNTER_32 0x1e +#define MV88E6XXX_G1_STATS_COUNTER_01 0x1f int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val); int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val); -- cgit v1.2.3 From ccba8f3a0642257d7d9c19fc7c741016053222b3 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 15 Jun 2017 12:14:06 -0400 Subject: net: dsa: mv88e6xxx: prefix Global Prio and Tag macros Prefix and document the remaining Global IP and IEEE Priority and Core Tag Type registers and give them a clear 16-bit register representation. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 18 +++++++++--------- drivers/net/dsa/mv88e6xxx/global1.h | 33 +++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 46e8d1871847..19772e3dd67e 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2022,33 +2022,33 @@ static int mv88e6xxx_g1_setup(struct mv88e6xxx_chip *chip) return err; /* Configure the IP ToS mapping registers. */ - err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_0, 0x0000); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_0, 0x0000); if (err) return err; - err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_1, 0x0000); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_1, 0x0000); if (err) return err; - err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_2, 0x5555); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_2, 0x5555); if (err) return err; - err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_3, 0x5555); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_3, 0x5555); if (err) return err; - err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_4, 0xaaaa); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_4, 0xaaaa); if (err) return err; - err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_5, 0xaaaa); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_5, 0xaaaa); if (err) return err; - err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_6, 0xffff); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_6, 0xffff); if (err) return err; - err = mv88e6xxx_g1_write(chip, GLOBAL_IP_PRI_7, 0xffff); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IP_PRI_7, 0xffff); if (err) return err; /* Configure the IEEE 802.1p priority mapping register. */ - err = mv88e6xxx_g1_write(chip, GLOBAL_IEEE_PRI, 0xfa41); + err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IEEE_PRI, 0xfa41); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 16c21bd671c5..950b914f9251 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -146,16 +146,29 @@ #define MV88E6XXX_G1_ATU_MAC23 0x0e #define MV88E6XXX_G1_ATU_MAC45 0x0f -#define GLOBAL_IP_PRI_0 0x10 -#define GLOBAL_IP_PRI_1 0x11 -#define GLOBAL_IP_PRI_2 0x12 -#define GLOBAL_IP_PRI_3 0x13 -#define GLOBAL_IP_PRI_4 0x14 -#define GLOBAL_IP_PRI_5 0x15 -#define GLOBAL_IP_PRI_6 0x16 -#define GLOBAL_IP_PRI_7 0x17 -#define GLOBAL_IEEE_PRI 0x18 -#define GLOBAL_CORE_TAG_TYPE 0x19 +/* Offset 0x10: IP-PRI Mapping Register 0 + * Offset 0x11: IP-PRI Mapping Register 1 + * Offset 0x12: IP-PRI Mapping Register 2 + * Offset 0x13: IP-PRI Mapping Register 3 + * Offset 0x14: IP-PRI Mapping Register 4 + * Offset 0x15: IP-PRI Mapping Register 5 + * Offset 0x16: IP-PRI Mapping Register 6 + * Offset 0x17: IP-PRI Mapping Register 7 + */ +#define MV88E6XXX_G1_IP_PRI_0 0x10 +#define MV88E6XXX_G1_IP_PRI_1 0x11 +#define MV88E6XXX_G1_IP_PRI_2 0x12 +#define MV88E6XXX_G1_IP_PRI_3 0x13 +#define MV88E6XXX_G1_IP_PRI_4 0x14 +#define MV88E6XXX_G1_IP_PRI_5 0x15 +#define MV88E6XXX_G1_IP_PRI_6 0x16 +#define MV88E6XXX_G1_IP_PRI_7 0x17 + +/* Offset 0x18: IEEE-PRI Register */ +#define MV88E6XXX_G1_IEEE_PRI 0x18 + +/* Offset 0x19: Core Tag Type */ +#define MV88E6185_G1_CORE_TAG_TYPE 0x19 /* Offset 0x1A: Monitor Control */ #define MV88E6185_G1_MONITOR_CTL 0x1a -- cgit v1.2.3 From 9d7cdedd0fe514c294dbae8016cbee09d1d6231f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 14 Jun 2017 21:58:17 -0500 Subject: net: s2io: remove useless variable in fill_rx_buffers Remove useless variable rxd_index and code related. Addresses-Coverity-ID: 1397691 Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/s2io.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index 118723ea681a..fd2ec36c6fa1 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -2459,7 +2459,6 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, struct buffAdd *ba; struct RxD_t *first_rxdp = NULL; u64 Buffer0_ptr = 0, Buffer1_ptr = 0; - int rxd_index = 0; struct RxD1 *rxdp1; struct RxD3 *rxdp3; struct swStat *swstats = &ring->nic->mac_control.stats_info->sw_stat; @@ -2474,10 +2473,6 @@ static int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, rxdp = ring->rx_blocks[block_no].rxds[off].virt_addr; - rxd_index = off + 1; - if (block_no) - rxd_index += (block_no * ring->rxd_count); - if ((block_no == block_no1) && (off == ring->rx_curr_get_info.offset) && (rxdp->Host_Control)) { -- cgit v1.2.3 From 7e9191c54a36c864b901ea8ce56dc42f10c2f5ae Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 14 Jun 2017 15:43:37 -0700 Subject: sunvnet: restrict advertized checksum offloads to just IP As much as we'd like to play well with others, we really aren't handling the checksums on non-IP protocol packets very well. This is easily seen when trying to do TCP over ipv6 - the checksums are garbage. Here we restrict the checksum feature flag to just IP traffic so that we aren't given work we can't yet do. Orabug: 26175391, 26259755 Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/ldmvsw.c | 2 +- drivers/net/ethernet/sun/sunvnet.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sun/ldmvsw.c b/drivers/net/ethernet/sun/ldmvsw.c index 5b56c24b6ed2..8603e397097e 100644 --- a/drivers/net/ethernet/sun/ldmvsw.c +++ b/drivers/net/ethernet/sun/ldmvsw.c @@ -248,7 +248,7 @@ static struct net_device *vsw_alloc_netdev(u8 hwaddr[], dev->ethtool_ops = &vsw_ethtool_ops; dev->watchdog_timeo = VSW_TX_TIMEOUT; - dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG; dev->features = dev->hw_features; /* MTU range: 68 - 65535 */ diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 0b95105f7060..75b167e3fe98 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -312,7 +312,7 @@ static struct vnet *vnet_new(const u64 *local_mac, dev->watchdog_timeo = VNET_TX_TIMEOUT; dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE | - NETIF_F_HW_CSUM | NETIF_F_SG; + NETIF_F_IP_CSUM | NETIF_F_SG; dev->features = dev->hw_features; /* MTU range: 68 - 65535 */ -- cgit v1.2.3 From c3e53b9a3efe300a7864ab1ccfbae239d50d0002 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 14 Jun 2017 23:50:05 -0500 Subject: ibmvnic: Activate disabled RX buffer pools on reset RX buffer pools are disabled while awaiting a device reset if firmware indicates that the resource is closed. This patch fixes a bug where pools were not being subsequently enabled after the device reset, causing the device to become inoperable. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 78fdd4f0e341..99c552a79e9d 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -383,6 +383,7 @@ static int reset_rx_pools(struct ibmvnic_adapter *adapter) atomic_set(&rx_pool->available, 0); rx_pool->next_alloc = 0; rx_pool->next_free = 0; + rx_pool->active = 1; } return 0; -- cgit v1.2.3 From 4c2687a512b9a6737e86d72f23ad0a1097d56bd5 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 14 Jun 2017 23:50:06 -0500 Subject: ibmvnic: Ensure that TX queues are disabled in __ibmvnic_close Use netif_tx_disable to guarantee that TX queues are disabled when __ibmvnic_close is called by the device reset routine. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 99c552a79e9d..134ab295c1d6 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -886,7 +886,13 @@ static int __ibmvnic_close(struct net_device *netdev) int i; adapter->state = VNIC_CLOSING; - netif_tx_stop_all_queues(netdev); + + /* ensure that transmissions are stopped if called by do_reset */ + if (adapter->resetting) + netif_tx_disable(netdev); + else + netif_tx_stop_all_queues(netdev); + ibmvnic_napi_disable(adapter); if (adapter->tx_scrq) { -- cgit v1.2.3 From c8b2ad0a4a9015228874708f83a17b7bdb194f84 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 14 Jun 2017 23:50:07 -0500 Subject: ibmvnic: Sanitize entire SCRQ buffer on reset Fixup a typo so that the entire SCRQ buffer is cleaned. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 134ab295c1d6..03ddf6e1b5b3 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1752,7 +1752,7 @@ static int reset_one_sub_crq_queue(struct ibmvnic_adapter *adapter, scrq->irq = 0; } - memset(scrq->msgs, 0, 2 * PAGE_SIZE); + memset(scrq->msgs, 0, 4 * PAGE_SIZE); scrq->cur = 0; rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token, -- cgit v1.2.3 From 1cf9cc72bd7024af69419b5adee42c39ad4caf6f Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 14 Jun 2017 23:50:08 -0500 Subject: ibmvnic: Remove VNIC_CLOSING check from pending_scrq Fix a kernel panic resulting from data access of a NULL pointer during device close. The pending_scrq routine is meant to determine whether there is a valid sub-CRQ message awaiting processing. When the device is closing, however, there is a possibility that NULL messages can be processed because pending_scrq will always return 1 even if there no valid message in the queue. It's not clear what this closing state check was originally meant to accomplish, so just remove it. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 03ddf6e1b5b3..ebe443fe51db 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -2275,8 +2275,7 @@ static int pending_scrq(struct ibmvnic_adapter *adapter, { union sub_crq *entry = &scrq->msgs[scrq->cur]; - if (entry->generic.first & IBMVNIC_CRQ_CMD_RSP || - adapter->state == VNIC_CLOSING) + if (entry->generic.first & IBMVNIC_CRQ_CMD_RSP) return 1; else return 0; -- cgit v1.2.3 From 21ecba6c48f903781d844b62854bedd8137df470 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 14 Jun 2017 23:50:09 -0500 Subject: ibmvnic: Exit polling routine correctly during adapter reset This patch fixes a bug where, in the case of a device reset, the polling routine will never complete, causing napi_disable to sleep indefinitely when attempting to close the device. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index ebe443fe51db..9923b9fa0c74 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1505,9 +1505,6 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget) int scrq_num = (int)(napi - adapter->napi); int frames_processed = 0; - if (adapter->resetting) - return 0; - restart_poll: while (frames_processed < budget) { struct sk_buff *skb; @@ -1517,6 +1514,12 @@ restart_poll: u16 offset; u8 flags = 0; + if (unlikely(adapter->resetting)) { + enable_scrq_irq(adapter, adapter->rx_scrq[scrq_num]); + napi_complete_done(napi, frames_processed); + return frames_processed; + } + if (!pending_scrq(adapter, adapter->rx_scrq[scrq_num])) break; next = ibmvnic_next_scrq(adapter, adapter->rx_scrq[scrq_num]); -- cgit v1.2.3 From c27b32c2a4e6adc09323262d5b38b06979f063ab Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 15 Jun 2017 14:44:02 +0800 Subject: r8152: support new chip 8050 The settings of the new chip are the same with RTL8152, except that its product ID is 0x8050. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 8589303b4bf1..1f4dd8d3e328 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -659,6 +659,7 @@ enum rtl_version { RTL_VER_04, RTL_VER_05, RTL_VER_06, + RTL_VER_07, RTL_VER_MAX }; @@ -4183,6 +4184,7 @@ static int rtl8152_get_coalesce(struct net_device *netdev, switch (tp->version) { case RTL_VER_01: case RTL_VER_02: + case RTL_VER_07: return -EOPNOTSUPP; default: break; @@ -4202,6 +4204,7 @@ static int rtl8152_set_coalesce(struct net_device *netdev, switch (tp->version) { case RTL_VER_01: case RTL_VER_02: + case RTL_VER_07: return -EOPNOTSUPP; default: break; @@ -4301,6 +4304,7 @@ static int rtl8152_change_mtu(struct net_device *dev, int new_mtu) switch (tp->version) { case RTL_VER_01: case RTL_VER_02: + case RTL_VER_07: dev->mtu = new_mtu; return 0; default: @@ -4370,6 +4374,7 @@ static int rtl_ops_init(struct r8152 *tp) switch (tp->version) { case RTL_VER_01: case RTL_VER_02: + case RTL_VER_07: ops->init = r8152b_init; ops->enable = rtl8152_enable; ops->disable = rtl8152_disable; @@ -4448,6 +4453,9 @@ static u8 rtl_get_version(struct usb_interface *intf) case 0x5c30: version = RTL_VER_06; break; + case 0x4800: + version = RTL_VER_07; + break; default: version = RTL_VER_UNKNOWN; dev_info(&intf->dev, "Unknown version 0x%04x\n", ocp_data); @@ -4495,6 +4503,7 @@ static int rtl8152_probe(struct usb_interface *intf, switch (version) { case RTL_VER_01: case RTL_VER_02: + case RTL_VER_07: tp->mii.supports_gmii = 0; break; default: @@ -4629,6 +4638,7 @@ static void rtl8152_disconnect(struct usb_interface *intf) /* table of devices that work with this driver */ static struct usb_device_id rtl8152_table[] = { + {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8050)}, {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)}, {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)}, {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab)}, -- cgit v1.2.3 From 65b82d696b9e84fda6dd7df61801b57d3e7fb976 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 15 Jun 2017 14:44:03 +0800 Subject: r8152: support RTL8153B This patch supports two new chips for RTL8153B. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 673 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 658 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 1f4dd8d3e328..932060c3bdc2 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -29,7 +29,7 @@ #include /* Information for net-next */ -#define NETNEXT_VERSION "08" +#define NETNEXT_VERSION "09" /* Information for net */ #define NET_VERSION "9" @@ -51,11 +51,14 @@ #define PLA_FMC 0xc0b4 #define PLA_CFG_WOL 0xc0b6 #define PLA_TEREDO_CFG 0xc0bc +#define PLA_TEREDO_WAKE_BASE 0xc0c4 #define PLA_MAR 0xcd00 #define PLA_BACKUP 0xd000 #define PAL_BDC_CR 0xd1a0 #define PLA_TEREDO_TIMER 0xd2cc #define PLA_REALWOW_TIMER 0xd2e8 +#define PLA_EFUSE_DATA 0xdd00 +#define PLA_EFUSE_CMD 0xdd02 #define PLA_LEDSEL 0xdd90 #define PLA_LED_FEATURE 0xdd92 #define PLA_PHYAR 0xde00 @@ -105,7 +108,9 @@ #define USB_CSR_DUMMY2 0xb466 #define USB_DEV_STAT 0xb808 #define USB_CONNECT_TIMER 0xcbf8 +#define USB_MSC_TIMER 0xcbfc #define USB_BURST_SIZE 0xcfc0 +#define USB_LPM_CONFIG 0xcfd8 #define USB_USB_CTRL 0xd406 #define USB_PHY_CTRL 0xd408 #define USB_TX_AGG 0xd40a @@ -113,15 +118,20 @@ #define USB_USB_TIMER 0xd428 #define USB_RX_EARLY_TIMEOUT 0xd42c #define USB_RX_EARLY_SIZE 0xd42e -#define USB_PM_CTRL_STATUS 0xd432 +#define USB_PM_CTRL_STATUS 0xd432 /* RTL8153A */ +#define USB_RX_EXTRA_AGGR_TMR 0xd432 /* RTL8153B */ #define USB_TX_DMA 0xd434 +#define USB_UPT_RXDMA_OWN 0xd437 #define USB_TOLERANCE 0xd490 #define USB_LPM_CTRL 0xd41a #define USB_BMU_RESET 0xd4b0 +#define USB_U1U2_TIMER 0xd4da #define USB_UPS_CTRL 0xd800 -#define USB_MISC_0 0xd81a #define USB_POWER_CUT 0xd80a +#define USB_MISC_0 0xd81a #define USB_AFE_CTRL2 0xd824 +#define USB_UPS_CFG 0xd842 +#define USB_UPS_FLAGS 0xd848 #define USB_WDT11_CTRL 0xe43c #define USB_BP_BA 0xfc26 #define USB_BP_0 0xfc28 @@ -133,6 +143,15 @@ #define USB_BP_6 0xfc34 #define USB_BP_7 0xfc36 #define USB_BP_EN 0xfc38 +#define USB_BP_8 0xfc38 +#define USB_BP_9 0xfc3a +#define USB_BP_10 0xfc3c +#define USB_BP_11 0xfc3e +#define USB_BP_12 0xfc40 +#define USB_BP_13 0xfc42 +#define USB_BP_14 0xfc44 +#define USB_BP_15 0xfc46 +#define USB_BP2_EN 0xfc48 /* OCP Registers */ #define OCP_ALDPS_CONFIG 0x2010 @@ -143,6 +162,7 @@ #define OCP_EEE_AR 0xa41a #define OCP_EEE_DATA 0xa41c #define OCP_PHY_STATUS 0xa420 +#define OCP_NCTL_CFG 0xa42c #define OCP_POWER_CFG 0xa430 #define OCP_EEE_CFG 0xa432 #define OCP_SRAM_ADDR 0xa436 @@ -152,9 +172,14 @@ #define OCP_EEE_ADV 0xa5d0 #define OCP_EEE_LPABLE 0xa5d2 #define OCP_PHY_STATE 0xa708 /* nway state for 8153 */ +#define OCP_PHY_PATCH_STAT 0xb800 +#define OCP_PHY_PATCH_CMD 0xb820 +#define OCP_ADC_IOFFSET 0xbcfc #define OCP_ADC_CFG 0xbc06 +#define OCP_SYSCLK_CFG 0xc416 /* SRAM Register */ +#define SRAM_GREEN_CFG 0x8011 #define SRAM_LPF_CFG 0x8012 #define SRAM_10M_AMP1 0x8080 #define SRAM_10M_AMP2 0x8082 @@ -252,6 +277,10 @@ /* PAL_BDC_CR */ #define ALDPS_PROXY_MODE 0x0001 +/* PLA_EFUSE_CMD */ +#define EFUSE_READ_CMD BIT(15) +#define EFUSE_DATA_BIT16 BIT(7) + /* PLA_CONFIG34 */ #define LINK_ON_WAKE_EN 0x0010 #define LINK_OFF_WAKE_EN 0x0008 @@ -277,6 +306,7 @@ /* PLA_MAC_PWR_CTRL2 */ #define EEE_SPDWN_RATIO 0x8007 +#define MAC_CLK_SPDWN_EN BIT(15) /* PLA_MAC_PWR_CTRL3 */ #define PKT_AVAIL_SPDWN_EN 0x0100 @@ -328,6 +358,9 @@ #define STAT_SPEED_HIGH 0x0000 #define STAT_SPEED_FULL 0x0002 +/* USB_LPM_CONFIG */ +#define LPM_U1U2_EN BIT(0) + /* USB_TX_AGG */ #define TX_AGG_MAX_THRESHOLD 0x03 @@ -335,6 +368,7 @@ #define RX_THR_SUPPER 0x0c350180 #define RX_THR_HIGH 0x7a120180 #define RX_THR_SLOW 0xffff0180 +#define RX_THR_B 0x00010001 /* USB_TX_DMA */ #define TEST_MODE_DISABLE 0x00000001 @@ -344,6 +378,10 @@ #define BMU_RESET_EP_IN 0x01 #define BMU_RESET_EP_OUT 0x02 +/* USB_UPT_RXDMA_OWN */ +#define OWN_UPDATE BIT(0) +#define OWN_CLEAR BIT(1) + /* USB_UPS_CTRL */ #define POWER_CUT 0x0100 @@ -360,6 +398,8 @@ /* USB_POWER_CUT */ #define PWR_EN 0x0001 #define PHASE2_EN 0x0008 +#define UPS_EN BIT(4) +#define USP_PREWAKE BIT(5) /* USB_MISC_0 */ #define PCUT_STATUS 0x0001 @@ -386,6 +426,37 @@ #define SEN_VAL_NORMAL 0xa000 #define SEL_RXIDLE 0x0100 +/* USB_UPS_CFG */ +#define SAW_CNT_1MS_MASK 0x0fff + +/* USB_UPS_FLAGS */ +#define UPS_FLAGS_R_TUNE BIT(0) +#define UPS_FLAGS_EN_10M_CKDIV BIT(1) +#define UPS_FLAGS_250M_CKDIV BIT(2) +#define UPS_FLAGS_EN_ALDPS BIT(3) +#define UPS_FLAGS_CTAP_SHORT_DIS BIT(4) +#define UPS_FLAGS_SPEED_MASK (0xf << 16) +#define ups_flags_speed(x) ((x) << 16) +#define UPS_FLAGS_EN_EEE BIT(20) +#define UPS_FLAGS_EN_500M_EEE BIT(21) +#define UPS_FLAGS_EN_EEE_CKDIV BIT(22) +#define UPS_FLAGS_EEE_PLLOFF_GIGA BIT(24) +#define UPS_FLAGS_EEE_CMOD_LV_EN BIT(25) +#define UPS_FLAGS_EN_GREEN BIT(26) +#define UPS_FLAGS_EN_FLOW_CTR BIT(27) + +enum spd_duplex { + NWAY_10M_HALF = 1, + NWAY_10M_FULL, + NWAY_100M_HALF, + NWAY_100M_FULL, + NWAY_1000M_FULL, + FORCE_10M_HALF, + FORCE_10M_FULL, + FORCE_100M_HALF, + FORCE_100M_FULL, +}; + /* OCP_ALDPS_CONFIG */ #define ENPWRSAVE 0x8000 #define ENPDNPS 0x0200 @@ -398,6 +469,9 @@ #define PHY_STAT_LAN_ON 3 #define PHY_STAT_PWRDN 5 +/* OCP_NCTL_CFG */ +#define PGA_RETURN_EN BIT(1) + /* OCP_POWER_CFG */ #define EEE_CLKDIV_EN 0x8000 #define EN_ALDPS 0x0004 @@ -439,17 +513,34 @@ #define EEE10_EN 0x0010 /* OCP_DOWN_SPEED */ +#define EN_EEE_CMODE BIT(14) +#define EN_EEE_1000 BIT(13) +#define EN_EEE_100 BIT(12) +#define EN_10M_CLKDIV BIT(11) #define EN_10M_BGOFF 0x0080 /* OCP_PHY_STATE */ #define TXDIS_STATE 0x01 #define ABD_STATE 0x02 +/* OCP_PHY_PATCH_STAT */ +#define PATCH_READY BIT(6) + +/* OCP_PHY_PATCH_CMD */ +#define PATCH_REQUEST BIT(4) + /* OCP_ADC_CFG */ #define CKADSEL_L 0x0100 #define ADC_EN 0x0080 #define EN_EMI_L 0x0040 +/* OCP_SYSCLK_CFG */ +#define clk_div_expo(x) (min(x, 5) << 8) + +/* SRAM_GREEN_CFG */ +#define GREEN_ETH_EN BIT(15) +#define R_TUNE_EN BIT(11) + /* SRAM_LPF_CFG */ #define LPF_AUTO_TUNE 0x8000 @@ -514,6 +605,7 @@ enum rtl8152_flags { SELECTIVE_SUSPEND, PHY_RESET, SCHEDULE_NAPI, + GREEN_ETHERNET, }; /* Define these values to match your device */ @@ -660,6 +752,8 @@ enum rtl_version { RTL_VER_05, RTL_VER_06, RTL_VER_07, + RTL_VER_08, + RTL_VER_09, RTL_VER_MAX }; @@ -984,6 +1078,12 @@ static void sram_write(struct r8152 *tp, u16 addr, u16 data) ocp_reg_write(tp, OCP_SRAM_DATA, data); } +static u16 sram_read(struct r8152 *tp, u16 addr) +{ + ocp_reg_write(tp, OCP_SRAM_ADDR, addr); + return ocp_reg_read(tp, OCP_SRAM_DATA); +} + static int read_mii_word(struct net_device *netdev, int phy_id, int reg) { struct r8152 *tp = netdev_priv(netdev); @@ -2251,18 +2351,64 @@ static int rtl8152_enable(struct r8152 *tp) return rtl_enable(tp); } +static inline void r8153b_rx_agg_chg_indicate(struct r8152 *tp) +{ + ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN, + OWN_UPDATE | OWN_CLEAR); +} + static void r8153_set_rx_early_timeout(struct r8152 *tp) { u32 ocp_data = tp->coalesce / 8; - ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, ocp_data); + switch (tp->version) { + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, + ocp_data); + break; + + case RTL_VER_08: + case RTL_VER_09: + /* The RTL8153B uses USB_RX_EXTRA_AGGR_TMR for rx timeout + * primarily. For USB_RX_EARLY_TIMEOUT, we fix it to 128ns. + */ + ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, + 128 / 8); + ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EXTRA_AGGR_TMR, + ocp_data); + r8153b_rx_agg_chg_indicate(tp); + break; + + default: + break; + } } static void r8153_set_rx_early_size(struct r8152 *tp) { - u32 ocp_data = (agg_buf_sz - rx_reserved_size(tp->netdev->mtu)) / 4; + u32 ocp_data = agg_buf_sz - rx_reserved_size(tp->netdev->mtu); - ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ocp_data); + switch (tp->version) { + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, + ocp_data / 4); + break; + case RTL_VER_08: + case RTL_VER_09: + ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, + ocp_data / 8); + r8153b_rx_agg_chg_indicate(tp); + break; + default: + WARN_ON_ONCE(1); + break; + } } static int rtl8153_enable(struct r8152 *tp) @@ -2470,6 +2616,19 @@ static void r8153_u1u2en(struct r8152 *tp, bool enable) usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2); } +static void r8153b_u1u2en(struct r8152 *tp, bool enable) +{ + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG); + if (enable) + ocp_data |= LPM_U1U2_EN; + else + ocp_data &= ~LPM_U1U2_EN; + + ocp_write_word(tp, MCU_TYPE_USB, USB_LPM_CONFIG, ocp_data); +} + static void r8153_u2p3en(struct r8152 *tp, bool enable) { u32 ocp_data; @@ -2482,6 +2641,37 @@ static void r8153_u2p3en(struct r8152 *tp, bool enable) ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); } +static void r8153b_ups_flags_w1w0(struct r8152 *tp, u32 set, u32 clear) +{ + u32 ocp_data; + + ocp_data = ocp_read_dword(tp, MCU_TYPE_USB, USB_UPS_FLAGS); + ocp_data &= ~clear; + ocp_data |= set; + ocp_write_dword(tp, MCU_TYPE_USB, USB_UPS_FLAGS, ocp_data); +} + +static void r8153b_green_en(struct r8152 *tp, bool enable) +{ + u16 data; + + if (enable) { + sram_write(tp, 0x8045, 0); /* 10M abiq&ldvbias */ + sram_write(tp, 0x804d, 0x1222); /* 100M short abiq&ldvbias */ + sram_write(tp, 0x805d, 0x0022); /* 1000M short abiq&ldvbias */ + } else { + sram_write(tp, 0x8045, 0x2444); /* 10M abiq&ldvbias */ + sram_write(tp, 0x804d, 0x2444); /* 100M short abiq&ldvbias */ + sram_write(tp, 0x805d, 0x2444); /* 1000M short abiq&ldvbias */ + } + + data = sram_read(tp, SRAM_GREEN_CFG); + data |= GREEN_ETH_EN; + sram_write(tp, SRAM_GREEN_CFG, data); + + r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_GREEN, 0); +} + static u16 r8153_phy_status(struct r8152 *tp, u16 desired) { u16 data; @@ -2504,6 +2694,55 @@ static u16 r8153_phy_status(struct r8152 *tp, u16 desired) return data; } +static void r8153b_ups_en(struct r8152 *tp, bool enable) +{ + u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_POWER_CUT); + + if (enable) { + ocp_data |= UPS_EN | USP_PREWAKE | PHASE2_EN; + ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xcfff); + ocp_data |= BIT(0); + ocp_write_byte(tp, MCU_TYPE_USB, 0xcfff, ocp_data); + } else { + u16 data; + + ocp_data &= ~(UPS_EN | USP_PREWAKE); + ocp_write_byte(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, 0xcfff); + ocp_data &= ~BIT(0); + ocp_write_byte(tp, MCU_TYPE_USB, 0xcfff, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); + ocp_data &= ~PCUT_STATUS; + ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); + + data = r8153_phy_status(tp, 0); + + switch (data) { + case PHY_STAT_PWRDN: + case PHY_STAT_EXT_INIT: + r8153b_green_en(tp, + test_bit(GREEN_ETHERNET, &tp->flags)); + + data = r8152_mdio_read(tp, MII_BMCR); + data &= ~BMCR_PDOWN; + data |= BMCR_RESET; + r8152_mdio_write(tp, MII_BMCR, data); + + data = r8153_phy_status(tp, PHY_STAT_LAN_ON); + + default: + if (data != PHY_STAT_LAN_ON) + netif_warn(tp, link, tp->netdev, + "PHY not ready"); + break; + } + } +} + static void r8153_power_cut_en(struct r8152 *tp, bool enable) { u32 ocp_data; @@ -2520,6 +2759,38 @@ static void r8153_power_cut_en(struct r8152 *tp, bool enable) ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); } +static void r8153b_power_cut_en(struct r8152 *tp, bool enable) +{ + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT); + if (enable) + ocp_data |= PWR_EN | PHASE2_EN; + else + ocp_data &= ~PWR_EN; + ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); + ocp_data &= ~PCUT_STATUS; + ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); +} + +static void r8153b_queue_wake(struct r8152 *tp, bool enable) +{ + u32 ocp_data; + + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, 0xd38a); + if (enable) + ocp_data |= BIT(0); + else + ocp_data &= ~BIT(0); + ocp_write_byte(tp, MCU_TYPE_PLA, 0xd38a, ocp_data); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, 0xd38c); + ocp_data &= ~BIT(0); + ocp_write_byte(tp, MCU_TYPE_PLA, 0xd38c, ocp_data); +} + static bool rtl_can_wakeup(struct r8152 *tp) { struct usb_device *udev = tp->udev; @@ -2582,13 +2853,52 @@ static void rtl8153_runtime_enable(struct r8152 *tp, bool enable) } } +static void rtl8153b_runtime_enable(struct r8152 *tp, bool enable) +{ + if (enable) { + r8153b_queue_wake(tp, true); + r8153b_u1u2en(tp, false); + r8153_u2p3en(tp, false); + rtl_runtime_suspend_enable(tp, true); + r8153b_ups_en(tp, true); + } else { + r8153b_ups_en(tp, false); + r8153b_queue_wake(tp, false); + rtl_runtime_suspend_enable(tp, false); + r8153_u2p3en(tp, true); + r8153b_u1u2en(tp, true); + } +} + static void r8153_teredo_off(struct r8152 *tp) { u32 ocp_data; - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); - ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); + switch (tp->version) { + case RTL_VER_01: + case RTL_VER_02: + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + case RTL_VER_07: + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); + ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | + OOB_TEREDO_EN); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); + break; + + case RTL_VER_08: + case RTL_VER_09: + /* The bit 0 ~ 7 are relative with teredo settings. They are + * W1C (write 1 to clear), so set all 1 to disable it. + */ + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, 0xff); + break; + + default: + break; + } ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE); ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0); @@ -2834,6 +3144,33 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); } +static int r8153_patch_request(struct r8152 *tp, bool request) +{ + u16 data; + int i; + + data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); + if (request) + data |= PATCH_REQUEST; + else + data &= ~PATCH_REQUEST; + ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); + + for (i = 0; request && i < 5000; i++) { + usleep_range(1000, 2000); + if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) + break; + } + + if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { + netif_err(tp, drv, tp->netdev, "patch request fail\n"); + r8153_patch_request(tp, false); + return -ETIME; + } else { + return 0; + } +} + static void r8153_aldps_en(struct r8152 *tp, bool enable) { u16 data; @@ -2855,6 +3192,16 @@ static void r8153_aldps_en(struct r8152 *tp, bool enable) } } +static void r8153b_aldps_en(struct r8152 *tp, bool enable) +{ + r8153_aldps_en(tp, enable); + + if (enable) + r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_ALDPS, 0); + else + r8153b_ups_flags_w1w0(tp, 0, UPS_FLAGS_EN_ALDPS); +} + static void r8153_eee_en(struct r8152 *tp, bool enable) { u32 ocp_data; @@ -2875,6 +3222,22 @@ static void r8153_eee_en(struct r8152 *tp, bool enable) ocp_reg_write(tp, OCP_EEE_CFG, config); } +static void r8153b_eee_en(struct r8152 *tp, bool enable) +{ + r8153_eee_en(tp, enable); + + if (enable) + r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_EEE, 0); + else + r8153b_ups_flags_w1w0(tp, 0, UPS_FLAGS_EN_EEE); +} + +static void r8153b_enable_fc(struct r8152 *tp) +{ + r8152b_enable_fc(tp); + r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_FLOW_CTR, 0); +} + static void r8153_hw_phy_cfg(struct r8152 *tp) { u32 ocp_data; @@ -2936,6 +3299,100 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) set_bit(PHY_RESET, &tp->flags); } +static u32 r8152_efuse_read(struct r8152 *tp, u8 addr) +{ + u32 ocp_data; + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD, EFUSE_READ_CMD | addr); + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_CMD); + ocp_data = (ocp_data & EFUSE_DATA_BIT16) << 9; /* data of bit16 */ + ocp_data |= ocp_read_word(tp, MCU_TYPE_PLA, PLA_EFUSE_DATA); + + return ocp_data; +} + +static void r8153b_hw_phy_cfg(struct r8152 *tp) +{ + u32 ocp_data, ups_flags = 0; + u16 data; + + /* disable ALDPS before updating the PHY parameters */ + r8153b_aldps_en(tp, false); + + /* disable EEE before updating the PHY parameters */ + r8153b_eee_en(tp, false); + ocp_reg_write(tp, OCP_EEE_ADV, 0); + + r8153b_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags)); + + data = sram_read(tp, SRAM_GREEN_CFG); + data |= R_TUNE_EN; + sram_write(tp, SRAM_GREEN_CFG, data); + data = ocp_reg_read(tp, OCP_NCTL_CFG); + data |= PGA_RETURN_EN; + ocp_reg_write(tp, OCP_NCTL_CFG, data); + + /* ADC Bias Calibration: + * read efuse offset 0x7d to get a 17-bit data. Remove the dummy/fake + * bit (bit3) to rebuild the real 16-bit data. Write the data to the + * ADC ioffset. + */ + ocp_data = r8152_efuse_read(tp, 0x7d); + data = (u16)(((ocp_data & 0x1fff0) >> 1) | (ocp_data & 0x7)); + if (data != 0xffff) + ocp_reg_write(tp, OCP_ADC_IOFFSET, data); + + /* ups mode tx-link-pulse timing adjustment: + * rg_saw_cnt = OCP reg 0xC426 Bit[13:0] + * swr_cnt_1ms_ini = 16000000 / rg_saw_cnt + */ + ocp_data = ocp_reg_read(tp, 0xc426); + ocp_data &= 0x3fff; + if (ocp_data) { + u32 swr_cnt_1ms_ini; + + swr_cnt_1ms_ini = (16000000 / ocp_data) & SAW_CNT_1MS_MASK; + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CFG); + ocp_data = (ocp_data & ~SAW_CNT_1MS_MASK) | swr_cnt_1ms_ini; + ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CFG, ocp_data); + } + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); + ocp_data |= PFM_PWM_SWITCH; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); + + /* Advnace EEE */ + if (!r8153_patch_request(tp, true)) { + data = ocp_reg_read(tp, OCP_POWER_CFG); + data |= EEE_CLKDIV_EN; + ocp_reg_write(tp, OCP_POWER_CFG, data); + + data = ocp_reg_read(tp, OCP_DOWN_SPEED); + data |= EN_EEE_CMODE | EN_EEE_1000 | EN_10M_CLKDIV; + ocp_reg_write(tp, OCP_DOWN_SPEED, data); + + ocp_reg_write(tp, OCP_SYSCLK_CFG, 0); + ocp_reg_write(tp, OCP_SYSCLK_CFG, clk_div_expo(5)); + + ups_flags |= UPS_FLAGS_EN_10M_CKDIV | UPS_FLAGS_250M_CKDIV | + UPS_FLAGS_EN_EEE_CKDIV | UPS_FLAGS_EEE_CMOD_LV_EN | + UPS_FLAGS_EEE_PLLOFF_GIGA; + + r8153_patch_request(tp, false); + } + + r8153b_ups_flags_w1w0(tp, ups_flags, 0); + + r8153b_eee_en(tp, true); + ocp_reg_write(tp, OCP_EEE_ADV, MDIO_EEE_1000T | MDIO_EEE_100TX); + + r8153b_aldps_en(tp, true); + r8153b_enable_fc(tp); + r8153_u2p3en(tp, true); + + set_bit(PHY_RESET, &tp->flags); +} + static void r8153_first_init(struct r8152 *tp) { u32 ocp_data; @@ -3033,9 +3490,28 @@ static void r8153_enter_oob(struct r8152 *tp) ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + CRC_SIZE; ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); - ocp_data &= ~TEREDO_WAKE_MASK; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); + switch (tp->version) { + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); + ocp_data &= ~TEREDO_WAKE_MASK; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); + break; + + case RTL_VER_08: + case RTL_VER_09: + /* Clear teredo wake event. bit[15:8] is the teredo wakeup + * type. Set it to zero. bits[7:0] are the W1C bits about + * the events. Set them to all 1 to clear them. + */ + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_WAKE_BASE, 0x00ff); + break; + + default: + break; + } rtl_rx_vlan_en(tp, true); @@ -3062,9 +3538,18 @@ static void rtl8153_disable(struct r8152 *tp) r8153_aldps_en(tp, true); } +static void rtl8153b_disable(struct r8152 *tp) +{ + r8153b_aldps_en(tp, false); + rtl_disable(tp); + rtl_reset_bmu(tp); + r8153b_aldps_en(tp, true); +} + static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) { u16 bmcr, anar, gbcr; + enum spd_duplex speed_duplex; int ret = 0; anar = r8152_mdio_read(tp, MII_ADVERTISE); @@ -3081,32 +3566,43 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) if (speed == SPEED_10) { bmcr = 0; anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; + speed_duplex = FORCE_10M_HALF; } else if (speed == SPEED_100) { bmcr = BMCR_SPEED100; anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; + speed_duplex = FORCE_100M_HALF; } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { bmcr = BMCR_SPEED1000; gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; + speed_duplex = NWAY_1000M_FULL; } else { ret = -EINVAL; goto out; } - if (duplex == DUPLEX_FULL) + if (duplex == DUPLEX_FULL) { bmcr |= BMCR_FULLDPLX; + if (speed != SPEED_1000) + speed_duplex++; + } } else { if (speed == SPEED_10) { - if (duplex == DUPLEX_FULL) + if (duplex == DUPLEX_FULL) { anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; - else + speed_duplex = NWAY_10M_FULL; + } else { anar |= ADVERTISE_10HALF; + speed_duplex = NWAY_10M_HALF; + } } else if (speed == SPEED_100) { if (duplex == DUPLEX_FULL) { anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; + speed_duplex = NWAY_100M_FULL; } else { anar |= ADVERTISE_10HALF; anar |= ADVERTISE_100HALF; + speed_duplex = NWAY_100M_HALF; } } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { if (duplex == DUPLEX_FULL) { @@ -3118,6 +3614,7 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) anar |= ADVERTISE_100HALF; gbcr |= ADVERTISE_1000HALF; } + speed_duplex = NWAY_1000M_FULL; } else { ret = -EINVAL; goto out; @@ -3135,6 +3632,17 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) r8152_mdio_write(tp, MII_ADVERTISE, anar); r8152_mdio_write(tp, MII_BMCR, bmcr); + switch (tp->version) { + case RTL_VER_08: + case RTL_VER_09: + r8153b_ups_flags_w1w0(tp, ups_flags_speed(speed_duplex), + UPS_FLAGS_SPEED_MASK); + break; + + default: + break; + } + if (bmcr & BMCR_RESET) { int i; @@ -3212,6 +3720,38 @@ static void rtl8153_down(struct r8152 *tp) r8153_aldps_en(tp, true); } +static void rtl8153b_up(struct r8152 *tp) +{ + if (test_bit(RTL8152_UNPLUG, &tp->flags)) + return; + + r8153b_u1u2en(tp, false); + r8153_u2p3en(tp, false); + r8153b_aldps_en(tp, false); + + r8153_first_init(tp); + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_B); + + r8153b_aldps_en(tp, true); + r8153_u2p3en(tp, true); + r8153b_u1u2en(tp, true); +} + +static void rtl8153b_down(struct r8152 *tp) +{ + if (test_bit(RTL8152_UNPLUG, &tp->flags)) { + rtl_drop_queued_tx(tp); + return; + } + + r8153b_u1u2en(tp, false); + r8153_u2p3en(tp, false); + r8153b_power_cut_en(tp, false); + r8153b_aldps_en(tp, false); + r8153_enter_oob(tp); + r8153b_aldps_en(tp, true); +} + static bool rtl8152_in_nway(struct r8152 *tp) { u16 nway_state; @@ -3607,6 +4147,66 @@ static void r8153_init(struct r8152 *tp) } } +static void r8153b_init(struct r8152 *tp) +{ + u32 ocp_data; + u16 data; + int i; + + if (test_bit(RTL8152_UNPLUG, &tp->flags)) + return; + + r8153b_u1u2en(tp, false); + + for (i = 0; i < 500; i++) { + if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & + AUTOLOAD_DONE) + break; + msleep(20); + } + + data = r8153_phy_status(tp, 0); + + data = r8152_mdio_read(tp, MII_BMCR); + if (data & BMCR_PDOWN) { + data &= ~BMCR_PDOWN; + r8152_mdio_write(tp, MII_BMCR, data); + } + + data = r8153_phy_status(tp, PHY_STAT_LAN_ON); + + r8153_u2p3en(tp, false); + + /* MSC timer = 0xfff * 8ms = 32760 ms */ + ocp_write_word(tp, MCU_TYPE_USB, USB_MSC_TIMER, 0x0fff); + + /* U1/U2/L1 idle timer. 500 us */ + ocp_write_word(tp, MCU_TYPE_USB, USB_U1U2_TIMER, 500); + + r8153b_power_cut_en(tp, false); + r8153b_ups_en(tp, false); + r8153b_queue_wake(tp, false); + rtl_runtime_suspend_enable(tp, false); + r8153b_u1u2en(tp, true); + usb_enable_lpm(tp->udev); + + /* MAC clock speed down */ + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2); + ocp_data |= MAC_CLK_SPDWN_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, ocp_data); + + set_bit(GREEN_ETHERNET, &tp->flags); + + /* rx aggregation */ + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); + ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); + ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); + + rtl_tally_reset(tp); + + tp->coalesce = 15000; /* 15 us */ +} + static int rtl8152_pre_reset(struct usb_interface *intf) { struct r8152 *tp = usb_get_intfdata(intf); @@ -4109,6 +4709,20 @@ static int r8153_set_eee(struct r8152 *tp, struct ethtool_eee *eee) return 0; } +static int r8153b_set_eee(struct r8152 *tp, struct ethtool_eee *eee) +{ + u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); + + r8153b_eee_en(tp, eee->eee_enabled); + + if (!eee->eee_enabled) + val = 0; + + ocp_reg_write(tp, OCP_EEE_ADV, val); + + return 0; +} + static int rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) { @@ -4366,6 +4980,14 @@ static void rtl8153_unload(struct r8152 *tp) r8153_power_cut_en(tp, false); } +static void rtl8153b_unload(struct r8152 *tp) +{ + if (test_bit(RTL8152_UNPLUG, &tp->flags)) + return; + + r8153b_power_cut_en(tp, false); +} + static int rtl_ops_init(struct r8152 *tp) { struct rtl_ops *ops = &tp->rtl_ops; @@ -4405,6 +5027,21 @@ static int rtl_ops_init(struct r8152 *tp) ops->autosuspend_en = rtl8153_runtime_enable; break; + case RTL_VER_08: + case RTL_VER_09: + ops->init = r8153b_init; + ops->enable = rtl8153_enable; + ops->disable = rtl8153b_disable; + ops->up = rtl8153b_up; + ops->down = rtl8153b_down; + ops->unload = rtl8153b_unload; + ops->eee_get = r8153_get_eee; + ops->eee_set = r8153b_set_eee; + ops->in_nway = rtl8153_in_nway; + ops->hw_phy_cfg = r8153b_hw_phy_cfg; + ops->autosuspend_en = rtl8153b_runtime_enable; + break; + default: ret = -ENODEV; netif_err(tp, probe, tp->netdev, "Unknown Device\n"); @@ -4456,6 +5093,12 @@ static u8 rtl_get_version(struct usb_interface *intf) case 0x4800: version = RTL_VER_07; break; + case 0x6000: + version = RTL_VER_08; + break; + case 0x6010: + version = RTL_VER_09; + break; default: version = RTL_VER_UNKNOWN; dev_info(&intf->dev, "Unknown version 0x%04x\n", ocp_data); -- cgit v1.2.3 From d8fbd27469fc02049c674de296a3263bef089131 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 15 Jun 2017 14:44:04 +0800 Subject: r8152: add byte_enable for ocp_read_word function Add byte_enable for ocp_read_word() to replace reading 4 bytes data with reading the desired 2 bytes data. This is used to avoid the issue which is described in commit b4d99def0938 ("r8152: remove sram_read"). The original method always reads 4 bytes data, and it may have problem when reading the PHY registers. The new method is supported since RTL8153B, but it doesn't influence the previous chips. The bits of the byte_enable for the previous chips are the reserved bits, and the hw would ignore them. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 932060c3bdc2..3a29072dc622 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -962,11 +962,13 @@ static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index) { u32 data; __le32 tmp; + u16 byen = BYTE_EN_WORD; u8 shift = index & 2; index &= ~3; + byen <<= shift; - generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type | byen); data = __le32_to_cpu(tmp); data >>= (shift * 8); -- cgit v1.2.3 From 14160ea227a1a6d9099495eadc55a900d371ab3d Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Fri, 28 Oct 2016 09:52:56 -0500 Subject: net/mlx5: Update eqe_type_str() event names Add missing NIC_VPORT_CHANGE event. Signed-off-by: Eli Cohen Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eq.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 0ed8e90ba54f..23048247d827 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -157,6 +157,8 @@ static const char *eqe_type_str(u8 type) return "MLX5_EVENT_TYPE_PAGE_FAULT"; case MLX5_EVENT_TYPE_PPS_EVENT: return "MLX5_EVENT_TYPE_PPS_EVENT"; + case MLX5_EVENT_TYPE_NIC_VPORT_CHANGE: + return "MLX5_EVENT_TYPE_NIC_VPORT_CHANGE"; case MLX5_EVENT_TYPE_FPGA_ERROR: return "MLX5_EVENT_TYPE_FPGA_ERROR"; default: -- cgit v1.2.3 From bd10838af2d918994a27c702e9910fb71bb9c304 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 28 May 2017 15:24:17 +0300 Subject: net/mlx5: Fix some spelling mistakes Fixed few places where endianness was misspelled and one spot whwere output was: CHECK: 'endianess' may be misspelled - perhaps 'endianness'? CHECK: 'ouput' may be misspelled - perhaps 'output'? Signed-off-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/infiniband/hw/mlx5/main.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/main.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 852a6a75db98..2ab505d1e8e3 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -439,7 +439,7 @@ static void get_atomic_caps(struct mlx5_ib_dev *dev, u8 atomic_operations = MLX5_CAP_ATOMIC(dev->mdev, atomic_operations); u8 atomic_size_qp = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_qp); u8 atomic_req_8B_endianness_mode = - MLX5_CAP_ATOMIC(dev->mdev, atomic_req_8B_endianess_mode); + MLX5_CAP_ATOMIC(dev->mdev, atomic_req_8B_endianness_mode); /* Check if HW supports 8 bytes standard atomic operations and capable * of host endianness respond diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 10d282841f5b..46efaab9da46 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -874,7 +874,7 @@ static const char *deliv_status_to_str(u8 status) case MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR: return "command input length error"; case MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR: - return "command ouput length error"; + return "command output length error"; case MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR: return "reserved fields not cleared"; case MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index dc890944c4ea..3319968ed789 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -356,7 +356,7 @@ static void mlx5_disable_msix(struct mlx5_core_dev *dev) kfree(priv->msix_arr); } -struct mlx5_reg_host_endianess { +struct mlx5_reg_host_endianness { u8 he; u8 rsvd[15]; }; @@ -475,7 +475,7 @@ static int handle_hca_cap_atomic(struct mlx5_core_dev *dev) req_endianness = MLX5_CAP_ATOMIC(dev, - supported_atomic_req_8B_endianess_mode_1); + supported_atomic_req_8B_endianness_mode_1); if (req_endianness != MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS) return 0; @@ -487,7 +487,7 @@ static int handle_hca_cap_atomic(struct mlx5_core_dev *dev) set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability); /* Set requestor to host endianness */ - MLX5_SET(atomic_caps, set_hca_cap, atomic_req_8B_endianess_mode, + MLX5_SET(atomic_caps, set_hca_cap, atomic_req_8B_endianness_mode, MLX5_ATOMIC_REQ_MODE_HOST_ENDIANNESS); err = set_caps(dev, set_ctx, set_sz, MLX5_SET_HCA_CAP_OP_MOD_ATOMIC); @@ -562,8 +562,8 @@ query_ex: static int set_hca_ctrl(struct mlx5_core_dev *dev) { - struct mlx5_reg_host_endianess he_in; - struct mlx5_reg_host_endianess he_out; + struct mlx5_reg_host_endianness he_in; + struct mlx5_reg_host_endianness he_out; int err; if (!mlx5_core_is_pf(dev)) -- cgit v1.2.3 From 1b9f533a909e6983808e48b94faea58ea561f9f9 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 28 May 2017 15:32:35 +0300 Subject: net/mlx5: Avoid using multiple blank lines Fixed bunch of this checkpatch complaint: CHECK: Please don't use multiple blank lines Signed-off-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/alloc.c | 1 - drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 2 -- drivers/net/ethernet/mellanox/mlx5/core/debugfs.c | 3 --- drivers/net/ethernet/mellanox/mlx5/core/en_common.c | 1 - drivers/net/ethernet/mellanox/mlx5/core/en_fs.c | 1 - drivers/net/ethernet/mellanox/mlx5/core/eq.c | 2 -- drivers/net/ethernet/mellanox/mlx5/core/lag.c | 2 -- drivers/net/ethernet/mellanox/mlx5/core/main.c | 1 - drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c | 1 - drivers/net/ethernet/mellanox/mlx5/core/qp.c | 1 - 10 files changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index 66bd213f35ce..3c95f7f53802 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -274,7 +274,6 @@ void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db) } EXPORT_SYMBOL_GPL(mlx5_db_free); - void mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas) { u64 addr; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 46efaab9da46..e283095b69c3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -217,7 +217,6 @@ static void free_cmd(struct mlx5_cmd_work_ent *ent) kfree(ent); } - static int verify_signature(struct mlx5_cmd_work_ent *ent) { struct mlx5_cmd_mailbox *next = ent->out->next; @@ -1001,7 +1000,6 @@ static ssize_t dbg_write(struct file *filp, const char __user *buf, return err ? err : count; } - static const struct file_operations fops = { .owner = THIS_MODULE, .open = simple_open, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index de40b6cfee95..7ecadb501743 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -168,7 +168,6 @@ static ssize_t average_read(struct file *filp, char __user *buf, size_t count, return ret; } - static ssize_t average_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { @@ -466,7 +465,6 @@ static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count, return -EINVAL; } - if (is_str) ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field); else @@ -562,7 +560,6 @@ void mlx5_debug_qp_remove(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp) rem_res_tree(qp->dbg); } - int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq) { int err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c index 46e56ec4c26f..ece3fb147e3e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c @@ -145,7 +145,6 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb) int inlen; void *in; - inlen = MLX5_ST_SZ_BYTES(modify_tir_in); in = kvzalloc(inlen, GFP_KERNEL); if (!in) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c index 7acc4fba7ece..dfccb5305e9c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c @@ -170,7 +170,6 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv, spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - switch (rule_type) { case MLX5E_VLAN_RULE_TYPE_UNTAGGED: rule_p = &priv->fs.vlan.untagged_rule; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 23048247d827..43b279b01e07 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -677,7 +677,6 @@ int mlx5_eq_init(struct mlx5_core_dev *dev) return err; } - void mlx5_eq_cleanup(struct mlx5_core_dev *dev) { mlx5_eq_debugfs_cleanup(dev); @@ -689,7 +688,6 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev) u64 async_event_mask = MLX5_ASYNC_EVENT_MASK; int err; - if (MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_ETH && MLX5_CAP_GEN(dev, vport_group_manager) && mlx5_core_is_pf(dev)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c index b5d5519542e8..b6993c4e4823 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c @@ -467,7 +467,6 @@ static void mlx5_lag_dev_remove_pf(struct mlx5_lag *ldev, mutex_unlock(&lag_mutex); } - /* Must be called with intf_mutex held */ void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev) { @@ -586,4 +585,3 @@ bool mlx5_lag_intf_add(struct mlx5_interface *intf, struct mlx5_priv *priv) /* If bonded, we do not add an IB device for PF1. */ return false; } - diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 3319968ed789..39e7e523a0dd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -361,7 +361,6 @@ struct mlx5_reg_host_endianness { u8 rsvd[15]; }; - #define CAP_MASK(pos, size) ((u64)((1 << (size)) - 1) << (pos)) enum { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index efcded7ca27a..e36d3e3675f9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -403,7 +403,6 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, for (i = 0; i < num_claimed; i++) free_4k(dev, MLX5_GET64(manage_pages_out, out, pas[i])); - if (nclaimed) *nclaimed = num_claimed; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 573a6b27fed8..da0f18f93616 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -30,7 +30,6 @@ * SOFTWARE. */ - #include #include #include -- cgit v1.2.3 From 8963ca45e70c8aa9309f44b463d50bccf7932dac Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 28 May 2017 15:35:27 +0300 Subject: net/mlx5: Avoid blank lines before/after closing/opening braces Fixed checkpatch complaints on that: CHECK: Blank lines aren't necessary before a close brace '}' CHECK: Blank lines aren't necessary after an open brace '{' and one on missing blank line.. Signed-off-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1 - drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 1 - drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 1 - drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 5afec0f4a658..c803a533ec3c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -3067,7 +3067,6 @@ mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) */ stats->multicast = VPORT_COUNTER_GET(vstats, received_eth_multicast.packets); - } static void mlx5e_set_rx_mode(struct net_device *dev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 70c2b8d020bd..01798e1ab667 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1019,7 +1019,6 @@ err_destroy_netdev: mlx5e_destroy_netdev(netdev_priv(netdev)); kfree(rpriv); return err; - } static void diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 37927156f258..89bfda419efe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1217,7 +1217,6 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, "vport[%d] configure ingress rules failed, illegal mac with spoofchk\n", vport->vport); return -EPERM; - } esw_vport_cleanup_ingress_rules(esw, vport); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 6380c2db355a..e8690fe46bf2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -104,6 +104,7 @@ struct node_caps { size_t arr_sz; long *caps; }; + static struct init_tree_node { enum fs_node_type type; struct init_tree_node *children; @@ -1858,7 +1859,6 @@ static int create_anchor_flow_table(struct mlx5_flow_steering *steering) static int init_root_ns(struct mlx5_flow_steering *steering) { - steering->root_ns = create_root_ns(steering, FS_FT_NIC_RX); if (!steering->root_ns) goto cleanup; -- cgit v1.2.3 From e53eef635073e3c945d44009679d0a83f1b31083 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 28 May 2017 15:40:43 +0300 Subject: net/mlx5: Align to match opening parenthesis Fixed checkpatch complaints of the form: CHECK: Alignment should match open parenthesis Signed-off-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 5 +++-- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index e283095b69c3..c1d8b0bcde75 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1151,7 +1151,7 @@ err_alloc: } static void mlx5_free_cmd_msg(struct mlx5_core_dev *dev, - struct mlx5_cmd_msg *msg) + struct mlx5_cmd_msg *msg) { struct mlx5_cmd_mailbox *head = msg->next; struct mlx5_cmd_mailbox *next; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index c803a533ec3c..9dad80f32314 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -124,7 +124,8 @@ static void mlx5e_update_carrier(struct mlx5e_priv *priv) u8 port_state; port_state = mlx5_query_vport_state(mdev, - MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT, 0); + MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT, + 0); if (port_state == VPORT_STATE_UP) { netdev_info(priv->netdev, "Link up\n"); @@ -3850,7 +3851,7 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, /* set CQE compression */ params->rx_cqe_compress_def = false; if (MLX5_CAP_GEN(mdev, cqe_compression) && - MLX5_CAP_GEN(mdev, vport_group_manager)) + MLX5_CAP_GEN(mdev, vport_group_manager)) params->rx_cqe_compress_def = cqe_compress_heuristic(link_speed, pci_bw); MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_CQE_COMPRESS, params->rx_cqe_compress_def); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index ab3bb026ff9e..ef3e1918d8cc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -245,7 +245,7 @@ mlx5e_txwqe_build_dsegs(struct mlx5e_txqsq *sq, struct sk_buff *skb, int fsz = skb_frag_size(frag); dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz, - DMA_TO_DEVICE); + DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sq->pdev, dma_addr))) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 3795943ef2d1..877395f34e89 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -691,7 +691,7 @@ mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn) flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec, - &flow_act, &dest, 1); + &flow_act, &dest, 1); if (IS_ERR(flow_rule)) { esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule)); goto out; -- cgit v1.2.3 From 2fe30e23cddaf16fa3ffd188341cdf35d75f0f1b Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 28 May 2017 15:50:50 +0300 Subject: net/mlx5: Avoid space after casting Fix checkpatch complaints on that: CHECK: No space is necessary after a cast Signed-off-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eq.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 43b279b01e07..af51a5d2b912 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -191,7 +191,7 @@ static void eq_update_ci(struct mlx5_eq *eq, int arm) { __be32 __iomem *addr = eq->doorbell + (arm ? 0 : 2); u32 val = (eq->cons_index & 0xffffff) | (eq->eqn << 24); - __raw_writel((__force u32) cpu_to_be32(val), addr); + __raw_writel((__force u32)cpu_to_be32(val), addr); /* We still want ordering, just not swabbing, so add a barrier */ mb(); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 877395f34e89..b8030b5707a5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1093,7 +1093,7 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap) if (err) { esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err); esw->offloads.encap = !encap; - (void) esw_create_offloads_fast_fdb_table(esw); + (void)esw_create_offloads_fast_fdb_table(esw); } return err; } -- cgit v1.2.3 From 552db7bca568a8efbd0883f0597fbc42333cf094 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Tue, 9 May 2017 12:20:55 +0300 Subject: net/mlx5: Undo LAG upon request to create virtual functions LAG cannot work if virtual functions are present. Therefore, if LAG is configured, the attempt to create virtual functions will fail. This gives precedence to LAG over SRIOV which is not the desired behavior as users might want to use the bonding/teaming driver also want to work with SRIOV. In that case we don't want to force an order of actions, first create virtual functions and only than configure a bonding/teaming net device. To fix, if LAG is configured during a request to create virtual functions, remove it and continue. We ignore ENODEV when trying to forbid lag. This makes sense because "No such device" means that lag is forbidden anyway. Signed-off-by: Moni Shoua Reviewed-by: Aviv Heller Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lag.c | 69 +++++++++++++++++++--- .../net/ethernet/mellanox/mlx5/core/mlx5_core.h | 3 + drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 15 +++-- 3 files changed, 74 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c index b6993c4e4823..a3a836bdcfd2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c @@ -61,6 +61,11 @@ struct mlx5_lag { struct lag_tracker tracker; struct delayed_work bond_work; struct notifier_block nb; + + /* Admin state. Allow lag only if allowed is true + * even if network conditions for lag were met + */ + bool allowed; }; /* General purpose, use for short periods of time. @@ -214,6 +219,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) struct lag_tracker tracker; u8 v2p_port1, v2p_port2; int i, err; + bool do_bond; if (!dev0 || !dev1) return; @@ -222,13 +228,9 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) tracker = ldev->tracker; mutex_unlock(&lag_mutex); - if (tracker.is_bonded && !mlx5_lag_is_bonded(ldev)) { - if (mlx5_sriov_is_enabled(dev0) || - mlx5_sriov_is_enabled(dev1)) { - mlx5_core_warn(dev0, "LAG is not supported with SRIOV"); - return; - } + do_bond = tracker.is_bonded && ldev->allowed; + if (do_bond && !mlx5_lag_is_bonded(ldev)) { for (i = 0; i < MLX5_MAX_PORTS; i++) mlx5_remove_dev_by_protocol(ldev->pf[i].dev, MLX5_INTERFACE_PROTOCOL_IB); @@ -237,7 +239,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) mlx5_add_dev_by_protocol(dev0, MLX5_INTERFACE_PROTOCOL_IB); mlx5_nic_vport_enable_roce(dev1); - } else if (tracker.is_bonded && mlx5_lag_is_bonded(ldev)) { + } else if (do_bond && mlx5_lag_is_bonded(ldev)) { mlx5_infer_tx_affinity_mapping(&tracker, &v2p_port1, &v2p_port2); @@ -252,7 +254,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) "Failed to modify LAG (%d)\n", err); } - } else if (!tracker.is_bonded && mlx5_lag_is_bonded(ldev)) { + } else if (!do_bond && mlx5_lag_is_bonded(ldev)) { mlx5_remove_dev_by_protocol(dev0, MLX5_INTERFACE_PROTOCOL_IB); mlx5_nic_vport_disable_roce(dev1); @@ -411,6 +413,15 @@ static int mlx5_lag_netdev_event(struct notifier_block *this, return NOTIFY_DONE; } +static bool mlx5_lag_check_prereq(struct mlx5_lag *ldev) +{ + if ((ldev->pf[0].dev && mlx5_sriov_is_enabled(ldev->pf[0].dev)) || + (ldev->pf[1].dev && mlx5_sriov_is_enabled(ldev->pf[1].dev))) + return false; + else + return true; +} + static struct mlx5_lag *mlx5_lag_dev_alloc(void) { struct mlx5_lag *ldev; @@ -420,6 +431,7 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(void) return NULL; INIT_DELAYED_WORK(&ldev->bond_work, mlx5_do_bond_work); + ldev->allowed = mlx5_lag_check_prereq(ldev); return ldev; } @@ -444,7 +456,9 @@ static void mlx5_lag_dev_add_pf(struct mlx5_lag *ldev, ldev->tracker.netdev_state[fn].link_up = 0; ldev->tracker.netdev_state[fn].tx_enabled = 0; + ldev->allowed = mlx5_lag_check_prereq(ldev); dev->priv.lag = ldev; + mutex_unlock(&lag_mutex); } @@ -464,6 +478,7 @@ static void mlx5_lag_dev_remove_pf(struct mlx5_lag *ldev, memset(&ldev->pf[i], 0, sizeof(*ldev->pf)); dev->priv.lag = NULL; + ldev->allowed = mlx5_lag_check_prereq(ldev); mutex_unlock(&lag_mutex); } @@ -542,6 +557,44 @@ bool mlx5_lag_is_active(struct mlx5_core_dev *dev) } EXPORT_SYMBOL(mlx5_lag_is_active); +static int mlx5_lag_set_state(struct mlx5_core_dev *dev, bool allow) +{ + struct mlx5_lag *ldev; + int ret = 0; + bool lag_active; + + mlx5_dev_list_lock(); + + ldev = mlx5_lag_dev_get(dev); + if (!ldev) { + ret = -ENODEV; + goto unlock; + } + lag_active = mlx5_lag_is_bonded(ldev); + if (!mlx5_lag_check_prereq(ldev) && allow) { + ret = -EINVAL; + goto unlock; + } + if (ldev->allowed == allow) + goto unlock; + ldev->allowed = allow; + if ((lag_active && !allow) || allow) + mlx5_do_bond(ldev); +unlock: + mlx5_dev_list_unlock(); + return ret; +} + +int mlx5_lag_forbid(struct mlx5_core_dev *dev) +{ + return mlx5_lag_set_state(dev, false); +} + +int mlx5_lag_allow(struct mlx5_core_dev *dev) +{ + return mlx5_lag_set_state(dev, true); +} + struct net_device *mlx5_lag_get_roce_netdev(struct mlx5_core_dev *dev) { struct net_device *ndev = NULL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index cf69b42278df..1fd279c0338d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -167,4 +167,7 @@ static inline int mlx5_lag_is_lacp_owner(struct mlx5_core_dev *dev) MLX5_CAP_GEN(dev, lag_master); } +int mlx5_lag_allow(struct mlx5_core_dev *dev); +int mlx5_lag_forbid(struct mlx5_core_dev *dev); + #endif /* __MLX5_CORE_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index e08627785590..bcdf7779c48d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -175,15 +175,20 @@ int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs) if (!mlx5_core_is_pf(dev)) return -EPERM; - if (num_vfs && mlx5_lag_is_active(dev)) { - mlx5_core_warn(dev, "can't turn sriov on while LAG is active"); - return -EINVAL; + if (num_vfs) { + int ret; + + ret = mlx5_lag_forbid(dev); + if (ret && (ret != -ENODEV)) + return ret; } - if (num_vfs) + if (num_vfs) { err = mlx5_sriov_enable(pdev, num_vfs); - else + } else { mlx5_sriov_disable(pdev); + mlx5_lag_allow(dev); + } return err ? err : num_vfs; } -- cgit v1.2.3 From 22303f790d8b00f274ebdac30ae6b0cc481ed57c Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Sun, 21 May 2017 11:08:18 +0300 Subject: net/mlx5e: Use function to map aRFS into traffic type For a better code reuse and readability, use the existing function arfs_get_tt() to map arfs_type into mlx5e_traffic_types, instead of duplicating the switch-case logic. Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index f4017c06ddd2..12d3ced61114 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -178,6 +178,7 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv, struct mlx5_flow_destination dest; MLX5_DECLARE_FLOW_ACT(flow_act); struct mlx5_flow_spec *spec; + enum mlx5e_traffic_types tt; int err = 0; spec = kvzalloc(sizeof(*spec), GFP_KERNEL); @@ -187,24 +188,16 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv, } dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; - switch (type) { - case ARFS_IPV4_TCP: - dest.tir_num = tir[MLX5E_TT_IPV4_TCP].tirn; - break; - case ARFS_IPV4_UDP: - dest.tir_num = tir[MLX5E_TT_IPV4_UDP].tirn; - break; - case ARFS_IPV6_TCP: - dest.tir_num = tir[MLX5E_TT_IPV6_TCP].tirn; - break; - case ARFS_IPV6_UDP: - dest.tir_num = tir[MLX5E_TT_IPV6_UDP].tirn; - break; - default: + tt = arfs_get_tt(type); + if (tt == -EINVAL) { + netdev_err(priv->netdev, "%s: bad arfs_type: %d\n", + __func__, type); err = -EINVAL; goto out; } + dest.tir_num = tir[tt].tirn; + arfs_t->default_rule = mlx5_add_flow_rules(arfs_t->ft.t, spec, &flow_act, &dest, 1); -- cgit v1.2.3 From 3e432ab6d9eb3671e065cd7a009adefd6dbf4a04 Mon Sep 17 00:00:00 2001 From: Itay Aveksis Date: Wed, 7 Jun 2017 17:01:51 +0300 Subject: net/mlx5e: Fix typo in warning if CQ moderation is not supported Signed-off-by: Itay Aveksis Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 9dad80f32314..51f686d737cb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -3718,7 +3718,7 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable)) mlx5_core_warn(mdev, "Self loop back prevention is not supported\n"); if (!MLX5_CAP_GEN(mdev, cq_moderation)) - mlx5_core_warn(mdev, "CQ modiration is not supported\n"); + mlx5_core_warn(mdev, "CQ moderation is not supported\n"); return 0; } -- cgit v1.2.3 From ebc88870dab343ef3d16832e40d53bd21f1bf0e5 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Wed, 19 Apr 2017 18:10:37 +0300 Subject: net/mlx5e: Rename physical symbol errors counter Rename rx_symbol_errors_phy to rx_pcs_symbol_err_phy, in order to prevent confusion with rx_symbol_err_phy counter. rx_pcs_symbol_err_phy counter counts the number of symbol errors that were detected on the PCS (regardless of traffic) and weren't corrected by FEC correction algorithm or that FEC algorithm was not active on this interface. rx_symbol_err_phy refers to errors on packet level (physical error during a packet receive). Fixes: 5db0a4f64c04 ("net/mlx5e: Expose physical layer statistical...") Signed-off-by: Gal Pressman Signed-off-by: Saeed Mahameed Cc: kernel-team@fb.com --- drivers/net/ethernet/mellanox/mlx5/core/en_stats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h index f81c3aa60b46..fda247587ff6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h @@ -268,7 +268,7 @@ static const struct counter_desc pport_2819_stats_desc[] = { }; static const struct counter_desc pport_phy_statistical_stats_desc[] = { - { "rx_symbol_errors_phy", PPORT_PHY_STATISTICAL_OFF(phy_symbol_errors) }, + { "rx_pcs_symbol_err_phy", PPORT_PHY_STATISTICAL_OFF(phy_symbol_errors) }, { "rx_corrected_bits_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits) }, }; -- cgit v1.2.3 From 0883b4f456f691a54df7a9ae5607ade456fa7b97 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 5 Jun 2017 16:45:45 +0300 Subject: net/mlx5e: Reduce number of heap allocated buffers for update stats Allocating buffers on the heap every 200ms is something we should avoid, let's use buffers located on the stack instead. Signed-off-by: Gal Pressman Reviewed-by: Eran Ben Elisha Signed-off-by: Saeed Mahameed Cc: kernel-team@fb.com --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 51f686d737cb..50184021624e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -248,14 +248,10 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) { struct mlx5e_pport_stats *pstats = &priv->stats.pport; struct mlx5_core_dev *mdev = priv->mdev; + u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {0}; int sz = MLX5_ST_SZ_BYTES(ppcnt_reg); int prio; void *out; - u32 *in; - - in = kvzalloc(sz, GFP_KERNEL); - if (!in) - return; MLX5_SET(ppcnt_reg, in, local_port, 1); @@ -288,8 +284,6 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0); } - - kvfree(in); } static void mlx5e_update_q_counter(struct mlx5e_priv *priv) @@ -307,22 +301,16 @@ static void mlx5e_update_pcie_counters(struct mlx5e_priv *priv) { struct mlx5e_pcie_stats *pcie_stats = &priv->stats.pcie; struct mlx5_core_dev *mdev = priv->mdev; + u32 in[MLX5_ST_SZ_DW(mpcnt_reg)] = {0}; int sz = MLX5_ST_SZ_BYTES(mpcnt_reg); void *out; - u32 *in; if (!MLX5_CAP_MCAM_FEATURE(mdev, pcie_performance_group)) return; - in = kvzalloc(sz, GFP_KERNEL); - if (!in) - return; - out = pcie_stats->pcie_perf_counters; MLX5_SET(mpcnt_reg, in, grp, MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP); mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_MPCNT, 0, 0); - - kvfree(in); } void mlx5e_update_stats(struct mlx5e_priv *priv) -- cgit v1.2.3 From 432609a4cdfb1c3e3a58e6e37b3501e42bfc50ab Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Wed, 14 Jun 2017 11:52:33 +0300 Subject: net/mlx5e: Move and optimize query out of buffer function Move "query queue counter out of buffer" helper function out of qp.c to en_main.c, since mlx5e netdev driver is the only one to use it. Also allocate the output buffer on the stack instead of the heap, to reduce number of heap allocs on update_stats work. Signed-off-by: Gal Pressman Signed-off-by: Saeed Mahameed Cc: kernel-team@fb.com --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 9 +++++++-- drivers/net/ethernet/mellanox/mlx5/core/qp.c | 20 -------------------- 2 files changed, 7 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 50184021624e..8bb0241df069 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -289,12 +289,17 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) static void mlx5e_update_q_counter(struct mlx5e_priv *priv) { struct mlx5e_qcounter_stats *qcnt = &priv->stats.qcnt; + u32 out[MLX5_ST_SZ_DW(query_q_counter_out)]; + int err; if (!priv->q_counter) return; - mlx5_core_query_out_of_buffer(priv->mdev, priv->q_counter, - &qcnt->rx_out_of_buffer); + err = mlx5_core_query_q_counter(priv->mdev, priv->q_counter, 0, out, sizeof(out)); + if (err) + return; + + qcnt->rx_out_of_buffer = MLX5_GET(query_q_counter_out, out, out_of_buffer); } static void mlx5e_update_pcie_counters(struct mlx5e_priv *priv) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index da0f18f93616..340f281c9801 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -518,23 +518,3 @@ int mlx5_core_query_q_counter(struct mlx5_core_dev *dev, u16 counter_id, return mlx5_cmd_exec(dev, in, sizeof(in), out, out_size); } EXPORT_SYMBOL_GPL(mlx5_core_query_q_counter); - -int mlx5_core_query_out_of_buffer(struct mlx5_core_dev *dev, u16 counter_id, - u32 *out_of_buffer) -{ - int outlen = MLX5_ST_SZ_BYTES(query_q_counter_out); - void *out; - int err; - - out = kvzalloc(outlen, GFP_KERNEL); - if (!out) - return -ENOMEM; - - err = mlx5_core_query_q_counter(dev, counter_id, 0, out, outlen); - if (!err) - *out_of_buffer = MLX5_GET(query_q_counter_out, out, - out_of_buffer); - - kfree(out); - return err; -} -- cgit v1.2.3 From 3834a5e62617603673474ada9831aa4bda955e03 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Wed, 10 May 2017 15:10:33 +0300 Subject: net/mlx5e: Optimize update stats work Unlike ethtool stats, get_stats ndo provides information cached by update stats work that is running in the background without updating them explicitly. We cannot update all counters inside the ndo because some updates require firmware commands that cannot be performed under a spinlock. update_stats work does not need to update ALL counters, since only some of them are needed by ndo_get_stats. This patch will allow for a minimal run of update_stats using an extra parameter which will update necessary counters only and cut 13 firmware commands in each iteration of the work. Work duration previous to this patch: ~4200us. Work duration after this patch: ~700us (17% of the original time). Signed-off-by: Gal Pressman Reviewed-by: Eran Ben Elisha Signed-off-by: Saeed Mahameed Cc: kernel-team@fb.com --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 19 ++++++++++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index a0516b0a5273..8094e78292de 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -822,7 +822,7 @@ void mlx5e_rx_am(struct mlx5e_rq *rq); void mlx5e_rx_am_work(struct work_struct *work); struct mlx5e_cq_moder mlx5e_am_get_def_profile(u8 rx_cq_period_mode); -void mlx5e_update_stats(struct mlx5e_priv *priv); +void mlx5e_update_stats(struct mlx5e_priv *priv, bool full); int mlx5e_create_flow_steering(struct mlx5e_priv *priv); void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index b4514f247402..216752070391 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -311,7 +311,7 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev, mutex_lock(&priv->state_lock); if (test_bit(MLX5E_STATE_OPENED, &priv->state)) - mlx5e_update_stats(priv); + mlx5e_update_stats(priv, true); channels = &priv->channels; mutex_unlock(&priv->state_lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 8bb0241df069..2e9a4187a533 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -244,7 +244,7 @@ static void mlx5e_update_vport_counters(struct mlx5e_priv *priv) mlx5_cmd_exec(mdev, in, sizeof(in), out, outlen); } -static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) +static void mlx5e_update_pport_counters(struct mlx5e_priv *priv, bool full) { struct mlx5e_pport_stats *pstats = &priv->stats.pport; struct mlx5_core_dev *mdev = priv->mdev; @@ -259,6 +259,9 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) MLX5_SET(ppcnt_reg, in, grp, MLX5_IEEE_802_3_COUNTERS_GROUP); mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0); + if (!full) + return; + out = pstats->RFC_2863_counters; MLX5_SET(ppcnt_reg, in, grp, MLX5_RFC_2863_COUNTERS_GROUP); mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0); @@ -318,15 +321,21 @@ static void mlx5e_update_pcie_counters(struct mlx5e_priv *priv) mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_MPCNT, 0, 0); } -void mlx5e_update_stats(struct mlx5e_priv *priv) +void mlx5e_update_stats(struct mlx5e_priv *priv, bool full) { - mlx5e_update_pcie_counters(priv); - mlx5e_update_pport_counters(priv); + if (full) + mlx5e_update_pcie_counters(priv); + mlx5e_update_pport_counters(priv, full); mlx5e_update_vport_counters(priv); mlx5e_update_q_counter(priv); mlx5e_update_sw_counters(priv); } +static void mlx5e_update_ndo_stats(struct mlx5e_priv *priv) +{ + mlx5e_update_stats(priv, false); +} + void mlx5e_update_stats_work(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); @@ -4195,7 +4204,7 @@ static const struct mlx5e_profile mlx5e_nic_profile = { .cleanup_tx = mlx5e_cleanup_nic_tx, .enable = mlx5e_nic_enable, .disable = mlx5e_nic_disable, - .update_stats = mlx5e_update_stats, + .update_stats = mlx5e_update_ndo_stats, .max_nch = mlx5e_get_max_num_channels, .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe, .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq, -- cgit v1.2.3 From 4525abeaae54560254a1bb8970b3d4c225d32ef4 Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Thu, 9 Feb 2017 13:20:46 +0200 Subject: net/mlx5: Expose command polling interface Add a new interface for commands execution that allows the caller to wait for the command's completion in a busy-wait loop (polling mode). This is useful if we want to execute a command in a polling mode while the driver is working in events mode for the rest of the commands. This interface will be used in the downstream patches. Signed-off-by: Majd Dibbiny Signed-off-by: Maor Gottlieb Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 30 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index c1d8b0bcde75..4d5bd01f1ebb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -785,6 +785,8 @@ static void cmd_work_handler(struct work_struct *work) struct mlx5_cmd_layout *lay; struct semaphore *sem; unsigned long flags; + bool poll_cmd = ent->polling; + sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem; down(sem); @@ -845,7 +847,7 @@ static void cmd_work_handler(struct work_struct *work) iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell); mmiowb(); /* if not in polling don't use ent after this point */ - if (cmd->mode == CMD_MODE_POLLING) { + if (cmd->mode == CMD_MODE_POLLING || poll_cmd) { poll_timeout(ent); /* make sure we read the descriptor after ownership is SW */ rmb(); @@ -889,7 +891,7 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent) struct mlx5_cmd *cmd = &dev->cmd; int err; - if (cmd->mode == CMD_MODE_POLLING) { + if (cmd->mode == CMD_MODE_POLLING || ent->polling) { wait_for_completion(&ent->done); } else if (!wait_for_completion_timeout(&ent->done, timeout)) { ent->ret = -ETIMEDOUT; @@ -917,7 +919,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, struct mlx5_cmd_msg *out, void *uout, int uout_size, mlx5_cmd_cbk_t callback, void *context, int page_queue, u8 *status, - u8 token) + u8 token, bool force_polling) { struct mlx5_cmd *cmd = &dev->cmd; struct mlx5_cmd_work_ent *ent; @@ -935,6 +937,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, return PTR_ERR(ent); ent->token = token; + ent->polling = force_polling; if (!callback) init_completion(&ent->done); @@ -1535,7 +1538,8 @@ static int is_manage_pages(void *in) } static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, - int out_size, mlx5_cmd_cbk_t callback, void *context) + int out_size, mlx5_cmd_cbk_t callback, void *context, + bool force_polling) { struct mlx5_cmd_msg *inb; struct mlx5_cmd_msg *outb; @@ -1580,7 +1584,7 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, } err = mlx5_cmd_invoke(dev, inb, outb, out, out_size, callback, context, - pages_queue, &status, token); + pages_queue, &status, token, force_polling); if (err) goto out_out; @@ -1608,7 +1612,7 @@ int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, { int err; - err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL); + err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL, false); return err ? : mlx5_cmd_check(dev, in, out); } EXPORT_SYMBOL(mlx5_cmd_exec); @@ -1617,10 +1621,22 @@ int mlx5_cmd_exec_cb(struct mlx5_core_dev *dev, void *in, int in_size, void *out, int out_size, mlx5_cmd_cbk_t callback, void *context) { - return cmd_exec(dev, in, in_size, out, out_size, callback, context); + return cmd_exec(dev, in, in_size, out, out_size, callback, context, + false); } EXPORT_SYMBOL(mlx5_cmd_exec_cb); +int mlx5_cmd_exec_polling(struct mlx5_core_dev *dev, void *in, int in_size, + void *out, int out_size) +{ + int err; + + err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL, true); + + return err ? : mlx5_cmd_check(dev, in, out); +} +EXPORT_SYMBOL(mlx5_cmd_exec_polling); + static void destroy_msg_cache(struct mlx5_core_dev *dev) { struct cmd_msg_cache *ch; -- cgit v1.2.3 From 8812c24d28f4972c4f2b9998bf30b1f2a1b62adf Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Thu, 9 Feb 2017 14:20:12 +0200 Subject: net/mlx5: Add fast unload support in shutdown flow Adding a support to flush all HW resources with one FW command and skip all the heavy unload flows of the driver on kernel shutdown. There's no need to free all the SW context since a new fresh kernel will be loaded afterwards. Regarding the FW resources, they should be closed, otherwise we will have leakage in the FW. To accelerate this flow, we execute one command in the beginning that tells the FW that the driver isn't going to close any of the FW resources and asks the FW to clean up everything. Once the commands complete, it's safe to close the PCI resources and finish the routine. Signed-off-by: Majd Dibbiny Signed-off-by: Maor Gottlieb Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 28 +++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/health.c | 4 +-- drivers/net/ethernet/mellanox/mlx5/core/main.c | 32 ++++++++++++++++++++-- .../net/ethernet/mellanox/mlx5/core/mlx5_core.h | 3 +- 4 files changed, 62 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 1bc14d0fded8..e9489e8d08bb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -195,3 +195,31 @@ int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev) MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA); return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); } + +int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev) +{ + u32 out[MLX5_ST_SZ_DW(teardown_hca_out)] = {0}; + u32 in[MLX5_ST_SZ_DW(teardown_hca_in)] = {0}; + int force_state; + int ret; + + if (!MLX5_CAP_GEN(dev, force_teardown)) { + mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n"); + return -EOPNOTSUPP; + } + + MLX5_SET(teardown_hca_in, in, opcode, MLX5_CMD_OP_TEARDOWN_HCA); + MLX5_SET(teardown_hca_in, in, profile, MLX5_TEARDOWN_HCA_IN_PROFILE_FORCE_CLOSE); + + ret = mlx5_cmd_exec_polling(dev, in, sizeof(in), out, sizeof(out)); + if (ret) + return ret; + + force_state = MLX5_GET(teardown_hca_out, out, force_state); + if (force_state == MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL) { + mlx5_core_err(dev, "teardown with force mode failed\n"); + return -EIO; + } + + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index c6679b21884e..0648a659b21d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -111,14 +111,14 @@ static int in_fatal(struct mlx5_core_dev *dev) return 0; } -void mlx5_enter_error_state(struct mlx5_core_dev *dev) +void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force) { mutex_lock(&dev->intf_state_mutex); if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) goto unlock; mlx5_core_err(dev, "start\n"); - if (pci_channel_offline(dev->pdev) || in_fatal(dev)) { + if (pci_channel_offline(dev->pdev) || in_fatal(dev) || force) { dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR; trigger_cmd_completions(dev); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 39e7e523a0dd..715eeab59999 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1418,7 +1418,7 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev, dev_info(&pdev->dev, "%s was called\n", __func__); - mlx5_enter_error_state(dev); + mlx5_enter_error_state(dev, false); mlx5_unload_one(dev, priv, false); /* In case of kernel call drain the health wq */ if (state) { @@ -1505,15 +1505,43 @@ static const struct pci_error_handlers mlx5_err_handler = { .resume = mlx5_pci_resume }; +static int mlx5_try_fast_unload(struct mlx5_core_dev *dev) +{ + int ret; + + if (!MLX5_CAP_GEN(dev, force_teardown)) { + mlx5_core_dbg(dev, "force teardown is not supported in the firmware\n"); + return -EOPNOTSUPP; + } + + if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { + mlx5_core_dbg(dev, "Device in internal error state, giving up\n"); + return -EAGAIN; + } + + ret = mlx5_cmd_force_teardown_hca(dev); + if (ret) { + mlx5_core_dbg(dev, "Firmware couldn't do fast unload error: %d\n", ret); + return ret; + } + + mlx5_enter_error_state(dev, true); + + return 0; +} + static void shutdown(struct pci_dev *pdev) { struct mlx5_core_dev *dev = pci_get_drvdata(pdev); struct mlx5_priv *priv = &dev->priv; + int err; dev_info(&pdev->dev, "Shutdown was called\n"); /* Notify mlx5 clients that the kernel is being shut down */ set_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &dev->intf_state); - mlx5_unload_one(dev, priv, false); + err = mlx5_try_fast_unload(dev); + if (err) + mlx5_unload_one(dev, priv, false); mlx5_pci_disable_device(dev); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 1fd279c0338d..5ccdf43e58a6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -83,12 +83,13 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev); int mlx5_query_board_id(struct mlx5_core_dev *dev); int mlx5_cmd_init_hca(struct mlx5_core_dev *dev); int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev); +int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev); void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, unsigned long param); void mlx5_core_page_fault(struct mlx5_core_dev *dev, struct mlx5_pagefault *pfault); void mlx5_port_module_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe); -void mlx5_enter_error_state(struct mlx5_core_dev *dev); +void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force); void mlx5_disable_device(struct mlx5_core_dev *dev); void mlx5_recover_device(struct mlx5_core_dev *dev); int mlx5_sriov_init(struct mlx5_core_dev *dev); -- cgit v1.2.3 From 1492a3a7b27e78a51efda143f84ff9674acc8491 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 15 Jun 2017 14:56:21 -0500 Subject: atm: solos-pci: remove useless variable assignments Value assigned to variable _data32_ at lines 1254 and 1257 is overwritten at line 1260 before it can be used. This makes such variable assignments useless. Addresses-Coverity-ID: 1227049 Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/atm/solos-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 5ad037c07ec7..9115b292e680 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -1251,10 +1251,10 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) if (reset) { iowrite32(1, card->config_regs + FPGA_MODE); - data32 = ioread32(card->config_regs + FPGA_MODE); + ioread32(card->config_regs + FPGA_MODE); iowrite32(0, card->config_regs + FPGA_MODE); - data32 = ioread32(card->config_regs + FPGA_MODE); + ioread32(card->config_regs + FPGA_MODE); } data32 = ioread32(card->config_regs + FPGA_VER); -- cgit v1.2.3 From cf97050d547281edc5b813b501d5888c60f23bb2 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 15 Jun 2017 14:35:31 +0300 Subject: net/mlx4_en: Remove unused argument in TX datapath function Remove owner argument, as it is obsolete and unused. This also saves the overhead of calculating its value in data-path. Signed-off-by: Tariq Toukan Reviewed-by: Saeed Mahameed Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 10 ++++------ drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 6ffd1849a604..37386abea54c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -265,7 +265,7 @@ static void mlx4_en_stamp_wqe(struct mlx4_en_priv *priv, u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int index, u8 owner, u64 timestamp, + int index, u64 timestamp, int napi_mode) { struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; @@ -344,7 +344,7 @@ u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, u32 mlx4_en_recycle_tx_desc(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int index, u8 owner, u64 timestamp, + int index, u64 timestamp, int napi_mode) { struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; @@ -381,8 +381,7 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) while (ring->cons != ring->prod) { ring->last_nr_txbb = ring->free_tx_desc(priv, ring, ring->cons & ring->size_mask, - !!(ring->cons & ring->size), 0, - 0 /* Non-NAPI caller */); + 0, 0 /* Non-NAPI caller */); ring->cons += ring->last_nr_txbb; cnt++; } @@ -464,8 +463,7 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, /* free next descriptor */ last_nr_txbb = ring->free_tx_desc( priv, ring, ring_index, - !!((ring_cons + txbbs_skipped) & - ring->size), timestamp, napi_budget); + timestamp, napi_budget); mlx4_en_stamp_wqe(priv, ring, stamp_index, !!((ring_cons + txbbs_stamp) & diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 8c4f63946b14..08b2906a98af 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -276,7 +276,7 @@ struct mlx4_en_tx_ring { struct netdev_queue *tx_queue; u32 (*free_tx_desc)(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int index, u8 owner, + int index, u64 timestamp, int napi_mode); struct mlx4_en_rx_ring *recycle_ring; @@ -723,11 +723,11 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget); int mlx4_en_poll_tx_cq(struct napi_struct *napi, int budget); u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int index, u8 owner, u64 timestamp, + int index, u64 timestamp, int napi_mode); u32 mlx4_en_recycle_tx_desc(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int index, u8 owner, u64 timestamp, + int index, u64 timestamp, int napi_mode); void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, int is_tx, int rss, int qpn, int cqn, int user_prio, -- cgit v1.2.3 From 4931c6ef04b4eb6f726def76f845c10d1bb7057d Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 15 Jun 2017 14:35:32 +0300 Subject: net/mlx4_en: Optimized single ring steering Avoid touching RX QP RSS context when loading with only one RX ring, to allow optimized A0 RX steering. Enable by: - loading mlx4_core with module param: log_num_mgm_entry_size = -6. - then: ethtool -L rx 1 Performance tests: Tested on ConnectX3Pro, Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz XDP_DROP packet rate: ------------------------------------- | Before | After | Gain | IPv4 | 20.5 Mpps | 28.1 Mpps | 37% | IPv6 | 18.4 Mpps | 28.1 Mpps | 53% | ------------------------------------- Signed-off-by: Saeed Mahameed Signed-off-by: Tariq Toukan Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_main.c | 6 ++-- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 12 ++++--- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 48 ++++++++++++++++++++------ drivers/net/ethernet/mellanox/mlx4/main.c | 4 +-- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 2 +- 5 files changed, 50 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index d94f981eafc4..56cdf38d150e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -125,9 +125,9 @@ void mlx4_en_update_loopback_state(struct net_device *dev, priv->flags |= MLX4_EN_FLAG_ENABLE_HW_LOOPBACK; mutex_lock(&priv->mdev->state_lock); - if (priv->mdev->dev->caps.flags2 & - MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB && - priv->rss_map.indir_qp.qpn) { + if ((priv->mdev->dev->caps.flags2 & + MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB) && + priv->rss_map.indir_qp && priv->rss_map.indir_qp->qpn) { int i; int err = 0; int loopback = !!(features & NETIF_F_LOOPBACK); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index c1de75fc399a..51ce111b719e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -596,6 +596,8 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv) return err; } + en_info(priv, "Steering Mode %d\n", dev->caps.steering_mode); + if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { int base_qpn = mlx4_get_base_qpn(dev, priv->port); *qpn = base_qpn + index; @@ -1010,7 +1012,7 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv, memcpy(&mc_list[10], mclist->addr, ETH_ALEN); mc_list[5] = priv->port; err = mlx4_multicast_detach(mdev->dev, - &priv->rss_map.indir_qp, + priv->rss_map.indir_qp, mc_list, MLX4_PROT_ETH, mclist->reg_id); @@ -1032,7 +1034,7 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv, /* needed for B0 steering support */ mc_list[5] = priv->port; err = mlx4_multicast_attach(mdev->dev, - &priv->rss_map.indir_qp, + priv->rss_map.indir_qp, mc_list, priv->port, 0, MLX4_PROT_ETH, @@ -1742,7 +1744,7 @@ int mlx4_en_start_port(struct net_device *dev) /* Attach rx QP to bradcast address */ eth_broadcast_addr(&mc_list[10]); mc_list[5] = priv->port; /* needed for B0 steering support */ - if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list, + if (mlx4_multicast_attach(mdev->dev, priv->rss_map.indir_qp, mc_list, priv->port, 0, MLX4_PROT_ETH, &priv->broadcast_id)) mlx4_warn(mdev, "Failed Attaching Broadcast\n"); @@ -1866,12 +1868,12 @@ void mlx4_en_stop_port(struct net_device *dev, int detach) /* Detach All multicasts */ eth_broadcast_addr(&mc_list[10]); mc_list[5] = priv->port; /* needed for B0 steering support */ - mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list, + mlx4_multicast_detach(mdev->dev, priv->rss_map.indir_qp, mc_list, MLX4_PROT_ETH, priv->broadcast_id); list_for_each_entry(mclist, &priv->curr_list, list) { memcpy(&mc_list[10], mclist->addr, ETH_ALEN); mc_list[5] = priv->port; - mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, + mlx4_multicast_detach(mdev->dev, priv->rss_map.indir_qp, mc_list, MLX4_PROT_ETH, mclist->reg_id); if (mclist->tunnel_reg_id) mlx4_flow_detach(mdev->dev, mclist->tunnel_reg_id); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 77abd1813047..c4edae854f1b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -1099,11 +1099,14 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) int i, qpn; int err = 0; int good_qps = 0; + u8 flags; en_dbg(DRV, priv, "Configuring rss steering\n"); + + flags = priv->rx_ring_num == 1 ? MLX4_RESERVE_A0_QP : 0; err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num, priv->rx_ring_num, - &rss_map->base_qpn, 0); + &rss_map->base_qpn, flags); if (err) { en_err(priv, "Failed reserving %d qps\n", priv->rx_ring_num); return err; @@ -1120,13 +1123,28 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) ++good_qps; } + if (priv->rx_ring_num == 1) { + rss_map->indir_qp = &rss_map->qps[0]; + priv->base_qpn = rss_map->indir_qp->qpn; + en_info(priv, "Optimized Non-RSS steering\n"); + return 0; + } + + rss_map->indir_qp = kzalloc(sizeof(*rss_map->indir_qp), GFP_KERNEL); + if (!rss_map->indir_qp) { + err = -ENOMEM; + goto rss_err; + } + /* Configure RSS indirection qp */ - err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp, GFP_KERNEL); + err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, rss_map->indir_qp, + GFP_KERNEL); if (err) { en_err(priv, "Failed to allocate RSS indirection QP\n"); goto rss_err; } - rss_map->indir_qp.event = mlx4_en_sqp_event; + + rss_map->indir_qp->event = mlx4_en_sqp_event; mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, priv->rx_ring[0]->cqn, -1, &context); @@ -1164,8 +1182,9 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) err = -EINVAL; goto indir_err; } + err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context, - &rss_map->indir_qp, &rss_map->indir_state); + rss_map->indir_qp, &rss_map->indir_state); if (err) goto indir_err; @@ -1173,9 +1192,11 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) indir_err: mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state, - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); - mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); - mlx4_qp_free(mdev->dev, &rss_map->indir_qp); + MLX4_QP_STATE_RST, NULL, 0, 0, rss_map->indir_qp); + mlx4_qp_remove(mdev->dev, rss_map->indir_qp); + mlx4_qp_free(mdev->dev, rss_map->indir_qp); + kfree(rss_map->indir_qp); + rss_map->indir_qp = NULL; rss_err: for (i = 0; i < good_qps; i++) { mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], @@ -1193,10 +1214,15 @@ void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) struct mlx4_en_rss_map *rss_map = &priv->rss_map; int i; - mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state, - MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); - mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); - mlx4_qp_free(mdev->dev, &rss_map->indir_qp); + if (priv->rx_ring_num > 1) { + mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state, + MLX4_QP_STATE_RST, NULL, 0, 0, + rss_map->indir_qp); + mlx4_qp_remove(mdev->dev, rss_map->indir_qp); + mlx4_qp_free(mdev->dev, rss_map->indir_qp); + kfree(rss_map->indir_qp); + rss_map->indir_qp = NULL; + } for (i = 0; i < priv->rx_ring_num; i++) { mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index ccae3c6593c4..457e070bca46 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2356,8 +2356,8 @@ static int mlx4_init_hca(struct mlx4_dev *dev) MLX4_A0_STEERING_TABLE_SIZE; } - mlx4_dbg(dev, "DMFS high rate steer mode is: %s\n", - dmfs_high_rate_steering_mode_str( + mlx4_info(dev, "DMFS high rate steer mode is: %s\n", + dmfs_high_rate_steering_mode_str( dev->caps.dmfs_high_steer_mode)); } } else { diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 08b2906a98af..41f4f8f9f300 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -431,7 +431,7 @@ struct mlx4_en_rss_map { int base_qpn; struct mlx4_qp qps[MAX_RX_RINGS]; enum mlx4_qp_state state[MAX_RX_RINGS]; - struct mlx4_qp indir_qp; + struct mlx4_qp *indir_qp; enum mlx4_qp_state indir_state; }; -- cgit v1.2.3 From 9bcee89ac4dbafe77b7a2fc68c4a784358d6e4e4 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 15 Jun 2017 14:35:33 +0300 Subject: net/mlx4_en: Improve receive data-path Several small performance improvements in RX datapath, including: - Compiler branch predictor hints. - Replace a multiplication with a shift operation. - Minimize variables scope. - Write-prefetch for packet header. - Avoid trinary-operator ("?") when value can be preset in a matching branch. - Save a branch by updating RX ring doorbell within mlx4_en_refill_rx_buffers(), which now returns void. Performance tests: Tested on ConnectX3Pro, Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz Single queue no-RSS optimization ON (enable by ethtool -L rx 1). XDP_DROP packet rate: Same (28.1 Mpps), lower CPU utilization (from ~100% to ~92%). Drop packets in TC: ------------------------------------- | Before | After | Gain | IPv4 | 4.14 Mpps | 4.18 Mpps | 1% | ------------------------------------- XDP_TX packet rate: ------------------------------------- | Before | After | Gain | IPv4 | 10.1 Mpps | 10.3 Mpps | 2% | IPv6 | 10.1 Mpps | 10.3 Mpps | 2% | ------------------------------------- Signed-off-by: Tariq Toukan Reviewed-by: Saeed Mahameed Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 73 ++++++++++++++++-------------- 1 file changed, 39 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index c4edae854f1b..507c48ef2674 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -134,10 +134,11 @@ static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring, int index, gfp_t gfp) { - struct mlx4_en_rx_desc *rx_desc = ring->buf + (index * ring->stride); + struct mlx4_en_rx_desc *rx_desc = ring->buf + + (index << ring->log_stride); struct mlx4_en_rx_alloc *frags = ring->rx_info + (index << priv->log_rx_info); - if (ring->page_cache.index > 0) { + if (likely(ring->page_cache.index > 0)) { /* XDP uses a single page per frame */ if (!frags->page) { ring->page_cache.index--; @@ -178,6 +179,7 @@ static void mlx4_en_free_rx_desc(const struct mlx4_en_priv *priv, } } +/* Function not in fast-path */ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) { struct mlx4_en_rx_ring *ring; @@ -539,14 +541,14 @@ static void validate_loopback(struct mlx4_en_priv *priv, void *va) priv->loopback_ok = 1; } -static bool mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv, +static void mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring) { u32 missing = ring->actual_size - (ring->prod - ring->cons); /* Try to batch allocations, but not too much. */ if (missing < 8) - return false; + return; do { if (mlx4_en_prepare_rx_desc(priv, ring, ring->prod & ring->size_mask, @@ -554,9 +556,9 @@ static bool mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv, __GFP_MEMALLOC)) break; ring->prod++; - } while (--missing); + } while (likely(--missing)); - return true; + mlx4_en_update_rx_prod_db(ring); } /* When hardware doesn't strip the vlan, we need to calculate the checksum @@ -637,21 +639,14 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va, int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_dev *mdev = priv->mdev; - struct mlx4_cqe *cqe; - struct mlx4_en_rx_ring *ring = priv->rx_ring[cq->ring]; - struct mlx4_en_rx_alloc *frags; + int factor = priv->cqe_factor; + struct mlx4_en_rx_ring *ring; struct bpf_prog *xdp_prog; + int cq_ring = cq->ring; int doorbell_pending; - struct sk_buff *skb; - int index; - int nr; - unsigned int length; + struct mlx4_cqe *cqe; int polled = 0; - int ip_summed; - int factor = priv->cqe_factor; - u64 timestamp; - bool l2_tunnel; + int index; if (unlikely(!priv->port_up)) return 0; @@ -659,6 +654,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud if (unlikely(budget <= 0)) return polled; + ring = priv->rx_ring[cq_ring]; + /* Protect accesses to: ring->xdp_prog, priv->mac_hash list */ rcu_read_lock(); xdp_prog = rcu_dereference(ring->xdp_prog); @@ -673,10 +670,17 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud /* Process all completed CQEs */ while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, cq->mcq.cons_index & cq->size)) { + struct mlx4_en_rx_alloc *frags; + enum pkt_hash_types hash_type; + struct sk_buff *skb; + unsigned int length; + int ip_summed; void *va; + int nr; frags = ring->rx_info + (index << priv->log_rx_info); va = page_address(frags[0].page) + frags[0].page_offset; + prefetchw(va); /* * make sure we read the CQE after we read the ownership bit */ @@ -768,7 +772,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud break; case XDP_TX: if (likely(!mlx4_en_xmit_frame(ring, frags, dev, - length, cq->ring, + length, cq_ring, &doorbell_pending))) { frags[0].page = NULL; goto next; @@ -790,24 +794,27 @@ xdp_drop_no_cnt: ring->packets++; skb = napi_get_frags(&cq->napi); - if (!skb) + if (unlikely(!skb)) goto next; if (unlikely(ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL)) { - timestamp = mlx4_en_get_cqe_ts(cqe); - mlx4_en_fill_hwtstamps(mdev, skb_hwtstamps(skb), + u64 timestamp = mlx4_en_get_cqe_ts(cqe); + + mlx4_en_fill_hwtstamps(priv->mdev, skb_hwtstamps(skb), timestamp); } - skb_record_rx_queue(skb, cq->ring); + skb_record_rx_queue(skb, cq_ring); if (likely(dev->features & NETIF_F_RXCSUM)) { if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP | MLX4_CQE_STATUS_UDP)) { if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && cqe->checksum == cpu_to_be16(0xffff)) { - ip_summed = CHECKSUM_UNNECESSARY; - l2_tunnel = (dev->hw_enc_features & NETIF_F_RXCSUM) && + bool l2_tunnel = (dev->hw_enc_features & NETIF_F_RXCSUM) && (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_L2_TUNNEL)); + + ip_summed = CHECKSUM_UNNECESSARY; + hash_type = PKT_HASH_TYPE_L4; if (l2_tunnel) skb->csum_level = 1; ring->csum_ok++; @@ -822,6 +829,7 @@ xdp_drop_no_cnt: goto csum_none; } else { ip_summed = CHECKSUM_COMPLETE; + hash_type = PKT_HASH_TYPE_L3; ring->csum_complete++; } } else { @@ -831,16 +839,14 @@ xdp_drop_no_cnt: } else { csum_none: ip_summed = CHECKSUM_NONE; + hash_type = PKT_HASH_TYPE_L3; ring->csum_none++; } skb->ip_summed = ip_summed; if (dev->features & NETIF_F_RXHASH) skb_set_hash(skb, be32_to_cpu(cqe->immed_rss_invalid), - (ip_summed == CHECKSUM_UNNECESSARY) ? - PKT_HASH_TYPE_L4 : - PKT_HASH_TYPE_L3); - + hash_type); if ((cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK)) && @@ -867,13 +873,13 @@ next: ++cq->mcq.cons_index; index = (cq->mcq.cons_index) & ring->size_mask; cqe = mlx4_en_get_cqe(cq->buf, index, priv->cqe_size) + factor; - if (++polled == budget) + if (unlikely(++polled == budget)) break; } rcu_read_unlock(); - if (polled) { + if (likely(polled)) { if (doorbell_pending) mlx4_en_xmit_doorbell(priv->tx_ring[TX_XDP][cq->ring]); @@ -883,8 +889,7 @@ next: } AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled); - if (mlx4_en_refill_rx_buffers(priv, ring)) - mlx4_en_update_rx_prod_db(ring); + mlx4_en_refill_rx_buffers(priv, ring); return polled; } @@ -936,7 +941,7 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget) done--; } /* Done for now */ - if (napi_complete_done(napi, done)) + if (likely(napi_complete_done(napi, done))) mlx4_en_arm_cq(priv, cq); return done; } -- cgit v1.2.3 From cc26a4908682698cafdb5bb917f19840aff1a149 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 15 Jun 2017 14:35:34 +0300 Subject: net/mlx4_en: Improve transmit CQ polling Several small performance improvements in TX CQ polling, including: - Compiler branch predictor hints. - Minimize variables scope. - More proper check of cq type. - Use boolean instead of int for a binary indication. Performance tests: Tested on ConnectX3Pro, Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz Packet-rate tests for both regular stack and XDP use cases: No noticeable gain, no degradation. Signed-off-by: Tariq Toukan Reviewed-by: Saeed Mahameed Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 37386abea54c..2d5e0da1de2f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -402,8 +402,7 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_cq *mcq = &cq->mcq; struct mlx4_en_tx_ring *ring = priv->tx_ring[cq->type][cq->ring]; struct mlx4_cqe *cqe; - u16 index; - u16 new_index, ring_index, stamp_index; + u16 index, ring_index, stamp_index; u32 txbbs_skipped = 0; u32 txbbs_stamp = 0; u32 cons_index = mcq->cons_index; @@ -418,7 +417,7 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, u32 last_nr_txbb; u32 ring_cons; - if (!priv->port_up) + if (unlikely(!priv->port_up)) return true; netdev_txq_bql_complete_prefetchw(ring->tx_queue); @@ -433,6 +432,8 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, /* Process all completed CQEs */ while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, cons_index & size) && (done < budget)) { + u16 new_index; + /* * make sure we read the CQE after we read the * ownership bit @@ -479,7 +480,6 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, cqe = mlx4_en_get_cqe(buf, index, priv->cqe_size) + factor; } - /* * To prevent CQ overflow we first update CQ consumer and only then * the ring consumer. @@ -492,7 +492,7 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, ACCESS_ONCE(ring->last_nr_txbb) = last_nr_txbb; ACCESS_ONCE(ring->cons) = ring_cons + txbbs_skipped; - if (ring->free_tx_desc == mlx4_en_recycle_tx_desc) + if (cq->type == TX_XDP) return done < budget; netdev_tx_completed_queue(ring->tx_queue, packets, bytes); @@ -504,6 +504,7 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, netif_tx_wake_queue(ring->tx_queue); ring->wake_queue++; } + return done < budget; } @@ -524,7 +525,7 @@ int mlx4_en_poll_tx_cq(struct napi_struct *napi, int budget) struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi); struct net_device *dev = cq->dev; struct mlx4_en_priv *priv = netdev_priv(dev); - int clean_complete; + bool clean_complete; clean_complete = mlx4_en_process_tx_cq(dev, cq, budget); if (!clean_complete) -- cgit v1.2.3 From f28186d6b55d4c0b315d025753c22927e836a0e2 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 15 Jun 2017 14:35:35 +0300 Subject: net/mlx4_en: Improve stack xmit function Several small code and performance improvements in stack TX datapath, including: - Compiler branch predictor hints. - Minimize variables scope. - Move tx_info non-inline flow handling to a separate function. - Calculate data_offset in compile time rather than in runtime (for !lso_header_size branch). - Avoid trinary-operator ("?") when value can be preset in a matching branch. Performance tests: Tested on ConnectX3Pro, Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz Gain is too small to be measurable, no degradation sensed. Results are similar for IPv4 and IPv6. Signed-off-by: Tariq Toukan Reviewed-by: Saeed Mahameed Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 151 +++++++++++++++++------------ 1 file changed, 87 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 2d5e0da1de2f..58f4b322587b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -774,37 +774,101 @@ static void mlx4_en_tx_write_desc(struct mlx4_en_tx_ring *ring, } } +static bool mlx4_en_build_dma_wqe(struct mlx4_en_priv *priv, + struct skb_shared_info *shinfo, + struct mlx4_wqe_data_seg *data, + struct sk_buff *skb, + int lso_header_size, + __be32 mr_key, + struct mlx4_en_tx_info *tx_info) +{ + struct device *ddev = priv->ddev; + dma_addr_t dma = 0; + u32 byte_count = 0; + int i_frag; + + /* Map fragments if any */ + for (i_frag = shinfo->nr_frags - 1; i_frag >= 0; i_frag--) { + const struct skb_frag_struct *frag; + + frag = &shinfo->frags[i_frag]; + byte_count = skb_frag_size(frag); + dma = skb_frag_dma_map(ddev, frag, + 0, byte_count, + DMA_TO_DEVICE); + if (dma_mapping_error(ddev, dma)) + goto tx_drop_unmap; + + data->addr = cpu_to_be64(dma); + data->lkey = mr_key; + dma_wmb(); + data->byte_count = cpu_to_be32(byte_count); + --data; + } + + /* Map linear part if needed */ + if (tx_info->linear) { + byte_count = skb_headlen(skb) - lso_header_size; + + dma = dma_map_single(ddev, skb->data + + lso_header_size, byte_count, + PCI_DMA_TODEVICE); + if (dma_mapping_error(ddev, dma)) + goto tx_drop_unmap; + + data->addr = cpu_to_be64(dma); + data->lkey = mr_key; + dma_wmb(); + data->byte_count = cpu_to_be32(byte_count); + } + /* tx completion can avoid cache line miss for common cases */ + tx_info->map0_dma = dma; + tx_info->map0_byte_count = byte_count; + + return true; + +tx_drop_unmap: + en_err(priv, "DMA mapping error\n"); + + while (++i_frag < shinfo->nr_frags) { + ++data; + dma_unmap_page(ddev, (dma_addr_t)be64_to_cpu(data->addr), + be32_to_cpu(data->byte_count), + PCI_DMA_TODEVICE); + } + + return false; +} + netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) { struct skb_shared_info *shinfo = skb_shinfo(skb); struct mlx4_en_priv *priv = netdev_priv(dev); union mlx4_wqe_qpn_vlan qpn_vlan = {}; - struct device *ddev = priv->ddev; struct mlx4_en_tx_ring *ring; struct mlx4_en_tx_desc *tx_desc; struct mlx4_wqe_data_seg *data; struct mlx4_en_tx_info *tx_info; - int tx_ind = 0; + int tx_ind; int nr_txbb; int desc_size; int real_size; u32 index, bf_index; __be32 op_own; - u16 vlan_proto = 0; - int i_frag; int lso_header_size; void *fragptr = NULL; bool bounce = false; bool send_doorbell; bool stop_queue; bool inline_ok; + u8 data_offset; u32 ring_cons; bool bf_ok; tx_ind = skb_get_queue_mapping(skb); ring = priv->tx_ring[TX][tx_ind]; - if (!priv->port_up) + if (unlikely(!priv->port_up)) goto tx_drop; /* fetch ring->cons far ahead before needing it to avoid stall */ @@ -826,6 +890,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) bf_ok = ring->bf_enabled; if (skb_vlan_tag_present(skb)) { + u16 vlan_proto; + qpn_vlan.vlan_tag = cpu_to_be16(skb_vlan_tag_get(skb)); vlan_proto = be16_to_cpu(skb->vlan_proto); if (vlan_proto == ETH_P_8021AD) @@ -862,64 +928,31 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) tx_info->skb = skb; tx_info->nr_txbb = nr_txbb; - data = &tx_desc->data; - if (lso_header_size) - data = ((void *)&tx_desc->lso + ALIGN(lso_header_size + 4, - DS_SIZE)); + if (!lso_header_size) { + data = &tx_desc->data; + data_offset = offsetof(struct mlx4_en_tx_desc, data); + } else { + int lso_align = ALIGN(lso_header_size + 4, DS_SIZE); + + data = (void *)&tx_desc->lso + lso_align; + data_offset = offsetof(struct mlx4_en_tx_desc, lso) + lso_align; + } /* valid only for none inline segments */ - tx_info->data_offset = (void *)data - (void *)tx_desc; + tx_info->data_offset = data_offset; tx_info->inl = inline_ok; - tx_info->linear = (lso_header_size < skb_headlen(skb) && - !inline_ok) ? 1 : 0; + tx_info->linear = lso_header_size < skb_headlen(skb) && !inline_ok; tx_info->nr_maps = shinfo->nr_frags + tx_info->linear; data += tx_info->nr_maps - 1; - if (!tx_info->inl) { - dma_addr_t dma = 0; - u32 byte_count = 0; - - /* Map fragments if any */ - for (i_frag = shinfo->nr_frags - 1; i_frag >= 0; i_frag--) { - const struct skb_frag_struct *frag; - - frag = &shinfo->frags[i_frag]; - byte_count = skb_frag_size(frag); - dma = skb_frag_dma_map(ddev, frag, - 0, byte_count, - DMA_TO_DEVICE); - if (dma_mapping_error(ddev, dma)) - goto tx_drop_unmap; - - data->addr = cpu_to_be64(dma); - data->lkey = ring->mr_key; - dma_wmb(); - data->byte_count = cpu_to_be32(byte_count); - --data; - } - - /* Map linear part if needed */ - if (tx_info->linear) { - byte_count = skb_headlen(skb) - lso_header_size; - - dma = dma_map_single(ddev, skb->data + - lso_header_size, byte_count, - PCI_DMA_TODEVICE); - if (dma_mapping_error(ddev, dma)) - goto tx_drop_unmap; - - data->addr = cpu_to_be64(dma); - data->lkey = ring->mr_key; - dma_wmb(); - data->byte_count = cpu_to_be32(byte_count); - } - /* tx completion can avoid cache line miss for common cases */ - tx_info->map0_dma = dma; - tx_info->map0_byte_count = byte_count; - } + if (!tx_info->inl) + if (!mlx4_en_build_dma_wqe(priv, shinfo, data, skb, + lso_header_size, ring->mr_key, + tx_info)) + goto tx_drop_count; /* * For timestamping add flag to skb_shinfo and @@ -1055,16 +1088,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) } return NETDEV_TX_OK; -tx_drop_unmap: - en_err(priv, "DMA mapping error\n"); - - while (++i_frag < shinfo->nr_frags) { - ++data; - dma_unmap_page(ddev, (dma_addr_t) be64_to_cpu(data->addr), - be32_to_cpu(data->byte_count), - PCI_DMA_TODEVICE); - } - tx_drop_count: ring->tx_dropped++; tx_drop: -- cgit v1.2.3 From 36ea7964982f54370e051386b74df914c53e2219 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 15 Jun 2017 14:35:36 +0300 Subject: net/mlx4_en: Improve XDP xmit function Several performance improvements in XDP TX datapath, including: - Ring a single doorbell for XDP TX ring per NAPI budget, instead of doing it per a lower threshold (was 8). This includes removing the flow of immediate doorbell ringing in case of a full TX ring. - Compiler branch predictor hints. - Calculate values in compile time rather than in runtime. Performance tests: Tested on ConnectX3Pro, Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz Single queue no-RSS optimization ON. XDP_TX packet rate: ------------------------------------- | Before | After | Gain | IPv4 | 10.3 Mpps | 12.0 Mpps | 17% | IPv6 | 10.3 Mpps | 12.0 Mpps | 17% | ------------------------------------- Signed-off-by: Tariq Toukan Reviewed-by: Saeed Mahameed Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 59 +++++++++------------------- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 3 +- 3 files changed, 21 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 507c48ef2674..747e4d7d7693 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -643,7 +643,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud struct mlx4_en_rx_ring *ring; struct bpf_prog *xdp_prog; int cq_ring = cq->ring; - int doorbell_pending; + bool doorbell_pending; struct mlx4_cqe *cqe; int polled = 0; int index; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 58f4b322587b..01bb43879221 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -1095,51 +1095,40 @@ tx_drop: return NETDEV_TX_OK; } +#define MLX4_EN_XDP_TX_NRTXBB 1 +#define MLX4_EN_XDP_TX_REAL_SZ (((CTRL_SIZE + MLX4_EN_XDP_TX_NRTXBB * DS_SIZE) \ + / 16) & 0x3f) + netdev_tx_t mlx4_en_xmit_frame(struct mlx4_en_rx_ring *rx_ring, struct mlx4_en_rx_alloc *frame, struct net_device *dev, unsigned int length, - int tx_ind, int *doorbell_pending) + int tx_ind, bool *doorbell_pending) { struct mlx4_en_priv *priv = netdev_priv(dev); union mlx4_wqe_qpn_vlan qpn_vlan = {}; - struct mlx4_en_tx_ring *ring; struct mlx4_en_tx_desc *tx_desc; - struct mlx4_wqe_data_seg *data; struct mlx4_en_tx_info *tx_info; - int index, bf_index; - bool send_doorbell; - int nr_txbb = 1; - bool stop_queue; + struct mlx4_wqe_data_seg *data; + struct mlx4_en_tx_ring *ring; dma_addr_t dma; - int real_size; __be32 op_own; - u32 ring_cons; - bool bf_ok; + int index; - BUILD_BUG_ON_MSG(ALIGN(CTRL_SIZE + DS_SIZE, TXBB_SIZE) != TXBB_SIZE, - "mlx4_en_xmit_frame requires minimum size tx desc"); + if (unlikely(!priv->port_up)) + goto tx_drop; ring = priv->tx_ring[TX_XDP][tx_ind]; - if (!priv->port_up) - goto tx_drop; - - if (mlx4_en_is_tx_ring_full(ring)) + if (unlikely(mlx4_en_is_tx_ring_full(ring))) goto tx_drop_count; - /* fetch ring->cons far ahead before needing it to avoid stall */ - ring_cons = READ_ONCE(ring->cons); - index = ring->prod & ring->size_mask; tx_info = &ring->tx_info[index]; - bf_ok = ring->bf_enabled; - /* Track current inflight packets for performance analysis */ AVG_PERF_COUNTER(priv->pstats.inflight_avg, - (u32)(ring->prod - ring_cons - 1)); + (u32)(ring->prod - READ_ONCE(ring->cons) - 1)); - bf_index = ring->prod; tx_desc = ring->buf + index * TXBB_SIZE; data = &tx_desc->data; @@ -1149,9 +1138,9 @@ netdev_tx_t mlx4_en_xmit_frame(struct mlx4_en_rx_ring *rx_ring, frame->page = NULL; tx_info->map0_dma = dma; tx_info->map0_byte_count = PAGE_SIZE; - tx_info->nr_txbb = nr_txbb; + tx_info->nr_txbb = MLX4_EN_XDP_TX_NRTXBB; tx_info->nr_bytes = max_t(unsigned int, length, ETH_ZLEN); - tx_info->data_offset = (void *)data - (void *)tx_desc; + tx_info->data_offset = offsetof(struct mlx4_en_tx_desc, data); tx_info->ts_requested = 0; tx_info->nr_maps = 1; tx_info->linear = 1; @@ -1175,23 +1164,13 @@ netdev_tx_t mlx4_en_xmit_frame(struct mlx4_en_rx_ring *rx_ring, rx_ring->xdp_tx++; AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, length); - ring->prod += nr_txbb; + ring->prod += MLX4_EN_XDP_TX_NRTXBB; - stop_queue = mlx4_en_is_tx_ring_full(ring); - send_doorbell = stop_queue || - *doorbell_pending > MLX4_EN_DOORBELL_BUDGET; - bf_ok &= send_doorbell; + qpn_vlan.fence_size = MLX4_EN_XDP_TX_REAL_SZ; - real_size = ((CTRL_SIZE + nr_txbb * DS_SIZE) / 16) & 0x3f; - - if (bf_ok) - qpn_vlan.bf_qpn = ring->doorbell_qpn | cpu_to_be32(real_size); - else - qpn_vlan.fence_size = real_size; - - mlx4_en_tx_write_desc(ring, tx_desc, qpn_vlan, TXBB_SIZE, bf_index, - op_own, bf_ok, send_doorbell); - *doorbell_pending = send_doorbell ? 0 : *doorbell_pending + 1; + mlx4_en_tx_write_desc(ring, tx_desc, qpn_vlan, TXBB_SIZE, 0, + op_own, false, false); + *doorbell_pending = true; return NETDEV_TX_OK; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 41f4f8f9f300..c52edb717add 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -121,7 +121,6 @@ MLX4_EN_NUM_UP) #define MLX4_EN_DEFAULT_TX_WORK 256 -#define MLX4_EN_DOORBELL_BUDGET 8 /* Target number of packets to coalesce with interrupt moderation */ #define MLX4_EN_RX_COAL_TARGET 44 @@ -689,7 +688,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); netdev_tx_t mlx4_en_xmit_frame(struct mlx4_en_rx_ring *rx_ring, struct mlx4_en_rx_alloc *frame, struct net_device *dev, unsigned int length, - int tx_ind, int *doorbell_pending); + int tx_ind, bool *doorbell_pending); void mlx4_en_xmit_doorbell(struct mlx4_en_tx_ring *ring); bool mlx4_en_rx_recycle(struct mlx4_en_rx_ring *ring, struct mlx4_en_rx_alloc *frame); -- cgit v1.2.3 From 6c78511b0503c9b53fd0f5ccc8b28d5e94a3dfcb Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 15 Jun 2017 14:35:37 +0300 Subject: net/mlx4_en: Poll XDP TX completion queue in RX NAPI Instead of having their own NAPIs, XDP TX completion queues get polled within the corresponding RX NAPI. This prevents any possible race on TX ring prod/cons indices, between the context that issues the transmits (RX NAPI) and the context that handles the completions (was previously done in a separate NAPI). This also improves performance, as it decreases the number of NAPIs running on a CPU, saving the overhead of syncing and switching between the contexts. Performance tests: Tested on ConnectX3Pro, Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz Single queue no-RSS optimization ON. XDP_TX packet rate: ------------------------------------- | Before | After | Gain | IPv4 | 12.0 Mpps | 13.8 Mpps | 15% | IPv6 | 12.0 Mpps | 13.8 Mpps | 15% | ------------------------------------- Signed-off-by: Tariq Toukan Reviewed-by: Saeed Mahameed Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_cq.c | 25 ++++++++++++++++++------- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 8 +++++--- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 22 +++++++++++++++++++--- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 5 +++-- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 7 ++++++- 5 files changed, 51 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 09dd3776db76..85fe17e4dcfb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -146,16 +146,25 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, if (err) goto free_eq; - cq->mcq.comp = cq->type != RX ? mlx4_en_tx_irq : mlx4_en_rx_irq; cq->mcq.event = mlx4_en_cq_event; - if (cq->type != RX) + switch (cq->type) { + case TX: + cq->mcq.comp = mlx4_en_tx_irq; netif_tx_napi_add(cq->dev, &cq->napi, mlx4_en_poll_tx_cq, NAPI_POLL_WEIGHT); - else + napi_enable(&cq->napi); + break; + case RX: + cq->mcq.comp = mlx4_en_rx_irq; netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64); - - napi_enable(&cq->napi); + napi_enable(&cq->napi); + break; + case TX_XDP: + /* nothing regarding napi, it's shared with rx ring */ + cq->xdp_busy = false; + break; + } return 0; @@ -184,8 +193,10 @@ void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq) void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) { - napi_disable(&cq->napi); - netif_napi_del(&cq->napi); + if (cq->type != TX_XDP) { + napi_disable(&cq->napi); + netif_napi_del(&cq->napi); + } mlx4_cq_free(priv->mdev->dev, &cq->mcq); } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 51ce111b719e..99c02bb4f302 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1679,13 +1679,15 @@ int mlx4_en_start_port(struct net_device *dev) if (t != TX_XDP) { tx_ring->tx_queue = netdev_get_tx_queue(dev, i); tx_ring->recycle_ring = NULL; + + /* Arm CQ for TX completions */ + mlx4_en_arm_cq(priv, cq); + } else { mlx4_en_init_recycle_ring(priv, i); + /* XDP TX CQ should never be armed */ } - /* Arm CQ for TX completions */ - mlx4_en_arm_cq(priv, cq); - /* Set initial ownership of all Tx TXBBs to SW (1) */ for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) *((u32 *)(tx_ring->buf + j)) = 0xffffffff; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 747e4d7d7693..e5fb89505a13 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -880,8 +880,10 @@ next: rcu_read_unlock(); if (likely(polled)) { - if (doorbell_pending) - mlx4_en_xmit_doorbell(priv->tx_ring[TX_XDP][cq->ring]); + if (doorbell_pending) { + priv->tx_cq[TX_XDP][cq_ring]->xdp_busy = true; + mlx4_en_xmit_doorbell(priv->tx_ring[TX_XDP][cq_ring]); + } mlx4_cq_set_ci(&cq->mcq); wmb(); /* ensure HW sees CQ consumer before we post new buffers */ @@ -912,16 +914,30 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget) struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi); struct net_device *dev = cq->dev; struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_cq *xdp_tx_cq = NULL; + bool clean_complete = true; int done; + if (priv->tx_ring_num[TX_XDP]) { + xdp_tx_cq = priv->tx_cq[TX_XDP][cq->ring]; + if (xdp_tx_cq->xdp_busy) { + clean_complete = mlx4_en_process_tx_cq(dev, xdp_tx_cq, + budget); + xdp_tx_cq->xdp_busy = !clean_complete; + } + } + done = mlx4_en_process_rx_cq(dev, cq, budget); /* If we used up all the quota - we're probably not done yet... */ - if (done == budget) { + if (done == budget || !clean_complete) { const struct cpumask *aff; struct irq_data *idata; int cpu_curr; + /* in case we got here because of !clean_complete */ + done = budget; + INC_PERF_COUNTER(priv->pstats.napi_quota); cpu_curr = smp_processor_id(); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 01bb43879221..500442c60342 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -395,8 +395,8 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) return cnt; } -static bool mlx4_en_process_tx_cq(struct net_device *dev, - struct mlx4_en_cq *cq, int napi_budget) +bool mlx4_en_process_tx_cq(struct net_device *dev, + struct mlx4_en_cq *cq, int napi_budget) { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_cq *mcq = &cq->mcq; @@ -1176,6 +1176,7 @@ netdev_tx_t mlx4_en_xmit_frame(struct mlx4_en_rx_ring *rx_ring, tx_drop_count: rx_ring->xdp_tx_full++; + *doorbell_pending = true; tx_drop: return NETDEV_TX_BUSY; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index c52edb717add..bde3bc869b70 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -358,7 +358,10 @@ struct mlx4_en_cq { struct mlx4_hwq_resources wqres; int ring; struct net_device *dev; - struct napi_struct napi; + union { + struct napi_struct napi; + bool xdp_busy; + }; int size; int buf_size; int vector; @@ -720,6 +723,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, int budget); int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget); int mlx4_en_poll_tx_cq(struct napi_struct *napi, int budget); +bool mlx4_en_process_tx_cq(struct net_device *dev, + struct mlx4_en_cq *cq, int napi_budget); u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, int index, u64 timestamp, -- cgit v1.2.3 From 77788b5bf6becc5ada0da9f99e90c20ea6e77a58 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 15 Jun 2017 14:35:38 +0300 Subject: net/mlx4_en: Increase default TX ring size Increase the default TX ring size (from 512 to 1024) to match the RX ring size. This gives the XDP TX ring a better chance to keep up with the rate of its RX ring in case of a high load of XDP_TX actions. Tested: Ethtool counter rx_xdp_tx_full used to increase, after applying this patch it stopped. Signed-off-by: Tariq Toukan Reviewed-by: Saeed Mahameed Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index bde3bc869b70..7f61b5829709 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -115,8 +115,8 @@ #define MLX4_EN_MIN_TX_RING_P_UP 1 #define MLX4_EN_MAX_TX_RING_P_UP 32 #define MLX4_EN_NUM_UP 8 -#define MLX4_EN_DEF_TX_RING_SIZE 512 #define MLX4_EN_DEF_RX_RING_SIZE 1024 +#define MLX4_EN_DEF_TX_RING_SIZE MLX4_EN_DEF_RX_RING_SIZE #define MAX_TX_RINGS (MLX4_EN_MAX_TX_RING_P_UP * \ MLX4_EN_NUM_UP) -- cgit v1.2.3 From 9573e0d39ff8d7d1e0bcc10e23d18b9cbc4ca14e Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 15 Jun 2017 14:35:39 +0300 Subject: net/mlx4_en: Replace TXBB_SIZE multiplications with shift operations Define LOG_TXBB_SIZE, log of TXBB_SIZE, and use it with a shift operation instead of a multiplication with TXBB_SIZE. Operations are equivalent as TXBB_SIZE is a power of two. Performance tests: Tested on ConnectX3Pro, Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz Gain is too small to be measurable, no degradation sensed. Results are similar for IPv4 and IPv6. Signed-off-by: Tariq Toukan Reviewed-by: Saeed Mahameed Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 26 ++++++++++++++------------ drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 3 ++- 2 files changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 500442c60342..efc4411b1e44 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -234,23 +234,24 @@ static void mlx4_en_stamp_wqe(struct mlx4_en_priv *priv, u8 owner) { __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT)); - struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE; + struct mlx4_en_tx_desc *tx_desc = ring->buf + (index << LOG_TXBB_SIZE); struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; void *end = ring->buf + ring->buf_size; __be32 *ptr = (__be32 *)tx_desc; int i; /* Optimize the common case when there are no wraparounds */ - if (likely((void *)tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) { + if (likely((void *)tx_desc + + (tx_info->nr_txbb << LOG_TXBB_SIZE) <= end)) { /* Stamp the freed descriptor */ - for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; + for (i = 0; i < tx_info->nr_txbb << LOG_TXBB_SIZE; i += STAMP_STRIDE) { *ptr = stamp; ptr += STAMP_DWORDS; } } else { /* Stamp the freed descriptor */ - for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; + for (i = 0; i < tx_info->nr_txbb << LOG_TXBB_SIZE; i += STAMP_STRIDE) { *ptr = stamp; ptr += STAMP_DWORDS; @@ -269,7 +270,7 @@ u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, int napi_mode) { struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; - struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE; + struct mlx4_en_tx_desc *tx_desc = ring->buf + (index << LOG_TXBB_SIZE); struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset; void *end = ring->buf + ring->buf_size; struct sk_buff *skb = tx_info->skb; @@ -289,7 +290,8 @@ u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, } /* Optimize the common case when there are no wraparounds */ - if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) { + if (likely((void *)tx_desc + + (tx_info->nr_txbb << LOG_TXBB_SIZE) <= end)) { if (!tx_info->inl) { if (tx_info->linear) dma_unmap_single(priv->ddev, @@ -542,7 +544,7 @@ static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, u32 index, unsigned int desc_size) { - u32 copy = (ring->size - index) * TXBB_SIZE; + u32 copy = (ring->size - index) << LOG_TXBB_SIZE; int i; for (i = desc_size - copy - 4; i >= 0; i -= 4) { @@ -557,12 +559,12 @@ static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, if ((i & (TXBB_SIZE - 1)) == 0) wmb(); - *((u32 *) (ring->buf + index * TXBB_SIZE + i)) = + *((u32 *)(ring->buf + (index << LOG_TXBB_SIZE) + i)) = *((u32 *) (ring->bounce_buf + i)); } /* Return real descriptor location */ - return ring->buf + index * TXBB_SIZE; + return ring->buf + (index << LOG_TXBB_SIZE); } /* Decide if skb can be inlined in tx descriptor to avoid dma mapping @@ -881,7 +883,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Align descriptor to TXBB size */ desc_size = ALIGN(real_size, TXBB_SIZE); - nr_txbb = desc_size / TXBB_SIZE; + nr_txbb = desc_size >> LOG_TXBB_SIZE; if (unlikely(nr_txbb > MAX_DESC_TXBBS)) { if (netif_msg_tx_err(priv)) en_warn(priv, "Oversized header or SG list\n"); @@ -916,7 +918,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* See if we have enough space for whole descriptor TXBB for setting * SW ownership on next descriptor; if not, use a bounce buffer. */ if (likely(index + nr_txbb <= ring->size)) - tx_desc = ring->buf + index * TXBB_SIZE; + tx_desc = ring->buf + (index << LOG_TXBB_SIZE); else { tx_desc = (struct mlx4_en_tx_desc *) ring->bounce_buf; bounce = true; @@ -1129,7 +1131,7 @@ netdev_tx_t mlx4_en_xmit_frame(struct mlx4_en_rx_ring *rx_ring, AVG_PERF_COUNTER(priv->pstats.inflight_avg, (u32)(ring->prod - READ_ONCE(ring->cons) - 1)); - tx_desc = ring->buf + index * TXBB_SIZE; + tx_desc = ring->buf + (index << LOG_TXBB_SIZE); data = &tx_desc->data; dma = frame->dma; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 7f61b5829709..963b77d51b48 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -72,7 +72,8 @@ #define DEF_RX_RINGS 16 #define MAX_RX_RINGS 128 #define MIN_RX_RINGS 4 -#define TXBB_SIZE 64 +#define LOG_TXBB_SIZE 6 +#define TXBB_SIZE BIT(LOG_TXBB_SIZE) #define HEADROOM (2048 / TXBB_SIZE + 1) #define STAMP_STRIDE 64 #define STAMP_DWORDS (STAMP_STRIDE / 4) -- cgit v1.2.3 From 4c07c132408a685d31bb6e638aef4d245e30703a Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 15 Jun 2017 14:35:40 +0300 Subject: net/mlx4_en: Refactor mlx4_en_free_tx_desc Some code re-ordering, functionally equivalent. - The !tx_info->inl check is evaluated anyway in both flows (common case/end case). Run it first, this might finish the flows earlier. - dma_unmap calls are identical in both flows, get it out of the if block into the common area. Performance tests: Tested on ConnectX3Pro, Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz Gain is too small to be measurable, no degradation sensed. Results are similar for IPv4 and IPv6. Signed-off-by: Tariq Toukan Reviewed-by: Saeed Mahameed Cc: kernel-team@fb.com Cc: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 45 +++++++++++------------------- 1 file changed, 16 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index efc4411b1e44..7d69d939ee2d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -289,20 +289,20 @@ u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, skb_tstamp_tx(skb, &hwts); } - /* Optimize the common case when there are no wraparounds */ - if (likely((void *)tx_desc + - (tx_info->nr_txbb << LOG_TXBB_SIZE) <= end)) { - if (!tx_info->inl) { - if (tx_info->linear) - dma_unmap_single(priv->ddev, - tx_info->map0_dma, - tx_info->map0_byte_count, - PCI_DMA_TODEVICE); - else - dma_unmap_page(priv->ddev, - tx_info->map0_dma, - tx_info->map0_byte_count, - PCI_DMA_TODEVICE); + if (!tx_info->inl) { + if (tx_info->linear) + dma_unmap_single(priv->ddev, + tx_info->map0_dma, + tx_info->map0_byte_count, + PCI_DMA_TODEVICE); + else + dma_unmap_page(priv->ddev, + tx_info->map0_dma, + tx_info->map0_byte_count, + PCI_DMA_TODEVICE); + /* Optimize the common case when there are no wraparounds */ + if (likely((void *)tx_desc + + (tx_info->nr_txbb << LOG_TXBB_SIZE) <= end)) { for (i = 1; i < nr_maps; i++) { data++; dma_unmap_page(priv->ddev, @@ -310,23 +310,10 @@ u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, be32_to_cpu(data->byte_count), PCI_DMA_TODEVICE); } - } - } else { - if (!tx_info->inl) { - if ((void *) data >= end) { + } else { + if ((void *)data >= end) data = ring->buf + ((void *)data - end); - } - if (tx_info->linear) - dma_unmap_single(priv->ddev, - tx_info->map0_dma, - tx_info->map0_byte_count, - PCI_DMA_TODEVICE); - else - dma_unmap_page(priv->ddev, - tx_info->map0_dma, - tx_info->map0_byte_count, - PCI_DMA_TODEVICE); for (i = 1; i < nr_maps; i++) { data++; /* Check for wraparound before unmapping */ -- cgit v1.2.3 From 03a016f8944c5992b62cb92d2d8318f574a07407 Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Tue, 6 Jun 2017 14:35:41 +0530 Subject: ath10k: define structures for CE ctrl/misc register Define structures for the copy engine ctrl/misc registers, that includes CE CMD halt, watermark source, watermark destination, host IE ring, source, destination and dmax ring. This adds support to avoid the conditional compilation, code optimization and dynamic configuration of the copy engine register map for respective hardware bus interface. Signed-off-by: Sarada Prasanna Garnayak Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 164 ++++++++++++++++++++------------- drivers/net/wireless/ath/ath10k/ce.h | 132 -------------------------- drivers/net/wireless/ath/ath10k/core.c | 5 + drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/hw.c | 137 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 81 ++++++++++++++++ 6 files changed, 325 insertions(+), 195 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 51309563990f..08b84c8c3614 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -59,205 +59,243 @@ * the buffer is sent/received. */ +static inline unsigned int +ath10k_set_ring_byte(unsigned int offset, + struct ath10k_hw_ce_regs_addr_map *addr_map) +{ + return ((offset << addr_map->lsb) & addr_map->mask); +} + +static inline unsigned int +ath10k_get_ring_byte(unsigned int offset, + struct ath10k_hw_ce_regs_addr_map *addr_map) +{ + return ((offset & addr_map->mask) >> (addr_map->lsb)); +} + static inline void ath10k_ce_dest_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS, n); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dst_wr_index_addr, n); } static inline u32 ath10k_ce_dest_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + DST_WR_INDEX_ADDRESS); + return ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dst_wr_index_addr); } static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_wr_index_addr, n); } static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS); + return ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_wr_index_addr); } static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + CURRENT_SRRI_ADDRESS); + return ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_srri_addr); } static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_BA_ADDRESS, addr); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_base_addr, addr); } static inline void ath10k_ce_src_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + SR_SIZE_ADDRESS, n); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_size_addr, n); } static inline void ath10k_ce_src_ring_dmax_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32((ar), - (ce_ctrl_addr) + CE_CTRL1_ADDRESS); + struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; + u32 ctrl1_addr = ath10k_pci_read32(ar, + ce_ctrl_addr + ctrl_regs->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, - (ctrl1_addr & ~CE_CTRL1_DMAX_LENGTH_MASK) | - CE_CTRL1_DMAX_LENGTH_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->dmax->mask)) | + ath10k_set_ring_byte(n, ctrl_regs->dmax)); } static inline void ath10k_ce_src_ring_byte_swap_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); + struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; + u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + ctrl_regs->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, - (ctrl1_addr & ~CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) | - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->src_ring->mask)) | + ath10k_set_ring_byte(n, ctrl_regs->src_ring)); } static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS); + struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; + u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + ctrl_regs->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + CE_CTRL1_ADDRESS, - (ctrl1_addr & ~CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) | - CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->dst_ring->mask)) | + ath10k_set_ring_byte(n, ctrl_regs->dst_ring)); } static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + CURRENT_DRRI_ADDRESS); + return ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_drri_addr); } static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, u32 addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + DR_BA_ADDRESS, addr); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dr_base_addr, addr); } static inline void ath10k_ce_dest_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + DR_SIZE_ADDRESS, n); + ath10k_pci_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dr_size_addr, n); } static inline void ath10k_ce_src_ring_highmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *srcr_wm = ar->hw_ce_regs->wm_srcr; + u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + srcr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, - (addr & ~SRC_WATERMARK_HIGH_MASK) | - SRC_WATERMARK_HIGH_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + srcr_wm->addr, + (addr & ~(srcr_wm->wm_high->mask)) | + (ath10k_set_ring_byte(n, srcr_wm->wm_high))); } static inline void ath10k_ce_src_ring_lowmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *srcr_wm = ar->hw_ce_regs->wm_srcr; + u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + srcr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + SRC_WATERMARK_ADDRESS, - (addr & ~SRC_WATERMARK_LOW_MASK) | - SRC_WATERMARK_LOW_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + srcr_wm->addr, + (addr & ~(srcr_wm->wm_low->mask)) | + (ath10k_set_ring_byte(n, srcr_wm->wm_low))); } static inline void ath10k_ce_dest_ring_highmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *dstr_wm = ar->hw_ce_regs->wm_dstr; + u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + dstr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, - (addr & ~DST_WATERMARK_HIGH_MASK) | - DST_WATERMARK_HIGH_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + dstr_wm->addr, + (addr & ~(dstr_wm->wm_high->mask)) | + (ath10k_set_ring_byte(n, dstr_wm->wm_high))); } static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS); + struct ath10k_hw_ce_dst_src_wm_regs *dstr_wm = ar->hw_ce_regs->wm_dstr; + u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + dstr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + DST_WATERMARK_ADDRESS, - (addr & ~DST_WATERMARK_LOW_MASK) | - DST_WATERMARK_LOW_SET(n)); + ath10k_pci_write32(ar, ce_ctrl_addr + dstr_wm->addr, + (addr & ~(dstr_wm->wm_low->mask)) | + (ath10k_set_ring_byte(n, dstr_wm->wm_low))); } static inline void ath10k_ce_copy_complete_inter_enable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + HOST_IE_ADDRESS); + struct ath10k_hw_ce_host_ie *host_ie = ar->hw_ce_regs->host_ie; + u32 host_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->host_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, - host_ie_addr | HOST_IE_COPY_COMPLETE_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr | host_ie->copy_complete->mask); } static inline void ath10k_ce_copy_complete_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + HOST_IE_ADDRESS); + struct ath10k_hw_ce_host_ie *host_ie = ar->hw_ce_regs->host_ie; + u32 host_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->host_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, - host_ie_addr & ~HOST_IE_COPY_COMPLETE_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr & ~(host_ie->copy_complete->mask)); } static inline void ath10k_ce_watermark_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 host_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + HOST_IE_ADDRESS); + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; + u32 host_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->host_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IE_ADDRESS, - host_ie_addr & ~CE_WATERMARK_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr & ~(wm_regs->wm_mask)); } static inline void ath10k_ce_error_intr_enable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 misc_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + MISC_IE_ADDRESS); + struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; + u32 misc_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->misc_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, - misc_ie_addr | CE_ERROR_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, + misc_ie_addr | misc_regs->err_mask); } static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { - u32 misc_ie_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + MISC_IE_ADDRESS); + struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; + u32 misc_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->misc_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + MISC_IE_ADDRESS, - misc_ie_addr & ~CE_ERROR_MASK); + ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, + misc_ie_addr & ~(misc_regs->err_mask)); } static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int mask) { - ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask); + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; + + ath10k_pci_write32(ar, ce_ctrl_addr + wm_regs->addr, mask); } /* @@ -719,13 +757,13 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; u32 ctrl_addr = ce_state->ctrl_addr; spin_lock_bh(&ar_pci->ce_lock); /* Clear the copy-complete interrupts that will be handled here. */ - ath10k_ce_engine_int_status_clear(ar, ctrl_addr, - HOST_IS_COPY_COMPLETE_MASK); + ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->cc_mask); spin_unlock_bh(&ar_pci->ce_lock); @@ -741,7 +779,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) * Misc CE interrupts are not being handled, but still need * to be cleared. */ - ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK); + ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->wm_mask); spin_unlock_bh(&ar_pci->ce_lock); } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index e76a98242b98..95743a57525d 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -263,143 +263,11 @@ struct ce_attr { void (*recv_cb)(struct ath10k_ce_pipe *); }; -#define SR_BA_ADDRESS 0x0000 -#define SR_SIZE_ADDRESS 0x0004 -#define DR_BA_ADDRESS 0x0008 -#define DR_SIZE_ADDRESS 0x000c -#define CE_CMD_ADDRESS 0x0018 - -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MSB 17 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000 -#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \ - (((0 | (x)) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \ - CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) - -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MSB 16 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000 -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_GET(x) \ - (((x) & CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) >> \ - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) -#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \ - (((0 | (x)) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \ - CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) - -#define CE_CTRL1_DMAX_LENGTH_MSB 15 -#define CE_CTRL1_DMAX_LENGTH_LSB 0 -#define CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff -#define CE_CTRL1_DMAX_LENGTH_GET(x) \ - (((x) & CE_CTRL1_DMAX_LENGTH_MASK) >> CE_CTRL1_DMAX_LENGTH_LSB) -#define CE_CTRL1_DMAX_LENGTH_SET(x) \ - (((0 | (x)) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK) - -#define CE_CTRL1_ADDRESS 0x0010 -#define CE_CTRL1_HW_MASK 0x0007ffff -#define CE_CTRL1_SW_MASK 0x0007ffff -#define CE_CTRL1_HW_WRITE_MASK 0x00000000 -#define CE_CTRL1_SW_WRITE_MASK 0x0007ffff -#define CE_CTRL1_RSTMASK 0xffffffff -#define CE_CTRL1_RESET 0x00000080 - -#define CE_CMD_HALT_STATUS_MSB 3 -#define CE_CMD_HALT_STATUS_LSB 3 -#define CE_CMD_HALT_STATUS_MASK 0x00000008 -#define CE_CMD_HALT_STATUS_GET(x) \ - (((x) & CE_CMD_HALT_STATUS_MASK) >> CE_CMD_HALT_STATUS_LSB) -#define CE_CMD_HALT_STATUS_SET(x) \ - (((0 | (x)) << CE_CMD_HALT_STATUS_LSB) & CE_CMD_HALT_STATUS_MASK) -#define CE_CMD_HALT_STATUS_RESET 0 -#define CE_CMD_HALT_MSB 0 -#define CE_CMD_HALT_MASK 0x00000001 - -#define HOST_IE_COPY_COMPLETE_MSB 0 -#define HOST_IE_COPY_COMPLETE_LSB 0 -#define HOST_IE_COPY_COMPLETE_MASK 0x00000001 -#define HOST_IE_COPY_COMPLETE_GET(x) \ - (((x) & HOST_IE_COPY_COMPLETE_MASK) >> HOST_IE_COPY_COMPLETE_LSB) -#define HOST_IE_COPY_COMPLETE_SET(x) \ - (((0 | (x)) << HOST_IE_COPY_COMPLETE_LSB) & HOST_IE_COPY_COMPLETE_MASK) -#define HOST_IE_COPY_COMPLETE_RESET 0 -#define HOST_IE_ADDRESS 0x002c - -#define HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 -#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 -#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 -#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 -#define HOST_IS_COPY_COMPLETE_MASK 0x00000001 -#define HOST_IS_ADDRESS 0x0030 - -#define MISC_IE_ADDRESS 0x0034 - -#define MISC_IS_AXI_ERR_MASK 0x00000400 - -#define MISC_IS_DST_ADDR_ERR_MASK 0x00000200 -#define MISC_IS_SRC_LEN_ERR_MASK 0x00000100 -#define MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 -#define MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 -#define MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 - -#define MISC_IS_ADDRESS 0x0038 - -#define SR_WR_INDEX_ADDRESS 0x003c - -#define DST_WR_INDEX_ADDRESS 0x0040 - -#define CURRENT_SRRI_ADDRESS 0x0044 - -#define CURRENT_DRRI_ADDRESS 0x0048 - -#define SRC_WATERMARK_LOW_MSB 31 -#define SRC_WATERMARK_LOW_LSB 16 -#define SRC_WATERMARK_LOW_MASK 0xffff0000 -#define SRC_WATERMARK_LOW_GET(x) \ - (((x) & SRC_WATERMARK_LOW_MASK) >> SRC_WATERMARK_LOW_LSB) -#define SRC_WATERMARK_LOW_SET(x) \ - (((0 | (x)) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK) -#define SRC_WATERMARK_LOW_RESET 0 -#define SRC_WATERMARK_HIGH_MSB 15 -#define SRC_WATERMARK_HIGH_LSB 0 -#define SRC_WATERMARK_HIGH_MASK 0x0000ffff -#define SRC_WATERMARK_HIGH_GET(x) \ - (((x) & SRC_WATERMARK_HIGH_MASK) >> SRC_WATERMARK_HIGH_LSB) -#define SRC_WATERMARK_HIGH_SET(x) \ - (((0 | (x)) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK) -#define SRC_WATERMARK_HIGH_RESET 0 -#define SRC_WATERMARK_ADDRESS 0x004c - -#define DST_WATERMARK_LOW_LSB 16 -#define DST_WATERMARK_LOW_MASK 0xffff0000 -#define DST_WATERMARK_LOW_SET(x) \ - (((0 | (x)) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK) -#define DST_WATERMARK_LOW_RESET 0 -#define DST_WATERMARK_HIGH_MSB 15 -#define DST_WATERMARK_HIGH_LSB 0 -#define DST_WATERMARK_HIGH_MASK 0x0000ffff -#define DST_WATERMARK_HIGH_GET(x) \ - (((x) & DST_WATERMARK_HIGH_MASK) >> DST_WATERMARK_HIGH_LSB) -#define DST_WATERMARK_HIGH_SET(x) \ - (((0 | (x)) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK) -#define DST_WATERMARK_HIGH_RESET 0 -#define DST_WATERMARK_ADDRESS 0x0050 - static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) { return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; } -#define CE_WATERMARK_MASK (HOST_IS_SRC_RING_LOW_WATERMARK_MASK | \ - HOST_IS_SRC_RING_HIGH_WATERMARK_MASK | \ - HOST_IS_DST_RING_LOW_WATERMARK_MASK | \ - HOST_IS_DST_RING_HIGH_WATERMARK_MASK) - -#define CE_ERROR_MASK (MISC_IS_AXI_ERR_MASK | \ - MISC_IS_DST_ADDR_ERR_MASK | \ - MISC_IS_SRC_LEN_ERR_MASK | \ - MISC_IS_DST_MAX_LEN_VIO_MASK | \ - MISC_IS_DST_RING_OVERFLOW_MASK | \ - MISC_IS_SRC_RING_OVERFLOW_MASK) - #define CE_SRC_RING_TO_DESC(baddr, idx) \ (&(((struct ce_desc *)baddr)[idx])) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index ce79a2e070bd..700efe3f6225 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2459,24 +2459,29 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, case ATH10K_HW_QCA988X: case ATH10K_HW_QCA9887: ar->regs = &qca988x_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca988x_values; break; case ATH10K_HW_QCA6174: case ATH10K_HW_QCA9377: ar->regs = &qca6174_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca6174_values; break; case ATH10K_HW_QCA99X0: case ATH10K_HW_QCA9984: ar->regs = &qca99x0_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca99x0_values; break; case ATH10K_HW_QCA9888: ar->regs = &qca99x0_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca9888_values; break; case ATH10K_HW_QCA4019: ar->regs = &qca4019_regs; + ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca4019_values; break; default: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 8fc08a5043db..1aa5cf12fce0 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -794,6 +794,7 @@ struct ath10k { struct completion target_suspend; const struct ath10k_hw_regs *regs; + const struct ath10k_hw_ce_regs *hw_ce_regs; const struct ath10k_hw_values *hw_values; struct ath10k_bmi bmi; struct ath10k_wmi wmi; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index c866ab524571..afb0c01cbb55 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -15,6 +15,7 @@ */ #include +#include #include "core.h" #include "hw.h" #include "hif.h" @@ -191,6 +192,142 @@ const struct ath10k_hw_values qca4019_values = { .ce_desc_meta_data_lsb = 4, }; +static struct ath10k_hw_ce_regs_addr_map qcax_src_ring = { + .msb = 0x00000010, + .lsb = 0x00000010, + .mask = GENMASK(16, 16), +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_dst_ring = { + .msb = 0x00000011, + .lsb = 0x00000011, + .mask = GENMASK(17, 17), +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_dmax = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = GENMASK(15, 0), +}; + +static struct ath10k_hw_ce_ctrl1 qcax_ctrl1 = { + .addr = 0x00000010, + .hw_mask = 0x0007ffff, + .sw_mask = 0x0007ffff, + .hw_wr_mask = 0x00000000, + .sw_wr_mask = 0x0007ffff, + .reset_mask = 0xffffffff, + .reset = 0x00000080, + .src_ring = &qcax_src_ring, + .dst_ring = &qcax_dst_ring, + .dmax = &qcax_dmax, +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_cmd_halt_status = { + .msb = 0x00000003, + .lsb = 0x00000003, + .mask = GENMASK(3, 3), +}; + +static struct ath10k_hw_ce_cmd_halt qcax_cmd_halt = { + .msb = 0x00000000, + .mask = GENMASK(0, 0), + .status_reset = 0x00000000, + .status = &qcax_cmd_halt_status, +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_host_ie_cc = { + .msb = 0x00000000, + .lsb = 0x00000000, + .mask = GENMASK(0, 0), +}; + +static struct ath10k_hw_ce_host_ie qcax_host_ie = { + .copy_complete_reset = 0x00000000, + .copy_complete = &qcax_host_ie_cc, +}; + +static struct ath10k_hw_ce_host_wm_regs qcax_wm_reg = { + .dstr_lmask = 0x00000010, + .dstr_hmask = 0x00000008, + .srcr_lmask = 0x00000004, + .srcr_hmask = 0x00000002, + .cc_mask = 0x00000001, + .wm_mask = 0x0000001E, + .addr = 0x00000030, +}; + +static struct ath10k_hw_ce_misc_regs qcax_misc_reg = { + .axi_err = 0x00000400, + .dstr_add_err = 0x00000200, + .srcr_len_err = 0x00000100, + .dstr_mlen_vio = 0x00000080, + .dstr_overflow = 0x00000040, + .srcr_overflow = 0x00000020, + .err_mask = 0x000007E0, + .addr = 0x00000038, +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_src_wm_low = { + .msb = 0x0000001f, + .lsb = 0x00000010, + .mask = GENMASK(31, 16), +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_src_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = GENMASK(15, 0), +}; + +static struct ath10k_hw_ce_dst_src_wm_regs qcax_wm_src_ring = { + .addr = 0x0000004c, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &qcax_src_wm_low, + .wm_high = &qcax_src_wm_high, +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_dst_wm_low = { + .lsb = 0x00000010, + .mask = GENMASK(31, 16), +}; + +static struct ath10k_hw_ce_regs_addr_map qcax_dst_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = GENMASK(15, 0), +}; + +static struct ath10k_hw_ce_dst_src_wm_regs qcax_wm_dst_ring = { + .addr = 0x00000050, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &qcax_dst_wm_low, + .wm_high = &qcax_dst_wm_high, +}; + +struct ath10k_hw_ce_regs qcax_ce_regs = { + .sr_base_addr = 0x00000000, + .sr_size_addr = 0x00000004, + .dr_base_addr = 0x00000008, + .dr_size_addr = 0x0000000c, + .ce_cmd_addr = 0x00000018, + .misc_ie_addr = 0x00000034, + .sr_wr_index_addr = 0x0000003c, + .dst_wr_index_addr = 0x00000040, + .current_srri_addr = 0x00000044, + .current_drri_addr = 0x00000048, + .host_ie_addr = 0x0000002c, + .ctrl1_regs = &qcax_ctrl1, + .cmd_halt = &qcax_cmd_halt, + .host_ie = &qcax_host_ie, + .wm_regs = &qcax_wm_reg, + .misc_regs = &qcax_misc_reg, + .wm_srcr = &qcax_wm_src_ring, + .wm_dstr = &qcax_wm_dst_ring, +}; + const struct ath10k_hw_clk_params qca6174_clk[ATH10K_HW_REFCLK_COUNT] = { { .refclk = 48000000, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index d34272803fd7..be3eea429ec6 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -268,6 +268,86 @@ extern const struct ath10k_hw_regs qca6174_regs; extern const struct ath10k_hw_regs qca99x0_regs; extern const struct ath10k_hw_regs qca4019_regs; +struct ath10k_hw_ce_regs_addr_map { + u32 msb; + u32 lsb; + u32 mask; +}; + +struct ath10k_hw_ce_ctrl1 { + u32 addr; + u32 hw_mask; + u32 sw_mask; + u32 hw_wr_mask; + u32 sw_wr_mask; + u32 reset_mask; + u32 reset; + struct ath10k_hw_ce_regs_addr_map *src_ring; + struct ath10k_hw_ce_regs_addr_map *dst_ring; + struct ath10k_hw_ce_regs_addr_map *dmax; }; + +struct ath10k_hw_ce_cmd_halt { + u32 status_reset; + u32 msb; + u32 mask; + struct ath10k_hw_ce_regs_addr_map *status; }; + +struct ath10k_hw_ce_host_ie { + u32 copy_complete_reset; + struct ath10k_hw_ce_regs_addr_map *copy_complete; }; + +struct ath10k_hw_ce_host_wm_regs { + u32 dstr_lmask; + u32 dstr_hmask; + u32 srcr_lmask; + u32 srcr_hmask; + u32 cc_mask; + u32 wm_mask; + u32 addr; +}; + +struct ath10k_hw_ce_misc_regs { + u32 axi_err; + u32 dstr_add_err; + u32 srcr_len_err; + u32 dstr_mlen_vio; + u32 dstr_overflow; + u32 srcr_overflow; + u32 err_mask; + u32 addr; +}; + +struct ath10k_hw_ce_dst_src_wm_regs { + u32 addr; + u32 low_rst; + u32 high_rst; + struct ath10k_hw_ce_regs_addr_map *wm_low; + struct ath10k_hw_ce_regs_addr_map *wm_high; }; + +struct ath10k_hw_ce_regs { + u32 sr_base_addr; + u32 sr_size_addr; + u32 dr_base_addr; + u32 dr_size_addr; + u32 ce_cmd_addr; + u32 misc_ie_addr; + u32 sr_wr_index_addr; + u32 dst_wr_index_addr; + u32 current_srri_addr; + u32 current_drri_addr; + u32 ddr_addr_for_rri_low; + u32 ddr_addr_for_rri_high; + u32 ce_rri_low; + u32 ce_rri_high; + u32 host_ie_addr; + struct ath10k_hw_ce_host_wm_regs *wm_regs; + struct ath10k_hw_ce_misc_regs *misc_regs; + struct ath10k_hw_ce_ctrl1 *ctrl1_regs; + struct ath10k_hw_ce_cmd_halt *cmd_halt; + struct ath10k_hw_ce_host_ie *host_ie; + struct ath10k_hw_ce_dst_src_wm_regs *wm_srcr; + struct ath10k_hw_ce_dst_src_wm_regs *wm_dstr; }; + struct ath10k_hw_values { u32 rtc_state_val_on; u8 ce_count; @@ -282,6 +362,7 @@ extern const struct ath10k_hw_values qca6174_values; extern const struct ath10k_hw_values qca99x0_values; extern const struct ath10k_hw_values qca9888_values; extern const struct ath10k_hw_values qca4019_values; +extern struct ath10k_hw_ce_regs qcax_ce_regs; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); -- cgit v1.2.3 From 8241253d03fe9098e98315a4d66027ae31ab65c5 Mon Sep 17 00:00:00 2001 From: Norik Dzhandzhapanyan Date: Mon, 12 Jun 2017 18:03:34 +0300 Subject: ath10k: add per chain RSSI reporting Report per chain RSSI to mac80211. Signed-off-by: Norik Dzhandzhapanyan [kvalo@qca.qualcomm.com: fix conflicts and style] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 6c0a821fe79d..398dda978d6e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -829,6 +829,19 @@ static void ath10k_htt_rx_h_signal(struct ath10k *ar, struct ieee80211_rx_status *status, struct htt_rx_desc *rxd) { + int i; + + for (i = 0; i < IEEE80211_MAX_CHAINS ; i++) { + status->chains &= ~BIT(i); + + if (rxd->ppdu_start.rssi_chains[i].pri20_mhz != 0x80) { + status->chain_signal[i] = ATH10K_DEFAULT_NOISE_FLOOR + + rxd->ppdu_start.rssi_chains[i].pri20_mhz; + + status->chains |= BIT(i); + } + } + /* FIXME: Get real NF */ status->signal = ATH10K_DEFAULT_NOISE_FLOOR + rxd->ppdu_start.rssi_comb; -- cgit v1.2.3 From fe611d047e454123a8e2364d86fffb2820b2a7d8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 4 Jun 2017 17:36:08 +0100 Subject: ath6kl: fix spelling mistake: "Indicat" -> "Indicate" Trivial fix to spelling mistake in ath6kl_dbg debug message Signed-off-by: Colin Ian King Reviewed-by: Steve deRosier Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc_pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index d127a08d60df..d4fd9e40fffb 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -383,7 +383,7 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, list_for_each_entry_safe(packet, tmp_pkt, txq, list) { ath6kl_dbg(ATH6KL_DBG_HTC, - "%s: Indicat overflowed TX pkts: %p\n", + "%s: Indicate overflowed TX pkts: %p\n", __func__, packet); action = ep->ep_cb.tx_full(ep->target, packet); if (action == HTC_SEND_FULL_DROP) { -- cgit v1.2.3 From 21cbd0ecad7943bbd4f7d10efaade0380637d4a0 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 13 Jun 2017 15:14:39 +0800 Subject: r8152: split rtl8152_resume function Split rtl8152_resume() into rtl8152_runtime_resume() and rtl8152_system_resume(). Besides, replace GFP_KERNEL with GFP_NOIO for usb_submit_urb(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 99 ++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 3a29072dc622..c7663e10707c 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -4289,6 +4289,61 @@ static bool delay_autosuspend(struct r8152 *tp) return false; } +static int rtl8152_runtime_resume(struct r8152 *tp) +{ + struct net_device *netdev = tp->netdev; + + if (netif_running(netdev) && netdev->flags & IFF_UP) { + struct napi_struct *napi = &tp->napi; + + tp->rtl_ops.autosuspend_en(tp, false); + napi_disable(napi); + set_bit(WORK_ENABLE, &tp->flags); + + if (netif_carrier_ok(netdev)) { + if (rtl8152_get_speed(tp) & LINK_STATUS) { + rtl_start_rx(tp); + } else { + netif_carrier_off(netdev); + tp->rtl_ops.disable(tp); + netif_info(tp, link, netdev, "linking down\n"); + } + } + + napi_enable(napi); + clear_bit(SELECTIVE_SUSPEND, &tp->flags); + smp_mb__after_atomic(); + + if (!list_empty(&tp->rx_done)) + napi_schedule(&tp->napi); + + usb_submit_urb(tp->intr_urb, GFP_NOIO); + } else { + if (netdev->flags & IFF_UP) + tp->rtl_ops.autosuspend_en(tp, false); + + clear_bit(SELECTIVE_SUSPEND, &tp->flags); + } + + return 0; +} + +static int rtl8152_system_resume(struct r8152 *tp) +{ + struct net_device *netdev = tp->netdev; + + netif_device_attach(netdev); + + if (netif_running(netdev) && netdev->flags & IFF_UP) { + tp->rtl_ops.up(tp); + netif_carrier_off(netdev); + set_bit(WORK_ENABLE, &tp->flags); + usb_submit_urb(tp->intr_urb, GFP_NOIO); + } + + return 0; +} + static int rtl8152_runtime_suspend(struct r8152 *tp) { struct net_device *netdev = tp->netdev; @@ -4387,50 +4442,18 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) static int rtl8152_resume(struct usb_interface *intf) { struct r8152 *tp = usb_get_intfdata(intf); - struct net_device *netdev = tp->netdev; + int ret; mutex_lock(&tp->control); - if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) - netif_device_attach(netdev); - - if (netif_running(netdev) && netdev->flags & IFF_UP) { - if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - struct napi_struct *napi = &tp->napi; - - tp->rtl_ops.autosuspend_en(tp, false); - napi_disable(napi); - set_bit(WORK_ENABLE, &tp->flags); - if (netif_carrier_ok(netdev)) { - if (rtl8152_get_speed(tp) & LINK_STATUS) { - rtl_start_rx(tp); - } else { - netif_carrier_off(netdev); - tp->rtl_ops.disable(tp); - netif_info(tp, link, netdev, - "linking down\n"); - } - } - napi_enable(napi); - clear_bit(SELECTIVE_SUSPEND, &tp->flags); - smp_mb__after_atomic(); - if (!list_empty(&tp->rx_done)) - napi_schedule(&tp->napi); - } else { - tp->rtl_ops.up(tp); - netif_carrier_off(netdev); - set_bit(WORK_ENABLE, &tp->flags); - } - usb_submit_urb(tp->intr_urb, GFP_KERNEL); - } else if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - if (netdev->flags & IFF_UP) - tp->rtl_ops.autosuspend_en(tp, false); - clear_bit(SELECTIVE_SUSPEND, &tp->flags); - } + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) + ret = rtl8152_runtime_resume(tp); + else + ret = rtl8152_system_resume(tp); mutex_unlock(&tp->control); - return 0; + return ret; } static int rtl8152_reset_resume(struct usb_interface *intf) -- cgit v1.2.3 From bd8829822204debbb2dd38a5b052ef7663e618cc Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 13 Jun 2017 15:14:40 +0800 Subject: r8152: move calling delay_autosuspend function Move calling delay_autosuspend() in rtl8152_runtime_suspend(). Calling delay_autosuspend() as late as possible. The original flows are 1. check if the driver/device is busy now. 2. set wake events. 3. enter runtime suspend. If the wake event occurs between (1) and (2), the device may miss it. Besides, to avoid the runtime resume occurs after runtime suspend immediately, move the checking to the end of rtl8152_runtime_suspend(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index c7663e10707c..8bc4573e0cd4 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -4355,13 +4355,6 @@ static int rtl8152_runtime_suspend(struct r8152 *tp) if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { u32 rcr = 0; - if (delay_autosuspend(tp)) { - clear_bit(SELECTIVE_SUSPEND, &tp->flags); - smp_mb__after_atomic(); - ret = -EBUSY; - goto out1; - } - if (netif_carrier_ok(netdev)) { u32 ocp_data; @@ -4395,6 +4388,11 @@ static int rtl8152_runtime_suspend(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr); napi_enable(napi); } + + if (delay_autosuspend(tp)) { + rtl8152_runtime_resume(tp); + ret = -EBUSY; + } } out1: -- cgit v1.2.3 From b080db585384b9f037e015c0c28d1ad33be41dfc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Jun 2017 14:29:19 +0200 Subject: networking: convert many more places to skb_put_zero() There were many places that my previous spatch didn't find, as pointed out by yuan linyu in various patches. The following spatch found many more and also removes the now unnecessary casts: @@ identifier p, p2; expression len; expression skb; type t, t2; @@ ( -p = skb_put(skb, len); +p = skb_put_zero(skb, len); | -p = (t)skb_put(skb, len); +p = skb_put_zero(skb, len); ) ... when != p ( p2 = (t2)p; -memset(p2, 0, len); | -memset(p, 0, len); ) @@ type t, t2; identifier p, p2; expression skb; @@ t *p; ... ( -p = skb_put(skb, sizeof(t)); +p = skb_put_zero(skb, sizeof(t)); | -p = (t *)skb_put(skb, sizeof(t)); +p = skb_put_zero(skb, sizeof(t)); ) ... when != p ( p2 = (t2)p; -memset(p2, 0, sizeof(*p)); | -memset(p, 0, sizeof(*p)); ) @@ expression skb, len; @@ -memset(skb_put(skb, len), 0, len); +skb_put_zero(skb, len); Apply it to the tree (with one manual fixup to keep the comment in vxlan.c, which spatch removed.) Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/infiniband/hw/cxgb3/cxio_hal.c | 6 ++---- drivers/infiniband/hw/cxgb3/iwch_cm.c | 3 +-- drivers/infiniband/hw/cxgb3/iwch_qp.c | 6 ++---- drivers/infiniband/hw/cxgb4/cm.c | 9 +++------ drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c | 2 +- drivers/net/usb/cdc_ncm.c | 4 ++-- drivers/net/usb/kalmia.c | 2 +- drivers/net/vxlan.c | 4 +--- drivers/net/wireless/ath/ath9k/channel.c | 3 +-- drivers/net/wireless/intersil/hostap/hostap_ap.c | 7 ++----- drivers/net/wireless/intersil/hostap/hostap_main.c | 4 +--- drivers/net/wireless/intersil/p54/txrx.c | 3 +-- drivers/net/wireless/marvell/mwifiex/cmdevt.c | 3 +-- drivers/net/wireless/marvell/mwifiex/tdls.c | 3 +-- drivers/net/wireless/quantenna/qtnfmac/commands.c | 10 +++------- drivers/net/wireless/realtek/rtlwifi/base.c | 6 ++---- drivers/net/wireless/ti/wlcore/cmd.c | 3 +-- drivers/net/wireless/ti/wlcore/main.c | 5 ++--- drivers/scsi/fcoe/fcoe_ctlr.c | 3 +-- drivers/scsi/libfc/fc_libfc.c | 2 +- drivers/usb/gadget/function/f_ncm.c | 15 +++++---------- 21 files changed, 35 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 558d6a03375d..97f7f9544e70 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -142,8 +142,7 @@ static int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid) pr_debug("%s alloc_skb failed\n", __func__); return -ENOMEM; } - wqe = (struct t3_modify_qp_wr *) skb_put(skb, sizeof(*wqe)); - memset(wqe, 0, sizeof(*wqe)); + wqe = skb_put_zero(skb, sizeof(*wqe)); build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, T3_COMPLETION_FLAG | T3_NOTIFY_FLAG, 0, qpid, 7, T3_SOPEOP); @@ -561,8 +560,7 @@ static int cxio_hal_init_ctrl_qp(struct cxio_rdev *rdev_p) ctx1 |= ((u64) (V_EC_BASE_HI((u32) base_addr & 0xf) | V_EC_RESPQ(0) | V_EC_TYPE(0) | V_EC_GEN(1) | V_EC_UP_TOKEN(T3_CTL_QP_TID) | F_EC_VALID)) << 32; - wqe = (struct t3_modify_qp_wr *) skb_put(skb, sizeof(*wqe)); - memset(wqe, 0, sizeof(*wqe)); + wqe = skb_put_zero(skb, sizeof(*wqe)); build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, 0, 0, T3_CTL_QP_TID, 7, T3_SOPEOP); wqe->flags = cpu_to_be32(MODQP_WRITE_EC); diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index b61630eba912..f4c23a74f18c 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -417,8 +417,7 @@ static int send_abort(struct iwch_ep *ep, struct sk_buff *skb, gfp_t gfp) } skb->priority = CPL_PRIORITY_DATA; set_arp_failure_handler(skb, abort_arp_failure); - req = (struct cpl_abort_req *) skb_put(skb, sizeof(*req)); - memset(req, 0, sizeof(*req)); + req = skb_put_zero(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ)); req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, ep->hwtid)); diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index ba6d5d281b03..7f633da0185d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -670,8 +670,7 @@ int iwch_post_zb_read(struct iwch_ep *ep) pr_err("%s cannot send zb_read!!\n", __func__); return -ENOMEM; } - wqe = (union t3_wr *)skb_put(skb, sizeof(struct t3_rdma_read_wr)); - memset(wqe, 0, sizeof(struct t3_rdma_read_wr)); + wqe = skb_put_zero(skb, sizeof(struct t3_rdma_read_wr)); wqe->read.rdmaop = T3_READ_REQ; wqe->read.reserved[0] = 0; wqe->read.reserved[1] = 0; @@ -702,8 +701,7 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg) pr_err("%s cannot send TERMINATE!\n", __func__); return -ENOMEM; } - wqe = (union t3_wr *)skb_put(skb, 40); - memset(wqe, 0, 40); + wqe = skb_put_zero(skb, 40); wqe->send.rdmaop = T3_TERMINATE; /* immediate data length */ diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 2f1136bf7b1f..7c32a7c7977d 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -927,8 +927,7 @@ static int send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb, } set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx); - req = (struct fw_ofld_tx_data_wr *)skb_put(skb, wrlen); - memset(req, 0, wrlen); + req = skb_put_zero(skb, wrlen); req->op_to_immdlen = cpu_to_be32( FW_WR_OP_V(FW_OFLD_TX_DATA_WR) | FW_WR_COMPL_F | @@ -1034,8 +1033,7 @@ static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen) } set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx); - req = (struct fw_ofld_tx_data_wr *)skb_put(skb, wrlen); - memset(req, 0, wrlen); + req = skb_put_zero(skb, wrlen); req->op_to_immdlen = cpu_to_be32( FW_WR_OP_V(FW_OFLD_TX_DATA_WR) | FW_WR_COMPL_F | @@ -1115,8 +1113,7 @@ static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen) } set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx); - req = (struct fw_ofld_tx_data_wr *) skb_put(skb, wrlen); - memset(req, 0, wrlen); + req = skb_put_zero(skb, wrlen); req->op_to_immdlen = cpu_to_be32( FW_WR_OP_V(FW_OFLD_TX_DATA_WR) | FW_WR_COMPL_F | diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c index 5225f2226a67..601abf240d63 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c @@ -172,7 +172,7 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv) mlxh->magic = cpu_to_be64(MLX5E_TEST_MAGIC); strlcpy(mlxh->text, mlx5e_test_text, sizeof(mlxh->text)); datalen -= sizeof(*mlxh); - memset(skb_put(skb, datalen), 0, datalen); + skb_put_zero(skb, datalen); skb->csum = 0; skb->ip_summed = CHECKSUM_PARTIAL; diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index b5cec1824a78..7f02954772c6 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1017,7 +1017,7 @@ static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remai if (skb->len + align > max) align = max - skb->len; if (align && skb_tailroom(skb) >= align) - memset(skb_put(skb, align), 0, align); + skb_put_zero(skb, align); } /* return a pointer to a valid struct usb_cdc_ncm_ndp16 of type sign, possibly @@ -1247,7 +1247,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) if (!(dev->driver_info->flags & FLAG_SEND_ZLP) && skb_out->len > ctx->min_tx_pkt) { padding_count = ctx->tx_max - skb_out->len; - memset(skb_put(skb_out, padding_count), 0, padding_count); + skb_put_zero(skb_out, padding_count); } else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0) { *skb_put(skb_out, 1) = 0; /* force short packet */ diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c index 8aefb282c862..ce0b0b4e3a57 100644 --- a/drivers/net/usb/kalmia.c +++ b/drivers/net/usb/kalmia.c @@ -217,7 +217,7 @@ done: remainder = skb->len % KALMIA_ALIGN_SIZE; if (remainder > 0) { padlen = KALMIA_ALIGN_SIZE - remainder; - memset(skb_put(skb, padlen), 0, padlen); + skb_put_zero(skb, padlen); } netdev_dbg(dev->net, diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 25b70cad055c..4e1d427d340c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1584,10 +1584,8 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request, skb_pull(reply, sizeof(struct ipv6hdr)); skb_reset_transport_header(reply); - na = (struct nd_msg *)skb_put(reply, sizeof(*na) + na_olen); - /* Neighbor Advertisement */ - memset(na, 0, sizeof(*na)+na_olen); + na = skb_put_zero(reply, sizeof(*na) + na_olen); na->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT; na->icmph.icmp6_router = isrouter; na->icmph.icmp6_override = 1; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index b84539d89f1a..373b1e9457fd 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -1526,8 +1526,7 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2; hdr[7] = noa_len; - noa = (void *) skb_put(skb, noa_len); - memset(noa, 0, noa_len); + noa = skb_put_zero(skb, noa_len); noa->index = avp->noa_index; noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp); diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c index c995ace153ee..89b5987303a4 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ap.c @@ -998,12 +998,10 @@ static void prism2_send_mgmt(struct net_device *dev, fc = type_subtype; hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype)); - hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen); + hdr = skb_put_zero(skb, hdrlen); if (body) memcpy(skb_put(skb, body_len), body, body_len); - memset(hdr, 0, hdrlen); - /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 * tx_control instead of using local->tx_control */ @@ -1325,8 +1323,7 @@ static char * ap_auth_make_challenge(struct ap_data *ap) } skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); - memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, - WLAN_AUTH_CHALLENGE_LEN); + skb_put_zero(skb, WLAN_AUTH_CHALLENGE_LEN); if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { dev_kfree_skb(skb); kfree(tmpbuf); diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c index 1372b20f931e..400f9b5d620e 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ b/drivers/net/wireless/intersil/hostap/hostap_main.c @@ -1039,9 +1039,7 @@ int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, if (skb == NULL) return -ENOMEM; - mgmt = (struct hostap_ieee80211_mgmt *) - skb_put(skb, IEEE80211_MGMT_HDR_LEN); - memset(mgmt, 0, IEEE80211_MGMT_HDR_LEN); + mgmt = skb_put_zero(skb, IEEE80211_MGMT_HDR_LEN); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); memcpy(mgmt->da, dst, ETH_ALEN); memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c index 5e1c91a80c58..60f9b678ef74 100644 --- a/drivers/net/wireless/intersil/p54/txrx.c +++ b/drivers/net/wireless/intersil/p54/txrx.c @@ -910,8 +910,7 @@ void p54_tx_80211(struct ieee80211_hw *dev, } /* reserve some space for ICV */ len += info->control.hw_key->icv_len; - memset(skb_put(skb, info->control.hw_key->icv_len), 0, - info->control.hw_key->icv_len); + skb_put_zero(skb, info->control.hw_key->icv_len); } else { txhdr->key_type = 0; txhdr->key_len = 0; diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 40c3fe5ab8ca..8dad52886034 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -622,8 +622,7 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, return -1; } - memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)), - 0, sizeof(struct host_cmd_ds_command)); + skb_put_zero(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)); cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); cmd_ptr->command = cpu_to_le16(cmd_no); diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index b7d124dbef0c..c76b7315af55 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -388,8 +388,7 @@ mwifiex_tdls_add_wmm_param_ie(struct mwifiex_private *priv, struct sk_buff *skb) u8 ac_be[] = {0x03, 0xa4, 0x00, 0x00}; u8 ac_bk[] = {0x27, 0xa4, 0x00, 0x00}; - wmm = (void *)skb_put(skb, sizeof(*wmm)); - memset(wmm, 0, sizeof(*wmm)); + wmm = skb_put_zero(skb, sizeof(*wmm)); wmm->element_id = WLAN_EID_VENDOR_SPECIFIC; wmm->len = sizeof(*wmm) - 2; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index f0a0cfa7d8a1..37c3bececa1f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -135,7 +135,7 @@ static struct sk_buff *qtnf_cmd_alloc_new_cmdskb(u8 macid, u8 vifid, u16 cmd_no, return NULL; } - memset(skb_put(cmd_skb, cmd_size), 0, cmd_size); + skb_put_zero(cmd_skb, cmd_size); cmd = (struct qlink_cmd *)cmd_skb->data; cmd->mhdr.len = cpu_to_le16(cmd_skb->len); @@ -238,9 +238,7 @@ int qtnf_cmd_send_config_ap(struct qtnf_vif *vif) bss_cfg->bcn_period); qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_DTIM, bss_cfg->dtim); - qchan = (struct qlink_tlv_channel *)skb_put(cmd_skb, sizeof(*qchan)); - - memset(qchan, 0, sizeof(*qchan)); + qchan = skb_put_zero(cmd_skb, sizeof(*qchan)); qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); qchan->hdr.len = cpu_to_le16(sizeof(*qchan) - sizeof(struct qlink_tlv_hdr)); @@ -1794,9 +1792,7 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) pr_debug("MAC%u: scan chan=%d, freq=%d, flags=%#x\n", mac->macid, sc->hw_value, sc->center_freq, sc->flags); - qchan = (struct qlink_tlv_channel *) - skb_put(cmd_skb, sizeof(*qchan)); - memset(qchan, 0, sizeof(*qchan)); + qchan = skb_put_zero(cmd_skb, sizeof(*qchan)); flags = 0; qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index bdc379178e87..710e5b447cff 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1875,8 +1875,7 @@ static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, return NULL; skb_reserve(skb, hw->extra_tx_headroom); - action_frame = (void *)skb_put(skb, 27); - memset(action_frame, 0, 27); + action_frame = skb_put_zero(skb, 27); memcpy(action_frame->da, da, ETH_ALEN); memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN); memcpy(action_frame->bssid, bssid, ETH_ALEN); @@ -2005,8 +2004,7 @@ struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw, return NULL; skb_reserve(skb, hw->extra_tx_headroom); - action_frame = (void *)skb_put(skb, 34); - memset(action_frame, 0, 34); + action_frame = skb_put_zero(skb, 34); memcpy(action_frame->sa, sa, ETH_ALEN); memcpy(action_frame->da, rtlefuse->dev_addr, ETH_ALEN); memcpy(action_frame->bssid, bssid, ETH_ALEN); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 7f4da727bb7b..4a39fb13c478 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1233,8 +1233,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); - tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); - memset(tmpl, 0, sizeof(*tmpl)); + tmpl = skb_put_zero(skb, sizeof(*tmpl)); /* llc layer */ memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 382ec15ec1af..60aaa850fbd1 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1308,13 +1308,12 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); - hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); - memset(hdr, 0, sizeof(*hdr)); + hdr = skb_put_zero(skb, sizeof(*hdr)); hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS); - memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size); + skb_put_zero(skb, dummy_packet_size); /* Dummy packets require the TID to be management */ skb->priority = WL1271_TID_MGMT; diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 656463ff9ccb..e17bdb3adf9e 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -660,8 +660,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, if (op != ELS_LS_RJT) { dlen += sizeof(*mac); - mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac)); - memset(mac, 0, sizeof(*mac)); + mac = skb_put_zero(skb, sizeof(*mac)); mac->fd_desc.fip_dtype = FIP_DT_MAC; mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW; if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) { diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index d623d084b7ec..dbadbc81b24b 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c @@ -178,7 +178,7 @@ void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp, fill = -fr_len(fp) & 3; if (fill) { /* TODO, this may be a problem with fragmented skb */ - memset(skb_put(fp_skb(fp), fill), 0, fill); + skb_put_zero(fp_skb(fp), fill); f_ctl |= fill; } fr_eof(fp) = FC_EOF_T; diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 864819ff9a7d..2882c6d3ae66 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1004,8 +1004,7 @@ static struct sk_buff *package_for_tx(struct f_ncm *ncm) } /* Insert NDP alignment. */ - ntb_iter = (void *) skb_put(skb2, ndp_pad); - memset(ntb_iter, 0, ndp_pad); + ntb_iter = skb_put_zero(skb2, ndp_pad); /* Copy NTB across. */ ntb_iter = (void *) skb_put(skb2, ncm->skb_tx_ndp->len); @@ -1014,8 +1013,7 @@ static struct sk_buff *package_for_tx(struct f_ncm *ncm) ncm->skb_tx_ndp = NULL; /* Insert zero'd datagram. */ - ntb_iter = (void *) skb_put(skb2, dgram_idx_len); - memset(ntb_iter, 0, dgram_idx_len); + ntb_iter = skb_put_zero(skb2, dgram_idx_len); return skb2; } @@ -1080,8 +1078,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, goto err; ncm->skb_tx_data->dev = ncm->netdev; - ntb_data = (void *) skb_put(ncm->skb_tx_data, ncb_len); - memset(ntb_data, 0, ncb_len); + ntb_data = skb_put_zero(ncm->skb_tx_data, ncb_len); /* dwSignature */ put_unaligned_le32(opts->nth_sign, ntb_data); ntb_data += 2; @@ -1118,8 +1115,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, HRTIMER_MODE_REL); /* Add the datagram position entries */ - ntb_ndp = (void *) skb_put(ncm->skb_tx_ndp, dgram_idx_len); - memset(ntb_ndp, 0, dgram_idx_len); + ntb_ndp = skb_put_zero(ncm->skb_tx_ndp, dgram_idx_len); ncb_len = ncm->skb_tx_data->len; dgram_pad = ALIGN(ncb_len, div) + rem - ncb_len; @@ -1132,8 +1128,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, ncm->ndp_dgram_count++; /* Add the new data to the skb */ - ntb_data = (void *) skb_put(ncm->skb_tx_data, dgram_pad); - memset(ntb_data, 0, dgram_pad); + ntb_data = skb_put_zero(ncm->skb_tx_data, dgram_pad); ntb_data = (void *) skb_put(ncm->skb_tx_data, skb->len); memcpy(ntb_data, skb->data, skb->len); dev_consume_skb_any(skb); -- cgit v1.2.3 From 59ae1d127ac0ae404baf414c434ba2651b793f46 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Jun 2017 14:29:20 +0200 Subject: networking: introduce and use skb_put_data() A common pattern with skb_put() is to just want to memcpy() some data into the new space, introduce skb_put_data() for this. An spatch similar to the one for skb_put_zero() converts many of the places using it: @@ identifier p, p2; expression len, skb, data; type t, t2; @@ ( -p = skb_put(skb, len); +p = skb_put_data(skb, data, len); | -p = (t)skb_put(skb, len); +p = skb_put_data(skb, data, len); ) ( p2 = (t2)p; -memcpy(p2, data, len); | -memcpy(p, data, len); ) @@ type t, t2; identifier p, p2; expression skb, data; @@ t *p; ... ( -p = skb_put(skb, sizeof(t)); +p = skb_put_data(skb, data, sizeof(t)); | -p = (t *)skb_put(skb, sizeof(t)); +p = skb_put_data(skb, data, sizeof(t)); ) ( p2 = (t2)p; -memcpy(p2, data, sizeof(*p)); | -memcpy(p, data, sizeof(*p)); ) @@ expression skb, len, data; @@ -memcpy(skb_put(skb, len), data, len); +skb_put_data(skb, data, len); (again, manually post-processed to retain some comments) Reviewed-by: Stephen Hemminger Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 2 +- drivers/atm/he.c | 2 +- drivers/atm/idt77252.c | 11 ++---- drivers/atm/solos-pci.c | 2 +- drivers/bluetooth/bfusb.c | 6 +-- drivers/bluetooth/bluecard_cs.c | 2 +- drivers/bluetooth/btmrvl_main.c | 2 +- drivers/bluetooth/btqcomsmd.c | 2 +- drivers/bluetooth/btusb.c | 12 +++--- drivers/bluetooth/hci_bcsp.c | 16 ++++---- drivers/bluetooth/hci_h4.c | 2 +- drivers/bluetooth/hci_h5.c | 12 +++--- drivers/bluetooth/hci_intel.c | 7 ++-- drivers/bluetooth/hci_ll.c | 2 +- drivers/bluetooth/hci_mrvl.c | 2 +- drivers/bluetooth/hci_qca.c | 2 +- drivers/char/pcmcia/synclink_cs.c | 2 +- drivers/firewire/net.c | 2 +- drivers/isdn/capi/capi.c | 2 +- drivers/isdn/capi/capidrv.c | 2 +- drivers/isdn/hardware/avm/b1.c | 6 +-- drivers/isdn/hardware/avm/b1dma.c | 6 +-- drivers/isdn/hardware/avm/c4.c | 6 +-- drivers/isdn/hardware/avm/t1isa.c | 6 +-- drivers/isdn/hardware/mISDN/hfcmulti.c | 5 +-- drivers/isdn/hardware/mISDN/hfcsusb.c | 2 +- drivers/isdn/hisax/amd7930_fn.c | 3 +- drivers/isdn/hisax/avm_pci.c | 5 ++- drivers/isdn/hisax/diva.c | 6 ++- drivers/isdn/hisax/elsa_ser.c | 4 +- drivers/isdn/hisax/hfc_usb.c | 2 +- drivers/isdn/hisax/hisax_fcpcipnp.c | 3 +- drivers/isdn/hisax/hisax_isac.c | 4 +- drivers/isdn/hisax/hscx_irq.c | 6 ++- drivers/isdn/hisax/icc.c | 2 +- drivers/isdn/hisax/ipacx.c | 8 ++-- drivers/isdn/hisax/isac.c | 2 +- drivers/isdn/hisax/isar.c | 6 +-- drivers/isdn/hisax/isdnl2.c | 4 +- drivers/isdn/hisax/jade_irq.c | 6 ++- drivers/isdn/hisax/l3_1tr6.c | 8 ++-- drivers/isdn/hisax/l3dss1.c | 28 ++++++------- drivers/isdn/hisax/l3ni1.c | 32 +++++++-------- drivers/isdn/hisax/netjet.c | 2 +- drivers/isdn/hisax/st5481_usb.c | 2 +- drivers/isdn/hisax/w6692.c | 9 +++-- drivers/isdn/hysdn/hycapi.c | 31 +++++++-------- drivers/isdn/hysdn/hysdn_net.c | 2 +- drivers/isdn/i4l/isdn_ppp.c | 3 +- drivers/isdn/i4l/isdn_tty.c | 2 +- drivers/isdn/i4l/isdn_v110.c | 6 +-- drivers/isdn/isdnloop/isdnloop.c | 2 +- drivers/isdn/mISDN/dsp_cmx.c | 3 +- drivers/isdn/mISDN/layer2.c | 8 ++-- drivers/isdn/mISDN/tei.c | 2 +- drivers/media/dvb-core/dvb_net.c | 3 +- drivers/media/radio/wl128x/fmdrv_common.c | 2 +- drivers/misc/ti-st/st_core.c | 2 +- drivers/misc/ti-st/st_kim.c | 2 +- drivers/net/bonding/bond_alb.c | 3 +- drivers/net/caif/caif_hsi.c | 6 +-- drivers/net/caif/caif_serial.c | 3 +- drivers/net/caif/caif_spi.c | 3 +- drivers/net/caif/caif_virtio.c | 2 +- drivers/net/can/slcan.c | 3 +- drivers/net/ethernet/3com/3c515.c | 6 +-- drivers/net/ethernet/3com/3c59x.c | 5 +-- drivers/net/ethernet/aeroflex/greth.c | 3 +- drivers/net/ethernet/agere/et131x.c | 2 +- drivers/net/ethernet/apple/macmace.c | 2 +- drivers/net/ethernet/aurora/nb8800.c | 4 +- drivers/net/ethernet/cadence/macb.c | 2 +- .../net/ethernet/cavium/liquidio/octeon_network.h | 4 +- drivers/net/ethernet/cirrus/cs89x0.c | 7 ++-- drivers/net/ethernet/dec/tulip/de4x5.c | 6 +-- drivers/net/ethernet/dec/tulip/interrupt.c | 12 +++--- drivers/net/ethernet/dec/tulip/uli526x.c | 6 +-- drivers/net/ethernet/ec_bhf.c | 2 +- drivers/net/ethernet/fealnx.c | 4 +- drivers/net/ethernet/i825xx/82596.c | 3 +- drivers/net/ethernet/i825xx/lib82596.c | 3 +- drivers/net/ethernet/intel/e1000/e1000_main.c | 2 +- drivers/net/ethernet/marvell/mvneta.c | 10 ++--- drivers/net/ethernet/micrel/ksz884x.c | 3 +- drivers/net/ethernet/nxp/lpc_eth.c | 7 ++-- drivers/net/ethernet/qlogic/qede/qede_fp.c | 3 +- drivers/net/ethernet/qlogic/qlge/qlge_main.c | 7 ++-- drivers/net/ethernet/silan/sc92031.c | 10 ++--- drivers/net/fjes/fjes_main.c | 3 +- drivers/net/hamradio/mkiss.c | 2 +- drivers/net/hippi/rrunner.c | 4 +- drivers/net/hyperv/netvsc_drv.c | 2 +- drivers/net/ieee802154/at86rf230.c | 2 +- drivers/net/ieee802154/ca8210.c | 2 +- drivers/net/ieee802154/mrf24j40.c | 2 +- drivers/net/irda/smsc-ircc2.c | 2 +- drivers/net/irda/vlsi_ir.c | 2 +- drivers/net/ppp/ppp_async.c | 3 +- drivers/net/ppp/ppp_synctty.c | 3 +- drivers/net/slip/slip.c | 2 +- drivers/net/usb/asix_common.c | 4 +- drivers/net/usb/cdc-phonet.c | 2 +- drivers/net/usb/cdc_mbim.c | 2 +- drivers/net/usb/cdc_ncm.c | 6 +-- drivers/net/usb/gl620a.c | 3 +- drivers/net/usb/hso.c | 13 +++--- drivers/net/usb/ipheth.c | 2 +- drivers/net/usb/lg-vl600.c | 2 +- drivers/net/usb/qmi_wwan.c | 2 +- drivers/net/virtio_net.c | 2 +- drivers/net/wan/farsync.c | 2 +- drivers/net/wan/hdlc_ppp.c | 4 +- drivers/net/wan/x25_asy.c | 2 +- drivers/net/wimax/i2400m/netdev.c | 2 +- drivers/net/wireless/admtek/adm8211.c | 6 +-- drivers/net/wireless/ath/ath10k/mac.c | 5 +-- drivers/net/wireless/ath/ath10k/wmi.c | 5 +-- drivers/net/wireless/ath/ath9k/channel.c | 5 +-- drivers/net/wireless/ath/ath9k/wmi.c | 3 +- drivers/net/wireless/ath/carl9170/rx.c | 6 +-- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- drivers/net/wireless/atmel/atmel.c | 5 +-- drivers/net/wireless/broadcom/b43legacy/dma.c | 2 +- drivers/net/wireless/intel/ipw2x00/ipw2200.c | 5 ++- drivers/net/wireless/intel/ipw2x00/libipw_tx.c | 6 +-- drivers/net/wireless/intel/iwlegacy/3945.c | 2 +- drivers/net/wireless/intel/iwlegacy/4965-mac.c | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/rx.c | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/tx.c | 3 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 5 +-- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 5 +-- .../net/wireless/intersil/hostap/hostap_80211_tx.c | 2 +- drivers/net/wireless/intersil/hostap/hostap_ap.c | 2 +- drivers/net/wireless/intersil/hostap/hostap_hw.c | 11 +++--- drivers/net/wireless/intersil/hostap/hostap_main.c | 2 +- drivers/net/wireless/intersil/orinoco/main.c | 2 +- drivers/net/wireless/intersil/p54/p54spi.c | 4 +- drivers/net/wireless/intersil/p54/txrx.c | 5 ++- drivers/net/wireless/mac80211_hwsim.c | 5 +-- drivers/net/wireless/marvell/libertas/if_sdio.c | 4 +- drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 2 +- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 10 ++--- drivers/net/wireless/marvell/mwifiex/tdls.c | 8 ++-- drivers/net/wireless/mediatek/mt7601u/dma.c | 4 +- drivers/net/wireless/mediatek/mt7601u/mcu.c | 2 +- .../net/wireless/quantenna/qtnfmac/pearl/pcie.c | 2 +- .../net/wireless/quantenna/qtnfmac/qlink_util.h | 3 +- drivers/net/wireless/ralink/rt2x00/rt2x00debug.c | 5 +-- drivers/net/wireless/realtek/rtlwifi/pci.c | 3 +- .../net/wireless/realtek/rtlwifi/rtl8188ee/fw.c | 3 +- .../net/wireless/realtek/rtlwifi/rtl8192se/fw.c | 7 ++-- drivers/net/wireless/realtek/rtlwifi/usb.c | 2 +- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 8 ++-- drivers/net/wireless/st/cw1200/scan.c | 2 +- drivers/net/wireless/ti/wl1251/main.c | 2 +- drivers/net/wireless/ti/wlcore/cmd.c | 4 +- drivers/net/wireless/ti/wlcore/rx.c | 4 +- drivers/net/wireless/zydas/zd1201.c | 26 ++++++------ drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 2 +- drivers/nfc/fdp/fdp.c | 3 +- drivers/nfc/fdp/i2c.c | 2 +- drivers/nfc/nfcmrvl/fw_dnld.c | 7 ++-- drivers/nfc/nfcmrvl/i2c.c | 2 +- drivers/nfc/nfcmrvl/usb.c | 4 +- drivers/nfc/nxp-nci/firmware.c | 3 +- drivers/nfc/nxp-nci/i2c.c | 5 +-- drivers/nfc/pn533/pn533.c | 28 ++++++------- drivers/nfc/pn533/usb.c | 4 +- drivers/nfc/port100.c | 14 +++---- drivers/nfc/s3fwrn5/firmware.c | 4 +- drivers/nfc/s3fwrn5/i2c.c | 2 +- drivers/nfc/st21nfca/dep.c | 2 +- drivers/nfc/st21nfca/i2c.c | 2 +- drivers/rpmsg/rpmsg_char.c | 2 +- drivers/s390/net/ctcm_fsms.c | 7 ++-- drivers/s390/net/ctcm_main.c | 10 ++--- drivers/s390/net/ctcm_mpc.c | 46 +++++++++------------- drivers/s390/net/lcs.c | 2 +- drivers/s390/net/netiucv.c | 10 ++--- drivers/s390/net/qeth_core_main.c | 10 ++--- drivers/staging/gdm724x/gdm_lte.c | 25 +++++------- drivers/staging/ks7010/ks_hostif.c | 11 +++--- drivers/staging/most/aim-network/networking.c | 8 ++-- drivers/staging/octeon/ethernet-rx.c | 10 ++--- drivers/staging/rtl8188eu/core/rtw_recv.c | 4 +- drivers/staging/rtl8188eu/os_dep/mon.c | 2 +- drivers/staging/rtl8192e/rtllib_rx.c | 11 ++---- drivers/staging/rtl8192e/rtllib_softmac.c | 9 ++--- drivers/staging/rtl8192e/rtllib_tx.c | 12 ++---- drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c | 9 ++--- .../staging/rtl8192u/ieee80211/ieee80211_softmac.c | 3 +- drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c | 7 ++-- drivers/staging/rtl8192u/r819xU_cmdpkt.c | 3 +- drivers/staging/rtl8712/rtl8712_recv.c | 3 +- drivers/staging/rtl8723bs/os_dep/recv_linux.c | 4 +- drivers/staging/wilc1000/linux_mon.c | 6 +-- drivers/staging/wilc1000/linux_wlan.c | 2 +- drivers/staging/wlan-ng/hfa384x_usb.c | 6 +-- drivers/tty/ipwireless/network.c | 2 +- drivers/tty/n_gsm.c | 2 +- drivers/tty/synclink.c | 2 +- drivers/tty/synclink_gt.c | 2 +- drivers/tty/synclinkmp.c | 2 +- drivers/usb/gadget/function/f_ncm.c | 11 +++--- drivers/usb/gadget/function/f_phonet.c | 2 +- 208 files changed, 497 insertions(+), 586 deletions(-) (limited to 'drivers') diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 637c3e6b0f9e..7584ae1ded85 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -1104,7 +1104,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp /* Make device DMA transfer visible to CPU. */ fore200e->bus->dma_sync_for_cpu(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, DMA_FROM_DEVICE); - memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length); + skb_put_data(skb, buffer->data.align_addr, rpd->rsd[i].length); /* Now let the device get at it again. */ fore200e->bus->dma_sync_for_device(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, DMA_FROM_DEVICE); diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 3617659b9184..461da2bce8ef 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1735,7 +1735,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) __net_timestamp(skb); list_for_each_entry(heb, &he_vcc->buffers, entry) - memcpy(skb_put(skb, heb->len), &heb->data, heb->len); + skb_put_data(skb, &heb->data, heb->len); switch (vcc->qos.aal) { case ATM_AAL0: diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 5ec109533bb9..4e64de380bda 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -1090,8 +1090,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) *((u32 *) sb->data) = aal0; skb_put(sb, sizeof(u32)); - memcpy(skb_put(sb, ATM_CELL_PAYLOAD), - cell, ATM_CELL_PAYLOAD); + skb_put_data(sb, cell, ATM_CELL_PAYLOAD); ATM_SKB(sb)->vcc = vcc; __net_timestamp(sb); @@ -1159,8 +1158,7 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) return; } skb_queue_walk(&rpp->queue, sb) - memcpy(skb_put(skb, sb->len), - sb->data, sb->len); + skb_put_data(skb, sb->data, sb->len); recycle_rx_pool_skb(card, rpp); @@ -1322,8 +1320,7 @@ idt77252_rx_raw(struct idt77252_dev *card) *((u32 *) sb->data) = header; skb_put(sb, sizeof(u32)); - memcpy(skb_put(sb, ATM_CELL_PAYLOAD), &(queue->data[16]), - ATM_CELL_PAYLOAD); + skb_put_data(sb, &(queue->data[16]), ATM_CELL_PAYLOAD); ATM_SKB(sb)->vcc = vcc; __net_timestamp(sb); @@ -2014,7 +2011,7 @@ idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags) } atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); - memcpy(skb_put(skb, 52), cell, 52); + skb_put_data(skb, cell, 52); return idt77252_send_skb(vcc, skb, 1); } diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 9115b292e680..077dd15c3a40 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -493,7 +493,7 @@ static int send_command(struct solos_card *card, int dev, const char *buf, size_ header->vci = cpu_to_le16(0); header->type = cpu_to_le16(PKT_COMMAND); - memcpy(skb_put(skb, size), buf, size); + skb_put_data(skb, buf, size); fpga_queue(card, dev, skb, NULL); diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 3bf4ec60e073..ab090a313a5f 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -335,7 +335,7 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch } if (len > 0) - memcpy(skb_put(data->reassembly, len), buf, len); + skb_put_data(data->reassembly, buf, len); if (hdr & 0x08) { hci_recv_frame(data->hdev, data->reassembly); @@ -505,7 +505,7 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) buf[1] = 0x00; buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size; - memcpy(skb_put(nskb, 3), buf, 3); + skb_put_data(nskb, buf, 3); skb_copy_from_linear_data_offset(skb, sent, skb_put(nskb, size), size); sent += size; @@ -516,7 +516,7 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) if ((nskb->len % data->bulk_pkt_size) == 0) { buf[0] = 0xdd; buf[1] = 0x00; - memcpy(skb_put(nskb, 2), buf, 2); + skb_put_data(nskb, buf, 2); } read_lock(&data->lock); diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 007c0a45f31b..1d30c116b2ee 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -597,7 +597,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) break; } - memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); + skb_put_data(skb, cmd, sizeof(cmd)); skb_queue_tail(&(info->txq), skb); diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index c38cb5b91291..24a188eab360 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -194,7 +194,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode, hdr->plen = len; if (len) - memcpy(skb_put(skb, len), param, len); + skb_put_data(skb, param, len); hci_skb_pkt_type(skb) = MRVL_VENDOR_PKT; diff --git a/drivers/bluetooth/btqcomsmd.c b/drivers/bluetooth/btqcomsmd.c index ef730c173d4b..d00c4fdae924 100644 --- a/drivers/bluetooth/btqcomsmd.c +++ b/drivers/bluetooth/btqcomsmd.c @@ -43,7 +43,7 @@ static int btqcomsmd_recv(struct hci_dev *hdev, unsigned int type, } hci_skb_pkt_type(skb) = type; - memcpy(skb_put(skb, count), data, count); + skb_put_data(skb, data, count); return hci_recv_frame(hdev, skb); } diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index bfd5f4bdec80..c7ea398e65c1 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -478,7 +478,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count) } len = min_t(uint, hci_skb_expect(skb), count); - memcpy(skb_put(skb, len), buffer, len); + skb_put_data(skb, buffer, len); count -= len; buffer += len; @@ -533,7 +533,7 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count) } len = min_t(uint, hci_skb_expect(skb), count); - memcpy(skb_put(skb, len), buffer, len); + skb_put_data(skb, buffer, len); count -= len; buffer += len; @@ -590,7 +590,7 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count) } len = min_t(uint, hci_skb_expect(skb), count); - memcpy(skb_put(skb, len), buffer, len); + skb_put_data(skb, buffer, len); count -= len; buffer += len; @@ -934,8 +934,8 @@ static void btusb_diag_complete(struct urb *urb) skb = bt_skb_alloc(urb->actual_length, GFP_ATOMIC); if (skb) { - memcpy(skb_put(skb, urb->actual_length), - urb->transfer_buffer, urb->actual_length); + skb_put_data(skb, urb->transfer_buffer, + urb->actual_length); hci_recv_diag(hdev, skb); } } else if (urb->status == -ENOENT) { @@ -2395,7 +2395,7 @@ static int marvell_config_oob_wake(struct hci_dev *hdev) return -ENOMEM; } - memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); + skb_put_data(skb, cmd, sizeof(cmd)); hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; ret = btusb_send_frame(hdev, skb); diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 910ec968f022..d880f4e33c75 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -125,7 +125,7 @@ static void bcsp_slip_msgdelim(struct sk_buff *skb) { const char pkt_delim = 0xc0; - memcpy(skb_put(skb, 1), &pkt_delim, 1); + skb_put_data(skb, &pkt_delim, 1); } static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c) @@ -135,13 +135,13 @@ static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c) switch (c) { case 0xc0: - memcpy(skb_put(skb, 2), &esc_c0, 2); + skb_put_data(skb, &esc_c0, 2); break; case 0xdb: - memcpy(skb_put(skb, 2), &esc_db, 2); + skb_put_data(skb, &esc_db, 2); break; default: - memcpy(skb_put(skb, 1), &c, 1); + skb_put_data(skb, &c, 1); } } @@ -423,7 +423,7 @@ static void bcsp_handle_le_pkt(struct hci_uart *hu) BT_DBG("Found a LE conf pkt"); if (!nskb) return; - memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4); + skb_put_data(nskb, conf_rsp_pkt, 4); hci_skb_pkt_type(nskb) = BCSP_LE_PKT; skb_queue_head(&bcsp->unrel, nskb); @@ -447,7 +447,7 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char bcsp->rx_esc_state = BCSP_ESCSTATE_ESC; break; default: - memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1); + skb_put_data(bcsp->rx_skb, &byte, 1); if ((bcsp->rx_skb->data[0] & 0x40) != 0 && bcsp->rx_state != BCSP_W4_CRC) bcsp_crc_update(&bcsp->message_crc, byte); @@ -458,7 +458,7 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char case BCSP_ESCSTATE_ESC: switch (byte) { case 0xdc: - memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1); + skb_put_data(bcsp->rx_skb, &c0, 1); if ((bcsp->rx_skb->data[0] & 0x40) != 0 && bcsp->rx_state != BCSP_W4_CRC) bcsp_crc_update(&bcsp->message_crc, 0xc0); @@ -467,7 +467,7 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char break; case 0xdd: - memcpy(skb_put(bcsp->rx_skb, 1), &db, 1); + skb_put_data(bcsp->rx_skb, &db, 1); if ((bcsp->rx_skb->data[0] & 0x40) != 0 && bcsp->rx_state != BCSP_W4_CRC) bcsp_crc_update(&bcsp->message_crc, 0xdb); diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 82e5a32b87a4..4e328d7d47bb 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -209,7 +209,7 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, } len = min_t(uint, hci_skb_expect(skb) - skb->len, count); - memcpy(skb_put(skb, len), buffer, len); + skb_put_data(skb, buffer, len); count -= len; buffer += len; diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 90d0456b6744..c0e4e26dc30d 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -109,7 +109,7 @@ static void h5_link_control(struct hci_uart *hu, const void *data, size_t len) hci_skb_pkt_type(nskb) = HCI_3WIRE_LINK_PKT; - memcpy(skb_put(nskb, len), data, len); + skb_put_data(nskb, data, len); skb_queue_tail(&h5->unrel, nskb); } @@ -487,7 +487,7 @@ static void h5_unslip_one_byte(struct h5 *h5, unsigned char c) } } - memcpy(skb_put(h5->rx_skb, 1), byte, 1); + skb_put_data(h5->rx_skb, byte, 1); h5->rx_pending--; BT_DBG("unsliped 0x%02hhx, rx_pending %zu", *byte, h5->rx_pending); @@ -579,7 +579,7 @@ static void h5_slip_delim(struct sk_buff *skb) { const char delim = SLIP_DELIMITER; - memcpy(skb_put(skb, 1), &delim, 1); + skb_put_data(skb, &delim, 1); } static void h5_slip_one_byte(struct sk_buff *skb, u8 c) @@ -589,13 +589,13 @@ static void h5_slip_one_byte(struct sk_buff *skb, u8 c) switch (c) { case SLIP_DELIMITER: - memcpy(skb_put(skb, 2), &esc_delim, 2); + skb_put_data(skb, &esc_delim, 2); break; case SLIP_ESC: - memcpy(skb_put(skb, 2), &esc_esc, 2); + skb_put_data(skb, &esc_esc, 2); break; default: - memcpy(skb_put(skb, 1), &c, 1); + skb_put_data(skb, &c, 1); } } diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 851bee82df2a..16e728577cd8 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -185,7 +185,7 @@ static int intel_lpm_suspend(struct hci_uart *hu) return -ENOMEM; } - memcpy(skb_put(skb, sizeof(suspend)), suspend, sizeof(suspend)); + skb_put_data(skb, suspend, sizeof(suspend)); hci_skb_pkt_type(skb) = HCI_LPM_PKT; set_bit(STATE_LPM_TRANSACTION, &intel->flags); @@ -270,8 +270,7 @@ static int intel_lpm_host_wake(struct hci_uart *hu) return -ENOMEM; } - memcpy(skb_put(skb, sizeof(lpm_resume_ack)), lpm_resume_ack, - sizeof(lpm_resume_ack)); + skb_put_data(skb, lpm_resume_ack, sizeof(lpm_resume_ack)); hci_skb_pkt_type(skb) = HCI_LPM_PKT; /* LPM flow is a priority, enqueue packet at list head */ @@ -522,7 +521,7 @@ static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed) return -ENOMEM; } - memcpy(skb_put(skb, sizeof(speed_cmd)), speed_cmd, sizeof(speed_cmd)); + skb_put_data(skb, speed_cmd, sizeof(speed_cmd)); hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; hci_uart_set_flow_control(hu, true); diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 2b16d48d82ee..cc2fa78b434e 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -413,7 +413,7 @@ static int ll_recv(struct hci_uart *hu, const void *data, int count) while (count) { if (ll->rx_count) { len = min_t(unsigned int, ll->rx_count, count); - memcpy(skb_put(ll->rx_skb, len), ptr, len); + skb_put_data(ll->rx_skb, ptr, len); ll->rx_count -= len; count -= len; ptr += len; if (ll->rx_count) diff --git a/drivers/bluetooth/hci_mrvl.c b/drivers/bluetooth/hci_mrvl.c index bbc4b39b1dbf..ffb00669346f 100644 --- a/drivers/bluetooth/hci_mrvl.c +++ b/drivers/bluetooth/hci_mrvl.c @@ -328,7 +328,7 @@ static int mrvl_load_firmware(struct hci_dev *hdev, const char *name) } bt_cb(skb)->pkt_type = MRVL_RAW_DATA; - memcpy(skb_put(skb, mrvl->tx_len), fw_ptr, mrvl->tx_len); + skb_put_data(skb, fw_ptr, mrvl->tx_len); fw_ptr += mrvl->tx_len; set_bit(STATE_FW_REQ_PENDING, &mrvl->flags); diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index f242dfd0c2e2..b55f01320631 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -869,7 +869,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) } /* Assign commands to change baudrate and packet type. */ - memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); + skb_put_data(skb, cmd, sizeof(cmd)); hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; skb_queue_tail(&qca->txq, skb); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index d136db1a10f0..62be953e5fb0 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -4235,7 +4235,7 @@ static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size) return; } - memcpy(skb_put(skb, size), buf, size); + skb_put_data(skb, buf, size); skb->protocol = hdlc_type_trans(skb, dev); diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 5d3640264f2d..d5040bbd34e8 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -600,7 +600,7 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, return -ENOMEM; } skb_reserve(skb, LL_RESERVED_SPACE(net)); - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); return fwnet_finish_incoming_packet(net, skb, source_node_id, is_broadcast, ether_type); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 6a2df3297e77..77be17590866 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1058,7 +1058,7 @@ static int capinc_tty_write(struct tty_struct *tty, } skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); - memcpy(skb_put(skb, count), buf, count); + skb_put_data(skb, buf, count); __skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 85cfa4f8691f..89dd1303a98a 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -516,7 +516,7 @@ static void send_message(capidrv_contr *card, _cmsg *cmsg) printk(KERN_ERR "capidrv::send_message: can't allocate mem\n"); return; } - memcpy(skb_put(skb, len), cmsg->buf, len); + skb_put_data(skb, cmsg->buf, len); if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR) kfree_skb(skb); } diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 9fdbd99c7547..b1833d08a5fe 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -529,8 +529,8 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr) printk(KERN_ERR "%s: incoming packet dropped\n", card->name); } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); - memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + skb_put_data(skb, card->msgbuf, MsgLen); + skb_put_data(skb, card->databuf, DataB3Len); capi_ctr_handle_message(ctrl, ApplId, skb); } break; @@ -544,7 +544,7 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr) card->name); spin_unlock_irqrestore(&card->lock, flags); } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + skb_put_data(skb, card->msgbuf, MsgLen); if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) capilib_data_b3_conf(&cinfo->ncci_head, ApplId, CAPIMSG_NCCI(skb->data), diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 818bd8f231db..9538a9e5e1a8 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -474,8 +474,8 @@ static void b1dma_handle_rx(avmcard *card) printk(KERN_ERR "%s: incoming packet dropped\n", card->name); } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); - memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + skb_put_data(skb, card->msgbuf, MsgLen); + skb_put_data(skb, card->databuf, DataB3Len); capi_ctr_handle_message(ctrl, ApplId, skb); } break; @@ -488,7 +488,7 @@ static void b1dma_handle_rx(avmcard *card) printk(KERN_ERR "%s: incoming packet dropped\n", card->name); } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + skb_put_data(skb, card->msgbuf, MsgLen); if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) { spin_lock(&card->lock); capilib_data_b3_conf(&cinfo->ncci_head, ApplId, diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 17beb2869dc1..40c7e2cf423b 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -536,8 +536,8 @@ static void c4_handle_rx(avmcard *card) printk(KERN_ERR "%s: incoming packet dropped\n", card->name); } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); - memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + skb_put_data(skb, card->msgbuf, MsgLen); + skb_put_data(skb, card->databuf, DataB3Len); capi_ctr_handle_message(ctrl, ApplId, skb); } break; @@ -555,7 +555,7 @@ static void c4_handle_rx(avmcard *card) printk(KERN_ERR "%s: incoming packet dropped\n", card->name); } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + skb_put_data(skb, card->msgbuf, MsgLen); if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) capilib_data_b3_conf(&cinfo->ncci_head, ApplId, CAPIMSG_NCCI(skb->data), diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index 9516203c735f..9f80d20ced87 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -171,8 +171,8 @@ static irqreturn_t t1isa_interrupt(int interrupt, void *devptr) printk(KERN_ERR "%s: incoming packet dropped\n", card->name); } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); - memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + skb_put_data(skb, card->msgbuf, MsgLen); + skb_put_data(skb, card->databuf, DataB3Len); capi_ctr_handle_message(ctrl, ApplId, skb); } break; @@ -186,7 +186,7 @@ static irqreturn_t t1isa_interrupt(int interrupt, void *devptr) printk(KERN_ERR "%s: incoming packet dropped\n", card->name); } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + skb_put_data(skb, card->msgbuf, MsgLen); if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3) capilib_data_b3_conf(&cinfo->ncci_head, ApplId, CAPIMSG_NCCI(skb->data), diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 961c07ee47b7..aea0c9616ea5 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -1926,7 +1926,7 @@ hfcmulti_dtmf(struct hfc_multi *hc) hh = mISDN_HEAD_P(skb); hh->prim = PH_CONTROL_IND; hh->id = DTMF_HFC_COEF; - memcpy(skb_put(skb, 512), hc->chan[ch].coeff, 512); + skb_put_data(skb, hc->chan[ch].coeff, 512); recv_Bchannel_skb(bch, skb); } } @@ -2332,8 +2332,7 @@ next_frame: skb = *sp; *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); if (*sp) { - memcpy(skb_put(*sp, skb->len), - skb->data, skb->len); + skb_put_data(*sp, skb->data, skb->len); skb_trim(skb, 0); } else { printk(KERN_DEBUG "%s: No mem\n", diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 114f3bcba1b0..17cc879ad2bb 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -893,7 +893,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, } } - memcpy(skb_put(rx_skb, len), data, len); + skb_put_data(rx_skb, data, len); if (hdlc) { /* we have a complete hdlc packet */ diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index 3a4c2f9e19e9..dcf4c2a9fcea 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -317,7 +317,8 @@ Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag) debugl1(cs, "%s", cs->dlog); } /* moves received data in sk-buffer */ - memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx); + skb_put_data(skb, cs->rcvbuf, + cs->rcvidx); skb_queue_tail(&cs->rq, skb); } } diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index d1427bd6452d..daf3742cdef6 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -378,8 +378,9 @@ HDLC_irq(struct BCState *bcs, u_int stat) { if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx))) printk(KERN_WARNING "HDLC: receive out of memory\n"); else { - memcpy(skb_put(skb, bcs->hw.hdlc.rcvidx), - bcs->hw.hdlc.rcvbuf, bcs->hw.hdlc.rcvidx); + skb_put_data(skb, + bcs->hw.hdlc.rcvbuf, + bcs->hw.hdlc.rcvidx); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.hdlc.rcvidx = 0; diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 079336e593f9..3fc94e7741ae 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -511,7 +511,8 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HSCX: receive out of memory\n"); else { - memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_put_data(skb, bcs->hw.hscx.rcvbuf, + count); skb_queue_tail(&bcs->rqueue, skb); } } @@ -526,7 +527,8 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) if (!(skb = dev_alloc_skb(fifo_size))) printk(KERN_WARNING "HiSax: receive out of memory\n"); else { - memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); + skb_put_data(skb, bcs->hw.hscx.rcvbuf, + fifo_size); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.hscx.rcvidx = 0; diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index a2a358c1dc8e..999effd7a276 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -333,8 +333,8 @@ static inline void receive_chars(struct IsdnCardState *cs, if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt))) printk(KERN_WARNING "ElsaSER: receive out of memory\n"); else { - memcpy(skb_put(skb, cs->hw.elsa.rcvcnt), cs->hw.elsa.rcvbuf, - cs->hw.elsa.rcvcnt); + skb_put_data(skb, cs->hw.elsa.rcvbuf, + cs->hw.elsa.rcvcnt); skb_queue_tail(&cs->hw.elsa.bcs->rqueue, skb); } schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY); diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 6dbd1f1da14f..ef4748083efd 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -799,7 +799,7 @@ collect_rx_frame(usb_fifo *fifo, __u8 *data, int len, int finish) } if (len) { if (fifo->skbuff->len + len < fifo->max_size) { - memcpy(skb_put(fifo->skbuff, len), data, len); + skb_put_data(fifo->skbuff, data, len); } else { DBG(HFCUSB_DBG_FIFO_ERR, "HCF-USB: got frame exceeded fifo->max_size(%d) fifo(%d)", diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c index 5e8a5d967162..5a9f39ed1d5d 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c @@ -495,8 +495,7 @@ static inline void hdlc_rpr_irq(struct fritz_bcs *bcs, u32 stat) if (!skb) { printk(KERN_WARNING "HDLC: receive out of memory\n"); } else { - memcpy(skb_put(skb, bcs->rcvidx), bcs->rcvbuf, - bcs->rcvidx); + skb_put_data(skb, bcs->rcvbuf, bcs->rcvidx); DBG_SKB(1, skb); B_L1L2(bcs, PH_DATA | INDICATION, skb); } diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c index 5154c252a25f..0f36375478c5 100644 --- a/drivers/isdn/hisax/hisax_isac.c +++ b/drivers/isdn/hisax/hisax_isac.c @@ -557,7 +557,7 @@ static inline void isac_rme_interrupt(struct isac *isac) DBG(DBG_WARN, "no memory, dropping\n"); goto out; } - memcpy(skb_put(skb, count), isac->rcvbuf, count); + skb_put_data(skb, isac->rcvbuf, count); DBG_SKB(DBG_RPACKET, skb); D_L1L2(isac, PH_DATA | INDICATION, skb); out: @@ -687,7 +687,7 @@ static inline void isacsx_rme_interrupt(struct isac *isac) DBG(DBG_WARN, "no memory, dropping"); goto out; } - memcpy(skb_put(skb, count), isac->rcvbuf, count); + skb_put_data(skb, isac->rcvbuf, count); DBG_SKB(DBG_RPACKET, skb); D_L1L2(isac, PH_DATA | INDICATION, skb); out: diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c index a8d6188402c6..0d7e783c8bef 100644 --- a/drivers/isdn/hisax/hscx_irq.c +++ b/drivers/isdn/hisax/hscx_irq.c @@ -169,7 +169,8 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HSCX: receive out of memory\n"); else { - memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_put_data(skb, bcs->hw.hscx.rcvbuf, + count); skb_queue_tail(&bcs->rqueue, skb); } } @@ -184,7 +185,8 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) if (!(skb = dev_alloc_skb(fifo_size))) printk(KERN_WARNING "HiSax: receive out of memory\n"); else { - memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); + skb_put_data(skb, bcs->hw.hscx.rcvbuf, + fifo_size); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.hscx.rcvidx = 0; diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index c7c3797a817e..8d1804572b32 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -217,7 +217,7 @@ icc_interrupt(struct IsdnCardState *cs, u_char val) if (!(skb = alloc_skb(count, GFP_ATOMIC))) printk(KERN_WARNING "HiSax: D receive out of memory\n"); else { - memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_put_data(skb, cs->rcvbuf, count); skb_queue_tail(&cs->rq, skb); } } diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c index 43effe7082ed..c426b4fea28a 100644 --- a/drivers/isdn/hisax/ipacx.c +++ b/drivers/isdn/hisax/ipacx.c @@ -350,7 +350,7 @@ dch_int(struct IsdnCardState *cs) if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n"); else { - memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_put_data(skb, cs->rcvbuf, count); skb_queue_tail(&cs->rq, skb); } } @@ -627,7 +627,8 @@ bch_int(struct IsdnCardState *cs, u_char hscx) if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n"); else { - memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_put_data(skb, bcs->hw.hscx.rcvbuf, + count); skb_queue_tail(&bcs->rqueue, skb); } } @@ -644,7 +645,8 @@ bch_int(struct IsdnCardState *cs, u_char hscx) if (!(skb = dev_alloc_skb(B_FIFO_SIZE))) printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n"); else { - memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, B_FIFO_SIZE); + skb_put_data(skb, bcs->hw.hscx.rcvbuf, + B_FIFO_SIZE); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.hscx.rcvidx = 0; diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 4273b4548825..ea965f29a555 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -222,7 +222,7 @@ isac_interrupt(struct IsdnCardState *cs, u_char val) if (!skb) printk(KERN_WARNING "HiSax: D receive out of memory\n"); else { - memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_put_data(skb, cs->rcvbuf, count); skb_queue_tail(&cs->rq, skb); } } diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 0dc60b287c4b..98b4b67ea337 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -458,7 +458,7 @@ send_DLE_ETX(struct BCState *bcs) struct sk_buff *skb; if ((skb = dev_alloc_skb(2))) { - memcpy(skb_put(skb, 2), dleetx, 2); + skb_put_data(skb, dleetx, 2); skb_queue_tail(&bcs->rqueue, skb); schedule_event(bcs, B_RCVBUFREADY); } else { @@ -550,8 +550,8 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx - 2))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { - memcpy(skb_put(skb, bcs->hw.isar.rcvidx - 2), - bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx - 2); + skb_put_data(skb, bcs->hw.isar.rcvbuf, + bcs->hw.isar.rcvidx - 2); skb_queue_tail(&bcs->rqueue, skb); schedule_event(bcs, B_RCVBUFREADY); } diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index c53a53f6efb6..1a40ed04cb52 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -433,7 +433,7 @@ send_uframe(struct PStack *st, u_char cmd, u_char cr) printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n"); return; } - memcpy(skb_put(skb, i), tmp, i); + skb_put_data(skb, tmp, i); enqueue_super(st, skb); } @@ -894,7 +894,7 @@ enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf) printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n"); return; } - memcpy(skb_put(skb, i), tmp, i); + skb_put_data(skb, tmp, i); enqueue_super(st, skb); } diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c index b930da9b5aa6..a89e2df911c5 100644 --- a/drivers/isdn/hisax/jade_irq.c +++ b/drivers/isdn/hisax/jade_irq.c @@ -147,7 +147,8 @@ jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B" : "A")); else { - memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_put_data(skb, bcs->hw.hscx.rcvbuf, + count); skb_queue_tail(&bcs->rqueue, skb); } } @@ -162,7 +163,8 @@ jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) if (!(skb = dev_alloc_skb(fifo_size))) printk(KERN_WARNING "HiSax: receive out of memory\n"); else { - memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); + skb_put_data(skb, bcs->hw.hscx.rcvbuf, + fifo_size); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.hscx.rcvidx = 0; diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index 875402e76d0a..da0a1c6aa329 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c @@ -149,7 +149,7 @@ l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T303, CC_T303); newl3state(pc, 1); @@ -497,7 +497,7 @@ l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T313, CC_T313); @@ -543,7 +543,7 @@ l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T305, CC_T305); } @@ -602,7 +602,7 @@ l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T308, CC_T308_1); } diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index cda700664e9c..18a3484b1f7e 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -525,7 +525,7 @@ l3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); } @@ -551,7 +551,7 @@ l3dss1_status_send(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); } @@ -587,7 +587,7 @@ l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); dss1_release_l3_process(pc); } @@ -944,7 +944,7 @@ l3dss1_msg_with_uus(struct l3_process *pc, u_char cmd) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); } /* l3dss1_msg_with_uus */ @@ -1420,7 +1420,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr, l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T303, CC_T303); newl3state(pc, 1); @@ -1786,7 +1786,7 @@ l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); newl3state(pc, 11); l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T305, CC_T305); @@ -1848,7 +1848,7 @@ l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); @@ -2145,7 +2145,7 @@ static void l3dss1_redir_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); } /* l3dss1_redir_req */ @@ -2216,7 +2216,7 @@ static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic) if (pc) dss1_release_l3_process(pc); return (-2); } - memcpy(skb_put(skb, l), temp, l); + skb_put_data(skb, temp, l); if (pc) { pc->prot.dss1.invoke_id = id; /* remember id */ @@ -2359,7 +2359,7 @@ l3dss1_t305(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); newl3state(pc, 19); l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T308, CC_T308_1); @@ -2528,7 +2528,7 @@ l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); newl3state(pc, 15); L3AddTimer(&pc->timer, T319, CC_T319); @@ -2603,7 +2603,7 @@ l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); newl3state(pc, 17); L3AddTimer(&pc->timer, T318, CC_T318); @@ -2721,7 +2721,7 @@ l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); newl3state(pc, 0); l3_msg(pc->st, DL_DATA | REQUEST, skb); } @@ -2929,7 +2929,7 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(proc->st, DL_DATA | REQUEST, skb); } else { if (st->l3.debug & L3_DEB_STATE) { diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c index 8dc791bfaa6f..ea311e7df48e 100644 --- a/drivers/isdn/hisax/l3ni1.c +++ b/drivers/isdn/hisax/l3ni1.c @@ -454,7 +454,7 @@ l3ni1_message_plus_chid(struct l3_process *pc, u_char mt) if (!(skb = l3_alloc_skb(7))) return; - memcpy(skb_put(skb, 7), tmp, 7); + skb_put_data(skb, tmp, 7); l3_msg(pc->st, DL_DATA | REQUEST, skb); } @@ -475,7 +475,7 @@ l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); } @@ -501,7 +501,7 @@ l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); } @@ -537,7 +537,7 @@ l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); ni1_release_l3_process(pc); } @@ -894,7 +894,7 @@ l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); } /* l3ni1_msg_with_uus */ @@ -1274,7 +1274,7 @@ l3ni1_setup_req(struct l3_process *pc, u_char pr, { return; } - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T303, CC_T303); newl3state(pc, 1); @@ -1640,7 +1640,7 @@ l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); newl3state(pc, 11); l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T305, CC_T305); @@ -1704,7 +1704,7 @@ l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); @@ -2001,7 +2001,7 @@ static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); } /* l3ni1_redir_req */ @@ -2076,7 +2076,7 @@ static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) if (pc) ni1_release_l3_process(pc); return (-2); } - memcpy(skb_put(skb, l), temp, l); + skb_put_data(skb, temp, l); if (pc) { pc->prot.ni1.invoke_id = id; /* remember id */ @@ -2219,7 +2219,7 @@ l3ni1_t305(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); newl3state(pc, 19); l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T308, CC_T308_1); @@ -2388,7 +2388,7 @@ l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); newl3state(pc, 15); L3AddTimer(&pc->timer, T319, CC_T319); @@ -2463,7 +2463,7 @@ l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(pc->st, DL_DATA | REQUEST, skb); newl3state(pc, 17); L3AddTimer(&pc->timer, T318, CC_T318); @@ -2582,7 +2582,7 @@ l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); newl3state(pc, 0); l3_msg(pc->st, DL_DATA | REQUEST, skb); } @@ -2655,7 +2655,7 @@ static void l3ni1_SendSpid(struct l3_process *pc, u_char pr, struct sk_buff *skb *p++ = IE_SPID; *p++ = l; - memcpy(skb_put(skb, l), pSPID, l); + skb_put_data(skb, pSPID, l); newl3state(pc, iNewState); @@ -2873,7 +2873,7 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; - memcpy(skb_put(skb, l), tmp, l); + skb_put_data(skb, tmp, l); l3_msg(proc->st, DL_DATA | REQUEST, skb); } else { if (st->l3.debug & L3_DEB_STATE) { diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index 233e432e06f6..b7f54fa29228 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -383,7 +383,7 @@ static void got_frame(struct BCState *bcs, int count) { if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "TIGER: receive out of memory\n"); else { - memcpy(skb_put(skb, count), bcs->hw.tiger.rcvbuf, count); + skb_put_data(skb, bcs->hw.tiger.rcvbuf, count); skb_queue_tail(&bcs->rqueue, skb); } test_and_set_bit(B_RCVBUFREADY, &bcs->event); diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index a0fdbc074b98..1cb9930d5e24 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -527,7 +527,7 @@ static void usb_in_complete(struct urb *urb) WARNING("receive out of memory\n"); break; } - memcpy(skb_put(skb, status), in->rcvbuf, status); + skb_put_data(skb, in->rcvbuf, status); in->hisax_if->l1l2(in->hisax_if, PH_DATA | INDICATION, skb); } else if (status == -HDLC_CRC_ERROR) { INFO("CRC error"); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index c99f0ec58a01..6f6733b7c1e4 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -309,7 +309,9 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "W6692: Bchan receive out of memory\n"); else { - memcpy(skb_put(skb, count), bcs->hw.w6692.rcvbuf, count); + skb_put_data(skb, + bcs->hw.w6692.rcvbuf, + count); skb_queue_tail(&bcs->rqueue, skb); } } @@ -332,7 +334,8 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH))) printk(KERN_WARNING "HiSax: receive out of memory\n"); else { - memcpy(skb_put(skb, W_B_FIFO_THRESH), bcs->hw.w6692.rcvbuf, W_B_FIFO_THRESH); + skb_put_data(skb, bcs->hw.w6692.rcvbuf, + W_B_FIFO_THRESH); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.w6692.rcvidx = 0; @@ -441,7 +444,7 @@ StartW6692: if (!(skb = alloc_skb(count, GFP_ATOMIC))) printk(KERN_WARNING "HiSax: D receive out of memory\n"); else { - memcpy(skb_put(skb, count), cs->rcvbuf, count); + skb_put_data(skb, cs->rcvbuf, count); skb_queue_tail(&cs->rq, skb); } } diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index 93bae94314a6..87119b517508 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -171,16 +171,16 @@ hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl, card->myid); return; } - memcpy(skb_put(skb, sizeof(__u16)), &len, sizeof(__u16)); - memcpy(skb_put(skb, sizeof(__u16)), &appl, sizeof(__u16)); + skb_put_data(skb, &len, sizeof(__u16)); + skb_put_data(skb, &appl, sizeof(__u16)); memcpy(skb_put(skb, sizeof(__u8)), &_command, sizeof(_command)); memcpy(skb_put(skb, sizeof(__u8)), &_subcommand, sizeof(_subcommand)); - memcpy(skb_put(skb, sizeof(__u16)), &MessageNumber, sizeof(__u16)); - memcpy(skb_put(skb, sizeof(__u16)), &MessageBufferSize, sizeof(__u16)); - memcpy(skb_put(skb, sizeof(__u16)), &(rp->level3cnt), sizeof(__u16)); - memcpy(skb_put(skb, sizeof(__u16)), &(rp->datablkcnt), sizeof(__u16)); - memcpy(skb_put(skb, sizeof(__u16)), &(rp->datablklen), sizeof(__u16)); - memcpy(skb_put(skb, slen), ExtFeatureDefaults, slen); + skb_put_data(skb, &MessageNumber, sizeof(__u16)); + skb_put_data(skb, &MessageBufferSize, sizeof(__u16)); + skb_put_data(skb, &(rp->level3cnt), sizeof(__u16)); + skb_put_data(skb, &(rp->datablkcnt), sizeof(__u16)); + skb_put_data(skb, &(rp->datablklen), sizeof(__u16)); + skb_put_data(skb, ExtFeatureDefaults, slen); hycapi_applications[appl - 1].ctrl_mask |= (1 << (ctrl->cnr - 1)); hycapi_send_message(ctrl, skb); } @@ -279,11 +279,11 @@ static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl) card->myid); return; } - memcpy(skb_put(skb, sizeof(__u16)), &len, sizeof(__u16)); - memcpy(skb_put(skb, sizeof(__u16)), &appl, sizeof(__u16)); + skb_put_data(skb, &len, sizeof(__u16)); + skb_put_data(skb, &appl, sizeof(__u16)); memcpy(skb_put(skb, sizeof(__u8)), &_command, sizeof(_command)); memcpy(skb_put(skb, sizeof(__u8)), &_subcommand, sizeof(_subcommand)); - memcpy(skb_put(skb, sizeof(__u16)), &MessageNumber, sizeof(__u16)); + skb_put_data(skb, &MessageNumber, sizeof(__u16)); hycapi_send_message(ctrl, skb); hycapi_applications[appl - 1].ctrl_mask &= ~(1 << (ctrl->cnr - 1)); } @@ -557,10 +557,9 @@ hycapi_rx_capipkt(hysdn_card *card, unsigned char *buf, unsigned short len) card->myid); return; } - memcpy(skb_put(skb, MsgLen), buf, MsgLen); - memcpy(skb_put(skb, 2 * sizeof(__u32)), CP64, 2 * sizeof(__u32)); - memcpy(skb_put(skb, len - MsgLen), buf + MsgLen, - len - MsgLen); + skb_put_data(skb, buf, MsgLen); + skb_put_data(skb, CP64, 2 * sizeof(__u32)); + skb_put_data(skb, buf + MsgLen, len - MsgLen); CAPIMSG_SETLEN(skb->data, 30); } else { if (!(skb = alloc_skb(len, GFP_ATOMIC))) { @@ -568,7 +567,7 @@ hycapi_rx_capipkt(hysdn_card *card, unsigned char *buf, unsigned short len) card->myid); return; } - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); } switch (CAPIMSG_CMD(skb->data)) { diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index b93a4e9a8d34..8e9c34f33d86 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -201,7 +201,7 @@ hysdn_rx_netpkt(hysdn_card *card, unsigned char *buf, unsigned short len) return; } /* copy the data */ - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); /* determine the used protocol */ skb->protocol = eth_type_trans(skb, dev); diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 8aa158a09180..9ce23cf3d7d2 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -2258,8 +2258,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, /* Now stuff remaining bytes */ if (len) { - p = skb_put(skb, len); - memcpy(p, data, len); + p = skb_put_data(skb, data, len); } /* skb is now ready for xmit */ diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index ddd8207e4e54..d30130c8d0f3 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -474,7 +474,7 @@ isdn_tty_senddown(modem_info *info) return; } skb_reserve(skb, skb_res); - memcpy(skb_put(skb, buflen), info->port.xmit_buf, buflen); + skb_put_data(skb, info->port.xmit_buf, buflen); info->xmit_count = 0; #ifdef CONFIG_ISDN_AUDIO if (info->vonline & 2) { diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c index 52827a80c51f..8b74ce412524 100644 --- a/drivers/isdn/i4l/isdn_v110.c +++ b/drivers/isdn/i4l/isdn_v110.c @@ -421,7 +421,7 @@ isdn_v110_sync(isdn_v110_stream *v) } if ((skb = dev_alloc_skb(v->framelen + v->skbres))) { skb_reserve(skb, v->skbres); - memcpy(skb_put(skb, v->framelen), v->OfflineFrame, v->framelen); + skb_put_data(skb, v->OfflineFrame, v->framelen); } return skb; } @@ -441,7 +441,7 @@ isdn_v110_idle(isdn_v110_stream *v) } if ((skb = dev_alloc_skb(v->framelen + v->skbres))) { skb_reserve(skb, v->skbres); - memcpy(skb_put(skb, v->framelen), v->OnlineFrame, v->framelen); + skb_put_data(skb, v->OnlineFrame, v->framelen); } return skb; } @@ -486,7 +486,7 @@ isdn_v110_encode(isdn_v110_stream *v, struct sk_buff *skb) } skb_reserve(nskb, v->skbres + sizeof(int)); if (skb->len == 0) { - memcpy(skb_put(nskb, v->framelen), v->OnlineFrame, v->framelen); + skb_put_data(nskb, v->OnlineFrame, v->framelen); *((int *)skb_push(nskb, sizeof(int))) = 0; return nskb; } diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index ef9c8e4f1fa2..7ac7badb8f55 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -479,7 +479,7 @@ isdnloop_fake(isdnloop_card *card, char *s, int ch) } if (ch >= 0) sprintf(skb_put(skb, 3), "%02d;", ch); - memcpy(skb_put(skb, strlen(s)), s, strlen(s)); + skb_put_data(skb, s, strlen(s)); skb_queue_tail(&card->dqueue, skb); return 0; } diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 8e3aa002767b..d4b6f01a3f0e 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1595,8 +1595,7 @@ send_packet: thh = mISDN_HEAD_P(txskb); thh->prim = DL_DATA_REQ; thh->id = 0; - memcpy(skb_put(txskb, len), nskb->data + preload, - len); + skb_put_data(txskb, nskb->data + preload, len); /* queue (trigger later) */ skb_queue_tail(&dsp->sendq, txskb); } diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 5eb380a25903..7243a6746f8b 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -176,7 +176,7 @@ l2up_create(struct layer2 *l2, u_int prim, int len, void *arg) hh->prim = prim; hh->id = (l2->ch.nr << 16) | l2->ch.addr; if (len) - memcpy(skb_put(skb, len), arg, len); + skb_put_data(skb, arg, len); err = l2->up->send(l2->up, skb); if (err) { printk(KERN_WARNING "%s: dev %s err=%d\n", __func__, @@ -235,7 +235,7 @@ l2down_create(struct layer2 *l2, u_int prim, u_int id, int len, void *arg) hh->prim = prim; hh->id = id; if (len) - memcpy(skb_put(skb, len), arg, len); + skb_put_data(skb, arg, len); err = l2down_raw(l2, skb); if (err) dev_kfree_skb(skb); @@ -640,7 +640,7 @@ send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr) return; } } - memcpy(skb_put(skb, i), tmp, i); + skb_put_data(skb, tmp, i); enqueue_super(l2, skb); } @@ -1125,7 +1125,7 @@ enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) mISDNDevName4ch(&l2->ch), __func__); return; } - memcpy(skb_put(skb, i), tmp, i); + skb_put_data(skb, tmp, i); enqueue_super(l2, skb); } diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 592f597d8951..908127efccf8 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -312,7 +312,7 @@ teiup_create(struct manager *mgr, u_int prim, int len, void *arg) hh->prim = prim; hh->id = (mgr->ch.nr << 16) | mgr->ch.addr; if (len) - memcpy(skb_put(skb, len), arg, len); + skb_put_data(skb, arg, len); err = mgr->up->send(mgr->up, skb); if (err) { printk(KERN_WARNING "%s: err=%d\n", __func__, err); diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 9947b342633e..bbaf0a8cae8b 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -828,8 +828,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) /* Copy data into our current skb. */ h.how_much = min(h.priv->ule_sndu_remain, (int)h.ts_remain); - memcpy(skb_put(h.priv->ule_skb, h.how_much), - h.from_where, h.how_much); + skb_put_data(h.priv->ule_skb, h.from_where, h.how_much); h.priv->ule_sndu_remain -= h.how_much; h.ts_remain -= h.how_much; h.from_where += h.how_much; diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 588e2d61c3b4..c67e055a12c9 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -442,7 +442,7 @@ static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, fm_cb(skb)->fm_op = *((u8 *)payload + 2); } if (payload != NULL) - memcpy(skb_put(skb, payload_len), payload, payload_len); + skb_put_data(skb, payload, payload_len); fm_cb(skb)->completion = wait_completion; skb_queue_tail(&fmdev->tx_q, skb); diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 00051590e00f..eda8d407be28 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -262,7 +262,7 @@ void st_int_recv(void *disc_data, while (count) { if (st_gdata->rx_count) { len = min_t(unsigned int, st_gdata->rx_count, count); - memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); + skb_put_data(st_gdata->rx_skb, ptr, len); st_gdata->rx_count -= len; count -= len; ptr += len; diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index bf0d7708beac..e74413f882ab 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -152,7 +152,7 @@ static void kim_int_recv(struct kim_data_s *kim_gdata, while (count) { if (kim_gdata->rx_count) { len = min_t(unsigned int, kim_gdata->rx_count, count); - memcpy(skb_put(kim_gdata->rx_skb, len), ptr, len); + skb_put_data(kim_gdata->rx_skb, ptr, len); kim_gdata->rx_count -= len; count -= len; ptr += len; diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 7d7a3cec149a..b796db7dd621 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -936,8 +936,7 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[], if (!skb) return; - data = skb_put(skb, size); - memcpy(data, &pkt, size); + data = skb_put_data(skb, &pkt, size); skb_reset_mac_header(skb); skb->network_header = skb->mac_header + ETH_HLEN; diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index 71a7c3b44fdd..4534326e20ac 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c @@ -454,8 +454,7 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi) } caif_assert(skb != NULL); - dst = skb_put(skb, len); - memcpy(dst, pfrm, len); + dst = skb_put_data(skb, pfrm, len); skb->protocol = htons(ETH_P_CAIF); skb_reset_mac_header(skb); @@ -585,8 +584,7 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) } caif_assert(skb != NULL); - dst = skb_put(skb, len); - memcpy(dst, pcffrm, len); + dst = skb_put_data(skb, pcffrm, len); skb->protocol = htons(ETH_P_CAIF); skb_reset_mac_header(skb); diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 76e1d3545105..5c57be2082ba 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -198,8 +198,7 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data, skb = netdev_alloc_skb(ser->dev, count+1); if (skb == NULL) return; - p = skb_put(skb, count); - memcpy(p, data, count); + p = skb_put_data(skb, data, count); skb->protocol = htons(ETH_P_CAIF); skb_reset_mac_header(skb); diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index fc21afe852b9..24a5f5ca2037 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -548,8 +548,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len) skb = netdev_alloc_skb(cfspi->ndev, pkt_len + 1); caif_assert(skb != NULL); - dst = skb_put(skb, pkt_len); - memcpy(dst, src, pkt_len); + dst = skb_put_data(skb, src, pkt_len); src += pkt_len; skb->protocol = htons(ETH_P_CAIF); diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c index 1794ea0420b7..c3d104feee13 100644 --- a/drivers/net/caif/caif_virtio.c +++ b/drivers/net/caif/caif_virtio.c @@ -242,7 +242,7 @@ static struct sk_buff *cfv_alloc_and_copy_skb(int *err, skb_reserve(skb, cfv->rx_hr + pad_len); - memcpy(skb_put(skb, cfpkt_len), frm + cfv->rx_hr, cfpkt_len); + skb_put_data(skb, frm + cfv->rx_hr, cfpkt_len); return skb; } diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 6a6e896e52fa..5d067c1b987f 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -216,8 +216,7 @@ static void slc_bump(struct slcan *sl) can_skb_prv(skb)->ifindex = sl->dev->ifindex; can_skb_prv(skb)->skbcnt = 0; - memcpy(skb_put(skb, sizeof(struct can_frame)), - &cf, sizeof(struct can_frame)); + skb_put_data(skb, &cf, sizeof(struct can_frame)); sl->dev->stats.rx_packets++; sl->dev->stats.rx_bytes += cf.can_dlc; diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c index e7b1fa56b290..c5987f518cb2 100644 --- a/drivers/net/ethernet/3com/3c515.c +++ b/drivers/net/ethernet/3com/3c515.c @@ -1370,9 +1370,9 @@ static int boomerang_rx(struct net_device *dev) (skb = netdev_alloc_skb(dev, pkt_len + 4)) != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ - memcpy(skb_put(skb, pkt_len), - isa_bus_to_virt(vp->rx_ring[entry]. - addr), pkt_len); + skb_put_data(skb, + isa_bus_to_virt(vp->rx_ring[entry].addr), + pkt_len); rx_copy++; } else { void *temp; diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 14cff6017756..3b516ebeeddb 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -2628,9 +2628,8 @@ boomerang_rx(struct net_device *dev) skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ - memcpy(skb_put(skb, pkt_len), - vp->rx_skbuff[entry]->data, - pkt_len); + skb_put_data(skb, vp->rx_skbuff[entry]->data, + pkt_len); pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); vp->rx_copy++; } else { diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c index d8e133ced7b8..4309be3724ad 100644 --- a/drivers/net/ethernet/aeroflex/greth.c +++ b/drivers/net/ethernet/aeroflex/greth.c @@ -807,7 +807,8 @@ static int greth_rx(struct net_device *dev, int limit) if (netif_msg_pktdata(greth)) greth_print_rx_packet(phys_to_virt(dma_addr), pkt_len); - memcpy(skb_put(skb, pkt_len), phys_to_virt(dma_addr), pkt_len); + skb_put_data(skb, phys_to_virt(dma_addr), + pkt_len); skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_bytes += pkt_len; diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c index 87a11b9f0ea5..54eff90e2f02 100644 --- a/drivers/net/ethernet/agere/et131x.c +++ b/drivers/net/ethernet/agere/et131x.c @@ -2282,7 +2282,7 @@ static struct rfd *nic_rx_pkts(struct et131x_adapter *adapter) adapter->netdev->stats.rx_bytes += rfd->len; - memcpy(skb_put(skb, rfd->len), fbr->virt[buff_index], rfd->len); + skb_put_data(skb, fbr->virt[buff_index], rfd->len); skb->protocol = eth_type_trans(skb, adapter->netdev); skb->ip_summed = CHECKSUM_NONE; diff --git a/drivers/net/ethernet/apple/macmace.c b/drivers/net/ethernet/apple/macmace.c index 857df9c45f04..f17a160dbff2 100644 --- a/drivers/net/ethernet/apple/macmace.c +++ b/drivers/net/ethernet/apple/macmace.c @@ -663,7 +663,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) return; } skb_reserve(skb, 2); - memcpy(skb_put(skb, frame_length), mf->data, frame_length); + skb_put_data(skb, mf->data, frame_length); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c index 5711fbbd6ae3..041cfb7952f8 100644 --- a/drivers/net/ethernet/aurora/nb8800.c +++ b/drivers/net/ethernet/aurora/nb8800.c @@ -251,7 +251,7 @@ static void nb8800_receive(struct net_device *dev, unsigned int i, if (len <= RX_COPYBREAK) { dma_sync_single_for_cpu(&dev->dev, dma, len, DMA_FROM_DEVICE); - memcpy(skb_put(skb, len), data, len); + skb_put_data(skb, data, len); dma_sync_single_for_device(&dev->dev, dma, len, DMA_FROM_DEVICE); } else { @@ -264,7 +264,7 @@ static void nb8800_receive(struct net_device *dev, unsigned int i, } dma_unmap_page(&dev->dev, dma, RX_BUF_SIZE, DMA_FROM_DEVICE); - memcpy(skb_put(skb, RX_COPYHDR), data, RX_COPYHDR); + skb_put_data(skb, data, RX_COPYHDR); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, offset + RX_COPYHDR, len - RX_COPYHDR, RX_BUF_SIZE); diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 91f7492623d3..4b0168bcbc8a 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2992,7 +2992,7 @@ static void at91ether_rx(struct net_device *dev) skb = netdev_alloc_skb(dev, pktlen + 2); if (skb) { skb_reserve(skb, 2); - memcpy(skb_put(skb, pktlen), p_recv, pktlen); + skb_put_data(skb, p_recv, pktlen); skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_packets++; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h index bf483932ff25..4b3507972243 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h @@ -443,8 +443,8 @@ static inline void octeon_fast_packet_next(struct octeon_droq *droq, int copy_len, int idx) { - memcpy(skb_put(nicbuf, copy_len), - get_rbd(droq->recv_buf_list[idx].buffer), copy_len); + skb_put_data(nicbuf, get_rbd(droq->recv_buf_list[idx].buffer), + copy_len); } /** diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c index da5b58b853e2..410a0a95130b 100644 --- a/drivers/net/ethernet/cirrus/cs89x0.c +++ b/drivers/net/ethernet/cirrus/cs89x0.c @@ -450,11 +450,10 @@ skip_this_frame: if (bp + length > lp->end_dma_buff) { int semi_cnt = lp->end_dma_buff - bp; - memcpy(skb_put(skb, semi_cnt), bp, semi_cnt); - memcpy(skb_put(skb, length - semi_cnt), lp->dma_buff, - length - semi_cnt); + skb_put_data(skb, bp, semi_cnt); + skb_put_data(skb, lp->dma_buff, length - semi_cnt); } else { - memcpy(skb_put(skb, length), bp, length); + skb_put_data(skb, bp, length); } bp += (length + 3) & ~3; if (bp >= lp->end_dma_buff) diff --git a/drivers/net/ethernet/dec/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c index fd6bcf024729..47be5018d35d 100644 --- a/drivers/net/ethernet/dec/tulip/de4x5.c +++ b/drivers/net/ethernet/dec/tulip/de4x5.c @@ -3624,10 +3624,10 @@ de4x5_alloc_rx_buff(struct net_device *dev, int index, int len) skb_reserve(p, 2); /* Align */ if (index < lp->rx_old) { /* Wrapped buffer */ short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ; - memcpy(skb_put(p,tlen),lp->rx_bufs + lp->rx_old * RX_BUFF_SZ,tlen); - memcpy(skb_put(p,len-tlen),lp->rx_bufs,len-tlen); + skb_put_data(p, lp->rx_bufs + lp->rx_old * RX_BUFF_SZ, tlen); + skb_put_data(p, lp->rx_bufs, len - tlen); } else { /* Linear buffer */ - memcpy(skb_put(p,len),lp->rx_bufs + lp->rx_old * RX_BUFF_SZ,len); + skb_put_data(p, lp->rx_bufs + lp->rx_old * RX_BUFF_SZ, len); } return p; diff --git a/drivers/net/ethernet/dec/tulip/interrupt.c b/drivers/net/ethernet/dec/tulip/interrupt.c index ba6ae24acf62..8df80880ecaa 100644 --- a/drivers/net/ethernet/dec/tulip/interrupt.c +++ b/drivers/net/ethernet/dec/tulip/interrupt.c @@ -218,9 +218,9 @@ int tulip_poll(struct napi_struct *napi, int budget) pkt_len); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), - tp->rx_buffers[entry].skb->data, - pkt_len); + skb_put_data(skb, + tp->rx_buffers[entry].skb->data, + pkt_len); #endif pci_dma_sync_single_for_device(tp->pdev, tp->rx_buffers[entry].mapping, @@ -444,9 +444,9 @@ static int tulip_rx(struct net_device *dev) pkt_len); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), - tp->rx_buffers[entry].skb->data, - pkt_len); + skb_put_data(skb, + tp->rx_buffers[entry].skb->data, + pkt_len); #endif pci_dma_sync_single_for_device(tp->pdev, tp->rx_buffers[entry].mapping, diff --git a/drivers/net/ethernet/dec/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c index 8d98b259d1ba..7fc248efc4ba 100644 --- a/drivers/net/ethernet/dec/tulip/uli526x.c +++ b/drivers/net/ethernet/dec/tulip/uli526x.c @@ -864,9 +864,9 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info skb = new_skb; /* size less than COPY_SIZE, allocate a rxlen SKB */ skb_reserve(skb, 2); /* 16byte align */ - memcpy(skb_put(skb, rxlen), - skb_tail_pointer(rxptr->rx_skb_ptr), - rxlen); + skb_put_data(skb, + skb_tail_pointer(rxptr->rx_skb_ptr), + rxlen); uli526x_reuse_skb(db, rxptr->rx_skb_ptr); } else skb_put(skb, rxlen); diff --git a/drivers/net/ethernet/ec_bhf.c b/drivers/net/ethernet/ec_bhf.c index 278f139f2a22..4ee042c034a1 100644 --- a/drivers/net/ethernet/ec_bhf.c +++ b/drivers/net/ethernet/ec_bhf.c @@ -223,7 +223,7 @@ static void ec_bhf_process_rx(struct ec_bhf_priv *priv) skb = netdev_alloc_skb_ip_align(priv->net_dev, pkt_size); if (skb) { - memcpy(skb_put(skb, pkt_size), data, pkt_size); + skb_put_data(skb, data, pkt_size); skb->protocol = eth_type_trans(skb, priv->net_dev); priv->stat_rx_bytes += pkt_size; diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index 610f9c07c21d..e92859dab7ae 100644 --- a/drivers/net/ethernet/fealnx.c +++ b/drivers/net/ethernet/fealnx.c @@ -1711,8 +1711,8 @@ static int netdev_rx(struct net_device *dev) np->cur_rx->skbuff->data, pkt_len); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), - np->cur_rx->skbuff->data, pkt_len); + skb_put_data(skb, np->cur_rx->skbuff->data, + pkt_len); #endif pci_dma_sync_single_for_device(np->pci_dev, np->cur_rx->buffer, diff --git a/drivers/net/ethernet/i825xx/82596.c b/drivers/net/ethernet/i825xx/82596.c index 945883842533..d719668a6684 100644 --- a/drivers/net/ethernet/i825xx/82596.c +++ b/drivers/net/ethernet/i825xx/82596.c @@ -809,7 +809,8 @@ memory_squeeze: if (!rx_in_place) { /* 16 byte align the data fields */ skb_reserve(skb, 2); - memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len); + skb_put_data(skb, rbd->v_data, + pkt_len); } skb->protocol=eth_type_trans(skb,dev); skb->len = pkt_len; diff --git a/drivers/net/ethernet/i825xx/lib82596.c b/drivers/net/ethernet/i825xx/lib82596.c index e86773325cbe..8449c58f01fd 100644 --- a/drivers/net/ethernet/i825xx/lib82596.c +++ b/drivers/net/ethernet/i825xx/lib82596.c @@ -727,7 +727,8 @@ memory_squeeze: dma_sync_single_for_cpu(dev->dev.parent, (dma_addr_t)SWAP32(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); - memcpy(skb_put(skb, pkt_len), rbd->v_data, pkt_len); + skb_put_data(skb, rbd->v_data, + pkt_len); dma_sync_single_for_device(dev->dev.parent, (dma_addr_t)SWAP32(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index bd8b05fe8258..98375e1e1185 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -4345,7 +4345,7 @@ static struct sk_buff *e1000_copybreak(struct e1000_adapter *adapter, dma_sync_single_for_cpu(&adapter->pdev->dev, buffer_info->dma, length, DMA_FROM_DEVICE); - memcpy(skb_put(skb, length), data, length); + skb_put_data(skb, data, length); return skb; } diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index d297011b535d..0aab74c2a209 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1976,9 +1976,8 @@ err_drop_frame: MVNETA_MH_SIZE + NET_SKB_PAD, rx_bytes, DMA_FROM_DEVICE); - memcpy(skb_put(skb, rx_bytes), - data + MVNETA_MH_SIZE + NET_SKB_PAD, - rx_bytes); + skb_put_data(skb, data + MVNETA_MH_SIZE + NET_SKB_PAD, + rx_bytes); skb->protocol = eth_type_trans(skb, dev); mvneta_rx_csum(pp, rx_status, skb); @@ -2103,9 +2102,8 @@ err_drop_frame: MVNETA_MH_SIZE + NET_SKB_PAD, rx_bytes, DMA_FROM_DEVICE); - memcpy(skb_put(skb, rx_bytes), - data + MVNETA_MH_SIZE + NET_SKB_PAD, - rx_bytes); + skb_put_data(skb, data + MVNETA_MH_SIZE + NET_SKB_PAD, + rx_bytes); skb->protocol = eth_type_trans(skb, dev); mvneta_rx_csum(pp, rx_status, skb); diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index ee1c78abab0b..e798fbe08600 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -5020,8 +5020,7 @@ static inline int rx_proc(struct net_device *dev, struct ksz_hw* hw, */ skb_reserve(skb, 2); - memcpy(skb_put(skb, packet_len), - dma_buf->skb->data, packet_len); + skb_put_data(skb, dma_buf->skb->data, packet_len); } while (0); skb->protocol = eth_type_trans(skb, dev); diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 9c7ffd649e9a..828bfd93cb54 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -959,11 +959,10 @@ static int __lpc_handle_recv(struct net_device *ndev, int budget) if (!skb) { ndev->stats.rx_dropped++; } else { - prdbuf = skb_put(skb, len); - /* Copy packet from buffer */ - memcpy(prdbuf, pldat->rx_buff_v + - rxconsidx * ENET_MAXF_SIZE, len); + prdbuf = skb_put_data(skb, + pldat->rx_buff_v + rxconsidx * ENET_MAXF_SIZE, + len); /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, ndev); diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index 892eb98290f6..6fc854b120b0 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -1079,8 +1079,7 @@ static struct sk_buff *qede_rx_allocate_skb(struct qede_dev *edev, * re-use the already allcoated & mapped memory. */ if (len + pad <= edev->rx_copybreak) { - memcpy(skb_put(skb, len), - page_address(page) + offset, len); + skb_put_data(skb, page_address(page) + offset, len); qede_reuse_page(rxq, bd); goto out; } diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 1188d420fe53..9feec7009443 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -1577,7 +1577,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, rx_ring->rx_dropped++; goto err_out; } - memcpy(skb_put(skb, hlen), addr, hlen); + skb_put_data(skb, addr, hlen); netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", length); @@ -1654,7 +1654,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, dma_unmap_len(sbq_desc, maplen), PCI_DMA_FROMDEVICE); - memcpy(skb_put(new_skb, length), skb->data, length); + skb_put_data(new_skb, skb->data, length); pci_dma_sync_single_for_device(qdev->pdev, dma_unmap_addr(sbq_desc, mapaddr), @@ -1817,8 +1817,7 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, dma_unmap_len (sbq_desc, maplen), PCI_DMA_FROMDEVICE); - memcpy(skb_put(skb, length), - sbq_desc->p.skb->data, length); + skb_put_data(skb, sbq_desc->p.skb->data, length); pci_dma_sync_single_for_device(qdev->pdev, dma_unmap_addr (sbq_desc, diff --git a/drivers/net/ethernet/silan/sc92031.c b/drivers/net/ethernet/silan/sc92031.c index 751c81848f35..c07fd594fe71 100644 --- a/drivers/net/ethernet/silan/sc92031.c +++ b/drivers/net/ethernet/silan/sc92031.c @@ -795,12 +795,12 @@ static void _sc92031_rx_tasklet(struct net_device *dev) } if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) { - memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset), - rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset); - memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)), - rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset)); + skb_put_data(skb, rx_ring + rx_ring_offset, + RX_BUF_LEN - rx_ring_offset); + skb_put_data(skb, rx_ring, + pkt_size - (RX_BUF_LEN - rx_ring_offset)); } else { - memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size); + skb_put_data(skb, rx_ring + rx_ring_offset, pkt_size); } skb->protocol = eth_type_trans(skb, dev); diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index b56e07fa44a8..750954be5a74 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -1156,8 +1156,7 @@ static int fjes_poll(struct napi_struct *napi, int budget) hw->ep_shm_info[cur_epid].net_stats .rx_errors += 1; } else { - memcpy(skb_put(skb, frame_len), - frame, frame_len); + skb_put_data(skb, frame, frame_len); skb->protocol = eth_type_trans(skb, netdev); skb->ip_summed = CHECKSUM_UNNECESSARY; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 4a40a3d825b4..aec6c26563cf 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -298,7 +298,7 @@ static void ax_bump(struct mkiss *ax) return; } - memcpy(skb_put(skb,count), ax->rbuff, count); + skb_put_data(skb, ax->rbuff, count); skb->protocol = ax25_type_trans(skb, ax->dev); netif_rx(skb); ax->dev->stats.rx_packets++; diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index 1ce6239a4849..7683fd544344 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -962,8 +962,8 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) pkt_len, PCI_DMA_FROMDEVICE); - memcpy(skb_put(skb, pkt_len), - rx_skb->data, pkt_len); + skb_put_data(skb, rx_skb->data, + pkt_len); pci_dma_sync_single_for_device(rrpriv->pci_dev, desc->addr.addrlo, diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index b65a97ecb78e..9a6c5864bc04 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -593,7 +593,7 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, * Copy to skb. This copy is needed here since the memory pointed by * hv_netvsc_packet cannot be deallocated */ - memcpy(skb_put(skb, buflen), data, buflen); + skb_put_data(skb, data, buflen); skb->protocol = eth_type_trans(skb, net); diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 76ba7ecfe142..548d9d026a85 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -723,7 +723,7 @@ at86rf230_rx_read_frame_complete(void *context) return; } - memcpy(skb_put(skb, len), buf + 2, len); + skb_put_data(skb, buf + 2, len); ieee802154_rx_irqsafe(lp->hw, skb, lqi); kfree(ctx); } diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index 7a218549c80a..a626c539fb17 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -1875,7 +1875,7 @@ static int ca8210_skb_rx( copy_payload: /* Add bytes of space to the back of the buffer */ /* Copy msdu to skb */ - memcpy(skb_put(skb, msdulen), &data_ind[29], msdulen); + skb_put_data(skb, &data_ind[29], msdulen); ieee802154_rx_irqsafe(hw, skb, mpdulinkquality); return 0; diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index bd63289c55e8..7d334963dc08 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -774,7 +774,7 @@ static void mrf24j40_handle_rx_read_buf_complete(void *context) return; } - memcpy(skb_put(skb, len), rx_local_buf, len); + skb_put_data(skb, rx_local_buf, len); ieee802154_rx_irqsafe(devrec->hw, skb, 0); #ifdef DEBUG diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 23ed89ae5ddc..19a55cba6beb 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -1459,7 +1459,7 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self) /* Make sure IP header gets aligned */ skb_reserve(skb, 1); - memcpy(skb_put(skb, len), self->rx_buff.data, len); + skb_put_data(skb, self->rx_buff.data, len); self->netdev->stats.rx_packets++; self->netdev->stats.rx_bytes += len; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 15b920086251..6638784c082e 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -578,7 +578,7 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) skb = rd->skb; rd->skb = NULL; skb->dev = ndev; - memcpy(skb_put(skb,len), rd->buf, len); + skb_put_data(skb, rd->buf, len); skb_reset_mac_header(skb); if (in_interrupt()) netif_rx(skb); diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index feb9569e3345..32c72db654e2 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -894,8 +894,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf, /* packet overflowed MRU */ ap->state |= SC_TOSS; } else { - sp = skb_put(skb, n); - memcpy(sp, buf, n); + sp = skb_put_data(skb, buf, n); if (ap->state & SC_ESCAPE) { sp[0] ^= PPP_TRANS; ap->state &= ~SC_ESCAPE; diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index 9ae53986cb4a..ce2300c0bcbf 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -697,8 +697,7 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf, goto err; } - p = skb_put(skb, count); - memcpy(p, buf, count); + p = skb_put_data(skb, buf, count); /* strip address/control field if present */ p = skb->data; diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 74b907206aa7..436dd78c396a 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -364,7 +364,7 @@ static void sl_bump(struct slip *sl) return; } skb->dev = dev; - memcpy(skb_put(skb, count), sl->rbuff, count); + skb_put_data(skb, sl->rbuff, count); skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IP); netif_rx_ni(skb); diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 125cff57c759..90facc5ecab0 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -167,8 +167,8 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, } if (rx->ax_skb) { - data = skb_put(rx->ax_skb, copy_length); - memcpy(data, skb->data + offset, copy_length); + data = skb_put_data(rx->ax_skb, skb->data + offset, + copy_length); if (!rx->remaining) usbnet_skb_return(dev, rx->ax_skb); } diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index c7a350bbaaa7..2952cb570996 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -162,7 +162,7 @@ static void rx_complete(struct urb *req) skb = pnd->rx_skb = netdev_alloc_skb(dev, 12); if (likely(skb)) { /* Can't use pskb_pull() on page in IRQ */ - memcpy(skb_put(skb, 1), page_address(page), 1); + skb_put_data(skb, page_address(page), 1); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, 1, req->actual_length, PAGE_SIZE); diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index a6b997cffd3b..18fa45fc979b 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -399,7 +399,7 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_ memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN); /* add datagram */ - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); /* map MBIM session to VLAN */ if (tci) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 7f02954772c6..8a4c8a1b9dd3 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1180,7 +1180,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) ndp16->dpe16[index].wDatagramLength = cpu_to_le16(skb->len); ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len); ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16)); - memcpy(skb_put(skb_out, skb->len), skb->data, skb->len); + skb_put_data(skb_out, skb->data, skb->len); ctx->tx_curr_frame_payload += skb->len; /* count real tx payload data */ dev_kfree_skb_any(skb); skb = NULL; @@ -1229,7 +1229,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); nth16->wNdpIndex = cpu_to_le16(skb_out->len); - memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size); + skb_put_data(skb_out, ctx->delayed_ndp16, ctx->max_ndp_size); /* Zero out delayed NDP - signature checking will naturally fail. */ ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size); @@ -1497,7 +1497,7 @@ next_ndp: skb = netdev_alloc_skb_ip_align(dev->net, len); if (!skb) goto error; - memcpy(skb_put(skb, len), skb_in->data + offset, len); + skb_put_data(skb, skb_in->data + offset, len); usbnet_skb_return(dev, skb); payload += len; /* count payload bytes in this NTB */ } diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index 1cc24e6f23e2..29276e54bb8b 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -121,8 +121,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (gl_skb) { // copy the packet data to the new skb - memcpy(skb_put(gl_skb, size), - packet->packet_data, size); + skb_put_data(gl_skb, packet->packet_data, size); usbnet_skb_return(dev, gl_skb); } diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 00067a0c51ca..908ada4ca21c 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -911,11 +911,9 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, /* Copy what we got so far. make room for iphdr * after tail. */ - tmp_rx_buf = - skb_put(odev->skb_rx_buf, - sizeof(struct iphdr)); - memcpy(tmp_rx_buf, (char *)&(odev->rx_ip_hdr), - sizeof(struct iphdr)); + tmp_rx_buf = skb_put_data(odev->skb_rx_buf, + (char *)&(odev->rx_ip_hdr), + sizeof(struct iphdr)); /* ETH_HLEN */ odev->rx_buf_size = sizeof(struct iphdr); @@ -934,8 +932,9 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, /* Copy the rest of the bytes that are left in the * buffer into the waiting sk_buf. */ /* Make room for temp_bytes after tail. */ - tmp_rx_buf = skb_put(odev->skb_rx_buf, temp_bytes); - memcpy(tmp_rx_buf, ip_pkt + buffer_offset, temp_bytes); + tmp_rx_buf = skb_put_data(odev->skb_rx_buf, + ip_pkt + buffer_offset, + temp_bytes); odev->rx_buf_missing -= temp_bytes; count -= temp_bytes; diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 76465b117b72..0f213ea22c75 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -253,7 +253,7 @@ static void ipheth_rcvbulk_callback(struct urb *urb) return; } - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); skb->dev = dev->net; skb->protocol = eth_type_trans(skb, dev->net); diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index 5714107533bb..d633492bf9eb 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -135,7 +135,7 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } buf = s->current_rx_buf; - memcpy(skb_put(buf, skb->len), skb->data, skb->len); + skb_put_data(buf, skb->data, skb->len); } else if (skb->len < 4) { netif_err(dev, ifup, dev->net, "Frame too short\n"); dev->net->stats.rx_length_errors++; diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 32a22f4e8356..ffd229ec8352 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -188,7 +188,7 @@ static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb) goto skip; } - memcpy(skb_put(skbn, len), skb->data + offset, len); + skb_put_data(skbn, skb->data + offset, len); if (netif_rx(skbn) != NET_RX_SUCCESS) return 0; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1f8c15cb63b0..6bacbd2f0eca 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -305,7 +305,7 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi, copy = len; if (copy > skb_tailroom(skb)) copy = skb_tailroom(skb); - memcpy(skb_put(skb, copy), p, copy); + skb_put_data(skb, p, copy); len -= copy; offset += copy; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 33265eb50420..bd46b2552980 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -857,7 +857,7 @@ fst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, dbg(DBG_TX, "fst_rx_dma_complete\n"); pi = port->index; - memcpy(skb_put(skb, len), card->rx_dma_handle_host, len); + skb_put_data(skb, card->rx_dma_handle_host, len); /* Reset buffer descriptor */ FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN); diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 47fdb87d3567..f5b4ad45831a 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -234,9 +234,9 @@ static void ppp_tx_cp(struct net_device *dev, u16 pid, u8 code, cp->len = htons(sizeof(struct cp_header) + magic_len + len); if (magic_len) - memcpy(skb_put(skb, magic_len), &magic, magic_len); + skb_put_data(skb, &magic, magic_len); if (len) - memcpy(skb_put(skb, len), data, len); + skb_put_data(skb, data, len); #if DEBUG_CP BUG_ON(code >= CP_CODES); diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 878b05d06fc7..40ee80c03c94 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -202,7 +202,7 @@ static void x25_asy_bump(struct x25_asy *sl) return; } skb_push(skb, 1); /* LAPB internal control */ - memcpy(skb_put(skb, count), sl->rbuff, count); + skb_put_data(skb, sl->rbuff, count); skb->protocol = x25_type_trans(skb, sl->dev); err = lapb_data_received(skb->dev, skb); if (err != LAPB_OK) { diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 7f64e74d746b..dd7f3168c07d 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -488,7 +488,7 @@ void i2400m_net_rx(struct i2400m *i2400m, struct sk_buff *skb_rx, net_dev->stats.rx_dropped++; goto error_skb_realloc; } - memcpy(skb_put(skb, buf_len), buf, buf_len); + skb_put_data(skb, buf, buf_len); } i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev, skb->data - ETH_HLEN, diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index ed626f568b58..5f64f3928c35 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -390,9 +390,9 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) priv->pdev, priv->rx_buffers[entry].mapping, pktlen, PCI_DMA_FROMDEVICE); - memcpy(skb_put(skb, pktlen), - skb_tail_pointer(priv->rx_buffers[entry].skb), - pktlen); + skb_put_data(skb, + skb_tail_pointer(priv->rx_buffers[entry].skb), + pktlen); pci_dma_sync_single_for_device( priv->pdev, priv->rx_buffers[entry].mapping, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4674ff33d320..16cf250f6c39 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3475,9 +3475,8 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, if (arvif->u.ap.noa_data) if (!pskb_expand_head(skb, 0, arvif->u.ap.noa_len, GFP_ATOMIC)) - memcpy(skb_put(skb, arvif->u.ap.noa_len), - arvif->u.ap.noa_data, - arvif->u.ap.noa_len); + skb_put_data(skb, arvif->u.ap.noa_data, + arvif->u.ap.noa_len); spin_unlock_bh(&ar->data_lock); } } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6afc8d27f0d5..a66e2482897f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3304,9 +3304,8 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, if (arvif->u.ap.noa_data) if (!pskb_expand_head(bcn, 0, arvif->u.ap.noa_len, GFP_ATOMIC)) - memcpy(skb_put(bcn, arvif->u.ap.noa_len), - arvif->u.ap.noa_data, - arvif->u.ap.noa_len); + skb_put_data(bcn, arvif->u.ap.noa_data, + arvif->u.ap.noa_len); } static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 373b1e9457fd..f0439f2d566b 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -1005,7 +1005,7 @@ static void ath_scan_send_probe(struct ath_softc *sc, info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; if (req->ie_len) - memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); + skb_put_data(skb, req->ie, req->ie_len); skb_set_queue_mapping(skb, IEEE80211_AC_VO); @@ -1521,8 +1521,7 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, noa_desc = !!avp->offchannel_duration + !!avp->noa_duration; noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc; - hdr = skb_put(skb, sizeof(noa_ie_hdr)); - memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr)); + hdr = skb_put_data(skb, noa_ie_hdr, sizeof(noa_ie_hdr)); hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2; hdr[7] = noa_len; diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 9c16e2a6d185..c51c69b1ad96 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -312,8 +312,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, skb_reserve(skb, headroom); if (cmd_len != 0 && cmd_buf != NULL) { - data = (u8 *) skb_put(skb, cmd_len); - memcpy(data, cmd_buf, cmd_len); + data = skb_put_data(skb, cmd_buf, cmd_len); } mutex_lock(&wmi->op_mutex); diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index b2166726b05d..705063259c8f 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -481,7 +481,7 @@ static struct sk_buff *carl9170_rx_copy_data(u8 *buf, int len) skb = dev_alloc_skb(len + reserved); if (likely(skb)) { skb_reserve(skb, reserved); - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); } return skb; @@ -916,7 +916,7 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) } } - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); + skb_put_data(ar->rx_failover, tbuf, tlen); ar->rx_failover_missing -= tlen; if (ar->rx_failover_missing <= 0) { @@ -958,7 +958,7 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) * the rx - descriptor comes round again. */ - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); + skb_put_data(ar->rx_failover, tbuf, tlen); ar->rx_failover_missing = clen - tlen; return; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 814c35645b73..cff9c585972f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -681,7 +681,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, ether_addr_copy(eth->h_dest, ndev->dev_addr); ether_addr_copy(eth->h_source, evt->src_mac); eth->h_proto = cpu_to_be16(ETH_P_PAE); - memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len); + skb_put_data(skb, evt->eapol, eapol_len); skb->protocol = eth_type_trans(skb, ndev); if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { ndev->stats.rx_packets++; diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c index 27b110dc8cc6..b68436b23a63 100644 --- a/drivers/net/wireless/atmel/atmel.c +++ b/drivers/net/wireless/atmel/atmel.c @@ -1036,9 +1036,8 @@ static void frag_rx_path(struct atmel_private *priv, priv->dev->stats.rx_dropped++; } else { skb_reserve(skb, 2); - memcpy(skb_put(skb, priv->frag_len + 12), - priv->rx_buf, - priv->frag_len + 12); + skb_put_data(skb, priv->rx_buf, + priv->frag_len + 12); skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c index f9dd892b9f27..cfa617ddb2f1 100644 --- a/drivers/net/wireless/broadcom/b43legacy/dma.c +++ b/drivers/net/wireless/broadcom/b43legacy/dma.c @@ -1072,7 +1072,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, goto out_unmap_hdr; } - memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + skb_put_data(bounce_skb, skb->data, skb->len); memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb)); bounce_skb->dev = skb->dev; skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb)); diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index bbc579b647b6..e0c690b48d4e 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -10274,8 +10274,9 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb, printk(KERN_INFO "Adding frag %d %d...\n", j, size); - memcpy(skb_put(skb, size), - txb->fragments[j]->data + hdr_len, size); + skb_put_data(skb, + txb->fragments[j]->data + hdr_len, + size); } dev_kfree_skb_any(txb->fragments[i]); txb->fragments[i] = skb; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c index 048f1e3ada11..5339d1eeb2f7 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c @@ -359,7 +359,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) goto failed; skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len); - memcpy(skb_put(skb_new, hdr_len), &header, hdr_len); + skb_put_data(skb_new, &header, hdr_len); snapped = 1; libipw_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)), ether_type); @@ -470,9 +470,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) skb_reserve(skb_frag, crypt->ops->extra_mpdu_prefix_len); - frag_hdr = - (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len); - memcpy(frag_hdr, &header, hdr_len); + frag_hdr = skb_put_data(skb_frag, &header, hdr_len); /* If this is not the last fragment, then add the MOREFRAGS * bit to the frame control */ diff --git a/drivers/net/wireless/intel/iwlegacy/3945.c b/drivers/net/wireless/intel/iwlegacy/3945.c index 080ea8155b90..dbf164d48ed3 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945.c +++ b/drivers/net/wireless/intel/iwlegacy/3945.c @@ -520,7 +520,7 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb, * and do not consume a full page */ if (len <= SMALL_PACKET_SIZE) { - memcpy(skb_put(skb, len), rx_hdr->payload, len); + skb_put_data(skb, rx_hdr->payload, len); } else { skb_add_rx_frag(skb, 0, rxb->page, (void *)rx_hdr->payload - (void *)pkt, len, diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 49a2ff15ddae..5b51fba75595 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -606,7 +606,7 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr, } if (len <= SMALL_PACKET_SIZE) { - memcpy(skb_put(skb, len), hdr, len); + skb_put_data(skb, hdr, len); } else { skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len, PAGE_SIZE << il->hw_params.rx_page_order); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index adfd6307edca..eaad7389b67c 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -657,7 +657,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, */ hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr); - memcpy(skb_put(skb, hdrlen), hdr, hdrlen); + skb_put_data(skb, hdr, hdrlen); fraglen = len - hdrlen; if (fraglen) { diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c index 4b97371c3b42..adaa2f0097cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c @@ -319,8 +319,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, if (noa_data && pskb_expand_head(skb, 0, noa_data->length, GFP_ATOMIC) == 0) { - memcpy(skb_put(skb, noa_data->length), - noa_data->data, noa_data->length); + skb_put_data(skb, noa_data->data, noa_data->length); hdr = (struct ieee80211_hdr *)skb->data; } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 119a3bd92c50..7a56a0ac151c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1431,7 +1431,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, if (!pkt) goto report; - memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen); + skb_put_data(pkt, pktdata, hdrlen); pktdata += hdrlen; pktsize -= hdrlen; @@ -1463,7 +1463,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, pktsize -= ivlen + icvlen; pktdata += ivlen; - memcpy(skb_put(pkt, pktsize), pktdata, pktsize); + skb_put_data(pkt, pktdata, pktsize); if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) goto report; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index fd2fc46e2fe5..15d13017c1df 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1596,7 +1596,7 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, rx_status.band); /* copy the data */ - memcpy(skb_put(skb, size), sb->data, size); + skb_put_data(skb, sb->data, size); memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); /* pass it as regular rx to mac80211 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index fd1dd06c4f18..2c07719aa45c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -133,7 +133,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, */ hdrlen = (len <= skb_tailroom(skb)) ? len : hdrlen + crypt_len + 8; - memcpy(skb_put(skb, hdrlen), hdr, hdrlen); + skb_put_data(skb, hdr, hdrlen); fraglen = len - hdrlen; if (fraglen) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 966cd7543629..cf48390f6f68 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -183,9 +183,8 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, * present before copying packet data. */ hdrlen += crypt_len; - memcpy(skb_put(skb, hdrlen), hdr, hdrlen); - memcpy(skb_put(skb, headlen - hdrlen), (u8 *)hdr + hdrlen + pad_len, - headlen - hdrlen); + skb_put_data(skb, hdr, hdrlen); + skb_put_data(skb, (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen); fraglen = len - headlen; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 386950a2d616..01013d273aa7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2141,8 +2141,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, htons(ETH_P_IPV6), data_left); - memcpy(skb_put(csum_skb, tcp_hdrlen(skb)), - tcph, tcp_hdrlen(skb)); + skb_put_data(csum_skb, tcph, tcp_hdrlen(skb)); skb_reset_transport_header(csum_skb); csum_skb->csum_start = (unsigned char *)tcp_hdr(csum_skb) - @@ -2176,7 +2175,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, dma_addr_t tb_phys; if (trans_pcie->sw_csum_tx) - memcpy(skb_put(csum_skb, size), tso.data, size); + skb_put_data(csum_skb, tso.data, size); tb_phys = dma_map_single(trans->dev, tso.data, size, DMA_TO_DEVICE); diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c index 055e11d353ca..c1b10d5117ad 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c @@ -242,7 +242,7 @@ netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); memcpy(skb_push(skb, hdr_len), &hdr, hdr_len); if (use_wds == WDS_OWN_FRAME) { - memcpy(skb_put(skb, ETH_ALEN), &hdr.addr4, ETH_ALEN); + skb_put_data(skb, &hdr.addr4, ETH_ALEN); } iface->stats.tx_packets++; diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c index 89b5987303a4..91757defb9be 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ap.c @@ -1000,7 +1000,7 @@ static void prism2_send_mgmt(struct net_device *dev, hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype)); hdr = skb_put_zero(skb, hdrlen); if (body) - memcpy(skb_put(skb, body_len), body, body_len); + skb_put_data(skb, body, body_len); /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 * tx_control instead of using local->tx_control */ diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index d4f0b730796e..72b46eaf3de2 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -2005,7 +2005,7 @@ static void prism2_rx(local_info_t *local) goto rx_dropped; } skb->dev = dev; - memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len); + skb_put_data(skb, &rxdesc, hdr_len); if (len > 0) res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len); @@ -2209,9 +2209,9 @@ static void hostap_tx_callback(local_info_t *local, return; } - memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen); + skb_put_data(skb, (void *)&txdesc->frame_control, hdrlen); if (payload) - memcpy(skb_put(skb, len), payload, len); + skb_put_data(skb, payload, len); skb->dev = local->dev; skb_reset_mac_header(skb); @@ -2362,8 +2362,7 @@ static void prism2_txexc(local_info_t *local) struct sk_buff *skb; skb = dev_alloc_skb(sizeof(txdesc)); if (skb) { - memcpy(skb_put(skb, sizeof(txdesc)), &txdesc, - sizeof(txdesc)); + skb_put_data(skb, &txdesc, sizeof(txdesc)); skb_queue_tail(&local->sta_tx_exc_list, skb); tasklet_schedule(&local->sta_tx_exc_tasklet); } @@ -2460,7 +2459,7 @@ static void prism2_info(local_info_t *local) goto out; } - memcpy(skb_put(skb, sizeof(info)), &info, sizeof(info)); + skb_put_data(skb, &info, sizeof(info)); if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left)) { spin_unlock(&local->baplock); diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c index 400f9b5d620e..a3c066f90afc 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ b/drivers/net/wireless/intersil/hostap/hostap_main.c @@ -1045,7 +1045,7 @@ int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, dst, ETH_ALEN); if (body) - memcpy(skb_put(skb, bodylen), body, bodylen); + skb_put_data(skb, body, bodylen); meta = (struct hostap_skb_tx_data *) skb->cb; memset(meta, 0, sizeof(*meta)); diff --git a/drivers/net/wireless/intersil/orinoco/main.c b/drivers/net/wireless/intersil/orinoco/main.c index d9128bb25e85..f7abc439fb92 100644 --- a/drivers/net/wireless/intersil/orinoco/main.c +++ b/drivers/net/wireless/intersil/orinoco/main.c @@ -792,7 +792,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, } /* Copy the 802.11 header to the skb */ - memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen); + skb_put_data(skb, &(desc->frame_ctl), hdrlen); skb_reset_mac_header(skb); /* If any, copy the data from the card to the skb */ diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index 7ab2f43ab425..e41bf042352e 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -372,9 +372,9 @@ static int p54spi_rx(struct p54s_priv *priv) } if (len <= READAHEAD_SZ) { - memcpy(skb_put(skb, len), rx_head + 1, len); + skb_put_data(skb, rx_head + 1, len); } else { - memcpy(skb_put(skb, READAHEAD_SZ), rx_head + 1, READAHEAD_SZ); + skb_put_data(skb, rx_head + 1, READAHEAD_SZ); p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len - READAHEAD_SZ), len - READAHEAD_SZ); diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c index 60f9b678ef74..b00c07d72f95 100644 --- a/drivers/net/wireless/intersil/p54/txrx.c +++ b/drivers/net/wireless/intersil/p54/txrx.c @@ -905,8 +905,9 @@ void p54_tx_80211(struct ieee80211_hw *dev, if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { /* reserve space for the MIC key */ len += 8; - memcpy(skb_put(skb, 8), &(info->control.hw_key->key - [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); + skb_put_data(skb, + &(info->control.hw_key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), + 8); } /* reserve some space for ICV */ len += info->control.hw_key->icv_len; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index c854a557998b..1d6e180052b8 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2020,8 +2020,7 @@ static void hw_scan_work(struct work_struct *work) memcpy(mgmt->bssid, req->bssid, ETH_ALEN); if (req->ie_len) - memcpy(skb_put(probe, req->ie_len), req->ie, - req->ie_len); + skb_put_data(probe, req->ie, req->ie_len); local_bh_disable(); mac80211_hwsim_tx_frame(hwsim->hw, probe, @@ -3021,7 +3020,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, goto err; /* Copy the data */ - memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len); + skb_put_data(skb, frame_data, frame_data_len); data2 = get_hwsim_data_ref_from_addr(dst); if (!data2) diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index e0196208ab0d..a9e2b06b3175 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -256,9 +256,7 @@ static int if_sdio_handle_data(struct if_sdio_card *card, skb_reserve(skb, NET_IP_ALIGN); - data = skb_put(skb, size); - - memcpy(data, buffer, size); + data = skb_put_data(skb, buffer, size); lbs_process_rxed_packet(card->priv, skb); diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c index 53e67526f40d..bc12c37e7501 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c @@ -81,7 +81,7 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN); /* Add payload */ - memcpy(skb_put(skb_aggr, skb_src->len), skb_src->data, skb_src->len); + skb_put_data(skb_aggr, skb_src->data, skb_src->len); /* Add padding for new MSDU to start from 4 byte boundary */ *pad = (4 - ((unsigned long)skb_aggr->tail & 0x3)) % 4; diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 025bc06a19d6..c20e4944ef87 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -176,12 +176,10 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) memcpy(skb_push(skb, sizeof(pkt_type)), &pkt_type, sizeof(pkt_type)); /* Add packet data and address4 */ - memcpy(skb_put(skb, sizeof(struct ieee80211_hdr_3addr)), buf, - sizeof(struct ieee80211_hdr_3addr)); - memcpy(skb_put(skb, ETH_ALEN), addr, ETH_ALEN); - memcpy(skb_put(skb, len - sizeof(struct ieee80211_hdr_3addr)), - buf + sizeof(struct ieee80211_hdr_3addr), - len - sizeof(struct ieee80211_hdr_3addr)); + skb_put_data(skb, buf, sizeof(struct ieee80211_hdr_3addr)); + skb_put_data(skb, addr, ETH_ALEN); + skb_put_data(skb, buf + sizeof(struct ieee80211_hdr_3addr), + len - sizeof(struct ieee80211_hdr_3addr)); skb->priority = LOW_PRIO_TID; __net_timestamp(skb); diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index c76b7315af55..d38555fe4284 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -679,8 +679,7 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, return ret; } if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, - extra_ies_len); + skb_put_data(skb, extra_ies, extra_ies_len); mwifiex_tdls_add_link_ie(skb, priv->curr_addr, peer, priv->cfg_bssid); break; @@ -693,8 +692,7 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, return ret; } if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, - extra_ies_len); + skb_put_data(skb, extra_ies, extra_ies_len); mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr, priv->cfg_bssid); break; @@ -865,7 +863,7 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, } if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); + skb_put_data(skb, extra_ies, extra_ies_len); /* the TDLS link IE is always added last we are the responder */ diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index a8bc064bc14f..660267b359e4 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -52,7 +52,7 @@ mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, goto bad_frame; if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) { - memcpy(skb_put(skb, hdr_len), data, hdr_len); + skb_put_data(skb, data, hdr_len); data += hdr_len + 2; true_len -= hdr_len; @@ -63,7 +63,7 @@ mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8; frag = true_len - copy; - memcpy(skb_put(skb, copy), data, copy); + skb_put_data(skb, data, copy); data += copy; if (frag) { diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c index a9f5f398b2f8..65a8004418ea 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mcu.c +++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c @@ -68,7 +68,7 @@ mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len) skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL); if (skb) { skb_reserve(skb, MT_DMA_HDR_LEN); - memcpy(skb_put(skb, len), data, len); + skb_put_data(skb, data, len); } return skb; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c index 4814d90c8040..f93b27f3a236 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -213,7 +213,7 @@ static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) return; } - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); qtnf_trans_handle_rx_ctl_packet(bus, skb); } diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h index d8de484b5995..9844ff0add2b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h @@ -35,8 +35,7 @@ qtnf_cmd_skb_put_buffer(struct sk_buff *skb, const u8 *buf_src, size_t len) { u8 *buf_dst; - buf_dst = skb_put(skb, len); - memcpy(buf_dst, buf_src, len); + buf_dst = skb_put_data(skb, buf_src, len); } static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index 4a1bca1b1e26..b70985e126bf 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -203,9 +203,8 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec); if (!(skbdesc->flags & SKBDESC_DESC_IN_SKB)) - memcpy(skb_put(skbcopy, skbdesc->desc_len), skbdesc->desc, - skbdesc->desc_len); - memcpy(skb_put(skbcopy, skb->len), skb->data, skb->len); + skb_put_data(skbcopy, skbdesc->desc, skbdesc->desc_len); + skb_put_data(skbcopy, skb->data, skb->len); skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy); wake_up_interruptible(&intf->frame_dump_waitqueue); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 2e6b888bd417..0c1f8307e179 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -735,8 +735,7 @@ static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw, if (likely(uskb)) { memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status)); - pdata = (u8 *)skb_put(uskb, skb->len); - memcpy(pdata, skb->data, skb->len); + pdata = skb_put_data(uskb, skb->data, skb->len); dev_kfree_skb_any(skb); ieee80211_rx_irqsafe(hw, uskb); } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c index 21ed9ad3be7a..a2eca669873b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c @@ -620,8 +620,7 @@ void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u1rsvdpageloc, 3); skb = dev_alloc_skb(totalpacketlen); - memcpy(skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c index 89a0a28b8b20..dd3ba4810e7d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c @@ -188,10 +188,9 @@ static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw, if (!skb) return false; skb_reserve(skb, extra_descoffset); - seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length - - extra_descoffset)); - memcpy(seg_ptr, code_virtual_address + frag_offset, - (u32)(frag_length - extra_descoffset)); + seg_ptr = skb_put_data(skb, + code_virtual_address + frag_offset, + (u32)(frag_length - extra_descoffset)); tcb_desc = (struct rtl_tcb_desc *)(skb->cb); tcb_desc->queue_index = TXCMD_QUEUE; diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 4d989b8ab185..5590d07d0918 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -653,7 +653,7 @@ static void _rtl_rx_completed(struct urb *_urb) /* reserve some space for mac80211's radiotap */ skb_reserve(skb, __RADIO_TAP_SIZE_RSV); - memcpy(skb_put(skb, size), _urb->transfer_buffer, size); + skb_put_data(skb, _urb->transfer_buffer, size); skb_queue_tail(&rtlusb->rx_queue, skb); tasklet_schedule(&rtlusb->rx_work_tasklet); diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index fac87c06357b..4433cec4367c 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -412,11 +412,9 @@ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, return -ENOMEM; } - buffer = skb_put(skb, msg_len); - - memcpy(buffer, - (u8 *)(msg + FRAME_DESC_SZ + pad_bytes), - msg_len); + buffer = skb_put_data(skb, + (u8 *)(msg + FRAME_DESC_SZ + pad_bytes), + msg_len); pkt_recv = buffer[0]; diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c index 0a0ff7e31f5b..cc2ce60f4f09 100644 --- a/drivers/net/wireless/st/cw1200/scan.c +++ b/drivers/net/wireless/st/cw1200/scan.c @@ -84,7 +84,7 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, return -ENOMEM; if (req->ie_len) - memcpy(skb_put(frame.skb, req->ie_len), req->ie, req->ie_len); + skb_put_data(frame.skb, req->ie, req->ie_len); /* will be unlocked in cw1200_scan_work() */ down(&priv->scan.lock); diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index bbf7604889b7..08f0477f78d9 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1036,7 +1036,7 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, goto out_idle; } if (req->ie_len) - memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); + skb_put_data(skb, req->ie, req->ie_len); ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, skb->len); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 4a39fb13c478..229f4d01f239 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1156,9 +1156,9 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, goto out; } if (ie0_len) - memcpy(skb_put(skb, ie0_len), ie0, ie0_len); + skb_put_data(skb, ie0, ie0_len); if (ie1_len) - memcpy(skb_put(skb, ie1_len), ie1, ie1_len); + skb_put_data(skb, ie1, ie1_len); if (sched_scan && (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 52a55f9acd80..53cd6d4d5b50 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -174,15 +174,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, /* reserve the unaligned payload(if any) */ skb_reserve(skb, reserved); - buf = skb_put(skb, pkt_data_len); - /* * Copy packets from aggregation buffer to the skbs without rx * descriptor and with packet payload aligned care. In case of unaligned * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ - memcpy(buf, data + sizeof(*desc), pkt_data_len); + buf = skb_put_data(skb, data + sizeof(*desc), pkt_data_len); if (rx_align == WLCORE_RX_BUF_PADDED) skb_pull(skb, RX_BUF_ALIGN); diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c index de7ff395977a..7f586d76cf17 100644 --- a/drivers/net/wireless/zydas/zd1201.c +++ b/drivers/net/wireless/zydas/zd1201.c @@ -326,13 +326,13 @@ static void zd1201_usbrx(struct urb *urb) if (!(skb = dev_alloc_skb(datalen+24))) goto resubmit; - memcpy(skb_put(skb, 2), &data[datalen-16], 2); - memcpy(skb_put(skb, 2), &data[datalen-2], 2); - memcpy(skb_put(skb, 6), &data[datalen-14], 6); - memcpy(skb_put(skb, 6), &data[datalen-22], 6); - memcpy(skb_put(skb, 6), &data[datalen-8], 6); - memcpy(skb_put(skb, 2), &data[datalen-24], 2); - memcpy(skb_put(skb, len), data, len); + skb_put_data(skb, &data[datalen - 16], 2); + skb_put_data(skb, &data[datalen - 2], 2); + skb_put_data(skb, &data[datalen - 14], 6); + skb_put_data(skb, &data[datalen - 22], 6); + skb_put_data(skb, &data[datalen - 8], 6); + skb_put_data(skb, &data[datalen - 24], 2); + skb_put_data(skb, data, len); skb->protocol = eth_type_trans(skb, zd->dev); zd->dev->stats.rx_packets++; zd->dev->stats.rx_bytes += skb->len; @@ -359,9 +359,9 @@ static void zd1201_usbrx(struct urb *urb) frag->skb = skb; frag->seq = seq & IEEE80211_SCTL_SEQ; skb_reserve(skb, 2); - memcpy(skb_put(skb, 12), &data[datalen-14], 12); - memcpy(skb_put(skb, 2), &data[6], 2); - memcpy(skb_put(skb, len), data+8, len); + skb_put_data(skb, &data[datalen - 14], 12); + skb_put_data(skb, &data[6], 2); + skb_put_data(skb, data + 8, len); hlist_add_head(&frag->fnode, &zd->fraglist); goto resubmit; } @@ -385,9 +385,9 @@ static void zd1201_usbrx(struct urb *urb) if (!skb) goto resubmit; skb_reserve(skb, 2); - memcpy(skb_put(skb, 12), &data[datalen-14], 12); - memcpy(skb_put(skb, 2), &data[6], 2); - memcpy(skb_put(skb, len), data+8, len); + skb_put_data(skb, &data[datalen - 14], 12); + skb_put_data(skb, &data[6], 2); + skb_put_data(skb, data + 8, len); } skb->protocol = eth_type_trans(skb, zd->dev); zd->dev->stats.rx_packets++; diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index fe6517a621b0..2d929d2edb00 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -1103,7 +1103,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) } /* FIXME : could we avoid this big memcpy ? */ - memcpy(skb_put(skb, length), buffer, length); + skb_put_data(skb, buffer, length); memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); ieee80211_rx_irqsafe(hw, skb); diff --git a/drivers/nfc/fdp/fdp.c b/drivers/nfc/fdp/fdp.c index 7c1eaea3b685..badd8167ac73 100644 --- a/drivers/nfc/fdp/fdp.c +++ b/drivers/nfc/fdp/fdp.c @@ -228,8 +228,7 @@ static int fdp_nci_send_patch(struct nci_dev *ndev, u8 conn_id, u8 type) skb_reserve(skb, NCI_CTRL_HDR_SIZE); - memcpy(skb_put(skb, payload_size), fw->data + (fw->size - len), - payload_size); + skb_put_data(skb, fw->data + (fw->size - len), payload_size); rc = nci_send_data(ndev, conn_id, skb); diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index 712936f5d2d6..0877e2283f35 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -186,7 +186,7 @@ static int fdp_nci_i2c_read(struct fdp_i2c_phy *phy, struct sk_buff **skb) goto flush; } - memcpy(skb_put(*skb, len), tmp, len); + skb_put_data(*skb, tmp, len); fdp_nci_i2c_dump_skb(&client->dev, "fdp_rd", *skb); fdp_nci_i2c_remove_len_lrc(*skb); diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c index c38bdd6a5a82..7c710458568e 100644 --- a/drivers/nfc/nfcmrvl/fw_dnld.c +++ b/drivers/nfc/nfcmrvl/fw_dnld.c @@ -324,10 +324,9 @@ static int process_state_fw_dnld(struct nfcmrvl_private *priv, out_skb = alloc_lc_skb(priv, priv->fw_dnld.chunk_len); if (!out_skb) return -ENOMEM; - memcpy(skb_put(out_skb, priv->fw_dnld.chunk_len), - ((uint8_t *)priv->fw_dnld.fw->data) + - priv->fw_dnld.offset, - priv->fw_dnld.chunk_len); + skb_put_data(out_skb, + ((uint8_t *)priv->fw_dnld.fw->data) + priv->fw_dnld.offset, + priv->fw_dnld.chunk_len); nci_send_frame(priv->ndev, out_skb); priv->fw_dnld.substate = SUBSTATE_WAIT_DATA_CREDIT; } diff --git a/drivers/nfc/nfcmrvl/i2c.c b/drivers/nfc/nfcmrvl/i2c.c index 78b7aa835c81..ffec103702f1 100644 --- a/drivers/nfc/nfcmrvl/i2c.c +++ b/drivers/nfc/nfcmrvl/i2c.c @@ -60,7 +60,7 @@ static int nfcmrvl_i2c_read(struct nfcmrvl_i2c_drv_data *drv_data, return -ENOMEM; /* Copy NCI header into the SKB */ - memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), &nci_hdr, NCI_CTRL_HDR_SIZE); + skb_put_data(*skb, &nci_hdr, NCI_CTRL_HDR_SIZE); if (nci_hdr.plen) { /* Read the NCI payload */ diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c index 585a0f20835b..699aa9d16575 100644 --- a/drivers/nfc/nfcmrvl/usb.c +++ b/drivers/nfc/nfcmrvl/usb.c @@ -83,8 +83,8 @@ static void nfcmrvl_bulk_complete(struct urb *urb) if (!skb) { nfc_err(&drv_data->udev->dev, "failed to alloc mem\n"); } else { - memcpy(skb_put(skb, urb->actual_length), - urb->transfer_buffer, urb->actual_length); + skb_put_data(skb, urb->transfer_buffer, + urb->actual_length); if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0) nfc_err(&drv_data->udev->dev, "corrupted Rx packet\n"); diff --git a/drivers/nfc/nxp-nci/firmware.c b/drivers/nfc/nxp-nci/firmware.c index 553011f58339..99ffee1dfd1e 100644 --- a/drivers/nfc/nxp-nci/firmware.c +++ b/drivers/nfc/nxp-nci/firmware.c @@ -124,8 +124,7 @@ static int nxp_nci_fw_send_chunk(struct nxp_nci_info *info) header |= chunk_len & NXP_NCI_FW_FRAME_LEN_MASK; put_unaligned_be16(header, skb_put(skb, NXP_NCI_FW_HDR_LEN)); - memcpy(skb_put(skb, chunk_len), fw_info->data + fw_info->written, - chunk_len); + skb_put_data(skb, fw_info->data + fw_info->written, chunk_len); crc = nxp_nci_fw_crc(skb->data, chunk_len + NXP_NCI_FW_HDR_LEN); put_unaligned_be16(crc, skb_put(skb, NXP_NCI_FW_CRC_LEN)); diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c index ff22d761183c..198585bbc771 100644 --- a/drivers/nfc/nxp-nci/i2c.c +++ b/drivers/nfc/nxp-nci/i2c.c @@ -135,7 +135,7 @@ static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy, goto fw_read_exit; } - memcpy(skb_put(*skb, NXP_NCI_FW_HDR_LEN), &header, NXP_NCI_FW_HDR_LEN); + skb_put_data(*skb, &header, NXP_NCI_FW_HDR_LEN); r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len); if (r != frame_len) { @@ -176,8 +176,7 @@ static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy, goto nci_read_exit; } - memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), (void *) &header, - NCI_CTRL_HDR_SIZE); + skb_put_data(*skb, (void *)&header, NCI_CTRL_HDR_SIZE); r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen); if (r != header.plen) { diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index 70c304504a29..9200bb308e42 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -1035,11 +1035,10 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) *skb_put(skb, 1) = PN533_INIT_TARGET_DEP; /* MIFARE params */ - memcpy(skb_put(skb, 6), mifare_params, 6); + skb_put_data(skb, mifare_params, 6); /* Felica params */ - felica = skb_put(skb, 18); - memcpy(felica, felica_params, 18); + felica = skb_put_data(skb, felica_params, 18); get_random_bytes(felica + 2, 6); /* NFCID3 */ @@ -1049,8 +1048,7 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) /* General bytes */ *skb_put(skb, 1) = gbytes_len; - gb = skb_put(skb, gbytes_len); - memcpy(gb, gbytes, gbytes_len); + gb = skb_put_data(skb, gbytes, gbytes_len); /* Len Tk */ *skb_put(skb, 1) = 0; @@ -1384,15 +1382,14 @@ static int pn533_poll_dep(struct nfc_dev *nfc_dev) *next = 0; /* Copy passive data */ - memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN); + skb_put_data(skb, passive_data, PASSIVE_DATA_LEN); *next |= 1; /* Copy NFCID3 (which is NFCID2 from SENSF_RES) */ - memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), nfcid3, - NFC_NFCID3_MAXSIZE); + skb_put_data(skb, nfcid3, NFC_NFCID3_MAXSIZE); *next |= 2; - memcpy(skb_put(skb, dev->gb_len), dev->gb, dev->gb_len); + skb_put_data(skb, dev->gb, dev->gb_len); *next |= 4; /* We have some Gi */ rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb, @@ -1472,7 +1469,7 @@ static struct sk_buff *pn533_alloc_poll_in_frame(struct pn533 *dev, if (!skb) return NULL; - memcpy(skb_put(skb, mod->len), &mod->data, mod->len); + skb_put_data(skb, &mod->data, mod->len); return skb; } @@ -1858,7 +1855,7 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, *next = 0; /* Copy passive data */ - memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN); + skb_put_data(skb, passive_data, PASSIVE_DATA_LEN); *next |= 1; /* Copy NFCID3 (which is NFCID2 from SENSF_RES) */ @@ -1866,12 +1863,11 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), target->nfcid2, target->nfcid2_len); else - memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), nfcid3, - NFC_NFCID3_MAXSIZE); + skb_put_data(skb, nfcid3, NFC_NFCID3_MAXSIZE); *next |= 2; if (gb != NULL && gb_len > 0) { - memcpy(skb_put(skb, gb_len), gb, gb_len); + skb_put_data(skb, gb, gb_len); *next |= 4; /* We have some Gi */ } else { *next = 0; @@ -2100,7 +2096,7 @@ static int pn533_fill_fragment_skbs(struct pn533 *dev, struct sk_buff *skb) *skb_push(frag, sizeof(u8)) = 1; /* TG */ } - memcpy(skb_put(frag, frag_size), skb->data, frag_size); + skb_put_data(frag, skb->data, frag_size); /* Reduce the size of incoming buffer */ skb_pull(skb, frag_size); @@ -2375,7 +2371,7 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, return -ENOMEM; *skb_put(skb, sizeof(cfgitem)) = cfgitem; - memcpy(skb_put(skb, cfgdata_len), cfgdata, cfgdata_len); + skb_put_data(skb, cfgdata, cfgdata_len); resp = pn533_send_cmd_sync(dev, PN533_CMD_RF_CONFIGURATION, skb); if (IS_ERR(resp)) diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index 8ed203ea21ea..e153e8b64bb8 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -75,8 +75,8 @@ static void pn533_recv_response(struct urb *urb) if (!skb) { nfc_err(&phy->udev->dev, "failed to alloc memory\n"); } else { - memcpy(skb_put(skb, urb->actual_length), - urb->transfer_buffer, urb->actual_length); + skb_put_data(skb, urb->transfer_buffer, + urb->actual_length); } } diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c index 19be93e177fe..e1260da73d45 100644 --- a/drivers/nfc/port100.c +++ b/drivers/nfc/port100.c @@ -1089,9 +1089,8 @@ static int port100_in_set_rf(struct nfc_digital_dev *ddev, u8 rf) if (!skb) return -ENOMEM; - memcpy(skb_put(skb, sizeof(struct port100_in_rf_setting)), - &in_rf_settings[rf], - sizeof(struct port100_in_rf_setting)); + skb_put_data(skb, &in_rf_settings[rf], + sizeof(struct port100_in_rf_setting)); resp = port100_send_cmd_sync(dev, PORT100_CMD_IN_SET_RF, skb); @@ -1133,7 +1132,7 @@ static int port100_in_set_framing(struct nfc_digital_dev *ddev, int param) if (!skb) return -ENOMEM; - memcpy(skb_put(skb, size), protocols, size); + skb_put_data(skb, protocols, size); resp = port100_send_cmd_sync(dev, PORT100_CMD_IN_SET_PROTOCOL, skb); @@ -1247,9 +1246,8 @@ static int port100_tg_set_rf(struct nfc_digital_dev *ddev, u8 rf) if (!skb) return -ENOMEM; - memcpy(skb_put(skb, sizeof(struct port100_tg_rf_setting)), - &tg_rf_settings[rf], - sizeof(struct port100_tg_rf_setting)); + skb_put_data(skb, &tg_rf_settings[rf], + sizeof(struct port100_tg_rf_setting)); resp = port100_send_cmd_sync(dev, PORT100_CMD_TG_SET_RF, skb); @@ -1291,7 +1289,7 @@ static int port100_tg_set_framing(struct nfc_digital_dev *ddev, int param) if (!skb) return -ENOMEM; - memcpy(skb_put(skb, size), protocols, size); + skb_put_data(skb, protocols, size); resp = port100_send_cmd_sync(dev, PORT100_CMD_TG_SET_PROTOCOL, skb); diff --git a/drivers/nfc/s3fwrn5/firmware.c b/drivers/nfc/s3fwrn5/firmware.c index 5f97da1947e3..38548bd970cd 100644 --- a/drivers/nfc/s3fwrn5/firmware.c +++ b/drivers/nfc/s3fwrn5/firmware.c @@ -76,9 +76,9 @@ static int s3fwrn5_fw_prep_msg(struct s3fwrn5_fw_info *fw_info, if (!skb) return -ENOMEM; - memcpy(skb_put(skb, S3FWRN5_FW_HDR_SIZE), &hdr, S3FWRN5_FW_HDR_SIZE); + skb_put_data(skb, &hdr, S3FWRN5_FW_HDR_SIZE); if (len) - memcpy(skb_put(skb, len), data, len); + skb_put_data(skb, data, len); *msg = skb; diff --git a/drivers/nfc/s3fwrn5/i2c.c b/drivers/nfc/s3fwrn5/i2c.c index 3ed0adf6479b..3f09d7fd2285 100644 --- a/drivers/nfc/s3fwrn5/i2c.c +++ b/drivers/nfc/s3fwrn5/i2c.c @@ -157,7 +157,7 @@ static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy) if (!skb) return -ENOMEM; - memcpy(skb_put(skb, hdr_size), hdr, hdr_size); + skb_put_data(skb, hdr, hdr_size); if (data_len == 0) goto out; diff --git a/drivers/nfc/st21nfca/dep.c b/drivers/nfc/st21nfca/dep.c index 798a32bbac5d..ada7b114b6c1 100644 --- a/drivers/nfc/st21nfca/dep.c +++ b/drivers/nfc/st21nfca/dep.c @@ -564,7 +564,7 @@ int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len) atr_req->ppi = ST21NFCA_LR_BITS_PAYLOAD_SIZE_254B; if (gb_len) { atr_req->ppi |= ST21NFCA_GB_BIT; - memcpy(skb_put(skb, gb_len), gb, gb_len); + skb_put_data(skb, gb, gb_len); } atr_req->length = sizeof(struct st21nfca_atr_req) + hdev->gb_len; diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 02a920ca07c8..94d0b913b627 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -407,7 +407,7 @@ static int st21nfca_hci_i2c_read(struct st21nfca_i2c_phy *phy, phy->current_read_len = 0; } - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); if (skb->data[skb->len - 1] == ST21NFCA_SOF_EOF) { phy->current_read_len = 0; diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 0ca2ccc09ca6..2576284f99a7 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -116,7 +116,7 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, if (!skb) return -ENOMEM; - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); spin_lock(&eptdev->queue_lock); skb_queue_tail(&eptdev->queue, skb); diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c index 730d9619400e..e9847ce3860d 100644 --- a/drivers/s390/net/ctcm_fsms.c +++ b/drivers/s390/net/ctcm_fsms.c @@ -1279,7 +1279,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg) __func__, data_space); while ((skb = skb_dequeue(&ch->collect_queue))) { - memcpy(skb_put(ch->trans_skb, skb->len), skb->data, skb->len); + skb_put_data(ch->trans_skb, skb->data, skb->len); p_header = (struct pdu *) (skb_tail_pointer(ch->trans_skb) - skb->len); p_header->pdu_flag = 0x00; @@ -1431,13 +1431,12 @@ static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg) break; case MPCG_STATE_FLOWC: case MPCG_STATE_READY: - memcpy(skb_put(new_skb, block_len), - skb->data, block_len); + skb_put_data(new_skb, skb->data, block_len); skb_queue_tail(&ch->io_queue, new_skb); tasklet_schedule(&ch->ch_tasklet); break; default: - memcpy(skb_put(new_skb, len), skb->data, len); + skb_put_data(new_skb, skb->data, len); skb_queue_tail(&ch->io_queue, new_skb); tasklet_hi_schedule(&ch->ch_tasklet); break; diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 198842ce6876..99121352c57b 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -522,7 +522,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb) ctcm_clear_busy(ch->netdev); return -ENOMEM; } else { - memcpy(skb_put(nskb, skb->len), skb->data, skb->len); + skb_put_data(nskb, skb->data, skb->len); atomic_inc(&nskb->users); atomic_dec(&skb->users); dev_kfree_skb_irq(skb); @@ -638,7 +638,7 @@ static void ctcmpc_send_sweep_req(struct channel *rch) header->th.th_seq_num = 0x00; header->sw.th_last_seq = ch->th_seq_num; - memcpy(skb_put(sweep_skb, TH_SWEEP_LENGTH), header, TH_SWEEP_LENGTH); + skb_put_data(sweep_skb, header, TH_SWEEP_LENGTH); kfree(header); @@ -728,7 +728,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) if (!nskb) { goto nomem_exit; } else { - memcpy(skb_put(nskb, skb->len), skb->data, skb->len); + skb_put_data(nskb, skb->data, skb->len); atomic_inc(&nskb->users); atomic_dec(&skb->users); dev_kfree_skb_irq(skb); @@ -809,7 +809,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) skb_reset_tail_pointer(ch->trans_skb); ch->trans_skb->len = 0; ch->ccw[1].count = skb->len; - memcpy(skb_put(ch->trans_skb, skb->len), skb->data, skb->len); + skb_put_data(ch->trans_skb, skb->data, skb->len); atomic_dec(&skb->users); dev_kfree_skb_irq(skb); ccw_idx = 0; @@ -960,7 +960,7 @@ static int ctcmpc_tx(struct sk_buff *skb, struct net_device *dev) } newskb->protocol = skb->protocol; skb_reserve(newskb, TH_HEADER_LENGTH + PDU_HEADER_LENGTH); - memcpy(skb_put(newskb, skb->len), skb->data, skb->len); + skb_put_data(newskb, skb->data, skb->len); dev_kfree_skb_any(skb); skb = newskb; } diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index c103fc7efe9f..f8be39634f03 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -667,7 +667,7 @@ static void ctcmpc_send_sweep_resp(struct channel *rch) header->th.th_seq_num = 0x00; header->sw.th_last_seq = ch->th_seq_num; - memcpy(skb_put(sweep_skb, TH_SWEEP_LENGTH), header, TH_SWEEP_LENGTH); + skb_put_data(sweep_skb, header, TH_SWEEP_LENGTH); kfree(header); @@ -974,9 +974,8 @@ void mpc_channel_action(struct channel *ch, int direction, int action) skb_reset_tail_pointer(ch->xid_skb); ch->xid_skb->len = 0; - memcpy(skb_put(ch->xid_skb, grp->xid_skb->len), - grp->xid_skb->data, - grp->xid_skb->len); + skb_put_data(ch->xid_skb, grp->xid_skb->data, + grp->xid_skb->len); ch->xid->xid2_dlc_type = ((CHANNEL_DIRECTION(ch->flags) == CTCM_READ) @@ -1149,7 +1148,7 @@ static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb) fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); goto done; } - memcpy(skb_put(skb, new_len), pskb->data, new_len); + skb_put_data(skb, pskb->data, new_len); skb_reset_mac_header(skb); skb->dev = pskb->dev; @@ -1297,16 +1296,15 @@ struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv) /* base xid for all channels in group */ grp->xid_skb_data = grp->xid_skb->data; grp->xid_th = (struct th_header *)grp->xid_skb->data; - memcpy(skb_put(grp->xid_skb, TH_HEADER_LENGTH), - &thnorm, TH_HEADER_LENGTH); + skb_put_data(grp->xid_skb, &thnorm, TH_HEADER_LENGTH); grp->xid = (struct xid2 *)skb_tail_pointer(grp->xid_skb); - memcpy(skb_put(grp->xid_skb, XID2_LENGTH), &init_xid, XID2_LENGTH); + skb_put_data(grp->xid_skb, &init_xid, XID2_LENGTH); grp->xid->xid2_adj_id = jiffies | 0xfff00000; grp->xid->xid2_sender_id = jiffies; grp->xid_id = skb_tail_pointer(grp->xid_skb); - memcpy(skb_put(grp->xid_skb, 4), "VTAM", 4); + skb_put_data(grp->xid_skb, "VTAM", 4); grp->rcvd_xid_skb = __dev_alloc_skb(MPC_BUFSIZE_DEFAULT, GFP_ATOMIC|GFP_DMA); @@ -1318,8 +1316,7 @@ struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv) } grp->rcvd_xid_data = grp->rcvd_xid_skb->data; grp->rcvd_xid_th = (struct th_header *)grp->rcvd_xid_skb->data; - memcpy(skb_put(grp->rcvd_xid_skb, TH_HEADER_LENGTH), - &thnorm, TH_HEADER_LENGTH); + skb_put_data(grp->rcvd_xid_skb, &thnorm, TH_HEADER_LENGTH); grp->saved_xid2 = NULL; priv->xid = grp->xid; priv->mpcg = grp; @@ -1410,8 +1407,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) skb_reset_tail_pointer(grp->rcvd_xid_skb); grp->rcvd_xid_skb->len = 0; grp->rcvd_xid_th = (struct th_header *)grp->rcvd_xid_skb->data; - memcpy(skb_put(grp->rcvd_xid_skb, TH_HEADER_LENGTH), &thnorm, - TH_HEADER_LENGTH); + skb_put_data(grp->rcvd_xid_skb, &thnorm, TH_HEADER_LENGTH); if (grp->send_qllc_disc == 1) { grp->send_qllc_disc = 0; @@ -1590,8 +1586,7 @@ static int mpc_validate_xid(struct mpcg_info *mpcginfo) grp->saved_xid2 = (struct xid2 *)skb_tail_pointer(grp->rcvd_xid_skb); - memcpy(skb_put(grp->rcvd_xid_skb, - XID2_LENGTH), xid, XID2_LENGTH); + skb_put_data(grp->rcvd_xid_skb, xid, XID2_LENGTH); grp->rcvd_xid_skb->data = grp->rcvd_xid_data; skb_reset_tail_pointer(grp->rcvd_xid_skb); @@ -1908,17 +1903,15 @@ static void mpc_action_doxid7(fsm_instance *fsm, int event, void *arg) if (fsm_getstate(ch->fsm) == CH_XID7_PENDING1) { fsm_newstate(ch->fsm, CH_XID7_PENDING2); ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD; - memcpy(skb_put(ch->xid_skb, - TH_HEADER_LENGTH), - &thdummy, TH_HEADER_LENGTH); + skb_put_data(ch->xid_skb, &thdummy, + TH_HEADER_LENGTH); send = 1; } } else if (fsm_getstate(ch->fsm) < CH_XID7_PENDING2) { fsm_newstate(ch->fsm, CH_XID7_PENDING2); ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL; - memcpy(skb_put(ch->xid_skb, - TH_HEADER_LENGTH), - &thnorm, TH_HEADER_LENGTH); + skb_put_data(ch->xid_skb, &thnorm, + TH_HEADER_LENGTH); send = 1; } } else { @@ -1926,17 +1919,16 @@ static void mpc_action_doxid7(fsm_instance *fsm, int event, void *arg) if (grp->roll == YSIDE) { if (fsm_getstate(ch->fsm) < CH_XID7_PENDING4) { fsm_newstate(ch->fsm, CH_XID7_PENDING4); - memcpy(skb_put(ch->xid_skb, - TH_HEADER_LENGTH), - &thnorm, TH_HEADER_LENGTH); + skb_put_data(ch->xid_skb, &thnorm, + TH_HEADER_LENGTH); ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL; send = 1; } } else if (fsm_getstate(ch->fsm) == CH_XID7_PENDING3) { fsm_newstate(ch->fsm, CH_XID7_PENDING4); ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD; - memcpy(skb_put(ch->xid_skb, TH_HEADER_LENGTH), - &thdummy, TH_HEADER_LENGTH); + skb_put_data(ch->xid_skb, &thdummy, + TH_HEADER_LENGTH); send = 1; } } @@ -2122,7 +2114,7 @@ static int mpc_send_qllc_discontact(struct net_device *dev) return -ENOMEM; } - memcpy(skb_put(skb, new_len), qllcptr, new_len); + skb_put_data(skb, qllcptr, new_len); kfree(qllcptr); if (skb_headroom(skb) < 4) { diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 211b31d9f157..337bacb43d68 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1796,7 +1796,7 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len) card->stats.rx_dropped++; return; } - memcpy(skb_put(skb, skb_len), skb_data, skb_len); + skb_put_data(skb, skb_data, skb_len); skb->protocol = card->lan_type_trans(skb, card->dev); card->stats.rx_bytes += skb_len; card->stats.rx_packets++; diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index fa732bd86729..7db427c0a6a4 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -759,8 +759,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) spin_lock_irqsave(&conn->collect_lock, saveflags); while ((skb = skb_dequeue(&conn->collect_queue))) { header.next = conn->tx_buff->len + skb->len + NETIUCV_HDRLEN; - memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, - NETIUCV_HDRLEN); + skb_put_data(conn->tx_buff, &header, NETIUCV_HDRLEN); skb_copy_from_linear_data(skb, skb_put(conn->tx_buff, skb->len), skb->len); @@ -780,7 +779,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) } header.next = 0; - memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); + skb_put_data(conn->tx_buff, &header, NETIUCV_HDRLEN); conn->prof.send_stamp = jiffies; txmsg.class = 0; txmsg.tag = 0; @@ -1201,8 +1200,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, return rc; } else { skb_reserve(nskb, NETIUCV_HDRLEN); - memcpy(skb_put(nskb, skb->len), - skb->data, skb->len); + skb_put_data(nskb, skb->data, skb->len); } copied = 1; } @@ -1212,7 +1210,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, header.next = nskb->len + NETIUCV_HDRLEN; memcpy(skb_push(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); header.next = 0; - memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); + skb_put_data(nskb, &header, NETIUCV_HDRLEN); fsm_newstate(conn->fsm, CONN_STATE_TX); conn->prof.send_stamp = jiffies; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 1fb92e870040..08338f27c82c 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5147,12 +5147,11 @@ static inline int qeth_create_skb_frag(struct qeth_qdio_buffer *qethbuffer, skb_reserve(*pskb, ETH_HLEN); if (data_len <= QETH_RX_PULL_LEN) { - memcpy(skb_put(*pskb, data_len), element->addr + offset, - data_len); + skb_put_data(*pskb, element->addr + offset, data_len); } else { get_page(page); - memcpy(skb_put(*pskb, QETH_RX_PULL_LEN), - element->addr + offset, QETH_RX_PULL_LEN); + skb_put_data(*pskb, element->addr + offset, + QETH_RX_PULL_LEN); skb_fill_page_desc(*pskb, *pfrag, page, offset + QETH_RX_PULL_LEN, data_len - QETH_RX_PULL_LEN); @@ -5248,8 +5247,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, &skb, offset, &frag, data_len)) goto no_mem; } else { - memcpy(skb_put(skb, data_len), data_ptr, - data_len); + skb_put_data(skb, data_ptr, data_len); } } skb_len -= data_len; diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c index cf809987f79f..9ab6ce231f11 100644 --- a/drivers/staging/gdm724x/gdm_lte.c +++ b/drivers/staging/gdm724x/gdm_lte.c @@ -161,12 +161,9 @@ static int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type) return -ENOMEM; skb_reserve(skb_out, NET_IP_ALIGN); - memcpy(skb_put(skb_out, mac_header_len), mac_header_data, - mac_header_len); - memcpy(skb_put(skb_out, sizeof(struct arphdr)), arp_out, - sizeof(struct arphdr)); - memcpy(skb_put(skb_out, sizeof(struct arpdata)), arp_data_out, - sizeof(struct arpdata)); + skb_put_data(skb_out, mac_header_data, mac_header_len); + skb_put_data(skb_out, arp_out, sizeof(struct arphdr)); + skb_put_data(skb_out, arp_data_out, sizeof(struct arpdata)); skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto; skb_out->dev = skb_in->dev; @@ -322,14 +319,10 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type) return -ENOMEM; skb_reserve(skb_out, NET_IP_ALIGN); - memcpy(skb_put(skb_out, mac_header_len), mac_header_data, - mac_header_len); - memcpy(skb_put(skb_out, sizeof(struct ipv6hdr)), &ipv6_out, - sizeof(struct ipv6hdr)); - memcpy(skb_put(skb_out, sizeof(struct icmp6hdr)), &icmp6_out, - sizeof(struct icmp6hdr)); - memcpy(skb_put(skb_out, sizeof(struct neighbour_advertisement)), &na, - sizeof(struct neighbour_advertisement)); + skb_put_data(skb_out, mac_header_data, mac_header_len); + skb_put_data(skb_out, &ipv6_out, sizeof(struct ipv6hdr)); + skb_put_data(skb_out, &icmp6_out, sizeof(struct icmp6hdr)); + skb_put_data(skb_out, &na, sizeof(struct neighbour_advertisement)); skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto; skb_out->dev = skb_in->dev; @@ -669,8 +662,8 @@ static void gdm_lte_netif_rx(struct net_device *dev, char *buf, return; skb_reserve(skb, NET_IP_ALIGN); - memcpy(skb_put(skb, mac_header_len), mac_header_data, mac_header_len); - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, mac_header_data, mac_header_len); + skb_put_data(skb, buf, len); skb->protocol = ((struct ethhdr *)mac_header_data)->h_proto; skb->dev = dev; diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 49e95426ac30..da801d3e0585 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -466,12 +466,12 @@ void hostif_data_indication(struct ks_wlan_private *priv) DPRINTK(4, "SNAP, rx_ind_size = %d\n", rx_ind_size); size = ETH_ALEN * 2; - memcpy(skb_put(skb, size), priv->rxp, size); + skb_put_data(skb, priv->rxp, size); /* (SNAP+UI..) skip */ size = rx_ind_size - (ETH_ALEN * 2); - memcpy(skb_put(skb, size), ð_hdr->h_proto, size); + skb_put_data(skb, ð_hdr->h_proto, size); aa1x_hdr = (struct ieee802_1x_hdr *)(priv->rxp + ETHER_HDR_SIZE); break; @@ -484,14 +484,13 @@ void hostif_data_indication(struct ks_wlan_private *priv) } DPRINTK(3, "NETBEUI/NetBIOS rx_ind_size=%d\n", rx_ind_size); - memcpy(skb_put(skb, 12), priv->rxp, 12); /* 8802/FDDI MAC copy */ + skb_put_data(skb, priv->rxp, 12); /* 8802/FDDI MAC copy */ temp[0] = (((rx_ind_size - 12) >> 8) & 0xff); /* NETBEUI size add */ temp[1] = ((rx_ind_size - 12) & 0xff); - memcpy(skb_put(skb, 2), temp, 2); + skb_put_data(skb, temp, 2); - memcpy(skb_put(skb, rx_ind_size - 14), priv->rxp + 12, - rx_ind_size - 14); /* copy after Type */ + skb_put_data(skb, priv->rxp + 12, rx_ind_size - 14); /* copy after Type */ aa1x_hdr = (struct ieee802_1x_hdr *)(priv->rxp + 14); break; diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c index ce1764cba5f0..995674f25172 100644 --- a/drivers/staging/most/aim-network/networking.c +++ b/drivers/staging/most/aim-network/networking.c @@ -486,11 +486,11 @@ static int aim_rx_data(struct mbo *mbo) ether_addr_copy(skb_put(skb, ETH_ALEN), dev->dev_addr); /* src */ - memcpy(skb_put(skb, 4), &zero, 4); - memcpy(skb_put(skb, 2), buf + 5, 2); + skb_put_data(skb, &zero, 4); + skb_put_data(skb, buf + 5, 2); /* eth type */ - memcpy(skb_put(skb, 2), buf + 10, 2); + skb_put_data(skb, buf + 10, 2); buf += MDP_HDR_LEN; len -= MDP_HDR_LEN; @@ -499,7 +499,7 @@ static int aim_rx_data(struct mbo *mbo) len -= MEP_HDR_LEN; } - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); skb->protocol = eth_type_trans(skb, dev); skb_len = skb->len; if (netif_rx(skb) == NET_RX_SUCCESS) { diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 65a285631994..72baedefa0f1 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -287,8 +287,7 @@ static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget) else ptr += 6; } - memcpy(skb_put(skb, work->word1.len), ptr, - work->word1.len); + skb_put_data(skb, ptr, work->word1.len); /* No packet buffers to free */ } else { int segments = work->word2.s.bufs; @@ -323,10 +322,9 @@ static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget) if (segment_size > len) segment_size = len; /* Copy the data into the packet */ - memcpy(skb_put(skb, segment_size), - cvmx_phys_to_ptr( - segment_ptr.s.addr), - segment_size); + skb_put_data(skb, + cvmx_phys_to_ptr(segment_ptr.s.addr), + segment_size); len -= segment_size; segment_ptr = next_ptr; } diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index c6c4404e717b..14173cf6e1e7 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -1544,8 +1544,8 @@ static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe) sub_skb = dev_alloc_skb(nSubframe_Length + 12); if (sub_skb) { skb_reserve(sub_skb, 12); - data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); - memcpy(data_ptr, pdata, nSubframe_Length); + data_ptr = skb_put_data(sub_skb, pdata, + nSubframe_Length); } else { sub_skb = skb_clone(prframe->pkt, GFP_ATOMIC); if (sub_skb) { diff --git a/drivers/staging/rtl8188eu/os_dep/mon.c b/drivers/staging/rtl8188eu/os_dep/mon.c index 859d0d6051cd..225c23fc69dc 100644 --- a/drivers/staging/rtl8188eu/os_dep/mon.c +++ b/drivers/staging/rtl8188eu/os_dep/mon.c @@ -53,7 +53,7 @@ static void mon_recv_decrypted(struct net_device *dev, const u8 *data, skb = netdev_alloc_skb(dev, data_len); if (!skb) return; - memcpy(skb_put(skb, data_len), data, data_len); + skb_put_data(skb, data, data_len); /* * Frame data is not encrypted. Strip off protection so diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index 43a77745e6fb..bae98ca0a9b6 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -817,8 +817,7 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb, if (!sub_skb) return 0; skb_reserve(sub_skb, 12); - data_ptr = (u8 *)skb_put(sub_skb, skb->len); - memcpy(data_ptr, skb->data, skb->len); + data_ptr = skb_put_data(sub_skb, skb->data, skb->len); sub_skb->dev = ieee->dev; rxb->subframes[0] = sub_skb; @@ -870,8 +869,7 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb, if (!sub_skb) return 0; skb_reserve(sub_skb, 12); - data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); - memcpy(data_ptr, skb->data, nSubframe_Length); + data_ptr = skb_put_data(sub_skb, skb->data, nSubframe_Length); sub_skb->dev = ieee->dev; rxb->subframes[rxb->nr_subframes++] = sub_skb; @@ -1141,13 +1139,12 @@ static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, /* copy first fragment (including full headers) into * beginning of the fragment cache skb */ - memcpy(skb_put(frag_skb, flen), skb->data, flen); + skb_put_data(frag_skb, skb->data, flen); } else { /* append frame payload to the end of the fragment * cache skb */ - memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, - flen); + skb_put_data(frag_skb, skb->data + hdrlen, flen); } dev_kfree_skb_any(skb); skb = NULL; diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index eeda17d6409b..60d07d0bb4eb 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -1272,8 +1272,7 @@ rtllib_association_req(struct rtllib_network *beacon, hdr->info_element[0].id = MFIE_TYPE_SSID; hdr->info_element[0].len = beacon->ssid_len; - tag = skb_put(skb, beacon->ssid_len); - memcpy(tag, beacon->ssid, beacon->ssid_len); + tag = skb_put_data(skb, beacon->ssid, beacon->ssid_len); tag = skb_put(skb, rate_len); @@ -1349,8 +1348,7 @@ rtllib_association_req(struct rtllib_network *beacon, } if (wpa_ie_len) { - tag = skb_put(skb, ieee->wpa_ie_len); - memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); + tag = skb_put_data(skb, ieee->wpa_ie, ieee->wpa_ie_len); if (PMKCacheIdx >= 0) { tag = skb_put(skb, 18); @@ -1366,8 +1364,7 @@ rtllib_association_req(struct rtllib_network *beacon, } if (wps_ie_len && ieee->wps_ie) { - tag = skb_put(skb, wps_ie_len); - memcpy(tag, ieee->wps_ie, wps_ie_len); + tag = skb_put_data(skb, ieee->wps_ie, wps_ie_len); } tag = skb_put(skb, turbo_info_len); diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c index 78a3ad5b231f..fc88d47dea43 100644 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ b/drivers/staging/rtl8192e/rtllib_tx.c @@ -624,8 +624,7 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) txb->encrypted = 0; txb->payload_size = cpu_to_le16(skb->len); - memcpy(skb_put(txb->fragments[0], skb->len), skb->data, - skb->len); + skb_put_data(txb->fragments[0], skb->data, skb->len); goto success; } @@ -818,9 +817,7 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) } else { tcb_desc->bHwSec = 0; } - frag_hdr = (struct rtllib_hdr_3addrqos *) - skb_put(skb_frag, hdr_len); - memcpy(frag_hdr, &header, hdr_len); + frag_hdr = skb_put_data(skb_frag, &header, hdr_len); /* If this is not the last fragment, then add the * MOREFRAGS bit to the frame control @@ -852,7 +849,7 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) bytes -= SNAP_SIZE + sizeof(u16); } - memcpy(skb_put(skb_frag, bytes), skb->data, bytes); + skb_put_data(skb_frag, skb->data, bytes); /* Advance the SKB... */ skb_pull(skb, bytes); @@ -895,8 +892,7 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) txb->encrypted = 0; txb->payload_size = cpu_to_le16(skb->len); - memcpy(skb_put(txb->fragments[0], skb->len), skb->data, - skb->len); + skb_put_data(txb->fragments[0], skb->data, skb->len); } success: diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index 7a31510f0524..c0e2f711cb4e 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -848,8 +848,8 @@ static u8 parse_subframe(struct sk_buff *skb, if (!sub_skb) return 0; skb_reserve(sub_skb, 12); - data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); - memcpy(data_ptr, skb->data, nSubframe_Length); + data_ptr = skb_put_data(sub_skb, skb->data, + nSubframe_Length); #endif rxb->subframes[rxb->nr_subframes++] = sub_skb; if (rxb->nr_subframes >= MAX_SUBFRAME_COUNT) { @@ -1180,12 +1180,11 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, if (frag == 0) { /* copy first fragment (including full headers) into * beginning of the fragment cache skb */ - memcpy(skb_put(frag_skb, flen), skb->data, flen); + skb_put_data(frag_skb, skb->data, flen); } else { /* append frame payload to the end of the fragment * cache skb */ - memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, - flen); + skb_put_data(frag_skb, skb->data + hdrlen, flen); } dev_kfree_skb_any(skb); skb = NULL; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 14aea26804f4..903a1d0269df 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -1115,8 +1115,7 @@ ieee80211_association_req(struct ieee80211_network *beacon, hdr->info_element[0].id = MFIE_TYPE_SSID; hdr->info_element[0].len = beacon->ssid_len; - tag = skb_put(skb, beacon->ssid_len); - memcpy(tag, beacon->ssid, beacon->ssid_len); + tag = skb_put_data(skb, beacon->ssid, beacon->ssid_len); tag = skb_put(skb, rate_len); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c index bdb96a45a9eb..f58971a4a2e3 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c @@ -794,8 +794,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { tcb_desc->bHwSec = 0; } - frag_hdr = (struct rtl_80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); - memcpy(frag_hdr, &header, hdr_len); + frag_hdr = skb_put_data(skb_frag, &header, hdr_len); /* If this is not the last fragment, then add the MOREFRAGS * bit to the frame control @@ -826,7 +825,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) bytes -= SNAP_SIZE + sizeof(u16); } - memcpy(skb_put(skb_frag, bytes), skb->data, bytes); + skb_put_data(skb_frag, skb->data, bytes); /* Advance the SKB... */ skb_pull(skb, bytes); @@ -869,7 +868,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) txb->encrypted = 0; txb->payload_size = __cpu_to_le16(skb->len); - memcpy(skb_put(txb->fragments[0],skb->len), skb->data, skb->len); + skb_put_data(txb->fragments[0], skb->data, skb->len); } success: diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c index bb6d8bd6c7ac..c3cf01c842a3 100644 --- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c +++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c @@ -45,8 +45,7 @@ rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen) tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL; tcb_desc->bLastIniPkt = 0; skb_reserve(skb, USB_HWDESC_HEADER_LEN); - ptr_buf = skb_put(skb, DataLen); - memcpy(ptr_buf, pData, DataLen); + ptr_buf = skb_put_data(skb, pData, DataLen); tcb_desc->txbuf_size = (u16)DataLen; if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) || diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index 266ffefd55ed..f96c558b3c6a 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -372,8 +372,7 @@ static int amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe) if (!sub_skb) break; skb_reserve(sub_skb, 12); - data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); - memcpy(data_ptr, pdata, nSubframe_Length); + data_ptr = skb_put_data(sub_skb, pdata, nSubframe_Length); subframes[nr_subframes++] = sub_skb; if (nr_subframes >= MAX_SUBFRAME_COUNT) { netdev_warn(padapter->pnetdev, "r8712u: ParseSubframe(): Too many Subframes! Packets dropped!\n"); diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index e731ab4e2bd7..1a6443dc3ff0 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -82,8 +82,8 @@ _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 if (sub_skb) { skb_reserve(sub_skb, 12); - data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); - memcpy(data_ptr, (pdata + ETH_HLEN), nSubframe_Length); + data_ptr = skb_put_data(sub_skb, (pdata + ETH_HLEN), + nSubframe_Length); } else { diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c index c9782d452b07..dbc266a37974 100644 --- a/drivers/staging/wilc1000/linux_mon.c +++ b/drivers/staging/wilc1000/linux_mon.c @@ -72,7 +72,7 @@ void WILC_WFI_monitor_rx(u8 *buff, u32 size) if (!skb) return; - memcpy(skb_put(skb, size), buff, size); + skb_put_data(skb, buff, size); cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *)skb_push(skb, sizeof(*cb_hdr)); memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); @@ -100,7 +100,7 @@ void WILC_WFI_monitor_rx(u8 *buff, u32 size) if (!skb) return; - memcpy(skb_put(skb, size), buff, size); + skb_put_data(skb, buff, size); hdr = (struct wilc_wfi_radiotap_hdr *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr)); hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ @@ -200,7 +200,7 @@ static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb, if (!skb2) return -ENOMEM; - memcpy(skb_put(skb2, skb->len), skb->data, skb->len); + skb_put_data(skb2, skb->data, skb->len); cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *)skb_push(skb2, sizeof(*cb_hdr)); memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index d6d803416be2..f36598a89ce0 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -1160,7 +1160,7 @@ void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset) skb->dev = wilc_netdev; - memcpy(skb_put(skb, frame_len), buff_to_send, frame_len); + skb_put_data(skb, buff_to_send, frame_len); skb->protocol = eth_type_trans(skb, wilc_netdev); vif->netstats.rx_packets++; diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c index a812e55ba1b0..1de67f209f2c 100644 --- a/drivers/staging/wlan-ng/hfa384x_usb.c +++ b/drivers/staging/wlan-ng/hfa384x_usb.c @@ -3530,13 +3530,11 @@ static void hfa384x_int_rxmonitor(struct wlandevice *wlandev, /* Copy the 802.11 header to the skb * (ctl frames may be less than a full header) */ - datap = skb_put(skb, hdrlen); - memcpy(datap, &rxdesc->frame_control, hdrlen); + datap = skb_put_data(skb, &rxdesc->frame_control, hdrlen); /* If any, copy the data from the card to the skb */ if (datalen > 0) { - datap = skb_put(skb, datalen); - memcpy(datap, rxfrm->data, datalen); + datap = skb_put_data(skb, rxfrm->data, datalen); /* check for unencrypted stuff if WEP bit set. */ if (*(datap - hdrlen + 1) & 0x40) /* wep set */ diff --git a/drivers/tty/ipwireless/network.c b/drivers/tty/ipwireless/network.c index c0dfb642383b..c2f9a3263b37 100644 --- a/drivers/tty/ipwireless/network.c +++ b/drivers/tty/ipwireless/network.c @@ -355,7 +355,7 @@ static struct sk_buff *ipw_packet_received_skb(unsigned char *data, if (skb == NULL) return NULL; skb_reserve(skb, 2); - memcpy(skb_put(skb, length), data, length); + skb_put_data(skb, data, length); return skb; } diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 2667a205a5ab..da830f833392 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2688,7 +2688,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, return; } skb_reserve(skb, NET_IP_ALIGN); - memcpy(skb_put(skb, size), in_buf, size); + skb_put_data(skb, in_buf, size); skb->dev = net; skb->protocol = htons(ETH_P_IP); diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index a2c308f7d637..3fafc5a1b2e0 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -7960,7 +7960,7 @@ static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size) return; } - memcpy(skb_put(skb, size), buf, size); + skb_put_data(skb, buf, size); skb->protocol = hdlc_type_trans(skb, dev); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 31885f20fc15..7e947ecf15f1 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1755,7 +1755,7 @@ static void hdlcdev_rx(struct slgt_info *info, char *buf, int size) return; } - memcpy(skb_put(skb, size), buf, size); + skb_put_data(skb, buf, size); skb->protocol = hdlc_type_trans(skb, dev); diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 51e8846cd68f..9b4fb0251c1a 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1874,7 +1874,7 @@ static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size) return; } - memcpy(skb_put(skb, size), buf, size); + skb_put_data(skb, buf, size); skb->protocol = hdlc_type_trans(skb, dev); diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 2882c6d3ae66..630616aaa861 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1007,8 +1007,8 @@ static struct sk_buff *package_for_tx(struct f_ncm *ncm) ntb_iter = skb_put_zero(skb2, ndp_pad); /* Copy NTB across. */ - ntb_iter = (void *) skb_put(skb2, ncm->skb_tx_ndp->len); - memcpy(ntb_iter, ncm->skb_tx_ndp->data, ncm->skb_tx_ndp->len); + ntb_iter = skb_put_data(skb2, ncm->skb_tx_ndp->data, + ncm->skb_tx_ndp->len); dev_consume_skb_any(ncm->skb_tx_ndp); ncm->skb_tx_ndp = NULL; @@ -1129,8 +1129,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, /* Add the new data to the skb */ ntb_data = skb_put_zero(ncm->skb_tx_data, dgram_pad); - ntb_data = (void *) skb_put(ncm->skb_tx_data, skb->len); - memcpy(ntb_data, skb->data, skb->len); + ntb_data = skb_put_data(ncm->skb_tx_data, skb->data, skb->len); dev_consume_skb_any(skb); skb = NULL; @@ -1313,8 +1312,8 @@ static int ncm_unwrap_ntb(struct gether *port, dg_len - crc_len); if (skb2 == NULL) goto err; - memcpy(skb_put(skb2, dg_len - crc_len), - skb->data + index, dg_len - crc_len); + skb_put_data(skb2, skb->data + index, + dg_len - crc_len); skb_queue_tail(list, skb2); diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c index 6a1ce6a55158..9c4c58e4a1a2 100644 --- a/drivers/usb/gadget/function/f_phonet.c +++ b/drivers/usb/gadget/function/f_phonet.c @@ -336,7 +336,7 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) skb->protocol = htons(ETH_P_PHONET); skb_reset_mac_header(skb); /* Can't use pskb_pull() on page in IRQ */ - memcpy(skb_put(skb, 1), page_address(page), 1); + skb_put_data(skb, page_address(page), 1); } skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, -- cgit v1.2.3 From 4df864c1d9afb46e2461a9f808d9f11a42d31bad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Jun 2017 14:29:21 +0200 Subject: networking: make skb_put & friends return void pointers It seems like a historic accident that these return unsigned char *, and in many places that means casts are required, more often than not. Make these functions (skb_put, __skb_put and pskb_put) return void * and remove all the casts across the tree, adding a (u8 *) cast only where the unsigned char pointer was used directly, all done with the following spatch: @@ expression SKB, LEN; typedef u8; identifier fn = { skb_put, __skb_put }; @@ - *(fn(SKB, LEN)) + *(u8 *)fn(SKB, LEN) @@ expression E, SKB, LEN; identifier fn = { skb_put, __skb_put }; type T; @@ - E = ((T *)(fn(SKB, LEN))) + E = fn(SKB, LEN) which actually doesn't cover pskb_put since there are only three users overall. A handful of stragglers were converted manually, notably a macro in drivers/isdn/i4l/isdn_bsdcomp.c and, oddly enough, one of the many instances in net/bluetooth/hci_sock.c. In the former file, I also had to fix one whitespace problem spatch introduced. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/atm/atmtcp.c | 4 +- drivers/atm/solos-pci.c | 12 +++--- drivers/bluetooth/bluecard_cs.c | 2 +- drivers/bluetooth/bt3c_cs.c | 2 +- drivers/bluetooth/btmrvl_main.c | 2 +- drivers/bluetooth/btuart_cs.c | 2 +- drivers/bluetooth/btusb.c | 10 ++--- drivers/bluetooth/dtl1_cs.c | 4 +- drivers/bluetooth/hci_bcm.c | 6 +-- drivers/bluetooth/hci_intel.c | 6 +-- drivers/bluetooth/hci_ll.c | 2 +- drivers/bluetooth/hci_nokia.c | 10 ++--- drivers/bluetooth/hci_qca.c | 2 +- drivers/bluetooth/hci_vhci.c | 4 +- drivers/crypto/chelsio/chcr_algo.c | 10 ++--- drivers/infiniband/core/addr.c | 3 +- drivers/infiniband/core/sa_query.c | 3 +- drivers/infiniband/hw/cxgb3/cxio_hal.c | 2 +- drivers/infiniband/hw/cxgb3/iwch_cm.c | 22 +++++------ drivers/infiniband/hw/cxgb4/cm.c | 22 +++++------ drivers/infiniband/hw/cxgb4/cq.c | 4 +- drivers/infiniband/hw/cxgb4/mem.c | 4 +- drivers/infiniband/hw/cxgb4/qp.c | 8 ++-- drivers/isdn/capi/capi.c | 4 +- drivers/isdn/gigaset/asyncdata.c | 26 ++++++------- drivers/isdn/gigaset/isocdata.c | 2 +- drivers/isdn/i4l/isdn_audio.c | 4 +- drivers/isdn/i4l/isdn_bsdcomp.c | 8 ++-- drivers/isdn/i4l/isdn_x25iface.c | 4 +- drivers/media/dvb-core/dvb_net.c | 2 +- drivers/media/radio/wl128x/fmdrv_common.c | 2 +- drivers/net/bonding/bond_3ad.c | 4 +- drivers/net/can/dev.c | 4 +- drivers/net/ethernet/allwinner/sun4i-emac.c | 2 +- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 12 +++--- drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c | 4 +- drivers/net/ethernet/chelsio/cxgb3/l2t.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 4 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 8 ++-- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 2 +- drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.h | 10 ++--- drivers/net/ethernet/davicom/dm9000.c | 2 +- drivers/net/ethernet/dnet.c | 2 +- drivers/net/ethernet/hp/hp100.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_selftest.c | 4 +- .../net/ethernet/mellanox/mlx5/core/en_selftest.c | 6 +-- drivers/net/ethernet/micrel/ks8842.c | 4 +- drivers/net/ethernet/sfc/falcon/selftest.c | 3 +- drivers/net/ethernet/sfc/selftest.c | 3 +- drivers/net/hamradio/scc.c | 4 +- drivers/net/ppp/pppoe.c | 2 +- drivers/net/usb/cdc_ncm.c | 2 +- drivers/net/usb/net1080.c | 4 +- drivers/net/usb/zaurus.c | 8 ++-- drivers/net/wan/hdlc_ppp.c | 2 +- drivers/net/wireless/ath/ath6kl/debug.c | 2 +- drivers/net/wireless/ath/ath6kl/htc_pipe.c | 6 +-- drivers/net/wireless/ath/ath9k/htc_hst.c | 9 ++--- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- drivers/net/wireless/cisco/airo.c | 4 +- drivers/net/wireless/intel/ipw2x00/ipw2200.c | 2 +- drivers/net/wireless/intel/ipw2x00/libipw_tx.c | 3 +- drivers/net/wireless/intersil/hostap/hostap_ap.c | 2 +- drivers/net/wireless/intersil/p54/fwio.c | 43 +++++++++++----------- drivers/net/wireless/mac80211_hwsim.c | 8 ++-- drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 2 +- drivers/net/wireless/marvell/mwifiex/tdls.c | 38 +++++++++---------- .../net/wireless/quantenna/qtnfmac/qlink_util.h | 11 ++---- drivers/net/wireless/ralink/rt2x00/rt2x00debug.c | 2 +- .../net/wireless/realtek/rtlwifi/rtl8192se/fw.c | 2 +- drivers/nfc/fdp/i2c.c | 2 +- drivers/nfc/microread/i2c.c | 4 +- drivers/nfc/microread/microread.c | 4 +- drivers/nfc/nfcmrvl/fw_dnld.c | 6 +-- drivers/nfc/pn533/pn533.c | 32 ++++++++-------- drivers/nfc/pn544/i2c.c | 6 +-- drivers/nfc/port100.c | 4 +- drivers/nfc/st21nfca/i2c.c | 6 +-- drivers/nfc/st95hf/core.c | 2 +- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 2 +- drivers/scsi/fcoe/fcoe.c | 2 +- drivers/scsi/qedf/qedf_main.c | 2 +- drivers/staging/rtl8192e/rtl819x_BAProc.c | 10 ++--- drivers/staging/rtl8192e/rtllib_softmac.c | 34 ++++++----------- .../staging/rtl8192u/ieee80211/ieee80211_softmac.c | 21 +++++------ .../staging/rtl8192u/ieee80211/rtl819x_BAProc.c | 8 ++-- drivers/target/iscsi/cxgbit/cxgbit_cm.c | 8 ++-- drivers/target/iscsi/cxgbit/cxgbit_ddp.c | 2 +- drivers/usb/gadget/function/f_ncm.c | 5 +-- 91 files changed, 282 insertions(+), 316 deletions(-) (limited to 'drivers') diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c index 3ef6253e1cce..56fa16c85ebf 100644 --- a/drivers/atm/atmtcp.c +++ b/drivers/atm/atmtcp.c @@ -60,7 +60,7 @@ static int atmtcp_send_control(struct atm_vcc *vcc,int type, return -EUNATCH; } atm_force_charge(out_vcc,skb->truesize); - new_msg = (struct atmtcp_control *) skb_put(skb,sizeof(*new_msg)); + new_msg = skb_put(skb, sizeof(*new_msg)); *new_msg = *msg; new_msg->hdr.length = ATMTCP_HDR_MAGIC; new_msg->type = type; @@ -217,7 +217,7 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb) atomic_inc(&vcc->stats->tx_err); return -ENOBUFS; } - hdr = (void *) skb_put(new_skb,sizeof(struct atmtcp_hdr)); + hdr = skb_put(new_skb, sizeof(struct atmtcp_hdr)); hdr->vpi = htons(vcc->vpi); hdr->vci = htons(vcc->vci); hdr->length = htonl(skb->len); diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 077dd15c3a40..4fc99ae1c534 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -205,7 +205,7 @@ static ssize_t solos_param_show(struct device *dev, struct device_attribute *att return -ENOMEM; } - header = (void *)skb_put(skb, sizeof(*header)); + header = skb_put(skb, sizeof(*header)); buflen = snprintf((void *)&header[1], buflen - 1, "L%05d\n%s\n", current->pid, attr->attr.name); @@ -261,7 +261,7 @@ static ssize_t solos_param_store(struct device *dev, struct device_attribute *at return -ENOMEM; } - header = (void *)skb_put(skb, sizeof(*header)); + header = skb_put(skb, sizeof(*header)); buflen = snprintf((void *)&header[1], buflen - 1, "L%05d\n%s\n%s\n", current->pid, attr->attr.name, buf); @@ -486,7 +486,7 @@ static int send_command(struct solos_card *card, int dev, const char *buf, size_ return 0; } - header = (void *)skb_put(skb, sizeof(*header)); + header = skb_put(skb, sizeof(*header)); header->size = cpu_to_le16(size); header->vpi = cpu_to_le16(0); @@ -945,7 +945,7 @@ static int popen(struct atm_vcc *vcc) dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); return -ENOMEM; } - header = (void *)skb_put(skb, sizeof(*header)); + header = skb_put(skb, sizeof(*header)); header->size = cpu_to_le16(0); header->vpi = cpu_to_le16(vcc->vpi); @@ -982,7 +982,7 @@ static void pclose(struct atm_vcc *vcc) dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); return; } - header = (void *)skb_put(skb, sizeof(*header)); + header = skb_put(skb, sizeof(*header)); header->size = cpu_to_le16(0); header->vpi = cpu_to_le16(vcc->vpi); @@ -1398,7 +1398,7 @@ static int atm_init(struct solos_card *card, struct device *parent) continue; } - header = (void *)skb_put(skb, sizeof(*header)); + header = skb_put(skb, sizeof(*header)); header->size = cpu_to_le16(0); header->vpi = cpu_to_le16(0); diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 1d30c116b2ee..39a05b0c8998 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -448,7 +448,7 @@ static void bluecard_receive(struct bluecard_info *info, } else { - *skb_put(info->rx_skb, 1) = buf[i]; + *(u8 *)skb_put(info->rx_skb, 1) = buf[i]; info->rx_count--; if (info->rx_count == 0) { diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 8165ef2fe877..be2d431aa366 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -282,7 +282,7 @@ static void bt3c_receive(struct bt3c_info *info) __u8 x = inb(iobase + DATA_L); - *skb_put(info->rx_skb, 1) = x; + *(u8 *)skb_put(info->rx_skb, 1) = x; inb(iobase + DATA_H); info->rx_count--; diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 24a188eab360..8d3d9175d891 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -189,7 +189,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode, return -ENOMEM; } - hdr = (struct hci_command_hdr *)skb_put(skb, HCI_COMMAND_HDR_SIZE); + hdr = skb_put(skb, HCI_COMMAND_HDR_SIZE); hdr->opcode = cpu_to_le16(opcode); hdr->plen = len; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 9624b29f8349..80b64e9684a3 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -233,7 +233,7 @@ static void btuart_receive(struct btuart_info *info) } else { - *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); + *(u8 *)skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); info->rx_count--; if (info->rx_count == 0) { diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c7ea398e65c1..ba207c787605 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1836,15 +1836,15 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) if (!skb) return -ENOMEM; - hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); hdr->evt = HCI_EV_CMD_COMPLETE; hdr->plen = sizeof(*evt) + 1; - evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt)); + evt = skb_put(skb, sizeof(*evt)); evt->ncmd = 0x01; evt->opcode = cpu_to_le16(opcode); - *skb_put(skb, 1) = 0x00; + *(u8 *)skb_put(skb, 1) = 0x00; hci_skb_pkt_type(skb) = HCI_EVENT_PKT; @@ -2767,8 +2767,8 @@ static struct urb *alloc_diag_urb(struct hci_dev *hdev, bool enable) return ERR_PTR(-ENOMEM); } - *skb_put(skb, 1) = 0xf0; - *skb_put(skb, 1) = enable; + *(u8 *)skb_put(skb, 1) = 0xf0; + *(u8 *)skb_put(skb, 1) = enable; pipe = usb_sndbulkpipe(data->udev, data->diag_tx_ep->bEndpointAddress); diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 6317c6f323bf..6c5a3aa566a4 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -226,7 +226,7 @@ static void dtl1_receive(struct dtl1_info *info) } } - *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); + *(u8 *)skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); nsh = (struct nsh *)info->rx_skb->data; info->rx_count--; @@ -414,7 +414,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) skb_reserve(s, NSHL); skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len); if (skb->len & 0x0001) - *skb_put(s, 1) = 0; /* PAD */ + *(u8 *)skb_put(s, 1) = 0; /* PAD */ /* Prepend skb with Nokia frame header and queue */ memcpy(skb_push(s, NSHL), &nsh, NSHL); diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index e2096c7803b3..c1c4048ee37d 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -262,9 +262,9 @@ static int bcm_set_diag(struct hci_dev *hdev, bool enable) if (!skb) return -ENOMEM; - *skb_put(skb, 1) = BCM_LM_DIAG_PKT; - *skb_put(skb, 1) = 0xf0; - *skb_put(skb, 1) = enable; + *(u8 *)skb_put(skb, 1) = BCM_LM_DIAG_PKT; + *(u8 *)skb_put(skb, 1) = 0xf0; + *(u8 *)skb_put(skb, 1) = enable; skb_queue_tail(&bcm->txq, skb); hci_uart_tx_wakeup(hu); diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 16e728577cd8..ee97c465e32e 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -462,15 +462,15 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) if (!skb) return -ENOMEM; - hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); hdr->evt = HCI_EV_CMD_COMPLETE; hdr->plen = sizeof(*evt) + 1; - evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt)); + evt = skb_put(skb, sizeof(*evt)); evt->ncmd = 0x01; evt->opcode = cpu_to_le16(opcode); - *skb_put(skb, 1) = 0x00; + *(u8 *)skb_put(skb, 1) = 0x00; hci_skb_pkt_type(skb) = HCI_EVENT_PKT; diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index cc2fa78b434e..c982943f0747 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -120,7 +120,7 @@ static int send_hcill_cmd(u8 cmd, struct hci_uart *hu) } /* prepare packet */ - hcill_packet = (struct hcill_cmd *) skb_put(skb, 1); + hcill_packet = skb_put(skb, 1); hcill_packet->cmd = cmd; /* send packet */ diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c index a7d687d8d456..c1b081725b2c 100644 --- a/drivers/bluetooth/hci_nokia.c +++ b/drivers/bluetooth/hci_nokia.c @@ -246,9 +246,9 @@ static int nokia_send_alive_packet(struct hci_uart *hu) hci_skb_pkt_type(skb) = HCI_NOKIA_ALIVE_PKT; memset(skb->data, 0x00, len); - hdr = (struct hci_nokia_alive_hdr *)skb_put(skb, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); hdr->dlen = sizeof(*pkt); - pkt = (struct hci_nokia_alive_pkt *)skb_put(skb, sizeof(*pkt)); + pkt = skb_put(skb, sizeof(*pkt)); pkt->mid = NOKIA_ALIVE_REQ; nokia_enqueue(hu, skb); @@ -285,10 +285,10 @@ static int nokia_send_negotiation(struct hci_uart *hu) hci_skb_pkt_type(skb) = HCI_NOKIA_NEG_PKT; - neg_hdr = (struct hci_nokia_neg_hdr *)skb_put(skb, sizeof(*neg_hdr)); + neg_hdr = skb_put(skb, sizeof(*neg_hdr)); neg_hdr->dlen = sizeof(*neg_cmd); - neg_cmd = (struct hci_nokia_neg_cmd *)skb_put(skb, sizeof(*neg_cmd)); + neg_cmd = skb_put(skb, sizeof(*neg_cmd)); neg_cmd->ack = NOKIA_NEG_REQ; neg_cmd->baud = cpu_to_le16(baud); neg_cmd->unused1 = 0x0000; @@ -532,7 +532,7 @@ static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb) err = skb_pad(skb, 1); if (err) return err; - *skb_put(skb, 1) = 0x00; + *(u8 *)skb_put(skb, 1) = 0x00; } skb_queue_tail(&btdev->txq, skb); diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index b55f01320631..e2c88515340a 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -215,7 +215,7 @@ static int send_hci_ibs_cmd(u8 cmd, struct hci_uart *hu) } /* Assign HCI_IBS type */ - *skb_put(skb, 1) = cmd; + *(u8 *)skb_put(skb, 1) = cmd; skb_queue_tail(&qca->txq, skb); diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 233e850fdac7..1ef9c427a2d8 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -146,8 +146,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) hci_skb_pkt_type(skb) = HCI_VENDOR_PKT; - *skb_put(skb, 1) = 0xff; - *skb_put(skb, 1) = opcode; + *(u8 *)skb_put(skb, 1) = 0xff; + *(u8 *)skb_put(skb, 1) = opcode; put_unaligned_le16(hdev->id, skb_put(skb, 2)); skb_queue_tail(&data->readq, skb); diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index f00e0d8bd039..92185ab6797d 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -604,7 +604,7 @@ static struct sk_buff if (!skb) return ERR_PTR(-ENOMEM); skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - chcr_req = (struct chcr_wr *)__skb_put(skb, transhdr_len); + chcr_req = __skb_put(skb, transhdr_len); memset(chcr_req, 0, transhdr_len); chcr_req->sec_cpl.op_ivinsrtofst = FILL_SEC_CPL_OP_IVINSR(ctx->dev->rx_channel_id, 2, 1); @@ -881,7 +881,7 @@ static struct sk_buff *create_hash_wr(struct ahash_request *req, return skb; skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - chcr_req = (struct chcr_wr *)__skb_put(skb, transhdr_len); + chcr_req = __skb_put(skb, transhdr_len); memset(chcr_req, 0, transhdr_len); chcr_req->sec_cpl.op_ivinsrtofst = @@ -1447,7 +1447,7 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, skb_reserve(skb, sizeof(struct sge_opaque_hdr)); /* Write WR */ - chcr_req = (struct chcr_wr *) __skb_put(skb, transhdr_len); + chcr_req = __skb_put(skb, transhdr_len); memset(chcr_req, 0, transhdr_len); stop_offset = (op_type == CHCR_ENCRYPT_OP) ? 0 : authsize; @@ -1779,7 +1779,7 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - chcr_req = (struct chcr_wr *) __skb_put(skb, transhdr_len); + chcr_req = __skb_put(skb, transhdr_len); memset(chcr_req, 0, transhdr_len); fill_sec_cpl_for_aead(&chcr_req->sec_cpl, dst_size, req, op_type, ctx); @@ -1892,7 +1892,7 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, /* NIC driver is going to write the sge hdr. */ skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - chcr_req = (struct chcr_wr *)__skb_put(skb, transhdr_len); + chcr_req = __skb_put(skb, transhdr_len); memset(chcr_req, 0, transhdr_len); if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 02971e239a18..d2957b38575f 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -179,8 +179,7 @@ static int ib_nl_ip_send_msg(struct rdma_dev_addr *dev_addr, } /* Construct the family header first */ - header = (struct rdma_ls_ip_resolve_header *) - skb_put(skb, NLMSG_ALIGN(sizeof(*header))); + header = skb_put(skb, NLMSG_ALIGN(sizeof(*header))); header->ifindex = dev_addr->bound_dev_if; nla_put(skb, attrtype, size, daddr); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index fb7aec4047c8..70fa4cabe48e 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -759,8 +759,7 @@ static void ib_nl_set_path_rec_attrs(struct sk_buff *skb, query->mad_buf->context[1] = NULL; /* Construct the family header first */ - header = (struct rdma_ls_resolve_header *) - skb_put(skb, NLMSG_ALIGN(sizeof(*header))); + header = skb_put(skb, NLMSG_ALIGN(sizeof(*header))); memcpy(header->device_name, query->port->agent->device->name, LS_DEVICE_NAME_MAX); header->port_num = query->port->port_num; diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 97f7f9544e70..3eff6541bd6f 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -835,7 +835,7 @@ int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr) if (!skb) return -ENOMEM; pr_debug("%s rdev_p %p\n", __func__, rdev_p); - wqe = (struct t3_rdma_init_wr *) __skb_put(skb, sizeof(*wqe)); + wqe = __skb_put(skb, sizeof(*wqe)); wqe->wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_INIT)); wqe->wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(attr->tid) | V_FW_RIWR_LEN(sizeof(*wqe) >> 3)); diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index f4c23a74f18c..9ae518c01bc2 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -175,7 +175,7 @@ static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb) skb = get_skb(skb, sizeof *req, GFP_KERNEL); if (!skb) return; - req = (struct cpl_tid_release *) skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, hwtid)); skb->priority = CPL_PRIORITY_SETUP; @@ -190,7 +190,7 @@ int iwch_quiesce_tid(struct iwch_ep *ep) if (!skb) return -ENOMEM; - req = (struct cpl_set_tcb_field *) skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, ep->hwtid)); @@ -211,7 +211,7 @@ int iwch_resume_tid(struct iwch_ep *ep) if (!skb) return -ENOMEM; - req = (struct cpl_set_tcb_field *) skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, ep->hwtid)); @@ -398,7 +398,7 @@ static int send_halfclose(struct iwch_ep *ep, gfp_t gfp) } skb->priority = CPL_PRIORITY_DATA; set_arp_failure_handler(skb, arp_failure_discard); - req = (struct cpl_close_con_req *) skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON)); req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, ep->hwtid)); @@ -455,7 +455,7 @@ static int send_connect(struct iwch_ep *ep) skb->priority = CPL_PRIORITY_SETUP; set_arp_failure_handler(skb, act_open_req_arp_failure); - req = (struct cpl_act_open_req *) skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, ep->atid)); req->local_port = ep->com.local_addr.sin_port; @@ -546,7 +546,7 @@ static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen) return -ENOMEM; } skb_reserve(skb, sizeof(*req)); - mpa = (struct mpa_message *) skb_put(skb, mpalen); + mpa = skb_put(skb, mpalen); memset(mpa, 0, sizeof(*mpa)); memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key)); mpa->flags = MPA_REJECT; @@ -596,7 +596,7 @@ static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen) } skb->priority = CPL_PRIORITY_DATA; skb_reserve(skb, sizeof(*req)); - mpa = (struct mpa_message *) skb_put(skb, mpalen); + mpa = skb_put(skb, mpalen); memset(mpa, 0, sizeof(*mpa)); memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key)); mpa->flags = (ep->mpa_attr.crc_enabled ? MPA_CRC : 0) | @@ -800,7 +800,7 @@ static int update_rx_credits(struct iwch_ep *ep, u32 credits) return 0; } - req = (struct cpl_rx_data_ack *) skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, ep->hwtid)); req->credit_dack = htonl(V_RX_CREDITS(credits) | V_RX_FORCE_ACK(1)); @@ -1205,7 +1205,7 @@ static int listen_start(struct iwch_listen_ep *ep) return -ENOMEM; } - req = (struct cpl_pass_open_req *) skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, ep->stid)); req->local_port = ep->com.local_addr.sin_port; @@ -1246,7 +1246,7 @@ static int listen_stop(struct iwch_listen_ep *ep) pr_err("%s - failed to alloc skb\n", __func__); return -ENOMEM; } - req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); req->cpu_idx = 0; OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid)); @@ -1614,7 +1614,7 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) goto out; } rpl_skb->priority = CPL_PRIORITY_DATA; - rpl = (struct cpl_abort_rpl *) skb_put(rpl_skb, sizeof(*rpl)); + rpl = skb_put(rpl_skb, sizeof(*rpl)); rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); rpl->wr.wr_lo = htonl(V_WR_TID(ep->hwtid)); OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid)); diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 7c32a7c7977d..36ae3023e703 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -597,7 +597,7 @@ static int send_flowc(struct c4iw_ep *ep) else nparams = 9; - flowc = (struct fw_flowc_wr *)__skb_put(skb, FLOWC_LEN); + flowc = __skb_put(skb, FLOWC_LEN); flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS_V(nparams)); @@ -787,18 +787,16 @@ static int send_connect(struct c4iw_ep *ep) if (ep->com.remote_addr.ss_family == AF_INET) { switch (CHELSIO_CHIP_VERSION(adapter_type)) { case CHELSIO_T4: - req = (struct cpl_act_open_req *)skb_put(skb, wrlen); + req = skb_put(skb, wrlen); INIT_TP_WR(req, 0); break; case CHELSIO_T5: - t5req = (struct cpl_t5_act_open_req *)skb_put(skb, - wrlen); + t5req = skb_put(skb, wrlen); INIT_TP_WR(t5req, 0); req = (struct cpl_act_open_req *)t5req; break; case CHELSIO_T6: - t6req = (struct cpl_t6_act_open_req *)skb_put(skb, - wrlen); + t6req = skb_put(skb, wrlen); INIT_TP_WR(t6req, 0); req = (struct cpl_act_open_req *)t6req; t5req = (struct cpl_t5_act_open_req *)t6req; @@ -839,18 +837,16 @@ static int send_connect(struct c4iw_ep *ep) } else { switch (CHELSIO_CHIP_VERSION(adapter_type)) { case CHELSIO_T4: - req6 = (struct cpl_act_open_req6 *)skb_put(skb, wrlen); + req6 = skb_put(skb, wrlen); INIT_TP_WR(req6, 0); break; case CHELSIO_T5: - t5req6 = (struct cpl_t5_act_open_req6 *)skb_put(skb, - wrlen); + t5req6 = skb_put(skb, wrlen); INIT_TP_WR(t5req6, 0); req6 = (struct cpl_act_open_req6 *)t5req6; break; case CHELSIO_T6: - t6req6 = (struct cpl_t6_act_open_req6 *)skb_put(skb, - wrlen); + t6req6 = skb_put(skb, wrlen); INIT_TP_WR(t6req6, 0); req6 = (struct cpl_act_open_req6 *)t6req6; t5req6 = (struct cpl_t5_act_open_req6 *)t6req6; @@ -1904,7 +1900,7 @@ static int send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid) int win; skb = get_skb(NULL, sizeof(*req), GFP_KERNEL); - req = (struct fw_ofld_connection_wr *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR)); req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16))); @@ -3807,7 +3803,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb, req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL); if (!req_skb) return; - req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req)); + req = __skb_put(req_skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL_F); req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16))); diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index 14de5bde1b63..394cfe2625fe 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -44,7 +44,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, wr_len = sizeof *res_wr + sizeof *res; set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len); + res_wr = __skb_put(skb, wr_len); memset(res_wr, 0, wr_len); res_wr->op_nres = cpu_to_be32( FW_WR_OP_V(FW_RI_RES_WR) | @@ -114,7 +114,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, } set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len); + res_wr = __skb_put(skb, wr_len); memset(res_wr, 0, wr_len); res_wr->op_nres = cpu_to_be32( FW_WR_OP_V(FW_RI_RES_WR) | diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index 3ee7f43e419a..ca992e4b66e4 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -81,7 +81,7 @@ static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr, } set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - req = (struct ulp_mem_io *)__skb_put(skb, wr_len); + req = __skb_put(skb, wr_len); memset(req, 0, wr_len); INIT_ULPTX_WR(req, wr_len, 0, 0); req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) | @@ -142,7 +142,7 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len, } set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - req = (struct ulp_mem_io *)__skb_put(skb, wr_len); + req = __skb_put(skb, wr_len); memset(req, 0, wr_len); INIT_ULPTX_WR(req, wr_len, 0, 0); diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 8e4154b4253e..b23a0b057347 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -293,7 +293,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, } set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len); + res_wr = __skb_put(skb, wr_len); memset(res_wr, 0, wr_len); res_wr->op_nres = cpu_to_be32( FW_WR_OP_V(FW_RI_RES_WR) | @@ -1228,7 +1228,7 @@ static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe, set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx); - wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe)); + wqe = __skb_put(skb, sizeof(*wqe)); memset(wqe, 0, sizeof *wqe); wqe->op_compl = cpu_to_be32(FW_WR_OP_V(FW_RI_INIT_WR)); wqe->flowid_len16 = cpu_to_be32( @@ -1350,7 +1350,7 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp, set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx); - wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe)); + wqe = __skb_put(skb, sizeof(*wqe)); memset(wqe, 0, sizeof *wqe); wqe->op_compl = cpu_to_be32( FW_WR_OP_V(FW_RI_INIT_WR) | @@ -1419,7 +1419,7 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp) } set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx); - wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe)); + wqe = __skb_put(skb, sizeof(*wqe)); memset(wqe, 0, sizeof *wqe); wqe->op_compl = cpu_to_be32( FW_WR_OP_V(FW_RI_INIT_WR) | diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 77be17590866..96f586d34d2d 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1082,7 +1082,7 @@ static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) skb = mp->outskb; if (skb) { if (skb_tailroom(skb) > 0) { - *(skb_put(skb, 1)) = ch; + *(u8 *)skb_put(skb, 1) = ch; goto unlock_out; } mp->outskb = NULL; @@ -1094,7 +1094,7 @@ static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + CAPI_MAX_BLKSIZE, GFP_ATOMIC); if (skb) { skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); - *(skb_put(skb, 1)) = ch; + *(u8 *)skb_put(skb, 1) = ch; mp->outskb = skb; } else { printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index c90dca5abeac..03ac9fbfe318 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -264,7 +264,7 @@ byte_stuff: /* skip remainder of packet */ bcs->rx_skb = skb = NULL; } else { - *__skb_put(skb, 1) = c; + *(u8 *)__skb_put(skb, 1) = c; fcs = crc_ccitt_byte(fcs, c); } } @@ -315,7 +315,7 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) /* regular data byte: append to current skb */ inputstate |= INS_have_data; - *__skb_put(skb, 1) = bitrev8(c); + *(u8 *)__skb_put(skb, 1) = bitrev8(c); } /* pass data up */ @@ -492,33 +492,33 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb) hdlc_skb->mac_len = skb->mac_len; /* Add flag sequence in front of everything.. */ - *(skb_put(hdlc_skb, 1)) = PPP_FLAG; + *(u8 *)skb_put(hdlc_skb, 1) = PPP_FLAG; /* Perform byte stuffing while copying data. */ while (skb->len--) { if (muststuff(*skb->data)) { - *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE; - *(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS; + *(u8 *)skb_put(hdlc_skb, 1) = PPP_ESCAPE; + *(u8 *)skb_put(hdlc_skb, 1) = (*skb->data++) ^ PPP_TRANS; } else - *(skb_put(hdlc_skb, 1)) = *skb->data++; + *(u8 *)skb_put(hdlc_skb, 1) = *skb->data++; } /* Finally add FCS (byte stuffed) and flag sequence */ c = (fcs & 0x00ff); /* least significant byte first */ if (muststuff(c)) { - *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE; + *(u8 *)skb_put(hdlc_skb, 1) = PPP_ESCAPE; c ^= PPP_TRANS; } - *(skb_put(hdlc_skb, 1)) = c; + *(u8 *)skb_put(hdlc_skb, 1) = c; c = ((fcs >> 8) & 0x00ff); if (muststuff(c)) { - *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE; + *(u8 *)skb_put(hdlc_skb, 1) = PPP_ESCAPE; c ^= PPP_TRANS; } - *(skb_put(hdlc_skb, 1)) = c; + *(u8 *)skb_put(hdlc_skb, 1) = c; - *(skb_put(hdlc_skb, 1)) = PPP_FLAG; + *(u8 *)skb_put(hdlc_skb, 1) = PPP_FLAG; dev_kfree_skb_any(skb); return hdlc_skb; @@ -561,8 +561,8 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb) while (len--) { c = bitrev8(*cp++); if (c == DLE_FLAG) - *(skb_put(iraw_skb, 1)) = c; - *(skb_put(iraw_skb, 1)) = c; + *(u8 *)skb_put(iraw_skb, 1) = c; + *(u8 *)skb_put(iraw_skb, 1) = c; } dev_kfree_skb_any(skb); return iraw_skb; diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index bc29f1d52a2f..74e250664ce9 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -511,7 +511,7 @@ static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) bcs->rx_skb = NULL; return; } - *__skb_put(bcs->rx_skb, 1) = c; + *(u8 *)__skb_put(bcs->rx_skb, 1) = c; } /* hdlc_flush diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c index 78ce42214713..b6bcd1eca128 100644 --- a/drivers/isdn/i4l/isdn_audio.c +++ b/drivers/isdn/i4l/isdn_audio.c @@ -462,7 +462,7 @@ isdn_audio_goertzel(int *sample, modem_info *info) info->line); return; } - result = (int *) skb_put(skb, sizeof(int) * NCOEFF); + result = skb_put(skb, sizeof(int) * NCOEFF); for (k = 0; k < NCOEFF; k++) { sk = sk1 = sk2 = 0; for (n = 0; n < DTMF_NPOINTS; n++) { @@ -672,7 +672,7 @@ isdn_audio_put_dle_code(modem_info *info, u_char code) info->line); return; } - p = (char *) skb_put(skb, 2); + p = skb_put(skb, 2); p[0] = 0x10; p[1] = code; ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index 8837ac5a492d..6ade0916da4e 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -472,7 +472,7 @@ static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb accm |= ((ent) << bitno); \ do { \ if (skb_out && skb_tailroom(skb_out) > 0) \ - *(skb_put(skb_out, 1)) = (unsigned char)(accm >> 24); \ + *(u8 *)skb_put(skb_out, 1) = (u8)(accm >> 24); \ accm <<= 8; \ bitno += 8; \ } while (bitno <= 24); \ @@ -602,7 +602,7 @@ static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb * Do not emit a completely useless byte of ones. */ if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0) - *(skb_put(skb_out, 1)) = (unsigned char)((accm | (0xff << (bitno - 8))) >> 24); + *(u8 *)skb_put(skb_out, 1) = (unsigned char)((accm | (0xff << (bitno - 8))) >> 24); /* * Increase code size if we would have without the packet @@ -698,7 +698,7 @@ static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *s db->bytes_out += ilen; if (skb_tailroom(skb_out) > 0) - *(skb_put(skb_out, 1)) = 0; + *(u8 *)skb_put(skb_out, 1) = 0; else return DECOMP_ERR_NOMEM; @@ -816,7 +816,7 @@ static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *s #endif if (extra) /* the KwKwK case again */ - *(skb_put(skb_out, 1)) = finchar; + *(u8 *)skb_put(skb_out, 1) = finchar; /* * If not first code in a packet, and diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c index ba60076e0b95..e33fa3073f74 100644 --- a/drivers/isdn/i4l/isdn_x25iface.c +++ b/drivers/isdn/i4l/isdn_x25iface.c @@ -224,7 +224,7 @@ static int isdn_x25iface_connect_ind(struct concap_proto *cprot) skb = dev_alloc_skb(1); if (skb) { - *(skb_put(skb, 1)) = X25_IFACE_CONNECT; + *(u8 *)skb_put(skb, 1) = X25_IFACE_CONNECT; skb->protocol = x25_type_trans(skb, cprot->net_dev); netif_rx(skb); return 0; @@ -253,7 +253,7 @@ static int isdn_x25iface_disconn_ind(struct concap_proto *cprot) *state_p = WAN_DISCONNECTED; skb = dev_alloc_skb(1); if (skb) { - *(skb_put(skb, 1)) = X25_IFACE_DISCONNECT; + *(u8 *)skb_put(skb, 1) = X25_IFACE_DISCONNECT; skb->protocol = x25_type_trans(skb, cprot->net_dev); netif_rx(skb); return 0; diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index bbaf0a8cae8b..06b0dcc13695 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -963,7 +963,7 @@ static void dvb_net_sec(struct net_device *dev, skb->dev = dev; /* copy L3 payload */ - eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap); + eth = skb_put(skb, pkt_len - 12 - 4 + 14 - snap); memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap); /* create ethernet header: */ diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index c67e055a12c9..ab3428bf63fe 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -416,7 +416,7 @@ static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) || test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { /* Fill command header info */ - hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE); + hdr = skb_put(skb, FM_CMD_MSG_HDR_SIZE); hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */ /* 3 (fm_opcode,rd_wr,dlen) + payload len) */ diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 5427032aa05e..f43fb2f958a5 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -857,7 +857,7 @@ static int ad_lacpdu_send(struct port *port) skb->protocol = PKT_TYPE_LACPDU; skb->priority = TC_PRIO_CONTROL; - lacpdu_header = (struct lacpdu_header *)skb_put(skb, length); + lacpdu_header = skb_put(skb, length); ether_addr_copy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr); /* Note: source address is set to be the member's PERMANENT address, @@ -899,7 +899,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) skb->network_header = skb->mac_header + ETH_HLEN; skb->protocol = PKT_TYPE_LACPDU; - marker_header = (struct bond_marker_header *)skb_put(skb, length); + marker_header = skb_put(skb, length); ether_addr_copy(marker_header->hdr.h_dest, lacpdu_mcast_addr); /* Note: source address is set to be the member's PERMANENT address, diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index ae4ed03dc642..a3011c001080 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -648,7 +648,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) can_skb_prv(skb)->ifindex = dev->ifindex; can_skb_prv(skb)->skbcnt = 0; - *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); + *cf = skb_put(skb, sizeof(struct can_frame)); memset(*cf, 0, sizeof(struct can_frame)); return skb; @@ -677,7 +677,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, can_skb_prv(skb)->ifindex = dev->ifindex; can_skb_prv(skb)->skbcnt = 0; - *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame)); + *cfd = skb_put(skb, sizeof(struct canfd_frame)); memset(*cfd, 0, sizeof(struct canfd_frame)); return skb; diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index c8f4d26fc9d4..3143de45baaa 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -633,7 +633,7 @@ static void emac_rx(struct net_device *dev) if (!skb) continue; skb_reserve(skb, 2); - rdptr = (u8 *) skb_put(skb, rxlen - 4); + rdptr = skb_put(skb, rxlen - 4); /* Read received packet from RX SRAM */ if (netif_msg_rx_status(db)) diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 2ff6bd139c96..e1a50c87c9a9 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -471,7 +471,7 @@ static int init_tp_parity(struct adapter *adap) if (!skb) goto alloc_skb_fail; - req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); @@ -495,7 +495,7 @@ static int init_tp_parity(struct adapter *adap) if (!skb) goto alloc_skb_fail; - req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); @@ -518,7 +518,7 @@ static int init_tp_parity(struct adapter *adap) if (!skb) goto alloc_skb_fail; - req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); @@ -538,7 +538,7 @@ static int init_tp_parity(struct adapter *adap) if (!skb) goto alloc_skb_fail; - greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq)); + greq = __skb_put(skb, sizeof(*greq)); memset(greq, 0, sizeof(*greq)); greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); @@ -909,7 +909,7 @@ static int write_smt_entry(struct adapter *adapter, int idx) if (!skb) return -ENOMEM; - req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ @@ -952,7 +952,7 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, if (!skb) return -ENOMEM; - req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; req->sched = sched; diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c index fa81445e334c..50cd660732c5 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c @@ -552,7 +552,7 @@ static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid) struct cpl_tid_release *req; skb->priority = CPL_PRIORITY_SETUP; - req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); } @@ -1096,7 +1096,7 @@ static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e) return; } skb->priority = CPL_PRIORITY_CONTROL; - req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); + req = skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); req->reply = 0; diff --git a/drivers/net/ethernet/chelsio/cxgb3/l2t.c b/drivers/net/ethernet/chelsio/cxgb3/l2t.c index 26264125865f..248e40c6966c 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb3/l2t.c @@ -96,7 +96,7 @@ static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, return -ENOMEM; } - req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx)); req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) | diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c index 10736738ff30..a0fab65e80e8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c @@ -190,7 +190,7 @@ static int del_filter_wr(struct adapter *adapter, int fidx) if (!skb) return -ENOMEM; - fwr = (struct fw_filter_wr *)__skb_put(skb, len); + fwr = __skb_put(skb, len); t4_mk_filtdelwr(f->tid, fwr, adapter->sge.fw_evtq.abs_id); /* Mark the filter as "pending" and ship off the Filter Work Request. @@ -231,7 +231,7 @@ int set_filter_wr(struct adapter *adapter, int fidx) } } - fwr = (struct fw_filter_wr *)__skb_put(skb, sizeof(*fwr)); + fwr = __skb_put(skb, sizeof(*fwr)); memset(fwr, 0, sizeof(*fwr)); /* It would be nice to put most of the following in t4_hw.c but most diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 2c6de769f4e6..15fb284eafc0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1175,7 +1175,7 @@ static void mk_tid_release(struct sk_buff *skb, unsigned int chan, struct cpl_tid_release *req; set_wr_txq(skb, CPL_PRIORITY_SETUP, chan); - req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); INIT_TP_WR(req, tid); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); } @@ -1359,7 +1359,7 @@ int cxgb4_create_server(const struct net_device *dev, unsigned int stid, return -ENOMEM; adap = netdev2adap(dev); - req = (struct cpl_pass_open_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid)); req->local_port = sport; @@ -1400,7 +1400,7 @@ int cxgb4_create_server6(const struct net_device *dev, unsigned int stid, return -ENOMEM; adap = netdev2adap(dev); - req = (struct cpl_pass_open_req6 *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ6, stid)); req->local_port = sport; @@ -1432,7 +1432,7 @@ int cxgb4_remove_server(const struct net_device *dev, unsigned int stid, if (!skb) return -ENOMEM; - req = (struct cpl_close_listsvr_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid)); req->reply_ctrl = htons(NO_REPLY_V(0) | (ipv6 ? LISTSVR_IPV6_V(1) : diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 6f3692db29af..f7ef8871dd0b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -146,7 +146,7 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) if (!skb) return -ENOMEM; - req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); + req = __skb_put(skb, sizeof(*req)); INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, diff --git a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.h b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.h index 515b94ff9080..4b5aacc09cab 100644 --- a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.h +++ b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.h @@ -90,7 +90,7 @@ cxgb_mk_tid_release(struct sk_buff *skb, u32 len, u32 tid, u16 chan) { struct cpl_tid_release *req; - req = (struct cpl_tid_release *)__skb_put(skb, len); + req = __skb_put(skb, len); memset(req, 0, len); INIT_TP_WR(req, tid); @@ -104,7 +104,7 @@ cxgb_mk_close_con_req(struct sk_buff *skb, u32 len, u32 tid, u16 chan, { struct cpl_close_con_req *req; - req = (struct cpl_close_con_req *)__skb_put(skb, len); + req = __skb_put(skb, len); memset(req, 0, len); INIT_TP_WR(req, tid); @@ -119,7 +119,7 @@ cxgb_mk_abort_req(struct sk_buff *skb, u32 len, u32 tid, u16 chan, { struct cpl_abort_req *req; - req = (struct cpl_abort_req *)__skb_put(skb, len); + req = __skb_put(skb, len); memset(req, 0, len); INIT_TP_WR(req, tid); @@ -134,7 +134,7 @@ cxgb_mk_abort_rpl(struct sk_buff *skb, u32 len, u32 tid, u16 chan) { struct cpl_abort_rpl *rpl; - rpl = (struct cpl_abort_rpl *)__skb_put(skb, len); + rpl = __skb_put(skb, len); memset(rpl, 0, len); INIT_TP_WR(rpl, tid); @@ -149,7 +149,7 @@ cxgb_mk_rx_data_ack(struct sk_buff *skb, u32 len, u32 tid, u16 chan, { struct cpl_rx_data_ack *req; - req = (struct cpl_rx_data_ack *)__skb_put(skb, len); + req = __skb_put(skb, len); memset(req, 0, len); INIT_TP_WR(req, tid); diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 008dc8161775..16fe776ddbe5 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -1171,7 +1171,7 @@ dm9000_rx(struct net_device *dev) if (GoodPacket && ((skb = netdev_alloc_skb(dev, RxLen + 4)) != NULL)) { skb_reserve(skb, 2); - rdptr = (u8 *) skb_put(skb, RxLen - 4); + rdptr = skb_put(skb, RxLen - 4); /* Read received packet from RX SRAM */ diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index 3e77dd863175..5a847941c46b 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -399,7 +399,7 @@ static int dnet_poll(struct napi_struct *napi, int budget) * 'skb_put()' points to the start of sk_buff * data area. */ - data_ptr = (unsigned int *)skb_put(skb, pkt_len); + data_ptr = skb_put(skb, pkt_len); for (i = 0; i < (pkt_len + 3) >> 2; i++) *data_ptr++ = dnet_readl(bp, RX_DATA_FIFO); skb->protocol = eth_type_trans(skb, dev); diff --git a/drivers/net/ethernet/hp/hp100.c b/drivers/net/ethernet/hp/hp100.c index 5673b071e39d..c6164a98f257 100644 --- a/drivers/net/ethernet/hp/hp100.c +++ b/drivers/net/ethernet/hp/hp100.c @@ -1281,7 +1281,7 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr, */ skb_reserve(ringptr->skb, 2); - ringptr->skb->data = (u_char *) skb_put(ringptr->skb, MAX_ETHER_SIZE); + ringptr->skb->data = skb_put(ringptr->skb, MAX_ETHER_SIZE); /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ /* Note: 1st Fragment is used for the 4 byte packet status diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index b077ef8b00fa..2d1253c5b7a1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -762,7 +762,7 @@ int i40e_fcoe_handle_offload(struct i40e_ring *rx_ring, (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA)) { struct fcoe_crc_eof *crc = NULL; - crc = (struct fcoe_crc_eof *)skb_put(skb, sizeof(*crc)); + crc = skb_put(skb, sizeof(*crc)); crc->fcoe_eof = FC_EOF_T; } else { /* otherwise, drop the header only frame */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c index 2a653ec954f5..a23c2b5411a0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c @@ -491,7 +491,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, if ((fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA) && (fctl & FC_FC_END_SEQ)) { skb_linearize(skb); - crc = (struct fcoe_crc_eof *)skb_put(skb, sizeof(*crc)); + crc = skb_put(skb, sizeof(*crc)); crc->fcoe_eof = FC_EOF_T; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c index 17112faafbcc..88699b181946 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c @@ -63,8 +63,8 @@ static int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv) skb_reserve(skb, NET_IP_ALIGN); - ethh = (struct ethhdr *)skb_put(skb, sizeof(struct ethhdr)); - packet = (unsigned char *)skb_put(skb, packet_size); + ethh = skb_put(skb, sizeof(struct ethhdr)); + packet = skb_put(skb, packet_size); memcpy(ethh->h_dest, priv->dev->dev_addr, ETH_ALEN); eth_zero_addr(ethh->h_source); ethh->h_proto = htons(ETH_P_ARP); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c index 601abf240d63..c456ca07b562 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c @@ -136,10 +136,10 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv) skb_reset_mac_header(skb); skb_set_network_header(skb, skb->len); - iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); + iph = skb_put(skb, sizeof(struct iphdr)); skb_set_transport_header(skb, skb->len); - udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); + udph = skb_put(skb, sizeof(struct udphdr)); /* Fill ETH header */ ether_addr_copy(ethh->h_dest, priv->netdev->dev_addr); @@ -167,7 +167,7 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv) ip_send_check(iph); /* Fill test header and data */ - mlxh = (struct mlx5ehdr *)skb_put(skb, sizeof(*mlxh)); + mlxh = skb_put(skb, sizeof(*mlxh)); mlxh->version = 0; mlxh->magic = cpu_to_be64(MLX5E_TEST_MAGIC); strlcpy(mlxh->text, mlx5e_test_text, sizeof(mlxh->text)); diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c index cb0102dd7f70..e3d7c74d47bb 100644 --- a/drivers/net/ethernet/micrel/ks8842.c +++ b/drivers/net/ethernet/micrel/ks8842.c @@ -669,7 +669,7 @@ static void ks8842_rx_frame(struct net_device *netdev, ks8842_update_rx_counters(netdev, status, len); if (adapter->conf_flags & KS884X_16BIT) { - u16 *data16 = (u16 *)skb_put(skb, len); + u16 *data16 = skb_put(skb, len); ks8842_select_bank(adapter, 17); while (len > 0) { *data16++ = ioread16(adapter->hw_addr + @@ -679,7 +679,7 @@ static void ks8842_rx_frame(struct net_device *netdev, len -= sizeof(u32); } } else { - u32 *data = (u32 *)skb_put(skb, len); + u32 *data = skb_put(skb, len); ks8842_select_bank(adapter, 17); while (len > 0) { diff --git a/drivers/net/ethernet/sfc/falcon/selftest.c b/drivers/net/ethernet/sfc/falcon/selftest.c index 92bc34c91547..55c0fbbc4fb8 100644 --- a/drivers/net/ethernet/sfc/falcon/selftest.c +++ b/drivers/net/ethernet/sfc/falcon/selftest.c @@ -431,8 +431,7 @@ static int ef4_begin_loopback(struct ef4_tx_queue *tx_queue) /* Copy the payload in, incrementing the source address to * exercise the rss vectors */ - payload = ((struct ef4_loopback_payload *) - skb_put(skb, sizeof(state->payload))); + payload = skb_put(skb, sizeof(state->payload)); memcpy(payload, &state->payload, sizeof(state->payload)); payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index dab286a337a6..f6936949fc85 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -431,8 +431,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) /* Copy the payload in, incrementing the source address to * exercise the rss vectors */ - payload = ((struct efx_loopback_payload *) - skb_put(skb, sizeof(state->payload))); + payload = skb_put(skb, sizeof(state->payload)); memcpy(payload, &state->payload, sizeof(state->payload)); payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 6754cd01c605..140a209f22ab 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -540,7 +540,7 @@ static inline void scc_rxint(struct scc_channel *scc) } scc->rx_buff = skb; - *(skb_put(skb, 1)) = 0; /* KISS data */ + *(u8 *)skb_put(skb, 1) = 0; /* KISS data */ } if (skb->len >= scc->stat.bufsize) @@ -555,7 +555,7 @@ static inline void scc_rxint(struct scc_channel *scc) return; } - *(skb_put(skb, 1)) = Inb(scc->data); + *(u8 *)skb_put(skb, 1) = Inb(scc->data); } diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index d7e405268983..4e1da1645b15 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -877,7 +877,7 @@ static int pppoe_sendmsg(struct socket *sock, struct msghdr *m, skb->priority = sk->sk_priority; skb->protocol = cpu_to_be16(ETH_P_PPP_SES); - ph = (struct pppoe_hdr *)skb_put(skb, total_len + sizeof(struct pppoe_hdr)); + ph = skb_put(skb, total_len + sizeof(struct pppoe_hdr)); start = (char *)&ph->tag[0]; error = memcpy_from_msg(start, m, total_len); diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 8a4c8a1b9dd3..4d4837a0645b 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1250,7 +1250,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) skb_put_zero(skb_out, padding_count); } else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0) { - *skb_put(skb_out, 1) = 0; /* force short packet */ + *(u8 *)skb_put(skb_out, 1) = 0; /* force short packet */ } /* set final frame length */ diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index 3202c19df83d..861ff45f0b09 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -473,8 +473,8 @@ encapsulate: /* maybe pad; then trailer */ if (!((skb->len + sizeof *trailer) & 0x01)) - *skb_put(skb, 1) = PAD_BYTE; - trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer); + *(u8 *)skb_put(skb, 1) = PAD_BYTE; + trailer = skb_put(skb, sizeof *trailer); put_unaligned(header->packet_id, &trailer->packet_id); #if 0 netdev_dbg(dev->net, "frame >tx h %d p %d id %d\n", diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 6aaa6eb9df72..dc3cd03763af 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -74,10 +74,10 @@ done: fcs = crc32_le(~0, skb->data, skb->len); fcs = ~fcs; - *skb_put (skb, 1) = fcs & 0xff; - *skb_put (skb, 1) = (fcs>> 8) & 0xff; - *skb_put (skb, 1) = (fcs>>16) & 0xff; - *skb_put (skb, 1) = (fcs>>24) & 0xff; + *(u8 *)skb_put(skb, 1) = fcs & 0xff; + *(u8 *)skb_put(skb, 1) = (fcs>> 8) & 0xff; + *(u8 *)skb_put(skb, 1) = (fcs>>16) & 0xff; + *(u8 *)skb_put(skb, 1) = (fcs>>24) & 0xff; } return skb; } diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index f5b4ad45831a..fa3460a0dbbe 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -228,7 +228,7 @@ static void ppp_tx_cp(struct net_device *dev, u16 pid, u8 code, } skb_reserve(skb, sizeof(struct hdlc_header)); - cp = (struct cp_header *)skb_put(skb, sizeof(struct cp_header)); + cp = skb_put(skb, sizeof(struct cp_header)); cp->code = code; cp->id = id; cp->len = htons(sizeof(struct cp_header) + magic_len + len); diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index e2b7809d7886..1eea6c23976f 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -348,7 +348,7 @@ void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) if (!skb) return; - slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len); + slot = skb_put(skb, slot_len); slot->timestamp = cpu_to_le32(jiffies); slot->length = cpu_to_le32(len); memcpy(slot->payload, buf, len); diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index d127a08d60df..b13d61111072 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -1274,8 +1274,7 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target, length = sizeof(struct htc_conn_service_msg); /* assemble connect service message */ - conn_msg = (struct htc_conn_service_msg *) skb_put(skb, - length); + conn_msg = skb_put(skb, length); if (conn_msg == NULL) { WARN_ON_ONCE(1); status = -EINVAL; @@ -1504,8 +1503,7 @@ static int ath6kl_htc_pipe_start(struct htc_target *target) skb = packet->skb; /* assemble setup complete message */ - setup = (struct htc_setup_comp_ext_msg *) skb_put(skb, - sizeof(*setup)); + setup = skb_put(skb, sizeof(*setup)); memset(setup, 0, sizeof(struct htc_setup_comp_ext_msg)); setup->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 8e6dae23669b..9fa8970a1f7d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -156,8 +156,7 @@ static int htc_config_pipe_credits(struct htc_target *target) } skb_reserve(skb, sizeof(struct htc_frame_hdr)); - cp_msg = (struct htc_config_pipe_msg *) - skb_put(skb, sizeof(struct htc_config_pipe_msg)); + cp_msg = skb_put(skb, sizeof(struct htc_config_pipe_msg)); cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID); cp_msg->pipe_id = USB_WLAN_TX_PIPE; @@ -195,8 +194,7 @@ static int htc_setup_complete(struct htc_target *target) } skb_reserve(skb, sizeof(struct htc_frame_hdr)); - comp_msg = (struct htc_comp_msg *) - skb_put(skb, sizeof(struct htc_comp_msg)); + comp_msg = skb_put(skb, sizeof(struct htc_comp_msg)); comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID); target->htc_flags |= HTC_OP_START_WAIT; @@ -265,8 +263,7 @@ int htc_connect_service(struct htc_target *target, skb_reserve(skb, sizeof(struct htc_frame_hdr)); - conn_msg = (struct htc_conn_svc_msg *) - skb_put(skb, sizeof(struct htc_conn_svc_msg)); + conn_msg = skb_put(skb, sizeof(struct htc_conn_svc_msg)); conn_msg->service_id = cpu_to_be16(service_connreq->service_id); conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID); conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index cff9c585972f..0a5020f31de1 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -677,7 +677,7 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, return; } - eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); + eth = skb_put(skb, ETH_HLEN); ether_addr_copy(eth->h_dest, ndev->dev_addr); ether_addr_copy(eth->h_source, evt->src_mac); eth->h_proto = cpu_to_be16(ETH_P_PAE); diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index 1b7e125a28e2..4623155ec36e 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -3330,7 +3330,7 @@ static void airo_handle_rx(struct airo_info *ai) } skb_reserve(skb, 2); /* This way the IP header is aligned */ - buffer = (__le16 *) skb_put(skb, len + hdrlen); + buffer = skb_put(skb, len + hdrlen); if (test_bit(FLAG_802_11, &ai->flags)) { buffer[0] = fc; bap_read(ai, buffer + 1, hdrlen - 2, BAP0); @@ -3734,7 +3734,7 @@ static void mpi_receive_802_11(struct airo_info *ai) ai->dev->stats.rx_dropped++; goto badrx; } - buffer = (u16*)skb_put (skb, len + hdrlen); + buffer = skb_put(skb, len + hdrlen); memcpy ((char *)buffer, ptr, hdrlen); ptr += hdrlen; if (hdrlen == 24) diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index e0c690b48d4e..5e4ce4abd62e 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -10371,7 +10371,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, if (!dst) continue; - rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr)); + rt_hdr = skb_put(dst, sizeof(*rt_hdr)); rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION; rt_hdr->it_pad = 0; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c index 5339d1eeb2f7..84205aa508df 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c @@ -439,8 +439,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) if (rts_required) { skb_frag = txb->fragments[0]; - frag_hdr = - (struct libipw_hdr_3addrqos *)skb_put(skb_frag, hdr_len); + frag_hdr = skb_put(skb_frag, hdr_len); /* * Set header frame_ctl to the RTS. diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c index 91757defb9be..eb9cd6fa9c4d 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ap.c @@ -2361,7 +2361,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) return; } - hdr = (struct ieee80211_hdr *) skb_put(skb, 16); + hdr = skb_put(skb, 16); /* Generate a fake pspoll frame to start packet delivery */ hdr->frame_control = cpu_to_le16( diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c index 3076f646c829..52c095c7765f 100644 --- a/drivers/net/wireless/intersil/p54/fwio.c +++ b/drivers/net/wireless/intersil/p54/fwio.c @@ -206,7 +206,7 @@ static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags, return NULL; skb_reserve(skb, priv->tx_hdr_len); - hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); hdr->flags = cpu_to_le16(hdr_flags); hdr->len = cpu_to_le16(payload_len); hdr->type = cpu_to_le16(type); @@ -236,8 +236,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, mutex_lock(&priv->eeprom_mutex); priv->eeprom = buf; - eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, - eeprom_hdr_size + len); + eeprom_hdr = skb_put(skb, eeprom_hdr_size + len); if (priv->fw_var < 0x509) { eeprom_hdr->v1.offset = cpu_to_le16(offset); @@ -273,7 +272,7 @@ int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set) if (unlikely(!skb)) return -ENOMEM; - tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); + tim = skb_put(skb, sizeof(*tim)); tim->count = 1; tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid); p54_tx(priv, skb); @@ -290,7 +289,7 @@ int p54_sta_unlock(struct p54_common *priv, u8 *addr) if (unlikely(!skb)) return -ENOMEM; - sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); + sta = skb_put(skb, sizeof(*sta)); memcpy(sta->addr, addr, ETH_ALEN); p54_tx(priv, skb); return 0; @@ -310,7 +309,7 @@ int p54_tx_cancel(struct p54_common *priv, __le32 req_id) if (unlikely(!skb)) return -ENOMEM; - cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); + cancel = skb_put(skb, sizeof(*cancel)); cancel->req_id = req_id; p54_tx(priv, skb); return 0; @@ -327,7 +326,7 @@ int p54_setup_mac(struct p54_common *priv) if (!skb) return -ENOMEM; - setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); + setup = skb_put(skb, sizeof(*setup)); if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) { switch (priv->mode) { case NL80211_IFTYPE_STATION: @@ -413,18 +412,18 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) if (!skb) return -ENOMEM; - head = (struct p54_scan_head *) skb_put(skb, sizeof(*head)); + head = skb_put(skb, sizeof(*head)); memset(head->scan_params, 0, sizeof(head->scan_params)); head->mode = cpu_to_le16(mode); head->dwell = cpu_to_le16(dwell); head->freq = freq; if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { - __le16 *pa_power_points = (__le16 *) skb_put(skb, 2); + __le16 *pa_power_points = skb_put(skb, 2); *pa_power_points = cpu_to_le16(0x0c); } - iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal)); + iq_autocal = skb_put(skb, sizeof(*iq_autocal)); for (i = 0; i < priv->iq_autocal_len; i++) { if (priv->iq_autocal[i].freq != freq) continue; @@ -437,9 +436,9 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) goto err; if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) - body = (void *) skb_put(skb, sizeof(body->longbow)); + body = skb_put(skb, sizeof(body->longbow)); else - body = (void *) skb_put(skb, sizeof(body->normal)); + body = skb_put(skb, sizeof(body->normal)); for (i = 0; i < priv->output_limit->entries; i++) { __le16 *entry_freq = (void *) (priv->output_limit->data + @@ -500,25 +499,25 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell) goto err; if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) { - rate = (void *) skb_put(skb, sizeof(*rate)); + rate = skb_put(skb, sizeof(*rate)); rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); for (i = 0; i < sizeof(rate->rts_rates); i++) rate->rts_rates[i] = i; } - rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi)); + rssi = skb_put(skb, sizeof(*rssi)); rssi_data = p54_rssi_find(priv, le16_to_cpu(freq)); rssi->mul = cpu_to_le16(rssi_data->mul); rssi->add = cpu_to_le16(rssi_data->add); if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) { /* Longbow frontend needs ever more */ - rssi = (void *) skb_put(skb, sizeof(*rssi)); + rssi = skb_put(skb, sizeof(*rssi)); rssi->mul = cpu_to_le16(rssi_data->longbow_unkn); rssi->add = cpu_to_le16(rssi_data->longbow_unk2); } if (priv->fw_var >= 0x509) { - rate = (void *) skb_put(skb, sizeof(*rate)); + rate = skb_put(skb, sizeof(*rate)); rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); for (i = 0; i < sizeof(rate->rts_rates); i++) rate->rts_rates[i] = i; @@ -550,7 +549,7 @@ int p54_set_leds(struct p54_common *priv) if (unlikely(!skb)) return -ENOMEM; - led = (struct p54_led *) skb_put(skb, sizeof(*led)); + led = skb_put(skb, sizeof(*led)); led->flags = cpu_to_le16(0x0003); led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state); led->delay[0] = cpu_to_le16(1); @@ -570,7 +569,7 @@ int p54_set_edcf(struct p54_common *priv) if (unlikely(!skb)) return -ENOMEM; - edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); + edcf = skb_put(skb, sizeof(*edcf)); if (priv->use_short_slot) { edcf->slottime = 9; edcf->sifs = 0x10; @@ -615,7 +614,7 @@ int p54_set_ps(struct p54_common *priv) if (!skb) return -ENOMEM; - psm = (struct p54_psm *)skb_put(skb, sizeof(*psm)); + psm = skb_put(skb, sizeof(*psm)); psm->mode = cpu_to_le16(mode); psm->aid = cpu_to_le16(priv->aid); for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) { @@ -644,7 +643,7 @@ int p54_init_xbow_synth(struct p54_common *priv) if (unlikely(!skb)) return -ENOMEM; - xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); + xbow = skb_put(skb, sizeof(*xbow)); xbow->magic1 = cpu_to_le16(0x1); xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); @@ -664,7 +663,7 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len, if (unlikely(!skb)) return -ENOMEM; - rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); + rxkey = skb_put(skb, sizeof(*rxkey)); rxkey->entry = slot; rxkey->key_id = idx; rxkey->key_type = algo; @@ -744,7 +743,7 @@ int p54_set_groupfilter(struct p54_common *priv) if (!skb) return -ENOMEM; - grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp)); + grp = skb_put(skb, sizeof(*grp)); on = !(priv->filter_flags & FIF_ALLMULTI) && (priv->mc_maclist_num > 0 && diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1d6e180052b8..7418088e296f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -650,7 +650,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) skb = dev_alloc_skb(sizeof(*pspoll)); if (!skb) return; - pspoll = (void *) skb_put(skb, sizeof(*pspoll)); + pspoll = skb_put(skb, sizeof(*pspoll)); pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM); @@ -681,7 +681,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, skb = dev_alloc_skb(sizeof(*hdr)); if (!skb) return; - hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); + hdr = skb_put(skb, sizeof(*hdr) - ETH_ALEN); hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | (ps ? IEEE80211_FCTL_PM : 0)); @@ -892,7 +892,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, if (skb == NULL) return; - hdr = (struct hwsim_radiotap_ack_hdr *) skb_put(skb, sizeof(*hdr)); + hdr = skb_put(skb, sizeof(*hdr)); hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; hdr->hdr.it_pad = 0; hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); @@ -904,7 +904,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, flags = IEEE80211_CHAN_2GHZ; hdr->rt_chbitmask = cpu_to_le16(flags); - hdr11 = (struct ieee80211_hdr *) skb_put(skb, 10); + hdr11 = skb_put(skb, 10); hdr11->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK); hdr11->duration_id = cpu_to_le16(0); diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c index bc12c37e7501..042a1d07f686 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c @@ -62,7 +62,7 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, }; struct tx_packet_hdr *tx_header; - tx_header = (void *)skb_put(skb_aggr, sizeof(*tx_header)); + tx_header = skb_put(skb_aggr, sizeof(*tx_header)); /* Copy DA and SA */ dt_offset = 2 * ETH_ALEN; diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index d38555fe4284..39cd677d4159 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -158,7 +158,7 @@ static void mwifiex_tdls_add_aid(struct mwifiex_private *priv, u8 *pos; assoc_rsp = (struct ieee_types_assoc_rsp *)&priv->assoc_rsp_buf; - pos = (void *)skb_put(skb, 4); + pos = skb_put(skb, 4); *pos++ = WLAN_EID_AID; *pos++ = 2; memcpy(pos, &assoc_rsp->a_id, sizeof(assoc_rsp->a_id)); @@ -172,7 +172,7 @@ static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv, struct ieee80211_vht_cap vht_cap; u8 *pos; - pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); *pos++ = WLAN_EID_VHT_CAPABILITY; *pos++ = sizeof(struct ieee80211_vht_cap); @@ -207,7 +207,7 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac, return 0; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2); *pos++ = WLAN_EID_HT_OPERATION; *pos++ = sizeof(struct ieee80211_ht_operation); ht_oper = (void *)pos; @@ -272,7 +272,7 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv, ap_vht_cap = bss_desc->bcn_vht_cap; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2); *pos++ = WLAN_EID_VHT_OPERATION; *pos++ = sizeof(struct ieee80211_vht_operation); vht_oper = (struct ieee80211_vht_operation *)pos; @@ -359,7 +359,7 @@ static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv, { struct ieee_types_extcap *extcap; - extcap = (void *)skb_put(skb, sizeof(struct ieee_types_extcap)); + extcap = skb_put(skb, sizeof(struct ieee_types_extcap)); extcap->ieee_hdr.element_id = WLAN_EID_EXT_CAPABILITY; extcap->ieee_hdr.len = 8; memset(extcap->ext_capab, 0, 8); @@ -372,7 +372,7 @@ static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv, static void mwifiex_tdls_add_qos_capab(struct sk_buff *skb) { - u8 *pos = (void *)skb_put(skb, 3); + u8 *pos = skb_put(skb, 3); *pos++ = WLAN_EID_QOS_CAPA; *pos++ = 1; @@ -413,8 +413,8 @@ mwifiex_add_wmm_info_ie(struct mwifiex_private *priv, struct sk_buff *skb, { u8 *buf; - buf = (void *)skb_put(skb, MWIFIEX_TDLS_WMM_INFO_SIZE + - sizeof(struct ieee_types_header)); + buf = skb_put(skb, + MWIFIEX_TDLS_WMM_INFO_SIZE + sizeof(struct ieee_types_header)); *buf++ = WLAN_EID_VENDOR_SPECIFIC; *buf++ = 7; /* len */ @@ -431,7 +431,7 @@ static void mwifiex_tdls_add_bss_co_2040(struct sk_buff *skb) { struct ieee_types_bss_co_2040 *bssco; - bssco = (void *)skb_put(skb, sizeof(struct ieee_types_bss_co_2040)); + bssco = skb_put(skb, sizeof(struct ieee_types_bss_co_2040)); bssco->ieee_hdr.element_id = WLAN_EID_BSS_COEX_2040; bssco->ieee_hdr.len = sizeof(struct ieee_types_bss_co_2040) - sizeof(struct ieee_types_header); @@ -443,8 +443,8 @@ static void mwifiex_tdls_add_supported_chan(struct sk_buff *skb) struct ieee_types_generic *supp_chan; u8 chan_supp[] = {1, 11}; - supp_chan = (void *)skb_put(skb, (sizeof(struct ieee_types_header) + - sizeof(chan_supp))); + supp_chan = skb_put(skb, + (sizeof(struct ieee_types_header) + sizeof(chan_supp))); supp_chan->ieee_hdr.element_id = WLAN_EID_SUPPORTED_CHANNELS; supp_chan->ieee_hdr.len = sizeof(chan_supp); memcpy(supp_chan->data, chan_supp, sizeof(chan_supp)); @@ -455,8 +455,8 @@ static void mwifiex_tdls_add_oper_class(struct sk_buff *skb) struct ieee_types_generic *reg_class; u8 rc_list[] = {1, 1, 2, 3, 4, 12, 22, 23, 24, 25, 27, 28, 29, 30, 32, 33}; - reg_class = (void *)skb_put(skb, (sizeof(struct ieee_types_header) + - sizeof(rc_list))); + reg_class = skb_put(skb, + (sizeof(struct ieee_types_header) + sizeof(rc_list))); reg_class->ieee_hdr.element_id = WLAN_EID_SUPPORTED_REGULATORY_CLASSES; reg_class->ieee_hdr.len = sizeof(rc_list); memcpy(reg_class->data, rc_list, sizeof(rc_list)); @@ -475,7 +475,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap; - tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); + tf = skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); memcpy(tf->da, peer, ETH_ALEN); memcpy(tf->sa, priv->curr_addr, ETH_ALEN); tf->ether_type = cpu_to_be16(ETH_P_TDLS); @@ -494,7 +494,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, return ret; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); ht_cap = (void *)pos; @@ -534,7 +534,7 @@ static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, return ret; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); ht_cap = (void *)pos; @@ -616,7 +616,7 @@ mwifiex_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr, { struct ieee80211_tdls_lnkie *lnkid; - lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); + lnkid = skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); lnkid->ie_type = WLAN_EID_LINK_ID; lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - sizeof(struct ieee_types_header); @@ -741,7 +741,7 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv, capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap; - mgmt = (void *)skb_put(skb, offsetof(struct ieee80211_mgmt, u)); + mgmt = skb_put(skb, offsetof(struct ieee80211_mgmt, u)); memset(mgmt, 0, 24); memcpy(mgmt->da, peer, ETH_ALEN); @@ -775,7 +775,7 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv, return ret; } - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); ht_cap = (void *)pos; diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h index 9844ff0add2b..f6ac39973b5d 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h @@ -26,7 +26,7 @@ static inline void qtnf_cmd_skb_put_action(struct sk_buff *skb, u16 action) { __le16 *buf_ptr; - buf_ptr = (__le16 *)skb_put(skb, sizeof(action)); + buf_ptr = skb_put(skb, sizeof(action)); *buf_ptr = cpu_to_le16(action); } @@ -42,8 +42,7 @@ static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb, u16 tlv_id, const u8 arr[], size_t arr_len) { - struct qlink_tlv_hdr *hdr = - (void *)skb_put(skb, sizeof(*hdr) + arr_len); + struct qlink_tlv_hdr *hdr = skb_put(skb, sizeof(*hdr) + arr_len); hdr->type = cpu_to_le16(tlv_id); hdr->len = cpu_to_le16(arr_len); @@ -53,8 +52,7 @@ static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb, static inline void qtnf_cmd_skb_put_tlv_u8(struct sk_buff *skb, u16 tlv_id, u8 value) { - struct qlink_tlv_hdr *hdr = - (void *)skb_put(skb, sizeof(*hdr) + sizeof(value)); + struct qlink_tlv_hdr *hdr = skb_put(skb, sizeof(*hdr) + sizeof(value)); hdr->type = cpu_to_le16(tlv_id); hdr->len = cpu_to_le16(sizeof(value)); @@ -64,8 +62,7 @@ static inline void qtnf_cmd_skb_put_tlv_u8(struct sk_buff *skb, u16 tlv_id, static inline void qtnf_cmd_skb_put_tlv_u16(struct sk_buff *skb, u16 tlv_id, u16 value) { - struct qlink_tlv_hdr *hdr = - (void *)skb_put(skb, sizeof(*hdr) + sizeof(value)); + struct qlink_tlv_hdr *hdr = skb_put(skb, sizeof(*hdr) + sizeof(value)); __le16 tmp = cpu_to_le16(value); hdr->type = cpu_to_le16(tlv_id); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index b70985e126bf..51520a0e2138 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -188,7 +188,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, return; } - dump_hdr = (struct rt2x00dump_hdr *)skb_put(skbcopy, sizeof(*dump_hdr)); + dump_hdr = skb_put(skbcopy, sizeof(*dump_hdr)); dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION); dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr)); dump_hdr->desc_length = cpu_to_le32(skbdesc->desc_len); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c index dd3ba4810e7d..e7b1d7c0f542 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c @@ -462,7 +462,7 @@ static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, break; /* Clear content */ - ph2c_buffer = (u8 *)skb_put(skb, (u32)len); + ph2c_buffer = skb_put(skb, (u32)len); memset((ph2c_buffer + totallen + tx_desclen), 0, len); /* CMD len */ diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index 0877e2283f35..97f003e84381 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -86,7 +86,7 @@ static void fdp_nci_i2c_add_len_lrc(struct sk_buff *skb) for (i = 0; i < len + 2; i++) lrc ^= skb->data[i]; - *skb_put(skb, 1) = lrc; + *(u8 *)skb_put(skb, 1) = lrc; } static void fdp_nci_i2c_remove_len_lrc(struct sk_buff *skb) diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c index e0e8afd27849..8e328c36a816 100644 --- a/drivers/nfc/microread/i2c.c +++ b/drivers/nfc/microread/i2c.c @@ -75,7 +75,7 @@ static void microread_i2c_add_len_crc(struct sk_buff *skb) for (i = 0; i < skb->len; i++) crc = crc ^ skb->data[i]; - *skb_put(skb, 1) = crc; + *(u8 *)skb_put(skb, 1) = crc; } static void microread_i2c_remove_len_crc(struct sk_buff *skb) @@ -173,7 +173,7 @@ static int microread_i2c_read(struct microread_i2c_phy *phy, goto flush; } - *skb_put(*skb, 1) = len; + *(u8 *)skb_put(*skb, 1) = len; r = i2c_master_recv(client, skb_put(*skb, len), len); if (r != len) { diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c index f454dc68cc03..9d0dd1be0923 100644 --- a/drivers/nfc/microread/microread.c +++ b/drivers/nfc/microread/microread.c @@ -441,8 +441,8 @@ static int microread_im_transceive(struct nfc_hci_dev *hdev, crc = crc_ccitt(0xffff, skb->data, skb->len); crc = ~crc; - *skb_put(skb, 1) = crc & 0xff; - *skb_put(skb, 1) = crc >> 8; + *(u8 *)skb_put(skb, 1) = crc & 0xff; + *(u8 *)skb_put(skb, 1) = crc >> 8; break; case MICROREAD_GATE_ID_MREAD_NFC_T3: control_bits = 0xDB; diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c index 7c710458568e..788599de9d8a 100644 --- a/drivers/nfc/nfcmrvl/fw_dnld.c +++ b/drivers/nfc/nfcmrvl/fw_dnld.c @@ -92,7 +92,7 @@ static struct sk_buff *alloc_lc_skb(struct nfcmrvl_private *priv, uint8_t plen) return NULL; } - hdr = (struct nci_data_hdr *) skb_put(skb, NCI_DATA_HDR_SIZE); + hdr = skb_put(skb, NCI_DATA_HDR_SIZE); hdr->conn_id = NCI_CORE_LC_CONNID_PROP_FW_DL; hdr->rfu = 0; hdr->plen = plen; @@ -292,7 +292,7 @@ static int process_state_fw_dnld(struct nfcmrvl_private *priv, out_skb = alloc_lc_skb(priv, 1); if (!out_skb) return -ENOMEM; - *skb_put(out_skb, 1) = 0xBF; + *(u8 *)skb_put(out_skb, 1) = 0xBF; nci_send_frame(priv->ndev, out_skb); priv->fw_dnld.substate = SUBSTATE_WAIT_NACK_CREDIT; return 0; @@ -301,7 +301,7 @@ static int process_state_fw_dnld(struct nfcmrvl_private *priv, out_skb = alloc_lc_skb(priv, 1); if (!out_skb) return -ENOMEM; - *skb_put(out_skb, 1) = HELPER_ACK_PACKET_FORMAT; + *(u8 *)skb_put(out_skb, 1) = HELPER_ACK_PACKET_FORMAT; nci_send_frame(priv->ndev, out_skb); priv->fw_dnld.substate = SUBSTATE_WAIT_ACK_CREDIT; break; diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index 9200bb308e42..68a3cd0287f6 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -1032,7 +1032,7 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) return NULL; /* DEP support only */ - *skb_put(skb, 1) = PN533_INIT_TARGET_DEP; + *(u8 *)skb_put(skb, 1) = PN533_INIT_TARGET_DEP; /* MIFARE params */ skb_put_data(skb, mifare_params, 6); @@ -1046,12 +1046,12 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) memcpy(nfcid3, felica, 8); /* General bytes */ - *skb_put(skb, 1) = gbytes_len; + *(u8 *)skb_put(skb, 1) = gbytes_len; gb = skb_put_data(skb, gbytes, gbytes_len); /* Len Tk */ - *skb_put(skb, 1) = 0; + *(u8 *)skb_put(skb, 1) = 0; return skb; } @@ -1280,8 +1280,8 @@ static void pn533_wq_rf(struct work_struct *work) if (!skb) return; - *skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD; - *skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD_AUTO_RFCA; + *(u8 *)skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD; + *(u8 *)skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD_AUTO_RFCA; rc = pn533_send_cmd_async(dev, PN533_CMD_RF_CONFIGURATION, skb, pn533_rf_complete, NULL); @@ -1375,8 +1375,8 @@ static int pn533_poll_dep(struct nfc_dev *nfc_dev) if (!skb) return -ENOMEM; - *skb_put(skb, 1) = 0x01; /* Active */ - *skb_put(skb, 1) = 0x02; /* 424 kbps */ + *(u8 *)skb_put(skb, 1) = 0x01; /* Active */ + *(u8 *)skb_put(skb, 1) = 0x02; /* 424 kbps */ next = skb_put(skb, 1); /* Next */ *next = 0; @@ -1620,8 +1620,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev) if (!skb) return -ENOMEM; - *skb_put(skb, sizeof(u8)) = 1; /* TG */ - *skb_put(skb, sizeof(u8)) = 0; /* Next */ + *(u8 *)skb_put(skb, sizeof(u8)) = 1; /* TG */ + *(u8 *)skb_put(skb, sizeof(u8)) = 0; /* Next */ resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_ATR, skb); if (IS_ERR(resp)) @@ -1737,7 +1737,7 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, if (!skb) return; - *skb_put(skb, 1) = 1; /* TG*/ + *(u8 *)skb_put(skb, 1) = 1; /* TG*/ rc = pn533_send_cmd_async(dev, PN533_CMD_IN_RELEASE, skb, pn533_deactivate_target_complete, NULL); @@ -1848,8 +1848,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, if (!skb) return -ENOMEM; - *skb_put(skb, 1) = !comm_mode; /* ActPass */ - *skb_put(skb, 1) = 0x02; /* 424 kbps */ + *(u8 *)skb_put(skb, 1) = !comm_mode; /* ActPass */ + *(u8 *)skb_put(skb, 1) = 0x02; /* 424 kbps */ next = skb_put(skb, 1); /* Next */ *next = 0; @@ -2274,7 +2274,7 @@ static void pn533_wq_mi_recv(struct work_struct *work) break; } default: - *skb_put(skb, sizeof(u8)) = 1; /*TG*/ + *(u8 *)skb_put(skb, sizeof(u8)) = 1; /*TG*/ rc = pn533_send_cmd_direct_async(dev, PN533_CMD_IN_DATA_EXCHANGE, @@ -2370,7 +2370,7 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, if (!skb) return -ENOMEM; - *skb_put(skb, sizeof(cfgitem)) = cfgitem; + *(u8 *)skb_put(skb, sizeof(cfgitem)) = cfgitem; skb_put_data(skb, cfgdata, cfgdata_len); resp = pn533_send_cmd_sync(dev, PN533_CMD_RF_CONFIGURATION, skb); @@ -2415,7 +2415,7 @@ static int pn533_pasori_fw_reset(struct pn533 *dev) if (!skb) return -ENOMEM; - *skb_put(skb, sizeof(u8)) = 0x1; + *(u8 *)skb_put(skb, sizeof(u8)) = 0x1; resp = pn533_send_cmd_sync(dev, 0x18, skb); if (IS_ERR(resp)) @@ -2454,7 +2454,7 @@ static int pn532_sam_configuration(struct nfc_dev *nfc_dev) if (!skb) return -ENOMEM; - *skb_put(skb, 1) = 0x01; + *(u8 *)skb_put(skb, 1) = 0x01; resp = pn533_send_cmd_sync(dev, PN533_CMD_SAM_CONFIGURATION, skb); if (IS_ERR(resp)) diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index 71ac0836c9f4..dc1e3768cee6 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -287,8 +287,8 @@ static void pn544_hci_i2c_add_len_crc(struct sk_buff *skb) crc = crc_ccitt(0xffff, skb->data, skb->len); crc = ~crc; - *skb_put(skb, 1) = crc & 0xff; - *skb_put(skb, 1) = crc >> 8; + *(u8 *)skb_put(skb, 1) = crc & 0xff; + *(u8 *)skb_put(skb, 1) = crc >> 8; } static void pn544_hci_i2c_remove_len_crc(struct sk_buff *skb) @@ -391,7 +391,7 @@ static int pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb) goto flush; } - *skb_put(*skb, 1) = len; + *(u8 *)skb_put(*skb, 1) = len; r = i2c_master_recv(client, skb_put(*skb, len), len); if (r != len) { diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c index e1260da73d45..5fa3cf0fabd6 100644 --- a/drivers/nfc/port100.c +++ b/drivers/nfc/port100.c @@ -991,7 +991,7 @@ static int port100_set_command_type(struct port100 *dev, u8 command_type) if (!skb) return -ENOMEM; - *skb_put(skb, sizeof(u8)) = command_type; + *(u8 *)skb_put(skb, sizeof(u8)) = command_type; resp = port100_send_cmd_sync(dev, PORT100_CMD_SET_COMMAND_TYPE, skb); if (IS_ERR(resp)) @@ -1059,7 +1059,7 @@ static int port100_switch_rf(struct nfc_digital_dev *ddev, bool on) if (!skb) return -ENOMEM; - *skb_put(skb, 1) = on ? 1 : 0; + *(u8 *)skb_put(skb, 1) = on ? 1 : 0; /* Cancel the last command if the device is being switched off */ if (!on) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 94d0b913b627..c36f0e0afdfd 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -177,10 +177,10 @@ static void st21nfca_hci_add_len_crc(struct sk_buff *skb) crc = ~crc; tmp = crc & 0x00ff; - *skb_put(skb, 1) = tmp; + *(u8 *)skb_put(skb, 1) = tmp; tmp = (crc >> 8) & 0x00ff; - *skb_put(skb, 1) = tmp; + *(u8 *)skb_put(skb, 1) = tmp; } static void st21nfca_hci_remove_len_crc(struct sk_buff *skb) @@ -214,7 +214,7 @@ static int st21nfca_hci_i2c_write(void *phy_id, struct sk_buff *skb) st21nfca_hci_add_len_crc(skb); /* add ST21NFCA_SOF_EOF on tail */ - *skb_put(skb, 1) = ST21NFCA_SOF_EOF; + *(u8 *)skb_put(skb, 1) = ST21NFCA_SOF_EOF; /* add ST21NFCA_SOF_EOF on head */ *skb_push(skb, 1) = ST21NFCA_SOF_EOF; diff --git a/drivers/nfc/st95hf/core.c b/drivers/nfc/st95hf/core.c index c2840e412962..168adcc46cb8 100644 --- a/drivers/nfc/st95hf/core.c +++ b/drivers/nfc/st95hf/core.c @@ -949,7 +949,7 @@ static int st95hf_in_send_cmd(struct nfc_digital_dev *ddev, switch (stcontext->current_rf_tech) { case NFC_DIGITAL_RF_TECH_106A: len_data_to_tag = skb->len + 1; - *skb_put(skb, 1) = stcontext->sendrcv_trflag; + *(u8 *)skb_put(skb, 1) = stcontext->sendrcv_trflag; break; case NFC_DIGITAL_RF_TECH_106B: case NFC_DIGITAL_RF_TECH_ISO15693: diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 902722dc4ce3..b025ee5da1ba 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -351,7 +351,7 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset; } else { - cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); + cp = skb_put(skb, tlen); } memset(cp, 0, sizeof(*cp)); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 90939f66bc0d..539e23ec0e59 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1543,7 +1543,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset; } else { - cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); + cp = skb_put(skb, tlen); } memset(cp, 0, sizeof(*cp)); diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index b97405ed6cae..da0fcce6f842 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -874,7 +874,7 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp) frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset; } else { - cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); + cp = skb_put(skb, tlen); } memset(cp, 0, sizeof(*cp)); diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c index 1d3963136295..1720e1b6ae04 100644 --- a/drivers/staging/rtl8192e/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192e/rtl819x_BAProc.c @@ -95,8 +95,7 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, skb_reserve(skb, ieee->tx_headroom); - BAReq = (struct rtllib_hdr_3addr *)skb_put(skb, - sizeof(struct rtllib_hdr_3addr)); + BAReq = skb_put(skb, sizeof(struct rtllib_hdr_3addr)); ether_addr_copy(BAReq->addr1, Dst); ether_addr_copy(BAReq->addr2, ieee->dev->dev_addr); @@ -104,7 +103,7 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, ether_addr_copy(BAReq->addr3, ieee->current_network.bssid); BAReq->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT); - tag = (u8 *)skb_put(skb, 9); + tag = skb_put(skb, 9); *tag++ = ACT_CAT_BA; *tag++ = type; *tag++ = pBA->DialogToken; @@ -159,15 +158,14 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, skb_reserve(skb, ieee->tx_headroom); - Delba = (struct rtllib_hdr_3addr *) skb_put(skb, - sizeof(struct rtllib_hdr_3addr)); + Delba = skb_put(skb, sizeof(struct rtllib_hdr_3addr)); ether_addr_copy(Delba->addr1, dst); ether_addr_copy(Delba->addr2, ieee->dev->dev_addr); ether_addr_copy(Delba->addr3, ieee->current_network.bssid); Delba->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT); - tag = (u8 *)skb_put(skb, 6); + tag = skb_put(skb, 6); *tag++ = ACT_CAT_BA; *tag++ = ACT_DELBA; diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index 60d07d0bb4eb..5f2751d4d464 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -351,8 +351,7 @@ static inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee) skb_reserve(skb, ieee->tx_headroom); - req = (struct rtllib_probe_request *) skb_put(skb, - sizeof(struct rtllib_probe_request)); + req = skb_put(skb, sizeof(struct rtllib_probe_request)); req->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_PROBE_REQ); req->header.duration_id = 0; @@ -360,7 +359,7 @@ static inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee) ether_addr_copy(req->header.addr2, ieee->dev->dev_addr); eth_broadcast_addr(req->header.addr3); - tag = (u8 *) skb_put(skb, len + 2 + rate_len); + tag = skb_put(skb, len + 2 + rate_len); *tag++ = MFIE_TYPE_SSID; *tag++ = len; @@ -789,8 +788,7 @@ rtllib_authentication_req(struct rtllib_network *beacon, skb_reserve(skb, ieee->tx_headroom); - auth = (struct rtllib_authentication *) - skb_put(skb, sizeof(struct rtllib_authentication)); + auth = skb_put(skb, sizeof(struct rtllib_authentication)); auth->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_AUTH); if (challengelen) @@ -889,8 +887,7 @@ static struct sk_buff *rtllib_probe_resp(struct rtllib_device *ieee, skb_reserve(skb, ieee->tx_headroom); - beacon_buf = (struct rtllib_probe_response *) skb_put(skb, - (beacon_size - ieee->tx_headroom)); + beacon_buf = skb_put(skb, (beacon_size - ieee->tx_headroom)); ether_addr_copy(beacon_buf->header.addr1, dest); ether_addr_copy(beacon_buf->header.addr2, ieee->dev->dev_addr); ether_addr_copy(beacon_buf->header.addr3, ieee->current_network.bssid); @@ -984,8 +981,7 @@ static struct sk_buff *rtllib_assoc_resp(struct rtllib_device *ieee, u8 *dest) skb_reserve(skb, ieee->tx_headroom); - assoc = (struct rtllib_assoc_response_frame *) - skb_put(skb, sizeof(struct rtllib_assoc_response_frame)); + assoc = skb_put(skb, sizeof(struct rtllib_assoc_response_frame)); assoc->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_ASSOC_RESP); ether_addr_copy(assoc->header.addr1, dest); @@ -1016,7 +1012,7 @@ static struct sk_buff *rtllib_assoc_resp(struct rtllib_device *ieee, u8 *dest) else ieee->assoc_id++; - tag = (u8 *) skb_put(skb, rate_len); + tag = skb_put(skb, rate_len); rtllib_MFIE_Brate(ieee, &tag); rtllib_MFIE_Grate(ieee, &tag); @@ -1038,8 +1034,7 @@ static struct sk_buff *rtllib_auth_resp(struct rtllib_device *ieee, int status, skb_reserve(skb, ieee->tx_headroom); - auth = (struct rtllib_authentication *) - skb_put(skb, sizeof(struct rtllib_authentication)); + auth = skb_put(skb, sizeof(struct rtllib_authentication)); auth->status = cpu_to_le16(status); auth->transaction = cpu_to_le16(2); @@ -1065,8 +1060,7 @@ static struct sk_buff *rtllib_null_func(struct rtllib_device *ieee, short pwr) skb_reserve(skb, ieee->tx_headroom); - hdr = (struct rtllib_hdr_3addr *)skb_put(skb, - sizeof(struct rtllib_hdr_3addr)); + hdr = skb_put(skb, sizeof(struct rtllib_hdr_3addr)); ether_addr_copy(hdr->addr1, ieee->current_network.bssid); ether_addr_copy(hdr->addr2, ieee->dev->dev_addr); @@ -1092,8 +1086,7 @@ static struct sk_buff *rtllib_pspoll_func(struct rtllib_device *ieee) skb_reserve(skb, ieee->tx_headroom); - hdr = (struct rtllib_pspoll_hdr *)skb_put(skb, - sizeof(struct rtllib_pspoll_hdr)); + hdr = skb_put(skb, sizeof(struct rtllib_pspoll_hdr)); ether_addr_copy(hdr->bssid, ieee->current_network.bssid); ether_addr_copy(hdr->ta, ieee->dev->dev_addr); @@ -1243,8 +1236,7 @@ rtllib_association_req(struct rtllib_network *beacon, skb_reserve(skb, ieee->tx_headroom); - hdr = (struct rtllib_assoc_request_frame *) - skb_put(skb, sizeof(struct rtllib_assoc_request_frame) + 2); + hdr = skb_put(skb, sizeof(struct rtllib_assoc_request_frame) + 2); hdr->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_ASSOC_REQ); @@ -3414,8 +3406,7 @@ rtllib_disauth_skb(struct rtllib_network *beacon, skb_reserve(skb, ieee->tx_headroom); - disauth = (struct rtllib_disauth *) skb_put(skb, - sizeof(struct rtllib_disauth)); + disauth = skb_put(skb, sizeof(struct rtllib_disauth)); disauth->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_DEAUTH); disauth->header.duration_id = 0; @@ -3442,8 +3433,7 @@ rtllib_disassociate_skb(struct rtllib_network *beacon, skb_reserve(skb, ieee->tx_headroom); - disass = (struct rtllib_disassoc *) skb_put(skb, - sizeof(struct rtllib_disassoc)); + disass = skb_put(skb, sizeof(struct rtllib_disassoc)); disass->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_DISASSOC); disass->header.duration_id = 0; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 903a1d0269df..107069180ed2 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -341,7 +341,7 @@ static inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee) skb_reserve(skb, ieee->tx_headroom); - req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); + req = skb_put(skb, sizeof(struct ieee80211_probe_request)); req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); req->header.duration_id = 0; /* FIXME: is this OK? */ @@ -349,7 +349,7 @@ static inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee) memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); eth_broadcast_addr(req->header.addr3); - tag = (u8 *) skb_put(skb,len+2+rate_len); + tag = skb_put(skb, len + 2 + rate_len); *tag++ = MFIE_TYPE_SSID; *tag++ = len; @@ -659,8 +659,7 @@ ieee80211_authentication_req(struct ieee80211_network *beacon, if (!skb) return NULL; skb_reserve(skb, ieee->tx_headroom); - auth = (struct ieee80211_authentication *) - skb_put(skb, sizeof(struct ieee80211_authentication)); + auth = skb_put(skb, sizeof(struct ieee80211_authentication)); if (challengelen) auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH @@ -768,7 +767,7 @@ static struct sk_buff *ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *d if (!skb) return NULL; skb_reserve(skb, ieee->tx_headroom); - beacon_buf = (struct ieee80211_probe_response *) skb_put(skb, (beacon_size - ieee->tx_headroom)); + beacon_buf = skb_put(skb, (beacon_size - ieee->tx_headroom)); memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); @@ -864,8 +863,7 @@ static struct sk_buff *ieee80211_assoc_resp(struct ieee80211_device *ieee, skb_reserve(skb, ieee->tx_headroom); - assoc = (struct ieee80211_assoc_response_frame *) - skb_put(skb, sizeof(struct ieee80211_assoc_response_frame)); + assoc = skb_put(skb, sizeof(struct ieee80211_assoc_response_frame)); assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); memcpy(assoc->header.addr1, dest,ETH_ALEN); @@ -892,7 +890,7 @@ static struct sk_buff *ieee80211_assoc_resp(struct ieee80211_device *ieee, if (ieee->assoc_id == 0x2007) ieee->assoc_id=0; else ieee->assoc_id++; - tag = (u8 *) skb_put(skb, rate_len); + tag = skb_put(skb, rate_len); ieee80211_MFIE_Brate(ieee, &tag); ieee80211_MFIE_Grate(ieee, &tag); @@ -940,7 +938,7 @@ static struct sk_buff *ieee80211_null_func(struct ieee80211_device *ieee, if (!skb) return NULL; - hdr = (struct rtl_80211_hdr_3addr *)skb_put(skb,sizeof(struct rtl_80211_hdr_3addr)); + hdr = skb_put(skb, sizeof(struct rtl_80211_hdr_3addr)); memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN); memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); @@ -1086,8 +1084,7 @@ ieee80211_association_req(struct ieee80211_network *beacon, skb_reserve(skb, ieee->tx_headroom); - hdr = (struct ieee80211_assoc_request_frame *) - skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)+2); + hdr = skb_put(skb, sizeof(struct ieee80211_assoc_request_frame) + 2); hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; @@ -3110,7 +3107,7 @@ static inline struct sk_buff *ieee80211_disassociate_skb( if (!skb) return NULL; - disass = (struct ieee80211_disassoc *) skb_put(skb, sizeof(struct ieee80211_disassoc)); + disass = skb_put(skb, sizeof(struct ieee80211_disassoc)); disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC); disass->header.duration_id = 0; diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c index e82b5073c3f1..8aa38dcf0dfd 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c @@ -125,7 +125,7 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, P memset(skb->data, 0, sizeof( struct rtl_80211_hdr_3addr)); //I wonder whether it's necessary. Apparently kernel will not do it when alloc a skb. skb_reserve(skb, ieee->tx_headroom); - BAReq = ( struct rtl_80211_hdr_3addr *) skb_put(skb,sizeof( struct rtl_80211_hdr_3addr)); + BAReq = skb_put(skb, sizeof(struct rtl_80211_hdr_3addr)); memcpy(BAReq->addr1, Dst, ETH_ALEN); memcpy(BAReq->addr2, ieee->dev->dev_addr, ETH_ALEN); @@ -135,7 +135,7 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, P BAReq->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame //tag += sizeof( struct rtl_80211_hdr_3addr); //move to action field - tag = (u8 *)skb_put(skb, 9); + tag = skb_put(skb, 9); *tag ++= ACT_CAT_BA; *tag ++= type; // Dialog Token @@ -209,14 +209,14 @@ static struct sk_buff *ieee80211_DELBA( // memset(skb->data, 0, len+sizeof( struct rtl_80211_hdr_3addr)); skb_reserve(skb, ieee->tx_headroom); - Delba = ( struct rtl_80211_hdr_3addr *) skb_put(skb,sizeof( struct rtl_80211_hdr_3addr)); + Delba = skb_put(skb, sizeof(struct rtl_80211_hdr_3addr)); memcpy(Delba->addr1, dst, ETH_ALEN); memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN); Delba->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame - tag = (u8 *)skb_put(skb, 6); + tag = skb_put(skb, 6); *tag ++= ACT_CAT_BA; *tag ++= ACT_DELBA; diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c index 939c6ec51e4d..15cd1e33b16b 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c @@ -1085,7 +1085,7 @@ cxgbit_pass_accept_rpl(struct cxgbit_sock *csk, struct cpl_pass_accept_req *req) return; } - rpl5 = (struct cpl_t5_pass_accept_rpl *)__skb_put(skb, len); + rpl5 = __skb_put(skb, len); memset(rpl5, 0, len); INIT_TP_WR(rpl5, csk->tid); @@ -1367,7 +1367,7 @@ u32 cxgbit_send_tx_flowc_wr(struct cxgbit_sock *csk) flowclen16 = cxgbit_tx_flowc_wr_credits(csk, &nparams, &flowclen); skb = __skb_dequeue(&csk->skbq); - flowc = (struct fw_flowc_wr *)__skb_put(skb, flowclen); + flowc = __skb_put(skb, flowclen); memset(flowc, 0, flowclen); flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) | @@ -1439,7 +1439,7 @@ int cxgbit_setup_conn_digest(struct cxgbit_sock *csk) return -ENOMEM; /* set up ulp submode */ - req = (struct cpl_set_tcb_field *)__skb_put(skb, len); + req = __skb_put(skb, len); memset(req, 0, len); INIT_TP_WR(req, csk->tid); @@ -1476,7 +1476,7 @@ int cxgbit_setup_conn_pgidx(struct cxgbit_sock *csk, u32 pg_idx) if (!skb) return -ENOMEM; - req = (struct cpl_set_tcb_field *)__skb_put(skb, len); + req = __skb_put(skb, len); memset(req, 0, len); INIT_TP_WR(req, csk->tid); diff --git a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c index 5d78bdb7fc64..5fdb57cac968 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c @@ -79,7 +79,7 @@ cxgbit_ppod_init_idata(struct cxgbit_device *cdev, struct cxgbi_ppm *ppm, if (!skb) return NULL; - req = (struct ulp_mem_io *)__skb_put(skb, wr_len); + req = __skb_put(skb, wr_len); INIT_ULPTX_WR(req, wr_len, 0, tid); req->wr.wr_hi = htonl(FW_WR_OP_V(FW_ULPTX_WR) | FW_WR_ATOMIC_V(0)); diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 630616aaa861..a9c28c72c1c7 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1047,7 +1047,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, crc = ~crc32_le(~0, skb->data, skb->len); - crc_pos = (void *) skb_put(skb, sizeof(uint32_t)); + crc_pos = skb_put(skb, sizeof(uint32_t)); put_unaligned_le32(crc, crc_pos); } @@ -1097,8 +1097,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, goto err; ncm->skb_tx_ndp->dev = ncm->netdev; - ntb_ndp = (void *) skb_put(ncm->skb_tx_ndp, - opts->ndp_size); + ntb_ndp = skb_put(ncm->skb_tx_ndp, opts->ndp_size); memset(ntb_ndp, 0, ncb_len); /* dwSignature */ put_unaligned_le32(ncm->ndp_sign, ntb_ndp); -- cgit v1.2.3 From af72868b9070d1b843c829f0d0d0b22c04a20815 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Jun 2017 14:29:22 +0200 Subject: networking: make skb_pull & friends return void pointers It seems like a historic accident that these return unsigned char *, and in many places that means casts are required, more often than not. Make these functions return void * and remove all the casts across the tree, adding a (u8 *) cast only where the unsigned char pointer was used directly, all done with the following spatch: @@ expression SKB, LEN; typedef u8; identifier fn = { skb_pull, __skb_pull, skb_pull_inline, __pskb_pull_tail, __pskb_pull, pskb_pull }; @@ - *(fn(SKB, LEN)) + *(u8 *)fn(SKB, LEN) @@ expression E, SKB, LEN; identifier fn = { skb_pull, __skb_pull, skb_pull_inline, __pskb_pull_tail, __pskb_pull, pskb_pull }; type T; @@ - E = ((T *)(fn(SKB, LEN))) + E = fn(SKB, LEN) Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/bluetooth/hci_nokia.c | 4 ++-- drivers/isdn/i4l/isdn_ppp.c | 2 +- drivers/net/wan/hdlc_ppp.c | 2 +- drivers/nfc/nxp-nci/firmware.c | 3 +-- drivers/scsi/fnic/fnic_fcs.c | 2 +- drivers/scsi/qedf/qedf_main.c | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c index c1b081725b2c..072a77a61e67 100644 --- a/drivers/bluetooth/hci_nokia.c +++ b/drivers/bluetooth/hci_nokia.c @@ -557,7 +557,7 @@ static int nokia_recv_negotiation_packet(struct hci_dev *hdev, goto finish_neg; } - evt = (struct hci_nokia_neg_evt *)skb_pull(skb, sizeof(*hdr)); + evt = skb_pull(skb, sizeof(*hdr)); if (evt->ack != NOKIA_NEG_ACK) { dev_err(dev, "Negotiation received: wrong reply"); @@ -595,7 +595,7 @@ static int nokia_recv_alive_packet(struct hci_dev *hdev, struct sk_buff *skb) goto finish_alive; } - pkt = (struct hci_nokia_alive_pkt *)skb_pull(skb, sizeof(*hdr)); + pkt = skb_pull(skb, sizeof(*hdr)); if (pkt->mid != NOKIA_ALIVE_RESP) { dev_err(dev, "Alive received: invalid response: 0x%02x!", diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 9ce23cf3d7d2..e26cae9baf17 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1509,7 +1509,7 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp) * temporarily remove part of the fake header stuck on * earlier. */ - *skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */ + *(u8 *)skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */ { __be16 *p = (__be16 *)skb->data; diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index fa3460a0dbbe..0d2e00ece804 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -448,7 +448,7 @@ static int ppp_rx(struct sk_buff *skb) /* Check HDLC header */ if (skb->len < sizeof(struct hdlc_header)) goto rx_error; - cp = (struct cp_header*)skb_pull(skb, sizeof(struct hdlc_header)); + cp = skb_pull(skb, sizeof(struct hdlc_header)); if (hdr->address != HDLC_ADDR_ALLSTATIONS || hdr->control != HDLC_CTRL_UI) goto rx_error; diff --git a/drivers/nfc/nxp-nci/firmware.c b/drivers/nfc/nxp-nci/firmware.c index 99ffee1dfd1e..e50c6f67bb39 100644 --- a/drivers/nfc/nxp-nci/firmware.c +++ b/drivers/nfc/nxp-nci/firmware.c @@ -311,8 +311,7 @@ void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb) if (nxp_nci_fw_check_crc(skb) != 0x00) fw_info->cmd_result = -EBADMSG; else - fw_info->cmd_result = nxp_nci_fw_read_status( - *skb_pull(skb, NXP_NCI_FW_HDR_LEN)); + fw_info->cmd_result = nxp_nci_fw_read_status(*(u8 *)skb_pull(skb, NXP_NCI_FW_HDR_LEN)); kfree_skb(skb); } else { fw_info->cmd_result = -EIO; diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 245dcd95e11f..e3b964b7235a 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -640,7 +640,7 @@ static inline int fnic_import_rq_eth_pkt(struct fnic *fnic, struct sk_buff *skb) eh = (struct ethhdr *)skb->data; if (eh->h_proto == htons(ETH_P_8021Q)) { memmove((u8 *)eh + VLAN_HLEN, eh, ETH_ALEN * 2); - eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); + eh = skb_pull(skb, VLAN_HLEN); skb_reset_mac_header(skb); } if (eh->h_proto == htons(ETH_P_FIP)) { diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index da0fcce6f842..542a6e75c2bb 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2117,7 +2117,7 @@ static void qedf_ll2_process_skb(struct work_struct *work) /* Undo VLAN encapsulation */ if (eh->h_proto == htons(ETH_P_8021Q)) { memmove((u8 *)eh + VLAN_HLEN, eh, ETH_ALEN * 2); - eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); + eh = skb_pull(skb, VLAN_HLEN); skb_reset_mac_header(skb); } -- cgit v1.2.3 From d58ff35122847a83ba55394e2ae3a1527b6febf5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Jun 2017 14:29:23 +0200 Subject: networking: make skb_push & __skb_push return void pointers It seems like a historic accident that these return unsigned char *, and in many places that means casts are required, more often than not. Make these functions return void * and remove all the casts across the tree, adding a (u8 *) cast only where the unsigned char pointer was used directly, all done with the following spatch: @@ expression SKB, LEN; typedef u8; identifier fn = { skb_push, __skb_push, skb_push_rcsum }; @@ - *(fn(SKB, LEN)) + *(u8 *)fn(SKB, LEN) @@ expression E, SKB, LEN; identifier fn = { skb_push, __skb_push, skb_push_rcsum }; type T; @@ - E = ((T *)(fn(SKB, LEN))) + E = fn(SKB, LEN) @@ expression SKB, LEN; identifier fn = { skb_push, __skb_push, skb_push_rcsum }; @@ - fn(SKB, LEN)[0] + *(u8 *)fn(SKB, LEN) Note that the last part there converts from push(...)[0] to the more idiomatic *(u8 *)push(...). Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/atm/solos-pci.c | 2 +- drivers/bluetooth/bpa10x.c | 2 +- drivers/firewire/net.c | 8 +++--- drivers/infiniband/hw/cxgb3/iwch_cm.c | 6 ++--- drivers/infiniband/hw/cxgb4/cm.c | 2 +- drivers/infiniband/ulp/ipoib/ipoib_main.c | 4 +-- drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c | 2 +- drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c | 2 +- drivers/isdn/i4l/isdn_ppp.c | 2 +- drivers/net/arcnet/arc-rawmode.c | 2 +- drivers/net/arcnet/capmode.c | 2 +- drivers/net/arcnet/rfc1051.c | 2 +- drivers/net/arcnet/rfc1201.c | 2 +- drivers/net/ethernet/broadcom/bcmsysport.c | 2 +- drivers/net/ethernet/chelsio/cxgb/sge.c | 4 +-- drivers/net/ethernet/freescale/gianfar.c | 2 +- .../net/ethernet/mellanox/mlx5/core/en_selftest.c | 2 +- drivers/net/ethernet/sun/niu.c | 2 +- drivers/net/ethernet/toshiba/ps3_gelic_net.c | 2 +- drivers/net/geneve.c | 3 +-- drivers/net/gtp.c | 4 +-- drivers/net/hippi/rrunner.c | 2 +- drivers/net/macsec.c | 2 +- drivers/net/ppp/ppp_async.c | 2 +- drivers/net/ppp/ppp_generic.c | 6 ++--- drivers/net/ppp/ppp_synctty.c | 2 +- drivers/net/ppp/pptp.c | 2 +- drivers/net/usb/gl620a.c | 2 +- drivers/net/usb/int51x1.c | 2 +- drivers/net/usb/kaweth.c | 2 +- drivers/net/usb/lg-vl600.c | 2 +- drivers/net/usb/net1080.c | 2 +- drivers/net/usb/qmi_wwan.c | 2 +- drivers/net/usb/rndis_host.c | 2 +- drivers/net/vrf.c | 2 +- drivers/net/vxlan.c | 2 +- drivers/net/wimax/i2400m/netdev.c | 2 +- drivers/net/wireless/admtek/adm8211.c | 2 +- drivers/net/wireless/ath/ar5523/ar5523.c | 4 +-- drivers/net/wireless/ath/ath6kl/htc_pipe.c | 3 +-- drivers/net/wireless/ath/ath9k/hif_usb.c | 2 +- drivers/net/wireless/ath/ath9k/htc_hst.c | 3 +-- drivers/net/wireless/ath/ath9k/wmi.c | 2 +- drivers/net/wireless/ath/carl9170/tx.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.c | 2 +- .../net/wireless/intersil/hostap/hostap_80211_rx.c | 8 +++--- drivers/net/wireless/intersil/orinoco/main.c | 7 +++-- drivers/net/wireless/intersil/p54/txrx.c | 4 +-- drivers/net/wireless/intersil/prism54/islpci_eth.c | 5 +--- drivers/net/wireless/mac80211_hwsim.c | 4 +-- drivers/net/wireless/marvell/libertas/rx.c | 2 +- drivers/net/wireless/marvell/libertas_tf/main.c | 2 +- drivers/net/wireless/mediatek/mt7601u/tx.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 6 ++--- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- .../net/wireless/realtek/rtlwifi/rtl8192cu/trx.c | 2 +- drivers/net/wireless/st/cw1200/txrx.c | 2 +- drivers/net/wireless/ti/wl1251/tx.c | 3 +-- drivers/net/wireless/ti/wlcore/cmd.c | 2 +- drivers/net/wireless/ti/wlcore/tx.c | 3 +-- drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 3 +-- drivers/nfc/fdp/i2c.c | 4 +-- drivers/nfc/microread/i2c.c | 2 +- drivers/nfc/microread/microread.c | 4 +-- drivers/nfc/nfcmrvl/main.c | 2 +- drivers/nfc/pn533/pn533.c | 8 +++--- drivers/nfc/pn544/i2c.c | 2 +- drivers/nfc/pn544/pn544.c | 8 +++--- drivers/nfc/st-nci/ndlc.c | 2 +- drivers/nfc/st21nfca/core.c | 6 ++--- drivers/nfc/st21nfca/dep.c | 30 +++++++++++----------- drivers/nfc/st21nfca/i2c.c | 4 +-- drivers/s390/net/qeth_l2_main.c | 3 +-- drivers/s390/net/qeth_l3_main.c | 6 ++--- drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 2 +- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 2 +- drivers/scsi/fcoe/fcoe_ctlr.c | 2 +- drivers/scsi/fnic/fnic_fcs.c | 7 +++-- drivers/scsi/qedf/qedf_fip.c | 3 +-- drivers/staging/wilc1000/linux_mon.c | 6 ++--- drivers/staging/wlan-ng/p80211conv.c | 14 ++++------ drivers/target/iscsi/cxgbit/cxgbit_target.c | 5 ++-- drivers/usb/gadget/function/rndis.c | 2 +- 83 files changed, 135 insertions(+), 161 deletions(-) (limited to 'drivers') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 4fc99ae1c534..c8f2ca6d8b29 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -1174,7 +1174,7 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb) } } - header = (void *)skb_push(skb, sizeof(*header)); + header = skb_push(skb, sizeof(*header)); /* This does _not_ include the size of the header */ header->size = cpu_to_le16(pktlen); diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index a9932fe57d92..48d10cb5c9a1 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -297,7 +297,7 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb) return -ENOMEM; /* Prepend skb with frame type */ - *skb_push(skb, 1) = hci_skb_pkt_type(skb); + *(u8 *)skb_push(skb, 1) = hci_skb_pkt_type(skb); switch (hci_skb_pkt_type(skb)) { case HCI_COMMAND_PKT: diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index d5040bbd34e8..242359c2d1f1 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -219,7 +219,7 @@ static int fwnet_header_create(struct sk_buff *skb, struct net_device *net, { struct fwnet_header *h; - h = (struct fwnet_header *)skb_push(skb, sizeof(*h)); + h = skb_push(skb, sizeof(*h)); put_unaligned_be16(type, &h->h_proto); if (net->flags & (IFF_LOOPBACK | IFF_NOARP)) { @@ -961,16 +961,14 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) tx_len = ptask->max_payload; switch (fwnet_get_hdr_lf(&ptask->hdr)) { case RFC2374_HDR_UNFRAG: - bufhdr = (struct rfc2734_header *) - skb_push(ptask->skb, RFC2374_UNFRAG_HDR_SIZE); + bufhdr = skb_push(ptask->skb, RFC2374_UNFRAG_HDR_SIZE); put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0); break; case RFC2374_HDR_FIRSTFRAG: case RFC2374_HDR_INTFRAG: case RFC2374_HDR_LASTFRAG: - bufhdr = (struct rfc2734_header *) - skb_push(ptask->skb, RFC2374_FRAG_HDR_SIZE); + bufhdr = skb_push(ptask->skb, RFC2374_FRAG_HDR_SIZE); put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0); put_unaligned_be32(ptask->hdr.w1, &bufhdr->w1); break; diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 9ae518c01bc2..86975370a4c0 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -513,7 +513,7 @@ static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb) set_arp_failure_handler(skb, arp_failure_discard); skb_reset_transport_header(skb); len = skb->len; - req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); + req = skb_push(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(len); @@ -564,7 +564,7 @@ static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen) skb->priority = CPL_PRIORITY_DATA; set_arp_failure_handler(skb, arp_failure_discard); skb_reset_transport_header(skb); - req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); + req = skb_push(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(mpalen); @@ -615,7 +615,7 @@ static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen) set_arp_failure_handler(skb, arp_failure_discard); skb_reset_transport_header(skb); len = skb->len; - req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); + req = skb_push(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(len); diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 36ae3023e703..76fb39415e18 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -3751,7 +3751,7 @@ static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos) tcp_clear_options(&tmp_opt); tcp_parse_options(&init_net, skb, &tmp_opt, 0, NULL); - req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req)); + req = __skb_push(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->l2info = cpu_to_be16(SYN_INTF_V(intf) | SYN_MAC_IDX_V(RX_MACIDX_G( diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index a115c0b7a310..5da6f2e9f22e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -681,7 +681,7 @@ static void push_pseudo_header(struct sk_buff *skb, const char *daddr) { struct ipoib_pseudo_header *phdr; - phdr = (struct ipoib_pseudo_header *)skb_push(skb, sizeof(*phdr)); + phdr = skb_push(skb, sizeof(*phdr)); memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); } @@ -1129,7 +1129,7 @@ static int ipoib_hard_header(struct sk_buff *skb, { struct ipoib_header *header; - header = (struct ipoib_header *) skb_push(skb, sizeof *header); + header = skb_push(skb, sizeof *header); header->proto = htons(type); header->reserved = 0; diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c index 2e8fee982436..afa938bd26d6 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c @@ -460,7 +460,7 @@ void opa_vnic_encap_skb(struct opa_vnic_adapter *adapter, struct sk_buff *skb) sc = opa_vnic_get_sc(info, skb); l4_hdr = info->vesw.vesw_id; - mdata = (struct opa_vnic_skb_mdata *)skb_push(skb, sizeof(*mdata)); + mdata = skb_push(skb, sizeof(*mdata)); mdata->vl = opa_vnic_get_vl(adapter, skb); mdata->entropy = entropy; mdata->flags = 0; diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c index 905f39dda5aa..fcf75323d62a 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c @@ -103,7 +103,7 @@ static u16 opa_vnic_select_queue(struct net_device *netdev, struct sk_buff *skb, int rc; /* pass entropy and vl as metadata in skb */ - mdata = (struct opa_vnic_skb_mdata *)skb_push(skb, sizeof(*mdata)); + mdata = skb_push(skb, sizeof(*mdata)); mdata->entropy = opa_vnic_calc_entropy(adapter, skb); mdata->vl = opa_vnic_get_vl(adapter, skb); rc = adapter->rn_ops->ndo_select_queue(netdev, skb, diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index e26cae9baf17..b7e3f1cde683 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1312,7 +1312,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) /* check if we should pass this packet * the filter instructions are constructed assuming * a four-byte PPP header on each packet */ - *skb_push(skb, 4) = 1; /* indicate outbound */ + *(u8 *)skb_push(skb, 4) = 1; /* indicate outbound */ { __be16 *p = (__be16 *)skb->data; diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c index d78f30186642..8c651fdee039 100644 --- a/drivers/net/arcnet/arc-rawmode.c +++ b/drivers/net/arcnet/arc-rawmode.c @@ -85,7 +85,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, uint8_t daddr) { int hdr_size = ARC_HDR_SIZE; - struct archdr *pkt = (struct archdr *)skb_push(skb, hdr_size); + struct archdr *pkt = skb_push(skb, hdr_size); /* Set the source hardware address. * diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c index 2056878fb087..a80f4eb9262d 100644 --- a/drivers/net/arcnet/capmode.c +++ b/drivers/net/arcnet/capmode.c @@ -101,7 +101,7 @@ static int build_header(struct sk_buff *skb, uint8_t daddr) { int hdr_size = ARC_HDR_SIZE; - struct archdr *pkt = (struct archdr *)skb_push(skb, hdr_size); + struct archdr *pkt = skb_push(skb, hdr_size); arc_printk(D_PROTO, dev, "Preparing header for cap packet %x.\n", *((int *)&pkt->soft.cap.cookie[0])); diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c index 4b1a75469cb1..a7752a5b647f 100644 --- a/drivers/net/arcnet/rfc1051.c +++ b/drivers/net/arcnet/rfc1051.c @@ -162,7 +162,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, uint8_t daddr) { int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; - struct archdr *pkt = (struct archdr *)skb_push(skb, hdr_size); + struct archdr *pkt = skb_push(skb, hdr_size); struct arc_rfc1051 *soft = &pkt->soft.rfc1051; /* set the protocol ID according to RFC1051 */ diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c index 566da5ecdc9d..a4c856282674 100644 --- a/drivers/net/arcnet/rfc1201.c +++ b/drivers/net/arcnet/rfc1201.c @@ -379,7 +379,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, { struct arcnet_local *lp = netdev_priv(dev); int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; - struct archdr *pkt = (struct archdr *)skb_push(skb, hdr_size); + struct archdr *pkt = skb_push(skb, hdr_size); struct arc_rfc1201 *soft = &pkt->soft.rfc1201; /* set the protocol ID according to RFC1201 */ diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 5274501428e4..5333601f855f 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1099,7 +1099,7 @@ static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb, skb = nskb; } - tsb = (struct bcm_tsb *)skb_push(skb, sizeof(*tsb)); + tsb = skb_push(skb, sizeof(*tsb)); /* Zero-out TSB by default */ memset(tsb, 0, sizeof(*tsb)); diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c index d56142b98534..0f13a7f7c1d3 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb/sge.c @@ -1801,7 +1801,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) eth_type = skb_network_offset(skb) == ETH_HLEN ? CPL_ETH_II : CPL_ETH_II_VLAN; - hdr = (struct cpl_tx_pkt_lso *)skb_push(skb, sizeof(*hdr)); + hdr = skb_push(skb, sizeof(*hdr)); hdr->opcode = CPL_TX_PKT_LSO; hdr->ip_csum_dis = hdr->l4_csum_dis = 0; hdr->ip_hdr_words = ip_hdr(skb)->ihl; @@ -1849,7 +1849,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) } } - cpl = (struct cpl_tx_pkt *)__skb_push(skb, sizeof(*cpl)); + cpl = __skb_push(skb, sizeof(*cpl)); cpl->opcode = CPL_TX_PKT; cpl->ip_csum_dis = 1; /* SW calculates IP csum */ cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_PARTIAL ? 0 : 1; diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 0ff166ec3e7e..a79e257bc338 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2250,7 +2250,7 @@ static int gfar_enet_open(struct net_device *dev) static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb) { - struct txfcb *fcb = (struct txfcb *)skb_push(skb, GMAC_FCB_LEN); + struct txfcb *fcb = skb_push(skb, GMAC_FCB_LEN); memset(fcb, 0, GMAC_FCB_LEN); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c index c456ca07b562..898759fcf9ec 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c @@ -132,7 +132,7 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv) skb_reserve(skb, NET_IP_ALIGN); /* Reserve for ethernet and IP header */ - ethh = (struct ethhdr *)skb_push(skb, ETH_HLEN); + ethh = skb_push(skb, ETH_HLEN); skb_reset_mac_header(skb); skb_set_network_header(skb, skb->len); diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index 2dcca249eb9c..46cb7f8955a2 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -6667,7 +6667,7 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb, headroom = align + sizeof(struct tx_pkt_hdr); ehdr = (struct ethhdr *) skb->data; - tp = (struct tx_pkt_hdr *) skb_push(skb, headroom); + tp = skb_push(skb, headroom); len = skb->len - sizeof(struct tx_pkt_hdr); tp->flags = cpu_to_le64(niu_compute_tx_flags(skb, ehdr, align, len)); diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c index fa6a06571187..88d74aef218a 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c @@ -754,7 +754,7 @@ static struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb, return NULL; dev_kfree_skb_any(sk_tmp); } - veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); + veth = skb_push(skb, VLAN_HLEN); /* Move the mac addresses to the top of buffer */ memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN); diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 7bcf1b52020e..d586ad93aaff 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -687,8 +687,7 @@ static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb, if (err) goto free_dst; - gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + - info->options_len); + gnvh = __skb_push(skb, sizeof(*gnvh) + info->options_len); geneve_build_header(gnvh, info); skb_set_inner_protocol(skb, htons(ETH_P_TEB)); return 0; diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index ca110cd2a4e4..8e333a8a2295 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -398,7 +398,7 @@ static inline void gtp0_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) int payload_len = skb->len; struct gtp0_header *gtp0; - gtp0 = (struct gtp0_header *) skb_push(skb, sizeof(*gtp0)); + gtp0 = skb_push(skb, sizeof(*gtp0)); gtp0->flags = 0x1e; /* v0, GTP-non-prime. */ gtp0->type = GTP_TPDU; @@ -415,7 +415,7 @@ static inline void gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) int payload_len = skb->len; struct gtp1_header *gtp1; - gtp1 = (struct gtp1_header *) skb_push(skb, sizeof(*gtp1)); + gtp1 = skb_push(skb, sizeof(*gtp1)); /* Bits 8 7 6 5 4 3 2 1 * +--+--+--+--+--+--+--+--+ diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index 7683fd544344..71ddadbf2368 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -1422,7 +1422,7 @@ static netdev_tx_t rr_start_xmit(struct sk_buff *skb, skb = new_skb; } - ifield = (u32 *)skb_push(skb, 8); + ifield = skb_push(skb, 8); ifield[0] = 0; ifield[1] = hcb->ifield; diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 2067dcc71535..e370d7c894cb 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -697,7 +697,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, unprotected_len = skb->len; eth = eth_hdr(skb); sci_present = send_sci(secy); - hh = (struct macsec_eth_header *)skb_push(skb, macsec_extra_len(sci_present)); + hh = skb_push(skb, macsec_extra_len(sci_present)); memmove(hh, eth, 2 * ETH_ALEN); pn = tx_sa_update_pn(tx_sa, secy); diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 32c72db654e2..814fd8fae67d 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -802,7 +802,7 @@ process_input_packet(struct asyncppp *ap) proto = p[0]; if (proto & 1) { /* protocol is compressed */ - skb_push(skb, 1)[0] = 0; + *(u8 *)skb_push(skb, 1) = 0; } else { if (skb->len < 2) goto err; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index bbded33120fe..d42091f11eb8 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1490,7 +1490,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) /* check if we should pass this packet */ /* the filter instructions are constructed assuming a four-byte PPP header on each packet */ - *skb_push(skb, 2) = 1; + *(u8 *)skb_push(skb, 2) = 1; if (ppp->pass_filter && BPF_PROG_RUN(ppp->pass_filter, skb) == 0) { if (ppp->debug & 1) @@ -2133,7 +2133,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) if (skb_unclone(skb, GFP_ATOMIC)) goto err; - *skb_push(skb, 2) = 0; + *(u8 *)skb_push(skb, 2) = 0; if (ppp->pass_filter && BPF_PROG_RUN(ppp->pass_filter, skb) == 0) { if (ppp->debug & 1) @@ -2267,7 +2267,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) * Do protocol ID decompression on the first fragment of each packet. */ if ((PPP_MP_CB(skb)->BEbits & B) && (skb->data[0] & 1)) - *skb_push(skb, 1) = 0; + *(u8 *)skb_push(skb, 1) = 0; /* * Expand sequence number to 32 bits, making it as close diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index ce2300c0bcbf..ef08590db873 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -711,7 +711,7 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf, /* decompress protocol field if compressed */ if (p[0] & 1) { /* protocol is compressed */ - skb_push(skb, 1)[0] = 0; + *(u8 *)skb_push(skb, 1) = 0; } else if (skb->len < 2) goto err; diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 1951b1085cb8..2f22e318a67f 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -328,7 +328,7 @@ allow_packet: if ((*skb->data) & 1) { /* protocol is compressed */ - skb_push(skb, 1)[0] = 0; + *(u8 *)skb_push(skb, 1) = 0; } skb->ip_summed = CHECKSUM_NONE; diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index 29276e54bb8b..ba1ce1006c4f 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -174,7 +174,7 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) } // attach the packet count to the header - packet_count = (__le32 *) skb_push(skb, (4 + 4*1)); + packet_count = skb_push(skb, (4 + 4 * 1)); packet_len = packet_count + 1; *packet_count = cpu_to_le32(1); diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c index 5a43b77a6b9c..be63a829b8fe 100644 --- a/drivers/net/usb/int51x1.c +++ b/drivers/net/usb/int51x1.c @@ -106,7 +106,7 @@ static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev, pack_len += need_tail; pack_len &= 0x07ff; - len = (__le16 *) __skb_push(skb, INT51X1_HEADER_SIZE); + len = __skb_push(skb, INT51X1_HEADER_SIZE); *len = cpu_to_le16(pack_len); if(need_tail) diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 37fb621fde86..92e4fd29ae44 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -809,7 +809,7 @@ static netdev_tx_t kaweth_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } - private_header = (__le16 *)__skb_push(skb, 2); + private_header = __skb_push(skb, 2); *private_header = cpu_to_le16(skb->len-2); kaweth->tx_skb = skb; diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index d633492bf9eb..dbabd7ca5268 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -304,7 +304,7 @@ encapsulate: memset(&packet->dummy, 0, sizeof(packet->dummy)); packet->len = cpu_to_le32(orig_len); - frame = (struct vl600_frame_hdr *) skb_push(skb, sizeof(*frame)); + frame = skb_push(skb, sizeof(*frame)); memset(frame, 0, sizeof(*frame)); frame->len = cpu_to_le32(full_len); frame->serial = cpu_to_le32(serial++); diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index 861ff45f0b09..be53ff30b7b5 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -466,7 +466,7 @@ net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) encapsulate: /* header first */ - header = (struct nc_header *) skb_push(skb, sizeof *header); + header = skb_push(skb, sizeof *header); header->hdr_len = cpu_to_le16(sizeof (*header)); header->packet_len = cpu_to_le16(len); header->packet_id = cpu_to_le16((u16)dev->xid++); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index ffd229ec8352..5894e3c9468f 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -101,7 +101,7 @@ static netdev_tx_t qmimux_start_xmit(struct sk_buff *skb, struct net_device *dev unsigned int len = skb->len; struct qmimux_hdr *hdr; - hdr = (struct qmimux_hdr *)skb_push(skb, sizeof(struct qmimux_hdr)); + hdr = skb_push(skb, sizeof(struct qmimux_hdr)); hdr->pad = 0; hdr->mux_id = priv->mux_id; hdr->pkt_len = cpu_to_be16(len); diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index e96e2e5673d7..a151f267aebb 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -578,7 +578,7 @@ rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) * packets; Linux minimizes wasted bandwidth through tx queues. */ fill: - hdr = (void *) __skb_push(skb, sizeof *hdr); + hdr = __skb_push(skb, sizeof *hdr); memset(hdr, 0, sizeof *hdr); hdr->msg_type = cpu_to_le32(RNDIS_MSG_PACKET); hdr->msg_len = cpu_to_le32(skb->len); diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 022c0b5f9844..c6c0595d267b 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -383,7 +383,7 @@ static int vrf_finish_direct(struct net *net, struct sock *sk, if (!list_empty(&vrf_dev->ptype_all) && likely(skb_headroom(skb) >= ETH_HLEN)) { - struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); + struct ethhdr *eth = skb_push(skb, ETH_HLEN); ether_addr_copy(eth->h_source, vrf_dev->dev_addr); eth_zero_addr(eth->h_dest); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 4e1d427d340c..94ce98229828 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1827,7 +1827,7 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst, if (err) return err; - vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); + vxh = __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = VXLAN_HF_VNI; vxh->vx_vni = vxlan_vni_field(vni); diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index dd7f3168c07d..a654687b5fa2 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -221,7 +221,7 @@ void i2400m_tx_prep_header(struct sk_buff *skb) { struct i2400m_pl_data_hdr *pl_hdr; skb_pull(skb, ETH_HLEN); - pl_hdr = (struct i2400m_pl_data_hdr *) skb_push(skb, sizeof(*pl_hdr)); + pl_hdr = skb_push(skb, sizeof(*pl_hdr)); pl_hdr->reserved = 0; } diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index 5f64f3928c35..3b0802fc5bf5 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1700,7 +1700,7 @@ static void adm8211_tx(struct ieee80211_hw *dev, skb_pull(skb, hdrlen); payload_len = skb->len; - txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr)); + txhdr = skb_push(skb, sizeof(*txhdr)); memset(txhdr, 0, sizeof(*txhdr)); memcpy(txhdr->da, ieee80211_get_DA(hdr), ETH_ALEN); txhdr->signal = plcp_signal; diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index f2f4ccfdf8da..106d6f8d471a 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -829,8 +829,8 @@ static void ar5523_tx_work_locked(struct ar5523 *ar) data->ar = ar; data->urb = urb; - desc = (struct ar5523_tx_desc *)skb_push(skb, sizeof(*desc)); - chunk = (struct ar5523_chunk *)skb_push(skb, sizeof(*chunk)); + desc = skb_push(skb, sizeof(*desc)); + chunk = skb_push(skb, sizeof(*chunk)); chunk->seqnum = 0; chunk->flags = UATH_CFLAGS_FINAL; diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index b13d61111072..5c0ba83a44aa 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -228,8 +228,7 @@ static int htc_issue_packets(struct htc_target *target, payload_len = packet->act_len; /* setup HTC frame header */ - htc_hdr = (struct htc_frame_hdr *) skb_push(skb, - sizeof(*htc_hdr)); + htc_hdr = skb_push(skb, sizeof(*htc_hdr)); if (!htc_hdr) { WARN_ON_ONCE(1); status = -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 12aa8abbcba4..0d9687a2aa98 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -199,7 +199,7 @@ static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev, cmd->skb = skb; cmd->hif_dev = hif_dev; - hdr = (__le16 *) skb_push(skb, 4); + hdr = skb_push(skb, 4); *hdr++ = cpu_to_le16(skb->len - 4); *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 9fa8970a1f7d..1bf63a4efb4c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -26,8 +26,7 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, struct htc_endpoint *endpoint = &target->endpoint[epid]; int status; - hdr = (struct htc_frame_hdr *) - skb_push(skb, sizeof(struct htc_frame_hdr)); + hdr = skb_push(skb, sizeof(struct htc_frame_hdr)); hdr->endpoint_id = epid; hdr->flags = flags; hdr->payload_len = cpu_to_be16(len); diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index c51c69b1ad96..85d09fdef8dc 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -277,7 +277,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi, struct wmi_cmd_hdr *hdr; unsigned long flags; - hdr = (struct wmi_cmd_hdr *) skb_push(skb, sizeof(struct wmi_cmd_hdr)); + hdr = skb_push(skb, sizeof(struct wmi_cmd_hdr)); hdr->command_id = cpu_to_be16(cmd); hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 2bf04c9edc98..0cb5b58925dc 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -991,7 +991,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar, else cvif = NULL; - txc = (void *)skb_push(skb, sizeof(*txc)); + txc = skb_push(skb, sizeof(*txc)); memset(txc, 0, sizeof(*txc)); SET_VAL(CARL9170_TX_SUPER_MISC_QUEUE, txc->s.misc, hw_queue); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index edab4c0a900f..84d91606e6f3 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -363,7 +363,7 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, return; } - rtap_vendor = (void *)skb_push(skb, rtap_len); + rtap_vendor = skb_push(skb, rtap_len); memset(rtap_vendor, 0, rtap_len); rtap_vendor->rtap.rthdr.it_version = PKTHDR_RADIOTAP_VERSION; diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c index 34dbddbf3f9b..6d8b64ca1a63 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c @@ -131,8 +131,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, if (prism_header == 1) { struct linux_wlan_ng_prism_hdr *hdr; - hdr = (struct linux_wlan_ng_prism_hdr *) - skb_push(skb, phdrlen); + hdr = skb_push(skb, phdrlen); memset(hdr, 0, phdrlen); hdr->msgcode = LWNG_CAP_DID_BASE; hdr->msglen = sizeof(*hdr); @@ -153,8 +152,7 @@ hdr->f.status = s; hdr->f.len = l; hdr->f.data = d #undef LWNG_SETVAL } else if (prism_header == 2) { struct linux_wlan_ng_cap_hdr *hdr; - hdr = (struct linux_wlan_ng_cap_hdr *) - skb_push(skb, phdrlen); + hdr = skb_push(skb, phdrlen); memset(hdr, 0, phdrlen); hdr->version = htonl(LWNG_CAPHDR_VERSION); hdr->length = htonl(phdrlen); @@ -172,7 +170,7 @@ hdr->f.status = s; hdr->f.len = l; hdr->f.data = d hdr->encoding = htonl(1); /* cck */ } else if (prism_header == 3) { struct hostap_radiotap_rx *hdr; - hdr = (struct hostap_radiotap_rx *)skb_push(skb, phdrlen); + hdr = skb_push(skb, phdrlen); memset(hdr, 0, phdrlen); hdr->hdr.it_len = cpu_to_le16(phdrlen); hdr->hdr.it_present = diff --git a/drivers/net/wireless/intersil/orinoco/main.c b/drivers/net/wireless/intersil/orinoco/main.c index f7abc439fb92..28dac36d7c4c 100644 --- a/drivers/net/wireless/intersil/orinoco/main.c +++ b/drivers/net/wireless/intersil/orinoco/main.c @@ -396,7 +396,7 @@ int orinoco_process_xmit_skb(struct sk_buff *skb, memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr)); /* Make room for the new header, and copy it in */ - eh = (struct ethhdr *) skb_push(skb, ENCAPS_OVERHEAD); + eh = skb_push(skb, ENCAPS_OVERHEAD); memcpy(eh, &hdr, sizeof(hdr)); } @@ -1029,11 +1029,10 @@ static void orinoco_rx(struct net_device *dev, /* These indicate a SNAP within 802.2 LLC within 802.11 frame which we'll need to de-encapsulate to the original EthernetII frame. */ - hdr = (struct ethhdr *)skb_push(skb, - ETH_HLEN - ENCAPS_OVERHEAD); + hdr = skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD); } else { /* 802.3 frame - prepend 802.3 header as is */ - hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN); + hdr = skb_push(skb, ETH_HLEN); hdr->h_proto = htons(length); } memcpy(hdr->h_dest, desc->addr1, ETH_ALEN); diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c index b00c07d72f95..3a4214d362ff 100644 --- a/drivers/net/wireless/intersil/p54/txrx.c +++ b/drivers/net/wireless/intersil/p54/txrx.c @@ -815,8 +815,8 @@ void p54_tx_80211(struct ieee80211_hw *dev, } } - txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); - hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); + txhdr = skb_push(skb, sizeof(*txhdr) + padding); + hdr = skb_push(skb, sizeof(*hdr)); if (padding) hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; diff --git a/drivers/net/wireless/intersil/prism54/islpci_eth.c b/drivers/net/wireless/intersil/prism54/islpci_eth.c index d83f6332019e..9b0ded733294 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_eth.c +++ b/drivers/net/wireless/intersil/prism54/islpci_eth.c @@ -276,10 +276,7 @@ islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb) } /* make room for the new header and fill it. */ - avs = - (struct avs_80211_1_header *) skb_push(*skb, - sizeof (struct - avs_80211_1_header)); + avs = skb_push(*skb, sizeof(struct avs_80211_1_header)); avs->version = cpu_to_be32(P80211CAPTURE_VERSION); avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 7418088e296f..c8852acc1462 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -848,7 +848,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, if (skb == NULL) return; - hdr = (struct hwsim_radiotap_hdr *) skb_push(skb, sizeof(*hdr)); + hdr = skb_push(skb, sizeof(*hdr)); hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; hdr->hdr.it_pad = 0; hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); @@ -1146,7 +1146,7 @@ static void mac80211_hwsim_add_vendor_rtap(struct sk_buff *skb) * Note that this code requires the headroom in the SKB * that was allocated earlier. */ - rtap = (void *)skb_push(skb, sizeof(*rtap) + 8 + 4); + rtap = skb_push(skb, sizeof(*rtap) + 8 + 4); rtap->oui[0] = HWSIM_RADIOTAP_OUI[0]; rtap->oui[1] = HWSIM_RADIOTAP_OUI[1]; rtap->oui[2] = HWSIM_RADIOTAP_OUI[2]; diff --git a/drivers/net/wireless/marvell/libertas/rx.c b/drivers/net/wireless/marvell/libertas/rx.c index a18bb7a9889c..7586ff681b23 100644 --- a/drivers/net/wireless/marvell/libertas/rx.c +++ b/drivers/net/wireless/marvell/libertas/rx.c @@ -257,7 +257,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, goto done; } - pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); + pradiotap_hdr = skb_push(skb, sizeof(struct rx_radiotap_hdr)); memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index d80333117989..81228bf73043 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -260,7 +260,7 @@ static void lbtf_tx_work(struct work_struct *work) len = skb->len; info = IEEE80211_SKB_CB(skb); - txpd = (struct txpd *) skb_push(skb, sizeof(struct txpd)); + txpd = skb_push(skb, sizeof(struct txpd)); if (priv->surpriseremoved) { dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c index ad77bec1ba0f..3600e911a63e 100644 --- a/drivers/net/wireless/mediatek/mt7601u/tx.c +++ b/drivers/net/wireless/mediatek/mt7601u/tx.c @@ -148,7 +148,7 @@ mt7601u_push_txwi(struct mt7601u_dev *dev, struct sk_buff *skb, u16 rate_ctl; u8 nss; - txwi = (struct mt76_txwi *)skb_push(skb, sizeof(struct mt76_txwi)); + txwi = skb_push(skb, sizeof(struct mt76_txwi)); memset(txwi, 0, sizeof(*txwi)); if (!wcid->tx_rate_set) diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 35fe991dcc56..55198ac2b755 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -278,8 +278,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, } if (!priv->is_rtl8187b) { - struct rtl8187_tx_hdr *hdr = - (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); + struct rtl8187_tx_hdr *hdr = skb_push(skb, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; @@ -292,8 +291,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, unsigned int epmap[4] = { 6, 7, 5, 4 }; u16 fc = le16_to_cpu(tx_hdr->frame_control); - struct rtl8187b_tx_hdr *hdr = - (struct rtl8187b_tx_hdr *)skb_push(skb, sizeof(*hdr)); + struct rtl8187b_tx_hdr *hdr = skb_push(skb, sizeof(*hdr)); struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info); memset(hdr, 0, sizeof(*hdr)); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 39d56313bc94..21e5ef021260 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4952,7 +4952,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, if (control && control->sta) sta = control->sta; - tx_desc = (struct rtl8xxxu_txdesc32 *)skb_push(skb, tx_desc_size); + tx_desc = skb_push(skb, tx_desc_size); memset(tx_desc, 0, tx_desc_size); tx_desc->pkt_size = cpu_to_le16(pktlen); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index 41422e4da8b7..de6c3428f7c6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -512,7 +512,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); - txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE); + txdesc = skb_push(skb, RTL_TX_HEADER_SIZE); memset(txdesc, 0, RTL_TX_HEADER_SIZE); SET_TX_DESC_PKT_SIZE(txdesc, pktlen); SET_TX_DESC_LINIP(txdesc, 0); diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c index cd63ffef025a..e9050b41157a 100644 --- a/drivers/net/wireless/st/cw1200/txrx.c +++ b/drivers/net/wireless/st/cw1200/txrx.c @@ -574,7 +574,7 @@ cw1200_tx_h_wsm(struct cw1200_common *priv, return NULL; } - wsm = (struct wsm_tx *)skb_push(t->skb, sizeof(struct wsm_tx)); + wsm = skb_push(t->skb, sizeof(struct wsm_tx)); t->txpriv.offset += sizeof(struct wsm_tx); memset(wsm, 0, sizeof(*wsm)); wsm->hdr.len = __cpu_to_le16(t->skb->len); diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c index 81de83c6fcf6..de2fa6705574 100644 --- a/drivers/net/wireless/ti/wl1251/tx.c +++ b/drivers/net/wireless/ti/wl1251/tx.c @@ -161,8 +161,7 @@ static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb, return id; fc = *(u16 *)skb->data; - tx_hdr = (struct tx_double_buffer_desc *) skb_push(skb, - sizeof(*tx_hdr)); + tx_hdr = skb_push(skb, sizeof(*tx_hdr)); tx_hdr->length = cpu_to_le16(skb->len - sizeof(*tx_hdr)); rate = ieee80211_get_tx_rate(wl->hw, control); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 229f4d01f239..2bfc12fdc929 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1282,7 +1282,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16)); /* mac80211 header */ - hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); + hdr = skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; if (wlvif->sta.qos) diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index c1b8e4e9d70b..a3f5e9ca492a 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -223,8 +223,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks); if (total_blocks <= wl->tx_blocks_available) { - desc = (struct wl1271_tx_hw_descr *)skb_push( - skb, total_len - skb->len); + desc = skb_push(skb, total_len - skb->len); wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks, spare_blocks); diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index 2d929d2edb00..b785742bfd9e 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -868,8 +868,7 @@ static int fill_ctrlset(struct zd_mac *mac, unsigned int frag_len = skb->len + FCS_LEN; unsigned int packet_length; struct ieee80211_rate *txrate; - struct zd_ctrlset *cs = (struct zd_ctrlset *) - skb_push(skb, sizeof(struct zd_ctrlset)); + struct zd_ctrlset *cs = skb_push(skb, sizeof(struct zd_ctrlset)); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ZD_ASSERT(frag_len <= 0xffff); diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index 97f003e84381..d5781aa0f791 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -79,8 +79,8 @@ static void fdp_nci_i2c_add_len_lrc(struct sk_buff *skb) /* Add length header */ len = skb->len; - *skb_push(skb, 1) = len & 0xff; - *skb_push(skb, 1) = len >> 8; + *(u8 *)skb_push(skb, 1) = len & 0xff; + *(u8 *)skb_push(skb, 1) = len >> 8; /* Compute and add lrc */ for (i = 0; i < len + 2; i++) diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c index 8e328c36a816..386cc61d95b9 100644 --- a/drivers/nfc/microread/i2c.c +++ b/drivers/nfc/microread/i2c.c @@ -70,7 +70,7 @@ static void microread_i2c_add_len_crc(struct sk_buff *skb) int len; len = skb->len; - *skb_push(skb, 1) = len; + *(u8 *)skb_push(skb, 1) = len; for (i = 0; i < skb->len; i++) crc = crc ^ skb->data[i]; diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c index 9d0dd1be0923..38a979eacc29 100644 --- a/drivers/nfc/microread/microread.c +++ b/drivers/nfc/microread/microread.c @@ -419,7 +419,7 @@ static int microread_im_transceive(struct nfc_hci_dev *hdev, pr_info("data exchange to gate 0x%x\n", target->hci_reader_gate); if (target->hci_reader_gate == MICROREAD_GATE_ID_P2P_INITIATOR) { - *skb_push(skb, 1) = 0; + *(u8 *)skb_push(skb, 1) = 0; return nfc_hci_send_event(hdev, target->hci_reader_gate, MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF, @@ -453,7 +453,7 @@ static int microread_im_transceive(struct nfc_hci_dev *hdev, return 1; } - *skb_push(skb, 1) = control_bits; + *(u8 *)skb_push(skb, 1) = control_bits; info->async_cb_type = MICROREAD_CB_TYPE_READER_ALL; info->async_cb = cb; diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c index 51c8240a1672..c5038e6447bd 100644 --- a/drivers/nfc/nfcmrvl/main.c +++ b/drivers/nfc/nfcmrvl/main.c @@ -68,7 +68,7 @@ static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb) unsigned char *hdr; unsigned char len = skb->len; - hdr = (char *) skb_push(skb, NFCMRVL_HCI_EVENT_HEADER_SIZE); + hdr = skb_push(skb, NFCMRVL_HCI_EVENT_HEADER_SIZE); hdr[0] = NFCMRVL_HCI_COMMAND_CODE; hdr[1] = NFCMRVL_HCI_OGF; hdr[2] = NFCMRVL_HCI_OCF; diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index 68a3cd0287f6..6a711b5b9490 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -2090,10 +2090,10 @@ static int pn533_fill_fragment_skbs(struct pn533 *dev, struct sk_buff *skb) /* MI + TG */ if (frag_size == PN533_CMD_DATAFRAME_MAXLEN) - *skb_push(frag, sizeof(u8)) = - (PN533_CMD_MI_MASK | 1); + *(u8 *)skb_push(frag, sizeof(u8)) = + (PN533_CMD_MI_MASK | 1); else - *skb_push(frag, sizeof(u8)) = 1; /* TG */ + *(u8 *)skb_push(frag, sizeof(u8)) = 1; /* TG */ } skb_put_data(frag, skb->data, frag_size); @@ -2160,7 +2160,7 @@ static int pn533_transceive(struct nfc_dev *nfc_dev, goto error; } } else { - *skb_push(skb, sizeof(u8)) = 1; /* TG */ + *(u8 *)skb_push(skb, sizeof(u8)) = 1; /* TG */ } rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE, diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index dc1e3768cee6..b7be6c25b7e6 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -283,7 +283,7 @@ static void pn544_hci_i2c_add_len_crc(struct sk_buff *skb) int len; len = skb->len + 2; - *skb_push(skb, 1) = len; + *(u8 *)skb_push(skb, 1) = len; crc = crc_ccitt(0xffff, skb->data, skb->len); crc = ~crc; diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index 12e819ddf17a..70e898e38b16 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -649,8 +649,8 @@ static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev, } else return 1; case PN544_RF_READER_F_GATE: - *skb_push(skb, 1) = 0; - *skb_push(skb, 1) = 0; + *(u8 *)skb_push(skb, 1) = 0; + *(u8 *)skb_push(skb, 1) = 0; info->async_cb_type = PN544_CB_TYPE_READER_F; info->async_cb = cb; @@ -665,7 +665,7 @@ static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev, PN544_JEWEL_RAW_CMD, skb->data, skb->len, cb, cb_context); case PN544_RF_READER_NFCIP1_INITIATOR_GATE: - *skb_push(skb, 1) = 0; + *(u8 *)skb_push(skb, 1) = 0; return nfc_hci_send_event(hdev, target->hci_reader_gate, PN544_HCI_EVT_SND_DATA, skb->data, @@ -680,7 +680,7 @@ static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb) int r; /* Set default false for multiple information chaining */ - *skb_push(skb, 1) = 0; + *(u8 *)skb_push(skb, 1) = 0; r = nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, PN544_HCI_EVT_SND_DATA, skb->data, skb->len); diff --git a/drivers/nfc/st-nci/ndlc.c b/drivers/nfc/st-nci/ndlc.c index 50880d747b02..9477994cf975 100644 --- a/drivers/nfc/st-nci/ndlc.c +++ b/drivers/nfc/st-nci/ndlc.c @@ -87,7 +87,7 @@ int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb) u8 pcb = PCB_TYPE_DATAFRAME | PCB_DATAFRAME_RETRANSMIT_NO | PCB_FRAME_CRC_INFO_NOTPRESENT; - *skb_push(skb, 1) = pcb; + *(u8 *)skb_push(skb, 1) = pcb; skb_queue_tail(&ndlc->send_q, skb); schedule_work(&ndlc->sm_work); diff --git a/drivers/nfc/st21nfca/core.c b/drivers/nfc/st21nfca/core.c index 50be3b788f1c..e803fdfa9189 100644 --- a/drivers/nfc/st21nfca/core.c +++ b/drivers/nfc/st21nfca/core.c @@ -782,12 +782,12 @@ static int st21nfca_hci_im_transceive(struct nfc_hci_dev *hdev, if (target->supported_protocols == NFC_PROTO_NFC_DEP_MASK) return st21nfca_im_send_dep_req(hdev, skb); - *skb_push(skb, 1) = 0x1a; + *(u8 *)skb_push(skb, 1) = 0x1a; return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, ST21NFCA_WR_XCHG_DATA, skb->data, skb->len, cb, cb_context); case ST21NFCA_RF_READER_14443_3_A_GATE: - *skb_push(skb, 1) = 0x1a; /* CTR, see spec:10.2.2.1 */ + *(u8 *)skb_push(skb, 1) = 0x1a; /* CTR, see spec:10.2.2.1 */ return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, ST21NFCA_WR_XCHG_DATA, skb->data, @@ -797,7 +797,7 @@ static int st21nfca_hci_im_transceive(struct nfc_hci_dev *hdev, info->async_cb = cb; info->async_cb_context = cb_context; - *skb_push(skb, 1) = 0x17; + *(u8 *)skb_push(skb, 1) = 0x17; return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, ST21NFCA_WR_XCHG_DATA, skb->data, diff --git a/drivers/nfc/st21nfca/dep.c b/drivers/nfc/st21nfca/dep.c index ada7b114b6c1..fd08be2917e6 100644 --- a/drivers/nfc/st21nfca/dep.c +++ b/drivers/nfc/st21nfca/dep.c @@ -315,10 +315,10 @@ int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb) int r; struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); - *skb_push(skb, 1) = info->dep_info.curr_nfc_dep_pni; - *skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_RES; - *skb_push(skb, 1) = ST21NFCA_NFCIP1_RES; - *skb_push(skb, 1) = skb->len; + *(u8 *)skb_push(skb, 1) = info->dep_info.curr_nfc_dep_pni; + *(u8 *)skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_RES; + *(u8 *)skb_push(skb, 1) = ST21NFCA_NFCIP1_RES; + *(u8 *)skb_push(skb, 1) = skb->len; r = nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE, ST21NFCA_EVT_SEND_DATA, skb->data, skb->len); @@ -466,7 +466,7 @@ static void st21nfca_im_send_psl_req(struct nfc_hci_dev *hdev, u8 did, u8 bsi, psl_req->brs = (0x30 & bsi << 4) | (bri & 0x03); psl_req->fsl = lri; - *skb_push(skb, 1) = info->dep_info.to | 0x10; + *(u8 *)skb_push(skb, 1) = info->dep_info.to | 0x10; st21nfca_im_send_pdu(info, skb); } @@ -568,7 +568,7 @@ int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len) } atr_req->length = sizeof(struct st21nfca_atr_req) + hdev->gb_len; - *skb_push(skb, 1) = info->dep_info.to | 0x10; /* timeout */ + *(u8 *)skb_push(skb, 1) = info->dep_info.to | 0x10; /* timeout */ info->async_cb_type = ST21NFCA_CB_TYPE_READER_F; info->async_cb_context = info; @@ -629,10 +629,10 @@ static void st21nfca_im_recv_dep_res_cb(void *context, struct sk_buff *skb, case ST21NFCA_NFC_DEP_PFB_SUPERVISOR_PDU: pr_err("Received a SUPERVISOR PDU\n"); skb_pull(skb, size); - *skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_REQ; - *skb_push(skb, 1) = ST21NFCA_NFCIP1_REQ; - *skb_push(skb, 1) = skb->len; - *skb_push(skb, 1) = info->dep_info.to | 0x10; + *(u8 *)skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_REQ; + *(u8 *)skb_push(skb, 1) = ST21NFCA_NFCIP1_REQ; + *(u8 *)skb_push(skb, 1) = skb->len; + *(u8 *)skb_push(skb, 1) = info->dep_info.to | 0x10; st21nfca_im_send_pdu(info, skb); break; @@ -655,12 +655,12 @@ int st21nfca_im_send_dep_req(struct nfc_hci_dev *hdev, struct sk_buff *skb) info->async_cb_context = info; info->async_cb = st21nfca_im_recv_dep_res_cb; - *skb_push(skb, 1) = info->dep_info.curr_nfc_dep_pni; - *skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_REQ; - *skb_push(skb, 1) = ST21NFCA_NFCIP1_REQ; - *skb_push(skb, 1) = skb->len; + *(u8 *)skb_push(skb, 1) = info->dep_info.curr_nfc_dep_pni; + *(u8 *)skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_REQ; + *(u8 *)skb_push(skb, 1) = ST21NFCA_NFCIP1_REQ; + *(u8 *)skb_push(skb, 1) = skb->len; - *skb_push(skb, 1) = info->dep_info.to | 0x10; + *(u8 *)skb_push(skb, 1) = info->dep_info.to | 0x10; return nfc_hci_send_cmd_async(hdev, ST21NFCA_RF_READER_F_GATE, ST21NFCA_WR_XCHG_DATA, diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index c36f0e0afdfd..396cdafb3e36 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -171,7 +171,7 @@ static void st21nfca_hci_add_len_crc(struct sk_buff *skb) u16 crc; u8 tmp; - *skb_push(skb, 1) = 0; + *(u8 *)skb_push(skb, 1) = 0; crc = crc_ccitt(0xffff, skb->data, skb->len); crc = ~crc; @@ -216,7 +216,7 @@ static int st21nfca_hci_i2c_write(void *phy_id, struct sk_buff *skb) /* add ST21NFCA_SOF_EOF on tail */ *(u8 *)skb_put(skb, 1) = ST21NFCA_SOF_EOF; /* add ST21NFCA_SOF_EOF on head */ - *skb_push(skb, 1) = ST21NFCA_SOF_EOF; + *(u8 *)skb_push(skb, 1) = ST21NFCA_SOF_EOF; /* * Compute byte stuffing diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 70b633f951ea..c6bc63b8b295 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -759,8 +759,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, sizeof(struct qeth_hdr)); if (!new_skb) goto tx_drop; - hdr = (struct qeth_hdr *)skb_push(new_skb, - sizeof(struct qeth_hdr)); + hdr = skb_push(new_skb, sizeof(struct qeth_hdr)); skb_set_mac_header(new_skb, sizeof(struct qeth_hdr)); qeth_l2_fill_header(card, hdr, new_skb, cast_type); if (new_skb->ip_summed == CHECKSUM_PARTIAL) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 37b594231b76..3062cde33a3d 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2729,16 +2729,14 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, } if (use_tso) { - hdr = (struct qeth_hdr *)skb_push(new_skb, - sizeof(struct qeth_hdr_tso)); + hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso)); memset(hdr, 0, sizeof(struct qeth_hdr_tso)); qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); qeth_tso_fill_header(card, hdr, new_skb); hdr_elements++; } else { if (data_offset < 0) { - hdr = (struct qeth_hdr *)skb_push(new_skb, - sizeof(struct qeth_hdr)); + hdr = skb_push(new_skb, sizeof(struct qeth_hdr)); qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); } else { diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index 1880eb6c68f7..7b09e7ddf35e 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -354,7 +354,7 @@ static inline void make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb, struct l2t_entry *l2t = csk->l2t; skb_reset_transport_header(skb); - req = (struct tx_data_wr *)__skb_push(skb, sizeof(*req)); + req = __skb_push(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA) | (req_completion ? F_WR_COMPL : 0)); req->wr_lo = htonl(V_WR_TID(csk->tid)); diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 397094b8bad6..5485d68f286a 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -644,7 +644,7 @@ static inline void make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb, unsigned int wr_ulp_mode = 0, val; bool imm = is_ofld_imm(skb); - req = (struct fw_ofld_tx_data_wr *)__skb_push(skb, sizeof(*req)); + req = __skb_push(skb, sizeof(*req)); if (imm) { req->op_to_immdlen = htonl(FW_WR_OP_V(FW_OFLD_TX_DATA_WR) | diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index e17bdb3adf9e..fff6f1851dc1 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -626,7 +626,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, fh = (struct fc_frame_header *)skb->data; op = *(u8 *)(fh + 1); dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */ - cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap)); + cap = skb_push(skb, sizeof(*cap)); memset(cap, 0, sizeof(*cap)); if (lport->point_to_multipoint) { diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index e3b964b7235a..e72becaad8a5 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -1000,8 +1000,7 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb) if (!fnic->vlan_hw_insert) { eth_hdr = (struct ethhdr *)skb_mac_header(skb); - vlan_hdr = (struct vlan_ethhdr *)skb_push(skb, - sizeof(*vlan_hdr) - sizeof(*eth_hdr)); + vlan_hdr = skb_push(skb, sizeof(*vlan_hdr) - sizeof(*eth_hdr)); memcpy(vlan_hdr, eth_hdr, 2 * ETH_ALEN); vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q); vlan_hdr->h_vlan_encapsulated_proto = eth_hdr->h_proto; @@ -1067,7 +1066,7 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) if (!fnic->vlan_hw_insert) { eth_hdr_len = sizeof(*vlan_hdr) + sizeof(*fcoe_hdr); - vlan_hdr = (struct vlan_ethhdr *)skb_push(skb, eth_hdr_len); + vlan_hdr = skb_push(skb, eth_hdr_len); eth_hdr = (struct ethhdr *)vlan_hdr; vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q); vlan_hdr->h_vlan_encapsulated_proto = htons(ETH_P_FCOE); @@ -1075,7 +1074,7 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) fcoe_hdr = (struct fcoe_hdr *)(vlan_hdr + 1); } else { eth_hdr_len = sizeof(*eth_hdr) + sizeof(*fcoe_hdr); - eth_hdr = (struct ethhdr *)skb_push(skb, eth_hdr_len); + eth_hdr = skb_push(skb, eth_hdr_len); eth_hdr->h_proto = htons(ETH_P_FCOE); fcoe_hdr = (struct fcoe_hdr *)(eth_hdr + 1); } diff --git a/drivers/scsi/qedf/qedf_fip.c b/drivers/scsi/qedf/qedf_fip.c index e10b91cc3c62..0d4bf70803ae 100644 --- a/drivers/scsi/qedf/qedf_fip.c +++ b/drivers/scsi/qedf/qedf_fip.c @@ -125,8 +125,7 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) sub = fiph->fip_subcode; if (!qedf->vlan_hw_insert) { - vlan_hdr = (struct vlan_ethhdr *)skb_push(skb, sizeof(*vlan_hdr) - - sizeof(*eth_hdr)); + vlan_hdr = skb_push(skb, sizeof(*vlan_hdr) - sizeof(*eth_hdr)); memcpy(vlan_hdr, eth_hdr, 2 * ETH_ALEN); vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q); vlan_hdr->h_vlan_encapsulated_proto = eth_hdr->h_proto; diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c index dbc266a37974..01efa80b4f88 100644 --- a/drivers/staging/wilc1000/linux_mon.c +++ b/drivers/staging/wilc1000/linux_mon.c @@ -74,7 +74,7 @@ void WILC_WFI_monitor_rx(u8 *buff, u32 size) skb_put_data(skb, buff, size); - cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *)skb_push(skb, sizeof(*cb_hdr)); + cb_hdr = skb_push(skb, sizeof(*cb_hdr)); memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ @@ -101,7 +101,7 @@ void WILC_WFI_monitor_rx(u8 *buff, u32 size) return; skb_put_data(skb, buff, size); - hdr = (struct wilc_wfi_radiotap_hdr *)skb_push(skb, sizeof(*hdr)); + hdr = skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr)); hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_hdr)); @@ -202,7 +202,7 @@ static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb, skb_put_data(skb2, skb->data, skb->len); - cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *)skb_push(skb2, sizeof(*cb_hdr)); + cb_hdr = skb_push(skb2, sizeof(*cb_hdr)); memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c index a062e80361ef..fc8ad33ade9f 100644 --- a/drivers/staging/wlan-ng/p80211conv.c +++ b/drivers/staging/wlan-ng/p80211conv.c @@ -148,9 +148,7 @@ int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv, skb_pull(skb, ETH_HLEN); /* tack on SNAP */ - e_snap = - (struct wlan_snap *)skb_push(skb, - sizeof(struct wlan_snap)); + e_snap = skb_push(skb, sizeof(struct wlan_snap)); e_snap->type = htons(proto); if (ethconv == WLAN_ETHCONV_8021h && p80211_stt_findproto(proto)) { @@ -162,9 +160,7 @@ int skb_ether_to_p80211(struct wlandevice *wlandev, u32 ethconv, } /* tack on llc */ - e_llc = - (struct wlan_llc *)skb_push(skb, - sizeof(struct wlan_llc)); + e_llc = skb_push(skb, sizeof(struct wlan_llc)); e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */ e_llc->ssap = 0xAA; e_llc->ctl = 0x03; @@ -407,7 +403,7 @@ int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv, skb_pull(skb, payload_offset); /* create 802.3 header at beginning of skb. */ - e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN); + e_hdr = skb_push(skb, ETH_HLEN); ether_addr_copy(e_hdr->daddr, daddr); ether_addr_copy(e_hdr->saddr, saddr); e_hdr->type = htons(payload_length); @@ -448,7 +444,7 @@ int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv, skb_pull(skb, sizeof(struct wlan_snap)); /* create 802.3 header at beginning of skb. */ - e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN); + e_hdr = skb_push(skb, ETH_HLEN); e_hdr->type = e_snap->type; ether_addr_copy(e_hdr->daddr, daddr); ether_addr_copy(e_hdr->saddr, saddr); @@ -475,7 +471,7 @@ int skb_p80211_to_ether(struct wlandevice *wlandev, u32 ethconv, skb_pull(skb, payload_offset); /* create 802.3 header at beginning of skb. */ - e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN); + e_hdr = skb_push(skb, ETH_HLEN); ether_addr_copy(e_hdr->daddr, daddr); ether_addr_copy(e_hdr->saddr, saddr); e_hdr->type = htons(payload_length); diff --git a/drivers/target/iscsi/cxgbit/cxgbit_target.c b/drivers/target/iscsi/cxgbit/cxgbit_target.c index bdcc8b4c522a..dda13f1af38e 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_target.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c @@ -136,7 +136,7 @@ cxgbit_cpl_tx_data_iso(struct sk_buff *skb, struct cxgbit_iso_info *iso_info) unsigned int fslice = !!(iso_info->flags & CXGBIT_ISO_FSLICE); unsigned int lslice = !!(iso_info->flags & CXGBIT_ISO_LSLICE); - cpl = (struct cpl_tx_data_iso *)__skb_push(skb, sizeof(*cpl)); + cpl = __skb_push(skb, sizeof(*cpl)); cpl->op_to_scsi = htonl(CPL_TX_DATA_ISO_OP_V(CPL_TX_DATA_ISO) | CPL_TX_DATA_ISO_FIRST_V(fslice) | @@ -183,8 +183,7 @@ cxgbit_tx_data_wr(struct cxgbit_sock *csk, struct sk_buff *skb, u32 dlen, if (cxgbit_is_ofld_imm(skb)) immlen += dlen; - req = (struct fw_ofld_tx_data_wr *)__skb_push(skb, - hdr_size); + req = __skb_push(skb, hdr_size); req->op_to_immdlen = cpu_to_be32(FW_WR_OP_V(opcode) | FW_WR_COMPL_V(compl) | FW_WR_IMMDLEN_V(immlen)); diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index a3b5e468b116..d6341045c631 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -999,7 +999,7 @@ void rndis_add_hdr(struct sk_buff *skb) if (!skb) return; - header = (void *)skb_push(skb, sizeof(*header)); + header = skb_push(skb, sizeof(*header)); memset(header, 0, sizeof *header); header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET); header->MessageLength = cpu_to_le32(skb->len); -- cgit v1.2.3 From 634fef61076d644b989b86abc2f560d81a089a31 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Jun 2017 14:29:24 +0200 Subject: networking: add and use skb_put_u8() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Joe and Bjørn suggested that it'd be nicer to not have the cast in the fairly common case of doing *(u8 *)skb_put(skb, 1) = c; Add skb_put_u8() for this case, and use it across the code, using the following spatch: @@ expression SKB, C, S; typedef u8; identifier fn = {skb_put}; fresh identifier fn2 = fn ## "_u8"; @@ - *(u8 *)fn(SKB, S) = C; + fn2(SKB, C); Note that due to the "S", the spatch isn't perfect, it should have checked that S is 1, but there's also places that use a sizeof expression like sizeof(var) or sizeof(u8) etc. Turns out that nobody ever did something like *(u8 *)skb_put(skb, 2) = c; which would be wrong anyway since the second byte wouldn't be initialized. Suggested-by: Joe Perches Suggested-by: Bjørn Mork Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/bluetooth/bluecard_cs.c | 2 +- drivers/bluetooth/bt3c_cs.c | 2 +- drivers/bluetooth/btuart_cs.c | 2 +- drivers/bluetooth/btusb.c | 6 +++--- drivers/bluetooth/dtl1_cs.c | 4 ++-- drivers/bluetooth/hci_bcm.c | 6 +++--- drivers/bluetooth/hci_intel.c | 2 +- drivers/bluetooth/hci_nokia.c | 2 +- drivers/bluetooth/hci_qca.c | 2 +- drivers/bluetooth/hci_vhci.c | 4 ++-- drivers/isdn/capi/capi.c | 4 ++-- drivers/isdn/gigaset/asyncdata.c | 22 +++++++++++----------- drivers/isdn/i4l/isdn_bsdcomp.c | 7 ++++--- drivers/isdn/i4l/isdn_x25iface.c | 4 ++-- drivers/net/hamradio/scc.c | 4 ++-- drivers/net/usb/cdc_ncm.c | 2 +- drivers/net/usb/net1080.c | 2 +- drivers/net/usb/zaurus.c | 8 ++++---- drivers/nfc/fdp/i2c.c | 2 +- drivers/nfc/microread/i2c.c | 4 ++-- drivers/nfc/microread/microread.c | 4 ++-- drivers/nfc/nfcmrvl/fw_dnld.c | 4 ++-- drivers/nfc/pn533/pn533.c | 32 ++++++++++++++++---------------- drivers/nfc/pn544/i2c.c | 6 +++--- drivers/nfc/port100.c | 4 ++-- drivers/nfc/st21nfca/i2c.c | 6 +++--- drivers/nfc/st95hf/core.c | 2 +- 27 files changed, 75 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 39a05b0c8998..d4b0b655dde6 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -448,7 +448,7 @@ static void bluecard_receive(struct bluecard_info *info, } else { - *(u8 *)skb_put(info->rx_skb, 1) = buf[i]; + skb_put_u8(info->rx_skb, buf[i]); info->rx_count--; if (info->rx_count == 0) { diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index be2d431aa366..32dcac017395 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -282,7 +282,7 @@ static void bt3c_receive(struct bt3c_info *info) __u8 x = inb(iobase + DATA_L); - *(u8 *)skb_put(info->rx_skb, 1) = x; + skb_put_u8(info->rx_skb, x); inb(iobase + DATA_H); info->rx_count--; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 80b64e9684a3..7df79bb12350 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -233,7 +233,7 @@ static void btuart_receive(struct btuart_info *info) } else { - *(u8 *)skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); + skb_put_u8(info->rx_skb, inb(iobase + UART_RX)); info->rx_count--; if (info->rx_count == 0) { diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ba207c787605..fa24d693af24 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1844,7 +1844,7 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) evt->ncmd = 0x01; evt->opcode = cpu_to_le16(opcode); - *(u8 *)skb_put(skb, 1) = 0x00; + skb_put_u8(skb, 0x00); hci_skb_pkt_type(skb) = HCI_EVENT_PKT; @@ -2767,8 +2767,8 @@ static struct urb *alloc_diag_urb(struct hci_dev *hdev, bool enable) return ERR_PTR(-ENOMEM); } - *(u8 *)skb_put(skb, 1) = 0xf0; - *(u8 *)skb_put(skb, 1) = enable; + skb_put_u8(skb, 0xf0); + skb_put_u8(skb, enable); pipe = usb_sndbulkpipe(data->udev, data->diag_tx_ep->bEndpointAddress); diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 6c5a3aa566a4..2adfe4fade76 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -226,7 +226,7 @@ static void dtl1_receive(struct dtl1_info *info) } } - *(u8 *)skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); + skb_put_u8(info->rx_skb, inb(iobase + UART_RX)); nsh = (struct nsh *)info->rx_skb->data; info->rx_count--; @@ -414,7 +414,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) skb_reserve(s, NSHL); skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len); if (skb->len & 0x0001) - *(u8 *)skb_put(s, 1) = 0; /* PAD */ + skb_put_u8(s, 0); /* PAD */ /* Prepend skb with Nokia frame header and queue */ memcpy(skb_push(s, NSHL), &nsh, NSHL); diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index c1c4048ee37d..d2e9e2d1b014 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -262,9 +262,9 @@ static int bcm_set_diag(struct hci_dev *hdev, bool enable) if (!skb) return -ENOMEM; - *(u8 *)skb_put(skb, 1) = BCM_LM_DIAG_PKT; - *(u8 *)skb_put(skb, 1) = 0xf0; - *(u8 *)skb_put(skb, 1) = enable; + skb_put_u8(skb, BCM_LM_DIAG_PKT); + skb_put_u8(skb, 0xf0); + skb_put_u8(skb, enable); skb_queue_tail(&bcm->txq, skb); hci_uart_tx_wakeup(hu); diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index ee97c465e32e..aad07e40ea4f 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -470,7 +470,7 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) evt->ncmd = 0x01; evt->opcode = cpu_to_le16(opcode); - *(u8 *)skb_put(skb, 1) = 0x00; + skb_put_u8(skb, 0x00); hci_skb_pkt_type(skb) = HCI_EVENT_PKT; diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c index 072a77a61e67..181a15b549e5 100644 --- a/drivers/bluetooth/hci_nokia.c +++ b/drivers/bluetooth/hci_nokia.c @@ -532,7 +532,7 @@ static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb) err = skb_pad(skb, 1); if (err) return err; - *(u8 *)skb_put(skb, 1) = 0x00; + skb_put_u8(skb, 0x00); } skb_queue_tail(&btdev->txq, skb); diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index e2c88515340a..392f412b4575 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -215,7 +215,7 @@ static int send_hci_ibs_cmd(u8 cmd, struct hci_uart *hu) } /* Assign HCI_IBS type */ - *(u8 *)skb_put(skb, 1) = cmd; + skb_put_u8(skb, cmd); skb_queue_tail(&qca->txq, skb); diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 1ef9c427a2d8..e6f6dbc04131 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -146,8 +146,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) hci_skb_pkt_type(skb) = HCI_VENDOR_PKT; - *(u8 *)skb_put(skb, 1) = 0xff; - *(u8 *)skb_put(skb, 1) = opcode; + skb_put_u8(skb, 0xff); + skb_put_u8(skb, opcode); put_unaligned_le16(hdev->id, skb_put(skb, 2)); skb_queue_tail(&data->readq, skb); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 96f586d34d2d..dde8f46bc254 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1082,7 +1082,7 @@ static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) skb = mp->outskb; if (skb) { if (skb_tailroom(skb) > 0) { - *(u8 *)skb_put(skb, 1) = ch; + skb_put_u8(skb, ch); goto unlock_out; } mp->outskb = NULL; @@ -1094,7 +1094,7 @@ static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + CAPI_MAX_BLKSIZE, GFP_ATOMIC); if (skb) { skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); - *(u8 *)skb_put(skb, 1) = ch; + skb_put_u8(skb, ch); mp->outskb = skb; } else { printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 03ac9fbfe318..4caecdcc6f29 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -492,33 +492,33 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb) hdlc_skb->mac_len = skb->mac_len; /* Add flag sequence in front of everything.. */ - *(u8 *)skb_put(hdlc_skb, 1) = PPP_FLAG; + skb_put_u8(hdlc_skb, PPP_FLAG); /* Perform byte stuffing while copying data. */ while (skb->len--) { if (muststuff(*skb->data)) { - *(u8 *)skb_put(hdlc_skb, 1) = PPP_ESCAPE; - *(u8 *)skb_put(hdlc_skb, 1) = (*skb->data++) ^ PPP_TRANS; + skb_put_u8(hdlc_skb, PPP_ESCAPE); + skb_put_u8(hdlc_skb, (*skb->data++) ^ PPP_TRANS); } else - *(u8 *)skb_put(hdlc_skb, 1) = *skb->data++; + skb_put_u8(hdlc_skb, *skb->data++); } /* Finally add FCS (byte stuffed) and flag sequence */ c = (fcs & 0x00ff); /* least significant byte first */ if (muststuff(c)) { - *(u8 *)skb_put(hdlc_skb, 1) = PPP_ESCAPE; + skb_put_u8(hdlc_skb, PPP_ESCAPE); c ^= PPP_TRANS; } - *(u8 *)skb_put(hdlc_skb, 1) = c; + skb_put_u8(hdlc_skb, c); c = ((fcs >> 8) & 0x00ff); if (muststuff(c)) { - *(u8 *)skb_put(hdlc_skb, 1) = PPP_ESCAPE; + skb_put_u8(hdlc_skb, PPP_ESCAPE); c ^= PPP_TRANS; } - *(u8 *)skb_put(hdlc_skb, 1) = c; + skb_put_u8(hdlc_skb, c); - *(u8 *)skb_put(hdlc_skb, 1) = PPP_FLAG; + skb_put_u8(hdlc_skb, PPP_FLAG); dev_kfree_skb_any(skb); return hdlc_skb; @@ -561,8 +561,8 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb) while (len--) { c = bitrev8(*cp++); if (c == DLE_FLAG) - *(u8 *)skb_put(iraw_skb, 1) = c; - *(u8 *)skb_put(iraw_skb, 1) = c; + skb_put_u8(iraw_skb, c); + skb_put_u8(iraw_skb, c); } dev_kfree_skb_any(skb); return iraw_skb; diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index 6ade0916da4e..3035210a6119 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -602,7 +602,8 @@ static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb * Do not emit a completely useless byte of ones. */ if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0) - *(u8 *)skb_put(skb_out, 1) = (unsigned char)((accm | (0xff << (bitno - 8))) >> 24); + skb_put_u8(skb_out, + (unsigned char)((accm | (0xff << (bitno - 8))) >> 24)); /* * Increase code size if we would have without the packet @@ -698,7 +699,7 @@ static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *s db->bytes_out += ilen; if (skb_tailroom(skb_out) > 0) - *(u8 *)skb_put(skb_out, 1) = 0; + skb_put_u8(skb_out, 0); else return DECOMP_ERR_NOMEM; @@ -816,7 +817,7 @@ static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *s #endif if (extra) /* the KwKwK case again */ - *(u8 *)skb_put(skb_out, 1) = finchar; + skb_put_u8(skb_out, finchar); /* * If not first code in a packet, and diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c index e33fa3073f74..48bfbcb4a09d 100644 --- a/drivers/isdn/i4l/isdn_x25iface.c +++ b/drivers/isdn/i4l/isdn_x25iface.c @@ -224,7 +224,7 @@ static int isdn_x25iface_connect_ind(struct concap_proto *cprot) skb = dev_alloc_skb(1); if (skb) { - *(u8 *)skb_put(skb, 1) = X25_IFACE_CONNECT; + skb_put_u8(skb, X25_IFACE_CONNECT); skb->protocol = x25_type_trans(skb, cprot->net_dev); netif_rx(skb); return 0; @@ -253,7 +253,7 @@ static int isdn_x25iface_disconn_ind(struct concap_proto *cprot) *state_p = WAN_DISCONNECTED; skb = dev_alloc_skb(1); if (skb) { - *(u8 *)skb_put(skb, 1) = X25_IFACE_DISCONNECT; + skb_put_u8(skb, X25_IFACE_DISCONNECT); skb->protocol = x25_type_trans(skb, cprot->net_dev); netif_rx(skb); return 0; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 140a209f22ab..295f267b73ea 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -540,7 +540,7 @@ static inline void scc_rxint(struct scc_channel *scc) } scc->rx_buff = skb; - *(u8 *)skb_put(skb, 1) = 0; /* KISS data */ + skb_put_u8(skb, 0); /* KISS data */ } if (skb->len >= scc->stat.bufsize) @@ -555,7 +555,7 @@ static inline void scc_rxint(struct scc_channel *scc) return; } - *(u8 *)skb_put(skb, 1) = Inb(scc->data); + skb_put_u8(skb, Inb(scc->data)); } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 4d4837a0645b..bcb974707118 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1250,7 +1250,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) skb_put_zero(skb_out, padding_count); } else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0) { - *(u8 *)skb_put(skb_out, 1) = 0; /* force short packet */ + skb_put_u8(skb_out, 0); /* force short packet */ } /* set final frame length */ diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index be53ff30b7b5..18a13aa5fcbb 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -473,7 +473,7 @@ encapsulate: /* maybe pad; then trailer */ if (!((skb->len + sizeof *trailer) & 0x01)) - *(u8 *)skb_put(skb, 1) = PAD_BYTE; + skb_put_u8(skb, PAD_BYTE); trailer = skb_put(skb, sizeof *trailer); put_unaligned(header->packet_id, &trailer->packet_id); #if 0 diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index dc3cd03763af..9c2196c3fd11 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -74,10 +74,10 @@ done: fcs = crc32_le(~0, skb->data, skb->len); fcs = ~fcs; - *(u8 *)skb_put(skb, 1) = fcs & 0xff; - *(u8 *)skb_put(skb, 1) = (fcs>> 8) & 0xff; - *(u8 *)skb_put(skb, 1) = (fcs>>16) & 0xff; - *(u8 *)skb_put(skb, 1) = (fcs>>24) & 0xff; + skb_put_u8(skb, fcs & 0xff); + skb_put_u8(skb, (fcs >> 8) & 0xff); + skb_put_u8(skb, (fcs >> 16) & 0xff); + skb_put_u8(skb, (fcs >> 24) & 0xff); } return skb; } diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index d5781aa0f791..e0baec848ff2 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -86,7 +86,7 @@ static void fdp_nci_i2c_add_len_lrc(struct sk_buff *skb) for (i = 0; i < len + 2; i++) lrc ^= skb->data[i]; - *(u8 *)skb_put(skb, 1) = lrc; + skb_put_u8(skb, lrc); } static void fdp_nci_i2c_remove_len_lrc(struct sk_buff *skb) diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c index 386cc61d95b9..b668b7b9a61e 100644 --- a/drivers/nfc/microread/i2c.c +++ b/drivers/nfc/microread/i2c.c @@ -75,7 +75,7 @@ static void microread_i2c_add_len_crc(struct sk_buff *skb) for (i = 0; i < skb->len; i++) crc = crc ^ skb->data[i]; - *(u8 *)skb_put(skb, 1) = crc; + skb_put_u8(skb, crc); } static void microread_i2c_remove_len_crc(struct sk_buff *skb) @@ -173,7 +173,7 @@ static int microread_i2c_read(struct microread_i2c_phy *phy, goto flush; } - *(u8 *)skb_put(*skb, 1) = len; + skb_put_u8(*skb, len); r = i2c_master_recv(client, skb_put(*skb, len), len); if (r != len) { diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c index 38a979eacc29..e5d5d2d97409 100644 --- a/drivers/nfc/microread/microread.c +++ b/drivers/nfc/microread/microread.c @@ -441,8 +441,8 @@ static int microread_im_transceive(struct nfc_hci_dev *hdev, crc = crc_ccitt(0xffff, skb->data, skb->len); crc = ~crc; - *(u8 *)skb_put(skb, 1) = crc & 0xff; - *(u8 *)skb_put(skb, 1) = crc >> 8; + skb_put_u8(skb, crc & 0xff); + skb_put_u8(skb, crc >> 8); break; case MICROREAD_GATE_ID_MREAD_NFC_T3: control_bits = 0xDB; diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c index 788599de9d8a..f9f000c546d1 100644 --- a/drivers/nfc/nfcmrvl/fw_dnld.c +++ b/drivers/nfc/nfcmrvl/fw_dnld.c @@ -292,7 +292,7 @@ static int process_state_fw_dnld(struct nfcmrvl_private *priv, out_skb = alloc_lc_skb(priv, 1); if (!out_skb) return -ENOMEM; - *(u8 *)skb_put(out_skb, 1) = 0xBF; + skb_put_u8(out_skb, 0xBF); nci_send_frame(priv->ndev, out_skb); priv->fw_dnld.substate = SUBSTATE_WAIT_NACK_CREDIT; return 0; @@ -301,7 +301,7 @@ static int process_state_fw_dnld(struct nfcmrvl_private *priv, out_skb = alloc_lc_skb(priv, 1); if (!out_skb) return -ENOMEM; - *(u8 *)skb_put(out_skb, 1) = HELPER_ACK_PACKET_FORMAT; + skb_put_u8(out_skb, HELPER_ACK_PACKET_FORMAT); nci_send_frame(priv->ndev, out_skb); priv->fw_dnld.substate = SUBSTATE_WAIT_ACK_CREDIT; break; diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index 6a711b5b9490..c8a8f5badb5b 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -1032,7 +1032,7 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) return NULL; /* DEP support only */ - *(u8 *)skb_put(skb, 1) = PN533_INIT_TARGET_DEP; + skb_put_u8(skb, PN533_INIT_TARGET_DEP); /* MIFARE params */ skb_put_data(skb, mifare_params, 6); @@ -1046,12 +1046,12 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) memcpy(nfcid3, felica, 8); /* General bytes */ - *(u8 *)skb_put(skb, 1) = gbytes_len; + skb_put_u8(skb, gbytes_len); gb = skb_put_data(skb, gbytes, gbytes_len); /* Len Tk */ - *(u8 *)skb_put(skb, 1) = 0; + skb_put_u8(skb, 0); return skb; } @@ -1280,8 +1280,8 @@ static void pn533_wq_rf(struct work_struct *work) if (!skb) return; - *(u8 *)skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD; - *(u8 *)skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD_AUTO_RFCA; + skb_put_u8(skb, PN533_CFGITEM_RF_FIELD); + skb_put_u8(skb, PN533_CFGITEM_RF_FIELD_AUTO_RFCA); rc = pn533_send_cmd_async(dev, PN533_CMD_RF_CONFIGURATION, skb, pn533_rf_complete, NULL); @@ -1375,8 +1375,8 @@ static int pn533_poll_dep(struct nfc_dev *nfc_dev) if (!skb) return -ENOMEM; - *(u8 *)skb_put(skb, 1) = 0x01; /* Active */ - *(u8 *)skb_put(skb, 1) = 0x02; /* 424 kbps */ + skb_put_u8(skb, 0x01); /* Active */ + skb_put_u8(skb, 0x02); /* 424 kbps */ next = skb_put(skb, 1); /* Next */ *next = 0; @@ -1620,8 +1620,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev) if (!skb) return -ENOMEM; - *(u8 *)skb_put(skb, sizeof(u8)) = 1; /* TG */ - *(u8 *)skb_put(skb, sizeof(u8)) = 0; /* Next */ + skb_put_u8(skb, 1); /* TG */ + skb_put_u8(skb, 0); /* Next */ resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_ATR, skb); if (IS_ERR(resp)) @@ -1737,7 +1737,7 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, if (!skb) return; - *(u8 *)skb_put(skb, 1) = 1; /* TG*/ + skb_put_u8(skb, 1); /* TG*/ rc = pn533_send_cmd_async(dev, PN533_CMD_IN_RELEASE, skb, pn533_deactivate_target_complete, NULL); @@ -1848,8 +1848,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, if (!skb) return -ENOMEM; - *(u8 *)skb_put(skb, 1) = !comm_mode; /* ActPass */ - *(u8 *)skb_put(skb, 1) = 0x02; /* 424 kbps */ + skb_put_u8(skb, !comm_mode); /* ActPass */ + skb_put_u8(skb, 0x02); /* 424 kbps */ next = skb_put(skb, 1); /* Next */ *next = 0; @@ -2274,7 +2274,7 @@ static void pn533_wq_mi_recv(struct work_struct *work) break; } default: - *(u8 *)skb_put(skb, sizeof(u8)) = 1; /*TG*/ + skb_put_u8(skb, 1); /*TG*/ rc = pn533_send_cmd_direct_async(dev, PN533_CMD_IN_DATA_EXCHANGE, @@ -2370,7 +2370,7 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, if (!skb) return -ENOMEM; - *(u8 *)skb_put(skb, sizeof(cfgitem)) = cfgitem; + skb_put_u8(skb, cfgitem); skb_put_data(skb, cfgdata, cfgdata_len); resp = pn533_send_cmd_sync(dev, PN533_CMD_RF_CONFIGURATION, skb); @@ -2415,7 +2415,7 @@ static int pn533_pasori_fw_reset(struct pn533 *dev) if (!skb) return -ENOMEM; - *(u8 *)skb_put(skb, sizeof(u8)) = 0x1; + skb_put_u8(skb, 0x1); resp = pn533_send_cmd_sync(dev, 0x18, skb); if (IS_ERR(resp)) @@ -2454,7 +2454,7 @@ static int pn532_sam_configuration(struct nfc_dev *nfc_dev) if (!skb) return -ENOMEM; - *(u8 *)skb_put(skb, 1) = 0x01; + skb_put_u8(skb, 0x01); resp = pn533_send_cmd_sync(dev, PN533_CMD_SAM_CONFIGURATION, skb); if (IS_ERR(resp)) diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index b7be6c25b7e6..fedde9d46ab6 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -287,8 +287,8 @@ static void pn544_hci_i2c_add_len_crc(struct sk_buff *skb) crc = crc_ccitt(0xffff, skb->data, skb->len); crc = ~crc; - *(u8 *)skb_put(skb, 1) = crc & 0xff; - *(u8 *)skb_put(skb, 1) = crc >> 8; + skb_put_u8(skb, crc & 0xff); + skb_put_u8(skb, crc >> 8); } static void pn544_hci_i2c_remove_len_crc(struct sk_buff *skb) @@ -391,7 +391,7 @@ static int pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb) goto flush; } - *(u8 *)skb_put(*skb, 1) = len; + skb_put_u8(*skb, len); r = i2c_master_recv(client, skb_put(*skb, len), len); if (r != len) { diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c index 5fa3cf0fabd6..bb43cebda9dc 100644 --- a/drivers/nfc/port100.c +++ b/drivers/nfc/port100.c @@ -991,7 +991,7 @@ static int port100_set_command_type(struct port100 *dev, u8 command_type) if (!skb) return -ENOMEM; - *(u8 *)skb_put(skb, sizeof(u8)) = command_type; + skb_put_u8(skb, command_type); resp = port100_send_cmd_sync(dev, PORT100_CMD_SET_COMMAND_TYPE, skb); if (IS_ERR(resp)) @@ -1059,7 +1059,7 @@ static int port100_switch_rf(struct nfc_digital_dev *ddev, bool on) if (!skb) return -ENOMEM; - *(u8 *)skb_put(skb, 1) = on ? 1 : 0; + skb_put_u8(skb, on ? 1 : 0); /* Cancel the last command if the device is being switched off */ if (!on) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 396cdafb3e36..4bff76baa341 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -177,10 +177,10 @@ static void st21nfca_hci_add_len_crc(struct sk_buff *skb) crc = ~crc; tmp = crc & 0x00ff; - *(u8 *)skb_put(skb, 1) = tmp; + skb_put_u8(skb, tmp); tmp = (crc >> 8) & 0x00ff; - *(u8 *)skb_put(skb, 1) = tmp; + skb_put_u8(skb, tmp); } static void st21nfca_hci_remove_len_crc(struct sk_buff *skb) @@ -214,7 +214,7 @@ static int st21nfca_hci_i2c_write(void *phy_id, struct sk_buff *skb) st21nfca_hci_add_len_crc(skb); /* add ST21NFCA_SOF_EOF on tail */ - *(u8 *)skb_put(skb, 1) = ST21NFCA_SOF_EOF; + skb_put_u8(skb, ST21NFCA_SOF_EOF); /* add ST21NFCA_SOF_EOF on head */ *(u8 *)skb_push(skb, 1) = ST21NFCA_SOF_EOF; diff --git a/drivers/nfc/st95hf/core.c b/drivers/nfc/st95hf/core.c index 168adcc46cb8..2b26f762fbc3 100644 --- a/drivers/nfc/st95hf/core.c +++ b/drivers/nfc/st95hf/core.c @@ -949,7 +949,7 @@ static int st95hf_in_send_cmd(struct nfc_digital_dev *ddev, switch (stcontext->current_rf_tech) { case NFC_DIGITAL_RF_TECH_106A: len_data_to_tag = skb->len + 1; - *(u8 *)skb_put(skb, 1) = stcontext->sendrcv_trflag; + skb_put_u8(skb, stcontext->sendrcv_trflag); break; case NFC_DIGITAL_RF_TECH_106B: case NFC_DIGITAL_RF_TECH_ISO15693: -- cgit v1.2.3 From 2e37e9b0f55e50a099c699ac41ea4fa507fc46ff Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 15 Jun 2017 17:29:10 -0700 Subject: bpf: mlx4: Report bpf_prog ID during XDP_QUERY_PROG Add support to mlx4 to report bpf_prog ID during XDP_QUERY_PROG. Signed-off-by: Martin KaFai Lau Cc: Tariq Toukan Cc: Saeed Mahameed Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 99c02bb4f302..18252a79a074 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2825,11 +2825,25 @@ out: return err; } -static bool mlx4_xdp_attached(struct net_device *dev) +static u32 mlx4_xdp_query(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + const struct bpf_prog *xdp_prog; + u32 prog_id = 0; + + if (!priv->tx_ring_num[TX_XDP]) + return prog_id; + + mutex_lock(&mdev->state_lock); + xdp_prog = rcu_dereference_protected( + priv->rx_ring[0]->xdp_prog, + lockdep_is_held(&mdev->state_lock)); + if (xdp_prog) + prog_id = xdp_prog->aux->id; + mutex_unlock(&mdev->state_lock); - return !!priv->tx_ring_num[TX_XDP]; + return prog_id; } static int mlx4_xdp(struct net_device *dev, struct netdev_xdp *xdp) @@ -2838,7 +2852,8 @@ static int mlx4_xdp(struct net_device *dev, struct netdev_xdp *xdp) case XDP_SETUP_PROG: return mlx4_xdp_set(dev, xdp->prog); case XDP_QUERY_PROG: - xdp->prog_attached = mlx4_xdp_attached(dev); + xdp->prog_id = mlx4_xdp_query(dev); + xdp->prog_attached = !!xdp->prog_id; return 0; default: return -EINVAL; -- cgit v1.2.3 From 821b2e294433f3b4e7db6911da5b0806c38d7bda Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 15 Jun 2017 17:29:11 -0700 Subject: bpf: mlx5e: Report bpf_prog ID during XDP_QUERY_PROG Add support to mlx5e to report bpf_prog ID during XDP_QUERY_PROG. Signed-off-by: Martin KaFai Lau Cc: Tariq Toukan Cc: Saeed Mahameed Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Acked-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 5afec0f4a658..c8f3aefe735d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -3599,11 +3599,19 @@ unlock: return err; } -static bool mlx5e_xdp_attached(struct net_device *dev) +static u32 mlx5e_xdp_query(struct net_device *dev) { struct mlx5e_priv *priv = netdev_priv(dev); + const struct bpf_prog *xdp_prog; + u32 prog_id = 0; - return !!priv->channels.params.xdp_prog; + mutex_lock(&priv->state_lock); + xdp_prog = priv->channels.params.xdp_prog; + if (xdp_prog) + prog_id = xdp_prog->aux->id; + mutex_unlock(&priv->state_lock); + + return prog_id; } static int mlx5e_xdp(struct net_device *dev, struct netdev_xdp *xdp) @@ -3612,7 +3620,8 @@ static int mlx5e_xdp(struct net_device *dev, struct netdev_xdp *xdp) case XDP_SETUP_PROG: return mlx5e_xdp_set(dev, xdp->prog); case XDP_QUERY_PROG: - xdp->prog_attached = mlx5e_xdp_attached(dev); + xdp->prog_id = mlx5e_xdp_query(dev); + xdp->prog_attached = !!xdp->prog_id; return 0; default: return -EINVAL; -- cgit v1.2.3 From 5b0e6629be5958d70e1f3263b021f0e4038fc675 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 15 Jun 2017 17:29:12 -0700 Subject: bpf: virtio_net: Report bpf_prog ID during XDP_QUERY_PROG Add support to virtio_net to report bpf_prog ID during XDP_QUERY_PROG. Signed-off-by: Martin KaFai Lau Cc: John Fastabend Cc: Jason Wang Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 6bacbd2f0eca..5c6388fb7dd1 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1955,16 +1955,18 @@ virtio_reset_err: return err; } -static bool virtnet_xdp_query(struct net_device *dev) +static u32 virtnet_xdp_query(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); + const struct bpf_prog *xdp_prog; int i; for (i = 0; i < vi->max_queue_pairs; i++) { - if (vi->rq[i].xdp_prog) - return true; + xdp_prog = rtnl_dereference(vi->rq[i].xdp_prog); + if (xdp_prog) + return xdp_prog->aux->id; } - return false; + return 0; } static int virtnet_xdp(struct net_device *dev, struct netdev_xdp *xdp) @@ -1973,7 +1975,8 @@ static int virtnet_xdp(struct net_device *dev, struct netdev_xdp *xdp) case XDP_SETUP_PROG: return virtnet_xdp_set(dev, xdp->prog, xdp->extack); case XDP_QUERY_PROG: - xdp->prog_attached = virtnet_xdp_query(dev); + xdp->prog_id = virtnet_xdp_query(dev); + xdp->prog_attached = !!xdp->prog_id; return 0; default: return -EINVAL; -- cgit v1.2.3 From 8902965f8cb23bba8aa7f3be293ec2f3067b82c6 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 15 Jun 2017 17:29:13 -0700 Subject: bpf: bnxt: Report bpf_prog ID during XDP_QUERY_PROG Add support to bnxt to report bpf_prog ID during XDP_QUERY_PROG. Signed-off-by: Martin KaFai Lau Cc: Michael Chan Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 8ce793a0d030..7d67552e70d7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -218,6 +218,7 @@ int bnxt_xdp(struct net_device *dev, struct netdev_xdp *xdp) break; case XDP_QUERY_PROG: xdp->prog_attached = !!bp->xdp_prog; + xdp->prog_id = bp->xdp_prog ? bp->xdp_prog->aux->id : 0; rc = 0; break; default: -- cgit v1.2.3 From 1efde2b668c98dc1c358fb460a738f50f291107c Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 15 Jun 2017 17:29:14 -0700 Subject: bpf: thunderx: Report bpf_prog ID during XDP_QUERY_PROG Add support to thunderx to report bpf_prog ID during XDP_QUERY_PROG. Signed-off-by: Martin KaFai Lau Cc: Sunil Goutham Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/nicvf_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index d6477af88085..573755b0a51b 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -1763,6 +1763,7 @@ static int nicvf_xdp(struct net_device *netdev, struct netdev_xdp *xdp) return nicvf_xdp_setup(nic, xdp->prog); case XDP_QUERY_PROG: xdp->prog_attached = !!nic->xdp_prog; + xdp->prog_id = nic->xdp_prog ? nic->xdp_prog->aux->id : 0; return 0; default: return -EINVAL; -- cgit v1.2.3 From 4792093edd032a1bc8ab6cac8abd877bbd8c53b2 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 15 Jun 2017 17:29:15 -0700 Subject: bpf: ixgbe: Report bpf_prog ID during XDP_QUERY_PROG Add support to ixgbe to report bpf_prog ID during XDP_QUERY_PROG. Signed-off-by: Martin KaFai Lau Cc: Alexander Duyck Cc: John Fastabend Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index f3dc5dea9300..f1dbdf26d8e1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -9815,6 +9815,8 @@ static int ixgbe_xdp(struct net_device *dev, struct netdev_xdp *xdp) return ixgbe_xdp_setup(dev, xdp->prog); case XDP_QUERY_PROG: xdp->prog_attached = !!(adapter->xdp_prog); + xdp->prog_id = adapter->xdp_prog ? + adapter->xdp_prog->aux->id : 0; return 0; default: return -EINVAL; -- cgit v1.2.3 From c330182479fa73227c44404d104577580d441458 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 15 Jun 2017 17:29:16 -0700 Subject: bpf: nfp: Report bpf_prog ID during XDP_QUERY_PROG Add support to nfp to report bpf_prog ID during XDP_QUERY_PROG. Signed-off-by: Martin KaFai Lau Cc: Jakub Kicinski Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 49d1756d6a8e..378512dec80d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3256,6 +3256,7 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) return nfp_net_xdp_setup(nn, xdp); case XDP_QUERY_PROG: xdp->prog_attached = !!nn->dp.xdp_prog; + xdp->prog_id = nn->dp.xdp_prog ? nn->dp.xdp_prog->aux->id : 0; return 0; default: return -EINVAL; -- cgit v1.2.3 From 22e0d75f43561957b2293f7f02f2c8c0c2d70842 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 15 Jun 2017 17:29:17 -0700 Subject: bpf: qede: Report bpf_prog ID during XDP_QUERY_PROG Add support to qede to report bpf_prog ID during XDP_QUERY_PROG. Signed-off-by: Martin KaFai Lau Cc: Mintz Yuval Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_filter.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c index 13955a3bd3b3..f939db5bac5f 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_filter.c +++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c @@ -1037,6 +1037,7 @@ int qede_xdp(struct net_device *dev, struct netdev_xdp *xdp) return qede_xdp_set(edev, xdp->prog); case XDP_QUERY_PROG: xdp->prog_attached = !!edev->xdp_prog; + xdp->prog_id = edev->xdp_prog ? edev->xdp_prog->aux->id : 0; return 0; default: return -EINVAL; -- cgit v1.2.3 From 14ef8b367165f88d708efbac60034e47986b23b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Thu, 15 Jun 2017 16:43:16 +0200 Subject: net: mvmdio: reorder headers alphabetically Cosmetic fix reordering headers alphabetically. Signed-off-by: Antoine Tenart Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 90a60b98c28e..109a2bff334d 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -17,16 +17,16 @@ * warranty of any kind, whether express or implied. */ +#include +#include +#include +#include #include #include #include +#include #include -#include #include -#include -#include -#include -#include #include #include -- cgit v1.2.3 From 2040ef2f74a42a56da424aea28249a7f188aa637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Thu, 15 Jun 2017 16:43:17 +0200 Subject: net: mvmdio: use tabs for defines Cosmetic patch replacing spaces by tabs for defined values. Signed-off-by: Antoine Tenart Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 109a2bff334d..17b518b13ae3 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -30,25 +30,25 @@ #include #include -#define MVMDIO_SMI_DATA_SHIFT 0 -#define MVMDIO_SMI_PHY_ADDR_SHIFT 16 -#define MVMDIO_SMI_PHY_REG_SHIFT 21 -#define MVMDIO_SMI_READ_OPERATION BIT(26) -#define MVMDIO_SMI_WRITE_OPERATION 0 -#define MVMDIO_SMI_READ_VALID BIT(27) -#define MVMDIO_SMI_BUSY BIT(28) -#define MVMDIO_ERR_INT_CAUSE 0x007C -#define MVMDIO_ERR_INT_SMI_DONE 0x00000010 -#define MVMDIO_ERR_INT_MASK 0x0080 +#define MVMDIO_SMI_DATA_SHIFT 0 +#define MVMDIO_SMI_PHY_ADDR_SHIFT 16 +#define MVMDIO_SMI_PHY_REG_SHIFT 21 +#define MVMDIO_SMI_READ_OPERATION BIT(26) +#define MVMDIO_SMI_WRITE_OPERATION 0 +#define MVMDIO_SMI_READ_VALID BIT(27) +#define MVMDIO_SMI_BUSY BIT(28) +#define MVMDIO_ERR_INT_CAUSE 0x007C +#define MVMDIO_ERR_INT_SMI_DONE 0x00000010 +#define MVMDIO_ERR_INT_MASK 0x0080 /* * SMI Timeout measurements: * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt) * - Armada 370 (Globalscale Mirabox): 41us to 43us (Polled) */ -#define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */ -#define MVMDIO_SMI_POLL_INTERVAL_MIN 45 -#define MVMDIO_SMI_POLL_INTERVAL_MAX 55 +#define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */ +#define MVMDIO_SMI_POLL_INTERVAL_MIN 45 +#define MVMDIO_SMI_POLL_INTERVAL_MAX 55 struct orion_mdio_dev { struct mutex lock; -- cgit v1.2.3 From fd3ebd857895884c2567a7f4dfbf50ba49bd2eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Thu, 15 Jun 2017 16:43:18 +0200 Subject: net: mvmdio: use GENMASK for masks Cosmetic patch to use the GENMASK helper for masks. Signed-off-by: Antoine Tenart Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 17b518b13ae3..583f1c5753c2 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -138,7 +138,7 @@ static int orion_mdio_read(struct mii_bus *bus, int mii_id, goto out; } - ret = val & 0xFFFF; + ret = val & GENMASK(15, 0); out: mutex_unlock(&dev->lock); return ret; -- cgit v1.2.3 From 0caf0305a39e62d5cb33cfd1e98aa77a25768232 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 15 Jun 2017 16:43:19 +0200 Subject: net: mvmdio: remove duplicate locking The MDIO layer already provides per-bus locking, so there's no need for MDIO bus drivers to do their own internal locking. Remove this. Signed-off-by: Russell King Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 583f1c5753c2..eab625752b12 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -51,7 +50,6 @@ #define MVMDIO_SMI_POLL_INTERVAL_MAX 55 struct orion_mdio_dev { - struct mutex lock; void __iomem *regs; struct clk *clk[3]; /* @@ -116,8 +114,6 @@ static int orion_mdio_read(struct mii_bus *bus, int mii_id, u32 val; int ret; - mutex_lock(&dev->lock); - ret = orion_mdio_wait_ready(bus); if (ret < 0) goto out; @@ -140,7 +136,6 @@ static int orion_mdio_read(struct mii_bus *bus, int mii_id, ret = val & GENMASK(15, 0); out: - mutex_unlock(&dev->lock); return ret; } @@ -150,8 +145,6 @@ static int orion_mdio_write(struct mii_bus *bus, int mii_id, struct orion_mdio_dev *dev = bus->priv; int ret; - mutex_lock(&dev->lock); - ret = orion_mdio_wait_ready(bus); if (ret < 0) goto out; @@ -163,7 +156,6 @@ static int orion_mdio_write(struct mii_bus *bus, int mii_id, dev->regs); out: - mutex_unlock(&dev->lock); return ret; } @@ -244,8 +236,6 @@ static int orion_mdio_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - mutex_init(&dev->lock); - if (pdev->dev.of_node) ret = of_mdiobus_register(bus, pdev->dev.of_node); else -- cgit v1.2.3 From b0b7fa4f7cd016087f22a4c173318b16c796ff11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Thu, 15 Jun 2017 16:43:20 +0200 Subject: net: mvmdio: introduce an ops structure Introduce an ops structure to add an indirection on the is_done function, as this is needed to add the xMDIO support later. Signed-off-by: Antoine Tenart Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index eab625752b12..2a8efc77f5fe 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -62,14 +62,14 @@ struct orion_mdio_dev { wait_queue_head_t smi_busy_wait; }; -static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev) -{ - return !(readl(dev->regs) & MVMDIO_SMI_BUSY); -} +struct orion_mdio_ops { + int (*is_done)(struct orion_mdio_dev *); +}; /* Wait for the SMI unit to be ready for another operation */ -static int orion_mdio_wait_ready(struct mii_bus *bus) +static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops, + struct mii_bus *bus) { struct orion_mdio_dev *dev = bus->priv; unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT); @@ -77,7 +77,7 @@ static int orion_mdio_wait_ready(struct mii_bus *bus) int timedout = 0; while (1) { - if (orion_mdio_smi_is_done(dev)) + if (ops->is_done(dev)) return 0; else if (timedout) break; @@ -96,8 +96,7 @@ static int orion_mdio_wait_ready(struct mii_bus *bus) if (timeout < 2) timeout = 2; wait_event_timeout(dev->smi_busy_wait, - orion_mdio_smi_is_done(dev), - timeout); + ops->is_done(dev), timeout); ++timedout; } @@ -107,6 +106,15 @@ static int orion_mdio_wait_ready(struct mii_bus *bus) return -ETIMEDOUT; } +static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev) +{ + return !(readl(dev->regs) & MVMDIO_SMI_BUSY); +} + +static const struct orion_mdio_ops orion_mdio_smi_ops = { + .is_done = orion_mdio_smi_is_done, +}; + static int orion_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { @@ -114,7 +122,7 @@ static int orion_mdio_read(struct mii_bus *bus, int mii_id, u32 val; int ret; - ret = orion_mdio_wait_ready(bus); + ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus); if (ret < 0) goto out; @@ -123,7 +131,7 @@ static int orion_mdio_read(struct mii_bus *bus, int mii_id, MVMDIO_SMI_READ_OPERATION), dev->regs); - ret = orion_mdio_wait_ready(bus); + ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus); if (ret < 0) goto out; @@ -145,7 +153,7 @@ static int orion_mdio_write(struct mii_bus *bus, int mii_id, struct orion_mdio_dev *dev = bus->priv; int ret; - ret = orion_mdio_wait_ready(bus); + ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus); if (ret < 0) goto out; -- cgit v1.2.3 From 1955796640a6736583b59c581d3ccddfca66cb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Thu, 15 Jun 2017 16:43:21 +0200 Subject: net: mvmdio: put the poll intervals in the ops structure Put the two poll intervals (min and max) in the driver's ops structure. This is needed to add the xmdio support later. Signed-off-by: Antoine Tenart Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 2a8efc77f5fe..e4aa8e2d2e8a 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -64,6 +64,8 @@ struct orion_mdio_dev { struct orion_mdio_ops { int (*is_done)(struct orion_mdio_dev *); + unsigned int poll_interval_min; + unsigned int poll_interval_max; }; /* Wait for the SMI unit to be ready for another operation @@ -83,8 +85,8 @@ static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops, break; if (dev->err_interrupt <= 0) { - usleep_range(MVMDIO_SMI_POLL_INTERVAL_MIN, - MVMDIO_SMI_POLL_INTERVAL_MAX); + usleep_range(ops->poll_interval_min, + ops->poll_interval_max); if (time_is_before_jiffies(end)) ++timedout; @@ -113,6 +115,8 @@ static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev) static const struct orion_mdio_ops orion_mdio_smi_ops = { .is_done = orion_mdio_smi_is_done, + .poll_interval_min = MVMDIO_SMI_POLL_INTERVAL_MIN, + .poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX, }; static int orion_mdio_read(struct mii_bus *bus, int mii_id, -- cgit v1.2.3 From 440ea77654d0fbb6e144dc90f6fa1d4429d83280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Thu, 15 Jun 2017 16:43:22 +0200 Subject: net: mvmdio: check the MII_ADDR_C45 bit is not set for smi operations Add a check for the read and write smi operations, to ensure the MII_ADDR_C45 bit isn't set. This will be needed as soon as the xSMI support is added to the mvmdio driver. Signed-off-by: Antoine Tenart Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index e4aa8e2d2e8a..fe6072aae0a6 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -126,6 +126,9 @@ static int orion_mdio_read(struct mii_bus *bus, int mii_id, u32 val; int ret; + if (regnum & MII_ADDR_C45) + return -EOPNOTSUPP; + ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus); if (ret < 0) goto out; @@ -157,6 +160,9 @@ static int orion_mdio_write(struct mii_bus *bus, int mii_id, struct orion_mdio_dev *dev = bus->priv; int ret; + if (regnum & MII_ADDR_C45) + return -EOPNOTSUPP; + ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus); if (ret < 0) goto out; -- cgit v1.2.3 From c0ac08f533e6995e1bc14e67cd3c21ad07dd9214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Thu, 15 Jun 2017 16:43:23 +0200 Subject: net: mvmdio: add xmdio xsmi support This patch adds the xmdio xsmi interface support in the mvmdio driver. This interface is used in Ethernet controllers on Marvell 370, 7k and 8k (as of now). The xsmi interface supported by this driver complies with the IEEE 802.3 clause 45. The xSMI interface is used by 10GbE devices. Signed-off-by: Antoine Tenart Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 112 +++++++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index fe6072aae0a6..0888e50f6b17 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,15 @@ #define MVMDIO_ERR_INT_SMI_DONE 0x00000010 #define MVMDIO_ERR_INT_MASK 0x0080 +#define MVMDIO_XSMI_MGNT_REG 0x0 +#define MVMDIO_XSMI_PHYADDR_SHIFT 16 +#define MVMDIO_XSMI_DEVADDR_SHIFT 21 +#define MVMDIO_XSMI_WRITE_OPERATION (0x5 << 26) +#define MVMDIO_XSMI_READ_OPERATION (0x7 << 26) +#define MVMDIO_XSMI_READ_VALID BIT(29) +#define MVMDIO_XSMI_BUSY BIT(30) +#define MVMDIO_XSMI_ADDR_REG 0x8 + /* * SMI Timeout measurements: * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt) @@ -49,6 +59,9 @@ #define MVMDIO_SMI_POLL_INTERVAL_MIN 45 #define MVMDIO_SMI_POLL_INTERVAL_MAX 55 +#define MVMDIO_XSMI_POLL_INTERVAL_MIN 150 +#define MVMDIO_XSMI_POLL_INTERVAL_MAX 160 + struct orion_mdio_dev { void __iomem *regs; struct clk *clk[3]; @@ -62,6 +75,11 @@ struct orion_mdio_dev { wait_queue_head_t smi_busy_wait; }; +enum orion_mdio_bus_type { + BUS_TYPE_SMI, + BUS_TYPE_XSMI +}; + struct orion_mdio_ops { int (*is_done)(struct orion_mdio_dev *); unsigned int poll_interval_min; @@ -119,8 +137,8 @@ static const struct orion_mdio_ops orion_mdio_smi_ops = { .poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX, }; -static int orion_mdio_read(struct mii_bus *bus, int mii_id, - int regnum) +static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id, + int regnum) { struct orion_mdio_dev *dev = bus->priv; u32 val; @@ -154,8 +172,8 @@ out: return ret; } -static int orion_mdio_write(struct mii_bus *bus, int mii_id, - int regnum, u16 value) +static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id, + int regnum, u16 value) { struct orion_mdio_dev *dev = bus->priv; int ret; @@ -177,6 +195,73 @@ out: return ret; } +static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev) +{ + return !(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & MVMDIO_XSMI_BUSY); +} + +static const struct orion_mdio_ops orion_mdio_xsmi_ops = { + .is_done = orion_mdio_xsmi_is_done, + .poll_interval_min = MVMDIO_XSMI_POLL_INTERVAL_MIN, + .poll_interval_max = MVMDIO_XSMI_POLL_INTERVAL_MAX, +}; + +static int orion_mdio_xsmi_read(struct mii_bus *bus, int mii_id, + int regnum) +{ + struct orion_mdio_dev *dev = bus->priv; + u16 dev_addr = (regnum >> 16) & GENMASK(4, 0); + int ret; + + if (!(regnum & MII_ADDR_C45)) + return -EOPNOTSUPP; + + ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus); + if (ret < 0) + return ret; + + writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG); + writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) | + (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) | + MVMDIO_XSMI_READ_OPERATION, + dev->regs + MVMDIO_XSMI_MGNT_REG); + + ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus); + if (ret < 0) + return ret; + + if (!(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & + MVMDIO_XSMI_READ_VALID)) { + dev_err(bus->parent, "XSMI bus read not valid\n"); + return -ENODEV; + } + + return readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0); +} + +static int orion_mdio_xsmi_write(struct mii_bus *bus, int mii_id, + int regnum, u16 value) +{ + struct orion_mdio_dev *dev = bus->priv; + u16 dev_addr = (regnum >> 16) & GENMASK(4, 0); + int ret; + + if (!(regnum & MII_ADDR_C45)) + return -EOPNOTSUPP; + + ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus); + if (ret < 0) + return ret; + + writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG); + writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) | + (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) | + MVMDIO_XSMI_WRITE_OPERATION | value, + dev->regs + MVMDIO_XSMI_MGNT_REG); + + return 0; +} + static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id) { struct orion_mdio_dev *dev = dev_id; @@ -194,11 +279,14 @@ static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id) static int orion_mdio_probe(struct platform_device *pdev) { + enum orion_mdio_bus_type type; struct resource *r; struct mii_bus *bus; struct orion_mdio_dev *dev; int i, ret; + type = (enum orion_mdio_bus_type)of_device_get_match_data(&pdev->dev); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { dev_err(&pdev->dev, "No SMI register address given\n"); @@ -210,9 +298,18 @@ static int orion_mdio_probe(struct platform_device *pdev) if (!bus) return -ENOMEM; + switch (type) { + case BUS_TYPE_SMI: + bus->read = orion_mdio_smi_read; + bus->write = orion_mdio_smi_write; + break; + case BUS_TYPE_XSMI: + bus->read = orion_mdio_xsmi_read; + bus->write = orion_mdio_xsmi_write; + break; + } + bus->name = "orion_mdio_bus"; - bus->read = orion_mdio_read; - bus->write = orion_mdio_write; snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); bus->parent = &pdev->dev; @@ -302,7 +399,8 @@ static int orion_mdio_remove(struct platform_device *pdev) } static const struct of_device_id orion_mdio_match[] = { - { .compatible = "marvell,orion-mdio" }, + { .compatible = "marvell,orion-mdio", .data = (void *)BUS_TYPE_SMI }, + { .compatible = "marvell,xmdio", .data = (void *)BUS_TYPE_XSMI }, { } }; MODULE_DEVICE_TABLE(of, orion_mdio_match); -- cgit v1.2.3 From 0268b51e3043d96c4133154b20a5b8338857cb5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20T=C3=A9nart?= Date: Thu, 15 Jun 2017 16:43:24 +0200 Subject: net: mvmdio: simplify the smi read and write error paths Cosmetic patch simplifying the smi read and write error paths. It also align their error paths with the ones of the xsmi functions. Signed-off-by: Antoine Tenart Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 0888e50f6b17..c9798210fa0f 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -149,7 +149,7 @@ static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id, ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus); if (ret < 0) - goto out; + return ret; writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) | (regnum << MVMDIO_SMI_PHY_REG_SHIFT) | @@ -158,18 +158,15 @@ static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id, ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus); if (ret < 0) - goto out; + return ret; val = readl(dev->regs); if (!(val & MVMDIO_SMI_READ_VALID)) { dev_err(bus->parent, "SMI bus read not valid\n"); - ret = -ENODEV; - goto out; + return -ENODEV; } - ret = val & GENMASK(15, 0); -out: - return ret; + return val & GENMASK(15, 0); } static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id, @@ -183,7 +180,7 @@ static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id, ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus); if (ret < 0) - goto out; + return ret; writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) | (regnum << MVMDIO_SMI_PHY_REG_SHIFT) | @@ -191,8 +188,7 @@ static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id, (value << MVMDIO_SMI_DATA_SHIFT)), dev->regs); -out: - return ret; + return 0; } static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev) -- cgit v1.2.3 From 3407dc8ed1a7528e8792c86d9ebc124aa5fa629f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 15 Jun 2017 10:15:52 -0700 Subject: net: dsa: loop: Inline unregister_fixed_phys() This is a simple function that only gets used in the driver's remove function, inline it there. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/dsa_loop.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 79e62593ff4e..fb888593c2e9 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -293,15 +293,6 @@ static struct mdio_driver dsa_loop_drv = { #define NUM_FIXED_PHYS (DSA_LOOP_NUM_PORTS - 2) -static void unregister_fixed_phys(void) -{ - unsigned int i; - - for (i = 0; i < NUM_FIXED_PHYS; i++) - if (phydevs[i]) - fixed_phy_unregister(phydevs[i]); -} - static int __init dsa_loop_init(void) { struct fixed_phy_status status = { @@ -320,8 +311,12 @@ module_init(dsa_loop_init); static void __exit dsa_loop_exit(void) { + unsigned int i; + mdio_driver_unregister(&dsa_loop_drv); - unregister_fixed_phys(); + for (i = 0; i < NUM_FIXED_PHYS; i++) + if (phydevs[i]) + fixed_phy_unregister(phydevs[i]); } module_exit(dsa_loop_exit); -- cgit v1.2.3 From 484c01720d84c65e996a6adc4ba8ce6a811879df Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 15 Jun 2017 10:15:53 -0700 Subject: net: dsa: loop: Implement ethtool statistics When a DSA driver implements ethtool statistics, we also override the master network device's ethtool statistics with the CPU port's statistics and this has proven to be a possible source of bugs in the past. Enhance the dsa_loop.c driver to provide statistics under the forme of ok/error reads and writes from the per-port PHY read/writes. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/dsa_loop.c | 79 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index fb888593c2e9..fdd8f3872102 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,30 @@ struct dsa_loop_vlan { u16 untagged; }; +struct dsa_loop_mib_entry { + char name[ETH_GSTRING_LEN]; + unsigned long val; +}; + +enum dsa_loop_mib_counters { + DSA_LOOP_PHY_READ_OK, + DSA_LOOP_PHY_READ_ERR, + DSA_LOOP_PHY_WRITE_OK, + DSA_LOOP_PHY_WRITE_ERR, + __DSA_LOOP_CNT_MAX, +}; + +static struct dsa_loop_mib_entry dsa_loop_mibs[] = { + [DSA_LOOP_PHY_READ_OK] = { "phy_read_ok", }, + [DSA_LOOP_PHY_READ_ERR] = { "phy_read_err", }, + [DSA_LOOP_PHY_WRITE_OK] = { "phy_write_ok", }, + [DSA_LOOP_PHY_WRITE_ERR] = { "phy_write_err", }, +}; + +struct dsa_loop_port { + struct dsa_loop_mib_entry mib[__DSA_LOOP_CNT_MAX]; +}; + #define DSA_LOOP_VLANS 5 struct dsa_loop_priv { @@ -33,6 +58,7 @@ struct dsa_loop_priv { unsigned int port_base; struct dsa_loop_vlan vlans[DSA_LOOP_VLANS]; struct net_device *netdev; + struct dsa_loop_port ports[DSA_MAX_PORTS]; u16 pvid; }; @@ -47,11 +73,43 @@ static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds) static int dsa_loop_setup(struct dsa_switch *ds) { + struct dsa_loop_priv *ps = ds->priv; + unsigned int i; + + for (i = 0; i < ds->num_ports; i++) + memcpy(ps->ports[i].mib, dsa_loop_mibs, + sizeof(dsa_loop_mibs)); + dev_dbg(ds->dev, "%s\n", __func__); return 0; } +static int dsa_loop_get_sset_count(struct dsa_switch *ds) +{ + return __DSA_LOOP_CNT_MAX; +} + +static void dsa_loop_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +{ + struct dsa_loop_priv *ps = ds->priv; + unsigned int i; + + for (i = 0; i < __DSA_LOOP_CNT_MAX; i++) + memcpy(data + i * ETH_GSTRING_LEN, + ps->ports[port].mib[i].name, ETH_GSTRING_LEN); +} + +static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port, + uint64_t *data) +{ + struct dsa_loop_priv *ps = ds->priv; + unsigned int i; + + for (i = 0; i < __DSA_LOOP_CNT_MAX; i++) + data[i] = ps->ports[port].mib[i].val; +} + static int dsa_loop_set_addr(struct dsa_switch *ds, u8 *addr) { dev_dbg(ds->dev, "%s\n", __func__); @@ -63,10 +121,17 @@ static int dsa_loop_phy_read(struct dsa_switch *ds, int port, int regnum) { struct dsa_loop_priv *ps = ds->priv; struct mii_bus *bus = ps->bus; + int ret; dev_dbg(ds->dev, "%s\n", __func__); - return mdiobus_read_nested(bus, ps->port_base + port, regnum); + ret = mdiobus_read_nested(bus, ps->port_base + port, regnum); + if (ret < 0) + ps->ports[port].mib[DSA_LOOP_PHY_READ_ERR].val++; + else + ps->ports[port].mib[DSA_LOOP_PHY_READ_OK].val++; + + return ret; } static int dsa_loop_phy_write(struct dsa_switch *ds, int port, @@ -74,10 +139,17 @@ static int dsa_loop_phy_write(struct dsa_switch *ds, int port, { struct dsa_loop_priv *ps = ds->priv; struct mii_bus *bus = ps->bus; + int ret; dev_dbg(ds->dev, "%s\n", __func__); - return mdiobus_write_nested(bus, ps->port_base + port, regnum, value); + ret = mdiobus_write_nested(bus, ps->port_base + port, regnum, value); + if (ret < 0) + ps->ports[port].mib[DSA_LOOP_PHY_WRITE_ERR].val++; + else + ps->ports[port].mib[DSA_LOOP_PHY_WRITE_OK].val++; + + return ret; } static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port, @@ -225,6 +297,9 @@ static int dsa_loop_port_vlan_dump(struct dsa_switch *ds, int port, static struct dsa_switch_ops dsa_loop_driver = { .get_tag_protocol = dsa_loop_get_protocol, .setup = dsa_loop_setup, + .get_strings = dsa_loop_get_strings, + .get_ethtool_stats = dsa_loop_get_ethtool_stats, + .get_sset_count = dsa_loop_get_sset_count, .set_addr = dsa_loop_set_addr, .phy_read = dsa_loop_phy_read, .phy_write = dsa_loop_phy_write, -- cgit v1.2.3 From 6a2fb0e99f9cab349dce0a36862b0cd370036452 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 15 Jun 2017 14:48:09 -0400 Subject: ibmvnic: driver initialization for kdump/kexec When booting into the kdump/kexec kernel, pHyp and vios are not prepared for the initialization crq request and a failover transport event is generated. This is not handled correctly. At this point in initialization the driver is still in the 'probing' state and cannot handle a full reset of the driver as is normally done for a failover transport event. To correct this we catch driver resets while still in the 'probing' state and return EAGAIN. This results in the driver tearing down the main crq and calling ibmvnic_init() again. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 9923b9fa0c74..722daf55d757 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1454,6 +1454,12 @@ static void ibmvnic_reset(struct ibmvnic_adapter *adapter, return; } + if (adapter->state == VNIC_PROBING) { + netdev_warn(netdev, "Adapter reset during probe\n"); + adapter->init_done_rc = EAGAIN; + return; + } + mutex_lock(&adapter->rwi_lock); list_for_each(entry, &adapter->rwi_list) { @@ -3649,12 +3655,18 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) adapter->from_passive_init = false; init_completion(&adapter->init_done); + adapter->init_done_rc = 0; ibmvnic_send_crq_init(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { dev_err(dev, "Initialization sequence timed out\n"); return -1; } + if (adapter->init_done_rc) { + release_crq_queue(adapter); + return adapter->init_done_rc; + } + if (adapter->from_passive_init) { adapter->state = VNIC_OPEN; adapter->from_passive_init = false; @@ -3723,11 +3735,13 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) mutex_init(&adapter->rwi_lock); adapter->resetting = false; - rc = ibmvnic_init(adapter); - if (rc) { - free_netdev(netdev); - return rc; - } + do { + rc = ibmvnic_init(adapter); + if (rc != EAGAIN) { + free_netdev(netdev); + return rc; + } + } while (rc == EAGAIN); netdev->mtu = adapter->req_mtu - ETH_HLEN; -- cgit v1.2.3 From 1cfb71eeb12047bcdbd3e6730ffed66e810a0855 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Sat, 17 Jun 2017 10:42:33 -0700 Subject: ipv6: take dst->__refcnt for insertion into fib6 tree In IPv6 routing code, struct rt6_info is created for each static route and RTF_CACHE route and inserted into fib6 tree. In both cases, dst ref count is not taken. As explained in the previous patch, this leads to the need of the dst garbage collector. This patch holds ref count of dst before inserting the route into fib6 tree and properly releases the dst when deleting it from the fib6 tree as a preparation in order to fully get rid of dst gc later. Also, correct fib6_age() logic to check dst->__refcnt to be 1 to indicate no user is referencing the dst. And remove dst_hold() in vrf_rt6_create() as ip6_dst_alloc() already puts dst->__refcnt to 1. Signed-off-by: Wei Wang Acked-by: Martin KaFai Lau Signed-off-by: David S. Miller --- drivers/net/vrf.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index c6c0595d267b..d038927acfca 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -583,8 +583,6 @@ static int vrf_rt6_create(struct net_device *dev) if (!rt6) goto out; - dst_hold(&rt6->dst); - rt6->rt6i_table = rt6i_table; rt6->dst.output = vrf_output6; @@ -597,8 +595,6 @@ static int vrf_rt6_create(struct net_device *dev) goto out; } - dst_hold(&rt6_local->dst); - rt6_local->rt6i_idev = in6_dev_get(dev); rt6_local->rt6i_flags = RTF_UP | RTF_NONEXTHOP | RTF_LOCAL; rt6_local->rt6i_table = rt6i_table; -- cgit v1.2.3 From a4c2fd7f78915a0d7c5275e7612e7793157a01f2 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Sat, 17 Jun 2017 10:42:42 -0700 Subject: net: remove DST_NOCACHE flag DST_NOCACHE flag check has been removed from dst_release() and dst_hold_safe() in a previous patch because all the dst are now ref counted properly and can be released based on refcnt only. Looking at the rest of the DST_NOCACHE use, all of them can now be removed or replaced with other checks. So this patch gets rid of all the DST_NOCACHE usage and remove this flag completely. Signed-off-by: Wei Wang Acked-by: Martin KaFai Lau Signed-off-by: David S. Miller --- drivers/net/vrf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index d038927acfca..997ef25189fd 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -563,7 +563,7 @@ static void vrf_rt6_release(struct net_device *dev, struct net_vrf *vrf) static int vrf_rt6_create(struct net_device *dev) { - int flags = DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE; + int flags = DST_HOST | DST_NOPOLICY | DST_NOXFRM; struct net_vrf *vrf = netdev_priv(dev); struct net *net = dev_net(dev); struct fib6_table *rt6i_table; -- cgit v1.2.3 From 67dec1928d08b6ca7dc9bebc4d3fe2d54da4b108 Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Tue, 25 Apr 2017 15:43:49 -0700 Subject: NFC: trf7970a: Don't de-assert EN2 unless it was asserted When the trf7970a part has the bug related to 'en2-rf-quirk', the GPIO connected to the EN2 pin will not be asserted by the driver when powering up so it shouldn't be de-asserted when powering down. Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 2d1c8ca6e679..1a87525a88cd 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -1940,8 +1940,10 @@ static int trf7970a_power_down(struct trf7970a *trf) } gpio_set_value(trf->en_gpio, 0); - if (gpio_is_valid(trf->en2_gpio)) - gpio_set_value(trf->en2_gpio, 0); + + if (!(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) + if (gpio_is_valid(trf->en2_gpio)) + gpio_set_value(trf->en2_gpio, 0); ret = regulator_disable(trf->regulator); if (ret) -- cgit v1.2.3 From 69f984f037a869477cac654a834e8b5435bb35b6 Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Tue, 25 Apr 2017 15:43:50 -0700 Subject: NFC: trf7970a: Fix inaccurate comment in trf7970a_probe() As of commit ce69b95ca4e4 ("NFC: Make EN2 pin optional in the TRF7970A driver"), only the GPIO for the 'EN' enable pin needs to be specified in the device tree so update the comments that says both 'EN' and 'EN2' must be specified. Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 1a87525a88cd..5d5a8b0e57d4 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -2046,7 +2046,7 @@ static int trf7970a_probe(struct spi_device *spi) if (of_property_read_bool(np, "irq-status-read-quirk")) trf->quirks |= TRF7970A_QUIRK_IRQ_STATUS_READ; - /* There are two enable pins - both must be present */ + /* There are two enable pins - only EN must be present in the DT */ trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0); if (!gpio_is_valid(trf->en_gpio)) { dev_err(trf->dev, "No EN GPIO property\n"); -- cgit v1.2.3 From afcb9fbdba71cd39daefaff1e288472565df6af2 Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Tue, 25 Apr 2017 15:43:51 -0700 Subject: NFC: trf7970a: Only check 'en2-rf-quirk' if EN2 is specified The quirk indicated by the 'en2-rf-quirk' device tree property is only relevant when there is a GPIO connected to the EN2 pin of the trf7970a. This means we should only check for 'en2-rf-quirk' when EN2 is specified in the 'ti,enable-gpios' property of the device tree. Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 5d5a8b0e57d4..4655680b0e7b 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -2070,6 +2070,9 @@ static int trf7970a_probe(struct spi_device *spi) dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret); return ret; } + + if (of_property_read_bool(np, "en2-rf-quirk")) + trf->quirks |= TRF7970A_QUIRK_EN2_MUST_STAY_LOW; } of_property_read_u32(np, "clock-frequency", &clk_freq); @@ -2081,9 +2084,6 @@ static int trf7970a_probe(struct spi_device *spi) return -EINVAL; } - if (of_property_read_bool(np, "en2-rf-quirk")) - trf->quirks |= TRF7970A_QUIRK_EN2_MUST_STAY_LOW; - ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL, trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "trf7970a", trf); -- cgit v1.2.3 From fcc652f6885cd37a0c3f3b1ed572d3544c3240c4 Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Tue, 25 Apr 2017 15:43:52 -0700 Subject: NFC: trf7970a: Remove useless comment The last entry in the trf7970a_of_match[] table must be an empty entry to demarcate the end of the table. Currently, there is a comment indicating this but it is obvious so remove the comment. Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 4655680b0e7b..b9a90843ea35 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -2273,7 +2273,7 @@ static const struct dev_pm_ops trf7970a_pm_ops = { static const struct of_device_id trf7970a_of_match[] = { { .compatible = "ti,trf7970a", }, - { /* sentinel */ }, + {}, }; MODULE_DEVICE_TABLE(of, trf7970a_of_match); -- cgit v1.2.3 From a34631c2723797dd31e6f83538899eeb4c03b753 Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Tue, 25 Apr 2017 15:43:53 -0700 Subject: NFC: trf7970a: Remove support for 'vin-voltage-override' DT property The 'vin-voltage-override' DT property is used by the trf7970a driver to override the voltage presented to the driver by the regulator subsystem. This is unnecessary as properly specifying the regulator chain via DT properties will accomplish the same thing. Therefore, remove support for 'vin-voltage-override'. Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index b9a90843ea35..5827ad111942 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -2005,12 +2005,6 @@ static int trf7970a_get_autosuspend_delay(struct device_node *np) return autosuspend_delay; } -static int trf7970a_get_vin_voltage_override(struct device_node *np, - u32 *vin_uvolts) -{ - return of_property_read_u32(np, "vin-voltage-override", vin_uvolts); -} - static int trf7970a_probe(struct spi_device *spi) { struct device_node *np = spi->dev.of_node; @@ -2108,10 +2102,7 @@ static int trf7970a_probe(struct spi_device *spi) goto err_destroy_lock; } - ret = trf7970a_get_vin_voltage_override(np, &uvolts); - if (ret) - uvolts = regulator_get_voltage(trf->regulator); - + uvolts = regulator_get_voltage(trf->regulator); if (uvolts > 4000000) trf->chip_status_ctrl = TRF7970A_CHIP_STATUS_VRS5_3; -- cgit v1.2.3 From d34e48d6a62a06eb7f72c7dc534c4c318a163dad Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Tue, 25 Apr 2017 15:43:55 -0700 Subject: NFC: trf7970a: Convert to descriptor based GPIO interface The trf7970a driver uses the deprecated integer-based GPIO consumer interface so convert it to use the new descriptor-based GPIO consumer interface. Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/Kconfig | 2 +- drivers/nfc/trf7970a.c | 61 +++++++++++++++++++++----------------------------- 2 files changed, 26 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index c4208487fadc..b065eb605215 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -7,7 +7,7 @@ menu "Near Field Communication (NFC) devices" config NFC_TRF7970A tristate "Texas Instruments TRF7970a NFC driver" - depends on SPI && NFC_DIGITAL + depends on SPI && NFC_DIGITAL && GPIOLIB help This option enables the NFC driver for Texas Instruments' TRF7970a device. Such device supports 5 different protocols: ISO14443A, diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 5827ad111942..bb777f50b4fb 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -20,9 +20,8 @@ #include #include #include -#include +#include #include -#include #include #include @@ -452,8 +451,8 @@ struct trf7970a { u8 tx_cmd; bool issue_eof; bool adjust_resp_len; - int en2_gpio; - int en_gpio; + struct gpio_desc *en_gpiod; + struct gpio_desc *en2_gpiod; struct mutex lock; unsigned int timeout; bool ignore_timeout; @@ -1908,14 +1907,13 @@ static int trf7970a_power_up(struct trf7970a *trf) usleep_range(5000, 6000); - if (!(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) { - if (gpio_is_valid(trf->en2_gpio)) { - gpio_set_value(trf->en2_gpio, 1); - usleep_range(1000, 2000); - } + if (trf->en2_gpiod && + !(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) { + gpiod_set_value_cansleep(trf->en2_gpiod, 1); + usleep_range(1000, 2000); } - gpio_set_value(trf->en_gpio, 1); + gpiod_set_value_cansleep(trf->en_gpiod, 1); usleep_range(20000, 21000); @@ -1939,11 +1937,11 @@ static int trf7970a_power_down(struct trf7970a *trf) return -EBUSY; } - gpio_set_value(trf->en_gpio, 0); + gpiod_set_value_cansleep(trf->en_gpiod, 0); - if (!(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) - if (gpio_is_valid(trf->en2_gpio)) - gpio_set_value(trf->en2_gpio, 0); + if (trf->en2_gpiod && + !(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) + gpiod_set_value_cansleep(trf->en2_gpiod, 0); ret = regulator_disable(trf->regulator); if (ret) @@ -2041,32 +2039,23 @@ static int trf7970a_probe(struct spi_device *spi) trf->quirks |= TRF7970A_QUIRK_IRQ_STATUS_READ; /* There are two enable pins - only EN must be present in the DT */ - trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0); - if (!gpio_is_valid(trf->en_gpio)) { + trf->en_gpiod = devm_gpiod_get_index(trf->dev, "ti,enable", 0, + GPIOD_OUT_LOW); + if (IS_ERR(trf->en_gpiod)) { dev_err(trf->dev, "No EN GPIO property\n"); - return trf->en_gpio; - } - - ret = devm_gpio_request_one(trf->dev, trf->en_gpio, - GPIOF_DIR_OUT | GPIOF_INIT_LOW, "trf7970a EN"); - if (ret) { - dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret); - return ret; + return PTR_ERR(trf->en_gpiod); } - trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1); - if (!gpio_is_valid(trf->en2_gpio)) { + trf->en2_gpiod = devm_gpiod_get_index_optional(trf->dev, "ti,enable", 1, + GPIOD_OUT_LOW); + if (!trf->en2_gpiod) { dev_info(trf->dev, "No EN2 GPIO property\n"); - } else { - ret = devm_gpio_request_one(trf->dev, trf->en2_gpio, - GPIOF_DIR_OUT | GPIOF_INIT_LOW, "trf7970a EN2"); - if (ret) { - dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret); - return ret; - } - - if (of_property_read_bool(np, "en2-rf-quirk")) - trf->quirks |= TRF7970A_QUIRK_EN2_MUST_STAY_LOW; + } else if (IS_ERR(trf->en2_gpiod)) { + dev_err(trf->dev, "Error getting EN2 GPIO property: %ld\n", + PTR_ERR(trf->en2_gpiod)); + return PTR_ERR(trf->en2_gpiod); + } else if (of_property_read_bool(np, "en2-rf-quirk")) { + trf->quirks |= TRF7970A_QUIRK_EN2_MUST_STAY_LOW; } of_property_read_u32(np, "clock-frequency", &clk_freq); -- cgit v1.2.3 From e2f0f67108a8f8ec23e2e530a1a52c97595a6f96 Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Tue, 25 Apr 2017 15:43:56 -0700 Subject: NFC: trf7970a: Clean up coding style issues Clean up coding style issues according to scripts/Lindent. Some scripts/Lindent changes were reverted when it appeared to make the code less readable or when it made the line run over 80 characters. Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 291 +++++++++++++++++++++++++------------------------ 1 file changed, 147 insertions(+), 144 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index bb777f50b4fb..28b942ea15fb 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -122,11 +122,10 @@ NFC_PROTO_ISO14443_B_MASK | NFC_PROTO_FELICA_MASK | \ NFC_PROTO_ISO15693_MASK | NFC_PROTO_NFC_DEP_MASK) -#define TRF7970A_AUTOSUSPEND_DELAY 30000 /* 30 seconds */ +#define TRF7970A_AUTOSUSPEND_DELAY 30000 /* 30 seconds */ #define TRF7970A_13MHZ_CLOCK_FREQUENCY 13560000 #define TRF7970A_27MHZ_CLOCK_FREQUENCY 27120000 - #define TRF7970A_RX_SKB_ALLOC_SIZE 256 #define TRF7970A_FIFO_SIZE 127 @@ -294,7 +293,7 @@ #define TRF7970A_REG_IO_CTRL_AUTO_REG BIT(7) /* IRQ Status Register Bits */ -#define TRF7970A_IRQ_STATUS_NORESP BIT(0) /* ISO15693 only */ +#define TRF7970A_IRQ_STATUS_NORESP BIT(0) /* ISO15693 only */ #define TRF7970A_IRQ_STATUS_NFC_COL_ERROR BIT(0) #define TRF7970A_IRQ_STATUS_COL BIT(1) #define TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR BIT(2) @@ -459,7 +458,6 @@ struct trf7970a { struct delayed_work timeout_work; }; - static int trf7970a_cmd(struct trf7970a *trf, u8 opcode) { u8 cmd = TRF7970A_CMD_BIT_CTRL | TRF7970A_CMD_BIT_OPCODE(opcode); @@ -470,7 +468,7 @@ static int trf7970a_cmd(struct trf7970a *trf, u8 opcode) ret = spi_write(trf->spi, &cmd, 1); if (ret) dev_err(trf->dev, "%s - cmd: 0x%x, ret: %d\n", __func__, cmd, - ret); + ret); return ret; } @@ -482,14 +480,15 @@ static int trf7970a_read(struct trf7970a *trf, u8 reg, u8 *val) ret = spi_write_then_read(trf->spi, &addr, 1, val, 1); if (ret) dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr, - ret); + ret); dev_dbg(trf->dev, "read(0x%x): 0x%x\n", addr, *val); return ret; } -static int trf7970a_read_cont(struct trf7970a *trf, u8 reg, u8 *buf, size_t len) +static int trf7970a_read_cont(struct trf7970a *trf, u8 reg, u8 *buf, + size_t len) { u8 addr = reg | TRF7970A_CMD_BIT_RW | TRF7970A_CMD_BIT_CONTINUOUS; struct spi_transfer t[2]; @@ -513,7 +512,7 @@ static int trf7970a_read_cont(struct trf7970a *trf, u8 reg, u8 *buf, size_t len) ret = spi_sync(trf->spi, &m); if (ret) dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr, - ret); + ret); return ret; } @@ -527,7 +526,7 @@ static int trf7970a_write(struct trf7970a *trf, u8 reg, u8 val) ret = spi_write(trf->spi, buf, 2); if (ret) dev_err(trf->dev, "%s - write: 0x%x 0x%x, ret: %d\n", __func__, - buf[0], buf[1], ret); + buf[0], buf[1], ret); return ret; } @@ -549,7 +548,7 @@ static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status) if (ret) dev_err(trf->dev, "%s - irqstatus: Status read failed: %d\n", - __func__, ret); + __func__, ret); else *status = buf[0]; @@ -563,12 +562,12 @@ static int trf7970a_read_target_proto(struct trf7970a *trf, u8 *target_proto) u8 addr; addr = TRF79070A_NFC_TARGET_PROTOCOL | TRF7970A_CMD_BIT_RW | - TRF7970A_CMD_BIT_CONTINUOUS; + TRF7970A_CMD_BIT_CONTINUOUS; ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2); if (ret) dev_err(trf->dev, "%s - target_proto: Read failed: %d\n", - __func__, ret); + __func__, ret); else *target_proto = buf[0]; @@ -599,7 +598,7 @@ static int trf7970a_mode_detect(struct trf7970a *trf, u8 *rf_tech) break; default: dev_dbg(trf->dev, "%s - mode_detect: target_proto: 0x%x\n", - __func__, target_proto); + __func__, target_proto); return -EIO; } @@ -615,8 +614,8 @@ static void trf7970a_send_upstream(struct trf7970a *trf) if (trf->rx_skb && !IS_ERR(trf->rx_skb) && !trf->aborting) print_hex_dump_debug("trf7970a rx data: ", DUMP_PREFIX_NONE, - 16, 1, trf->rx_skb->data, trf->rx_skb->len, - false); + 16, 1, trf->rx_skb->data, trf->rx_skb->len, + false); trf->state = TRF7970A_ST_IDLE; @@ -656,7 +655,8 @@ static void trf7970a_send_err_upstream(struct trf7970a *trf, int errno) } static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb, - unsigned int len, u8 *prefix, unsigned int prefix_len) + unsigned int len, u8 *prefix, + unsigned int prefix_len) { struct spi_transfer t[2]; struct spi_message m; @@ -664,7 +664,7 @@ static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb, int ret; print_hex_dump_debug("trf7970a tx data: ", DUMP_PREFIX_NONE, - 16, 1, skb->data, len, false); + 16, 1, skb->data, len, false); spi_message_init(&m); @@ -681,7 +681,7 @@ static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb, ret = spi_sync(trf->spi, &m); if (ret) { dev_err(trf->dev, "%s - Can't send tx data: %d\n", __func__, - ret); + ret); return ret; } @@ -705,7 +705,7 @@ static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb, } dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout, - trf->state); + trf->state); schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout)); @@ -773,9 +773,9 @@ static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status) if (fifo_bytes > skb_tailroom(skb)) { skb = skb_copy_expand(skb, skb_headroom(skb), - max_t(int, fifo_bytes, - TRF7970A_RX_SKB_ALLOC_SIZE), - GFP_KERNEL); + max_t(int, fifo_bytes, + TRF7970A_RX_SKB_ALLOC_SIZE), + GFP_KERNEL); if (!skb) { trf7970a_send_err_upstream(trf, -ENOMEM); return; @@ -786,7 +786,7 @@ static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status) } ret = trf7970a_read_cont(trf, TRF7970A_FIFO_IO_REGISTER, - skb_put(skb, fifo_bytes), fifo_bytes); + skb_put(skb, fifo_bytes), fifo_bytes); if (ret) { trf7970a_send_err_upstream(trf, ret); return; @@ -794,8 +794,7 @@ static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status) /* If received Type 2 ACK/NACK, shift right 4 bits and pass up */ if ((trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T) && (skb->len == 1) && - (trf->special_fcn_reg1 == - TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX)) { + (trf->special_fcn_reg1 == TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX)) { skb->data[0] >>= 4; status = TRF7970A_IRQ_STATUS_SRX; } else { @@ -818,16 +817,16 @@ static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status) } no_rx_data: - if (status == TRF7970A_IRQ_STATUS_SRX) { /* Receive complete */ + if (status == TRF7970A_IRQ_STATUS_SRX) { /* Receive complete */ trf7970a_send_upstream(trf); return; } dev_dbg(trf->dev, "Setting timeout for %d ms\n", - TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT); + TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT); schedule_delayed_work(&trf->timeout_work, - msecs_to_jiffies(TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT)); + msecs_to_jiffies(TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT)); } static irqreturn_t trf7970a_irq(int irq, void *dev_id) @@ -850,7 +849,7 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) } dev_dbg(trf->dev, "IRQ - state: %d, status: 0x%x\n", trf->state, - status); + status); if (!status) { mutex_unlock(&trf->lock); @@ -875,7 +874,7 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) case TRF7970A_ST_WAIT_FOR_TX_FIFO: if (status & TRF7970A_IRQ_STATUS_TX) { trf->ignore_timeout = - !cancel_delayed_work(&trf->timeout_work); + !cancel_delayed_work(&trf->timeout_work); trf7970a_fill_fifo(trf); } else { trf7970a_send_err_upstream(trf, -EIO); @@ -885,11 +884,11 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT: if (status & TRF7970A_IRQ_STATUS_SRX) { trf->ignore_timeout = - !cancel_delayed_work(&trf->timeout_work); + !cancel_delayed_work(&trf->timeout_work); trf7970a_drain_fifo(trf, status); } else if (status & TRF7970A_IRQ_STATUS_FIFO) { ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, - &fifo_bytes); + &fifo_bytes); fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW; @@ -898,14 +897,14 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) else if (!fifo_bytes) trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET); } else if ((status == TRF7970A_IRQ_STATUS_TX) || - (!trf->is_initiator && - (status == (TRF7970A_IRQ_STATUS_TX | - TRF7970A_IRQ_STATUS_NFC_RF)))) { + (!trf->is_initiator && + (status == (TRF7970A_IRQ_STATUS_TX | + TRF7970A_IRQ_STATUS_NFC_RF)))) { trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET); if (!trf->timeout) { - trf->ignore_timeout = !cancel_delayed_work( - &trf->timeout_work); + trf->ignore_timeout = + !cancel_delayed_work(&trf->timeout_work); trf->rx_skb = ERR_PTR(0); trf7970a_send_upstream(trf); break; @@ -929,13 +928,13 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) break; case NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE: ret = trf7970a_write(trf, - TRF7970A_SPECIAL_FCN_REG1, - TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL); + TRF7970A_SPECIAL_FCN_REG1, + TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL); if (ret) goto err_unlock_exit; trf->special_fcn_reg1 = - TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL; + TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL; break; default: break; @@ -943,7 +942,7 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) if (iso_ctrl != trf->iso_ctrl) { ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, - iso_ctrl); + iso_ctrl); if (ret) goto err_unlock_exit; @@ -960,7 +959,7 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) case TRF7970A_ST_LISTENING: if (status & TRF7970A_IRQ_STATUS_SRX) { trf->ignore_timeout = - !cancel_delayed_work(&trf->timeout_work); + !cancel_delayed_work(&trf->timeout_work); trf7970a_drain_fifo(trf, status); } else if (!(status & TRF7970A_IRQ_STATUS_NFC_RF)) { trf7970a_send_err_upstream(trf, -EIO); @@ -969,7 +968,7 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) case TRF7970A_ST_LISTENING_MD: if (status & TRF7970A_IRQ_STATUS_SRX) { trf->ignore_timeout = - !cancel_delayed_work(&trf->timeout_work); + !cancel_delayed_work(&trf->timeout_work); ret = trf7970a_mode_detect(trf, &trf->md_rf_tech); if (ret) { @@ -984,7 +983,7 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) break; default: dev_err(trf->dev, "%s - Driver in invalid state: %d\n", - __func__, trf->state); + __func__, trf->state); } err_unlock_exit: @@ -1009,19 +1008,19 @@ static void trf7970a_issue_eof(struct trf7970a *trf) trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA; dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", - trf->timeout, trf->state); + trf->timeout, trf->state); schedule_delayed_work(&trf->timeout_work, - msecs_to_jiffies(trf->timeout)); + msecs_to_jiffies(trf->timeout)); } static void trf7970a_timeout_work_handler(struct work_struct *work) { struct trf7970a *trf = container_of(work, struct trf7970a, - timeout_work.work); + timeout_work.work); dev_dbg(trf->dev, "Timeout - state: %d, ignore_timeout: %d\n", - trf->state, trf->ignore_timeout); + trf->state, trf->ignore_timeout); mutex_lock(&trf->lock); @@ -1052,7 +1051,7 @@ static int trf7970a_init(struct trf7970a *trf) goto err_out; ret = trf7970a_write(trf, TRF7970A_REG_IO_CTRL, - trf->io_ctrl | TRF7970A_REG_IO_CTRL_VRS(0x1)); + trf->io_ctrl | TRF7970A_REG_IO_CTRL_VRS(0x1)); if (ret) goto err_out; @@ -1065,13 +1064,13 @@ static int trf7970a_init(struct trf7970a *trf) trf->chip_status_ctrl &= ~TRF7970A_CHIP_STATUS_RF_ON; ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL, - trf->modulator_sys_clk_ctrl); + trf->modulator_sys_clk_ctrl); if (ret) goto err_out; ret = trf7970a_write(trf, TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS, - TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 | - TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32); + TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 | + TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32); if (ret) goto err_out; @@ -1092,7 +1091,7 @@ err_out: static void trf7970a_switch_rf_off(struct trf7970a *trf) { if ((trf->state == TRF7970A_ST_PWR_OFF) || - (trf->state == TRF7970A_ST_RF_OFF)) + (trf->state == TRF7970A_ST_RF_OFF)) return; dev_dbg(trf->dev, "Switching rf off\n"); @@ -1116,9 +1115,9 @@ static int trf7970a_switch_rf_on(struct trf7970a *trf) pm_runtime_get_sync(trf->dev); - if (trf->state != TRF7970A_ST_RF_OFF) { /* Power on, RF off */ + if (trf->state != TRF7970A_ST_RF_OFF) { /* Power on, RF off */ dev_err(trf->dev, "%s - Incorrect state: %d\n", __func__, - trf->state); + trf->state); return -EINVAL; } @@ -1153,7 +1152,7 @@ static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on) break; default: dev_err(trf->dev, "%s - Invalid request: %d %d\n", - __func__, trf->state, on); + __func__, trf->state, on); trf7970a_switch_rf_off(trf); ret = -EINVAL; } @@ -1164,7 +1163,7 @@ static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on) break; default: dev_err(trf->dev, "%s - Invalid request: %d %d\n", - __func__, trf->state, on); + __func__, trf->state, on); ret = -EINVAL; /* FALLTHROUGH */ case TRF7970A_ST_IDLE: @@ -1189,36 +1188,36 @@ static int trf7970a_in_config_rf_tech(struct trf7970a *trf, int tech) case NFC_DIGITAL_RF_TECH_106A: trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_14443A_106; trf->modulator_sys_clk_ctrl = - (trf->modulator_sys_clk_ctrl & 0xf8) | - TRF7970A_MODULATOR_DEPTH_OOK; + (trf->modulator_sys_clk_ctrl & 0xf8) | + TRF7970A_MODULATOR_DEPTH_OOK; trf->guard_time = TRF7970A_GUARD_TIME_NFCA; break; case NFC_DIGITAL_RF_TECH_106B: trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_14443B_106; trf->modulator_sys_clk_ctrl = - (trf->modulator_sys_clk_ctrl & 0xf8) | - TRF7970A_MODULATOR_DEPTH_ASK10; + (trf->modulator_sys_clk_ctrl & 0xf8) | + TRF7970A_MODULATOR_DEPTH_ASK10; trf->guard_time = TRF7970A_GUARD_TIME_NFCB; break; case NFC_DIGITAL_RF_TECH_212F: trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_FELICA_212; trf->modulator_sys_clk_ctrl = - (trf->modulator_sys_clk_ctrl & 0xf8) | - TRF7970A_MODULATOR_DEPTH_ASK10; + (trf->modulator_sys_clk_ctrl & 0xf8) | + TRF7970A_MODULATOR_DEPTH_ASK10; trf->guard_time = TRF7970A_GUARD_TIME_NFCF; break; case NFC_DIGITAL_RF_TECH_424F: trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_FELICA_424; trf->modulator_sys_clk_ctrl = - (trf->modulator_sys_clk_ctrl & 0xf8) | - TRF7970A_MODULATOR_DEPTH_ASK10; + (trf->modulator_sys_clk_ctrl & 0xf8) | + TRF7970A_MODULATOR_DEPTH_ASK10; trf->guard_time = TRF7970A_GUARD_TIME_NFCF; break; case NFC_DIGITAL_RF_TECH_ISO15693: trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648; trf->modulator_sys_clk_ctrl = - (trf->modulator_sys_clk_ctrl & 0xf8) | - TRF7970A_MODULATOR_DEPTH_OOK; + (trf->modulator_sys_clk_ctrl & 0xf8) | + TRF7970A_MODULATOR_DEPTH_OOK; trf->guard_time = TRF7970A_GUARD_TIME_15693; break; default: @@ -1245,7 +1244,8 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) u8 rssi; ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL, - trf->chip_status_ctrl | TRF7970A_CHIP_STATUS_REC_ON); + trf->chip_status_ctrl | + TRF7970A_CHIP_STATUS_REC_ON); if (ret) return ret; @@ -1260,7 +1260,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) return ret; ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL, - trf->chip_status_ctrl); + trf->chip_status_ctrl); if (ret) return ret; @@ -1327,15 +1327,15 @@ static int trf7970a_in_config_framing(struct trf7970a *trf, int framing) trf->iso_ctrl = iso_ctrl; ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL, - trf->modulator_sys_clk_ctrl); + trf->modulator_sys_clk_ctrl); if (ret) return ret; } if (!(trf->chip_status_ctrl & TRF7970A_CHIP_STATUS_RF_ON)) { ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL, - trf->chip_status_ctrl | - TRF7970A_CHIP_STATUS_RF_ON); + trf->chip_status_ctrl | + TRF7970A_CHIP_STATUS_RF_ON); if (ret) return ret; @@ -1348,7 +1348,7 @@ static int trf7970a_in_config_framing(struct trf7970a *trf, int framing) } static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type, - int param) + int param) { struct trf7970a *trf = nfc_digital_get_drvdata(ddev); int ret; @@ -1360,7 +1360,7 @@ static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type, trf->is_initiator = true; if ((trf->state == TRF7970A_ST_PWR_OFF) || - (trf->state == TRF7970A_ST_RF_OFF)) { + (trf->state == TRF7970A_ST_RF_OFF)) { ret = trf7970a_switch_rf_on(trf); if (ret) goto err_unlock; @@ -1418,7 +1418,7 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) * has to send an EOF in order to get a response. */ if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) && - (trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) { + (trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) { if (req[0] == NFC_T2T_CMD_READ) special_fcn_reg1 = 0; else @@ -1426,7 +1426,7 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) if (special_fcn_reg1 != trf->special_fcn_reg1) { ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1, - special_fcn_reg1); + special_fcn_reg1); if (ret) return ret; @@ -1446,7 +1446,7 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648; break; case (ISO15693_REQ_FLAG_SUB_CARRIER | - ISO15693_REQ_FLAG_DATA_RATE): + ISO15693_REQ_FLAG_DATA_RATE): iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669; break; } @@ -1461,10 +1461,10 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) if (trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) { if (trf7970a_is_iso15693_write_or_lock(req[1]) && - (req[0] & ISO15693_REQ_FLAG_OPTION)) + (req[0] & ISO15693_REQ_FLAG_OPTION)) trf->issue_eof = true; else if ((trf->quirks & - TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE) && + TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE) && (req[1] == ISO15693_CMD_READ_MULTIPLE_BLOCK)) trf->adjust_resp_len = true; } @@ -1474,8 +1474,8 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) } static int trf7970a_send_cmd(struct nfc_digital_dev *ddev, - struct sk_buff *skb, u16 timeout, - nfc_digital_cmd_complete_t cb, void *arg) + struct sk_buff *skb, u16 timeout, + nfc_digital_cmd_complete_t cb, void *arg) { struct trf7970a *trf = nfc_digital_get_drvdata(ddev); u8 prefix[5]; @@ -1484,7 +1484,7 @@ static int trf7970a_send_cmd(struct nfc_digital_dev *ddev, u8 status; dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n", - trf->state, timeout, skb->len); + trf->state, timeout, skb->len); if (skb->len > TRF7970A_TX_MAX) return -EINVAL; @@ -1492,9 +1492,9 @@ static int trf7970a_send_cmd(struct nfc_digital_dev *ddev, mutex_lock(&trf->lock); if ((trf->state != TRF7970A_ST_IDLE) && - (trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) { + (trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) { dev_err(trf->dev, "%s - Bogus state: %d\n", __func__, - trf->state); + trf->state); ret = -EIO; goto out_err; } @@ -1508,7 +1508,7 @@ static int trf7970a_send_cmd(struct nfc_digital_dev *ddev, if (timeout) { trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE, - GFP_KERNEL); + GFP_KERNEL); if (!trf->rx_skb) { dev_dbg(trf->dev, "Can't alloc rx_skb\n"); ret = -ENOMEM; @@ -1545,14 +1545,14 @@ static int trf7970a_send_cmd(struct nfc_digital_dev *ddev, * That totals 5 bytes. */ prefix[0] = TRF7970A_CMD_BIT_CTRL | - TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET); + TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET); prefix[1] = TRF7970A_CMD_BIT_CTRL | - TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd); + TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd); prefix[2] = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_TX_LENGTH_BYTE1; if (trf->framing == NFC_DIGITAL_FRAMING_NFCA_SHORT) { prefix[3] = 0x00; - prefix[4] = 0x0f; /* 7 bits */ + prefix[4] = 0x0f; /* 7 bits */ } else { prefix[3] = (len & 0xf00) >> 4; prefix[3] |= ((len & 0xf0) >> 4); @@ -1586,25 +1586,24 @@ static int trf7970a_tg_config_rf_tech(struct trf7970a *trf, int tech) switch (tech) { case NFC_DIGITAL_RF_TECH_106A: trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE | - TRF7970A_ISO_CTRL_NFC_CE | - TRF7970A_ISO_CTRL_NFC_CE_14443A; + TRF7970A_ISO_CTRL_NFC_CE | TRF7970A_ISO_CTRL_NFC_CE_14443A; trf->modulator_sys_clk_ctrl = - (trf->modulator_sys_clk_ctrl & 0xf8) | - TRF7970A_MODULATOR_DEPTH_OOK; + (trf->modulator_sys_clk_ctrl & 0xf8) | + TRF7970A_MODULATOR_DEPTH_OOK; break; case NFC_DIGITAL_RF_TECH_212F: trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE | - TRF7970A_ISO_CTRL_NFC_NFCF_212; + TRF7970A_ISO_CTRL_NFC_NFCF_212; trf->modulator_sys_clk_ctrl = - (trf->modulator_sys_clk_ctrl & 0xf8) | - TRF7970A_MODULATOR_DEPTH_ASK10; + (trf->modulator_sys_clk_ctrl & 0xf8) | + TRF7970A_MODULATOR_DEPTH_ASK10; break; case NFC_DIGITAL_RF_TECH_424F: trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE | - TRF7970A_ISO_CTRL_NFC_NFCF_424; + TRF7970A_ISO_CTRL_NFC_NFCF_424; trf->modulator_sys_clk_ctrl = - (trf->modulator_sys_clk_ctrl & 0xf8) | - TRF7970A_MODULATOR_DEPTH_ASK10; + (trf->modulator_sys_clk_ctrl & 0xf8) | + TRF7970A_MODULATOR_DEPTH_ASK10; break; default: dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech); @@ -1621,9 +1620,9 @@ static int trf7970a_tg_config_rf_tech(struct trf7970a *trf, int tech) * here. */ if ((trf->framing == NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED) && - (trf->iso_ctrl_tech != trf->iso_ctrl)) { + (trf->iso_ctrl_tech != trf->iso_ctrl)) { ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, - trf->iso_ctrl_tech); + trf->iso_ctrl_tech); trf->iso_ctrl = trf->iso_ctrl_tech; } @@ -1678,15 +1677,15 @@ static int trf7970a_tg_config_framing(struct trf7970a *trf, int framing) trf->iso_ctrl = iso_ctrl; ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL, - trf->modulator_sys_clk_ctrl); + trf->modulator_sys_clk_ctrl); if (ret) return ret; } if (!(trf->chip_status_ctrl & TRF7970A_CHIP_STATUS_RF_ON)) { ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL, - trf->chip_status_ctrl | - TRF7970A_CHIP_STATUS_RF_ON); + trf->chip_status_ctrl | + TRF7970A_CHIP_STATUS_RF_ON); if (ret) return ret; @@ -1697,7 +1696,7 @@ static int trf7970a_tg_config_framing(struct trf7970a *trf, int framing) } static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev, int type, - int param) + int param) { struct trf7970a *trf = nfc_digital_get_drvdata(ddev); int ret; @@ -1709,7 +1708,7 @@ static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev, int type, trf->is_initiator = false; if ((trf->state == TRF7970A_ST_PWR_OFF) || - (trf->state == TRF7970A_ST_RF_OFF)) { + (trf->state == TRF7970A_ST_RF_OFF)) { ret = trf7970a_switch_rf_on(trf); if (ret) goto err_unlock; @@ -1733,7 +1732,8 @@ err_unlock: } static int _trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, - nfc_digital_cmd_complete_t cb, void *arg, bool mode_detect) + nfc_digital_cmd_complete_t cb, void *arg, + bool mode_detect) { struct trf7970a *trf = nfc_digital_get_drvdata(ddev); int ret; @@ -1741,9 +1741,9 @@ static int _trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, mutex_lock(&trf->lock); if ((trf->state != TRF7970A_ST_IDLE) && - (trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) { + (trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) { dev_err(trf->dev, "%s - Bogus state: %d\n", __func__, - trf->state); + trf->state); ret = -EIO; goto out_err; } @@ -1756,7 +1756,7 @@ static int _trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, } trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE, - GFP_KERNEL); + GFP_KERNEL); if (!trf->rx_skb) { dev_dbg(trf->dev, "Can't alloc rx_skb\n"); ret = -ENOMEM; @@ -1764,25 +1764,25 @@ static int _trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, } ret = trf7970a_write(trf, TRF7970A_RX_SPECIAL_SETTINGS, - TRF7970A_RX_SPECIAL_SETTINGS_HBT | - TRF7970A_RX_SPECIAL_SETTINGS_M848 | - TRF7970A_RX_SPECIAL_SETTINGS_C424 | - TRF7970A_RX_SPECIAL_SETTINGS_C212); + TRF7970A_RX_SPECIAL_SETTINGS_HBT | + TRF7970A_RX_SPECIAL_SETTINGS_M848 | + TRF7970A_RX_SPECIAL_SETTINGS_C424 | + TRF7970A_RX_SPECIAL_SETTINGS_C212); if (ret) goto out_err; ret = trf7970a_write(trf, TRF7970A_REG_IO_CTRL, - trf->io_ctrl | TRF7970A_REG_IO_CTRL_VRS(0x1)); + trf->io_ctrl | TRF7970A_REG_IO_CTRL_VRS(0x1)); if (ret) goto out_err; ret = trf7970a_write(trf, TRF7970A_NFC_LOW_FIELD_LEVEL, - TRF7970A_NFC_LOW_FIELD_LEVEL_RFDET(0x3)); + TRF7970A_NFC_LOW_FIELD_LEVEL_RFDET(0x3)); if (ret) goto out_err; ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL, - TRF7970A_NFC_TARGET_LEVEL_RFDET(0x7)); + TRF7970A_NFC_TARGET_LEVEL_RFDET(0x7)); if (ret) goto out_err; @@ -1807,32 +1807,33 @@ out_err: } static int trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, - nfc_digital_cmd_complete_t cb, void *arg) + nfc_digital_cmd_complete_t cb, void *arg) { struct trf7970a *trf = nfc_digital_get_drvdata(ddev); dev_dbg(trf->dev, "Listen - state: %d, timeout: %d ms\n", - trf->state, timeout); + trf->state, timeout); return _trf7970a_tg_listen(ddev, timeout, cb, arg, false); } static int trf7970a_tg_listen_md(struct nfc_digital_dev *ddev, - u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) + u16 timeout, nfc_digital_cmd_complete_t cb, + void *arg) { struct trf7970a *trf = nfc_digital_get_drvdata(ddev); int ret; dev_dbg(trf->dev, "Listen MD - state: %d, timeout: %d ms\n", - trf->state, timeout); + trf->state, timeout); ret = trf7970a_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, - NFC_DIGITAL_RF_TECH_106A); + NFC_DIGITAL_RF_TECH_106A); if (ret) return ret; ret = trf7970a_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, - NFC_DIGITAL_FRAMING_NFCA_NFC_DEP); + NFC_DIGITAL_FRAMING_NFCA_NFC_DEP); if (ret) return ret; @@ -1844,7 +1845,7 @@ static int trf7970a_tg_get_rf_tech(struct nfc_digital_dev *ddev, u8 *rf_tech) struct trf7970a *trf = nfc_digital_get_drvdata(ddev); dev_dbg(trf->dev, "Get RF Tech - state: %d, rf_tech: %d\n", - trf->state, trf->md_rf_tech); + trf->state, trf->md_rf_tech); *rf_tech = trf->md_rf_tech; @@ -1933,20 +1934,19 @@ static int trf7970a_power_down(struct trf7970a *trf) if (trf->state != TRF7970A_ST_RF_OFF) { dev_dbg(trf->dev, "Can't power down - not RF_OFF state (%d)\n", - trf->state); + trf->state); return -EBUSY; } gpiod_set_value_cansleep(trf->en_gpiod, 0); - if (trf->en2_gpiod && - !(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) + if (trf->en2_gpiod && !(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) gpiod_set_value_cansleep(trf->en2_gpiod, 0); ret = regulator_disable(trf->regulator); if (ret) dev_err(trf->dev, "%s - Can't disable VIN: %d\n", __func__, - ret); + ret); trf->state = TRF7970A_ST_PWR_OFF; @@ -2060,16 +2060,16 @@ static int trf7970a_probe(struct spi_device *spi) of_property_read_u32(np, "clock-frequency", &clk_freq); if ((clk_freq != TRF7970A_27MHZ_CLOCK_FREQUENCY) || - (clk_freq != TRF7970A_13MHZ_CLOCK_FREQUENCY)) { + (clk_freq != TRF7970A_13MHZ_CLOCK_FREQUENCY)) { dev_err(trf->dev, - "clock-frequency (%u Hz) unsupported\n", - clk_freq); + "clock-frequency (%u Hz) unsupported\n", clk_freq); return -EINVAL; } ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL, - trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "trf7970a", trf); + trf7970a_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "trf7970a", trf); if (ret) { dev_err(trf->dev, "Can't request IRQ#%d: %d\n", spi->irq, ret); return ret; @@ -2114,9 +2114,10 @@ static int trf7970a_probe(struct spi_device *spi) } trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops, - TRF7970A_SUPPORTED_PROTOCOLS, - NFC_DIGITAL_DRV_CAPS_IN_CRC | - NFC_DIGITAL_DRV_CAPS_TG_CRC, 0, 0); + TRF7970A_SUPPORTED_PROTOCOLS, + NFC_DIGITAL_DRV_CAPS_IN_CRC | + NFC_DIGITAL_DRV_CAPS_TG_CRC, 0, + 0); if (!trf->ddev) { dev_err(trf->dev, "Can't allocate NFC digital device\n"); ret = -ENOMEM; @@ -2139,7 +2140,7 @@ static int trf7970a_probe(struct spi_device *spi) ret = nfc_digital_register_device(trf->ddev); if (ret) { dev_err(trf->dev, "Can't register NFC digital device: %d\n", - ret); + ret); goto err_shutdown; } @@ -2248,29 +2249,31 @@ static int trf7970a_pm_runtime_resume(struct device *dev) static const struct dev_pm_ops trf7970a_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(trf7970a_suspend, trf7970a_resume) SET_RUNTIME_PM_OPS(trf7970a_pm_runtime_suspend, - trf7970a_pm_runtime_resume, NULL) + trf7970a_pm_runtime_resume, NULL) }; static const struct of_device_id trf7970a_of_match[] = { - { .compatible = "ti,trf7970a", }, + {.compatible = "ti,trf7970a",}, {}, }; + MODULE_DEVICE_TABLE(of, trf7970a_of_match); static const struct spi_device_id trf7970a_id_table[] = { - { "trf7970a", 0 }, - { } + {"trf7970a", 0}, + {} }; + MODULE_DEVICE_TABLE(spi, trf7970a_id_table); static struct spi_driver trf7970a_spi_driver = { .probe = trf7970a_probe, .remove = trf7970a_remove, .id_table = trf7970a_id_table, - .driver = { - .name = "trf7970a", - .of_match_table = of_match_ptr(trf7970a_of_match), - .pm = &trf7970a_pm_ops, + .driver = { + .name = "trf7970a", + .of_match_table = of_match_ptr(trf7970a_of_match), + .pm = &trf7970a_pm_ops, }, }; -- cgit v1.2.3 From 15e0c59f1535926a939d1df66d6edcf997d7c1b9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Mar 2017 12:15:36 +0200 Subject: NFC: nfcmrvl_uart: add missing tty-device sanity check Make sure to check the tty-device pointer before trying to access the parent device to avoid dereferencing a NULL-pointer when the tty is one end of a Unix98 pty. Fixes: e097dc624f78 ("NFC: nfcmrvl: add UART driver") Cc: stable # 4.2 Cc: Vincent Cuissard Signed-off-by: Johan Hovold Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcmrvl/uart.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c index 83a99e38e7bd..6c0c301611c4 100644 --- a/drivers/nfc/nfcmrvl/uart.c +++ b/drivers/nfc/nfcmrvl/uart.c @@ -109,6 +109,7 @@ static int nfcmrvl_nci_uart_open(struct nci_uart *nu) struct nfcmrvl_private *priv; struct nfcmrvl_platform_data *pdata = NULL; struct nfcmrvl_platform_data config; + struct device *dev = nu->tty->dev; /* * Platform data cannot be used here since usually it is already used @@ -116,9 +117,8 @@ static int nfcmrvl_nci_uart_open(struct nci_uart *nu) * and check if DT entries were added. */ - if (nu->tty->dev->parent && nu->tty->dev->parent->of_node) - if (nfcmrvl_uart_parse_dt(nu->tty->dev->parent->of_node, - &config) == 0) + if (dev && dev->parent && dev->parent->of_node) + if (nfcmrvl_uart_parse_dt(dev->parent->of_node, &config) == 0) pdata = &config; if (!pdata) { @@ -131,7 +131,7 @@ static int nfcmrvl_nci_uart_open(struct nci_uart *nu) } priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_UART, nu, &uart_ops, - nu->tty->dev, pdata); + dev, pdata); if (IS_ERR(priv)) return PTR_ERR(priv); -- cgit v1.2.3 From 0cbe40112f42cf5e008f9127f6cd5952ba3946c7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Mar 2017 12:15:37 +0200 Subject: NFC: nfcmrvl: do not use device-managed resources This specifically fixes resource leaks in the registration error paths. Device-managed resources is a bad fit for this driver as devices can be registered from the n_nci line discipline. Firstly, a tty may not even have a corresponding device (should it be part of a Unix98 pty) something which would lead to a NULL-pointer dereference when registering resources. Secondly, if the tty has a class device, its lifetime exceeds that of the line discipline, which means that resources would leak every time the line discipline is closed (or if registration fails). Currently, the devres interface was only being used to request a reset gpio despite the fact that it was already explicitly freed in nfcmrvl_nci_unregister_dev() (along with the private data), something which also prevented the resource leak at close. Note that the driver treats gpio number 0 as invalid despite it being perfectly valid. This will be addressed in a follow-up patch. Fixes: b2fe288eac72 ("NFC: nfcmrvl: free reset gpio") Fixes: 4a2b947f56b3 ("NFC: nfcmrvl: add chip reset management") Cc: stable # 4.2: b2fe288eac72 Cc: Vincent Cuissard Signed-off-by: Johan Hovold Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcmrvl/main.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c index c5038e6447bd..968da1901e85 100644 --- a/drivers/nfc/nfcmrvl/main.c +++ b/drivers/nfc/nfcmrvl/main.c @@ -124,12 +124,13 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(enum nfcmrvl_phy phy, memcpy(&priv->config, pdata, sizeof(*pdata)); if (priv->config.reset_n_io) { - rc = devm_gpio_request_one(dev, - priv->config.reset_n_io, - GPIOF_OUT_INIT_LOW, - "nfcmrvl_reset_n"); - if (rc < 0) + rc = gpio_request_one(priv->config.reset_n_io, + GPIOF_OUT_INIT_LOW, + "nfcmrvl_reset_n"); + if (rc < 0) { + priv->config.reset_n_io = 0; nfc_err(dev, "failed to request reset_n io\n"); + } } if (phy == NFCMRVL_PHY_SPI) { @@ -154,7 +155,7 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(enum nfcmrvl_phy phy, if (!priv->ndev) { nfc_err(dev, "nci_allocate_device failed\n"); rc = -ENOMEM; - goto error; + goto error_free_gpio; } nci_set_drvdata(priv->ndev, priv); @@ -179,7 +180,9 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(enum nfcmrvl_phy phy, error_free_dev: nci_free_device(priv->ndev); -error: +error_free_gpio: + if (priv->config.reset_n_io) + gpio_free(priv->config.reset_n_io); kfree(priv); return ERR_PTR(rc); } @@ -195,7 +198,7 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv) nfcmrvl_fw_dnld_deinit(priv); if (priv->config.reset_n_io) - devm_gpio_free(priv->dev, priv->config.reset_n_io); + gpio_free(priv->config.reset_n_io); nci_unregister_device(ndev); nci_free_device(ndev); -- cgit v1.2.3 From e5834ac22948169bbd7c45996d8d4905edd20f5e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Mar 2017 12:15:38 +0200 Subject: NFC: nfcmrvl: use nfc-device for firmware download Use the nfc- rather than phy-device in firmware-management code that needs a valid struct device. This specifically fixes a NULL-pointer dereference in nfcmrvl_fw_dnld_init() during registration when the underlying tty is one end of a Unix98 pty. Note that the driver still uses the phy device for any debugging, which is fine for now. Fixes: 3194c6870158 ("NFC: nfcmrvl: add firmware download support") Cc: stable # 4.4 Cc: Vincent Cuissard Signed-off-by: Johan Hovold Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcmrvl/fw_dnld.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c index f9f000c546d1..7f8960a46aab 100644 --- a/drivers/nfc/nfcmrvl/fw_dnld.c +++ b/drivers/nfc/nfcmrvl/fw_dnld.c @@ -457,7 +457,7 @@ int nfcmrvl_fw_dnld_init(struct nfcmrvl_private *priv) INIT_WORK(&priv->fw_dnld.rx_work, fw_dnld_rx_work); snprintf(name, sizeof(name), "%s_nfcmrvl_fw_dnld_rx_wq", - dev_name(priv->dev)); + dev_name(&priv->ndev->nfc_dev->dev)); priv->fw_dnld.rx_wq = create_singlethread_workqueue(name); if (!priv->fw_dnld.rx_wq) return -ENOMEM; @@ -494,6 +494,7 @@ int nfcmrvl_fw_dnld_start(struct nci_dev *ndev, const char *firmware_name) { struct nfcmrvl_private *priv = nci_get_drvdata(ndev); struct nfcmrvl_fw_dnld *fw_dnld = &priv->fw_dnld; + int res; if (!priv->support_fw_dnld) return -ENOTSUPP; @@ -509,7 +510,9 @@ int nfcmrvl_fw_dnld_start(struct nci_dev *ndev, const char *firmware_name) */ /* Retrieve FW binary */ - if (request_firmware(&fw_dnld->fw, firmware_name, priv->dev) < 0) { + res = request_firmware(&fw_dnld->fw, firmware_name, + &ndev->nfc_dev->dev); + if (res < 0) { nfc_err(priv->dev, "failed to retrieve FW %s", firmware_name); return -ENOENT; } -- cgit v1.2.3 From 45dd39b974f6632222dd5cdcbea7358a077ab0b0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Mar 2017 12:15:39 +0200 Subject: NFC: nfcmrvl: fix firmware-management initialisation The nci-device was never deregistered in the event that fw-initialisation failed. Fix this by moving the firmware initialisation before device registration since the firmware work queue should be available before registering. Note that this depends on a recent fix that moved device-name initialisation back to to nci_allocate_device() as the firmware-workqueue name is now derived from the nfc-device name. Fixes: 3194c6870158 ("NFC: nfcmrvl: add firmware download support") Cc: stable # 4.4 Cc: Vincent Cuissard Signed-off-by: Johan Hovold Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcmrvl/main.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c index 968da1901e85..a5faa604a3b4 100644 --- a/drivers/nfc/nfcmrvl/main.c +++ b/drivers/nfc/nfcmrvl/main.c @@ -158,26 +158,28 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(enum nfcmrvl_phy phy, goto error_free_gpio; } + rc = nfcmrvl_fw_dnld_init(priv); + if (rc) { + nfc_err(dev, "failed to initialize FW download %d\n", rc); + goto error_free_dev; + } + nci_set_drvdata(priv->ndev, priv); rc = nci_register_device(priv->ndev); if (rc) { nfc_err(dev, "nci_register_device failed %d\n", rc); - goto error_free_dev; + goto error_fw_dnld_deinit; } /* Ensure that controller is powered off */ nfcmrvl_chip_halt(priv); - rc = nfcmrvl_fw_dnld_init(priv); - if (rc) { - nfc_err(dev, "failed to initialize FW download %d\n", rc); - goto error_free_dev; - } - nfc_info(dev, "registered with nci successfully\n"); return priv; +error_fw_dnld_deinit: + nfcmrvl_fw_dnld_deinit(priv); error_free_dev: nci_free_device(priv->ndev); error_free_gpio: -- cgit v1.2.3 From d0607aa4aee88cb097b694caa619e68f1e0a39c6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Mar 2017 12:15:40 +0200 Subject: NFC: nfcmrvl_uart: fix device-node leak during probe Make sure to release the device-node reference when done parsing the node. Fixes: e097dc624f78 ("NFC: nfcmrvl: add UART driver") Cc: Vincent Cuissard Signed-off-by: Johan Hovold Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcmrvl/uart.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c index 6c0c301611c4..91162f8e0366 100644 --- a/drivers/nfc/nfcmrvl/uart.c +++ b/drivers/nfc/nfcmrvl/uart.c @@ -84,6 +84,7 @@ static int nfcmrvl_uart_parse_dt(struct device_node *node, ret = nfcmrvl_parse_dt(matched_node, pdata); if (ret < 0) { pr_err("Failed to get generic entries\n"); + of_node_put(matched_node); return ret; } @@ -97,6 +98,8 @@ static int nfcmrvl_uart_parse_dt(struct device_node *node, else pdata->break_control = 0; + of_node_put(matched_node); + return 0; } -- cgit v1.2.3 From 0d1ca88bbfdfdad4f6fc0421da5e4ea9a13a0d42 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Mar 2017 12:15:41 +0200 Subject: NFC: nfcmrvl_usb: use interface as phy device Use the USB-interface rather than parent USB-device device, which is what this driver binds to, when registering the nci device. Note that using the right device is important when dealing with device- managed resources as the interface can be unbound independently of the parent device. Also note that private device pointer had already been set by nfcmrvl_nci_register_dev() so the redundant assignment can therefore be removed. Signed-off-by: Johan Hovold Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcmrvl/usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c index 699aa9d16575..bd35eab652be 100644 --- a/drivers/nfc/nfcmrvl/usb.c +++ b/drivers/nfc/nfcmrvl/usb.c @@ -341,15 +341,13 @@ static int nfcmrvl_probe(struct usb_interface *intf, init_usb_anchor(&drv_data->deferred); priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_USB, drv_data, &usb_ops, - &drv_data->udev->dev, &config); + &intf->dev, &config); if (IS_ERR(priv)) return PTR_ERR(priv); drv_data->priv = priv; drv_data->priv->support_fw_dnld = false; - priv->dev = &drv_data->udev->dev; - usb_set_intfdata(intf, drv_data); return 0; -- cgit v1.2.3 From e33a3f84f88f13eab6a45c5230c9b9ee9ac78e60 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Mar 2017 12:15:42 +0200 Subject: NFC: nfcmrvl: allow gpio 0 for reset signalling Allow gpio 0 to be used for reset signalling, and instead use negative errnos to disable the reset functionality. Signed-off-by: Johan Hovold Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcmrvl/main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c index a5faa604a3b4..e65d027b91fa 100644 --- a/drivers/nfc/nfcmrvl/main.c +++ b/drivers/nfc/nfcmrvl/main.c @@ -123,12 +123,12 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(enum nfcmrvl_phy phy, memcpy(&priv->config, pdata, sizeof(*pdata)); - if (priv->config.reset_n_io) { + if (gpio_is_valid(priv->config.reset_n_io)) { rc = gpio_request_one(priv->config.reset_n_io, GPIOF_OUT_INIT_LOW, "nfcmrvl_reset_n"); if (rc < 0) { - priv->config.reset_n_io = 0; + priv->config.reset_n_io = -EINVAL; nfc_err(dev, "failed to request reset_n io\n"); } } @@ -183,7 +183,7 @@ error_fw_dnld_deinit: error_free_dev: nci_free_device(priv->ndev); error_free_gpio: - if (priv->config.reset_n_io) + if (gpio_is_valid(priv->config.reset_n_io)) gpio_free(priv->config.reset_n_io); kfree(priv); return ERR_PTR(rc); @@ -199,7 +199,7 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv) nfcmrvl_fw_dnld_deinit(priv); - if (priv->config.reset_n_io) + if (gpio_is_valid(priv->config.reset_n_io)) gpio_free(priv->config.reset_n_io); nci_unregister_device(ndev); @@ -267,7 +267,6 @@ int nfcmrvl_parse_dt(struct device_node *node, reset_n_io = of_get_named_gpio(node, "reset-n-io", 0); if (reset_n_io < 0) { pr_info("no reset-n-io config\n"); - reset_n_io = 0; } else if (!gpio_is_valid(reset_n_io)) { pr_err("invalid reset-n-io GPIO\n"); return reset_n_io; -- cgit v1.2.3 From 836d57e5c08e13bb206dcd559d96ee9355e8316e Mon Sep 17 00:00:00 2001 From: Prasad Kanneganti Date: Sun, 18 Jun 2017 12:41:34 -0700 Subject: liquidio: implement vlan filter enable and disable Add implementation to support ethtool -K ethX rx-vlan-filter on/off. Rename OCTNET_CMD_ENABLE_VLAN_FILTER command to OCTNET_CMD_VLAN_FILTER_CTL and add OCTNET_CMD_VLAN_FILTER_ENABLE and OCTNET_CMD_VLAN_FILTER_DISABLE parameters so that it can be used to enable or disable the filter. Signed-off-by: Prasad Kanneganti Signed-off-by: Derek Chickles Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_core.c | 10 +++++--- drivers/net/ethernet/cavium/liquidio/lio_main.c | 28 +++++++++++++++++----- .../net/ethernet/cavium/liquidio/liquidio_common.h | 4 +++- 3 files changed, 32 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 796c2cbc11f6..adde7745d069 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -202,9 +202,13 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr) netdev->name); break; - case OCTNET_CMD_ENABLE_VLAN_FILTER: - dev_info(&oct->pci_dev->dev, "%s VLAN filter enabled\n", - netdev->name); + case OCTNET_CMD_VLAN_FILTER_CTL: + if (nctrl->ncmd.s.param1) + dev_info(&oct->pci_dev->dev, + "%s VLAN filter enabled\n", netdev->name); + else + dev_info(&oct->pci_dev->dev, + "%s VLAN filter disabled\n", netdev->name); break; case OCTNET_CMD_ADD_VLAN_FILTER: diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index ba012427edd6..17f963b7f819 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -3591,6 +3591,10 @@ static netdev_features_t liquidio_fix_features(struct net_device *netdev, (lio->dev_capability & NETIF_F_LRO)) request &= ~NETIF_F_LRO; + if ((request & NETIF_F_HW_VLAN_CTAG_FILTER) && + !(lio->dev_capability & NETIF_F_HW_VLAN_CTAG_FILTER)) + request &= ~NETIF_F_HW_VLAN_CTAG_FILTER; + return request; } @@ -3603,14 +3607,14 @@ static int liquidio_set_features(struct net_device *netdev, { struct lio *lio = netdev_priv(netdev); - if (!((netdev->features ^ features) & NETIF_F_LRO)) - return 0; - - if ((features & NETIF_F_LRO) && (lio->dev_capability & NETIF_F_LRO)) + if ((features & NETIF_F_LRO) && + (lio->dev_capability & NETIF_F_LRO) && + !(netdev->features & NETIF_F_LRO)) liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE, OCTNIC_LROIPV4 | OCTNIC_LROIPV6); else if (!(features & NETIF_F_LRO) && - (lio->dev_capability & NETIF_F_LRO)) + (lio->dev_capability & NETIF_F_LRO) && + (netdev->features & NETIF_F_LRO)) liquidio_set_feature(netdev, OCTNET_CMD_LRO_DISABLE, OCTNIC_LROIPV4 | OCTNIC_LROIPV6); @@ -3629,6 +3633,17 @@ static int liquidio_set_features(struct net_device *netdev, liquidio_set_rxcsum_command(netdev, OCTNET_CMD_TNL_RX_CSUM_CTL, OCTNET_CMD_RXCSUM_DISABLE); + if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) && + (lio->dev_capability & NETIF_F_HW_VLAN_CTAG_FILTER) && + !(netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) + liquidio_set_feature(netdev, OCTNET_CMD_VLAN_FILTER_CTL, + OCTNET_CMD_VLAN_FILTER_ENABLE); + else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) && + (lio->dev_capability & NETIF_F_HW_VLAN_CTAG_FILTER) && + (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) + liquidio_set_feature(netdev, OCTNET_CMD_VLAN_FILTER_CTL, + OCTNET_CMD_VLAN_FILTER_DISABLE); + return 0; } @@ -4199,7 +4214,8 @@ static int setup_nic_devices(struct octeon_device *octeon_dev) liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE, OCTNIC_LROIPV4 | OCTNIC_LROIPV6); - liquidio_set_feature(netdev, OCTNET_CMD_ENABLE_VLAN_FILTER, 0); + liquidio_set_feature(netdev, OCTNET_CMD_VLAN_FILTER_CTL, + OCTNET_CMD_VLAN_FILTER_ENABLE); if ((debug != -1) && (debug & NETIF_MSG_HW)) liquidio_set_feature(netdev, diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h index 8ea2323d8d67..d03f5296f33e 100644 --- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h +++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h @@ -215,7 +215,7 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, #define OCTNET_CMD_VERBOSE_ENABLE 0x14 #define OCTNET_CMD_VERBOSE_DISABLE 0x15 -#define OCTNET_CMD_ENABLE_VLAN_FILTER 0x16 +#define OCTNET_CMD_VLAN_FILTER_CTL 0x16 #define OCTNET_CMD_ADD_VLAN_FILTER 0x17 #define OCTNET_CMD_DEL_VLAN_FILTER 0x18 #define OCTNET_CMD_VXLAN_PORT_CONFIG 0x19 @@ -230,6 +230,8 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, #define OCTNET_CMD_RXCSUM_DISABLE 0x1 #define OCTNET_CMD_TXCSUM_ENABLE 0x0 #define OCTNET_CMD_TXCSUM_DISABLE 0x1 +#define OCTNET_CMD_VLAN_FILTER_ENABLE 0x1 +#define OCTNET_CMD_VLAN_FILTER_DISABLE 0x0 /* RX(packets coming from wire) Checksum verification flags */ /* TCP/UDP csum */ -- cgit v1.2.3 From 47b3e2f701b93c57abcb3ba1f9f2041abd6b9147 Mon Sep 17 00:00:00 2001 From: Christos Gkekas Date: Sun, 18 Jun 2017 16:41:40 +0100 Subject: pptp: Remove unused variable in pptp_release() Variable opt in pptp_release() is set but never used, thus needs to be removed. Signed-off-by: Christos Gkekas Signed-off-by: David S. Miller --- drivers/net/ppp/pptp.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 2f22e318a67f..eac499c58aa7 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -506,7 +506,6 @@ static int pptp_release(struct socket *sock) { struct sock *sk = sock->sk; struct pppox_sock *po; - struct pptp_opt *opt; int error = 0; if (!sk) @@ -520,7 +519,6 @@ static int pptp_release(struct socket *sock) } po = pppox_sk(sk); - opt = &po->proto.pptp; del_chan(po); pppox_unbind_sock(sk); -- cgit v1.2.3 From c4ee5d8103ed78502170e9f0c22dc31cb335c412 Mon Sep 17 00:00:00 2001 From: Prasad Kanneganti Date: Sun, 18 Jun 2017 05:04:11 -0700 Subject: liquidio: replace info-pointer mode with buffer-pointer-only mode Each Octeon output ring can DMA packets to host memory in two modes: info- pointer mode and buffer-pointer-only mode. In info-pointer mode, Octeon takes two buffer pointers for each packet and places the length of the packet along with specified number of bytes from the beginning of the packet into one buffer and the rest of the packet in a separate buffer. In buffer-pointer-only mode, Octeon takes single buffer pointer and places the length of the packet at the beginning of the buffer followed by the packet data. This patch switches all Octeon output rings from info-pointer mode to buffer-pointer-only mode. This results in fewer DMA setups and cache line snoops. Signed-off-by: Prasad Kanneganti Signed-off-by: Derek Chickles Signed-off-by: Satanand Burla Signed-off-by: Felix Manlunas Signed-off-by: David S. Miller --- .../ethernet/cavium/liquidio/cn23xx_pf_device.c | 10 +++--- .../ethernet/cavium/liquidio/cn23xx_vf_device.c | 7 ++-- .../net/ethernet/cavium/liquidio/cn66xx_device.c | 8 ++--- drivers/net/ethernet/cavium/liquidio/lio_main.c | 7 ++-- drivers/net/ethernet/cavium/liquidio/lio_vf_main.c | 5 +-- .../net/ethernet/cavium/liquidio/liquidio_common.h | 2 ++ .../net/ethernet/cavium/liquidio/octeon_config.h | 13 ++------ .../net/ethernet/cavium/liquidio/octeon_device.c | 10 +++--- drivers/net/ethernet/cavium/liquidio/octeon_droq.c | 37 ++++++---------------- drivers/net/ethernet/cavium/liquidio/octeon_droq.h | 18 ++--------- .../net/ethernet/cavium/liquidio/octeon_network.h | 29 ----------------- 11 files changed, 37 insertions(+), 109 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c index 962dcbcef8b5..6081c3132135 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c @@ -493,9 +493,8 @@ static void cn23xx_pf_setup_global_output_regs(struct octeon_device *oct) for (q_no = srn; q_no < ern; q_no++) { reg_val = octeon_read_csr(oct, CN23XX_SLI_OQ_PKT_CONTROL(q_no)); - /* set IPTR & DPTR */ - reg_val |= - (CN23XX_PKT_OUTPUT_CTL_IPTR | CN23XX_PKT_OUTPUT_CTL_DPTR); + /* set DPTR */ + reg_val |= CN23XX_PKT_OUTPUT_CTL_DPTR; /* reset BMODE */ reg_val &= ~(CN23XX_PKT_OUTPUT_CTL_BMODE); @@ -638,7 +637,7 @@ static void cn23xx_setup_oq_regs(struct octeon_device *oct, u32 oq_no) octeon_write_csr(oct, CN23XX_SLI_OQ_SIZE(oq_no), droq->max_count); octeon_write_csr(oct, CN23XX_SLI_OQ_BUFF_INFO_SIZE(oq_no), - (droq->buffer_size | (OCT_RH_SIZE << 16))); + droq->buffer_size); /* Get the mapped address of the pkt_sent and pkts_credit regs */ droq->pkts_sent_reg = @@ -1343,8 +1342,7 @@ int validate_cn23xx_pf_config_info(struct octeon_device *oct, return 1; } - if (!(CFG_GET_OQ_INFO_PTR(conf23xx)) || - !(CFG_GET_OQ_REFILL_THRESHOLD(conf23xx))) { + if (!CFG_GET_OQ_REFILL_THRESHOLD(conf23xx)) { dev_err(&oct->pci_dev->dev, "%s: Invalid parameter for OQ\n", __func__); return 1; diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c index 20f3d2adf0c2..9338a0008378 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c @@ -165,9 +165,8 @@ static void cn23xx_vf_setup_global_output_regs(struct octeon_device *oct) reg_val = octeon_read_csr(oct, CN23XX_VF_SLI_OQ_PKT_CONTROL(q_no)); - /* set IPTR & DPTR */ - reg_val |= - (CN23XX_PKT_OUTPUT_CTL_IPTR | CN23XX_PKT_OUTPUT_CTL_DPTR); + /* set DPTR */ + reg_val |= CN23XX_PKT_OUTPUT_CTL_DPTR; /* reset BMODE */ reg_val &= ~(CN23XX_PKT_OUTPUT_CTL_BMODE); @@ -249,7 +248,7 @@ static void cn23xx_setup_vf_oq_regs(struct octeon_device *oct, u32 oq_no) octeon_write_csr(oct, CN23XX_VF_SLI_OQ_SIZE(oq_no), droq->max_count); octeon_write_csr(oct, CN23XX_VF_SLI_OQ_BUFF_INFO_SIZE(oq_no), - (droq->buffer_size | (OCT_RH_SIZE << 16))); + droq->buffer_size); /* Get the mapped address of the pkt_sent and pkts_credit regs */ droq->pkts_sent_reg = diff --git a/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c index bdec051107a6..b28253c96d97 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c @@ -209,9 +209,6 @@ void lio_cn6xxx_setup_global_output_regs(struct octeon_device *oct) octeon_write_csr64(oct, CN6XXX_SLI_OQ_WMARK, 0); } - /* / Select Info Ptr for length & data */ - octeon_write_csr(oct, CN6XXX_SLI_PKT_IPTR, 0xFFFFFFFF); - /* / Select Packet count instead of bytes for SLI_PKTi_CNTS[CNT] */ octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_BMODE, 0); @@ -314,7 +311,7 @@ void lio_cn6xxx_setup_oq_regs(struct octeon_device *oct, u32 oq_no) octeon_write_csr(oct, CN6XXX_SLI_OQ_SIZE(oq_no), droq->max_count); octeon_write_csr(oct, CN6XXX_SLI_OQ_BUFF_INFO_SIZE(oq_no), - (droq->buffer_size | (OCT_RH_SIZE << 16))); + droq->buffer_size); /* Get the mapped address of the pkt_sent and pkts_credit regs */ droq->pkts_sent_reg = @@ -734,8 +731,7 @@ int lio_validate_cn6xxx_config_info(struct octeon_device *oct, __func__); return 1; } - if (!(CFG_GET_OQ_INFO_PTR(conf6xxx)) || - !(CFG_GET_OQ_REFILL_THRESHOLD(conf6xxx))) { + if (!CFG_GET_OQ_REFILL_THRESHOLD(conf6xxx)) { dev_err(&oct->pci_dev->dev, "%s: Invalid parameter for OQ\n", __func__); return 1; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 17f963b7f819..51583ae4b1eb 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -3899,7 +3899,7 @@ static int lio_nic_info(struct octeon_recv_info *recv_info, void *buf) union oct_link_status *ls; int i; - if (recv_pkt->buffer_size[0] != sizeof(*ls)) { + if (recv_pkt->buffer_size[0] != (sizeof(*ls) + OCT_DROQ_INFO_SIZE)) { dev_err(&oct->pci_dev->dev, "Malformed NIC_INFO, len=%d, ifidx=%d\n", recv_pkt->buffer_size[0], recv_pkt->rh.r_nic_info.gmxport); @@ -3907,7 +3907,8 @@ static int lio_nic_info(struct octeon_recv_info *recv_info, void *buf) } gmxport = recv_pkt->rh.r_nic_info.gmxport; - ls = (union oct_link_status *)get_rbd(recv_pkt->buffer_ptr[0]); + ls = (union oct_link_status *)(get_rbd(recv_pkt->buffer_ptr[0]) + + OCT_DROQ_INFO_SIZE); octeon_swap_8B_data((u64 *)ls, (sizeof(union oct_link_status)) >> 3); for (i = 0; i < oct->ifcount; i++) { @@ -4465,7 +4466,7 @@ octeon_recv_vf_drv_notice(struct octeon_recv_info *recv_info, void *buf) u64 *data, vf_num; notice = recv_pkt->rh.r.ossp; - data = (u64 *)get_rbd(recv_pkt->buffer_ptr[0]); + data = (u64 *)(get_rbd(recv_pkt->buffer_ptr[0]) + OCT_DROQ_INFO_SIZE); /* the first 64-bit word of data is the vf_num */ vf_num = data[0]; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 1f7032614ae5..9b247102eb92 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -2718,7 +2718,7 @@ static int lio_nic_info(struct octeon_recv_info *recv_info, void *buf) int gmxport = 0; int i; - if (recv_pkt->buffer_size[0] != sizeof(*ls)) { + if (recv_pkt->buffer_size[0] != (sizeof(*ls) + OCT_DROQ_INFO_SIZE)) { dev_err(&oct->pci_dev->dev, "Malformed NIC_INFO, len=%d, ifidx=%d\n", recv_pkt->buffer_size[0], recv_pkt->rh.r_nic_info.gmxport); @@ -2726,7 +2726,8 @@ static int lio_nic_info(struct octeon_recv_info *recv_info, void *buf) } gmxport = recv_pkt->rh.r_nic_info.gmxport; - ls = (union oct_link_status *)get_rbd(recv_pkt->buffer_ptr[0]); + ls = (union oct_link_status *)(get_rbd(recv_pkt->buffer_ptr[0]) + + OCT_DROQ_INFO_SIZE); octeon_swap_8B_data((u64 *)ls, (sizeof(union oct_link_status)) >> 3); diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h index d03f5296f33e..231dd7fbfb80 100644 --- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h +++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h @@ -173,6 +173,8 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, /*------------------------- End Scatter/Gather ---------------------------*/ +#define OCTNET_FRM_LENGTH_SIZE 8 + #define OCTNET_FRM_PTP_HEADER_SIZE 8 #define OCTNET_FRM_HEADER_SIZE 22 /* VLAN + Ethernet */ diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_config.h b/drivers/net/ethernet/cavium/liquidio/octeon_config.h index d29ebc531151..f229d792c2b3 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_config.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_config.h @@ -47,7 +47,7 @@ /* CN6xxx OQ configuration macros */ #define CN6XXX_MAX_OUTPUT_QUEUES 32 #define CN6XXX_MAX_OQ_DESCRIPTORS 2048 -#define CN6XXX_OQ_BUF_SIZE 1536 +#define CN6XXX_OQ_BUF_SIZE 1664 #define CN6XXX_OQ_PKTSPER_INTR ((CN6XXX_MAX_OQ_DESCRIPTORS < 512) ? \ (CN6XXX_MAX_OQ_DESCRIPTORS / 4) : 128) #define CN6XXX_OQ_REFIL_THRESHOLD ((CN6XXX_MAX_OQ_DESCRIPTORS < 512) ? \ @@ -78,7 +78,7 @@ #define CN23XX_MAX_OUTPUT_QUEUES CN23XX_MAX_RINGS_PER_PF #define CN23XX_MAX_OQ_DESCRIPTORS 512 -#define CN23XX_OQ_BUF_SIZE 1536 +#define CN23XX_OQ_BUF_SIZE 1664 #define CN23XX_OQ_PKTSPER_INTR 128 /*#define CAVIUM_ONLY_CN23XX_RX_PERF*/ #define CN23XX_OQ_REFIL_THRESHOLD 16 @@ -98,8 +98,6 @@ #define OCTEON_32BYTE_INSTR 32 #define OCTEON_64BYTE_INSTR 64 #define OCTEON_MAX_BASE_IOQ 4 -#define OCTEON_OQ_BUFPTR_MODE 0 -#define OCTEON_OQ_INFOPTR_MODE 1 #define OCTEON_DMA_INTR_PKT 64 #define OCTEON_DMA_INTR_TIME 1000 @@ -125,7 +123,6 @@ #define CFG_SET_IQ_INTR_PKT(cfg, val) (cfg)->iq.iq_intr_pkt = val #define CFG_GET_OQ_MAX_Q(cfg) ((cfg)->oq.max_oqs) -#define CFG_GET_OQ_INFO_PTR(cfg) ((cfg)->oq.info_ptr) #define CFG_GET_OQ_PKTS_PER_INTR(cfg) ((cfg)->oq.pkts_per_intr) #define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold) #define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt) @@ -266,9 +263,6 @@ struct octeon_oq_config { */ u64 refill_threshold:16; - /** If set, the Output queue uses info-pointer mode. (Default: 1) */ - u64 info_ptr:32; - /* Max number of OQs available */ u64 max_oqs:8; @@ -276,9 +270,6 @@ struct octeon_oq_config { /* Max number of OQs available */ u64 max_oqs:8; - /** If set, the Output queue uses info-pointer mode. (Default: 1) */ - u64 info_ptr:32; - /** The number of buffers that were consumed during packet processing by * the driver on this Output queue before the driver attempts to * replenish diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index 3b7cc9320deb..623e28ca736e 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -51,7 +51,6 @@ static struct octeon_config default_cn66xx_conf = { /** OQ attributes */ .oq = { .max_oqs = CN6XXX_CFG_IO_QUEUES, - .info_ptr = OCTEON_OQ_INFOPTR_MODE, .refill_threshold = CN6XXX_OQ_REFIL_THRESHOLD, .oq_intr_pkt = CN6XXX_OQ_INTR_PKT, .oq_intr_time = CN6XXX_OQ_INTR_TIME, @@ -161,7 +160,6 @@ static struct octeon_config default_cn68xx_conf = { /** OQ attributes */ .oq = { .max_oqs = CN6XXX_CFG_IO_QUEUES, - .info_ptr = OCTEON_OQ_INFOPTR_MODE, .refill_threshold = CN6XXX_OQ_REFIL_THRESHOLD, .oq_intr_pkt = CN6XXX_OQ_INTR_PKT, .oq_intr_time = CN6XXX_OQ_INTR_TIME, @@ -328,7 +326,6 @@ static struct octeon_config default_cn68xx_210nv_conf = { /** OQ attributes */ .oq = { .max_oqs = CN6XXX_CFG_IO_QUEUES, - .info_ptr = OCTEON_OQ_INFOPTR_MODE, .refill_threshold = CN6XXX_OQ_REFIL_THRESHOLD, .oq_intr_pkt = CN6XXX_OQ_INTR_PKT, .oq_intr_time = CN6XXX_OQ_INTR_TIME, @@ -432,7 +429,6 @@ static struct octeon_config default_cn23xx_conf = { /** OQ attributes */ .oq = { .max_oqs = CN23XX_CFG_IO_QUEUES, - .info_ptr = OCTEON_OQ_INFOPTR_MODE, .pkts_per_intr = CN23XX_OQ_PKTSPER_INTR, .refill_threshold = CN23XX_OQ_REFIL_THRESHOLD, .oq_intr_pkt = CN23XX_OQ_INTR_PKT, @@ -1236,13 +1232,15 @@ int octeon_core_drv_init(struct octeon_recv_info *recv_info, void *buf) cs = &core_setup[oct->octeon_id]; - if (recv_pkt->buffer_size[0] != sizeof(*cs)) { + if (recv_pkt->buffer_size[0] != (sizeof(*cs) + OCT_DROQ_INFO_SIZE)) { dev_dbg(&oct->pci_dev->dev, "Core setup bytes expected %u found %d\n", (u32)sizeof(*cs), recv_pkt->buffer_size[0]); } - memcpy(cs, get_rbd(recv_pkt->buffer_ptr[0]), sizeof(*cs)); + memcpy(cs, get_rbd( + recv_pkt->buffer_ptr[0]) + OCT_DROQ_INFO_SIZE, sizeof(*cs)); + strncpy(oct->boardinfo.name, cs->boardname, OCT_BOARD_NAME); strncpy(oct->boardinfo.serial_number, cs->board_serial_number, OCT_SERIAL_LEN); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index d3a6a1c28053..2e190deb2233 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -181,10 +181,7 @@ octeon_droq_setup_ring_buffers(struct octeon_device *oct, droq->recv_buf_list[i].buffer = buf; droq->recv_buf_list[i].data = get_rbd(buf); - droq->info_list[i].length = 0; - - /* map ring buffers into memory */ - desc_ring[i].info_ptr = lio_map_ring_info(droq, i); + desc_ring[i].info_ptr = 0; desc_ring[i].buffer_ptr = lio_map_ring(droq->recv_buf_list[i].buffer); } @@ -205,9 +202,6 @@ int octeon_delete_droq(struct octeon_device *oct, u32 q_no) octeon_droq_destroy_ring_buffers(oct, droq); vfree(droq->recv_buf_list); - if (droq->info_base_addr) - lio_free_info_buffer(oct, droq); - if (droq->desc_ring) lio_dma_free(oct, (droq->max_count * OCT_DROQ_DESC_SIZE), droq->desc_ring, droq->desc_ring_dma); @@ -280,14 +274,6 @@ int octeon_init_droq(struct octeon_device *oct, dev_dbg(&oct->pci_dev->dev, "droq[%d]: num_desc: %d\n", q_no, droq->max_count); - droq->info_list = lio_alloc_info_buffer(oct, droq); - if (!droq->info_list) { - dev_err(&oct->pci_dev->dev, "Cannot allocate memory for info list.\n"); - lio_dma_free(oct, (droq->max_count * OCT_DROQ_DESC_SIZE), - droq->desc_ring, droq->desc_ring_dma); - return 1; - } - droq->recv_buf_list = (struct octeon_recv_buffer *) vmalloc_node(droq->max_count * OCT_DROQ_RECVBUF_SIZE, @@ -357,7 +343,7 @@ static inline struct octeon_recv_info *octeon_create_recv_info( u32 i, bytes_left; struct octeon_skb_page_info *pg_info; - info = &droq->info_list[idx]; + info = (struct octeon_droq_info *)droq->recv_buf_list[idx].data; recv_info = octeon_alloc_recv_info(sizeof(struct __dispatch)); if (!recv_info) @@ -491,8 +477,6 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq) desc_ring[droq->refill_idx].buffer_ptr = lio_map_ring(droq->recv_buf_list[ droq->refill_idx].buffer); - /* Reset any previous values in the length field. */ - droq->info_list[droq->refill_idx].length = 0; droq->refill_idx = incr_index(droq->refill_idx, 1, droq->max_count); @@ -541,11 +525,7 @@ void octeon_droq_check_oom(struct octeon_droq *droq) static inline u32 octeon_droq_get_bufcount(u32 buf_size, u32 total_len) { - u32 buf_cnt = 0; - - while (total_len > (buf_size * buf_cnt)) - buf_cnt++; - return buf_cnt; + return ((total_len + buf_size - 1) / buf_size); } static int @@ -593,11 +573,12 @@ static inline void octeon_droq_drop_packets(struct octeon_device *oct, struct octeon_droq_info *info; for (i = 0; i < cnt; i++) { - info = &droq->info_list[droq->read_idx]; + info = (struct octeon_droq_info *) + droq->recv_buf_list[droq->read_idx].data; octeon_swap_8B_data((u64 *)info, 2); if (info->length) { - info->length -= OCT_RH_SIZE; + info->length += OCTNET_FRM_LENGTH_SIZE; droq->stats.bytes_received += info->length; buf_cnt = octeon_droq_get_bufcount(droq->buffer_size, (u32)info->length); @@ -629,7 +610,8 @@ octeon_droq_fast_process_packets(struct octeon_device *oct, struct octeon_skb_page_info *pg_info; void *buf; - info = &droq->info_list[droq->read_idx]; + info = (struct octeon_droq_info *) + droq->recv_buf_list[droq->read_idx].data; octeon_swap_8B_data((u64 *)info, 2); if (!info->length) { @@ -643,9 +625,10 @@ octeon_droq_fast_process_packets(struct octeon_device *oct, } /* Len of resp hdr in included in the received data len. */ - info->length -= OCT_RH_SIZE; rh = &info->rh; + info->length += OCTNET_FRM_LENGTH_SIZE; + rh->r_dh.len += (ROUNDUP8(OCT_DROQ_INFO_SIZE) / sizeof(u64)); total_len += (u32)info->length; if (opcode_slow_path(rh)) { u32 buf_cnt; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h index 9781577115e7..6efd139b894d 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h @@ -51,11 +51,11 @@ struct octeon_droq_desc { * about the packet. */ struct octeon_droq_info { - /** The Output Receive Header. */ - union octeon_rh rh; - /** The Length of the packet. */ u64 length; + + /** The Output Receive Header. */ + union octeon_rh rh; }; #define OCT_DROQ_INFO_SIZE (sizeof(struct octeon_droq_info)) @@ -294,9 +294,6 @@ struct octeon_droq { */ u32 max_empty_descs; - /** The 8B aligned info ptrs begin from this address. */ - struct octeon_droq_info *info_list; - /** The receive buffer list. This list has the virtual addresses of the * buffers. */ @@ -324,15 +321,6 @@ struct octeon_droq { /** DMA mapped address of the DROQ descriptor ring. */ size_t desc_ring_dma; - /** Info ptr list are allocated at this virtual address. */ - void *info_base_addr; - - /** DMA mapped address of the info list */ - dma_addr_t info_list_dma; - - /** Allocated size of info list. */ - u32 info_alloc_size; - /** application context */ void *app_ctx; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h index 4b3507972243..ec8504b2942d 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h @@ -356,29 +356,6 @@ static inline void tx_buffer_free(void *buffer) #define lio_dma_free(oct, size, virt_addr, dma_addr) \ dma_free_coherent(&(oct)->pci_dev->dev, size, virt_addr, dma_addr) -static inline void * -lio_alloc_info_buffer(struct octeon_device *oct, - struct octeon_droq *droq) -{ - void *virt_ptr; - - virt_ptr = lio_dma_alloc(oct, (droq->max_count * OCT_DROQ_INFO_SIZE), - &droq->info_list_dma); - if (virt_ptr) { - droq->info_alloc_size = droq->max_count * OCT_DROQ_INFO_SIZE; - droq->info_base_addr = virt_ptr; - } - - return virt_ptr; -} - -static inline void lio_free_info_buffer(struct octeon_device *oct, - struct octeon_droq *droq) -{ - lio_dma_free(oct, droq->info_alloc_size, droq->info_base_addr, - droq->info_list_dma); -} - static inline void *get_rbd(struct sk_buff *skb) { @@ -391,12 +368,6 @@ void *get_rbd(struct sk_buff *skb) return va; } -static inline u64 -lio_map_ring_info(struct octeon_droq *droq, u32 i) -{ - return droq->info_list_dma + (i * sizeof(struct octeon_droq_info)); -} - static inline u64 lio_map_ring(void *buf) { -- cgit v1.2.3 From d427caee5a3f04938f47bec6fdec97a52668ee53 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Fri, 16 Jun 2017 15:36:09 +0530 Subject: cxgb4: fix a NULL dereference Avoid NULL dereference in setup_sge_queues() when the adapter is in non offload mode. Fixes: 0fbc81b3ad51 ('chcr/cxgb4i/cxgbit/RDMA/cxgb4: Allocate resources dynamically for all cxgb4 ULD's') Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 15fb284eafc0..257ac18dc22b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -824,9 +824,12 @@ static int setup_sge_queues(struct adapter *adap) { int err, i, j; struct sge *s = &adap->sge; - struct sge_uld_rxq_info *rxq_info = s->uld_rxq_info[CXGB4_ULD_RDMA]; + struct sge_uld_rxq_info *rxq_info = NULL; unsigned int cmplqid = 0; + if (is_uld(adap)) + rxq_info = s->uld_rxq_info[CXGB4_ULD_RDMA]; + for_each_port(adap, i) { struct net_device *dev = adap->port[i]; struct port_info *pi = netdev_priv(dev); -- cgit v1.2.3 From b64052fc9bcb4fa3ca8701e74c1aac0e2847b724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Casc=C3=B3n?= Date: Thu, 15 Jun 2017 16:22:15 -0700 Subject: nfp: add VLAN filtering support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add general use per-vNIC mailbox area and use it for VLAN filtering support. Initially proto is hardcoded to 802.1q. Signed-off-by: Pablo Cascón Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 74 +++++++++++++++++++++- drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h | 27 ++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 378512dec80d..2bdddd1ae666 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -280,6 +280,30 @@ int nfp_net_reconfig(struct nfp_net *nn, u32 update) return ret; } +/** + * nfp_net_reconfig_mbox() - Reconfigure the firmware via the mailbox + * @nn: NFP Net device to reconfigure + * @mbox_cmd: The value for the mailbox command + * + * Helper function for mailbox updates + * + * Return: Negative errno on error, 0 on success + */ +static int nfp_net_reconfig_mbox(struct nfp_net *nn, u32 mbox_cmd) +{ + int ret; + + nn_writeq(nn, NFP_NET_CFG_MBOX_CMD, mbox_cmd); + + ret = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_MBOX); + if (ret) { + nn_err(nn, "Mailbox update error\n"); + return ret; + } + + return -nn_readl(nn, NFP_NET_CFG_MBOX_RET); +} + /* Interrupt configuration and handling */ @@ -2960,6 +2984,40 @@ static int nfp_net_change_mtu(struct net_device *netdev, int new_mtu) return nfp_net_ring_reconfig(nn, dp, NULL); } +static int +nfp_net_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) +{ + struct nfp_net *nn = netdev_priv(netdev); + + /* Priority tagged packets with vlan id 0 are processed by the + * NFP as untagged packets + */ + if (!vid) + return 0; + + nn_writew(nn, NFP_NET_CFG_VLAN_FILTER_VID, vid); + nn_writew(nn, NFP_NET_CFG_VLAN_FILTER_PROTO, ETH_P_8021Q); + + return nfp_net_reconfig_mbox(nn, NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_ADD); +} + +static int +nfp_net_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) +{ + struct nfp_net *nn = netdev_priv(netdev); + + /* Priority tagged packets with vlan id 0 are processed by the + * NFP as untagged packets + */ + if (!vid) + return 0; + + nn_writew(nn, NFP_NET_CFG_VLAN_FILTER_VID, vid); + nn_writew(nn, NFP_NET_CFG_VLAN_FILTER_PROTO, ETH_P_8021Q); + + return nfp_net_reconfig_mbox(nn, NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL); +} + static void nfp_net_stat64(struct net_device *netdev, struct rtnl_link_stats64 *stats) { @@ -3053,6 +3111,13 @@ static int nfp_net_set_features(struct net_device *netdev, new_ctrl &= ~NFP_NET_CFG_CTRL_TXVLAN; } + if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { + if (features & NETIF_F_HW_VLAN_CTAG_FILTER) + new_ctrl |= NFP_NET_CFG_CTRL_CTAG_FILTER; + else + new_ctrl &= ~NFP_NET_CFG_CTRL_CTAG_FILTER; + } + if (changed & NETIF_F_SG) { if (features & NETIF_F_SG) new_ctrl |= NFP_NET_CFG_CTRL_GATHER; @@ -3289,6 +3354,8 @@ const struct net_device_ops nfp_net_netdev_ops = { .ndo_stop = nfp_net_netdev_close, .ndo_start_xmit = nfp_net_tx, .ndo_get_stats64 = nfp_net_stat64, + .ndo_vlan_rx_add_vid = nfp_net_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = nfp_net_vlan_rx_kill_vid, .ndo_setup_tc = nfp_net_setup_tc, .ndo_tx_timeout = nfp_net_tx_timeout, .ndo_set_rx_mode = nfp_net_set_rx_mode, @@ -3316,7 +3383,7 @@ void nfp_net_info(struct nfp_net *nn) nn->fw_ver.resv, nn->fw_ver.class, nn->fw_ver.major, nn->fw_ver.minor, nn->max_mtu); - nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", nn->cap, nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "", nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "", @@ -3331,6 +3398,7 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_LSO2 ? "TSO2 " : "", nn->cap & NFP_NET_CFG_CTRL_RSS ? "RSS1 " : "", nn->cap & NFP_NET_CFG_CTRL_RSS2 ? "RSS2 " : "", + nn->cap & NFP_NET_CFG_CTRL_CTAG_FILTER ? "CTAG_FILTER " : "", nn->cap & NFP_NET_CFG_CTRL_L2SWITCH ? "L2SWITCH " : "", nn->cap & NFP_NET_CFG_CTRL_MSIXAUTO ? "AUTOMASK " : "", nn->cap & NFP_NET_CFG_CTRL_IRQMOD ? "IRQMOD " : "", @@ -3547,6 +3615,10 @@ static void nfp_net_netdev_init(struct nfp_net *nn) nn->dp.ctrl |= NFP_NET_CFG_CTRL_TXVLAN; } } + if (nn->cap & NFP_NET_CFG_CTRL_CTAG_FILTER) { + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + nn->dp.ctrl |= NFP_NET_CFG_CTRL_CTAG_FILTER; + } netdev->features = netdev->hw_features; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 48a8bf97645e..e5e94e0746ec 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -124,6 +124,7 @@ #define NFP_NET_CFG_CTRL_SCATTER (0x1 << 8) /* Scatter DMA */ #define NFP_NET_CFG_CTRL_GATHER (0x1 << 9) /* Gather DMA */ #define NFP_NET_CFG_CTRL_LSO (0x1 << 10) /* LSO/TSO (version 1) */ +#define NFP_NET_CFG_CTRL_CTAG_FILTER (0x1 << 11) /* VLAN CTAG filtering */ #define NFP_NET_CFG_CTRL_RINGCFG (0x1 << 16) /* Ring runtime changes */ #define NFP_NET_CFG_CTRL_RSS (0x1 << 17) /* RSS (version 1) */ #define NFP_NET_CFG_CTRL_IRQMOD (0x1 << 18) /* Interrupt moderation */ @@ -162,6 +163,7 @@ #define NFP_NET_CFG_UPDATE_VXLAN (0x1 << 9) /* VXLAN port change */ #define NFP_NET_CFG_UPDATE_BPF (0x1 << 10) /* BPF program load */ #define NFP_NET_CFG_UPDATE_MACADDR (0x1 << 11) /* MAC address change */ +#define NFP_NET_CFG_UPDATE_MBOX (0x1 << 12) /* Mailbox update */ #define NFP_NET_CFG_UPDATE_ERR (0x1 << 31) /* A error occurred */ #define NFP_NET_CFG_TXRS_ENABLE 0x0008 #define NFP_NET_CFG_RXRS_ENABLE 0x0010 @@ -400,4 +402,29 @@ #define NFP_NET_CFG_RXR_STATS(_x) (NFP_NET_CFG_RXR_STATS_BASE + \ ((_x) * 0x10)) +/** + * General use mailbox area (0x1800 - 0x19ff) + * 4B used for update command and 4B return code + * followed by a max of 504B of variable length value + */ +#define NFP_NET_CFG_MBOX_CMD 0x1800 +#define NFP_NET_CFG_MBOX_RET 0x1804 +#define NFP_NET_CFG_MBOX_VAL 0x1808 +#define NFP_NET_CFG_MBOX_VAL_MAX_SZ 0x1F8 + +#define NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_ADD 1 +#define NFP_NET_CFG_MBOX_CMD_CTAG_FILTER_KILL 2 + +/** + * VLAN filtering using general use mailbox + * @NFP_NET_CFG_VLAN_FILTER: Base address of VLAN filter mailbox + * @NFP_NET_CFG_VLAN_FILTER_VID: VLAN ID to filter + * @NFP_NET_CFG_VLAN_FILTER_PROTO: VLAN proto to filter + * @NFP_NET_CFG_VXLAN_SZ: Size of the VLAN filter mailbox in bytes + */ +#define NFP_NET_CFG_VLAN_FILTER NFP_NET_CFG_MBOX_VAL +#define NFP_NET_CFG_VLAN_FILTER_VID NFP_NET_CFG_VLAN_FILTER +#define NFP_NET_CFG_VLAN_FILTER_PROTO (NFP_NET_CFG_VLAN_FILTER + 2) +#define NFP_NET_CFG_VLAN_FILTER_SZ 0x0004 + #endif /* _NFP_NET_CTRL_H_ */ -- cgit v1.2.3 From 89ff67718c900754d2aa5c8e37efbe607be36154 Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Mon, 19 Jun 2017 15:37:13 +0530 Subject: cxgb4: add new T6 pci device id's Add 0x6082, 0x6083 and 0x6084 T6 device id's Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index be7041f6cf71..99987d8e437e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -192,6 +192,9 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x6015), CH_PCI_ID_TABLE_FENTRY(0x6080), CH_PCI_ID_TABLE_FENTRY(0x6081), + CH_PCI_ID_TABLE_FENTRY(0x6082), /* Custom T6225-CR SFP28 */ + CH_PCI_ID_TABLE_FENTRY(0x6083), /* Custom T62100-CR QSFP28 */ + CH_PCI_ID_TABLE_FENTRY(0x6084), /* Custom T64100-CR QSFP28 */ CH_PCI_DEVICE_ID_TABLE_DEFINE_END; #endif /* __T4_PCI_ID_TBL_H__ */ -- cgit v1.2.3 From 910603818c6c0558fe9b5e056a3bd5195aaae1a5 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Mon, 19 Jun 2017 17:40:48 +0530 Subject: cxgb4: notify uP to route ctrlq compl to rdma rspq During the module initialisation there is a possible race (basically race between uld and lld) where neither the uld nor lld notifies the uP about where to route the ctrl queue completions. LLD skips notifying uP as the rdma queues were not created by then (will leave it to ULD to notify the uP). As the ULD comes up, it also skips notifying the uP as the flag FULL_INIT_DONE is not set yet (ULD assumes that the interface is not up yet). Consequently, this race between uld and lld leaves uP unnotified about where to send the ctrl queue completions to, leading to iwarp RI_RES WR failure. Here is the race: CPU 0 CPU1 - allocates nic rx queus - t4_sge_alloc_ctrl_txq() (if rdma rsp queues exists, tell uP to route ctrl queue compl to rdma rspq) - acquires the mutex_lock - allocates rdma response queues - if FULL_INIT_DONE set, tell uP to route ctrl queue compl to rdma rspq - relinquishes mutex_lock - acquires the mutex_lock - enable_rx() - set FULL_INIT_DONE - relinquishes mutex_lock This patch fixes the above issue. Fixes: e7519f9926f1('cxgb4: avoid enabling napi twice to the same queue') Signed-off-by: Raju Rangoju Acked-by: Steve Wise CC: Stable # 4.9+ Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 257ac18dc22b..b3753ed74cec 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2190,9 +2190,10 @@ static int cxgb_up(struct adapter *adap) { int err; + mutex_lock(&uld_mutex); err = setup_sge_queues(adap); if (err) - goto out; + goto rel_lock; err = setup_rss(adap); if (err) goto freeq; @@ -2216,7 +2217,6 @@ static int cxgb_up(struct adapter *adap) goto irq_err; } - mutex_lock(&uld_mutex); enable_rx(adap); t4_sge_start(adap); t4_intr_enable(adap); @@ -2229,13 +2229,15 @@ static int cxgb_up(struct adapter *adap) #endif /* Initialize hash mac addr list*/ INIT_LIST_HEAD(&adap->mac_hlist); - out: return err; + irq_err: dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err); freeq: t4_free_sge_resources(adap); - goto out; + rel_lock: + mutex_unlock(&uld_mutex); + return err; } static void cxgb_down(struct adapter *adapter) -- cgit v1.2.3 From 4301ba7b3ed9d3ffbaebc295413fcd3e8ab34949 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Sun, 18 Jun 2017 17:13:44 +0300 Subject: net/mlx5e: IPoIB, Move to a separate directory IPoIB netdevice driver was only introduced in previous kernel release and it is growing in terms of features and LOC, move it to a separate directory. Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/ipoib.c | 513 --------------------- drivers/net/ethernet/mellanox/mlx5/core/ipoib.h | 56 --- .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 513 +++++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h | 56 +++ 7 files changed, 572 insertions(+), 572 deletions(-) delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/ipoib.c delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/ipoib.h create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 12556c03eec4..59b87b30e438 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -15,4 +15,4 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o -mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib.o +mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 66b5fec15313..806139d62139 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -40,7 +40,7 @@ #include "en_tc.h" #include "eswitch.h" #include "en_rep.h" -#include "ipoib.h" +#include "ipoib/ipoib.h" static inline bool mlx5e_rx_hw_stamp(struct mlx5e_tstamp *tstamp) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index ef3e1918d8cc..354f474322ce 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -33,7 +33,7 @@ #include #include #include "en.h" -#include "ipoib.h" +#include "ipoib/ipoib.h" #define MLX5E_SQ_NOPS_ROOM MLX5_SEND_WQE_MAX_WQEBBS #define MLX5E_SQ_STOP_ROOM (MLX5_SEND_WQE_MAX_WQEBBS +\ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c deleted file mode 100644 index 22ca59145e6c..000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Copyright (c) 2017, Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include "en.h" -#include "ipoib.h" - -#define IB_DEFAULT_Q_KEY 0xb1b - -static int mlx5i_open(struct net_device *netdev); -static int mlx5i_close(struct net_device *netdev); -static int mlx5i_dev_init(struct net_device *dev); -static void mlx5i_dev_cleanup(struct net_device *dev); - -static const struct net_device_ops mlx5i_netdev_ops = { - .ndo_open = mlx5i_open, - .ndo_stop = mlx5i_close, - .ndo_init = mlx5i_dev_init, - .ndo_uninit = mlx5i_dev_cleanup, -}; - -/* IPoIB mlx5 netdev profile */ - -/* Called directly after IPoIB netdevice was created to initialize SW structs */ -static void mlx5i_init(struct mlx5_core_dev *mdev, - struct net_device *netdev, - const struct mlx5e_profile *profile, - void *ppriv) -{ - struct mlx5e_priv *priv = mlx5i_epriv(netdev); - - priv->mdev = mdev; - priv->netdev = netdev; - priv->profile = profile; - priv->ppriv = ppriv; - - mlx5e_build_nic_params(mdev, &priv->channels.params, profile->max_nch(mdev)); - - /* Override RQ params as IPoIB supports only LINKED LIST RQ for now */ - mlx5e_set_rq_type_params(mdev, &priv->channels.params, MLX5_WQ_TYPE_LINKED_LIST); - priv->channels.params.lro_en = false; - - mutex_init(&priv->state_lock); - - netdev->hw_features |= NETIF_F_SG; - netdev->hw_features |= NETIF_F_IP_CSUM; - netdev->hw_features |= NETIF_F_IPV6_CSUM; - netdev->hw_features |= NETIF_F_GRO; - netdev->hw_features |= NETIF_F_TSO; - netdev->hw_features |= NETIF_F_TSO6; - netdev->hw_features |= NETIF_F_RXCSUM; - netdev->hw_features |= NETIF_F_RXHASH; - - netdev->netdev_ops = &mlx5i_netdev_ops; -} - -/* Called directly before IPoIB netdevice is destroyed to cleanup SW structs */ -static void mlx5i_cleanup(struct mlx5e_priv *priv) -{ - /* Do nothing .. */ -} - -#define MLX5_QP_ENHANCED_ULP_STATELESS_MODE 2 - -static int mlx5i_create_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *qp) -{ - struct mlx5_qp_context *context = NULL; - u32 *in = NULL; - void *addr_path; - int ret = 0; - int inlen; - void *qpc; - - inlen = MLX5_ST_SZ_BYTES(create_qp_in); - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); - MLX5_SET(qpc, qpc, st, MLX5_QP_ST_UD); - MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); - MLX5_SET(qpc, qpc, ulp_stateless_offload_mode, - MLX5_QP_ENHANCED_ULP_STATELESS_MODE); - - addr_path = MLX5_ADDR_OF(qpc, qpc, primary_address_path); - MLX5_SET(ads, addr_path, port, 1); - MLX5_SET(ads, addr_path, grh, 1); - - ret = mlx5_core_create_qp(mdev, qp, in, inlen); - if (ret) { - mlx5_core_err(mdev, "Failed creating IPoIB QP err : %d\n", ret); - goto out; - } - - /* QP states */ - context = kzalloc(sizeof(*context), GFP_KERNEL); - if (!context) { - ret = -ENOMEM; - goto out; - } - - context->flags = cpu_to_be32(MLX5_QP_PM_MIGRATED << 11); - context->pri_path.port = 1; - context->qkey = cpu_to_be32(IB_DEFAULT_Q_KEY); - - ret = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_RST2INIT_QP, 0, context, qp); - if (ret) { - mlx5_core_err(mdev, "Failed to modify qp RST2INIT, err: %d\n", ret); - goto out; - } - memset(context, 0, sizeof(*context)); - - ret = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_INIT2RTR_QP, 0, context, qp); - if (ret) { - mlx5_core_err(mdev, "Failed to modify qp INIT2RTR, err: %d\n", ret); - goto out; - } - - ret = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_RTR2RTS_QP, 0, context, qp); - if (ret) { - mlx5_core_err(mdev, "Failed to modify qp RTR2RTS, err: %d\n", ret); - goto out; - } - -out: - kfree(context); - kvfree(in); - return ret; -} - -static void mlx5i_destroy_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *qp) -{ - mlx5_fs_remove_rx_underlay_qpn(mdev, qp->qpn); - - mlx5_core_destroy_qp(mdev, qp); -} - -static int mlx5i_init_tx(struct mlx5e_priv *priv) -{ - struct mlx5i_priv *ipriv = priv->ppriv; - int err; - - err = mlx5i_create_underlay_qp(priv->mdev, &ipriv->qp); - if (err) { - mlx5_core_warn(priv->mdev, "create underlay QP failed, %d\n", err); - return err; - } - - mlx5_fs_add_rx_underlay_qpn(priv->mdev, ipriv->qp.qpn); - - err = mlx5e_create_tis(priv->mdev, 0 /* tc */, ipriv->qp.qpn, &priv->tisn[0]); - if (err) { - mlx5_core_warn(priv->mdev, "create tis failed, %d\n", err); - return err; - } - - return 0; -} - -static void mlx5i_cleanup_tx(struct mlx5e_priv *priv) -{ - struct mlx5i_priv *ipriv = priv->ppriv; - - mlx5e_destroy_tis(priv->mdev, priv->tisn[0]); - mlx5i_destroy_underlay_qp(priv->mdev, &ipriv->qp); -} - -static int mlx5i_create_flow_steering(struct mlx5e_priv *priv) -{ - int err; - - priv->fs.ns = mlx5_get_flow_namespace(priv->mdev, - MLX5_FLOW_NAMESPACE_KERNEL); - - if (!priv->fs.ns) - return -EINVAL; - - err = mlx5e_arfs_create_tables(priv); - if (err) { - netdev_err(priv->netdev, "Failed to create arfs tables, err=%d\n", - err); - priv->netdev->hw_features &= ~NETIF_F_NTUPLE; - } - - err = mlx5e_create_ttc_table(priv); - if (err) { - netdev_err(priv->netdev, "Failed to create ttc table, err=%d\n", - err); - goto err_destroy_arfs_tables; - } - - return 0; - -err_destroy_arfs_tables: - mlx5e_arfs_destroy_tables(priv); - - return err; -} - -static void mlx5i_destroy_flow_steering(struct mlx5e_priv *priv) -{ - mlx5e_destroy_ttc_table(priv); - mlx5e_arfs_destroy_tables(priv); -} - -static int mlx5i_init_rx(struct mlx5e_priv *priv) -{ - int err; - - err = mlx5e_create_indirect_rqt(priv); - if (err) - return err; - - err = mlx5e_create_direct_rqts(priv); - if (err) - goto err_destroy_indirect_rqts; - - err = mlx5e_create_indirect_tirs(priv); - if (err) - goto err_destroy_direct_rqts; - - err = mlx5e_create_direct_tirs(priv); - if (err) - goto err_destroy_indirect_tirs; - - err = mlx5i_create_flow_steering(priv); - if (err) - goto err_destroy_direct_tirs; - - return 0; - -err_destroy_direct_tirs: - mlx5e_destroy_direct_tirs(priv); -err_destroy_indirect_tirs: - mlx5e_destroy_indirect_tirs(priv); -err_destroy_direct_rqts: - mlx5e_destroy_direct_rqts(priv); -err_destroy_indirect_rqts: - mlx5e_destroy_rqt(priv, &priv->indir_rqt); - return err; -} - -static void mlx5i_cleanup_rx(struct mlx5e_priv *priv) -{ - mlx5i_destroy_flow_steering(priv); - mlx5e_destroy_direct_tirs(priv); - mlx5e_destroy_indirect_tirs(priv); - mlx5e_destroy_direct_rqts(priv); - mlx5e_destroy_rqt(priv, &priv->indir_rqt); -} - -static const struct mlx5e_profile mlx5i_nic_profile = { - .init = mlx5i_init, - .cleanup = mlx5i_cleanup, - .init_tx = mlx5i_init_tx, - .cleanup_tx = mlx5i_cleanup_tx, - .init_rx = mlx5i_init_rx, - .cleanup_rx = mlx5i_cleanup_rx, - .enable = NULL, /* mlx5i_enable */ - .disable = NULL, /* mlx5i_disable */ - .update_stats = NULL, /* mlx5i_update_stats */ - .max_nch = mlx5e_get_max_num_channels, - .rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe, - .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */ - .max_tc = MLX5I_MAX_NUM_TC, -}; - -/* mlx5i netdev NDos */ - -static int mlx5i_dev_init(struct net_device *dev) -{ - struct mlx5e_priv *priv = mlx5i_epriv(dev); - struct mlx5i_priv *ipriv = priv->ppriv; - - /* Set dev address using underlay QP */ - dev->dev_addr[1] = (ipriv->qp.qpn >> 16) & 0xff; - dev->dev_addr[2] = (ipriv->qp.qpn >> 8) & 0xff; - dev->dev_addr[3] = (ipriv->qp.qpn) & 0xff; - - return 0; -} - -static void mlx5i_dev_cleanup(struct net_device *dev) -{ - struct mlx5e_priv *priv = mlx5i_epriv(dev); - struct mlx5_core_dev *mdev = priv->mdev; - struct mlx5i_priv *ipriv = priv->ppriv; - struct mlx5_qp_context context; - - /* detach qp from flow-steering by reset it */ - mlx5_core_qp_modify(mdev, MLX5_CMD_OP_2RST_QP, 0, &context, &ipriv->qp); -} - -static int mlx5i_open(struct net_device *netdev) -{ - struct mlx5e_priv *priv = mlx5i_epriv(netdev); - int err; - - mutex_lock(&priv->state_lock); - - set_bit(MLX5E_STATE_OPENED, &priv->state); - - err = mlx5e_open_channels(priv, &priv->channels); - if (err) - goto err_clear_state_opened_flag; - - mlx5e_refresh_tirs(priv, false); - mlx5e_activate_priv_channels(priv); - mutex_unlock(&priv->state_lock); - return 0; - -err_clear_state_opened_flag: - clear_bit(MLX5E_STATE_OPENED, &priv->state); - mutex_unlock(&priv->state_lock); - return err; -} - -static int mlx5i_close(struct net_device *netdev) -{ - struct mlx5e_priv *priv = mlx5i_epriv(netdev); - - /* May already be CLOSED in case a previous configuration operation - * (e.g RX/TX queue size change) that involves close&open failed. - */ - mutex_lock(&priv->state_lock); - - if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) - goto unlock; - - clear_bit(MLX5E_STATE_OPENED, &priv->state); - - netif_carrier_off(priv->netdev); - mlx5e_deactivate_priv_channels(priv); - mlx5e_close_channels(&priv->channels); -unlock: - mutex_unlock(&priv->state_lock); - return 0; -} - -/* IPoIB RDMA netdev callbacks */ -static int mlx5i_attach_mcast(struct net_device *netdev, struct ib_device *hca, - union ib_gid *gid, u16 lid, int set_qkey, - u32 qkey) -{ - struct mlx5e_priv *epriv = mlx5i_epriv(netdev); - struct mlx5_core_dev *mdev = epriv->mdev; - struct mlx5i_priv *ipriv = epriv->ppriv; - int err; - - mlx5_core_dbg(mdev, "attaching QPN 0x%x, MGID %pI6\n", ipriv->qp.qpn, gid->raw); - err = mlx5_core_attach_mcg(mdev, gid, ipriv->qp.qpn); - if (err) - mlx5_core_warn(mdev, "failed attaching QPN 0x%x, MGID %pI6\n", - ipriv->qp.qpn, gid->raw); - - if (set_qkey) { - mlx5_core_dbg(mdev, "%s setting qkey 0x%x\n", - netdev->name, qkey); - ipriv->qkey = qkey; - } - - return err; -} - -static int mlx5i_detach_mcast(struct net_device *netdev, struct ib_device *hca, - union ib_gid *gid, u16 lid) -{ - struct mlx5e_priv *epriv = mlx5i_epriv(netdev); - struct mlx5_core_dev *mdev = epriv->mdev; - struct mlx5i_priv *ipriv = epriv->ppriv; - int err; - - mlx5_core_dbg(mdev, "detaching QPN 0x%x, MGID %pI6\n", ipriv->qp.qpn, gid->raw); - - err = mlx5_core_detach_mcg(mdev, gid, ipriv->qp.qpn); - if (err) - mlx5_core_dbg(mdev, "failed dettaching QPN 0x%x, MGID %pI6\n", - ipriv->qp.qpn, gid->raw); - - return err; -} - -static int mlx5i_xmit(struct net_device *dev, struct sk_buff *skb, - struct ib_ah *address, u32 dqpn) -{ - struct mlx5e_priv *epriv = mlx5i_epriv(dev); - struct mlx5e_txqsq *sq = epriv->txq2sq[skb_get_queue_mapping(skb)]; - struct mlx5_ib_ah *mah = to_mah(address); - struct mlx5i_priv *ipriv = epriv->ppriv; - - return mlx5i_sq_xmit(sq, skb, &mah->av, dqpn, ipriv->qkey); -} - -static int mlx5i_check_required_hca_cap(struct mlx5_core_dev *mdev) -{ - if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_IB) - return -EOPNOTSUPP; - - if (!MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads)) { - mlx5_core_warn(mdev, "IPoIB enhanced offloads are not supported\n"); - return -EOPNOTSUPP; - } - - return 0; -} - -struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev, - struct ib_device *ibdev, - const char *name, - void (*setup)(struct net_device *)) -{ - const struct mlx5e_profile *profile = &mlx5i_nic_profile; - int nch = profile->max_nch(mdev); - struct net_device *netdev; - struct mlx5i_priv *ipriv; - struct mlx5e_priv *epriv; - struct rdma_netdev *rn; - int err; - - if (mlx5i_check_required_hca_cap(mdev)) { - mlx5_core_warn(mdev, "Accelerated mode is not supported\n"); - return ERR_PTR(-EOPNOTSUPP); - } - - /* This function should only be called once per mdev */ - err = mlx5e_create_mdev_resources(mdev); - if (err) - return NULL; - - netdev = alloc_netdev_mqs(sizeof(struct mlx5i_priv) + sizeof(struct mlx5e_priv), - name, NET_NAME_UNKNOWN, - setup, - nch * MLX5E_MAX_NUM_TC, - nch); - if (!netdev) { - mlx5_core_warn(mdev, "alloc_netdev_mqs failed\n"); - goto free_mdev_resources; - } - - ipriv = netdev_priv(netdev); - epriv = mlx5i_epriv(netdev); - - epriv->wq = create_singlethread_workqueue("mlx5i"); - if (!epriv->wq) - goto err_free_netdev; - - profile->init(mdev, netdev, profile, ipriv); - - mlx5e_attach_netdev(epriv); - netif_carrier_off(netdev); - - /* set rdma_netdev func pointers */ - rn = &ipriv->rn; - rn->hca = ibdev; - rn->send = mlx5i_xmit; - rn->attach_mcast = mlx5i_attach_mcast; - rn->detach_mcast = mlx5i_detach_mcast; - - return netdev; - -err_free_netdev: - free_netdev(netdev); -free_mdev_resources: - mlx5e_destroy_mdev_resources(mdev); - - return NULL; -} -EXPORT_SYMBOL(mlx5_rdma_netdev_alloc); - -void mlx5_rdma_netdev_free(struct net_device *netdev) -{ - struct mlx5e_priv *priv = mlx5i_epriv(netdev); - const struct mlx5e_profile *profile = priv->profile; - - mlx5e_detach_netdev(priv); - profile->cleanup(priv); - destroy_workqueue(priv->wq); - free_netdev(netdev); - - mlx5e_destroy_mdev_resources(priv->mdev); -} -EXPORT_SYMBOL(mlx5_rdma_netdev_free); - diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib.h deleted file mode 100644 index 213191a78464..000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017, Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __MLX5E_IPOB_H__ -#define __MLX5E_IPOB_H__ - -#include -#include "en.h" - -#define MLX5I_MAX_NUM_TC 1 - -/* ipoib rdma netdev's private data structure */ -struct mlx5i_priv { - struct rdma_netdev rn; /* keep this first */ - struct mlx5_core_qp qp; - u32 qkey; - char *mlx5e_priv[0]; -}; - -/* Extract mlx5e_priv from IPoIB netdev */ -#define mlx5i_epriv(netdev) ((void *)(((struct mlx5i_priv *)netdev_priv(netdev))->mlx5e_priv)) - -netdev_tx_t mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb, - struct mlx5_av *av, u32 dqpn, u32 dqkey); -void mlx5i_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); - -#endif /* __MLX5E_IPOB_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c new file mode 100644 index 000000000000..22ca59145e6c --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2017, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "en.h" +#include "ipoib.h" + +#define IB_DEFAULT_Q_KEY 0xb1b + +static int mlx5i_open(struct net_device *netdev); +static int mlx5i_close(struct net_device *netdev); +static int mlx5i_dev_init(struct net_device *dev); +static void mlx5i_dev_cleanup(struct net_device *dev); + +static const struct net_device_ops mlx5i_netdev_ops = { + .ndo_open = mlx5i_open, + .ndo_stop = mlx5i_close, + .ndo_init = mlx5i_dev_init, + .ndo_uninit = mlx5i_dev_cleanup, +}; + +/* IPoIB mlx5 netdev profile */ + +/* Called directly after IPoIB netdevice was created to initialize SW structs */ +static void mlx5i_init(struct mlx5_core_dev *mdev, + struct net_device *netdev, + const struct mlx5e_profile *profile, + void *ppriv) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + + priv->mdev = mdev; + priv->netdev = netdev; + priv->profile = profile; + priv->ppriv = ppriv; + + mlx5e_build_nic_params(mdev, &priv->channels.params, profile->max_nch(mdev)); + + /* Override RQ params as IPoIB supports only LINKED LIST RQ for now */ + mlx5e_set_rq_type_params(mdev, &priv->channels.params, MLX5_WQ_TYPE_LINKED_LIST); + priv->channels.params.lro_en = false; + + mutex_init(&priv->state_lock); + + netdev->hw_features |= NETIF_F_SG; + netdev->hw_features |= NETIF_F_IP_CSUM; + netdev->hw_features |= NETIF_F_IPV6_CSUM; + netdev->hw_features |= NETIF_F_GRO; + netdev->hw_features |= NETIF_F_TSO; + netdev->hw_features |= NETIF_F_TSO6; + netdev->hw_features |= NETIF_F_RXCSUM; + netdev->hw_features |= NETIF_F_RXHASH; + + netdev->netdev_ops = &mlx5i_netdev_ops; +} + +/* Called directly before IPoIB netdevice is destroyed to cleanup SW structs */ +static void mlx5i_cleanup(struct mlx5e_priv *priv) +{ + /* Do nothing .. */ +} + +#define MLX5_QP_ENHANCED_ULP_STATELESS_MODE 2 + +static int mlx5i_create_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *qp) +{ + struct mlx5_qp_context *context = NULL; + u32 *in = NULL; + void *addr_path; + int ret = 0; + int inlen; + void *qpc; + + inlen = MLX5_ST_SZ_BYTES(create_qp_in); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); + MLX5_SET(qpc, qpc, st, MLX5_QP_ST_UD); + MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); + MLX5_SET(qpc, qpc, ulp_stateless_offload_mode, + MLX5_QP_ENHANCED_ULP_STATELESS_MODE); + + addr_path = MLX5_ADDR_OF(qpc, qpc, primary_address_path); + MLX5_SET(ads, addr_path, port, 1); + MLX5_SET(ads, addr_path, grh, 1); + + ret = mlx5_core_create_qp(mdev, qp, in, inlen); + if (ret) { + mlx5_core_err(mdev, "Failed creating IPoIB QP err : %d\n", ret); + goto out; + } + + /* QP states */ + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) { + ret = -ENOMEM; + goto out; + } + + context->flags = cpu_to_be32(MLX5_QP_PM_MIGRATED << 11); + context->pri_path.port = 1; + context->qkey = cpu_to_be32(IB_DEFAULT_Q_KEY); + + ret = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_RST2INIT_QP, 0, context, qp); + if (ret) { + mlx5_core_err(mdev, "Failed to modify qp RST2INIT, err: %d\n", ret); + goto out; + } + memset(context, 0, sizeof(*context)); + + ret = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_INIT2RTR_QP, 0, context, qp); + if (ret) { + mlx5_core_err(mdev, "Failed to modify qp INIT2RTR, err: %d\n", ret); + goto out; + } + + ret = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_RTR2RTS_QP, 0, context, qp); + if (ret) { + mlx5_core_err(mdev, "Failed to modify qp RTR2RTS, err: %d\n", ret); + goto out; + } + +out: + kfree(context); + kvfree(in); + return ret; +} + +static void mlx5i_destroy_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *qp) +{ + mlx5_fs_remove_rx_underlay_qpn(mdev, qp->qpn); + + mlx5_core_destroy_qp(mdev, qp); +} + +static int mlx5i_init_tx(struct mlx5e_priv *priv) +{ + struct mlx5i_priv *ipriv = priv->ppriv; + int err; + + err = mlx5i_create_underlay_qp(priv->mdev, &ipriv->qp); + if (err) { + mlx5_core_warn(priv->mdev, "create underlay QP failed, %d\n", err); + return err; + } + + mlx5_fs_add_rx_underlay_qpn(priv->mdev, ipriv->qp.qpn); + + err = mlx5e_create_tis(priv->mdev, 0 /* tc */, ipriv->qp.qpn, &priv->tisn[0]); + if (err) { + mlx5_core_warn(priv->mdev, "create tis failed, %d\n", err); + return err; + } + + return 0; +} + +static void mlx5i_cleanup_tx(struct mlx5e_priv *priv) +{ + struct mlx5i_priv *ipriv = priv->ppriv; + + mlx5e_destroy_tis(priv->mdev, priv->tisn[0]); + mlx5i_destroy_underlay_qp(priv->mdev, &ipriv->qp); +} + +static int mlx5i_create_flow_steering(struct mlx5e_priv *priv) +{ + int err; + + priv->fs.ns = mlx5_get_flow_namespace(priv->mdev, + MLX5_FLOW_NAMESPACE_KERNEL); + + if (!priv->fs.ns) + return -EINVAL; + + err = mlx5e_arfs_create_tables(priv); + if (err) { + netdev_err(priv->netdev, "Failed to create arfs tables, err=%d\n", + err); + priv->netdev->hw_features &= ~NETIF_F_NTUPLE; + } + + err = mlx5e_create_ttc_table(priv); + if (err) { + netdev_err(priv->netdev, "Failed to create ttc table, err=%d\n", + err); + goto err_destroy_arfs_tables; + } + + return 0; + +err_destroy_arfs_tables: + mlx5e_arfs_destroy_tables(priv); + + return err; +} + +static void mlx5i_destroy_flow_steering(struct mlx5e_priv *priv) +{ + mlx5e_destroy_ttc_table(priv); + mlx5e_arfs_destroy_tables(priv); +} + +static int mlx5i_init_rx(struct mlx5e_priv *priv) +{ + int err; + + err = mlx5e_create_indirect_rqt(priv); + if (err) + return err; + + err = mlx5e_create_direct_rqts(priv); + if (err) + goto err_destroy_indirect_rqts; + + err = mlx5e_create_indirect_tirs(priv); + if (err) + goto err_destroy_direct_rqts; + + err = mlx5e_create_direct_tirs(priv); + if (err) + goto err_destroy_indirect_tirs; + + err = mlx5i_create_flow_steering(priv); + if (err) + goto err_destroy_direct_tirs; + + return 0; + +err_destroy_direct_tirs: + mlx5e_destroy_direct_tirs(priv); +err_destroy_indirect_tirs: + mlx5e_destroy_indirect_tirs(priv); +err_destroy_direct_rqts: + mlx5e_destroy_direct_rqts(priv); +err_destroy_indirect_rqts: + mlx5e_destroy_rqt(priv, &priv->indir_rqt); + return err; +} + +static void mlx5i_cleanup_rx(struct mlx5e_priv *priv) +{ + mlx5i_destroy_flow_steering(priv); + mlx5e_destroy_direct_tirs(priv); + mlx5e_destroy_indirect_tirs(priv); + mlx5e_destroy_direct_rqts(priv); + mlx5e_destroy_rqt(priv, &priv->indir_rqt); +} + +static const struct mlx5e_profile mlx5i_nic_profile = { + .init = mlx5i_init, + .cleanup = mlx5i_cleanup, + .init_tx = mlx5i_init_tx, + .cleanup_tx = mlx5i_cleanup_tx, + .init_rx = mlx5i_init_rx, + .cleanup_rx = mlx5i_cleanup_rx, + .enable = NULL, /* mlx5i_enable */ + .disable = NULL, /* mlx5i_disable */ + .update_stats = NULL, /* mlx5i_update_stats */ + .max_nch = mlx5e_get_max_num_channels, + .rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe, + .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */ + .max_tc = MLX5I_MAX_NUM_TC, +}; + +/* mlx5i netdev NDos */ + +static int mlx5i_dev_init(struct net_device *dev) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + struct mlx5i_priv *ipriv = priv->ppriv; + + /* Set dev address using underlay QP */ + dev->dev_addr[1] = (ipriv->qp.qpn >> 16) & 0xff; + dev->dev_addr[2] = (ipriv->qp.qpn >> 8) & 0xff; + dev->dev_addr[3] = (ipriv->qp.qpn) & 0xff; + + return 0; +} + +static void mlx5i_dev_cleanup(struct net_device *dev) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5i_priv *ipriv = priv->ppriv; + struct mlx5_qp_context context; + + /* detach qp from flow-steering by reset it */ + mlx5_core_qp_modify(mdev, MLX5_CMD_OP_2RST_QP, 0, &context, &ipriv->qp); +} + +static int mlx5i_open(struct net_device *netdev) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + int err; + + mutex_lock(&priv->state_lock); + + set_bit(MLX5E_STATE_OPENED, &priv->state); + + err = mlx5e_open_channels(priv, &priv->channels); + if (err) + goto err_clear_state_opened_flag; + + mlx5e_refresh_tirs(priv, false); + mlx5e_activate_priv_channels(priv); + mutex_unlock(&priv->state_lock); + return 0; + +err_clear_state_opened_flag: + clear_bit(MLX5E_STATE_OPENED, &priv->state); + mutex_unlock(&priv->state_lock); + return err; +} + +static int mlx5i_close(struct net_device *netdev) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + + /* May already be CLOSED in case a previous configuration operation + * (e.g RX/TX queue size change) that involves close&open failed. + */ + mutex_lock(&priv->state_lock); + + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) + goto unlock; + + clear_bit(MLX5E_STATE_OPENED, &priv->state); + + netif_carrier_off(priv->netdev); + mlx5e_deactivate_priv_channels(priv); + mlx5e_close_channels(&priv->channels); +unlock: + mutex_unlock(&priv->state_lock); + return 0; +} + +/* IPoIB RDMA netdev callbacks */ +static int mlx5i_attach_mcast(struct net_device *netdev, struct ib_device *hca, + union ib_gid *gid, u16 lid, int set_qkey, + u32 qkey) +{ + struct mlx5e_priv *epriv = mlx5i_epriv(netdev); + struct mlx5_core_dev *mdev = epriv->mdev; + struct mlx5i_priv *ipriv = epriv->ppriv; + int err; + + mlx5_core_dbg(mdev, "attaching QPN 0x%x, MGID %pI6\n", ipriv->qp.qpn, gid->raw); + err = mlx5_core_attach_mcg(mdev, gid, ipriv->qp.qpn); + if (err) + mlx5_core_warn(mdev, "failed attaching QPN 0x%x, MGID %pI6\n", + ipriv->qp.qpn, gid->raw); + + if (set_qkey) { + mlx5_core_dbg(mdev, "%s setting qkey 0x%x\n", + netdev->name, qkey); + ipriv->qkey = qkey; + } + + return err; +} + +static int mlx5i_detach_mcast(struct net_device *netdev, struct ib_device *hca, + union ib_gid *gid, u16 lid) +{ + struct mlx5e_priv *epriv = mlx5i_epriv(netdev); + struct mlx5_core_dev *mdev = epriv->mdev; + struct mlx5i_priv *ipriv = epriv->ppriv; + int err; + + mlx5_core_dbg(mdev, "detaching QPN 0x%x, MGID %pI6\n", ipriv->qp.qpn, gid->raw); + + err = mlx5_core_detach_mcg(mdev, gid, ipriv->qp.qpn); + if (err) + mlx5_core_dbg(mdev, "failed dettaching QPN 0x%x, MGID %pI6\n", + ipriv->qp.qpn, gid->raw); + + return err; +} + +static int mlx5i_xmit(struct net_device *dev, struct sk_buff *skb, + struct ib_ah *address, u32 dqpn) +{ + struct mlx5e_priv *epriv = mlx5i_epriv(dev); + struct mlx5e_txqsq *sq = epriv->txq2sq[skb_get_queue_mapping(skb)]; + struct mlx5_ib_ah *mah = to_mah(address); + struct mlx5i_priv *ipriv = epriv->ppriv; + + return mlx5i_sq_xmit(sq, skb, &mah->av, dqpn, ipriv->qkey); +} + +static int mlx5i_check_required_hca_cap(struct mlx5_core_dev *mdev) +{ + if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_IB) + return -EOPNOTSUPP; + + if (!MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads)) { + mlx5_core_warn(mdev, "IPoIB enhanced offloads are not supported\n"); + return -EOPNOTSUPP; + } + + return 0; +} + +struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev, + struct ib_device *ibdev, + const char *name, + void (*setup)(struct net_device *)) +{ + const struct mlx5e_profile *profile = &mlx5i_nic_profile; + int nch = profile->max_nch(mdev); + struct net_device *netdev; + struct mlx5i_priv *ipriv; + struct mlx5e_priv *epriv; + struct rdma_netdev *rn; + int err; + + if (mlx5i_check_required_hca_cap(mdev)) { + mlx5_core_warn(mdev, "Accelerated mode is not supported\n"); + return ERR_PTR(-EOPNOTSUPP); + } + + /* This function should only be called once per mdev */ + err = mlx5e_create_mdev_resources(mdev); + if (err) + return NULL; + + netdev = alloc_netdev_mqs(sizeof(struct mlx5i_priv) + sizeof(struct mlx5e_priv), + name, NET_NAME_UNKNOWN, + setup, + nch * MLX5E_MAX_NUM_TC, + nch); + if (!netdev) { + mlx5_core_warn(mdev, "alloc_netdev_mqs failed\n"); + goto free_mdev_resources; + } + + ipriv = netdev_priv(netdev); + epriv = mlx5i_epriv(netdev); + + epriv->wq = create_singlethread_workqueue("mlx5i"); + if (!epriv->wq) + goto err_free_netdev; + + profile->init(mdev, netdev, profile, ipriv); + + mlx5e_attach_netdev(epriv); + netif_carrier_off(netdev); + + /* set rdma_netdev func pointers */ + rn = &ipriv->rn; + rn->hca = ibdev; + rn->send = mlx5i_xmit; + rn->attach_mcast = mlx5i_attach_mcast; + rn->detach_mcast = mlx5i_detach_mcast; + + return netdev; + +err_free_netdev: + free_netdev(netdev); +free_mdev_resources: + mlx5e_destroy_mdev_resources(mdev); + + return NULL; +} +EXPORT_SYMBOL(mlx5_rdma_netdev_alloc); + +void mlx5_rdma_netdev_free(struct net_device *netdev) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + const struct mlx5e_profile *profile = priv->profile; + + mlx5e_detach_netdev(priv); + profile->cleanup(priv); + destroy_workqueue(priv->wq); + free_netdev(netdev); + + mlx5e_destroy_mdev_resources(priv->mdev); +} +EXPORT_SYMBOL(mlx5_rdma_netdev_free); + diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h new file mode 100644 index 000000000000..213191a78464 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __MLX5E_IPOB_H__ +#define __MLX5E_IPOB_H__ + +#include +#include "en.h" + +#define MLX5I_MAX_NUM_TC 1 + +/* ipoib rdma netdev's private data structure */ +struct mlx5i_priv { + struct rdma_netdev rn; /* keep this first */ + struct mlx5_core_qp qp; + u32 qkey; + char *mlx5e_priv[0]; +}; + +/* Extract mlx5e_priv from IPoIB netdev */ +#define mlx5i_epriv(netdev) ((void *)(((struct mlx5i_priv *)netdev_priv(netdev))->mlx5e_priv)) + +netdev_tx_t mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb, + struct mlx5_av *av, u32 dqpn, u32 dqkey); +void mlx5i_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); + +#endif /* __MLX5E_IPOB_H__ */ -- cgit v1.2.3 From c66f2091c9248ddf42504c74cd327ae8619b04a4 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Sun, 4 Jun 2017 17:45:02 +0300 Subject: net/mlx5e: Prevent PFC call for non ethernet ports Port flow control supported only for ethernet ports, therefore, prevent any call if the port type differs from MLX5_CAP_PORT_TYPE_ETH. Signed-off-by: Feras Daoud Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 216752070391..7408c298ce2f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -135,6 +135,9 @@ static unsigned long mlx5e_query_pfc_combined(struct mlx5e_priv *priv) u8 pfc_en_rx; int err; + if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) + return 0; + err = mlx5_query_port_pfc(mdev, &pfc_en_tx, &pfc_en_rx); return err ? 0 : pfc_en_tx | pfc_en_rx; @@ -147,6 +150,9 @@ static bool mlx5e_query_global_pause_combined(struct mlx5e_priv *priv) u32 tx_pause; int err; + if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) + return false; + err = mlx5_query_port_pause(mdev, &rx_pause, &tx_pause); return err ? false : rx_pause | tx_pause; -- cgit v1.2.3 From 076b0936e5fb8dd5513c1472a2c1d487b64d1580 Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Mon, 15 May 2017 13:32:28 +0300 Subject: net/mlx5e: IPoIB, Add ethtool support Add support for the following: "ethtool -S" (statistics). "ethtool -i" (driver info). "ethtool -g/G" (rings parameters). "ethtool -l/L" (channels parameters). "ethtool -c/C" (coalesce options). Signed-off-by: Erez Shitrit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en.h | 21 ++++ .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 138 +++++++++++++++------ .../ethernet/mellanox/mlx5/core/ipoib/ethtool.c | 127 +++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 2 +- .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h | 2 + 6 files changed, 255 insertions(+), 37 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 59b87b30e438..5ad093a21a6e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -15,4 +15,4 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o -mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o +mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 8094e78292de..49c5fe9fdff0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -1021,6 +1021,27 @@ int mlx5e_open(struct net_device *netdev); void mlx5e_update_stats_work(struct work_struct *work); u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeout); +/* ethtool helpers */ +void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv, + struct ethtool_drvinfo *drvinfo); +void mlx5e_ethtool_get_strings(struct mlx5e_priv *priv, + uint32_t stringset, uint8_t *data); +int mlx5e_ethtool_get_sset_count(struct mlx5e_priv *priv, int sset); +void mlx5e_ethtool_get_ethtool_stats(struct mlx5e_priv *priv, + struct ethtool_stats *stats, u64 *data); +void mlx5e_ethtool_get_ringparam(struct mlx5e_priv *priv, + struct ethtool_ringparam *param); +int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv, + struct ethtool_ringparam *param); +void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv, + struct ethtool_channels *ch); +int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv, + struct ethtool_channels *ch); +int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv, + struct ethtool_coalesce *coal); +int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv, + struct ethtool_coalesce *coal); + /* mlx5e generic netdev management API */ struct net_device* mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 7408c298ce2f..fa472c4d3d00 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -32,10 +32,9 @@ #include "en.h" -static void mlx5e_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *drvinfo) +void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv, + struct ethtool_drvinfo *drvinfo) { - struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5_core_dev *mdev = priv->mdev; strlcpy(drvinfo->driver, DRIVER_NAME, sizeof(drvinfo->driver)); @@ -49,6 +48,14 @@ static void mlx5e_get_drvinfo(struct net_device *dev, sizeof(drvinfo->bus_info)); } +static void mlx5e_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + mlx5e_ethtool_get_drvinfo(priv, drvinfo); +} + struct ptys2ethtool_config { __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); __ETHTOOL_DECLARE_LINK_MODE_MASK(advertised); @@ -166,9 +173,8 @@ static bool mlx5e_query_global_pause_combined(struct mlx5e_priv *priv) ((mlx5e_query_global_pause_combined(priv) + hweight8(mlx5e_query_pfc_combined(priv))) * \ NUM_PPORT_PER_PRIO_PFC_COUNTERS) -static int mlx5e_get_sset_count(struct net_device *dev, int sset) +int mlx5e_ethtool_get_sset_count(struct mlx5e_priv *priv, int sset) { - struct mlx5e_priv *priv = netdev_priv(dev); switch (sset) { case ETH_SS_STATS: @@ -192,6 +198,13 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset) } } +static int mlx5e_get_sset_count(struct net_device *dev, int sset) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + return mlx5e_ethtool_get_sset_count(priv, sset); +} + static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, uint8_t *data) { int i, j, tc, prio, idx = 0; @@ -279,10 +292,9 @@ static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, uint8_t *data) priv->channel_tc2txq[i][tc]); } -static void mlx5e_get_strings(struct net_device *dev, - uint32_t stringset, uint8_t *data) +void mlx5e_ethtool_get_strings(struct mlx5e_priv *priv, + uint32_t stringset, uint8_t *data) { - struct mlx5e_priv *priv = netdev_priv(dev); int i; switch (stringset) { @@ -303,10 +315,17 @@ static void mlx5e_get_strings(struct net_device *dev, } } -static void mlx5e_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) +static void mlx5e_get_strings(struct net_device *dev, + uint32_t stringset, uint8_t *data) { struct mlx5e_priv *priv = netdev_priv(dev); + + mlx5e_ethtool_get_strings(priv, stringset, data); +} + +void mlx5e_ethtool_get_ethtool_stats(struct mlx5e_priv *priv, + struct ethtool_stats *stats, u64 *data) +{ struct mlx5e_channels *channels; struct mlx5_priv *mlx5_priv; int i, j, tc, prio, idx = 0; @@ -401,6 +420,15 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev, sq_stats_desc, j); } +static void mlx5e_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + u64 *data) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + mlx5e_ethtool_get_ethtool_stats(priv, stats, data); +} + static u32 mlx5e_rx_wqes_to_packets(struct mlx5e_priv *priv, int rq_wq_type, int num_wqe) { @@ -445,10 +473,9 @@ static u32 mlx5e_packets_to_rx_wqes(struct mlx5e_priv *priv, int rq_wq_type, return 1 << (order_base_2(num_wqes)); } -static void mlx5e_get_ringparam(struct net_device *dev, - struct ethtool_ringparam *param) +void mlx5e_ethtool_get_ringparam(struct mlx5e_priv *priv, + struct ethtool_ringparam *param) { - struct mlx5e_priv *priv = netdev_priv(dev); int rq_wq_type = priv->channels.params.rq_wq_type; param->rx_max_pending = mlx5e_rx_wqes_to_packets(priv, rq_wq_type, @@ -459,10 +486,17 @@ static void mlx5e_get_ringparam(struct net_device *dev, param->tx_pending = 1 << priv->channels.params.log_sq_size; } -static int mlx5e_set_ringparam(struct net_device *dev, - struct ethtool_ringparam *param) +static void mlx5e_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) { struct mlx5e_priv *priv = netdev_priv(dev); + + mlx5e_ethtool_get_ringparam(priv, param); +} + +int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv, + struct ethtool_ringparam *param) +{ int rq_wq_type = priv->channels.params.rq_wq_type; struct mlx5e_channels new_channels = {}; u32 rx_pending_wqes; @@ -474,12 +508,12 @@ static int mlx5e_set_ringparam(struct net_device *dev, int err = 0; if (param->rx_jumbo_pending) { - netdev_info(dev, "%s: rx_jumbo_pending not supported\n", + netdev_info(priv->netdev, "%s: rx_jumbo_pending not supported\n", __func__); return -EINVAL; } if (param->rx_mini_pending) { - netdev_info(dev, "%s: rx_mini_pending not supported\n", + netdev_info(priv->netdev, "%s: rx_mini_pending not supported\n", __func__); return -EINVAL; } @@ -492,13 +526,13 @@ static int mlx5e_set_ringparam(struct net_device *dev, param->rx_pending); if (param->rx_pending < min_rq_size) { - netdev_info(dev, "%s: rx_pending (%d) < min (%d)\n", + netdev_info(priv->netdev, "%s: rx_pending (%d) < min (%d)\n", __func__, param->rx_pending, min_rq_size); return -EINVAL; } if (param->rx_pending > max_rq_size) { - netdev_info(dev, "%s: rx_pending (%d) > max (%d)\n", + netdev_info(priv->netdev, "%s: rx_pending (%d) > max (%d)\n", __func__, param->rx_pending, max_rq_size); return -EINVAL; @@ -507,19 +541,19 @@ static int mlx5e_set_ringparam(struct net_device *dev, num_mtts = MLX5E_REQUIRED_MTTS(rx_pending_wqes); if (priv->channels.params.rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ && !MLX5E_VALID_NUM_MTTS(num_mtts)) { - netdev_info(dev, "%s: rx_pending (%d) request can't be satisfied, try to reduce.\n", + netdev_info(priv->netdev, "%s: rx_pending (%d) request can't be satisfied, try to reduce.\n", __func__, param->rx_pending); return -EINVAL; } if (param->tx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { - netdev_info(dev, "%s: tx_pending (%d) < min (%d)\n", + netdev_info(priv->netdev, "%s: tx_pending (%d) < min (%d)\n", __func__, param->tx_pending, 1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); return -EINVAL; } if (param->tx_pending > (1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE)) { - netdev_info(dev, "%s: tx_pending (%d) > max (%d)\n", + netdev_info(priv->netdev, "%s: tx_pending (%d) > max (%d)\n", __func__, param->tx_pending, 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE); return -EINVAL; @@ -555,26 +589,39 @@ unlock: return err; } -static void mlx5e_get_channels(struct net_device *dev, - struct ethtool_channels *ch) +static int mlx5e_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) { struct mlx5e_priv *priv = netdev_priv(dev); + return mlx5e_ethtool_set_ringparam(priv, param); +} + +void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv, + struct ethtool_channels *ch) +{ ch->max_combined = priv->profile->max_nch(priv->mdev); ch->combined_count = priv->channels.params.num_channels; } -static int mlx5e_set_channels(struct net_device *dev, - struct ethtool_channels *ch) +static void mlx5e_get_channels(struct net_device *dev, + struct ethtool_channels *ch) { struct mlx5e_priv *priv = netdev_priv(dev); + + mlx5e_ethtool_get_channels(priv, ch); +} + +int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv, + struct ethtool_channels *ch) +{ unsigned int count = ch->combined_count; struct mlx5e_channels new_channels = {}; bool arfs_enabled; int err = 0; if (!count) { - netdev_info(dev, "%s: combined_count=0 not supported\n", + netdev_info(priv->netdev, "%s: combined_count=0 not supported\n", __func__); return -EINVAL; } @@ -599,7 +646,7 @@ static int mlx5e_set_channels(struct net_device *dev, if (err) goto out; - arfs_enabled = dev->features & NETIF_F_NTUPLE; + arfs_enabled = priv->netdev->features & NETIF_F_NTUPLE; if (arfs_enabled) mlx5e_arfs_disable(priv); @@ -609,7 +656,7 @@ static int mlx5e_set_channels(struct net_device *dev, if (arfs_enabled) { err = mlx5e_arfs_enable(priv); if (err) - netdev_err(dev, "%s: mlx5e_arfs_enable failed: %d\n", + netdev_err(priv->netdev, "%s: mlx5e_arfs_enable failed: %d\n", __func__, err); } @@ -619,11 +666,17 @@ out: return err; } -static int mlx5e_get_coalesce(struct net_device *netdev, - struct ethtool_coalesce *coal) +static int mlx5e_set_channels(struct net_device *dev, + struct ethtool_channels *ch) { - struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5e_priv *priv = netdev_priv(dev); + + return mlx5e_ethtool_set_channels(priv, ch); +} +int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv, + struct ethtool_coalesce *coal) +{ if (!MLX5_CAP_GEN(priv->mdev, cq_moderation)) return -EOPNOTSUPP; @@ -636,6 +689,14 @@ static int mlx5e_get_coalesce(struct net_device *netdev, return 0; } +static int mlx5e_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *coal) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + return mlx5e_ethtool_get_coalesce(priv, coal); +} + static void mlx5e_set_priv_channels_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal) { @@ -659,10 +720,9 @@ mlx5e_set_priv_channels_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesc } } -static int mlx5e_set_coalesce(struct net_device *netdev, - struct ethtool_coalesce *coal) +int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv, + struct ethtool_coalesce *coal) { - struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5_core_dev *mdev = priv->mdev; struct mlx5e_channels new_channels = {}; int err = 0; @@ -705,6 +765,14 @@ out: return err; } +static int mlx5e_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *coal) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + return mlx5e_ethtool_set_coalesce(priv, coal); +} + static void ptys2ethtool_supported_link(unsigned long *supported_modes, u32 eth_proto_cap) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c new file mode 100644 index 000000000000..20105eda2e11 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2017, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "en.h" +#include "ipoib.h" + +static void mlx5i_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + + mlx5e_ethtool_get_drvinfo(priv, drvinfo); +} + +static void mlx5i_get_strings(struct net_device *dev, + uint32_t stringset, uint8_t *data) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + + mlx5e_ethtool_get_strings(priv, stringset, data); +} + +static int mlx5i_get_sset_count(struct net_device *dev, int sset) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + + return mlx5e_ethtool_get_sset_count(priv, sset); +} + +static void mlx5i_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + u64 *data) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + + mlx5e_ethtool_get_ethtool_stats(priv, stats, data); +} + +static int mlx5i_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + + return mlx5e_ethtool_set_ringparam(priv, param); +} + +static void mlx5i_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + + mlx5e_ethtool_get_ringparam(priv, param); +} + +static int mlx5i_set_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + + return mlx5e_ethtool_set_channels(priv, ch); +} + +static void mlx5i_get_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + + mlx5e_ethtool_get_channels(priv, ch); +} + +static int mlx5i_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *coal) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + + return mlx5e_ethtool_set_coalesce(priv, coal); +} + +static int mlx5i_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *coal) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + + return mlx5e_ethtool_get_coalesce(priv, coal); +} + +const struct ethtool_ops mlx5i_ethtool_ops = { + .get_drvinfo = mlx5i_get_drvinfo, + .get_strings = mlx5i_get_strings, + .get_sset_count = mlx5i_get_sset_count, + .get_ethtool_stats = mlx5i_get_ethtool_stats, + .get_ringparam = mlx5i_get_ringparam, + .set_ringparam = mlx5i_set_ringparam, + .get_channels = mlx5i_get_channels, + .set_channels = mlx5i_set_channels, + .get_coalesce = mlx5i_get_coalesce, + .set_coalesce = mlx5i_set_coalesce, +}; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 22ca59145e6c..fdeb426d4751 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -82,6 +82,7 @@ static void mlx5i_init(struct mlx5_core_dev *mdev, netdev->hw_features |= NETIF_F_RXHASH; netdev->netdev_ops = &mlx5i_netdev_ops; + netdev->ethtool_ops = &mlx5i_ethtool_ops; } /* Called directly before IPoIB netdevice is destroyed to cleanup SW structs */ @@ -510,4 +511,3 @@ void mlx5_rdma_netdev_free(struct net_device *netdev) mlx5e_destroy_mdev_resources(priv->mdev); } EXPORT_SYMBOL(mlx5_rdma_netdev_free); - diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h index 213191a78464..3553a06c8fa6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h @@ -38,6 +38,8 @@ #define MLX5I_MAX_NUM_TC 1 +extern const struct ethtool_ops mlx5i_ethtool_ops; + /* ipoib rdma netdev's private data structure */ struct mlx5i_priv { struct rdma_netdev rn; /* keep this first */ -- cgit v1.2.3 From 7ca42c8094a4e265b8007a6776380f57cf093624 Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Thu, 18 May 2017 14:32:11 +0300 Subject: net/mlx5e: Add new profile function update_carrier Updating the carrier involves specific HW setting, each profile should use its own function for that. Both IPoIB and VF representor don't need carrier update function, since VF representor has only a logical link to VF and IPoIB manages its own link via ib_core upper layer. Signed-off-by: Erez Shitrit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 14 ++++++++++---- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 1 + drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 2 ++ 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 49c5fe9fdff0..a223a8e15ece 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -782,6 +782,7 @@ struct mlx5e_profile { void (*enable)(struct mlx5e_priv *priv); void (*disable)(struct mlx5e_priv *priv); void (*update_stats)(struct mlx5e_priv *priv); + void (*update_carrier)(struct mlx5e_priv *priv); int (*max_nch)(struct mlx5_core_dev *mdev); struct { mlx5e_fp_handle_rx_cqe handle_rx_cqe; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 06eb7a8b487c..343be65621db 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -143,7 +143,8 @@ static void mlx5e_update_carrier_work(struct work_struct *work) mutex_lock(&priv->state_lock); if (test_bit(MLX5E_STATE_OPENED, &priv->state)) - mlx5e_update_carrier(priv); + if (priv->profile->update_carrier) + priv->profile->update_carrier(priv); mutex_unlock(&priv->state_lock); } @@ -2598,9 +2599,10 @@ void mlx5e_switch_priv_channels(struct mlx5e_priv *priv, { struct net_device *netdev = priv->netdev; int new_num_txqs; - + int carrier_ok; new_num_txqs = new_chs->num * new_chs->params.num_tc; + carrier_ok = netif_carrier_ok(netdev); netif_carrier_off(netdev); if (new_num_txqs < netdev->real_num_tx_queues) @@ -2618,7 +2620,9 @@ void mlx5e_switch_priv_channels(struct mlx5e_priv *priv, mlx5e_refresh_tirs(priv, false); mlx5e_activate_priv_channels(priv); - mlx5e_update_carrier(priv); + /* return carrier back if needed */ + if (carrier_ok) + netif_carrier_on(netdev); } int mlx5e_open_locked(struct net_device *netdev) @@ -2634,7 +2638,8 @@ int mlx5e_open_locked(struct net_device *netdev) mlx5e_refresh_tirs(priv, false); mlx5e_activate_priv_channels(priv); - mlx5e_update_carrier(priv); + if (priv->profile->update_carrier) + priv->profile->update_carrier(priv); mlx5e_timestamp_init(priv); if (priv->profile->update_stats) @@ -4215,6 +4220,7 @@ static const struct mlx5e_profile mlx5e_nic_profile = { .disable = mlx5e_nic_disable, .update_stats = mlx5e_update_ndo_stats, .max_nch = mlx5e_get_max_num_channels, + .update_carrier = mlx5e_update_carrier, .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe, .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq, .max_tc = MLX5E_MAX_NUM_TC, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 01798e1ab667..a39873bd88a6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -916,6 +916,7 @@ static struct mlx5e_profile mlx5e_rep_profile = { .cleanup_tx = mlx5e_cleanup_nic_tx, .update_stats = mlx5e_rep_update_stats, .max_nch = mlx5e_get_rep_max_num_channels, + .update_carrier = NULL, .rx_handlers.handle_rx_cqe = mlx5e_handle_rx_cqe_rep, .rx_handlers.handle_rx_cqe_mpwqe = NULL /* Not supported */, .max_tc = 1, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index fdeb426d4751..cc9ff4014e5c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -291,6 +291,7 @@ static const struct mlx5e_profile mlx5i_nic_profile = { .disable = NULL, /* mlx5i_disable */ .update_stats = NULL, /* mlx5i_update_stats */ .max_nch = mlx5e_get_max_num_channels, + .update_carrier = NULL, /* no HW update in IB link */ .rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe, .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */ .max_tc = MLX5I_MAX_NUM_TC, @@ -337,6 +338,7 @@ static int mlx5i_open(struct net_device *netdev) mlx5e_refresh_tirs(priv, false); mlx5e_activate_priv_channels(priv); + mutex_unlock(&priv->state_lock); return 0; -- cgit v1.2.3 From b6dc510fac4796a57527667d47c48ef57a578dfc Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Thu, 18 May 2017 14:44:15 +0300 Subject: net/mlx5e: IPoIB, Change parameters default values Add function that sets the default values for ipoib, setting/clearing abilities that IPoIB doesn't support, like RQ size in this case. Signed-off-by: Erez Shitrit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index cc9ff4014e5c..45ca869118c0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -36,6 +36,7 @@ #include "ipoib.h" #define IB_DEFAULT_Q_KEY 0xb1b +#define MLX5I_PARAMS_DEFAULT_LOG_RQ_SIZE 9 static int mlx5i_open(struct net_device *netdev); static int mlx5i_close(struct net_device *netdev); @@ -50,6 +51,19 @@ static const struct net_device_ops mlx5i_netdev_ops = { }; /* IPoIB mlx5 netdev profile */ +static void mlx5i_build_nic_params(struct mlx5_core_dev *mdev, + struct mlx5e_params *params) +{ + /* Override RQ params as IPoIB supports only LINKED LIST RQ for now */ + mlx5e_set_rq_type_params(mdev, params, MLX5_WQ_TYPE_LINKED_LIST); + + /* RQ size in ipoib by default is 512 */ + params->log_rq_size = is_kdump_kernel() ? + MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE : + MLX5I_PARAMS_DEFAULT_LOG_RQ_SIZE; + + params->lro_en = false; +} /* Called directly after IPoIB netdevice was created to initialize SW structs */ static void mlx5i_init(struct mlx5_core_dev *mdev, @@ -65,10 +79,7 @@ static void mlx5i_init(struct mlx5_core_dev *mdev, priv->ppriv = ppriv; mlx5e_build_nic_params(mdev, &priv->channels.params, profile->max_nch(mdev)); - - /* Override RQ params as IPoIB supports only LINKED LIST RQ for now */ - mlx5e_set_rq_type_params(mdev, &priv->channels.params, MLX5_WQ_TYPE_LINKED_LIST); - priv->channels.params.lro_en = false; + mlx5i_build_nic_params(mdev, &priv->channels.params); mutex_init(&priv->state_lock); -- cgit v1.2.3 From c139dbfddd2c7848550ed06345060aa87701e818 Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Thu, 18 May 2017 17:03:21 +0300 Subject: net/mlx5e: Use hard_mtu as part of the mlx5e_priv struct The mtu extra space that kept for the HW is specific for each link type, and it is different in mlx5e and mlx5i modules. Now it is kept in the priv structures, set by the mlx5e/mlx5i driver accordingly. Signed-off-by: Erez Shitrit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 7 +++++-- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 10 ++++++---- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 3 +++ drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 6 +----- drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 6 ++++-- drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h | 5 +++++ 6 files changed, 24 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index a223a8e15ece..318ef7f0292f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -52,8 +52,10 @@ #define MLX5_SET_CFG(p, f, v) MLX5_SET(create_flow_group_in, p, f, v) -#define MLX5E_HW2SW_MTU(hwmtu) ((hwmtu) - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)) -#define MLX5E_SW2HW_MTU(swmtu) ((swmtu) + (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)) +#define MLX5E_ETH_HARD_MTU (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) + +#define MLX5E_HW2SW_MTU(priv, hwmtu) ((hwmtu) - ((priv)->hard_mtu)) +#define MLX5E_SW2HW_MTU(priv, swmtu) ((swmtu) + ((priv)->hard_mtu)) #define MLX5E_MAX_NUM_TC 8 @@ -747,6 +749,7 @@ struct mlx5e_priv { struct mlx5e_tir indir_tir[MLX5E_NUM_INDIR_TIRS]; struct mlx5e_tir direct_tir[MLX5E_MAX_NUM_CHANNELS]; u32 tx_rates[MLX5E_MAX_NUM_SQS]; + int hard_mtu; struct mlx5e_flow_steering fs; struct mlx5e_vxlan_db vxlan; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 343be65621db..de1e936fc2be 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -635,7 +635,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, rq->buff.wqe_sz = params->lro_en ? params->lro_wqe_sz : - MLX5E_SW2HW_MTU(c->netdev->mtu); + MLX5E_SW2HW_MTU(c->priv, c->netdev->mtu); byte_count = rq->buff.wqe_sz; /* calc the required page order */ @@ -2468,7 +2468,7 @@ free_in: static int mlx5e_set_mtu(struct mlx5e_priv *priv, u16 mtu) { struct mlx5_core_dev *mdev = priv->mdev; - u16 hw_mtu = MLX5E_SW2HW_MTU(mtu); + u16 hw_mtu = MLX5E_SW2HW_MTU(priv, mtu); int err; err = mlx5_set_port_mtu(mdev, hw_mtu, 1); @@ -2490,7 +2490,7 @@ static void mlx5e_query_mtu(struct mlx5e_priv *priv, u16 *mtu) if (err || !hw_mtu) /* fallback to port oper mtu */ mlx5_query_port_oper_mtu(mdev, &hw_mtu, 1); - *mtu = MLX5E_HW2SW_MTU(hw_mtu); + *mtu = MLX5E_HW2SW_MTU(priv, hw_mtu); } static int mlx5e_set_dev_port_mtu(struct mlx5e_priv *priv) @@ -3876,6 +3876,7 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev, mlx5e_set_rq_params(mdev, params); /* HW LRO */ + /* TODO: && MLX5_CAP_ETH(mdev, lro_cap) */ if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) params->lro_en = hw_lro_heuristic(link_speed, pci_bw); @@ -3916,6 +3917,7 @@ static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev, priv->netdev = netdev; priv->profile = profile; priv->ppriv = ppriv; + priv->hard_mtu = MLX5E_ETH_HARD_MTU; mlx5e_build_nic_params(mdev, &priv->channels.params, profile->max_nch(mdev)); @@ -4161,7 +4163,7 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv) /* MTU range: 68 - hw-specific max */ netdev->min_mtu = ETH_MIN_MTU; mlx5_query_port_max_mtu(priv->mdev, &max_mtu, 1); - netdev->max_mtu = MLX5E_HW2SW_MTU(max_mtu); + netdev->max_mtu = MLX5E_HW2SW_MTU(priv, max_mtu); mlx5e_set_dev_port_mtu(priv); mlx5_lag_add(mdev, netdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index a39873bd88a6..76cb6ad6e00b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -833,6 +833,9 @@ static void mlx5e_init_rep(struct mlx5_core_dev *mdev, INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); priv->channels.params.num_channels = profile->max_nch(mdev); + + priv->hard_mtu = MLX5E_ETH_HARD_MTU; + mlx5e_build_rep_params(mdev, &priv->channels.params); mlx5e_build_rep_netdev(netdev); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 806139d62139..da42d55939ed 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -648,7 +648,7 @@ static inline bool mlx5e_xmit_xdp_frame(struct mlx5e_rq *rq, prefetchw(wqe); if (unlikely(dma_len < MLX5E_XDP_MIN_INLINE || - MLX5E_SW2HW_MTU(rq->netdev->mtu) < dma_len)) { + MLX5E_SW2HW_MTU(rq->channel->priv, rq->netdev->mtu) < dma_len)) { rq->stats.xdp_drop++; mlx5e_page_release(rq, di, true); return false; @@ -1038,11 +1038,7 @@ void mlx5e_free_xdpsq_descs(struct mlx5e_xdpsq *sq) #ifdef CONFIG_MLX5_CORE_IPOIB #define MLX5_IB_GRH_DGID_OFFSET 24 -#define MLX5_IB_GRH_BYTES 40 -#define MLX5_IPOIB_ENCAP_LEN 4 #define MLX5_GID_SIZE 16 -#define MLX5_IPOIB_PSEUDO_LEN 20 -#define MLX5_IPOIB_HARD_LEN (MLX5_IPOIB_PSEUDO_LEN + MLX5_IPOIB_ENCAP_LEN) static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 45ca869118c0..9cf5f465caae 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -73,16 +73,18 @@ static void mlx5i_init(struct mlx5_core_dev *mdev, { struct mlx5e_priv *priv = mlx5i_epriv(netdev); + /* priv init */ priv->mdev = mdev; priv->netdev = netdev; priv->profile = profile; priv->ppriv = ppriv; + priv->hard_mtu = MLX5_IB_GRH_BYTES + MLX5_IPOIB_HARD_LEN; + mutex_init(&priv->state_lock); mlx5e_build_nic_params(mdev, &priv->channels.params, profile->max_nch(mdev)); mlx5i_build_nic_params(mdev, &priv->channels.params); - mutex_init(&priv->state_lock); - + /* netdev init */ netdev->hw_features |= NETIF_F_SG; netdev->hw_features |= NETIF_F_IP_CSUM; netdev->hw_features |= NETIF_F_IPV6_CSUM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h index 3553a06c8fa6..a0f405f520f7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h @@ -40,6 +40,11 @@ extern const struct ethtool_ops mlx5i_ethtool_ops; +#define MLX5_IB_GRH_BYTES 40 +#define MLX5_IPOIB_ENCAP_LEN 4 +#define MLX5_IPOIB_PSEUDO_LEN 20 +#define MLX5_IPOIB_HARD_LEN (MLX5_IPOIB_PSEUDO_LEN + MLX5_IPOIB_ENCAP_LEN) + /* ipoib rdma netdev's private data structure */ struct mlx5i_priv { struct rdma_netdev rn; /* keep this first */ -- cgit v1.2.3 From 807c4415974ff0d0bd101fd99ff6152feb22b0ac Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Sun, 21 May 2017 08:56:20 +0300 Subject: net/mlx5e: IPoIB, Handle change_mtu Add the ndo that supports change mtu for IPoIB. The callback called from the ipoib ULP driver, that gives the ability to change the SW and HW resources accordingly in the lower driver. Signed-off-by: Erez Shitrit Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 9cf5f465caae..52a58af571a2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -42,12 +42,14 @@ static int mlx5i_open(struct net_device *netdev); static int mlx5i_close(struct net_device *netdev); static int mlx5i_dev_init(struct net_device *dev); static void mlx5i_dev_cleanup(struct net_device *dev); +static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu); static const struct net_device_ops mlx5i_netdev_ops = { .ndo_open = mlx5i_open, .ndo_stop = mlx5i_close, .ndo_init = mlx5i_dev_init, .ndo_uninit = mlx5i_dev_cleanup, + .ndo_change_mtu = mlx5i_change_mtu, }; /* IPoIB mlx5 netdev profile */ @@ -312,6 +314,35 @@ static const struct mlx5e_profile mlx5i_nic_profile = { /* mlx5i netdev NDos */ +static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + struct mlx5e_channels new_channels = {}; + int curr_mtu; + int err = 0; + + mutex_lock(&priv->state_lock); + + curr_mtu = netdev->mtu; + netdev->mtu = new_mtu; + + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) + goto out; + + new_channels.params = priv->channels.params; + err = mlx5e_open_channels(priv, &new_channels); + if (err) { + netdev->mtu = curr_mtu; + goto out; + } + + mlx5e_switch_priv_channels(priv, &new_channels, NULL); + +out: + mutex_unlock(&priv->state_lock); + return err; +} + static int mlx5i_dev_init(struct net_device *dev) { struct mlx5e_priv *priv = mlx5i_epriv(dev); -- cgit v1.2.3 From 4ec5cf781b13ef9bcacfd96e108adb61629aa97a Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Sun, 21 May 2017 16:28:07 +0300 Subject: net/mlx5e: IPoIB, Get more TX statistics Add misses counters (bytes, packet, gso, xmit_more) in TX flow for ipoib traffic. Fixes: 58545449b7b ("net/mlx5e: IPoIB, Xmit flow") Signed-off-by: Erez Shitrit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 354f474322ce..0433d69429f3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -557,11 +557,16 @@ netdev_tx_t mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb, if (skb_is_gso(skb)) { opcode = MLX5_OPCODE_LSO; ihs = mlx5e_txwqe_build_eseg_gso(sq, skb, eseg, &num_bytes); + sq->stats.packets += skb_shinfo(skb)->gso_segs; } else { ihs = mlx5e_calc_min_inline(sq->min_inline_mode, skb); num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN); + sq->stats.packets++; } + sq->stats.bytes += num_bytes; + sq->stats.xmit_more += skb->xmit_more; + ds_cnt = sizeof(*wqe) / MLX5_SEND_WQE_DS; if (ihs) { memcpy(eseg->inline_hdr.start, skb_data, ihs); -- cgit v1.2.3 From 3844b07ee4c96d0cf8886611c21bb3a367b759e1 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Thu, 1 Jun 2017 14:43:43 +0300 Subject: net/mlx5e: IPoIB, Add PTP support to IPoIB device driver Enable PTP for IPoIB rdma_netdev and add the ability to get the time stamping parameters using ethtool. Signed-off-by: Feras Daoud Signed-off-by: Eitan Rabin Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 15 +++++++++++---- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 4 ++++ drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c | 9 +++++++++ drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 2 ++ 5 files changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 318ef7f0292f..626683f0f487 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -1045,6 +1045,8 @@ int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal); int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal); +int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv, + struct ethtool_ts_info *info); /* mlx5e generic netdev management API */ struct net_device* diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index fa472c4d3d00..ab46061f72ab 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -1372,13 +1372,12 @@ static int mlx5e_set_pauseparam(struct net_device *netdev, return err; } -static int mlx5e_get_ts_info(struct net_device *dev, - struct ethtool_ts_info *info) +int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv, + struct ethtool_ts_info *info) { - struct mlx5e_priv *priv = netdev_priv(dev); int ret; - ret = ethtool_op_get_ts_info(dev, info); + ret = ethtool_op_get_ts_info(priv->netdev, info); if (ret) return ret; @@ -1401,6 +1400,14 @@ static int mlx5e_get_ts_info(struct net_device *dev, return 0; } +static int mlx5e_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *info) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + return mlx5e_ethtool_get_ts_info(priv, info); +} + static __u32 mlx5e_get_wol_supported(struct mlx5_core_dev *mdev) { __u32 ret = 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index da42d55939ed..abf6d2fcfe0f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -1046,6 +1046,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq, struct sk_buff *skb) { struct net_device *netdev = rq->netdev; + struct mlx5e_tstamp *tstamp = rq->tstamp; char *pseudo_header; u8 *dgid; u8 g; @@ -1070,6 +1071,9 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq, skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = csum_unfold((__force __sum16)cqe->check_sum); + if (unlikely(mlx5e_rx_hw_stamp(tstamp))) + mlx5e_fill_hwstamp(tstamp, get_cqe_ts(cqe), skb_hwtstamps(skb)); + skb_record_rx_queue(skb, rq->ix); if (likely(netdev->features & NETIF_F_RXHASH)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c index 20105eda2e11..bf686f0fde5d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c @@ -113,6 +113,14 @@ static int mlx5i_get_coalesce(struct net_device *netdev, return mlx5e_ethtool_get_coalesce(priv, coal); } +static int mlx5i_get_ts_info(struct net_device *netdev, + struct ethtool_ts_info *info) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + + return mlx5e_ethtool_get_ts_info(priv, info); +} + const struct ethtool_ops mlx5i_ethtool_ops = { .get_drvinfo = mlx5i_get_drvinfo, .get_strings = mlx5i_get_strings, @@ -124,4 +132,5 @@ const struct ethtool_ops mlx5i_ethtool_ops = { .set_channels = mlx5i_set_channels, .get_coalesce = mlx5i_get_coalesce, .set_coalesce = mlx5i_set_coalesce, + .get_ts_info = mlx5i_get_ts_info, }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 52a58af571a2..58bf0665f50b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -382,6 +382,7 @@ static int mlx5i_open(struct net_device *netdev) mlx5e_refresh_tirs(priv, false); mlx5e_activate_priv_channels(priv); + mlx5e_timestamp_init(priv); mutex_unlock(&priv->state_lock); return 0; @@ -406,6 +407,7 @@ static int mlx5i_close(struct net_device *netdev) clear_bit(MLX5E_STATE_OPENED, &priv->state); + mlx5e_timestamp_cleanup(priv); netif_carrier_off(priv->netdev); mlx5e_deactivate_priv_channels(priv); mlx5e_close_channels(&priv->channels); -- cgit v1.2.3 From 1170fbd8ff43ff7808ae4a698054762b8bfae340 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Thu, 1 Jun 2017 14:56:17 +0300 Subject: net/mlx5e: IPoIB, Add ioctl support to IPoIB device driver Add ioctl support to IPoIB device driver. For now, this ioctl will support timestamp get and set. Signed-off-by: Feras Daoud Signed-off-by: Eitan Rabin Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/en_clock.c | 10 ++++------ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 6 ++++-- drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 16 ++++++++++++++++ 4 files changed, 26 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 626683f0f487..5d9ace493d85 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -853,8 +853,8 @@ void mlx5e_timestamp_init(struct mlx5e_priv *priv); void mlx5e_timestamp_cleanup(struct mlx5e_priv *priv); void mlx5e_pps_event_handler(struct mlx5e_priv *priv, struct ptp_clock_event *event); -int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr); -int mlx5e_hwstamp_get(struct net_device *dev, struct ifreq *ifr); +int mlx5e_hwstamp_set(struct mlx5e_priv *priv, struct ifreq *ifr); +int mlx5e_hwstamp_get(struct mlx5e_priv *priv, struct ifreq *ifr); int mlx5e_modify_rx_cqe_compression_locked(struct mlx5e_priv *priv, bool val); int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c index e29494464cae..66f432385dbb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_clock.c @@ -86,9 +86,8 @@ static void mlx5e_timestamp_overflow(struct work_struct *work) schedule_delayed_work(&tstamp->overflow_work, tstamp->overflow_period); } -int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr) +int mlx5e_hwstamp_set(struct mlx5e_priv *priv, struct ifreq *ifr) { - struct mlx5e_priv *priv = netdev_priv(dev); struct hwtstamp_config config; int err; @@ -130,10 +129,10 @@ int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: case HWTSTAMP_FILTER_NTP_ALL: /* Disable CQE compression */ - netdev_warn(dev, "Disabling cqe compression"); + netdev_warn(priv->netdev, "Disabling cqe compression"); err = mlx5e_modify_rx_cqe_compression_locked(priv, false); if (err) { - netdev_err(dev, "Failed disabling cqe compression err=%d\n", err); + netdev_err(priv->netdev, "Failed disabling cqe compression err=%d\n", err); mutex_unlock(&priv->state_lock); return err; } @@ -151,9 +150,8 @@ int mlx5e_hwstamp_set(struct net_device *dev, struct ifreq *ifr) sizeof(config)) ? -EFAULT : 0; } -int mlx5e_hwstamp_get(struct net_device *dev, struct ifreq *ifr) +int mlx5e_hwstamp_get(struct mlx5e_priv *priv, struct ifreq *ifr) { - struct mlx5e_priv *priv = netdev_priv(dev); struct hwtstamp_config *cfg = &priv->tstamp.hwtstamp_config; if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index de1e936fc2be..20ee29a2209e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -3317,11 +3317,13 @@ out: static int mlx5e_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { + struct mlx5e_priv *priv = netdev_priv(dev); + switch (cmd) { case SIOCSHWTSTAMP: - return mlx5e_hwstamp_set(dev, ifr); + return mlx5e_hwstamp_set(priv, ifr); case SIOCGHWTSTAMP: - return mlx5e_hwstamp_get(dev, ifr); + return mlx5e_hwstamp_get(priv, ifr); default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 58bf0665f50b..1ee5bce85901 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -43,6 +43,7 @@ static int mlx5i_close(struct net_device *netdev); static int mlx5i_dev_init(struct net_device *dev); static void mlx5i_dev_cleanup(struct net_device *dev); static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu); +static int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static const struct net_device_ops mlx5i_netdev_ops = { .ndo_open = mlx5i_open, @@ -50,6 +51,7 @@ static const struct net_device_ops mlx5i_netdev_ops = { .ndo_init = mlx5i_dev_init, .ndo_uninit = mlx5i_dev_cleanup, .ndo_change_mtu = mlx5i_change_mtu, + .ndo_do_ioctl = mlx5i_ioctl, }; /* IPoIB mlx5 netdev profile */ @@ -356,6 +358,20 @@ static int mlx5i_dev_init(struct net_device *dev) return 0; } +static int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct mlx5e_priv *priv = mlx5i_epriv(dev); + + switch (cmd) { + case SIOCSHWTSTAMP: + return mlx5e_hwstamp_set(priv, ifr); + case SIOCGHWTSTAMP: + return mlx5e_hwstamp_get(priv, ifr); + default: + return -EOPNOTSUPP; + } +} + static void mlx5i_dev_cleanup(struct net_device *dev) { struct mlx5e_priv *priv = mlx5i_epriv(dev); -- cgit v1.2.3 From 1a4a69751f4d24ffd3530f5a9694636db1566a3b Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Tue, 20 Jun 2017 16:00:00 +0300 Subject: qed: Chain support for external PBL iWARP would require the chains to allocate/free their PBL memory independently, so add the infrastructure to provide it externally. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/infiniband/hw/qedr/main.c | 2 +- drivers/infiniband/hw/qedr/verbs.c | 6 ++--- drivers/net/ethernet/qlogic/qed/qed_dev.c | 35 ++++++++++++++++++++------- drivers/net/ethernet/qlogic/qed/qed_dev_api.h | 5 +++- drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 6 ++--- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 6 ++--- drivers/net/ethernet/qlogic/qed/qed_spq.c | 6 ++--- drivers/net/ethernet/qlogic/qede/qede_main.c | 8 +++--- 8 files changed, 47 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 485c1fef238b..5a32b802e4da 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -276,7 +276,7 @@ static int qedr_alloc_resources(struct qedr_dev *dev) QED_CHAIN_CNT_TYPE_U16, n_entries, sizeof(struct regpair *), - &cnq->pbl); + &cnq->pbl, NULL); if (rc) goto err4; diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 17685cfea6a2..80df89b5a9ce 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -925,7 +925,7 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, QED_CHAIN_CNT_TYPE_U32, chain_entries, sizeof(union rdma_cqe), - &cq->pbl); + &cq->pbl, NULL); if (rc) goto err1; @@ -1413,7 +1413,7 @@ qedr_roce_create_kernel_qp(struct qedr_dev *dev, QED_CHAIN_CNT_TYPE_U32, n_sq_elems, QEDR_SQE_ELEMENT_SIZE, - &qp->sq.pbl); + &qp->sq.pbl, NULL); if (rc) return rc; @@ -1427,7 +1427,7 @@ qedr_roce_create_kernel_qp(struct qedr_dev *dev, QED_CHAIN_CNT_TYPE_U32, n_rq_elems, QEDR_RQE_ELEMENT_SIZE, - &qp->rq.pbl); + &qp->rq.pbl, NULL); if (rc) return rc; diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 65fe4940f20d..8b140541736a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -3075,12 +3075,15 @@ static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *p_chain) } pbl_size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; - dma_free_coherent(&cdev->pdev->dev, - pbl_size, - p_chain->pbl_sp.p_virt_table, - p_chain->pbl_sp.p_phys_table); + + if (!p_chain->b_external_pbl) + dma_free_coherent(&cdev->pdev->dev, + pbl_size, + p_chain->pbl_sp.p_virt_table, + p_chain->pbl_sp.p_phys_table); out: vfree(p_chain->pbl.pp_virt_addr_tbl); + p_chain->pbl.pp_virt_addr_tbl = NULL; } void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain) @@ -3174,7 +3177,10 @@ qed_chain_alloc_single(struct qed_dev *cdev, struct qed_chain *p_chain) return 0; } -static int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *p_chain) +static int +qed_chain_alloc_pbl(struct qed_dev *cdev, + struct qed_chain *p_chain, + struct qed_chain_ext_pbl *ext_pbl) { u32 page_cnt = p_chain->page_cnt, size, i; dma_addr_t p_phys = 0, p_pbl_phys = 0; @@ -3194,8 +3200,16 @@ static int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *p_chain) * should be saved to allow its freeing during the error flow. */ size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; - p_pbl_virt = dma_alloc_coherent(&cdev->pdev->dev, - size, &p_pbl_phys, GFP_KERNEL); + + if (!ext_pbl) { + p_pbl_virt = dma_alloc_coherent(&cdev->pdev->dev, + size, &p_pbl_phys, GFP_KERNEL); + } else { + p_pbl_virt = ext_pbl->p_pbl_virt; + p_pbl_phys = ext_pbl->p_pbl_phys; + p_chain->b_external_pbl = true; + } + qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys, pp_virt_addr_tbl); if (!p_pbl_virt) @@ -3228,7 +3242,10 @@ int qed_chain_alloc(struct qed_dev *cdev, enum qed_chain_use_mode intended_use, enum qed_chain_mode mode, enum qed_chain_cnt_type cnt_type, - u32 num_elems, size_t elem_size, struct qed_chain *p_chain) + u32 num_elems, + size_t elem_size, + struct qed_chain *p_chain, + struct qed_chain_ext_pbl *ext_pbl) { u32 page_cnt; int rc = 0; @@ -3259,7 +3276,7 @@ int qed_chain_alloc(struct qed_dev *cdev, rc = qed_chain_alloc_single(cdev, p_chain); break; case QED_CHAIN_MODE_PBL: - rc = qed_chain_alloc_pbl(cdev, p_chain); + rc = qed_chain_alloc_pbl(cdev, p_chain, ext_pbl); break; } if (rc) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h index 12d16c096e36..1f1df1bf127c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h @@ -307,6 +307,7 @@ int qed_dmae_host2host(struct qed_hwfn *p_hwfn, * @param num_elems * @param elem_size * @param p_chain + * @param ext_pbl - a possible external PBL * * @return int */ @@ -315,7 +316,9 @@ qed_chain_alloc(struct qed_dev *cdev, enum qed_chain_use_mode intended_use, enum qed_chain_mode mode, enum qed_chain_cnt_type cnt_type, - u32 num_elems, size_t elem_size, struct qed_chain *p_chain); + u32 num_elems, + size_t elem_size, + struct qed_chain *p_chain, struct qed_chain_ext_pbl *ext_pbl); /** * @brief qed_chain_free - Free chain DMA memory diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index 6103723d7118..5a1ed05d0c5f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -752,7 +752,7 @@ static int qed_iscsi_allocate_connection(struct qed_hwfn *p_hwfn, QED_CHAIN_USE_TO_CONSUME_PRODUCE, QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, - r2tq_num_elements, 0x80, &p_conn->r2tq); + r2tq_num_elements, 0x80, &p_conn->r2tq, NULL); if (rc) goto nomem_r2tq; @@ -763,7 +763,7 @@ static int qed_iscsi_allocate_connection(struct qed_hwfn *p_hwfn, QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, uhq_num_elements, - sizeof(struct iscsi_uhqe), &p_conn->uhq); + sizeof(struct iscsi_uhqe), &p_conn->uhq, NULL); if (rc) goto nomem_uhq; @@ -773,7 +773,7 @@ static int qed_iscsi_allocate_connection(struct qed_hwfn *p_hwfn, QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, xhq_num_elements, - sizeof(struct iscsi_xhqe), &p_conn->xhq); + sizeof(struct iscsi_xhqe), &p_conn->xhq, NULL); if (rc) goto nomem; diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 0e26193156e4..f9c51cb8585e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -1056,7 +1056,7 @@ qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn, QED_CHAIN_CNT_TYPE_U16, p_ll2_info->input.rx_num_desc, sizeof(struct core_rx_bd), - &p_ll2_info->rx_queue.rxq_chain); + &p_ll2_info->rx_queue.rxq_chain, NULL); if (rc) { DP_NOTICE(p_hwfn, "Failed to allocate ll2 rxq chain\n"); goto out; @@ -1078,7 +1078,7 @@ qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn, QED_CHAIN_CNT_TYPE_U16, p_ll2_info->input.rx_num_desc, sizeof(struct core_rx_fast_path_cqe), - &p_ll2_info->rx_queue.rcq_chain); + &p_ll2_info->rx_queue.rcq_chain, NULL); if (rc) { DP_NOTICE(p_hwfn, "Failed to allocate ll2 rcq chain\n"); goto out; @@ -1108,7 +1108,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn *p_hwfn, QED_CHAIN_CNT_TYPE_U16, p_ll2_info->input.tx_num_desc, sizeof(struct core_tx_bd), - &p_ll2_info->tx_queue.txq_chain); + &p_ll2_info->tx_queue.txq_chain, NULL); if (rc) goto out; diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index dede73f41e61..a971916af7cc 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -419,7 +419,7 @@ int qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem) QED_CHAIN_CNT_TYPE_U16, num_elem, sizeof(union event_ring_element), - &p_eq->chain)) + &p_eq->chain, NULL)) goto eq_allocate_fail; /* register EQ completion on the SP SB */ @@ -547,7 +547,7 @@ int qed_spq_alloc(struct qed_hwfn *p_hwfn) QED_CHAIN_CNT_TYPE_U16, 0, /* N/A when the mode is SINGLE */ sizeof(struct slow_path_element), - &p_spq->chain)) + &p_spq->chain, NULL)) goto spq_allocate_fail; /* allocate and fill the SPQ elements (incl. ramrod data list) */ @@ -953,7 +953,7 @@ int qed_consq_alloc(struct qed_hwfn *p_hwfn) QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, QED_CHAIN_PAGE_SIZE / 0x80, - 0x80, &p_consq->chain)) + 0x80, &p_consq->chain, NULL)) goto consq_allocate_fail; p_hwfn->p_consq = p_consq; diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index fdf04bc5406e..37ad79917770 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1317,8 +1317,7 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq) QED_CHAIN_CNT_TYPE_U16, RX_RING_SIZE, sizeof(struct eth_rx_bd), - &rxq->rx_bd_ring); - + &rxq->rx_bd_ring, NULL); if (rc) goto err; @@ -1329,7 +1328,7 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq) QED_CHAIN_CNT_TYPE_U16, RX_RING_SIZE, sizeof(union eth_rx_cqe), - &rxq->rx_comp_ring); + &rxq->rx_comp_ring, NULL); if (rc) goto err; @@ -1387,7 +1386,8 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) QED_CHAIN_MODE_PBL, QED_CHAIN_CNT_TYPE_U16, txq->num_tx_buffers, - sizeof(*p_virt), &txq->tx_pbl); + sizeof(*p_virt), + &txq->tx_pbl, NULL); if (rc) goto err; -- cgit v1.2.3 From 26462ad9c7ea18643f1a37adeab8b7eff6c5f5f4 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Tue, 20 Jun 2017 16:00:01 +0300 Subject: qed: RoCE EDPM to honor PFC Configure device according to DCBx results so that EDPMs made by RoCE would honor flow-control. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 16 ++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 6 ++++++ 2 files changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index e2a62c091b80..15b516a84582 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -896,6 +896,22 @@ qed_dcbx_mib_update_event(struct qed_hwfn *p_hwfn, } qed_dcbx_get_params(p_hwfn, &p_hwfn->p_dcbx_info->get, type); + + if (type == QED_DCBX_OPERATIONAL_MIB) { + struct qed_dcbx_results *p_data; + u16 val; + + /* Configure in NIG which protocols support EDPM and should + * honor PFC. + */ + p_data = &p_hwfn->p_dcbx_info->results; + val = (0x1 << p_data->arr[DCBX_PROTOCOL_ROCE].tc) | + (0x1 << p_data->arr[DCBX_PROTOCOL_ROCE_V2].tc); + val <<= NIG_REG_TX_EDPM_CTRL_TX_EDPM_TC_EN_SHIFT; + val |= NIG_REG_TX_EDPM_CTRL_TX_EDPM_EN; + qed_wr(p_hwfn, p_ptt, NIG_REG_TX_EDPM_CTRL, val); + } + qed_dcbx_aen(p_hwfn, type); return rc; diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 7e4639c9207a..0cdb4337b3a0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -1564,6 +1564,12 @@ #define NIG_REG_TSGEN_FREECNT_UPDATE_K2 0x509008UL #define CNIG_REG_NIG_PORT0_CONF_K2 0x218200UL +#define NIG_REG_TX_EDPM_CTRL 0x501f0cUL +#define NIG_REG_TX_EDPM_CTRL_TX_EDPM_EN (0x1 << 0) +#define NIG_REG_TX_EDPM_CTRL_TX_EDPM_EN_SHIFT 0 +#define NIG_REG_TX_EDPM_CTRL_TX_EDPM_TC_EN (0xff << 1) +#define NIG_REG_TX_EDPM_CTRL_TX_EDPM_TC_EN_SHIFT 1 + #define PRS_REG_SEARCH_GFT 0x1f11bcUL #define PRS_REG_CM_HDR_GFT 0x1f11c8UL #define PRS_REG_GFT_CAM 0x1f1100UL -- cgit v1.2.3 From 9331dad1bb7f3438c27e4f57136b6ad683d11fe0 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Tue, 20 Jun 2017 16:00:02 +0300 Subject: qed: Disable RoCE dpm when DCBx change occurs If DCBx update occurs while QPs are open, stop sending edpms until all QPs are closed. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 8 +++++++ drivers/net/ethernet/qlogic/qed/qed_roce.c | 36 ++++++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_roce.h | 5 +++++ 3 files changed, 49 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index 15b516a84582..f888045e1ae9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -44,6 +44,7 @@ #include "qed_hsi.h" #include "qed_sp.h" #include "qed_sriov.h" +#include "qed_roce.h" #ifdef CONFIG_DCB #include #endif @@ -892,6 +893,13 @@ qed_dcbx_mib_update_event(struct qed_hwfn *p_hwfn, /* update storm FW with negotiation results */ qed_sp_pf_update(p_hwfn); + + /* for roce PFs, we may want to enable/disable DPM + * when DCBx change occurs + */ + if (p_hwfn->hw_info.personality == + QED_PCI_ETH_ROCE) + qed_roce_dpm_dcbx(p_hwfn, p_ptt); } } diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 4bc2f6c47f69..8419dcc111d8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -162,6 +162,11 @@ static int qed_bmap_test_id(struct qed_hwfn *p_hwfn, return test_bit(id_num, bmap->bitmap); } +static bool qed_bmap_is_empty(struct qed_bmap *bmap) +{ + return bmap->max_count == find_first_bit(bmap->bitmap, bmap->max_count); +} + static u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id) { /* First sb id for RoCE is after all the l2 sb */ @@ -2638,6 +2643,23 @@ static void *qed_rdma_get_rdma_ctx(struct qed_dev *cdev) return QED_LEADING_HWFN(cdev); } +static bool qed_rdma_allocated_qps(struct qed_hwfn *p_hwfn) +{ + bool result; + + /* if rdma info has not been allocated, naturally there are no qps */ + if (!p_hwfn->p_rdma_info) + return false; + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + if (!p_hwfn->p_rdma_info->cid_map.bitmap) + result = false; + else + result = !qed_bmap_is_empty(&p_hwfn->p_rdma_info->cid_map); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + return result; +} + static void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { u32 val; @@ -2650,6 +2672,20 @@ static void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) val, p_hwfn->dcbx_no_edpm, p_hwfn->db_bar_no_edpm); } +void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + u8 val; + + /* if any QPs are already active, we want to disable DPM, since their + * context information contains information from before the latest DCBx + * update. Otherwise enable it. + */ + val = qed_rdma_allocated_qps(p_hwfn) ? true : false; + p_hwfn->dcbx_no_edpm = (u8)val; + + qed_rdma_dpm_conf(p_hwfn, p_ptt); +} + void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { p_hwfn->db_bar_no_edpm = true; diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.h b/drivers/net/ethernet/qlogic/qed/qed_roce.h index 94be3b5a39c4..ddd77618e6fa 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.h +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.h @@ -168,10 +168,15 @@ struct qed_rdma_qp { #if IS_ENABLED(CONFIG_QED_RDMA) void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); void qed_roce_async_event(struct qed_hwfn *p_hwfn, u8 fw_event_code, union rdma_eqe_data *rdma_data); #else static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} + +static inline void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) {} + static inline void qed_roce_async_event(struct qed_hwfn *p_hwfn, u8 fw_event_code, union rdma_eqe_data *rdma_data) {} -- cgit v1.2.3 From b262a06e642cfb1eeb6c2c772f76dad674ada57e Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Tue, 20 Jun 2017 16:00:03 +0300 Subject: qed*: qede_roce.[ch] -> qede_rdma.[ch] Once we have iWARP support, the qede portion of the qedr<->qede would serve all the RDMA protocols - so rename the file to be appropriate to its function. While we're at it, we're also moving a couple of inclusions to it into .h files and adding includes to make sure it contains all type definitions it requires. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/infiniband/hw/qedr/main.c | 2 +- drivers/infiniband/hw/qedr/qedr.h | 2 +- drivers/net/ethernet/qlogic/qede/Makefile | 2 +- drivers/net/ethernet/qlogic/qede/qede.h | 1 + drivers/net/ethernet/qlogic/qede/qede_main.c | 1 - drivers/net/ethernet/qlogic/qede/qede_rdma.c | 314 +++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qede/qede_roce.c | 314 --------------------------- 7 files changed, 318 insertions(+), 318 deletions(-) create mode 100644 drivers/net/ethernet/qlogic/qede/qede_rdma.c delete mode 100644 drivers/net/ethernet/qlogic/qede/qede_roce.c (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 5a32b802e4da..714eb0c92312 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -37,7 +37,7 @@ #include #include #include -#include + #include #include #include "qedr.h" diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 80333ec2c8b6..2376019a48ae 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include "qedr_hsi_rdma.h" diff --git a/drivers/net/ethernet/qlogic/qede/Makefile b/drivers/net/ethernet/qlogic/qede/Makefile index bc5f7c3b277d..75408fbb7680 100644 --- a/drivers/net/ethernet/qlogic/qede/Makefile +++ b/drivers/net/ethernet/qlogic/qede/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_QEDE) := qede.o qede-y := qede_main.o qede_fp.o qede_filter.o qede_ethtool.o qede_ptp.o qede-$(CONFIG_DCB) += qede_dcbnl.o -qede-$(CONFIG_QED_RDMA) += qede_roce.o +qede-$(CONFIG_QED_RDMA) += qede_rdma.o diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 694c09b8997e..2d6b30c47b3a 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #ifdef CONFIG_RFS_ACCEL #include diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 37ad79917770..e9eaa38895e6 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -60,7 +60,6 @@ #include #include #include -#include #include "qede.h" #include "qede_ptp.h" diff --git a/drivers/net/ethernet/qlogic/qede/qede_rdma.c b/drivers/net/ethernet/qlogic/qede/qede_rdma.c new file mode 100644 index 000000000000..9837ee20cbae --- /dev/null +++ b/drivers/net/ethernet/qlogic/qede/qede_rdma.c @@ -0,0 +1,314 @@ +/* QLogic qedr NIC Driver + * Copyright (c) 2015-2017 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include "qede.h" + +static struct qedr_driver *qedr_drv; +static LIST_HEAD(qedr_dev_list); +static DEFINE_MUTEX(qedr_dev_list_lock); + +bool qede_roce_supported(struct qede_dev *dev) +{ + return dev->dev_info.common.rdma_supported; +} + +static void _qede_roce_dev_add(struct qede_dev *edev) +{ + if (!qedr_drv) + return; + + edev->rdma_info.qedr_dev = qedr_drv->add(edev->cdev, edev->pdev, + edev->ndev); +} + +static int qede_roce_create_wq(struct qede_dev *edev) +{ + INIT_LIST_HEAD(&edev->rdma_info.roce_event_list); + edev->rdma_info.roce_wq = create_singlethread_workqueue("roce_wq"); + if (!edev->rdma_info.roce_wq) { + DP_NOTICE(edev, "qedr: Could not create workqueue\n"); + return -ENOMEM; + } + + return 0; +} + +static void qede_roce_cleanup_event(struct qede_dev *edev) +{ + struct list_head *head = &edev->rdma_info.roce_event_list; + struct qede_roce_event_work *event_node; + + flush_workqueue(edev->rdma_info.roce_wq); + while (!list_empty(head)) { + event_node = list_entry(head->next, struct qede_roce_event_work, + list); + cancel_work_sync(&event_node->work); + list_del(&event_node->list); + kfree(event_node); + } +} + +static void qede_roce_destroy_wq(struct qede_dev *edev) +{ + qede_roce_cleanup_event(edev); + destroy_workqueue(edev->rdma_info.roce_wq); +} + +int qede_roce_dev_add(struct qede_dev *edev) +{ + int rc = 0; + + if (qede_roce_supported(edev)) { + rc = qede_roce_create_wq(edev); + if (rc) + return rc; + + INIT_LIST_HEAD(&edev->rdma_info.entry); + mutex_lock(&qedr_dev_list_lock); + list_add_tail(&edev->rdma_info.entry, &qedr_dev_list); + _qede_roce_dev_add(edev); + mutex_unlock(&qedr_dev_list_lock); + } + + return rc; +} + +static void _qede_roce_dev_remove(struct qede_dev *edev) +{ + if (qedr_drv && qedr_drv->remove && edev->rdma_info.qedr_dev) + qedr_drv->remove(edev->rdma_info.qedr_dev); + edev->rdma_info.qedr_dev = NULL; +} + +void qede_roce_dev_remove(struct qede_dev *edev) +{ + if (!qede_roce_supported(edev)) + return; + + qede_roce_destroy_wq(edev); + mutex_lock(&qedr_dev_list_lock); + _qede_roce_dev_remove(edev); + list_del(&edev->rdma_info.entry); + mutex_unlock(&qedr_dev_list_lock); +} + +static void _qede_roce_dev_open(struct qede_dev *edev) +{ + if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) + qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_UP); +} + +static void qede_roce_dev_open(struct qede_dev *edev) +{ + if (!qede_roce_supported(edev)) + return; + + mutex_lock(&qedr_dev_list_lock); + _qede_roce_dev_open(edev); + mutex_unlock(&qedr_dev_list_lock); +} + +static void _qede_roce_dev_close(struct qede_dev *edev) +{ + if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) + qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_DOWN); +} + +static void qede_roce_dev_close(struct qede_dev *edev) +{ + if (!qede_roce_supported(edev)) + return; + + mutex_lock(&qedr_dev_list_lock); + _qede_roce_dev_close(edev); + mutex_unlock(&qedr_dev_list_lock); +} + +static void qede_roce_dev_shutdown(struct qede_dev *edev) +{ + if (!qede_roce_supported(edev)) + return; + + mutex_lock(&qedr_dev_list_lock); + if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) + qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_CLOSE); + mutex_unlock(&qedr_dev_list_lock); +} + +int qede_roce_register_driver(struct qedr_driver *drv) +{ + struct qede_dev *edev; + u8 qedr_counter = 0; + + mutex_lock(&qedr_dev_list_lock); + if (qedr_drv) { + mutex_unlock(&qedr_dev_list_lock); + return -EINVAL; + } + qedr_drv = drv; + + list_for_each_entry(edev, &qedr_dev_list, rdma_info.entry) { + struct net_device *ndev; + + qedr_counter++; + _qede_roce_dev_add(edev); + ndev = edev->ndev; + if (netif_running(ndev) && netif_oper_up(ndev)) + _qede_roce_dev_open(edev); + } + mutex_unlock(&qedr_dev_list_lock); + + pr_notice("qedr: discovered and registered %d RoCE funcs\n", + qedr_counter); + + return 0; +} +EXPORT_SYMBOL(qede_roce_register_driver); + +void qede_roce_unregister_driver(struct qedr_driver *drv) +{ + struct qede_dev *edev; + + mutex_lock(&qedr_dev_list_lock); + list_for_each_entry(edev, &qedr_dev_list, rdma_info.entry) { + if (edev->rdma_info.qedr_dev) + _qede_roce_dev_remove(edev); + } + qedr_drv = NULL; + mutex_unlock(&qedr_dev_list_lock); +} +EXPORT_SYMBOL(qede_roce_unregister_driver); + +static void qede_roce_changeaddr(struct qede_dev *edev) +{ + if (!qede_roce_supported(edev)) + return; + + if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) + qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_CHANGE_ADDR); +} + +static struct qede_roce_event_work * +qede_roce_get_free_event_node(struct qede_dev *edev) +{ + struct qede_roce_event_work *event_node = NULL; + struct list_head *list_node = NULL; + bool found = false; + + list_for_each(list_node, &edev->rdma_info.roce_event_list) { + event_node = list_entry(list_node, struct qede_roce_event_work, + list); + if (!work_pending(&event_node->work)) { + found = true; + break; + } + } + + if (!found) { + event_node = kzalloc(sizeof(*event_node), GFP_KERNEL); + if (!event_node) { + DP_NOTICE(edev, + "qedr: Could not allocate memory for roce work\n"); + return NULL; + } + list_add_tail(&event_node->list, + &edev->rdma_info.roce_event_list); + } + + return event_node; +} + +static void qede_roce_handle_event(struct work_struct *work) +{ + struct qede_roce_event_work *event_node; + enum qede_roce_event event; + struct qede_dev *edev; + + event_node = container_of(work, struct qede_roce_event_work, work); + event = event_node->event; + edev = event_node->ptr; + + switch (event) { + case QEDE_UP: + qede_roce_dev_open(edev); + break; + case QEDE_DOWN: + qede_roce_dev_close(edev); + break; + case QEDE_CLOSE: + qede_roce_dev_shutdown(edev); + break; + case QEDE_CHANGE_ADDR: + qede_roce_changeaddr(edev); + break; + default: + DP_NOTICE(edev, "Invalid roce event %d", event); + } +} + +static void qede_roce_add_event(struct qede_dev *edev, + enum qede_roce_event event) +{ + struct qede_roce_event_work *event_node; + + if (!edev->rdma_info.qedr_dev) + return; + + event_node = qede_roce_get_free_event_node(edev); + if (!event_node) + return; + + event_node->event = event; + event_node->ptr = edev; + + INIT_WORK(&event_node->work, qede_roce_handle_event); + queue_work(edev->rdma_info.roce_wq, &event_node->work); +} + +void qede_roce_dev_event_open(struct qede_dev *edev) +{ + qede_roce_add_event(edev, QEDE_UP); +} + +void qede_roce_dev_event_close(struct qede_dev *edev) +{ + qede_roce_add_event(edev, QEDE_DOWN); +} + +void qede_roce_event_changeaddr(struct qede_dev *edev) +{ + qede_roce_add_event(edev, QEDE_CHANGE_ADDR); +} diff --git a/drivers/net/ethernet/qlogic/qede/qede_roce.c b/drivers/net/ethernet/qlogic/qede/qede_roce.c deleted file mode 100644 index c0030fb8d842..000000000000 --- a/drivers/net/ethernet/qlogic/qede/qede_roce.c +++ /dev/null @@ -1,314 +0,0 @@ -/* QLogic qedr NIC Driver - * Copyright (c) 2015-2017 QLogic Corporation - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and /or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include -#include -#include "qede.h" - -static struct qedr_driver *qedr_drv; -static LIST_HEAD(qedr_dev_list); -static DEFINE_MUTEX(qedr_dev_list_lock); - -bool qede_roce_supported(struct qede_dev *dev) -{ - return dev->dev_info.common.rdma_supported; -} - -static void _qede_roce_dev_add(struct qede_dev *edev) -{ - if (!qedr_drv) - return; - - edev->rdma_info.qedr_dev = qedr_drv->add(edev->cdev, edev->pdev, - edev->ndev); -} - -static int qede_roce_create_wq(struct qede_dev *edev) -{ - INIT_LIST_HEAD(&edev->rdma_info.roce_event_list); - edev->rdma_info.roce_wq = create_singlethread_workqueue("roce_wq"); - if (!edev->rdma_info.roce_wq) { - DP_NOTICE(edev, "qedr: Could not create workqueue\n"); - return -ENOMEM; - } - - return 0; -} - -static void qede_roce_cleanup_event(struct qede_dev *edev) -{ - struct list_head *head = &edev->rdma_info.roce_event_list; - struct qede_roce_event_work *event_node; - - flush_workqueue(edev->rdma_info.roce_wq); - while (!list_empty(head)) { - event_node = list_entry(head->next, struct qede_roce_event_work, - list); - cancel_work_sync(&event_node->work); - list_del(&event_node->list); - kfree(event_node); - } -} - -static void qede_roce_destroy_wq(struct qede_dev *edev) -{ - qede_roce_cleanup_event(edev); - destroy_workqueue(edev->rdma_info.roce_wq); -} - -int qede_roce_dev_add(struct qede_dev *edev) -{ - int rc = 0; - - if (qede_roce_supported(edev)) { - rc = qede_roce_create_wq(edev); - if (rc) - return rc; - - INIT_LIST_HEAD(&edev->rdma_info.entry); - mutex_lock(&qedr_dev_list_lock); - list_add_tail(&edev->rdma_info.entry, &qedr_dev_list); - _qede_roce_dev_add(edev); - mutex_unlock(&qedr_dev_list_lock); - } - - return rc; -} - -static void _qede_roce_dev_remove(struct qede_dev *edev) -{ - if (qedr_drv && qedr_drv->remove && edev->rdma_info.qedr_dev) - qedr_drv->remove(edev->rdma_info.qedr_dev); - edev->rdma_info.qedr_dev = NULL; -} - -void qede_roce_dev_remove(struct qede_dev *edev) -{ - if (!qede_roce_supported(edev)) - return; - - qede_roce_destroy_wq(edev); - mutex_lock(&qedr_dev_list_lock); - _qede_roce_dev_remove(edev); - list_del(&edev->rdma_info.entry); - mutex_unlock(&qedr_dev_list_lock); -} - -static void _qede_roce_dev_open(struct qede_dev *edev) -{ - if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) - qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_UP); -} - -static void qede_roce_dev_open(struct qede_dev *edev) -{ - if (!qede_roce_supported(edev)) - return; - - mutex_lock(&qedr_dev_list_lock); - _qede_roce_dev_open(edev); - mutex_unlock(&qedr_dev_list_lock); -} - -static void _qede_roce_dev_close(struct qede_dev *edev) -{ - if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) - qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_DOWN); -} - -static void qede_roce_dev_close(struct qede_dev *edev) -{ - if (!qede_roce_supported(edev)) - return; - - mutex_lock(&qedr_dev_list_lock); - _qede_roce_dev_close(edev); - mutex_unlock(&qedr_dev_list_lock); -} - -static void qede_roce_dev_shutdown(struct qede_dev *edev) -{ - if (!qede_roce_supported(edev)) - return; - - mutex_lock(&qedr_dev_list_lock); - if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) - qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_CLOSE); - mutex_unlock(&qedr_dev_list_lock); -} - -int qede_roce_register_driver(struct qedr_driver *drv) -{ - struct qede_dev *edev; - u8 qedr_counter = 0; - - mutex_lock(&qedr_dev_list_lock); - if (qedr_drv) { - mutex_unlock(&qedr_dev_list_lock); - return -EINVAL; - } - qedr_drv = drv; - - list_for_each_entry(edev, &qedr_dev_list, rdma_info.entry) { - struct net_device *ndev; - - qedr_counter++; - _qede_roce_dev_add(edev); - ndev = edev->ndev; - if (netif_running(ndev) && netif_oper_up(ndev)) - _qede_roce_dev_open(edev); - } - mutex_unlock(&qedr_dev_list_lock); - - pr_notice("qedr: discovered and registered %d RoCE funcs\n", - qedr_counter); - - return 0; -} -EXPORT_SYMBOL(qede_roce_register_driver); - -void qede_roce_unregister_driver(struct qedr_driver *drv) -{ - struct qede_dev *edev; - - mutex_lock(&qedr_dev_list_lock); - list_for_each_entry(edev, &qedr_dev_list, rdma_info.entry) { - if (edev->rdma_info.qedr_dev) - _qede_roce_dev_remove(edev); - } - qedr_drv = NULL; - mutex_unlock(&qedr_dev_list_lock); -} -EXPORT_SYMBOL(qede_roce_unregister_driver); - -static void qede_roce_changeaddr(struct qede_dev *edev) -{ - if (!qede_roce_supported(edev)) - return; - - if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) - qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_CHANGE_ADDR); -} - -static struct qede_roce_event_work * -qede_roce_get_free_event_node(struct qede_dev *edev) -{ - struct qede_roce_event_work *event_node = NULL; - struct list_head *list_node = NULL; - bool found = false; - - list_for_each(list_node, &edev->rdma_info.roce_event_list) { - event_node = list_entry(list_node, struct qede_roce_event_work, - list); - if (!work_pending(&event_node->work)) { - found = true; - break; - } - } - - if (!found) { - event_node = kzalloc(sizeof(*event_node), GFP_KERNEL); - if (!event_node) { - DP_NOTICE(edev, - "qedr: Could not allocate memory for roce work\n"); - return NULL; - } - list_add_tail(&event_node->list, - &edev->rdma_info.roce_event_list); - } - - return event_node; -} - -static void qede_roce_handle_event(struct work_struct *work) -{ - struct qede_roce_event_work *event_node; - enum qede_roce_event event; - struct qede_dev *edev; - - event_node = container_of(work, struct qede_roce_event_work, work); - event = event_node->event; - edev = event_node->ptr; - - switch (event) { - case QEDE_UP: - qede_roce_dev_open(edev); - break; - case QEDE_DOWN: - qede_roce_dev_close(edev); - break; - case QEDE_CLOSE: - qede_roce_dev_shutdown(edev); - break; - case QEDE_CHANGE_ADDR: - qede_roce_changeaddr(edev); - break; - default: - DP_NOTICE(edev, "Invalid roce event %d", event); - } -} - -static void qede_roce_add_event(struct qede_dev *edev, - enum qede_roce_event event) -{ - struct qede_roce_event_work *event_node; - - if (!edev->rdma_info.qedr_dev) - return; - - event_node = qede_roce_get_free_event_node(edev); - if (!event_node) - return; - - event_node->event = event; - event_node->ptr = edev; - - INIT_WORK(&event_node->work, qede_roce_handle_event); - queue_work(edev->rdma_info.roce_wq, &event_node->work); -} - -void qede_roce_dev_event_open(struct qede_dev *edev) -{ - qede_roce_add_event(edev, QEDE_UP); -} - -void qede_roce_dev_event_close(struct qede_dev *edev) -{ - qede_roce_add_event(edev, QEDE_DOWN); -} - -void qede_roce_event_changeaddr(struct qede_dev *edev) -{ - qede_roce_add_event(edev, QEDE_CHANGE_ADDR); -} -- cgit v1.2.3 From bbfcd1e8e1677b1e692144c5709945e1dfe1ed30 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Tue, 20 Jun 2017 16:00:04 +0300 Subject: qed*: Set rdma generic functions prefix Rename the functions common to both iWARP and RoCE to have a prefix of _rdma_ instead of _roce_. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/infiniband/hw/qedr/main.c | 6 +- drivers/net/ethernet/qlogic/qede/qede.h | 4 +- drivers/net/ethernet/qlogic/qede/qede_main.c | 12 +-- drivers/net/ethernet/qlogic/qede/qede_rdma.c | 142 +++++++++++++-------------- 4 files changed, 82 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 714eb0c92312..b5851fd67d4f 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -902,7 +902,7 @@ static void qedr_mac_address_change(struct qedr_dev *dev) * initialization done before RoCE driver notifies * event to stack. */ -static void qedr_notify(struct qedr_dev *dev, enum qede_roce_event event) +static void qedr_notify(struct qedr_dev *dev, enum qede_rdma_event event) { switch (event) { case QEDE_UP: @@ -931,12 +931,12 @@ static struct qedr_driver qedr_drv = { static int __init qedr_init_module(void) { - return qede_roce_register_driver(&qedr_drv); + return qede_rdma_register_driver(&qedr_drv); } static void __exit qedr_exit_module(void) { - qede_roce_unregister_driver(&qedr_drv); + qede_rdma_unregister_driver(&qedr_drv); } module_init(qedr_init_module); diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 2d6b30c47b3a..4dfb238221f9 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -154,8 +154,8 @@ struct qede_vlan { struct qede_rdma_dev { struct qedr_dev *qedr_dev; struct list_head entry; - struct list_head roce_event_list; - struct workqueue_struct *roce_wq; + struct list_head rdma_event_list; + struct workqueue_struct *rdma_wq; }; struct qede_ptp; diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index e9eaa38895e6..06ca13dd9ddb 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -262,7 +262,7 @@ static int qede_netdev_event(struct notifier_block *this, unsigned long event, break; case NETDEV_CHANGEADDR: edev = netdev_priv(ndev); - qede_roce_event_changeaddr(edev); + qede_rdma_event_changeaddr(edev); break; } @@ -977,7 +977,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, qede_init_ndev(edev); - rc = qede_roce_dev_add(edev); + rc = qede_rdma_dev_add(edev); if (rc) goto err3; @@ -1013,7 +1013,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, return 0; err4: - qede_roce_dev_remove(edev); + qede_rdma_dev_remove(edev); err3: free_netdev(edev->ndev); err2: @@ -1064,7 +1064,7 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) qede_ptp_disable(edev); - qede_roce_dev_remove(edev); + qede_rdma_dev_remove(edev); edev->ops->common->set_power_state(cdev, PCI_D0); @@ -1964,7 +1964,7 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, edev->state = QEDE_STATE_CLOSED; - qede_roce_dev_event_close(edev); + qede_rdma_dev_event_close(edev); /* Close OS Tx */ netif_tx_disable(edev->ndev); @@ -2069,7 +2069,7 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, link_params.link_up = true; edev->ops->common->set_link(edev->cdev, &link_params); - qede_roce_dev_event_open(edev); + qede_rdma_dev_event_open(edev); edev->state = QEDE_STATE_OPEN; diff --git a/drivers/net/ethernet/qlogic/qede/qede_rdma.c b/drivers/net/ethernet/qlogic/qede/qede_rdma.c index 9837ee20cbae..50b142fad6b8 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_rdma.c +++ b/drivers/net/ethernet/qlogic/qede/qede_rdma.c @@ -40,12 +40,12 @@ static struct qedr_driver *qedr_drv; static LIST_HEAD(qedr_dev_list); static DEFINE_MUTEX(qedr_dev_list_lock); -bool qede_roce_supported(struct qede_dev *dev) +bool qede_rdma_supported(struct qede_dev *dev) { return dev->dev_info.common.rdma_supported; } -static void _qede_roce_dev_add(struct qede_dev *edev) +static void _qede_rdma_dev_add(struct qede_dev *edev) { if (!qedr_drv) return; @@ -54,11 +54,11 @@ static void _qede_roce_dev_add(struct qede_dev *edev) edev->ndev); } -static int qede_roce_create_wq(struct qede_dev *edev) +static int qede_rdma_create_wq(struct qede_dev *edev) { - INIT_LIST_HEAD(&edev->rdma_info.roce_event_list); - edev->rdma_info.roce_wq = create_singlethread_workqueue("roce_wq"); - if (!edev->rdma_info.roce_wq) { + INIT_LIST_HEAD(&edev->rdma_info.rdma_event_list); + edev->rdma_info.rdma_wq = create_singlethread_workqueue("rdma_wq"); + if (!edev->rdma_info.rdma_wq) { DP_NOTICE(edev, "qedr: Could not create workqueue\n"); return -ENOMEM; } @@ -66,14 +66,14 @@ static int qede_roce_create_wq(struct qede_dev *edev) return 0; } -static void qede_roce_cleanup_event(struct qede_dev *edev) +static void qede_rdma_cleanup_event(struct qede_dev *edev) { - struct list_head *head = &edev->rdma_info.roce_event_list; - struct qede_roce_event_work *event_node; + struct list_head *head = &edev->rdma_info.rdma_event_list; + struct qede_rdma_event_work *event_node; - flush_workqueue(edev->rdma_info.roce_wq); + flush_workqueue(edev->rdma_info.rdma_wq); while (!list_empty(head)) { - event_node = list_entry(head->next, struct qede_roce_event_work, + event_node = list_entry(head->next, struct qede_rdma_event_work, list); cancel_work_sync(&event_node->work); list_del(&event_node->list); @@ -81,85 +81,85 @@ static void qede_roce_cleanup_event(struct qede_dev *edev) } } -static void qede_roce_destroy_wq(struct qede_dev *edev) +static void qede_rdma_destroy_wq(struct qede_dev *edev) { - qede_roce_cleanup_event(edev); - destroy_workqueue(edev->rdma_info.roce_wq); + qede_rdma_cleanup_event(edev); + destroy_workqueue(edev->rdma_info.rdma_wq); } -int qede_roce_dev_add(struct qede_dev *edev) +int qede_rdma_dev_add(struct qede_dev *edev) { int rc = 0; - if (qede_roce_supported(edev)) { - rc = qede_roce_create_wq(edev); + if (qede_rdma_supported(edev)) { + rc = qede_rdma_create_wq(edev); if (rc) return rc; INIT_LIST_HEAD(&edev->rdma_info.entry); mutex_lock(&qedr_dev_list_lock); list_add_tail(&edev->rdma_info.entry, &qedr_dev_list); - _qede_roce_dev_add(edev); + _qede_rdma_dev_add(edev); mutex_unlock(&qedr_dev_list_lock); } return rc; } -static void _qede_roce_dev_remove(struct qede_dev *edev) +static void _qede_rdma_dev_remove(struct qede_dev *edev) { if (qedr_drv && qedr_drv->remove && edev->rdma_info.qedr_dev) qedr_drv->remove(edev->rdma_info.qedr_dev); edev->rdma_info.qedr_dev = NULL; } -void qede_roce_dev_remove(struct qede_dev *edev) +void qede_rdma_dev_remove(struct qede_dev *edev) { - if (!qede_roce_supported(edev)) + if (!qede_rdma_supported(edev)) return; - qede_roce_destroy_wq(edev); + qede_rdma_destroy_wq(edev); mutex_lock(&qedr_dev_list_lock); - _qede_roce_dev_remove(edev); + _qede_rdma_dev_remove(edev); list_del(&edev->rdma_info.entry); mutex_unlock(&qedr_dev_list_lock); } -static void _qede_roce_dev_open(struct qede_dev *edev) +static void _qede_rdma_dev_open(struct qede_dev *edev) { if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_UP); } -static void qede_roce_dev_open(struct qede_dev *edev) +static void qede_rdma_dev_open(struct qede_dev *edev) { - if (!qede_roce_supported(edev)) + if (!qede_rdma_supported(edev)) return; mutex_lock(&qedr_dev_list_lock); - _qede_roce_dev_open(edev); + _qede_rdma_dev_open(edev); mutex_unlock(&qedr_dev_list_lock); } -static void _qede_roce_dev_close(struct qede_dev *edev) +static void _qede_rdma_dev_close(struct qede_dev *edev) { if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_DOWN); } -static void qede_roce_dev_close(struct qede_dev *edev) +static void qede_rdma_dev_close(struct qede_dev *edev) { - if (!qede_roce_supported(edev)) + if (!qede_rdma_supported(edev)) return; mutex_lock(&qedr_dev_list_lock); - _qede_roce_dev_close(edev); + _qede_rdma_dev_close(edev); mutex_unlock(&qedr_dev_list_lock); } -static void qede_roce_dev_shutdown(struct qede_dev *edev) +static void qede_rdma_dev_shutdown(struct qede_dev *edev) { - if (!qede_roce_supported(edev)) + if (!qede_rdma_supported(edev)) return; mutex_lock(&qedr_dev_list_lock); @@ -168,7 +168,7 @@ static void qede_roce_dev_shutdown(struct qede_dev *edev) mutex_unlock(&qedr_dev_list_lock); } -int qede_roce_register_driver(struct qedr_driver *drv) +int qede_rdma_register_driver(struct qedr_driver *drv) { struct qede_dev *edev; u8 qedr_counter = 0; @@ -184,52 +184,52 @@ int qede_roce_register_driver(struct qedr_driver *drv) struct net_device *ndev; qedr_counter++; - _qede_roce_dev_add(edev); + _qede_rdma_dev_add(edev); ndev = edev->ndev; if (netif_running(ndev) && netif_oper_up(ndev)) - _qede_roce_dev_open(edev); + _qede_rdma_dev_open(edev); } mutex_unlock(&qedr_dev_list_lock); - pr_notice("qedr: discovered and registered %d RoCE funcs\n", + pr_notice("qedr: discovered and registered %d RDMA funcs\n", qedr_counter); return 0; } -EXPORT_SYMBOL(qede_roce_register_driver); +EXPORT_SYMBOL(qede_rdma_register_driver); -void qede_roce_unregister_driver(struct qedr_driver *drv) +void qede_rdma_unregister_driver(struct qedr_driver *drv) { struct qede_dev *edev; mutex_lock(&qedr_dev_list_lock); list_for_each_entry(edev, &qedr_dev_list, rdma_info.entry) { if (edev->rdma_info.qedr_dev) - _qede_roce_dev_remove(edev); + _qede_rdma_dev_remove(edev); } qedr_drv = NULL; mutex_unlock(&qedr_dev_list_lock); } -EXPORT_SYMBOL(qede_roce_unregister_driver); +EXPORT_SYMBOL(qede_rdma_unregister_driver); -static void qede_roce_changeaddr(struct qede_dev *edev) +static void qede_rdma_changeaddr(struct qede_dev *edev) { - if (!qede_roce_supported(edev)) + if (!qede_rdma_supported(edev)) return; if (qedr_drv && edev->rdma_info.qedr_dev && qedr_drv->notify) qedr_drv->notify(edev->rdma_info.qedr_dev, QEDE_CHANGE_ADDR); } -static struct qede_roce_event_work * -qede_roce_get_free_event_node(struct qede_dev *edev) +static struct qede_rdma_event_work * +qede_rdma_get_free_event_node(struct qede_dev *edev) { - struct qede_roce_event_work *event_node = NULL; + struct qede_rdma_event_work *event_node = NULL; struct list_head *list_node = NULL; bool found = false; - list_for_each(list_node, &edev->rdma_info.roce_event_list) { - event_node = list_entry(list_node, struct qede_roce_event_work, + list_for_each(list_node, &edev->rdma_info.rdma_event_list) { + event_node = list_entry(list_node, struct qede_rdma_event_work, list); if (!work_pending(&event_node->work)) { found = true; @@ -241,74 +241,74 @@ qede_roce_get_free_event_node(struct qede_dev *edev) event_node = kzalloc(sizeof(*event_node), GFP_KERNEL); if (!event_node) { DP_NOTICE(edev, - "qedr: Could not allocate memory for roce work\n"); + "qedr: Could not allocate memory for rdma work\n"); return NULL; } list_add_tail(&event_node->list, - &edev->rdma_info.roce_event_list); + &edev->rdma_info.rdma_event_list); } return event_node; } -static void qede_roce_handle_event(struct work_struct *work) +static void qede_rdma_handle_event(struct work_struct *work) { - struct qede_roce_event_work *event_node; - enum qede_roce_event event; + struct qede_rdma_event_work *event_node; + enum qede_rdma_event event; struct qede_dev *edev; - event_node = container_of(work, struct qede_roce_event_work, work); + event_node = container_of(work, struct qede_rdma_event_work, work); event = event_node->event; edev = event_node->ptr; switch (event) { case QEDE_UP: - qede_roce_dev_open(edev); + qede_rdma_dev_open(edev); break; case QEDE_DOWN: - qede_roce_dev_close(edev); + qede_rdma_dev_close(edev); break; case QEDE_CLOSE: - qede_roce_dev_shutdown(edev); + qede_rdma_dev_shutdown(edev); break; case QEDE_CHANGE_ADDR: - qede_roce_changeaddr(edev); + qede_rdma_changeaddr(edev); break; default: - DP_NOTICE(edev, "Invalid roce event %d", event); + DP_NOTICE(edev, "Invalid rdma event %d", event); } } -static void qede_roce_add_event(struct qede_dev *edev, - enum qede_roce_event event) +static void qede_rdma_add_event(struct qede_dev *edev, + enum qede_rdma_event event) { - struct qede_roce_event_work *event_node; + struct qede_rdma_event_work *event_node; if (!edev->rdma_info.qedr_dev) return; - event_node = qede_roce_get_free_event_node(edev); + event_node = qede_rdma_get_free_event_node(edev); if (!event_node) return; event_node->event = event; event_node->ptr = edev; - INIT_WORK(&event_node->work, qede_roce_handle_event); - queue_work(edev->rdma_info.roce_wq, &event_node->work); + INIT_WORK(&event_node->work, qede_rdma_handle_event); + queue_work(edev->rdma_info.rdma_wq, &event_node->work); } -void qede_roce_dev_event_open(struct qede_dev *edev) +void qede_rdma_dev_event_open(struct qede_dev *edev) { - qede_roce_add_event(edev, QEDE_UP); + qede_rdma_add_event(edev, QEDE_UP); } -void qede_roce_dev_event_close(struct qede_dev *edev) +void qede_rdma_dev_event_close(struct qede_dev *edev) { - qede_roce_add_event(edev, QEDE_DOWN); + qede_rdma_add_event(edev, QEDE_DOWN); } -void qede_roce_event_changeaddr(struct qede_dev *edev) +void qede_rdma_event_changeaddr(struct qede_dev *edev) { - qede_roce_add_event(edev, QEDE_CHANGE_ADDR); + qede_rdma_add_event(edev, QEDE_CHANGE_ADDR); } -- cgit v1.2.3 From 898fff120d9e73c2432432d4e457bf584b2a9df7 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Tue, 20 Jun 2017 16:00:05 +0300 Subject: qed: Wait for resources before FUNC_CLOSE Driver needs to wait for all resources to return from FW before it can send the FUNC_CLOSE ramrod. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_roce.c | 35 +++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 8419dcc111d8..74829058d6ec 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -372,22 +372,7 @@ end: static void qed_rdma_resc_free(struct qed_hwfn *p_hwfn) { - struct qed_bmap *rcid_map = &p_hwfn->p_rdma_info->real_cid_map; struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; - int wait_count = 0; - - /* when destroying a_RoCE QP the control is returned to the user after - * the synchronous part. The asynchronous part may take a little longer. - * We delay for a short while if an async destroy QP is still expected. - * Beyond the added delay we clear the bitmap anyway. - */ - while (bitmap_weight(rcid_map->bitmap, rcid_map->max_count)) { - msleep(100); - if (wait_count++ > 20) { - DP_NOTICE(p_hwfn, "cid bitmap wait timed out\n"); - break; - } - } qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->cid_map, 1); qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->pd_map, 1); @@ -704,6 +689,25 @@ static int qed_rdma_setup(struct qed_hwfn *p_hwfn, return qed_rdma_start_fw(p_hwfn, params, p_ptt); } +void qed_roce_stop(struct qed_hwfn *p_hwfn) +{ + struct qed_bmap *rcid_map = &p_hwfn->p_rdma_info->real_cid_map; + int wait_count = 0; + + /* when destroying a_RoCE QP the control is returned to the user after + * the synchronous part. The asynchronous part may take a little longer. + * We delay for a short while if an async destroy QP is still expected. + * Beyond the added delay we clear the bitmap anyway. + */ + while (bitmap_weight(rcid_map->bitmap, rcid_map->max_count)) { + msleep(100); + if (wait_count++ > 20) { + DP_NOTICE(p_hwfn, "cid bitmap wait timed out\n"); + break; + } + } +} + static int qed_rdma_stop(void *rdma_cxt) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; @@ -733,6 +737,7 @@ static int qed_rdma_stop(void *rdma_cxt) qed_wr(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN, (ll2_ethertype_en & 0xFFFE)); + qed_roce_stop(p_hwfn); qed_ptt_release(p_hwfn, p_ptt); /* Get SPQ entry */ -- cgit v1.2.3 From 6c9e80ea571db545a0baff1e0f48ae75a7ed127d Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Tue, 20 Jun 2017 16:00:06 +0300 Subject: qed: SPQ async callback registration Whenever firmware indicates that there's an async indication it needs to handle, there's a switch-case where the right functionality is called based on function's personality and information. Before iWARP is added [as yet another client], switch over the SPQ into a callback-registered mechanism, allowing registration of the relevant event-processing logic based on the function's personality. This allows us to tidy the code by removing protocol-specifics from a common file. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 24 ++++++++++++- drivers/net/ethernet/qlogic/qed/qed_roce.c | 16 ++++++--- drivers/net/ethernet/qlogic/qed/qed_roce.h | 6 ---- drivers/net/ethernet/qlogic/qed/qed_sp.h | 17 +++++++++ drivers/net/ethernet/qlogic/qed/qed_spq.c | 54 ++++++++++++++++------------- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 16 +++++++-- drivers/net/ethernet/qlogic/qed/qed_sriov.h | 18 ---------- 7 files changed, 96 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index 5a1ed05d0c5f..813c77cc857f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -62,6 +62,22 @@ #include "qed_sriov.h" #include "qed_reg_addr.h" +static int +qed_iscsi_async_event(struct qed_hwfn *p_hwfn, + u8 fw_event_code, + u16 echo, union event_ring_data *data, u8 fw_return_code) +{ + if (p_hwfn->p_iscsi_info->event_cb) { + struct qed_iscsi_info *p_iscsi = p_hwfn->p_iscsi_info; + + return p_iscsi->event_cb(p_iscsi->event_context, + fw_event_code, data); + } else { + DP_NOTICE(p_hwfn, "iSCSI async completion is not set\n"); + return -EINVAL; + } +} + struct qed_iscsi_conn { struct list_head list_entry; bool free_on_delete; @@ -265,6 +281,9 @@ qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn, p_hwfn->p_iscsi_info->event_context = event_context; p_hwfn->p_iscsi_info->event_cb = async_event_cb; + qed_spq_register_async_cb(p_hwfn, PROTOCOLID_ISCSI, + qed_iscsi_async_event); + return qed_spq_post(p_hwfn, p_ent, NULL); } @@ -631,7 +650,10 @@ static int qed_sp_iscsi_func_stop(struct qed_hwfn *p_hwfn, p_ramrod = &p_ent->ramrod.iscsi_destroy; p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_DESTROY_FUNC; - return qed_spq_post(p_hwfn, p_ent, NULL); + rc = qed_spq_post(p_hwfn, p_ent, NULL); + + qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_ISCSI); + return rc; } static void __iomem *qed_iscsi_get_db_addr(struct qed_hwfn *p_hwfn, u32 cid) diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 74829058d6ec..673f80aa690d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -68,12 +68,14 @@ static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid); -void qed_roce_async_event(struct qed_hwfn *p_hwfn, - u8 fw_event_code, union rdma_eqe_data *rdma_data) +static int +qed_roce_async_event(struct qed_hwfn *p_hwfn, + u8 fw_event_code, + u16 echo, union event_ring_data *data, u8 fw_return_code) { if (fw_event_code == ROCE_ASYNC_EVENT_DESTROY_QP_DONE) { u16 icid = - (u16)le32_to_cpu(rdma_data->rdma_destroy_qp_data.cid); + (u16)le32_to_cpu(data->rdma_data.rdma_destroy_qp_data.cid); /* icid release in this async event can occur only if the icid * was offloaded to the FW. In case it wasn't offloaded this is @@ -85,8 +87,10 @@ void qed_roce_async_event(struct qed_hwfn *p_hwfn, events->affiliated_event(p_hwfn->p_rdma_info->events.context, fw_event_code, - &rdma_data->async_handle); + (void *)&data->rdma_data.async_handle); } + + return 0; } static int qed_rdma_bmap_alloc(struct qed_hwfn *p_hwfn, @@ -686,6 +690,9 @@ static int qed_rdma_setup(struct qed_hwfn *p_hwfn, if (rc) return rc; + qed_spq_register_async_cb(p_hwfn, PROTOCOLID_ROCE, + qed_roce_async_event); + return qed_rdma_start_fw(p_hwfn, params, p_ptt); } @@ -706,6 +713,7 @@ void qed_roce_stop(struct qed_hwfn *p_hwfn) break; } } + qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_ROCE); } static int qed_rdma_stop(void *rdma_cxt) diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.h b/drivers/net/ethernet/qlogic/qed/qed_roce.h index ddd77618e6fa..b178d9994a45 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.h +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.h @@ -169,16 +169,10 @@ struct qed_rdma_qp { #if IS_ENABLED(CONFIG_QED_RDMA) void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); -void qed_roce_async_event(struct qed_hwfn *p_hwfn, - u8 fw_event_code, union rdma_eqe_data *rdma_data); #else static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} static inline void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} - -static inline void qed_roce_async_event(struct qed_hwfn *p_hwfn, - u8 fw_event_code, - union rdma_eqe_data *rdma_data) {} #endif #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index 00dd50f8c42f..56c95fb9a26d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -174,6 +174,22 @@ struct qed_consq { struct qed_chain chain; }; +typedef int +(*qed_spq_async_comp_cb)(struct qed_hwfn *p_hwfn, + u8 opcode, + u16 echo, + union event_ring_data *data, + u8 fw_return_code); + +int +qed_spq_register_async_cb(struct qed_hwfn *p_hwfn, + enum protocol_type protocol_id, + qed_spq_async_comp_cb cb); + +void +qed_spq_unregister_async_cb(struct qed_hwfn *p_hwfn, + enum protocol_type protocol_id); + struct qed_spq { spinlock_t lock; /* SPQ lock */ @@ -203,6 +219,7 @@ struct qed_spq { u32 comp_count; u32 cid; + qed_spq_async_comp_cb async_comp_cb[MAX_PROTOCOL_TYPE]; }; /** diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index a971916af7cc..78954d2c596e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -302,32 +302,16 @@ static int qed_async_event_completion(struct qed_hwfn *p_hwfn, struct event_ring_entry *p_eqe) { - switch (p_eqe->protocol_id) { -#if IS_ENABLED(CONFIG_QED_RDMA) - case PROTOCOLID_ROCE: - qed_roce_async_event(p_hwfn, p_eqe->opcode, - &p_eqe->data.rdma_data); - return 0; -#endif - case PROTOCOLID_COMMON: - return qed_sriov_eqe_event(p_hwfn, - p_eqe->opcode, - p_eqe->echo, &p_eqe->data); - case PROTOCOLID_ISCSI: - if (!IS_ENABLED(CONFIG_QED_ISCSI)) - return -EINVAL; + qed_spq_async_comp_cb cb; - if (p_hwfn->p_iscsi_info->event_cb) { - struct qed_iscsi_info *p_iscsi = p_hwfn->p_iscsi_info; + if (!p_hwfn->p_spq || (p_eqe->protocol_id >= MAX_PROTOCOL_TYPE)) + return -EINVAL; - return p_iscsi->event_cb(p_iscsi->event_context, - p_eqe->opcode, &p_eqe->data); - } else { - DP_NOTICE(p_hwfn, - "iSCSI async completion is not set\n"); - return -EINVAL; - } - default: + cb = p_hwfn->p_spq->async_comp_cb[p_eqe->protocol_id]; + if (cb) { + return cb(p_hwfn, p_eqe->opcode, p_eqe->echo, + &p_eqe->data, p_eqe->fw_return_code); + } else { DP_NOTICE(p_hwfn, "Unknown Async completion for protocol: %d\n", p_eqe->protocol_id); @@ -335,6 +319,28 @@ qed_async_event_completion(struct qed_hwfn *p_hwfn, } } +int +qed_spq_register_async_cb(struct qed_hwfn *p_hwfn, + enum protocol_type protocol_id, + qed_spq_async_comp_cb cb) +{ + if (!p_hwfn->p_spq || (protocol_id >= MAX_PROTOCOL_TYPE)) + return -EINVAL; + + p_hwfn->p_spq->async_comp_cb[protocol_id] = cb; + return 0; +} + +void +qed_spq_unregister_async_cb(struct qed_hwfn *p_hwfn, + enum protocol_type protocol_id) +{ + if (!p_hwfn->p_spq || (protocol_id >= MAX_PROTOCOL_TYPE)) + return; + + p_hwfn->p_spq->async_comp_cb[protocol_id] = NULL; +} + /*************************************************************************** * EQ API ***************************************************************************/ diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index e39ad22947cf..2cfd3bd9a031 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -44,6 +44,11 @@ #include "qed_sp.h" #include "qed_sriov.h" #include "qed_vf.h" +static int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn, + u8 opcode, + __le16 echo, + union event_ring_data *data, u8 fw_return_code); + static u8 qed_vf_calculate_legacy(struct qed_vf_info *p_vf) { @@ -565,6 +570,9 @@ int qed_iov_alloc(struct qed_hwfn *p_hwfn) p_hwfn->pf_iov_info = p_sriov; + qed_spq_register_async_cb(p_hwfn, PROTOCOLID_COMMON, + qed_sriov_eqe_event); + return qed_iov_allocate_vfdb(p_hwfn); } @@ -578,6 +586,8 @@ void qed_iov_setup(struct qed_hwfn *p_hwfn) void qed_iov_free(struct qed_hwfn *p_hwfn) { + qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_COMMON); + if (IS_PF_SRIOV_ALLOC(p_hwfn)) { qed_iov_free_vfdb(p_hwfn); kfree(p_hwfn->pf_iov_info); @@ -3833,8 +3843,10 @@ static void qed_sriov_vfpf_malicious(struct qed_hwfn *p_hwfn, } } -int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn, - u8 opcode, __le16 echo, union event_ring_data *data) +static int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn, + u8 opcode, + __le16 echo, + union event_ring_data *data, u8 fw_return_code) { switch (opcode) { case COMMON_EVENT_VF_PF_CHANNEL: diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index 95f55ae2ee8b..c2e44bce398c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -343,17 +343,6 @@ void qed_iov_free(struct qed_hwfn *p_hwfn); */ void qed_iov_free_hw_info(struct qed_dev *cdev); -/** - * @brief qed_sriov_eqe_event - handle async sriov event arrived on eqe. - * - * @param p_hwfn - * @param opcode - * @param echo - * @param data - */ -int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn, - u8 opcode, __le16 echo, union event_ring_data *data); - /** * @brief Mark structs of vfs that have been FLR-ed. * @@ -418,13 +407,6 @@ static inline void qed_iov_free_hw_info(struct qed_dev *cdev) { } -static inline int qed_sriov_eqe_event(struct qed_hwfn *p_hwfn, - u8 opcode, - __le16 echo, union event_ring_data *data) -{ - return -EINVAL; -} - static inline bool qed_iov_mark_vf_flr(struct qed_hwfn *p_hwfn, u32 *disabled_vfs) { -- cgit v1.2.3 From 1450ba8a61a96a7f7f9742e149ea6aaf90817e20 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 17 Jun 2017 22:07:36 +0800 Subject: net-next: stmmac: dwmac-sun8i: force EPHY clock freq to 24MHz The EPHY control part of the EMAC syscon register has a bit called CLK_SEL. On the datasheet it says that if it's 0 the EPHY clock is 25MHz and if it's 1 the clock is 24MHz. However, according to the datasheets, no Allwinner SoC with EPHY has any extra xtal input pins for the EPHY, and the system xtal is 24MHz. That means the EPHY is not possible to get a 25MHz xtal input, and thus the frequency can only be 24MHz. It doesn't matter on H3 as the default value of H3 is 24MHz, however on V3s the default value is wrongly set to 25MHz, which prevented the EPHY from working properly. Force the EPHY clock frequency to 24MHz. Signed-off-by: Icenowy Zheng Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index 54f93ee53ef7..61ce3b54f0c6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -185,6 +185,7 @@ static const struct emac_variant emac_variant_a64 = { /* H3 specific bits for EPHY */ #define H3_EPHY_ADDR_SHIFT 20 +#define H3_EPHY_CLK_SEL BIT(18) /* 1: 24MHz, 0: 25MHz */ #define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */ #define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */ #define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */ @@ -656,6 +657,9 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) else reg &= ~H3_EPHY_LED_POL; + /* Force EPHY xtal frequency to 24MHz. */ + reg |= H3_EPHY_CLK_SEL; + ret = of_mdio_parse_addr(priv->device, priv->plat->phy_node); if (ret < 0) { -- cgit v1.2.3 From 57fde47db808346287fbe931d0346d90c4229387 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 17 Jun 2017 22:07:37 +0800 Subject: net-next: stmmac: dwmac-sun8i: add support for V3s EMAC Allwinner V3s SoC has an Ethernet MAC and an internal PHY like the ones in H3 SoC, however the MAC has no external *MII interfaces available at GPIOs, thus only MII connection to internal PHY is supported. Add this variant of EMAC to dwmac-sun8i driver. The default value of the syscon EMAC-related register seems to have changed from H3, but it seems to be a harmless change. Signed-off-by: Icenowy Zheng Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 8 ++++++++ drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 1 + 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index 61ce3b54f0c6..fffd6d5fc907 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -81,6 +81,12 @@ static const struct emac_variant emac_variant_h3 = { .support_rgmii = true }; +static const struct emac_variant emac_variant_v3s = { + .default_syscon_value = 0x38000, + .internal_phy = PHY_INTERFACE_MODE_MII, + .support_mii = true +}; + static const struct emac_variant emac_variant_a83t = { .default_syscon_value = 0, .internal_phy = 0, @@ -975,6 +981,8 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) static const struct of_device_id sun8i_dwmac_match[] = { { .compatible = "allwinner,sun8i-h3-emac", .data = &emac_variant_h3 }, + { .compatible = "allwinner,sun8i-v3s-emac", + .data = &emac_variant_v3s }, { .compatible = "allwinner,sun8i-a83t-emac", .data = &emac_variant_a83t }, { .compatible = "allwinner,sun50i-a64-emac", diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 3840529344ed..a366b3747eeb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -313,6 +313,7 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat, { .compatible = "snps,dwc-qos-ethernet-4.10" }, { .compatible = "allwinner,sun8i-a83t-emac" }, { .compatible = "allwinner,sun8i-h3-emac" }, + { .compatible = "allwinner,sun8i-v3s-emac" }, { .compatible = "allwinner,sun50i-a64-emac" }, }; -- cgit v1.2.3 From cd8da8bb0ec199d00f055fb6ceb4c15ce0aaf562 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:36 -0400 Subject: net: dsa: mv88e6xxx: add irl_init_all op Some Marvell chips have an Ingress Rate Limit unit. But the command values slightly differs between models: 88E6352 use 3-bit for operations while 88E6390 use different 2-bit operations. This commit kills the IRL flags in favor of a new operation implementing the "Init all resources to the initial state" operation. This fixes the operation of 88E6390 family where 0x1000 means Read the selected resource 0, register 0 on port 16, instead of init all. A mv88e6xxx_irl_setup helper is added to wrap the operation call. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 47 ++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 19 +++---------- drivers/net/dsa/mv88e6xxx/global2.c | 54 ++++++++++++++++++------------------- drivers/net/dsa/mv88e6xxx/global2.h | 46 ++++++++++++++++++++++++++----- 4 files changed, 116 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 19772e3dd67e..53b088166c28 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -941,6 +941,26 @@ static int mv88e6xxx_atu_setup(struct mv88e6xxx_chip *chip) return mv88e6xxx_g1_atu_set_age_time(chip, 300000); } +static int mv88e6xxx_irl_setup(struct mv88e6xxx_chip *chip) +{ + int port; + int err; + + if (!chip->info->ops->irl_init_all) + return 0; + + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { + /* Disable ingress rate limiting by resetting all per port + * ingress rate limit resources to their initial state. + */ + err = chip->info->ops->irl_init_all(chip, port); + if (err) + return err; + } + + return 0; +} + static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) { u16 pvlan = 0; @@ -2102,6 +2122,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) goto unlock; } + err = mv88e6xxx_irl_setup(chip); + if (err) + goto unlock; + err = mv88e6xxx_phy_setup(chip); if (err) goto unlock; @@ -2339,6 +2363,7 @@ static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, static const struct mv88e6xxx_ops mv88e6085_ops = { /* MV88E6XXX_FAMILY_6097 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .set_switch_mac = mv88e6xxx_g1_set_switch_mac, .phy_read = mv88e6185_phy_ppu_read, .phy_write = mv88e6185_phy_ppu_write, @@ -2393,6 +2418,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = { static const struct mv88e6xxx_ops mv88e6097_ops = { /* MV88E6XXX_FAMILY_6097 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, @@ -2423,6 +2449,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { static const struct mv88e6xxx_ops mv88e6123_ops = { /* MV88E6XXX_FAMILY_6165 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, @@ -2479,6 +2506,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = { static const struct mv88e6xxx_ops mv88e6141_ops = { /* MV88E6XXX_FAMILY_6341 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2512,6 +2540,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { static const struct mv88e6xxx_ops mv88e6161_ops = { /* MV88E6XXX_FAMILY_6165 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, @@ -2542,6 +2571,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { static const struct mv88e6xxx_ops mv88e6165_ops = { /* MV88E6XXX_FAMILY_6165 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, .phy_read = mv88e6165_phy_read, .phy_write = mv88e6165_phy_write, @@ -2565,6 +2595,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = { static const struct mv88e6xxx_ops mv88e6171_ops = { /* MV88E6XXX_FAMILY_6351 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, @@ -2596,6 +2627,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { static const struct mv88e6xxx_ops mv88e6172_ops = { /* MV88E6XXX_FAMILY_6352 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom16, .set_eeprom = mv88e6xxx_g2_set_eeprom16, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2630,6 +2662,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { static const struct mv88e6xxx_ops mv88e6175_ops = { /* MV88E6XXX_FAMILY_6351 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, @@ -2661,6 +2694,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = { static const struct mv88e6xxx_ops mv88e6176_ops = { /* MV88E6XXX_FAMILY_6352 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom16, .set_eeprom = mv88e6xxx_g2_set_eeprom16, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2722,6 +2756,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { static const struct mv88e6xxx_ops mv88e6190_ops = { /* MV88E6XXX_FAMILY_6390 */ + .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2755,6 +2790,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { static const struct mv88e6xxx_ops mv88e6190x_ops = { /* MV88E6XXX_FAMILY_6390 */ + .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2788,6 +2824,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { static const struct mv88e6xxx_ops mv88e6191_ops = { /* MV88E6XXX_FAMILY_6390 */ + .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2821,6 +2858,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { static const struct mv88e6xxx_ops mv88e6240_ops = { /* MV88E6XXX_FAMILY_6352 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom16, .set_eeprom = mv88e6xxx_g2_set_eeprom16, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2855,6 +2893,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { static const struct mv88e6xxx_ops mv88e6290_ops = { /* MV88E6XXX_FAMILY_6390 */ + .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2889,6 +2928,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { static const struct mv88e6xxx_ops mv88e6320_ops = { /* MV88E6XXX_FAMILY_6320 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom16, .set_eeprom = mv88e6xxx_g2_set_eeprom16, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2920,6 +2960,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { static const struct mv88e6xxx_ops mv88e6321_ops = { /* MV88E6XXX_FAMILY_6321 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom16, .set_eeprom = mv88e6xxx_g2_set_eeprom16, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2950,6 +2991,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { static const struct mv88e6xxx_ops mv88e6341_ops = { /* MV88E6XXX_FAMILY_6341 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -2983,6 +3025,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { static const struct mv88e6xxx_ops mv88e6350_ops = { /* MV88E6XXX_FAMILY_6351 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, @@ -3014,6 +3057,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = { static const struct mv88e6xxx_ops mv88e6351_ops = { /* MV88E6XXX_FAMILY_6351 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, @@ -3045,6 +3089,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { static const struct mv88e6xxx_ops mv88e6352_ops = { /* MV88E6XXX_FAMILY_6352 */ + .irl_init_all = mv88e6352_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom16, .set_eeprom = mv88e6xxx_g2_set_eeprom16, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -3079,6 +3124,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { static const struct mv88e6xxx_ops mv88e6390_ops = { /* MV88E6XXX_FAMILY_6390 */ + .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, @@ -3115,6 +3161,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { static const struct mv88e6xxx_ops mv88e6390x_ops = { /* MV88E6XXX_FAMILY_6390 */ + .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, .set_switch_mac = mv88e6xxx_g2_set_switch_mac, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 409452ebc4b9..086444016352 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -121,8 +121,6 @@ enum mv88e6xxx_cap { MV88E6XXX_CAP_G2_INT, /* (0x00) Interrupt Status */ MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */ MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */ - MV88E6XXX_CAP_G2_IRL_CMD, /* (0x09) Ingress Rate Command */ - MV88E6XXX_CAP_G2_IRL_DATA, /* (0x0a) Ingress Rate Data */ MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */ /* Per VLAN Spanning Tree Unit (STU). @@ -149,15 +147,8 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_G2_INT BIT_ULL(MV88E6XXX_CAP_G2_INT) #define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_2X) #define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT_ULL(MV88E6XXX_CAP_G2_MGMT_EN_0X) -#define MV88E6XXX_FLAG_G2_IRL_CMD BIT_ULL(MV88E6XXX_CAP_G2_IRL_CMD) -#define MV88E6XXX_FLAG_G2_IRL_DATA BIT_ULL(MV88E6XXX_CAP_G2_IRL_DATA) #define MV88E6XXX_FLAG_G2_POT BIT_ULL(MV88E6XXX_CAP_G2_POT) -/* Ingress Rate Limit unit */ -#define MV88E6XXX_FLAGS_IRL \ - (MV88E6XXX_FLAG_G2_IRL_CMD | \ - MV88E6XXX_FLAG_G2_IRL_DATA) - /* Multi-chip Addressing Mode */ #define MV88E6XXX_FLAGS_MULTI_CHIP \ (MV88E6XXX_FLAG_SMI_CMD | \ @@ -175,7 +166,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6165 \ @@ -185,7 +175,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6185 \ @@ -200,7 +189,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6341 \ @@ -209,7 +197,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_INT | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6351 \ @@ -219,7 +206,6 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6352 \ @@ -230,14 +216,12 @@ enum mv88e6xxx_cap { MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ MV88E6XXX_FLAG_G2_POT | \ - MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) #define MV88E6XXX_FLAGS_FAMILY_6390 \ (MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_GLOBAL2 | \ MV88E6XXX_FLAG_G2_INT | \ - MV88E6XXX_FLAGS_IRL | \ MV88E6XXX_FLAGS_MULTI_CHIP) struct mv88e6xxx_ops; @@ -358,6 +342,9 @@ struct mv88e6xxx_mdio_bus { }; struct mv88e6xxx_ops { + /* Ingress Rate Limit unit (IRL) operations */ + int (*irl_init_all)(struct mv88e6xxx_chip *chip, int port); + int (*get_eeprom)(struct mv88e6xxx_chip *chip, struct ethtool_eeprom *eeprom, u8 *data); int (*set_eeprom)(struct mv88e6xxx_chip *chip, diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 8e8bc4ee464f..baa86b1abad3 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -149,27 +149,36 @@ static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip) * Offset 0x0A: Ingress Rate Data register */ -static int mv88e6xxx_g2_clear_irl(struct mv88e6xxx_chip *chip) +static int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip) { - int port, err; - - /* Init all Ingress Rate Limit resources of all ports */ - for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { - /* XXX newer chips (like 88E6390) have different 2-bit ops */ - err = mv88e6xxx_g2_write(chip, GLOBAL2_IRL_CMD, - GLOBAL2_IRL_CMD_OP_INIT_ALL | - (port << 8)); - if (err) - break; + return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_IRL_CMD, + MV88E6XXX_G2_IRL_CMD_BUSY); +} - /* Wait for the operation to complete */ - err = mv88e6xxx_g2_wait(chip, GLOBAL2_IRL_CMD, - GLOBAL2_IRL_CMD_BUSY); - if (err) - break; - } +static int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port, + int res, int reg) +{ + int err; - return err; + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_IRL_CMD, + MV88E6XXX_G2_IRL_CMD_BUSY | op | (port << 8) | + (res << 5) | reg); + if (err) + return err; + + return mv88e6xxx_g2_irl_wait(chip); +} + +int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port) +{ + return mv88e6xxx_g2_irl_op(chip, MV88E6352_G2_IRL_CMD_OP_INIT_ALL, port, + 0, 0); +} + +int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port) +{ + return mv88e6xxx_g2_irl_op(chip, MV88E6390_G2_IRL_CMD_OP_INIT_ALL, port, + 0, 0); } /* Offset 0x0B: Cross-chip Port VLAN (Addr) Register @@ -1030,15 +1039,6 @@ int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) if (err) return err; - if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_IRL)) { - /* Disable ingress rate limiting by resetting all per port - * ingress rate limit resources to their initial state. - */ - err = mv88e6xxx_g2_clear_irl(chip); - if (err) - return err; - } - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) { /* Clear the priority override table. */ err = mv88e6xxx_g2_clear_pot(chip); diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 479d42971706..6843b8b4bfee 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -42,13 +42,30 @@ #define GLOBAL2_TRUNK_MAPPING 0x08 #define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) #define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 -#define GLOBAL2_IRL_CMD 0x09 -#define GLOBAL2_IRL_CMD_BUSY BIT(15) -#define GLOBAL2_IRL_CMD_OP_INIT_ALL ((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_INIT_SEL ((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_WRITE_SEL ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_CMD_OP_READ_SEL ((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY) -#define GLOBAL2_IRL_DATA 0x0a + +/* Offset 0x09: Ingress Rate Command Register */ +#define MV88E6XXX_G2_IRL_CMD 0x09 +#define MV88E6XXX_G2_IRL_CMD_BUSY 0x8000 +#define MV88E6352_G2_IRL_CMD_OP_MASK 0x7000 +#define MV88E6352_G2_IRL_CMD_OP_NOOP 0x0000 +#define MV88E6352_G2_IRL_CMD_OP_INIT_ALL 0x1000 +#define MV88E6352_G2_IRL_CMD_OP_INIT_RES 0x2000 +#define MV88E6352_G2_IRL_CMD_OP_WRITE_REG 0x3000 +#define MV88E6352_G2_IRL_CMD_OP_READ_REG 0x4000 +#define MV88E6390_G2_IRL_CMD_OP_MASK 0x6000 +#define MV88E6390_G2_IRL_CMD_OP_READ_REG 0x0000 +#define MV88E6390_G2_IRL_CMD_OP_INIT_ALL 0x2000 +#define MV88E6390_G2_IRL_CMD_OP_INIT_RES 0x4000 +#define MV88E6390_G2_IRL_CMD_OP_WRITE_REG 0x6000 +#define MV88E6352_G2_IRL_CMD_PORT_MASK 0x0f00 +#define MV88E6390_G2_IRL_CMD_PORT_MASK 0x1f00 +#define MV88E6XXX_G2_IRL_CMD_RES_MASK 0x00e0 +#define MV88E6XXX_G2_IRL_CMD_REG_MASK 0x000f + +/* Offset 0x0A: Ingress Rate Data Register */ +#define MV88E6XXX_G2_IRL_DATA 0x0a +#define MV88E6XXX_G2_IRL_DATA_MASK 0xffff + #define GLOBAL2_PVT_ADDR 0x0b #define GLOBAL2_PVT_ADDR_BUSY BIT(15) #define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) @@ -127,6 +144,9 @@ static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip) return 0; } +int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port); +int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port); + int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 *val); @@ -169,6 +189,18 @@ static inline int mv88e6xxx_g2_require(struct mv88e6xxx_chip *chip) return 0; } +static inline int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, + int port) +{ + return -EOPNOTSUPP; +} + +static inline int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, + int port) +{ + return -EOPNOTSUPP; +} + static inline int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 *val) -- cgit v1.2.3 From e289ef0ded13021db292be9aef134451546e7c60 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:37 -0400 Subject: net: dsa: mv88e6xxx: clarify SMI PHY functions Marvell chips with an SMI PHY access in Global 2 registers handle both Clause 22 and Clause 45 of IEEE 802.3. The 88E6390 family has addition bits to target the internal or external PHYs connected to the device, and a Setup function in addition to the default (register) Access function. Prefix the SMI PHY Command and Data registers macros, implement clear helpers for Clause 22 and 44 Access functions, rename variable to match the SMI and switch vocabulary (device and register addresses for Clause 22 and port and device class for Clause 45.) Finally do not use complex macros but simple 16-bit mask to document the registers organization. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 200 +++++++++++++++++++++--------------- drivers/net/dsa/mv88e6xxx/global2.h | 43 ++++---- 2 files changed, 143 insertions(+), 100 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index baa86b1abad3..f20a60af35cb 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -13,6 +13,7 @@ * (at your option) any later version. */ +#include #include #include @@ -541,171 +542,206 @@ int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip, static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip) { - return mv88e6xxx_g2_wait(chip, GLOBAL2_SMI_PHY_CMD, - GLOBAL2_SMI_PHY_CMD_BUSY); + return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_SMI_PHY_CMD, + MV88E6XXX_G2_SMI_PHY_CMD_BUSY); } static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd) { int err; - err = mv88e6xxx_g2_write(chip, GLOBAL2_SMI_PHY_CMD, cmd); + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD, + MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd); if (err) return err; return mv88e6xxx_g2_smi_phy_wait(chip); } -static int mv88e6xxx_g2_smi_phy_write_addr(struct mv88e6xxx_chip *chip, - int addr, int device, int reg, - bool external) +static int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip, + bool external, bool c45, u16 op, int dev, + int reg) { - int cmd = SMI_CMD_OP_45_WRITE_ADDR | (addr << 5) | device; - int err; + u16 cmd = op; if (external) - cmd |= GLOBAL2_SMI_PHY_CMD_EXTERNAL; + cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL; + else + cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */ - err = mv88e6xxx_g2_smi_phy_wait(chip); - if (err) - return err; + if (c45) + cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */ + else + cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22; - err = mv88e6xxx_g2_write(chip, GLOBAL2_SMI_PHY_DATA, reg); - if (err) - return err; + dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK); + cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK; + cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK; return mv88e6xxx_g2_smi_phy_cmd(chip, cmd); } -static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip, - int addr, int reg_c45, u16 *val, - bool external) +static int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip, + bool external, u16 op, int dev, + int reg) +{ + return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg); +} + +/* IEEE 802.3 Clause 22 Read Data Register */ +static int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip, + bool external, int dev, int reg, + u16 *data) { - int device = (reg_c45 >> 16) & 0x1f; - int reg = reg_c45 & 0xffff; + u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA; int err; - u16 cmd; - err = mv88e6xxx_g2_smi_phy_write_addr(chip, addr, device, reg, - external); + err = mv88e6xxx_g2_smi_phy_wait(chip); + if (err) + return err; + + err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg); if (err) return err; - cmd = GLOBAL2_SMI_PHY_CMD_OP_45_READ_DATA | (addr << 5) | device; + return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data); +} - if (external) - cmd |= GLOBAL2_SMI_PHY_CMD_EXTERNAL; +/* IEEE 802.3 Clause 22 Write Data Register */ +static int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip, + bool external, int dev, int reg, + u16 data) +{ + u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA; + int err; - err = mv88e6xxx_g2_smi_phy_cmd(chip, cmd); + err = mv88e6xxx_g2_smi_phy_wait(chip); if (err) return err; - err = mv88e6xxx_g2_read(chip, GLOBAL2_SMI_PHY_DATA, val); + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data); if (err) return err; - err = *val; + return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg); +} - return 0; +static int mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip *chip, + bool external, u16 op, int port, + int dev) +{ + return mv88e6xxx_g2_smi_phy_access(chip, external, true, op, port, dev); } -static int mv88e6xxx_g2_smi_phy_read_c22(struct mv88e6xxx_chip *chip, - int addr, int reg, u16 *val, - bool external) +/* IEEE 802.3 Clause 45 Write Address Register */ +static int mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip *chip, + bool external, int port, int dev, + int addr) { - u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA | (addr << 5) | reg; + u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR; int err; - if (external) - cmd |= GLOBAL2_SMI_PHY_CMD_EXTERNAL; - err = mv88e6xxx_g2_smi_phy_wait(chip); if (err) return err; - err = mv88e6xxx_g2_smi_phy_cmd(chip, cmd); + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, addr); if (err) return err; - return mv88e6xxx_g2_read(chip, GLOBAL2_SMI_PHY_DATA, val); + return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev); } -int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, - int addr, int reg, u16 *val) +/* IEEE 802.3 Clause 45 Read Data Register */ +static int mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip *chip, + bool external, int port, int dev, + u16 *data) { - struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; - bool external = mdio_bus->external; + u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA; + int err; - if (reg & MII_ADDR_C45) - return mv88e6xxx_g2_smi_phy_read_c45(chip, addr, reg, val, - external); - return mv88e6xxx_g2_smi_phy_read_c22(chip, addr, reg, val, external); + err = mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev); + if (err) + return err; + + return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data); } -static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip, - int addr, int reg_c45, u16 val, - bool external) +static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip, + bool external, int port, int reg, + u16 *data) { - int device = (reg_c45 >> 16) & 0x1f; - int reg = reg_c45 & 0xffff; + int dev = (reg >> 16) & 0x1f; + int addr = reg & 0xffff; int err; - u16 cmd; - err = mv88e6xxx_g2_smi_phy_write_addr(chip, addr, device, reg, - external); + err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev, + addr); if (err) return err; - cmd = GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_DATA | (addr << 5) | device; - - if (external) - cmd |= GLOBAL2_SMI_PHY_CMD_EXTERNAL; + return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, dev, + data); +} - err = mv88e6xxx_g2_write(chip, GLOBAL2_SMI_PHY_DATA, val); - if (err) - return err; +/* IEEE 802.3 Clause 45 Write Data Register */ +static int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip, + bool external, int port, int dev, + u16 data) +{ + u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA; + int err; - err = mv88e6xxx_g2_smi_phy_cmd(chip, cmd); + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data); if (err) return err; - return 0; + return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev); } -static int mv88e6xxx_g2_smi_phy_write_c22(struct mv88e6xxx_chip *chip, - int addr, int reg, u16 val, - bool external) +static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip, + bool external, int port, int reg, + u16 data) { - u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA | (addr << 5) | reg; + int dev = (reg >> 16) & 0x1f; + int addr = reg & 0xffff; int err; - if (external) - cmd |= GLOBAL2_SMI_PHY_CMD_EXTERNAL; - - err = mv88e6xxx_g2_smi_phy_wait(chip); + err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev, + addr); if (err) return err; - err = mv88e6xxx_g2_write(chip, GLOBAL2_SMI_PHY_DATA, val); - if (err) - return err; + return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, dev, + data); +} - return mv88e6xxx_g2_smi_phy_cmd(chip, cmd); +int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, + int addr, int reg, u16 *val) +{ + struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; + bool external = mdio_bus->external; + + if (reg & MII_ADDR_C45) + return mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, reg, + val); + + return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg, + val); } -int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, - struct mii_bus *bus, +int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, int addr, int reg, u16 val) { struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; bool external = mdio_bus->external; if (reg & MII_ADDR_C45) - return mv88e6xxx_g2_smi_phy_write_c45(chip, addr, reg, val, - external); + return mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, reg, + val); - return mv88e6xxx_g2_smi_phy_write_c22(chip, addr, reg, val, external); + return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg, + val); } static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq) diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 6843b8b4bfee..8085c3bfb870 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -91,24 +91,31 @@ #define GLOBAL2_EEPROM_ADDR 0x15 /* 6390, 6341 */ #define GLOBAL2_PTP_AVB_OP 0x16 #define GLOBAL2_PTP_AVB_DATA 0x17 -#define GLOBAL2_SMI_PHY_CMD 0x18 -#define GLOBAL2_SMI_PHY_CMD_BUSY BIT(15) -#define GLOBAL2_SMI_PHY_CMD_EXTERNAL BIT(13) -#define GLOBAL2_SMI_PHY_CMD_MODE_22 BIT(12) -#define GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA ((0x1 << 10) | \ - GLOBAL2_SMI_PHY_CMD_MODE_22 | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA ((0x2 << 10) | \ - GLOBAL2_SMI_PHY_CMD_MODE_22 | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_ADDR ((0x0 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_WRITE_DATA ((0x1 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) -#define GLOBAL2_SMI_PHY_CMD_OP_45_READ_DATA ((0x3 << 10) | \ - GLOBAL2_SMI_PHY_CMD_BUSY) - -#define GLOBAL2_SMI_PHY_DATA 0x19 + +/* Offset 0x18: SMI PHY Command Register */ +#define MV88E6XXX_G2_SMI_PHY_CMD 0x18 +#define MV88E6XXX_G2_SMI_PHY_CMD_BUSY 0x8000 +#define MV88E6390_G2_SMI_PHY_CMD_FUNC_MASK 0x6000 +#define MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL 0x0000 +#define MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL 0x2000 +#define MV88E6390_G2_SMI_PHY_CMD_FUNC_SETUP 0x4000 +#define MV88E6XXX_G2_SMI_PHY_CMD_MODE_MASK 0x1000 +#define MV88E6XXX_G2_SMI_PHY_CMD_MODE_45 0x0000 +#define MV88E6XXX_G2_SMI_PHY_CMD_MODE_22 0x1000 +#define MV88E6XXX_G2_SMI_PHY_CMD_OP_MASK 0x0c00 +#define MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA 0x0400 +#define MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA 0x0800 +#define MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR 0x0000 +#define MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA 0x0400 +#define MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA_INC 0x0800 +#define MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA 0x0c00 +#define MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK 0x03e0 +#define MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK 0x001f +#define MV88E6XXX_G2_SMI_PHY_CMD_SETUP_PTR_MASK 0x03ff + +/* Offset 0x19: SMI PHY Data Register */ +#define MV88E6XXX_G2_SMI_PHY_DATA 0x19 + #define GLOBAL2_SCRATCH_MISC 0x1a #define GLOBAL2_SCRATCH_BUSY BIT(15) #define GLOBAL2_SCRATCH_REGISTER_SHIFT 8 -- cgit v1.2.3 From 56dc734712233417ecbf22f2a52b6151c0af29f7 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:38 -0400 Subject: net: dsa: mv88e6xxx: prefix Global 2 Trunk macros Prefix and document the Global 2 Trunk registers macros. At the same time, fix the hask -> hash typo and use the mv88e6xxx_port_mask helper. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 13 ++++++------- drivers/net/dsa/mv88e6xxx/global2.h | 18 +++++++++++------- 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index f20a60af35cb..d821b9591a8f 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -102,15 +102,14 @@ static int mv88e6xxx_g2_set_device_mapping(struct mv88e6xxx_chip *chip) /* Offset 0x07: Trunk Mask Table register */ static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num, - bool hask, u16 mask) + bool hash, u16 mask) { - const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1; - u16 val = (num << 12) | (mask & port_mask); + u16 val = (num << 12) | (mask & mv88e6xxx_port_mask(chip)); - if (hask) - val |= GLOBAL2_TRUNK_MASK_HASK; + if (hash) + val |= MV88E6XXX_G2_TRUNK_MASK_HASH; - return mv88e6xxx_g2_update(chip, GLOBAL2_TRUNK_MASK, val); + return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MASK, val); } /* Offset 0x08: Trunk Mapping Table register */ @@ -121,7 +120,7 @@ static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id, const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1; u16 val = (id << 11) | (map & port_mask); - return mv88e6xxx_g2_update(chip, GLOBAL2_TRUNK_MAPPING, val); + return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MAPPING, val); } static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip) diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 8085c3bfb870..c838c51cb2a1 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -35,13 +35,17 @@ #define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15) #define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8 #define GLOBAL2_DEVICE_MAPPING_PORT_MASK 0x0f -#define GLOBAL2_TRUNK_MASK 0x07 -#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15) -#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12 -#define GLOBAL2_TRUNK_MASK_HASK BIT(11) -#define GLOBAL2_TRUNK_MAPPING 0x08 -#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15) -#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11 + +/* Offset 0x07: Trunk Mask Table Register */ +#define MV88E6XXX_G2_TRUNK_MASK 0x07 +#define MV88E6XXX_G2_TRUNK_MASK_UPDATE 0x8000 +#define MV88E6XXX_G2_TRUNK_MASK_NUM_MASK 0x7000 +#define MV88E6XXX_G2_TRUNK_MASK_HASH 0x0800 + +/* Offset 0x08: Trunk Mapping Table Register */ +#define MV88E6XXX_G2_TRUNK_MAPPING 0x08 +#define MV88E6XXX_G2_TRUNK_MAPPING_UPDATE 0x8000 +#define MV88E6XXX_G2_TRUNK_MAPPING_ID_MASK 0x7800 /* Offset 0x09: Ingress Rate Command Register */ #define MV88E6XXX_G2_IRL_CMD 0x09 -- cgit v1.2.3 From 067e474a03c03e0b667cc2ec5ae6a56b8af5ad7d Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:39 -0400 Subject: net: dsa: mv88e6xxx: prefix Global 2 Device Mapping macros Prefix and document the Global 2 Device Mapping macros. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 2 +- drivers/net/dsa/mv88e6xxx/global2.h | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index d821b9591a8f..d5239c4f3a9b 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -73,7 +73,7 @@ static int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, { u16 val = (target << 8) | (port & 0xf); - return mv88e6xxx_g2_update(chip, GLOBAL2_DEVICE_MAPPING, val); + return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_DEVICE_MAPPING, val); } static int mv88e6xxx_g2_set_device_mapping(struct mv88e6xxx_chip *chip) diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index c838c51cb2a1..dd9b243309a0 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -31,10 +31,12 @@ #define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13) #define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7) #define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3) -#define GLOBAL2_DEVICE_MAPPING 0x06 -#define GLOBAL2_DEVICE_MAPPING_UPDATE BIT(15) -#define GLOBAL2_DEVICE_MAPPING_TARGET_SHIFT 8 -#define GLOBAL2_DEVICE_MAPPING_PORT_MASK 0x0f + +/* Offset 0x06: Device Mapping Table Register */ +#define MV88E6XXX_G2_DEVICE_MAPPING 0x06 +#define MV88E6XXX_G2_DEVICE_MAPPING_UPDATE 0x8000 +#define MV88E6XXX_G2_DEVICE_MAPPING_DEV_MASK 0x1f00 +#define MV88E6XXX_G2_DEVICE_MAPPING_PORT_MASK 0x000f /* Offset 0x07: Trunk Mask Table Register */ #define MV88E6XXX_G2_TRUNK_MASK 0x07 -- cgit v1.2.3 From 6bff47bec258ef9edba192674fe7366898af137f Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:40 -0400 Subject: net: dsa: mv88e6xxx: prefix Global 2 MGMT macros Prefix and document the Global 2 MGMT registers macros. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 11 ++++++----- drivers/net/dsa/mv88e6xxx/global2.h | 23 +++++++++++++++-------- 2 files changed, 21 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index d5239c4f3a9b..718bc9bf430d 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -52,7 +52,7 @@ int mv88e6095_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip) * addresses matching 01:80:c2:00:00:2x as MGMT. */ if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) { - err = mv88e6xxx_g2_write(chip, GLOBAL2_MGMT_EN_2X, 0xffff); + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, 0xffff); if (err) return err; } @@ -61,7 +61,8 @@ int mv88e6095_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip) * addresses matching 01:80:c2:00:00:0x as MGMT. */ if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X)) - return mv88e6xxx_g2_write(chip, GLOBAL2_MGMT_EN_0X, 0xffff); + return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X, + 0xffff); return 0; } @@ -1056,11 +1057,11 @@ int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) * highest, and send all special multicast frames to the CPU * port at the highest priority. */ - reg = GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI | (0x7 << 4); + reg = MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI | (0x7 << 4); if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X) || mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) - reg |= GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x7; - err = mv88e6xxx_g2_write(chip, GLOBAL2_SWITCH_MGMT, reg); + reg |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU | 0x7; + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, reg); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index dd9b243309a0..4c8ae59b49d4 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -22,15 +22,22 @@ #define GLOBAL2_INT_SOURCE 0x00 #define GLOBAL2_INT_SOURCE_WATCHDOG 15 #define GLOBAL2_INT_MASK 0x01 -#define GLOBAL2_MGMT_EN_2X 0x02 -#define GLOBAL2_MGMT_EN_0X 0x03 + +/* Offset 0x02: MGMT Enable Register 2x */ +#define MV88E6XXX_G2_MGMT_EN_2X 0x02 + +/* Offset 0x03: MGMT Enable Register 0x */ +#define MV88E6XXX_G2_MGMT_EN_0X 0x03 + #define GLOBAL2_FLOW_CONTROL 0x04 -#define GLOBAL2_SWITCH_MGMT 0x05 -#define GLOBAL2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA BIT(15) -#define GLOBAL2_SWITCH_MGMT_PREVENT_LOOPS BIT(14) -#define GLOBAL2_SWITCH_MGMT_FLOW_CONTROL_MSG BIT(13) -#define GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI BIT(7) -#define GLOBAL2_SWITCH_MGMT_RSVD2CPU BIT(3) + +/* Offset 0x05: Switch Management Register */ +#define MV88E6XXX_G2_SWITCH_MGMT 0x05 +#define MV88E6XXX_G2_SWITCH_MGMT_USE_DOUBLE_TAG_DATA 0x8000 +#define MV88E6XXX_G2_SWITCH_MGMT_PREVENT_LOOPS 0x4000 +#define MV88E6XXX_G2_SWITCH_MGMT_FLOW_CTL_MSG 0x2000 +#define MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI 0x0080 +#define MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU 0x0008 /* Offset 0x06: Device Mapping Table Register */ #define MV88E6XXX_G2_DEVICE_MAPPING 0x06 -- cgit v1.2.3 From 67d1ea8e847c699ce638165bff7da2480590d3bf Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:41 -0400 Subject: net: dsa: mv88e6xxx: prefix Global 2 PVT macros Prefix and document the Global 2 Cross-chip Port VLAN registers macros. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 14 ++++++++------ drivers/net/dsa/mv88e6xxx/global2.h | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 718bc9bf430d..dc6c0f5fd605 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -188,7 +188,8 @@ int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port) static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip) { - return mv88e6xxx_g2_wait(chip, GLOBAL2_PVT_ADDR, GLOBAL2_PVT_ADDR_BUSY); + return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_PVT_ADDR, + MV88E6XXX_G2_PVT_ADDR_BUSY); } static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev, @@ -196,13 +197,14 @@ static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev, { int err; - /* 9-bit Cross-chip PVT pointer: with GLOBAL2_MISC_5_BIT_PORT cleared, - * source device is 5-bit, source port is 4-bit. + /* 9-bit Cross-chip PVT pointer: with MV88E6XXX_G2_MISC_5_BIT_PORT + * cleared, source device is 5-bit, source port is 4-bit. */ + op |= MV88E6XXX_G2_PVT_ADDR_BUSY; op |= (src_dev & 0x1f) << 4; op |= (src_port & 0xf); - err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_ADDR, op); + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_ADDR, op); if (err) return err; @@ -218,12 +220,12 @@ int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev, if (err) return err; - err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_DATA, data); + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_DATA, data); if (err) return err; return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port, - GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN); + MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN); } /* Offset 0x0D: Switch MAC/WoL/WoF register */ diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 4c8ae59b49d4..0133c1cdfd6c 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -79,12 +79,19 @@ #define MV88E6XXX_G2_IRL_DATA 0x0a #define MV88E6XXX_G2_IRL_DATA_MASK 0xffff -#define GLOBAL2_PVT_ADDR 0x0b -#define GLOBAL2_PVT_ADDR_BUSY BIT(15) -#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY) -#define GLOBAL2_PVT_DATA 0x0c +/* Offset 0x0B: Cross-chip Port VLAN Register */ +#define MV88E6XXX_G2_PVT_ADDR 0x0b +#define MV88E6XXX_G2_PVT_ADDR_BUSY 0x8000 +#define MV88E6XXX_G2_PVT_ADDR_OP_MASK 0x7000 +#define MV88E6XXX_G2_PVT_ADDR_OP_INIT_ONES 0x1000 +#define MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN 0x3000 +#define MV88E6XXX_G2_PVT_ADDR_OP_READ 0x4000 +#define MV88E6XXX_G2_PVT_ADDR_PTR_MASK 0x01ff + +/* Offset 0x0C: Cross-chip Port VLAN Data Register */ +#define MV88E6XXX_G2_PVT_DATA 0x0c +#define MV88E6XXX_G2_PVT_DATA_MASK 0x7f + #define GLOBAL2_SWITCH_MAC 0x0d #define GLOBAL2_ATU_STATS 0x0e #define GLOBAL2_PRIO_OVERRIDE 0x0f -- cgit v1.2.3 From 7fc8c9d5206e8c17eb6d938717dc3cc692d9d72c Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:42 -0400 Subject: net: dsa: mv88e6xxx: prefix Global 2 EEPROM macros Prefix and document the Global 2 EEPROM registers macros. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 32 +++++++++++++++++--------------- drivers/net/dsa/mv88e6xxx/global2.h | 31 +++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index dc6c0f5fd605..8621f5893406 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -282,16 +282,17 @@ static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip) static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip) { - return mv88e6xxx_g2_wait(chip, GLOBAL2_EEPROM_CMD, - GLOBAL2_EEPROM_CMD_BUSY | - GLOBAL2_EEPROM_CMD_RUNNING); + return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_EEPROM_CMD, + MV88E6XXX_G2_EEPROM_CMD_BUSY | + MV88E6XXX_G2_EEPROM_CMD_RUNNING); } static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd) { int err; - err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_CMD, cmd); + err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_EEPROM_CMD, + MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd); if (err) return err; @@ -301,14 +302,14 @@ static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd) static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip, u16 addr, u8 *data) { - u16 cmd = GLOBAL2_EEPROM_CMD_OP_READ; + u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ; int err; err = mv88e6xxx_g2_eeprom_wait(chip); if (err) return err; - err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_ADDR, addr); + err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr); if (err) return err; @@ -316,7 +317,7 @@ static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip, if (err) return err; - err = mv88e6xxx_g2_read(chip, GLOBAL2_EEPROM_CMD, &cmd); + err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &cmd); if (err) return err; @@ -328,14 +329,15 @@ static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip, static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip, u16 addr, u8 data) { - u16 cmd = GLOBAL2_EEPROM_CMD_OP_WRITE | GLOBAL2_EEPROM_CMD_WRITE_EN; + u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | + MV88E6XXX_G2_EEPROM_CMD_WRITE_EN; int err; err = mv88e6xxx_g2_eeprom_wait(chip); if (err) return err; - err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_ADDR, addr); + err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr); if (err) return err; @@ -345,7 +347,7 @@ static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip, static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip, u8 addr, u16 *data) { - u16 cmd = GLOBAL2_EEPROM_CMD_OP_READ | addr; + u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr; int err; err = mv88e6xxx_g2_eeprom_wait(chip); @@ -356,20 +358,20 @@ static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip, if (err) return err; - return mv88e6xxx_g2_read(chip, GLOBAL2_EEPROM_DATA, data); + return mv88e6xxx_g2_read(chip, MV88E6352_G2_EEPROM_DATA, data); } static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip, u8 addr, u16 data) { - u16 cmd = GLOBAL2_EEPROM_CMD_OP_WRITE | addr; + u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr; int err; err = mv88e6xxx_g2_eeprom_wait(chip); if (err) return err; - err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_DATA, data); + err = mv88e6xxx_g2_write(chip, MV88E6352_G2_EEPROM_DATA, data); if (err) return err; @@ -481,11 +483,11 @@ int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip, int err; /* Ensure the RO WriteEn bit is set */ - err = mv88e6xxx_g2_read(chip, GLOBAL2_EEPROM_CMD, &val); + err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &val); if (err) return err; - if (!(val & GLOBAL2_EEPROM_CMD_WRITE_EN)) + if (!(val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN)) return -EROFS; eeprom->len = 0; diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 0133c1cdfd6c..a0a6cb3cb6fe 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -99,16 +99,27 @@ #define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 #define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) #define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 -#define GLOBAL2_EEPROM_CMD 0x14 -#define GLOBAL2_EEPROM_CMD_BUSY BIT(15) -#define GLOBAL2_EEPROM_CMD_OP_WRITE ((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY) -#define GLOBAL2_EEPROM_CMD_RUNNING BIT(11) -#define GLOBAL2_EEPROM_CMD_WRITE_EN BIT(10) -#define GLOBAL2_EEPROM_CMD_ADDR_MASK 0xff -#define GLOBAL2_EEPROM_DATA 0x15 -#define GLOBAL2_EEPROM_ADDR 0x15 /* 6390, 6341 */ + +/* Offset 0x14: EEPROM Command */ +#define MV88E6XXX_G2_EEPROM_CMD 0x14 +#define MV88E6XXX_G2_EEPROM_CMD_BUSY 0x8000 +#define MV88E6XXX_G2_EEPROM_CMD_OP_MASK 0x7000 +#define MV88E6XXX_G2_EEPROM_CMD_OP_WRITE 0x3000 +#define MV88E6XXX_G2_EEPROM_CMD_OP_READ 0x4000 +#define MV88E6XXX_G2_EEPROM_CMD_OP_LOAD 0x6000 +#define MV88E6XXX_G2_EEPROM_CMD_RUNNING 0x0800 +#define MV88E6XXX_G2_EEPROM_CMD_WRITE_EN 0x0400 +#define MV88E6352_G2_EEPROM_CMD_ADDR_MASK 0x00ff +#define MV88E6390_G2_EEPROM_CMD_DATA_MASK 0x00ff + +/* Offset 0x15: EEPROM Data */ +#define MV88E6352_G2_EEPROM_DATA 0x15 +#define MV88E6352_G2_EEPROM_DATA_MASK 0xffff + +/* Offset 0x15: EEPROM Addr */ +#define MV88E6390_G2_EEPROM_ADDR 0x15 +#define MV88E6390_G2_EEPROM_ADDR_MASK 0xffff + #define GLOBAL2_PTP_AVB_OP 0x16 #define GLOBAL2_PTP_AVB_DATA 0x17 -- cgit v1.2.3 From ed44152f21281120b421b0606ad255ce810a8043 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:43 -0400 Subject: net: dsa: mv88e6xxx: prefix Global 2 Switch MAC macros Prefix and document the Global 2 Switch MAC registers macros. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 2 +- drivers/net/dsa/mv88e6xxx/global2.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 8621f5893406..0977ba1697a6 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -235,7 +235,7 @@ static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip, { u16 val = (pointer << 8) | data; - return mv88e6xxx_g2_update(chip, GLOBAL2_SWITCH_MAC, val); + return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_SWITCH_MAC, val); } int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index a0a6cb3cb6fe..6b17343e481e 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -92,7 +92,12 @@ #define MV88E6XXX_G2_PVT_DATA 0x0c #define MV88E6XXX_G2_PVT_DATA_MASK 0x7f -#define GLOBAL2_SWITCH_MAC 0x0d +/* Offset 0x0D: Switch MAC/WoL/WoF Register */ +#define MV88E6XXX_G2_SWITCH_MAC 0x0d +#define MV88E6XXX_G2_SWITCH_MAC_UPDATE 0x8000 +#define MV88E6XXX_G2_SWITCH_MAC_PTR_MASK 0x1f00 +#define MV88E6XXX_G2_SWITCH_MAC_DATA_MASK 0x00ff + #define GLOBAL2_ATU_STATS 0x0e #define GLOBAL2_PRIO_OVERRIDE 0x0f #define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7) -- cgit v1.2.3 From 3b19df73bab2a66b1ea174b063e3a7dfeb732ad7 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:44 -0400 Subject: net: dsa: mv88e6xxx: prefix Global 2 Watchdog macros The Marvell 88E6352 family has a Global 2 register dedicated to the watchdog setup. But the 88E6390 turned it into an indirect table. Prefix and document that. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 48 +++++++++++++++++++------------------ drivers/net/dsa/mv88e6xxx/global2.h | 47 ++++++++++++++++++++---------------- 2 files changed, 52 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 0977ba1697a6..ab72eaa92cc3 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -752,7 +752,7 @@ static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq) { u16 reg; - mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, ®); + mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, ®); dev_info(chip->dev, "Watchdog event: 0x%04x", reg); @@ -763,20 +763,20 @@ static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip) { u16 reg; - mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, ®); + mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, ®); - reg &= ~(GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE | - GLOBAL2_WDOG_CONTROL_QC_ENABLE); + reg &= ~(MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE | + MV88E6352_G2_WDOG_CTL_QC_ENABLE); - mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, reg); + mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, reg); } static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip) { - return mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, - GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE | - GLOBAL2_WDOG_CONTROL_QC_ENABLE | - GLOBAL2_WDOG_CONTROL_SWRESET); + return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, + MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE | + MV88E6352_G2_WDOG_CTL_QC_ENABLE | + MV88E6352_G2_WDOG_CTL_SWRESET); } const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = { @@ -787,12 +787,12 @@ const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = { static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip) { - return mv88e6xxx_g2_update(chip, GLOBAL2_WDOG_CONTROL, - GLOBAL2_WDOG_INT_ENABLE | - GLOBAL2_WDOG_CUT_THROUGH | - GLOBAL2_WDOG_QUEUE_CONTROLLER | - GLOBAL2_WDOG_EGRESS | - GLOBAL2_WDOG_FORCE_IRQ); + return mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL, + MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE | + MV88E6390_G2_WDOG_CTL_CUT_THROUGH | + MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER | + MV88E6390_G2_WDOG_CTL_EGRESS | + MV88E6390_G2_WDOG_CTL_FORCE_IRQ); } static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq) @@ -800,17 +800,19 @@ static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq) int err; u16 reg; - mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, GLOBAL2_WDOG_EVENT); - err = mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, ®); + mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, + MV88E6390_G2_WDOG_CTL_PTR_EVENT); + err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, ®); dev_info(chip->dev, "Watchdog event: 0x%04x", - reg & GLOBAL2_WDOG_DATA_MASK); + reg & MV88E6390_G2_WDOG_CTL_DATA_MASK); - mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, GLOBAL2_WDOG_HISTORY); - err = mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, ®); + mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, + MV88E6390_G2_WDOG_CTL_PTR_HISTORY); + err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, ®); dev_info(chip->dev, "Watchdog history: 0x%04x", - reg & GLOBAL2_WDOG_DATA_MASK); + reg & MV88E6390_G2_WDOG_CTL_DATA_MASK); /* Trigger a software reset to try to recover the switch */ if (chip->info->ops->reset) @@ -823,8 +825,8 @@ static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq) static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip) { - mv88e6xxx_g2_update(chip, GLOBAL2_WDOG_CONTROL, - GLOBAL2_WDOG_INT_ENABLE); + mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL, + MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE); } const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = { diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 6b17343e481e..1f75e7a88633 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -156,26 +156,33 @@ #define GLOBAL2_SCRATCH_BUSY BIT(15) #define GLOBAL2_SCRATCH_REGISTER_SHIFT 8 #define GLOBAL2_SCRATCH_VALUE_MASK 0xff -#define GLOBAL2_WDOG_CONTROL 0x1b -#define GLOBAL2_WDOG_CONTROL_EGRESS_EVENT BIT(7) -#define GLOBAL2_WDOG_CONTROL_RMU_TIMEOUT BIT(6) -#define GLOBAL2_WDOG_CONTROL_QC_ENABLE BIT(5) -#define GLOBAL2_WDOG_CONTROL_EGRESS_HISTORY BIT(4) -#define GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE BIT(3) -#define GLOBAL2_WDOG_CONTROL_FORCE_IRQ BIT(2) -#define GLOBAL2_WDOG_CONTROL_HISTORY BIT(1) -#define GLOBAL2_WDOG_CONTROL_SWRESET BIT(0) -#define GLOBAL2_WDOG_UPDATE BIT(15) -#define GLOBAL2_WDOG_INT_SOURCE (0x00 << 8) -#define GLOBAL2_WDOG_INT_STATUS (0x10 << 8) -#define GLOBAL2_WDOG_INT_ENABLE (0x11 << 8) -#define GLOBAL2_WDOG_EVENT (0x12 << 8) -#define GLOBAL2_WDOG_HISTORY (0x13 << 8) -#define GLOBAL2_WDOG_DATA_MASK 0xff -#define GLOBAL2_WDOG_CUT_THROUGH BIT(3) -#define GLOBAL2_WDOG_QUEUE_CONTROLLER BIT(2) -#define GLOBAL2_WDOG_EGRESS BIT(1) -#define GLOBAL2_WDOG_FORCE_IRQ BIT(0) + +/* Offset 0x1B: Watch Dog Control Register */ +#define MV88E6352_G2_WDOG_CTL 0x1b +#define MV88E6352_G2_WDOG_CTL_EGRESS_EVENT 0x0080 +#define MV88E6352_G2_WDOG_CTL_RMU_TIMEOUT 0x0040 +#define MV88E6352_G2_WDOG_CTL_QC_ENABLE 0x0020 +#define MV88E6352_G2_WDOG_CTL_EGRESS_HISTORY 0x0010 +#define MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE 0x0008 +#define MV88E6352_G2_WDOG_CTL_FORCE_IRQ 0x0004 +#define MV88E6352_G2_WDOG_CTL_HISTORY 0x0002 +#define MV88E6352_G2_WDOG_CTL_SWRESET 0x0001 + +/* Offset 0x1B: Watch Dog Control Register */ +#define MV88E6390_G2_WDOG_CTL 0x1b +#define MV88E6390_G2_WDOG_CTL_UPDATE 0x8000 +#define MV88E6390_G2_WDOG_CTL_PTR_MASK 0x7f00 +#define MV88E6390_G2_WDOG_CTL_PTR_INT_SOURCE 0x0000 +#define MV88E6390_G2_WDOG_CTL_PTR_INT_STS 0x1000 +#define MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE 0x1100 +#define MV88E6390_G2_WDOG_CTL_PTR_EVENT 0x1200 +#define MV88E6390_G2_WDOG_CTL_PTR_HISTORY 0x1300 +#define MV88E6390_G2_WDOG_CTL_DATA_MASK 0x00ff +#define MV88E6390_G2_WDOG_CTL_CUT_THROUGH 0x0008 +#define MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER 0x0004 +#define MV88E6390_G2_WDOG_CTL_EGRESS 0x0002 +#define MV88E6390_G2_WDOG_CTL_FORCE_IRQ 0x0001 + #define GLOBAL2_QOS_WEIGHT 0x1c #define GLOBAL2_MISC 0x1d #define GLOBAL2_MISC_5_BIT_PORT BIT(14) -- cgit v1.2.3 From 1d90016d094b5896e43d61e8b9d5ab5312fe4f30 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jun 2017 10:55:45 -0400 Subject: net: dsa: mv88e6xxx: prefix Global 2 remaining macros Prefix and document the remaining Global 2 registers macros. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 27 ++++++++------- drivers/net/dsa/mv88e6xxx/global2.h | 65 +++++++++++++++++++++++++------------ 2 files changed, 57 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index ab72eaa92cc3..158d0f499874 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -1,6 +1,5 @@ /* - * Marvell 88E6xxx Switch Global 2 Registers support (device address - * 0x1C) + * Marvell 88E6xxx Switch Global 2 Registers support * * Copyright (c) 2008 Marvell Semiconductor * @@ -23,22 +22,22 @@ static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) { - return mv88e6xxx_read(chip, ADDR_GLOBAL2, reg, val); + return mv88e6xxx_read(chip, MV88E6XXX_G2, reg, val); } static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val) { - return mv88e6xxx_write(chip, ADDR_GLOBAL2, reg, val); + return mv88e6xxx_write(chip, MV88E6XXX_G2, reg, val); } static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update) { - return mv88e6xxx_update(chip, ADDR_GLOBAL2, reg, update); + return mv88e6xxx_update(chip, MV88E6XXX_G2, reg, update); } static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask) { - return mv88e6xxx_wait(chip, ADDR_GLOBAL2, reg, mask); + return mv88e6xxx_wait(chip, MV88E6XXX_G2, reg, mask); } /* Offset 0x02: Management Enable 2x */ @@ -258,7 +257,7 @@ static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer, { u16 val = (pointer << 8) | (data & 0x7); - return mv88e6xxx_g2_update(chip, GLOBAL2_PRIO_OVERRIDE, val); + return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_PRIO_OVERRIDE, val); } static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip) @@ -864,7 +863,7 @@ static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip) int err; chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain, - GLOBAL2_INT_SOURCE_WATCHDOG); + MV88E6XXX_G2_INT_SOURCE_WATCHDOG); if (chip->watchdog_irq < 0) return chip->watchdog_irq; @@ -891,16 +890,16 @@ static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip, u16 val; int err; - err = mv88e6xxx_g2_read(chip, GLOBAL2_MISC, &val); + err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_MISC, &val); if (err) return err; if (port_5_bit) - val |= GLOBAL2_MISC_5_BIT_PORT; + val |= MV88E6XXX_G2_MISC_5_BIT_PORT; else - val &= ~GLOBAL2_MISC_5_BIT_PORT; + val &= ~MV88E6XXX_G2_MISC_5_BIT_PORT; - return mv88e6xxx_g2_write(chip, GLOBAL2_MISC, val); + return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MISC, val); } int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip) @@ -934,7 +933,7 @@ static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id) u16 reg; mutex_lock(&chip->reg_lock); - err = mv88e6xxx_g2_read(chip, GLOBAL2_INT_SOURCE, ®); + err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SOURCE, ®); mutex_unlock(&chip->reg_lock); if (err) goto out; @@ -961,7 +960,7 @@ static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d) { struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); - mv88e6xxx_g2_write(chip, GLOBAL2_INT_MASK, ~chip->g2_irq.masked); + mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, ~chip->g2_irq.masked); mutex_unlock(&chip->reg_lock); } diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 1f75e7a88633..317ffd8f323d 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -1,5 +1,5 @@ /* - * Marvell 88E6xxx Switch Global 2 Registers support (device address 0x1C) + * Marvell 88E6xxx Switch Global 2 Registers support * * Copyright (c) 2008 Marvell Semiconductor * @@ -17,11 +17,14 @@ #include "chip.h" -#define ADDR_GLOBAL2 0x1c +#define MV88E6XXX_G2 0x1c -#define GLOBAL2_INT_SOURCE 0x00 -#define GLOBAL2_INT_SOURCE_WATCHDOG 15 -#define GLOBAL2_INT_MASK 0x01 +/* Offset 0x00: Interrupt Source Register */ +#define MV88E6XXX_G2_INT_SOURCE 0x00 +#define MV88E6XXX_G2_INT_SOURCE_WATCHDOG 15 + +/* Offset 0x01: Interrupt Mask Register */ +#define MV88E6XXX_G2_INT_MASK 0x01 /* Offset 0x02: MGMT Enable Register 2x */ #define MV88E6XXX_G2_MGMT_EN_2X 0x02 @@ -29,7 +32,8 @@ /* Offset 0x03: MGMT Enable Register 0x */ #define MV88E6XXX_G2_MGMT_EN_0X 0x03 -#define GLOBAL2_FLOW_CONTROL 0x04 +/* Offset 0x04: Flow Control Delay Register */ +#define MV88E6XXX_G2_FLOW_CTL 0x04 /* Offset 0x05: Switch Management Register */ #define MV88E6XXX_G2_SWITCH_MGMT 0x05 @@ -98,12 +102,18 @@ #define MV88E6XXX_G2_SWITCH_MAC_PTR_MASK 0x1f00 #define MV88E6XXX_G2_SWITCH_MAC_DATA_MASK 0x00ff -#define GLOBAL2_ATU_STATS 0x0e -#define GLOBAL2_PRIO_OVERRIDE 0x0f -#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7) -#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 -#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) -#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 +/* Offset 0x0E: ATU Stats Register */ +#define MV88E6XXX_G2_ATU_STATS 0x0e + +/* Offset 0x0F: Priority Override Table */ +#define MV88E6XXX_G2_PRIO_OVERRIDE 0x0f +#define MV88E6XXX_G2_PRIO_OVERRIDE_UPDATE 0x8000 +#define MV88E6XXX_G2_PRIO_OVERRIDE_FPRISET 0x1000 +#define MV88E6XXX_G2_PRIO_OVERRIDE_PTR_MASK 0x0f00 +#define MV88E6352_G2_PRIO_OVERRIDE_QPRIAVBEN 0x0080 +#define MV88E6352_G2_PRIO_OVERRIDE_DATAAVB_MASK 0x0030 +#define MV88E6XXX_G2_PRIO_OVERRIDE_QFPRIEN 0x0008 +#define MV88E6XXX_G2_PRIO_OVERRIDE_DATA_MASK 0x0007 /* Offset 0x14: EEPROM Command */ #define MV88E6XXX_G2_EEPROM_CMD 0x14 @@ -125,8 +135,11 @@ #define MV88E6390_G2_EEPROM_ADDR 0x15 #define MV88E6390_G2_EEPROM_ADDR_MASK 0xffff -#define GLOBAL2_PTP_AVB_OP 0x16 -#define GLOBAL2_PTP_AVB_DATA 0x17 +/* Offset 0x16: AVB Command Register */ +#define MV88E6352_G2_AVB_CMD 0x16 + +/* Offset 0x17: AVB Data Register */ +#define MV88E6352_G2_AVB_DATA 0x17 /* Offset 0x18: SMI PHY Command Register */ #define MV88E6XXX_G2_SMI_PHY_CMD 0x18 @@ -152,10 +165,11 @@ /* Offset 0x19: SMI PHY Data Register */ #define MV88E6XXX_G2_SMI_PHY_DATA 0x19 -#define GLOBAL2_SCRATCH_MISC 0x1a -#define GLOBAL2_SCRATCH_BUSY BIT(15) -#define GLOBAL2_SCRATCH_REGISTER_SHIFT 8 -#define GLOBAL2_SCRATCH_VALUE_MASK 0xff +/* Offset 0x1A: Scratch and Misc. Register */ +#define MV88E6XXX_G2_SCRATCH_MISC_MISC 0x1a +#define MV88E6XXX_G2_SCRATCH_MISC_UPDATE 0x8000 +#define MV88E6XXX_G2_SCRATCH_MISC_PTR_MASK 0x7f00 +#define MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK 0x00ff /* Offset 0x1B: Watch Dog Control Register */ #define MV88E6352_G2_WDOG_CTL 0x1b @@ -183,9 +197,18 @@ #define MV88E6390_G2_WDOG_CTL_EGRESS 0x0002 #define MV88E6390_G2_WDOG_CTL_FORCE_IRQ 0x0001 -#define GLOBAL2_QOS_WEIGHT 0x1c -#define GLOBAL2_MISC 0x1d -#define GLOBAL2_MISC_5_BIT_PORT BIT(14) +/* Offset 0x1C: QoS Weights Register */ +#define MV88E6XXX_G2_QOS_WEIGHTS 0x1c +#define MV88E6XXX_G2_QOS_WEIGHTS_UPDATE 0x8000 +#define MV88E6352_G2_QOS_WEIGHTS_PTR_MASK 0x3f00 +#define MV88E6390_G2_QOS_WEIGHTS_PTR_MASK 0x7f00 +#define MV88E6XXX_G2_QOS_WEIGHTS_DATA_MASK 0x00ff + +/* Offset 0x1D: Misc Register */ +#define MV88E6XXX_G2_MISC 0x1d +#define MV88E6XXX_G2_MISC_5_BIT_PORT 0x4000 +#define MV88E6352_G2_NOEGR_POLICY 0x2000 +#define MV88E6390_G2_LAG_ID_4 0x2000 #ifdef CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 -- cgit v1.2.3 From ddcbabf4404606fcc3edf6e48caa9707b33d3df4 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Sat, 17 Jun 2017 23:07:14 -0400 Subject: net: dsa: mv88e6xxx: better IEEE Prio Mapping Table description Kill the remaining shift macro in favor of calculating at compile time its value from the more descriptive mask, which gives us a better representation of the register layout. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/port.c | 11 +++++------ drivers/net/dsa/mv88e6xxx/port.h | 4 +++- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 73d825e08be3..a7801f6668a5 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -12,6 +12,7 @@ * (at your option) any later version. */ +#include #include #include @@ -912,15 +913,13 @@ int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port) } static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip, - int port, u16 table, - u8 pointer, u16 data) + int port, u16 table, u8 ptr, u16 data) { u16 reg; - reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | - table | - (pointer << MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT) | - data; + reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table | + (ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) | + (data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK); return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg); diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 8a34ea7c868a..8f3991bf1851 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -222,6 +222,7 @@ /* Offset 0x18: IEEE Priority Mapping Table */ #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_MASK 0x7000 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP 0x0000 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP 0x1000 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP 0x2000 @@ -229,7 +230,8 @@ #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_DSCP 0x5000 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_DSCP 0x6000 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_DSCP 0x7000 -#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT 9 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK 0x0e00 +#define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK 0x01ff /* Offset 0x18: Port IEEE Priority Remapping Registers (0-3) */ #define MV88E6095_PORT_IEEE_PRIO_REMAP_0123 0x18 -- cgit v1.2.3 From de77b966ce8adcb4c58d50e2f087320d5479812a Mon Sep 17 00:00:00 2001 From: yuan linyu Date: Sun, 18 Jun 2017 22:48:17 +0800 Subject: net: introduce __skb_put_[zero, data, u8] follow Johannes Berg, semantic patch file as below, @@ identifier p, p2; expression len; expression skb; type t, t2; @@ ( -p = __skb_put(skb, len); +p = __skb_put_zero(skb, len); | -p = (t)__skb_put(skb, len); +p = __skb_put_zero(skb, len); ) ... when != p ( p2 = (t2)p; -memset(p2, 0, len); | -memset(p, 0, len); ) @@ identifier p; expression len; expression skb; type t; @@ ( -t p = __skb_put(skb, len); +t p = __skb_put_zero(skb, len); ) ... when != p ( -memset(p, 0, len); ) @@ type t, t2; identifier p, p2; expression skb; @@ t *p; ... ( -p = __skb_put(skb, sizeof(t)); +p = __skb_put_zero(skb, sizeof(t)); | -p = (t *)__skb_put(skb, sizeof(t)); +p = __skb_put_zero(skb, sizeof(t)); ) ... when != p ( p2 = (t2)p; -memset(p2, 0, sizeof(*p)); | -memset(p, 0, sizeof(*p)); ) @@ expression skb, len; @@ -memset(__skb_put(skb, len), 0, len); +__skb_put_zero(skb, len); @@ expression skb, len, data; @@ -memcpy(__skb_put(skb, len), data, len); +__skb_put_data(skb, data, len); @@ expression SKB, C, S; typedef u8; identifier fn = {__skb_put}; fresh identifier fn2 = fn ## "_u8"; @@ - *(u8 *)fn(SKB, S) = C; + fn2(SKB, C); Signed-off-by: yuan linyu Signed-off-by: David S. Miller --- drivers/crypto/chelsio/chcr_algo.c | 15 +++++---------- drivers/infiniband/hw/cxgb4/cm.c | 6 ++---- drivers/infiniband/hw/cxgb4/cq.c | 6 ++---- drivers/infiniband/hw/cxgb4/mem.c | 6 ++---- drivers/infiniband/hw/cxgb4/qp.c | 3 +-- drivers/isdn/gigaset/asyncdata.c | 4 ++-- drivers/isdn/gigaset/isocdata.c | 2 +- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 12 ++++-------- drivers/net/ethernet/chelsio/cxgb3/sge.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 3 +-- drivers/net/usb/int51x1.c | 2 +- drivers/staging/octeon/ethernet-tx.c | 3 +-- drivers/target/iscsi/cxgbit/cxgbit_cm.c | 12 ++++-------- 13 files changed, 27 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 92185ab6797d..b75b8beed68f 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -604,8 +604,7 @@ static struct sk_buff if (!skb) return ERR_PTR(-ENOMEM); skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - chcr_req = __skb_put(skb, transhdr_len); - memset(chcr_req, 0, transhdr_len); + chcr_req = __skb_put_zero(skb, transhdr_len); chcr_req->sec_cpl.op_ivinsrtofst = FILL_SEC_CPL_OP_IVINSR(ctx->dev->rx_channel_id, 2, 1); @@ -881,8 +880,7 @@ static struct sk_buff *create_hash_wr(struct ahash_request *req, return skb; skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - chcr_req = __skb_put(skb, transhdr_len); - memset(chcr_req, 0, transhdr_len); + chcr_req = __skb_put_zero(skb, transhdr_len); chcr_req->sec_cpl.op_ivinsrtofst = FILL_SEC_CPL_OP_IVINSR(ctx->dev->rx_channel_id, 2, 0); @@ -1447,8 +1445,7 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, skb_reserve(skb, sizeof(struct sge_opaque_hdr)); /* Write WR */ - chcr_req = __skb_put(skb, transhdr_len); - memset(chcr_req, 0, transhdr_len); + chcr_req = __skb_put_zero(skb, transhdr_len); stop_offset = (op_type == CHCR_ENCRYPT_OP) ? 0 : authsize; @@ -1779,8 +1776,7 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - chcr_req = __skb_put(skb, transhdr_len); - memset(chcr_req, 0, transhdr_len); + chcr_req = __skb_put_zero(skb, transhdr_len); fill_sec_cpl_for_aead(&chcr_req->sec_cpl, dst_size, req, op_type, ctx); @@ -1892,8 +1888,7 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, /* NIC driver is going to write the sge hdr. */ skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - chcr_req = __skb_put(skb, transhdr_len); - memset(chcr_req, 0, transhdr_len); + chcr_req = __skb_put_zero(skb, transhdr_len); if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106) req->assoclen -= 8; diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 76fb39415e18..e49b34c3b136 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1900,8 +1900,7 @@ static int send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid) int win; skb = get_skb(NULL, sizeof(*req), GFP_KERNEL); - req = __skb_put(skb, sizeof(*req)); - memset(req, 0, sizeof(*req)); + req = __skb_put_zero(skb, sizeof(*req)); req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR)); req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16))); req->le.filter = cpu_to_be32(cxgb4_select_ntuple( @@ -3803,8 +3802,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb, req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL); if (!req_skb) return; - req = __skb_put(req_skb, sizeof(*req)); - memset(req, 0, sizeof(*req)); + req = __skb_put_zero(req_skb, sizeof(*req)); req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL_F); req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16))); req->le.version_cpl = htonl(FW_OFLD_CONNECTION_WR_CPL_F); diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index 394cfe2625fe..e16fcaf6b5a3 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -44,8 +44,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, wr_len = sizeof *res_wr + sizeof *res; set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - res_wr = __skb_put(skb, wr_len); - memset(res_wr, 0, wr_len); + res_wr = __skb_put_zero(skb, wr_len); res_wr->op_nres = cpu_to_be32( FW_WR_OP_V(FW_RI_RES_WR) | FW_RI_RES_WR_NRES_V(1) | @@ -114,8 +113,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, } set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - res_wr = __skb_put(skb, wr_len); - memset(res_wr, 0, wr_len); + res_wr = __skb_put_zero(skb, wr_len); res_wr->op_nres = cpu_to_be32( FW_WR_OP_V(FW_RI_RES_WR) | FW_RI_RES_WR_NRES_V(1) | diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index ca992e4b66e4..5332f06b99ba 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -81,8 +81,7 @@ static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr, } set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - req = __skb_put(skb, wr_len); - memset(req, 0, wr_len); + req = __skb_put_zero(skb, wr_len); INIT_ULPTX_WR(req, wr_len, 0, 0); req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) | (wait ? FW_WR_COMPL_F : 0)); @@ -142,8 +141,7 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len, } set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - req = __skb_put(skb, wr_len); - memset(req, 0, wr_len); + req = __skb_put_zero(skb, wr_len); INIT_ULPTX_WR(req, wr_len, 0, 0); if (i == (num_wqe-1)) { diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index b23a0b057347..bfc77596acbe 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -293,8 +293,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, } set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - res_wr = __skb_put(skb, wr_len); - memset(res_wr, 0, wr_len); + res_wr = __skb_put_zero(skb, wr_len); res_wr->op_nres = cpu_to_be32( FW_WR_OP_V(FW_RI_RES_WR) | FW_RI_RES_WR_NRES_V(2) | diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 4caecdcc6f29..bc208557f783 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -264,7 +264,7 @@ byte_stuff: /* skip remainder of packet */ bcs->rx_skb = skb = NULL; } else { - *(u8 *)__skb_put(skb, 1) = c; + __skb_put_u8(skb, c); fcs = crc_ccitt_byte(fcs, c); } } @@ -315,7 +315,7 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) /* regular data byte: append to current skb */ inputstate |= INS_have_data; - *(u8 *)__skb_put(skb, 1) = bitrev8(c); + __skb_put_u8(skb, bitrev8(c)); } /* pass data up */ diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 74e250664ce9..97e00118ccfe 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -511,7 +511,7 @@ static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) bcs->rx_skb = NULL; return; } - *(u8 *)__skb_put(bcs->rx_skb, 1) = c; + __skb_put_u8(bcs->rx_skb, c); } /* hdlc_flush diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index e1a50c87c9a9..0bc6a4ffce30 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -471,8 +471,7 @@ static int init_tp_parity(struct adapter *adap) if (!skb) goto alloc_skb_fail; - req = __skb_put(skb, sizeof(*req)); - memset(req, 0, sizeof(*req)); + req = __skb_put_zero(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); req->mtu_idx = NMTUS - 1; @@ -495,8 +494,7 @@ static int init_tp_parity(struct adapter *adap) if (!skb) goto alloc_skb_fail; - req = __skb_put(skb, sizeof(*req)); - memset(req, 0, sizeof(*req)); + req = __skb_put_zero(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); req->params = htonl(V_L2T_W_IDX(i)); @@ -518,8 +516,7 @@ static int init_tp_parity(struct adapter *adap) if (!skb) goto alloc_skb_fail; - req = __skb_put(skb, sizeof(*req)); - memset(req, 0, sizeof(*req)); + req = __skb_put_zero(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); req->l2t_idx = htonl(V_L2T_W_IDX(i)); @@ -538,8 +535,7 @@ static int init_tp_parity(struct adapter *adap) if (!skb) goto alloc_skb_fail; - greq = __skb_put(skb, sizeof(*greq)); - memset(greq, 0, sizeof(*greq)); + greq = __skb_put_zero(skb, sizeof(*greq)); greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); greq->mask = cpu_to_be64(1); diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index 1b9d154f1149..e2d342647b19 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -2282,7 +2282,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, if (!skb) goto no_mem; - memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE); + __skb_put_data(skb, r, AN_PKT_SIZE); skb->data[0] = CPL_ASYNC_NOTIF; rss_hi = htonl(CPL_ASYNC_NOTIF << 24); q->async_notif++; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c index a0fab65e80e8..45b5853ca2f1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c @@ -231,8 +231,7 @@ int set_filter_wr(struct adapter *adapter, int fidx) } } - fwr = __skb_put(skb, sizeof(*fwr)); - memset(fwr, 0, sizeof(*fwr)); + fwr = __skb_put_zero(skb, sizeof(*fwr)); /* It would be nice to put most of the following in t4_hw.c but most * of the work is translating the cxgbtool ch_filter_specification diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c index be63a829b8fe..ae2b2563460b 100644 --- a/drivers/net/usb/int51x1.c +++ b/drivers/net/usb/int51x1.c @@ -110,7 +110,7 @@ static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev, *len = cpu_to_le16(pack_len); if(need_tail) - memset(__skb_put(skb, need_tail), 0, need_tail); + __skb_put_zero(skb, need_tail); return skb; } diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index ff4119e8de42..31f35025d19e 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -251,8 +251,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) if ((skb_tail_pointer(skb) + add_bytes) <= skb_end_pointer(skb)) - memset(__skb_put(skb, add_bytes), 0, - add_bytes); + __skb_put_zero(skb, add_bytes); } } } diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c index 15cd1e33b16b..e583dd8a418b 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c @@ -1085,8 +1085,7 @@ cxgbit_pass_accept_rpl(struct cxgbit_sock *csk, struct cpl_pass_accept_req *req) return; } - rpl5 = __skb_put(skb, len); - memset(rpl5, 0, len); + rpl5 = __skb_put_zero(skb, len); INIT_TP_WR(rpl5, csk->tid); OPCODE_TID(rpl5) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL, @@ -1367,8 +1366,7 @@ u32 cxgbit_send_tx_flowc_wr(struct cxgbit_sock *csk) flowclen16 = cxgbit_tx_flowc_wr_credits(csk, &nparams, &flowclen); skb = __skb_dequeue(&csk->skbq); - flowc = __skb_put(skb, flowclen); - memset(flowc, 0, flowclen); + flowc = __skb_put_zero(skb, flowclen); flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS_V(nparams)); @@ -1439,8 +1437,7 @@ int cxgbit_setup_conn_digest(struct cxgbit_sock *csk) return -ENOMEM; /* set up ulp submode */ - req = __skb_put(skb, len); - memset(req, 0, len); + req = __skb_put_zero(skb, len); INIT_TP_WR(req, csk->tid); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid)); @@ -1476,8 +1473,7 @@ int cxgbit_setup_conn_pgidx(struct cxgbit_sock *csk, u32 pg_idx) if (!skb) return -ENOMEM; - req = __skb_put(skb, len); - memset(req, 0, len); + req = __skb_put_zero(skb, len); INIT_TP_WR(req, csk->tid); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid)); -- cgit v1.2.3 From ad941e693b24ad8b13c28382d323552ef6fb434b Mon Sep 17 00:00:00 2001 From: yuan linyu Date: Sun, 18 Jun 2017 22:49:30 +0800 Subject: net: replace more place to skb_put_[data:zero] spatch file, @@ expression skb, len, data; type t; @@ -memcpy((t *)skb_put(skb, len), data, len); +skb_put_data(skb, data, len); @@ identifier p; expression skb, len, data; type t; @@ -p = (t *)memset(skb_put(skb, len), data, len); +p = skb_put_zero(skb, len); @@ expression skb, len, data; type t; @@ -memcpy((t *)__skb_put(skb, len), data, len); +__skb_put_data(skb, data, len); @@ identifier p; expression skb, len, data; type t; @@ -p = (t *)memset(__skb_put(skb, len), data, len); +p = __skb_put_zero(skb, len); Signed-off-by: yuan linyu Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ncm.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c | 3 +-- drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c | 3 +-- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c | 3 +-- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c | 3 +-- drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c | 3 +-- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c | 6 ++---- 7 files changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index bcb974707118..2067743f51ca 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1069,7 +1069,7 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_ /* push a new empty NDP */ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) - ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); + ndp16 = skb_put_zero(skb, ctx->max_ndp_size); else ndp16 = ctx->delayed_ndp16; @@ -1120,7 +1120,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) goto exit_no_skb; } /* fill out the initial 16-bit NTB header */ - nth16 = (struct usb_cdc_ncm_nth16 *)memset(skb_put(skb_out, sizeof(struct usb_cdc_ncm_nth16)), 0, sizeof(struct usb_cdc_ncm_nth16)); + nth16 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth16)); nth16->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN); nth16->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16)); nth16->wSequence = cpu_to_le16(ctx->tx_seq++); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c index c7a77467b20e..015476e3f7e5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c @@ -647,8 +647,7 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); if (cmd_send_packet) rtstatus = cmd_send_packet(hw, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c index 88faeab2574f..f4129cf96e7c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c @@ -668,8 +668,7 @@ void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) if (!skb) { dlok = false; } else { - memcpy((u8 *) skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); rtstatus = _rtl92d_cmd_send_packet(hw, skb); if (rtstatus) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index 1f42ce5f8f27..6f8f75ad0881 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -708,8 +708,7 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u1rsvdpageloc, 3); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); b_dlok = true; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c index a954a87b0ed9..bf9859f74b6f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c @@ -470,8 +470,7 @@ void rtl8723e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u1rsvdpageloc, 3); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c index 4fc839b1d601..01205578a3f4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c @@ -527,8 +527,7 @@ void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, u1rsvdpageloc, sizeof(u1rsvdpageloc)); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet, totalpacketlen); + skb_put_data(skb, &reserved_page_packet, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index 73350103b736..67aec20cdbf0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -1588,8 +1588,7 @@ out: &reserved_page_packet_8812[0], totalpacketlen); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet_8812, totalpacketlen); + skb_put_data(skb, &reserved_page_packet_8812, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); @@ -1725,8 +1724,7 @@ out: &reserved_page_packet_8821[0], totalpacketlen); skb = dev_alloc_skb(totalpacketlen); - memcpy((u8 *)skb_put(skb, totalpacketlen), - &reserved_page_packet_8821, totalpacketlen); + skb_put_data(skb, &reserved_page_packet_8821, totalpacketlen); rtstatus = rtl_cmd_send_packet(hw, skb); -- cgit v1.2.3 From b952f4dff2751252db073c27c0f8a16a416a2ddc Mon Sep 17 00:00:00 2001 From: yuan linyu Date: Sun, 18 Jun 2017 22:52:04 +0800 Subject: net: manual clean code which call skb_put_[data:zero] Signed-off-by: yuan linyu Signed-off-by: David S. Miller --- drivers/isdn/hysdn/hycapi.c | 8 ++++---- drivers/isdn/i4l/isdn_bsdcomp.c | 2 +- drivers/isdn/i4l/isdn_ppp.c | 2 +- drivers/net/bonding/bond_alb.c | 3 +-- drivers/net/caif/caif_hsi.c | 6 ++---- drivers/net/caif/caif_serial.c | 3 +-- drivers/net/caif/caif_spi.c | 3 +-- drivers/net/ethernet/nxp/lpc_eth.c | 7 +++---- drivers/net/ethernet/packetengines/hamachi.c | 4 ++-- drivers/net/ppp/ppp_synctty.c | 2 +- drivers/net/usb/asix_common.c | 5 ++--- drivers/net/usb/hso.c | 13 ++++++------- drivers/net/wireless/ath/ath9k/wmi.c | 3 +-- drivers/net/wireless/marvell/libertas/if_sdio.c | 3 +-- drivers/net/wireless/quantenna/qtnfmac/qlink_util.h | 4 +--- drivers/net/wireless/realtek/rtlwifi/pci.c | 3 +-- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 10 +++------- drivers/net/wireless/ti/wlcore/rx.c | 3 +-- drivers/nfc/pn533/pn533.c | 4 ++-- drivers/staging/rtl8188eu/core/rtw_recv.c | 4 +--- drivers/staging/rtl8192e/rtllib_rx.c | 5 ++--- drivers/staging/rtl8192e/rtllib_softmac.c | 11 ++++++----- drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c | 4 +--- drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c | 11 +++++------ drivers/staging/rtl8192u/r819xU_cmdpkt.c | 3 +-- drivers/staging/rtl8712/rtl8712_recv.c | 4 ++-- drivers/staging/rtl8723bs/os_dep/recv_linux.c | 4 +--- drivers/staging/wlan-ng/hfa384x_usb.c | 2 +- drivers/usb/gadget/function/f_ncm.c | 11 +++++------ 29 files changed, 60 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index 87119b517508..eac0f51a0f60 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -173,8 +173,8 @@ hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl, } skb_put_data(skb, &len, sizeof(__u16)); skb_put_data(skb, &appl, sizeof(__u16)); - memcpy(skb_put(skb, sizeof(__u8)), &_command, sizeof(_command)); - memcpy(skb_put(skb, sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + skb_put_data(skb, &_command, sizeof(__u8)); + skb_put_data(skb, &_subcommand, sizeof(__u8)); skb_put_data(skb, &MessageNumber, sizeof(__u16)); skb_put_data(skb, &MessageBufferSize, sizeof(__u16)); skb_put_data(skb, &(rp->level3cnt), sizeof(__u16)); @@ -281,8 +281,8 @@ static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl) } skb_put_data(skb, &len, sizeof(__u16)); skb_put_data(skb, &appl, sizeof(__u16)); - memcpy(skb_put(skb, sizeof(__u8)), &_command, sizeof(_command)); - memcpy(skb_put(skb, sizeof(__u8)), &_subcommand, sizeof(_subcommand)); + skb_put_data(skb, &_command, sizeof(__u8)); + skb_put_data(skb, &_subcommand, sizeof(__u8)); skb_put_data(skb, &MessageNumber, sizeof(__u16)); hycapi_send_message(ctrl, skb); hycapi_applications[appl - 1].ctrl_mask &= ~(1 << (ctrl->cnr - 1)); diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index 3035210a6119..5b64a1389a7c 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -472,7 +472,7 @@ static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb accm |= ((ent) << bitno); \ do { \ if (skb_out && skb_tailroom(skb_out) > 0) \ - *(u8 *)skb_put(skb_out, 1) = (u8)(accm >> 24); \ + skb_put(skb_out, (u8)(accm >> 24)); \ accm <<= 8; \ bitno += 8; \ } while (bitno <= 24); \ diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index b7e3f1cde683..88e5a025cea7 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -2258,7 +2258,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, /* Now stuff remaining bytes */ if (len) { - p = skb_put_data(skb, data, len); + skb_put_data(skb, data, len); } /* skb is now ready for xmit */ diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index b796db7dd621..c02cc817a490 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -925,7 +925,6 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[], struct learning_pkt pkt; struct sk_buff *skb; int size = sizeof(struct learning_pkt); - char *data; memset(&pkt, 0, size); ether_addr_copy(pkt.mac_dst, mac_addr); @@ -936,7 +935,7 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[], if (!skb) return; - data = skb_put_data(skb, &pkt, size); + skb_put_data(skb, &pkt, size); skb_reset_mac_header(skb); skb->network_header = skb->mac_header + ETH_HLEN; diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index 4534326e20ac..11ba6e3eea22 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c @@ -426,7 +426,6 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi) /* Check for embedded CAIF frame. */ if (desc->offset) { struct sk_buff *skb; - u8 *dst = NULL; int len = 0; pfrm = ((u8 *)desc) + desc->offset; @@ -454,7 +453,7 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi) } caif_assert(skb != NULL); - dst = skb_put_data(skb, pfrm, len); + skb_put_data(skb, pfrm, len); skb->protocol = htons(ETH_P_CAIF); skb_reset_mac_header(skb); @@ -555,7 +554,6 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) /* Parse payload. */ while (nfrms < CFHSI_MAX_PKTS && *plen) { struct sk_buff *skb; - u8 *dst = NULL; u8 *pcffrm = NULL; int len; @@ -584,7 +582,7 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) } caif_assert(skb != NULL); - dst = skb_put_data(skb, pcffrm, len); + skb_put_data(skb, pcffrm, len); skb->protocol = htons(ETH_P_CAIF); skb_reset_mac_header(skb); diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 5c57be2082ba..709838e4c062 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -171,7 +171,6 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data, struct sk_buff *skb = NULL; struct ser_device *ser; int ret; - u8 *p; ser = tty->disc_data; @@ -198,7 +197,7 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data, skb = netdev_alloc_skb(ser->dev, count+1); if (skb == NULL) return; - p = skb_put_data(skb, data, count); + skb_put_data(skb, data, count); skb->protocol = htons(ETH_P_CAIF); skb_reset_mac_header(skb); diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index 24a5f5ca2037..207cb8423de0 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -526,7 +526,6 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len) struct sk_buff *skb = NULL; int spad = 0; int epad = 0; - u8 *dst = NULL; int pkt_len = 0; /* @@ -548,7 +547,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len) skb = netdev_alloc_skb(cfspi->ndev, pkt_len + 1); caif_assert(skb != NULL); - dst = skb_put_data(skb, src, pkt_len); + skb_put_data(skb, src, pkt_len); src += pkt_len; skb->protocol = htons(ETH_P_CAIF); diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 828bfd93cb54..08381ef8bdb4 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -919,7 +919,6 @@ static int __lpc_handle_recv(struct net_device *ndev, int budget) struct sk_buff *skb; u32 rxconsidx, len, ethst; struct rx_status_t *prxstat; - u8 *prdbuf; int rx_done = 0; /* Get the current RX buffer indexes */ @@ -960,9 +959,9 @@ static int __lpc_handle_recv(struct net_device *ndev, int budget) ndev->stats.rx_dropped++; } else { /* Copy packet from buffer */ - prdbuf = skb_put_data(skb, - pldat->rx_buff_v + rxconsidx * ENET_MAXF_SIZE, - len); + skb_put_data(skb, + pldat->rx_buff_v + rxconsidx * ENET_MAXF_SIZE, + len); /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, ndev); diff --git a/drivers/net/ethernet/packetengines/hamachi.c b/drivers/net/ethernet/packetengines/hamachi.c index 8b026dbf0d8d..482b85e4d665 100644 --- a/drivers/net/ethernet/packetengines/hamachi.c +++ b/drivers/net/ethernet/packetengines/hamachi.c @@ -1495,8 +1495,8 @@ static int hamachi_rx(struct net_device *dev) hmp->rx_skbuff[entry]->data, pkt_len); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), hmp->rx_ring_dma - + entry*sizeof(*desc), pkt_len); + skb_put_data(skb, hmp->rx_ring_dma + + entry*sizeof(*desc), pkt_len); #endif pci_dma_sync_single_for_device(hmp->pci_dev, leXX_to_cpu(hmp->rx_ring[entry].addr), diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index ef08590db873..7868c29071d4 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -697,7 +697,7 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf, goto err; } - p = skb_put_data(skb, buf, count); + skb_put_data(skb, buf, count); /* strip address/control field if present */ p = skb->data; diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 90facc5ecab0..7847436c441e 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -113,7 +113,6 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, while (offset + sizeof(u16) <= skb->len) { u16 copy_length; - unsigned char *data; if (!rx->remaining) { if (skb->len - offset == sizeof(u16)) { @@ -167,8 +166,8 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, } if (rx->ax_skb) { - data = skb_put_data(rx->ax_skb, skb->data + offset, - copy_length); + skb_put_data(rx->ax_skb, skb->data + offset, + copy_length); if (!rx->remaining) usbnet_skb_return(dev, rx->ax_skb); } diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 908ada4ca21c..d7a3379ea668 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -861,7 +861,6 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, unsigned short temp_bytes; unsigned short buffer_offset = 0; unsigned short frame_len; - unsigned char *tmp_rx_buf; /* log if needed */ hso_dbg(0x1, "Rx %d bytes\n", count); @@ -911,9 +910,9 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, /* Copy what we got so far. make room for iphdr * after tail. */ - tmp_rx_buf = skb_put_data(odev->skb_rx_buf, - (char *)&(odev->rx_ip_hdr), - sizeof(struct iphdr)); + skb_put_data(odev->skb_rx_buf, + (char *)&(odev->rx_ip_hdr), + sizeof(struct iphdr)); /* ETH_HLEN */ odev->rx_buf_size = sizeof(struct iphdr); @@ -932,9 +931,9 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, /* Copy the rest of the bytes that are left in the * buffer into the waiting sk_buf. */ /* Make room for temp_bytes after tail. */ - tmp_rx_buf = skb_put_data(odev->skb_rx_buf, - ip_pkt + buffer_offset, - temp_bytes); + skb_put_data(odev->skb_rx_buf, + ip_pkt + buffer_offset, + temp_bytes); odev->rx_buf_missing -= temp_bytes; count -= temp_bytes; diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 85d09fdef8dc..64a354fa78ab 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -298,7 +298,6 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, u16 headroom = sizeof(struct htc_frame_hdr) + sizeof(struct wmi_cmd_hdr); struct sk_buff *skb; - u8 *data; unsigned long time_left; int ret = 0; @@ -312,7 +311,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, skb_reserve(skb, headroom); if (cmd_len != 0 && cmd_buf != NULL) { - data = skb_put_data(skb, cmd_buf, cmd_len); + skb_put_data(skb, cmd_buf, cmd_len); } mutex_lock(&wmi->op_mutex); diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index a9e2b06b3175..2300e796c6ab 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -239,7 +239,6 @@ static int if_sdio_handle_data(struct if_sdio_card *card, { int ret; struct sk_buff *skb; - char *data; if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_deb_sdio("response packet too large (%d bytes)\n", @@ -256,7 +255,7 @@ static int if_sdio_handle_data(struct if_sdio_card *card, skb_reserve(skb, NET_IP_ALIGN); - data = skb_put_data(skb, buffer, size); + skb_put_data(skb, buffer, size); lbs_process_rxed_packet(card->priv, skb); diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h index f6ac39973b5d..90d7d09a6c63 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h @@ -33,9 +33,7 @@ static inline void qtnf_cmd_skb_put_action(struct sk_buff *skb, u16 action) static inline void qtnf_cmd_skb_put_buffer(struct sk_buff *skb, const u8 *buf_src, size_t len) { - u8 *buf_dst; - - buf_dst = skb_put_data(skb, buf_src, len); + skb_put_data(skb, buf_src, len); } static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb, diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 0c1f8307e179..df5f6795f650 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -729,13 +729,12 @@ static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw, dev_kfree_skb_any(skb); } else { struct sk_buff *uskb = NULL; - u8 *pdata; uskb = dev_alloc_skb(skb->len + 128); if (likely(uskb)) { memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status)); - pdata = skb_put_data(uskb, skb->data, skb->len); + skb_put_data(uskb, skb->data, skb->len); dev_kfree_skb_any(skb); ieee80211_rx_irqsafe(hw, uskb); } else { diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 4433cec4367c..a0f04371d93b 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -389,9 +389,7 @@ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, struct ieee80211_tx_info *info; struct skb_info *rx_params; u8 pad_bytes = msg[4]; - u8 pkt_recv; struct sk_buff *skb; - char *buffer; if (type == RX_DOT11_MGMT) { if (!adapter->sc_nvifs) @@ -412,11 +410,9 @@ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, return -ENOMEM; } - buffer = skb_put_data(skb, - (u8 *)(msg + FRAME_DESC_SZ + pad_bytes), - msg_len); - - pkt_recv = buffer[0]; + skb_put_data(skb, + (u8 *)(msg + FRAME_DESC_SZ + pad_bytes), + msg_len); info = IEEE80211_SKB_CB(skb); rx_params = (struct skb_info *)info->driver_data; diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 53cd6d4d5b50..0f15696195f8 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -117,7 +117,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; - u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = 0, offset_to_data = 0; @@ -180,7 +179,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ - buf = skb_put_data(skb, data + sizeof(*desc), pkt_data_len); + skb_put_data(skb, data + sizeof(*desc), pkt_data_len); if (rx_align == WLCORE_RX_BUF_PADDED) skb_pull(skb, RX_BUF_ALIGN); diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index c8a8f5badb5b..c05cb637ba92 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -1006,7 +1006,7 @@ static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp) static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) { struct sk_buff *skb; - u8 *felica, *nfcid3, *gb; + u8 *felica, *nfcid3; u8 *gbytes = dev->gb; size_t gbytes_len = dev->gb_len; @@ -1048,7 +1048,7 @@ static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) /* General bytes */ skb_put_u8(skb, gbytes_len); - gb = skb_put_data(skb, gbytes, gbytes_len); + skb_put_data(skb, gbytes, gbytes_len); /* Len Tk */ skb_put_u8(skb, 0); diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 14173cf6e1e7..afb9dadc1cfe 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -1510,7 +1510,6 @@ static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe) u8 nr_subframes, i; unsigned char *pdata; struct rx_pkt_attrib *pattrib; - unsigned char *data_ptr; struct sk_buff *sub_skb, *subframes[MAX_SUBFRAME_COUNT]; struct recv_priv *precvpriv = &padapter->recvpriv; struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue); @@ -1544,8 +1543,7 @@ static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe) sub_skb = dev_alloc_skb(nSubframe_Length + 12); if (sub_skb) { skb_reserve(sub_skb, 12); - data_ptr = skb_put_data(sub_skb, pdata, - nSubframe_Length); + skb_put_data(sub_skb, pdata, nSubframe_Length); } else { sub_skb = skb_clone(prframe->pkt, GFP_ATOMIC); if (sub_skb) { diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index bae98ca0a9b6..03a81ba136b2 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -782,7 +782,6 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb, u8 nPadding_Length = 0; u16 SeqNum = 0; struct sk_buff *sub_skb; - u8 *data_ptr; /* just for debug purpose */ SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl)); if ((RTLLIB_QOS_HAS_SEQ(fc)) && @@ -817,7 +816,7 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb, if (!sub_skb) return 0; skb_reserve(sub_skb, 12); - data_ptr = skb_put_data(sub_skb, skb->data, skb->len); + skb_put_data(sub_skb, skb->data, skb->len); sub_skb->dev = ieee->dev; rxb->subframes[0] = sub_skb; @@ -869,7 +868,7 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb, if (!sub_skb) return 0; skb_reserve(sub_skb, 12); - data_ptr = skb_put_data(sub_skb, skb->data, nSubframe_Length); + skb_put_data(sub_skb, skb->data, nSubframe_Length); sub_skb->dev = ieee->dev; rxb->subframes[rxb->nr_subframes++] = sub_skb; diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index 5f2751d4d464..09d2c8649171 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -1264,7 +1264,7 @@ rtllib_association_req(struct rtllib_network *beacon, hdr->info_element[0].id = MFIE_TYPE_SSID; hdr->info_element[0].len = beacon->ssid_len; - tag = skb_put_data(skb, beacon->ssid, beacon->ssid_len); + skb_put_data(skb, beacon->ssid, beacon->ssid_len); tag = skb_put(skb, rate_len); @@ -1340,7 +1340,7 @@ rtllib_association_req(struct rtllib_network *beacon, } if (wpa_ie_len) { - tag = skb_put_data(skb, ieee->wpa_ie, ieee->wpa_ie_len); + skb_put_data(skb, ieee->wpa_ie, ieee->wpa_ie_len); if (PMKCacheIdx >= 0) { tag = skb_put(skb, 18); @@ -1356,12 +1356,13 @@ rtllib_association_req(struct rtllib_network *beacon, } if (wps_ie_len && ieee->wps_ie) { - tag = skb_put_data(skb, ieee->wps_ie, wps_ie_len); + skb_put_data(skb, ieee->wps_ie, wps_ie_len); } - tag = skb_put(skb, turbo_info_len); - if (turbo_info_len) + if (turbo_info_len) { + tag = skb_put(skb, turbo_info_len); rtllib_TURBO_Info(ieee, &tag); + } if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT) { if (ieee->pHTInfo->ePeerHTSpecVer == HT_SPEC_VER_EWC) { diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index c0e2f711cb4e..a4aedb489e92 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -780,7 +780,6 @@ static u8 parse_subframe(struct sk_buff *skb, u16 SeqNum=0; struct sk_buff *sub_skb; - u8 *data_ptr; /* just for debug purpose */ SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl)); @@ -848,8 +847,7 @@ static u8 parse_subframe(struct sk_buff *skb, if (!sub_skb) return 0; skb_reserve(sub_skb, 12); - data_ptr = skb_put_data(sub_skb, skb->data, - nSubframe_Length); + skb_put_data(sub_skb, skb->data, nSubframe_Length); #endif rxb->subframes[rxb->nr_subframes++] = sub_skb; if (rxb->nr_subframes >= MAX_SUBFRAME_COUNT) { diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 107069180ed2..fe6f38b7ec35 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -1112,7 +1112,7 @@ ieee80211_association_req(struct ieee80211_network *beacon, hdr->info_element[0].id = MFIE_TYPE_SSID; hdr->info_element[0].len = beacon->ssid_len; - tag = skb_put_data(skb, beacon->ssid, beacon->ssid_len); + skb_put_data(skb, beacon->ssid, beacon->ssid_len); tag = skb_put(skb, rate_len); @@ -1184,18 +1184,17 @@ ieee80211_association_req(struct ieee80211_network *beacon, //choose what wpa_supplicant gives to associate. - tag = skb_put(skb, wpa_ie_len); if (wpa_ie_len) { - memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); + skb_put_data(skb, ieee->wpa_ie, wpa_ie_len); } - tag = skb_put(skb, wmm_info_len); if (wmm_info_len) { - ieee80211_WMM_Info(ieee, &tag); + tag = skb_put(skb, wmm_info_len); + ieee80211_WMM_Info(ieee, &tag); } #ifdef THOMAS_TURBO - tag = skb_put(skb, turbo_info_len); if (turbo_info_len) { + tag = skb_put(skb, turbo_info_len); ieee80211_TURBO_Info(ieee, &tag); } #endif diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c index c3cf01c842a3..87ab3ba760fc 100644 --- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c +++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c @@ -31,7 +31,6 @@ rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen) struct r8192_priv *priv = ieee80211_priv(dev); struct sk_buff *skb; struct cb_desc *tcb_desc; - unsigned char *ptr_buf; /* Get TCB and local buffer from common pool. * (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) @@ -45,7 +44,7 @@ rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen) tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL; tcb_desc->bLastIniPkt = 0; skb_reserve(skb, USB_HWDESC_HEADER_LEN); - ptr_buf = skb_put_data(skb, pData, DataLen); + skb_put_data(skb, pData, DataLen); tcb_desc->txbuf_size = (u16)DataLen; if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) || diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index f96c558b3c6a..ea3eb94b28b3 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -340,7 +340,7 @@ static int amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe) int a_len, padding_len; u16 eth_type, nSubframe_Length; u8 nr_subframes, i; - unsigned char *data_ptr, *pdata; + unsigned char *pdata; struct rx_pkt_attrib *pattrib; _pkt *sub_skb, *subframes[MAX_SUBFRAME_COUNT]; struct recv_priv *precvpriv = &padapter->recvpriv; @@ -372,7 +372,7 @@ static int amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe) if (!sub_skb) break; skb_reserve(sub_skb, 12); - data_ptr = skb_put_data(sub_skb, pdata, nSubframe_Length); + skb_put_data(sub_skb, pdata, nSubframe_Length); subframes[nr_subframes++] = sub_skb; if (nr_subframes >= MAX_SUBFRAME_COUNT) { netdev_warn(padapter->pnetdev, "r8712u: ParseSubframe(): Too many Subframes! Packets dropped!\n"); diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index 1a6443dc3ff0..f42e00081e0e 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -72,7 +72,6 @@ int rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *prec _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata) { u16 eth_type; - u8 *data_ptr; _pkt *sub_skb; struct rx_pkt_attrib *pattrib; @@ -82,8 +81,7 @@ _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 if (sub_skb) { skb_reserve(sub_skb, 12); - data_ptr = skb_put_data(sub_skb, (pdata + ETH_HLEN), - nSubframe_Length); + skb_put_data(sub_skb, (pdata + ETH_HLEN), nSubframe_Length); } else { diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c index 1de67f209f2c..83ea8ab4f2f4 100644 --- a/drivers/staging/wlan-ng/hfa384x_usb.c +++ b/drivers/staging/wlan-ng/hfa384x_usb.c @@ -3530,7 +3530,7 @@ static void hfa384x_int_rxmonitor(struct wlandevice *wlandev, /* Copy the 802.11 header to the skb * (ctl frames may be less than a full header) */ - datap = skb_put_data(skb, &rxdesc->frame_control, hdrlen); + skb_put_data(skb, &rxdesc->frame_control, hdrlen); /* If any, copy the data from the card to the skb */ if (datalen > 0) { diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index a9c28c72c1c7..24e34cfcb4bd 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1004,16 +1004,15 @@ static struct sk_buff *package_for_tx(struct f_ncm *ncm) } /* Insert NDP alignment. */ - ntb_iter = skb_put_zero(skb2, ndp_pad); + skb_put_zero(skb2, ndp_pad); /* Copy NTB across. */ - ntb_iter = skb_put_data(skb2, ncm->skb_tx_ndp->data, - ncm->skb_tx_ndp->len); + skb_put_data(skb2, ncm->skb_tx_ndp->data, ncm->skb_tx_ndp->len); dev_consume_skb_any(ncm->skb_tx_ndp); ncm->skb_tx_ndp = NULL; /* Insert zero'd datagram. */ - ntb_iter = skb_put_zero(skb2, dgram_idx_len); + skb_put_zero(skb2, dgram_idx_len); return skb2; } @@ -1127,8 +1126,8 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, ncm->ndp_dgram_count++; /* Add the new data to the skb */ - ntb_data = skb_put_zero(ncm->skb_tx_data, dgram_pad); - ntb_data = skb_put_data(ncm->skb_tx_data, skb->data, skb->len); + skb_put_zero(ncm->skb_tx_data, dgram_pad); + skb_put_data(ncm->skb_tx_data, skb->data, skb->len); dev_consume_skb_any(skb); skb = NULL; -- cgit v1.2.3 From a985343ba90635cda3f3704f71021254c91cebbd Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 19 Jun 2017 10:03:55 +0200 Subject: vxlan: refactor verification and application of configuration The vxlan_dev_configure function was mixing validation and application of the vxlan configuration; this could easily lead to bugs with the changelink operation, as it was hard to see if the function wcould return an error after parts of the configuration had already been applied. This commit splits validation and application out of vxlan_dev_configure as separate functions to make it clearer where error returns are allowed and where the vxlan_dev or net_device may be configured. Log messages in these functions are removed, as it is generally unexpected to find error output for netlink requests in the kernel log. Userspace should be able to handle errors based on the error codes returned via netlink just fine. In addition, some validation and initialization is moved to vxlan_validate and vxlan_setup respectively to improve grouping of similar settings. Finally, this also fixes two actual bugs: * if set, conf->mtu would overwrite dev->mtu in each changelink operation, reverting other changes of dev->mtu * the "if (!conf->dst_port)" branch would never be run, as conf->dst_port was set in vxlan_setup before. This caused VXLAN-GPE to use the same default port as other VXLAN sockets instead of the intended IANA-assigned 4790. Signed-off-by: Matthias Schiffer Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 208 ++++++++++++++++++++++++++++------------------------ 1 file changed, 111 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 94ce98229828..9139f15a2ec1 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2623,6 +2623,10 @@ static void vxlan_setup(struct net_device *dev) netif_keep_dst(dev); dev->priv_flags |= IFF_NO_QUEUE; + /* MTU range: 68 - 65535 */ + dev->min_mtu = ETH_MIN_MTU; + dev->max_mtu = ETH_MAX_MTU; + INIT_LIST_HEAD(&vxlan->next); spin_lock_init(&vxlan->hash_lock); @@ -2630,9 +2634,8 @@ static void vxlan_setup(struct net_device *dev) vxlan->age_timer.function = vxlan_cleanup; vxlan->age_timer.data = (unsigned long) vxlan; - vxlan->cfg.dst_port = htons(vxlan_port); - vxlan->dev = dev; + vxlan->net = dev_net(dev); gro_cells_init(&vxlan->gro_cells, dev); @@ -2701,11 +2704,19 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) } } + if (tb[IFLA_MTU]) { + u32 mtu = nla_get_u32(data[IFLA_MTU]); + + if (mtu < ETH_MIN_MTU || mtu > ETH_MAX_MTU) + return -EINVAL; + } + if (!data) return -EINVAL; if (data[IFLA_VXLAN_ID]) { - __u32 id = nla_get_u32(data[IFLA_VXLAN_ID]); + u32 id = nla_get_u32(data[IFLA_VXLAN_ID]); + if (id >= VXLAN_N_VID) return -ERANGE; } @@ -2866,116 +2877,128 @@ static int vxlan_sock_add(struct vxlan_dev *vxlan) return ret; } -static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, - struct vxlan_config *conf, - bool changelink) +static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, + struct net_device **lower, + struct vxlan_dev *old) { struct vxlan_net *vn = net_generic(src_net, vxlan_net_id); - struct vxlan_dev *vxlan = netdev_priv(dev), *tmp; - struct vxlan_rdst *dst = &vxlan->default_dst; - unsigned short needed_headroom = ETH_HLEN; + struct vxlan_dev *tmp; bool use_ipv6 = false; - __be16 default_port = vxlan->cfg.dst_port; - struct net_device *lowerdev = NULL; - if (!changelink) { - if (conf->flags & VXLAN_F_GPE) { - /* For now, allow GPE only together with - * COLLECT_METADATA. This can be relaxed later; in such - * case, the other side of the PtP link will have to be - * provided. - */ - if ((conf->flags & ~VXLAN_F_ALLOWED_GPE) || - !(conf->flags & VXLAN_F_COLLECT_METADATA)) { - pr_info("unsupported combination of extensions\n"); - return -EINVAL; - } - vxlan_raw_setup(dev); - } else { - vxlan_ether_setup(dev); + if (conf->flags & VXLAN_F_GPE) { + /* For now, allow GPE only together with + * COLLECT_METADATA. This can be relaxed later; in such + * case, the other side of the PtP link will have to be + * provided. + */ + if ((conf->flags & ~VXLAN_F_ALLOWED_GPE) || + !(conf->flags & VXLAN_F_COLLECT_METADATA)) { + return -EINVAL; } - - /* MTU range: 68 - 65535 */ - dev->min_mtu = ETH_MIN_MTU; - dev->max_mtu = ETH_MAX_MTU; - vxlan->net = src_net; } - dst->remote_vni = conf->vni; - - memcpy(&dst->remote_ip, &conf->remote_ip, sizeof(conf->remote_ip)); - - /* Unless IPv6 is explicitly requested, assume IPv4 */ - if (!dst->remote_ip.sa.sa_family) - dst->remote_ip.sa.sa_family = AF_INET; + if (!conf->remote_ip.sa.sa_family) + conf->remote_ip.sa.sa_family = AF_INET; - if (dst->remote_ip.sa.sa_family == AF_INET6 || - vxlan->cfg.saddr.sa.sa_family == AF_INET6) { + if (conf->remote_ip.sa.sa_family == AF_INET6 || + conf->saddr.sa.sa_family == AF_INET6) { if (!IS_ENABLED(CONFIG_IPV6)) return -EPFNOSUPPORT; use_ipv6 = true; - vxlan->flags |= VXLAN_F_IPV6; + conf->flags |= VXLAN_F_IPV6; } - if (conf->label && !use_ipv6) { - pr_info("label only supported in use with IPv6\n"); + if (conf->label && !use_ipv6) return -EINVAL; - } - if (conf->remote_ifindex && - conf->remote_ifindex != vxlan->cfg.remote_ifindex) { - lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex); - dst->remote_ifindex = conf->remote_ifindex; + if (conf->remote_ifindex) { + struct net_device *lowerdev; - if (!lowerdev) { - pr_info("ifindex %d does not exist\n", - dst->remote_ifindex); + lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex); + if (!lowerdev) return -ENODEV; - } #if IS_ENABLED(CONFIG_IPV6) if (use_ipv6) { struct inet6_dev *idev = __in6_dev_get(lowerdev); - if (idev && idev->cnf.disable_ipv6) { - pr_info("IPv6 is disabled via sysctl\n"); + if (idev && idev->cnf.disable_ipv6) return -EPERM; - } } #endif - if (!conf->mtu) - dev->mtu = lowerdev->mtu - - (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM); + *lower = lowerdev; + } else { + if (vxlan_addr_multicast(&conf->remote_ip)) + return -EINVAL; - needed_headroom = lowerdev->hard_header_len; - } else if (!conf->remote_ifindex && - vxlan_addr_multicast(&dst->remote_ip)) { - pr_info("multicast destination requires interface to be specified\n"); - return -EINVAL; + *lower = NULL; } - if (lowerdev) { - dev->gso_max_size = lowerdev->gso_max_size; - dev->gso_max_segs = lowerdev->gso_max_segs; + if (!conf->dst_port) { + if (conf->flags & VXLAN_F_GPE) + conf->dst_port = htons(4790); /* IANA VXLAN-GPE port */ + else + conf->dst_port = htons(vxlan_port); } - if (conf->mtu) { - int max_mtu = ETH_MAX_MTU; + if (!conf->age_interval) + conf->age_interval = FDB_AGE_DEFAULT; - if (lowerdev) - max_mtu = lowerdev->mtu; + list_for_each_entry(tmp, &vn->vxlan_list, next) { + if (tmp == old) + continue; - max_mtu -= (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM); + if (tmp->cfg.vni == conf->vni && + (tmp->default_dst.remote_ip.sa.sa_family == AF_INET6 || + tmp->cfg.saddr.sa.sa_family == AF_INET6) == use_ipv6 && + tmp->cfg.dst_port == conf->dst_port && + (tmp->flags & VXLAN_F_RCV_FLAGS) == + (conf->flags & VXLAN_F_RCV_FLAGS)) + return -EEXIST; + } - if (conf->mtu < dev->min_mtu || conf->mtu > dev->max_mtu) - return -EINVAL; + return 0; +} - dev->mtu = conf->mtu; +static void vxlan_config_apply(struct net_device *dev, + struct vxlan_config *conf, + struct net_device *lowerdev, bool changelink) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_rdst *dst = &vxlan->default_dst; + unsigned short needed_headroom = ETH_HLEN; + bool use_ipv6 = !!(conf->flags & VXLAN_F_IPV6); + int max_mtu = ETH_MAX_MTU; + + if (!changelink) { + if (conf->flags & VXLAN_F_GPE) + vxlan_raw_setup(dev); + else + vxlan_ether_setup(dev); - if (conf->mtu > max_mtu) - dev->mtu = max_mtu; + if (conf->mtu) + dev->mtu = conf->mtu; } + dst->remote_vni = conf->vni; + + memcpy(&dst->remote_ip, &conf->remote_ip, sizeof(conf->remote_ip)); + + if (lowerdev) { + dst->remote_ifindex = conf->remote_ifindex; + + dev->gso_max_size = lowerdev->gso_max_size; + dev->gso_max_segs = lowerdev->gso_max_segs; + + needed_headroom = lowerdev->hard_header_len; + + max_mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM : + VXLAN_HEADROOM); + } + + if (dev->mtu > max_mtu) + dev->mtu = max_mtu; + if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA) needed_headroom += VXLAN6_HEADROOM; else @@ -2983,31 +3006,22 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, dev->needed_headroom = needed_headroom; memcpy(&vxlan->cfg, conf, sizeof(*conf)); - if (!vxlan->cfg.dst_port) { - if (conf->flags & VXLAN_F_GPE) - vxlan->cfg.dst_port = htons(4790); /* IANA VXLAN-GPE port */ - else - vxlan->cfg.dst_port = default_port; - } vxlan->flags |= conf->flags; +} - if (!vxlan->cfg.age_interval) - vxlan->cfg.age_interval = FDB_AGE_DEFAULT; +static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, + struct vxlan_config *conf, + bool changelink) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + struct net_device *lowerdev; + int ret; - if (changelink) - return 0; + ret = vxlan_config_validate(src_net, conf, &lowerdev, vxlan); + if (ret) + return ret; - list_for_each_entry(tmp, &vn->vxlan_list, next) { - if (tmp->cfg.vni == conf->vni && - (tmp->default_dst.remote_ip.sa.sa_family == AF_INET6 || - tmp->cfg.saddr.sa.sa_family == AF_INET6) == use_ipv6 && - tmp->cfg.dst_port == vxlan->cfg.dst_port && - (tmp->flags & VXLAN_F_RCV_FLAGS) == - (vxlan->flags & VXLAN_F_RCV_FLAGS)) { - pr_info("duplicate VNI %u\n", be32_to_cpu(conf->vni)); - return -EEXIST; - } - } + vxlan_config_apply(dev, conf, lowerdev, changelink); return 0; } -- cgit v1.2.3 From dc5321d79697db1b610c25fa4fad1aec7533ea3e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 19 Jun 2017 10:03:56 +0200 Subject: vxlan: get rid of redundant vxlan_dev.flags There is no good reason to keep the flags twice in vxlan_dev and vxlan_config. Signed-off-by: Matthias Schiffer Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 76 ++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 9139f15a2ec1..b4fce3b29647 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -305,7 +305,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, if (rdst->remote_vni != vxlan->default_dst.remote_vni && nla_put_u32(skb, NDA_VNI, be32_to_cpu(rdst->remote_vni))) goto nla_put_failure; - if ((vxlan->flags & VXLAN_F_COLLECT_METADATA) && fdb->vni && + if ((vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) && fdb->vni && nla_put_u32(skb, NDA_SRC_VNI, be32_to_cpu(fdb->vni))) goto nla_put_failure; @@ -419,7 +419,7 @@ static u32 eth_vni_hash(const unsigned char *addr, __be32 vni) static inline struct hlist_head *vxlan_fdb_head(struct vxlan_dev *vxlan, const u8 *mac, __be32 vni) { - if (vxlan->flags & VXLAN_F_COLLECT_METADATA) + if (vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) return &vxlan->fdb_head[eth_vni_hash(mac, vni)]; else return &vxlan->fdb_head[eth_hash(mac)]; @@ -434,7 +434,7 @@ static struct vxlan_fdb *__vxlan_find_mac(struct vxlan_dev *vxlan, hlist_for_each_entry_rcu(f, head, hlist) { if (ether_addr_equal(mac, f->eth_addr)) { - if (vxlan->flags & VXLAN_F_COLLECT_METADATA) { + if (vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) { if (vni == f->vni) return f; } else { @@ -1284,7 +1284,7 @@ static bool vxlan_set_mac(struct vxlan_dev *vxlan, #endif } - if ((vxlan->flags & VXLAN_F_LEARN) && + if ((vxlan->cfg.flags & VXLAN_F_LEARN) && vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, vni)) return false; @@ -1507,7 +1507,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) if (netif_rx_ni(reply) == NET_RX_DROP) dev->stats.rx_dropped++; - } else if (vxlan->flags & VXLAN_F_L3MISS) { + } else if (vxlan->cfg.flags & VXLAN_F_L3MISS) { union vxlan_addr ipa = { .sin.sin_addr.s_addr = tip, .sin.sin_family = AF_INET, @@ -1665,7 +1665,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) if (netif_rx_ni(reply) == NET_RX_DROP) dev->stats.rx_dropped++; - } else if (vxlan->flags & VXLAN_F_L3MISS) { + } else if (vxlan->cfg.flags & VXLAN_F_L3MISS) { union vxlan_addr ipa = { .sin6.sin6_addr = msg->target, .sin6.sin6_family = AF_INET6, @@ -1698,7 +1698,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) return false; pip = ip_hdr(skb); n = neigh_lookup(&arp_tbl, &pip->daddr, dev); - if (!n && (vxlan->flags & VXLAN_F_L3MISS)) { + if (!n && (vxlan->cfg.flags & VXLAN_F_L3MISS)) { union vxlan_addr ipa = { .sin.sin_addr.s_addr = pip->daddr, .sin.sin_family = AF_INET, @@ -1719,7 +1719,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) return false; pip6 = ipv6_hdr(skb); n = neigh_lookup(ipv6_stub->nd_tbl, &pip6->daddr, dev); - if (!n && (vxlan->flags & VXLAN_F_L3MISS)) { + if (!n && (vxlan->cfg.flags & VXLAN_F_L3MISS)) { union vxlan_addr ipa = { .sin6.sin6_addr = pip6->daddr, .sin6.sin6_family = AF_INET6, @@ -1993,7 +1993,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, #endif } - if (dst_vxlan->flags & VXLAN_F_LEARN) + if (dst_vxlan->cfg.flags & VXLAN_F_LEARN) vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source, vni); u64_stats_update_begin(&tx_stats->syncp); @@ -2031,7 +2031,7 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, dst_release(dst); dst_vxlan = vxlan_find_vni(vxlan->net, vni, daddr->sa.sa_family, dst_port, - vxlan->flags); + vxlan->cfg.flags); if (!dst_vxlan) { dev->stats.tx_errors++; kfree_skb(skb); @@ -2062,7 +2062,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, __be32 vni, label; __u8 tos, ttl; int err; - u32 flags = vxlan->flags; + u32 flags = vxlan->cfg.flags; bool udp_sum = false; bool xnet = !net_eq(vxlan->net, dev_net(vxlan->dev)); @@ -2244,7 +2244,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) skb_reset_mac_header(skb); - if (vxlan->flags & VXLAN_F_COLLECT_METADATA) { + if (vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) { if (info && info->mode & IP_TUNNEL_INFO_BRIDGE && info->mode & IP_TUNNEL_INFO_TX) { vni = tunnel_id_to_key32(info->key.tun_id); @@ -2257,7 +2257,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) } } - if (vxlan->flags & VXLAN_F_PROXY) { + if (vxlan->cfg.flags & VXLAN_F_PROXY) { eth = eth_hdr(skb); if (ntohs(eth->h_proto) == ETH_P_ARP) return arp_reduce(dev, skb, vni); @@ -2277,7 +2277,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) f = vxlan_find_mac(vxlan, eth->h_dest, vni); did_rsc = false; - if (f && (f->flags & NTF_ROUTER) && (vxlan->flags & VXLAN_F_RSC) && + if (f && (f->flags & NTF_ROUTER) && (vxlan->cfg.flags & VXLAN_F_RSC) && (ntohs(eth->h_proto) == ETH_P_IP || ntohs(eth->h_proto) == ETH_P_IPV6)) { did_rsc = route_shortcircuit(dev, skb); @@ -2288,7 +2288,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) if (f == NULL) { f = vxlan_find_mac(vxlan, all_zeros_mac, vni); if (f == NULL) { - if ((vxlan->flags & VXLAN_F_L2MISS) && + if ((vxlan->cfg.flags & VXLAN_F_L2MISS) && !is_multicast_ether_addr(eth->h_dest)) vxlan_fdb_miss(vxlan, eth->h_dest); @@ -2832,7 +2832,7 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) if (!vxlan->cfg.no_share) { spin_lock(&vn->sock_lock); vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET, - vxlan->cfg.dst_port, vxlan->flags); + vxlan->cfg.dst_port, vxlan->cfg.flags); if (vs && !atomic_add_unless(&vs->refcnt, 1, 0)) { spin_unlock(&vn->sock_lock); return -EBUSY; @@ -2841,7 +2841,7 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) } if (!vs) vs = vxlan_socket_create(vxlan->net, ipv6, - vxlan->cfg.dst_port, vxlan->flags); + vxlan->cfg.dst_port, vxlan->cfg.flags); if (IS_ERR(vs)) return PTR_ERR(vs); #if IS_ENABLED(CONFIG_IPV6) @@ -2856,8 +2856,8 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) static int vxlan_sock_add(struct vxlan_dev *vxlan) { - bool metadata = vxlan->flags & VXLAN_F_COLLECT_METADATA; - bool ipv6 = vxlan->flags & VXLAN_F_IPV6 || metadata; + bool metadata = vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA; + bool ipv6 = vxlan->cfg.flags & VXLAN_F_IPV6 || metadata; bool ipv4 = !ipv6 || metadata; int ret = 0; @@ -2952,7 +2952,7 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, (tmp->default_dst.remote_ip.sa.sa_family == AF_INET6 || tmp->cfg.saddr.sa.sa_family == AF_INET6) == use_ipv6 && tmp->cfg.dst_port == conf->dst_port && - (tmp->flags & VXLAN_F_RCV_FLAGS) == + (tmp->cfg.flags & VXLAN_F_RCV_FLAGS) == (conf->flags & VXLAN_F_RCV_FLAGS)) return -EEXIST; } @@ -3006,7 +3006,6 @@ static void vxlan_config_apply(struct net_device *dev, dev->needed_headroom = needed_headroom; memcpy(&vxlan->cfg, conf, sizeof(*conf)); - vxlan->flags |= conf->flags; } static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, @@ -3120,12 +3119,10 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], IPV6_FLOWLABEL_MASK; if (data[IFLA_VXLAN_LEARNING]) { - if (nla_get_u8(data[IFLA_VXLAN_LEARNING])) { + if (nla_get_u8(data[IFLA_VXLAN_LEARNING])) conf->flags |= VXLAN_F_LEARN; - } else { + else conf->flags &= ~VXLAN_F_LEARN; - vxlan->flags &= ~VXLAN_F_LEARN; - } } else if (!changelink) { /* default to learn on a new device */ conf->flags |= VXLAN_F_LEARN; @@ -3408,43 +3405,44 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) || nla_put_be32(skb, IFLA_VXLAN_LABEL, vxlan->cfg.label) || nla_put_u8(skb, IFLA_VXLAN_LEARNING, - !!(vxlan->flags & VXLAN_F_LEARN)) || + !!(vxlan->cfg.flags & VXLAN_F_LEARN)) || nla_put_u8(skb, IFLA_VXLAN_PROXY, - !!(vxlan->flags & VXLAN_F_PROXY)) || - nla_put_u8(skb, IFLA_VXLAN_RSC, !!(vxlan->flags & VXLAN_F_RSC)) || + !!(vxlan->cfg.flags & VXLAN_F_PROXY)) || + nla_put_u8(skb, IFLA_VXLAN_RSC, + !!(vxlan->cfg.flags & VXLAN_F_RSC)) || nla_put_u8(skb, IFLA_VXLAN_L2MISS, - !!(vxlan->flags & VXLAN_F_L2MISS)) || + !!(vxlan->cfg.flags & VXLAN_F_L2MISS)) || nla_put_u8(skb, IFLA_VXLAN_L3MISS, - !!(vxlan->flags & VXLAN_F_L3MISS)) || + !!(vxlan->cfg.flags & VXLAN_F_L3MISS)) || nla_put_u8(skb, IFLA_VXLAN_COLLECT_METADATA, - !!(vxlan->flags & VXLAN_F_COLLECT_METADATA)) || + !!(vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA)) || nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->cfg.age_interval) || nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->cfg.addrmax) || nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->cfg.dst_port) || nla_put_u8(skb, IFLA_VXLAN_UDP_CSUM, - !(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM_TX)) || + !(vxlan->cfg.flags & VXLAN_F_UDP_ZERO_CSUM_TX)) || nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, - !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) || + !!(vxlan->cfg.flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) || nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, - !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) || + !!(vxlan->cfg.flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) || nla_put_u8(skb, IFLA_VXLAN_REMCSUM_TX, - !!(vxlan->flags & VXLAN_F_REMCSUM_TX)) || + !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_TX)) || nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX, - !!(vxlan->flags & VXLAN_F_REMCSUM_RX))) + !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX))) goto nla_put_failure; if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) goto nla_put_failure; - if (vxlan->flags & VXLAN_F_GBP && + if (vxlan->cfg.flags & VXLAN_F_GBP && nla_put_flag(skb, IFLA_VXLAN_GBP)) goto nla_put_failure; - if (vxlan->flags & VXLAN_F_GPE && + if (vxlan->cfg.flags & VXLAN_F_GPE && nla_put_flag(skb, IFLA_VXLAN_GPE)) goto nla_put_failure; - if (vxlan->flags & VXLAN_F_REMCSUM_NOPARTIAL && + if (vxlan->cfg.flags & VXLAN_F_REMCSUM_NOPARTIAL && nla_put_flag(skb, IFLA_VXLAN_REMCSUM_NOPARTIAL)) goto nla_put_failure; -- cgit v1.2.3 From ce44a4aea5e4203147013759a363c17b2ee5132b Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 19 Jun 2017 10:03:57 +0200 Subject: vxlan: improve validation of address family configuration Address families of source and destination addresses must match, and changelink operations can't change the address family. In addition, always use the VXLAN_F_IPV6 to check if a VXLAN device uses IPv4 or IPv6. Signed-off-by: Matthias Schiffer Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index b4fce3b29647..00680cc597ac 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2484,10 +2484,7 @@ static int vxlan_change_mtu(struct net_device *dev, int new_mtu) struct vxlan_rdst *dst = &vxlan->default_dst; struct net_device *lowerdev = __dev_get_by_index(vxlan->net, dst->remote_ifindex); - bool use_ipv6 = false; - - if (dst->remote_ip.sa.sa_family == AF_INET6) - use_ipv6 = true; + bool use_ipv6 = !!(vxlan->cfg.flags & VXLAN_F_IPV6); /* This check is different than dev->max_mtu, because it looks at * the lowerdev->mtu, rather than the static dev->max_mtu @@ -2897,11 +2894,20 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, } } - if (!conf->remote_ip.sa.sa_family) + if (!conf->remote_ip.sa.sa_family && !conf->saddr.sa.sa_family) { + /* Unless IPv6 is explicitly requested, assume IPv4 */ conf->remote_ip.sa.sa_family = AF_INET; + conf->saddr.sa.sa_family = AF_INET; + } else if (!conf->remote_ip.sa.sa_family) { + conf->remote_ip.sa.sa_family = conf->saddr.sa.sa_family; + } else if (!conf->saddr.sa.sa_family) { + conf->saddr.sa.sa_family = conf->remote_ip.sa.sa_family; + } + + if (conf->saddr.sa.sa_family != conf->remote_ip.sa.sa_family) + return -EINVAL; - if (conf->remote_ip.sa.sa_family == AF_INET6 || - conf->saddr.sa.sa_family == AF_INET6) { + if (conf->saddr.sa.sa_family == AF_INET6) { if (!IS_ENABLED(CONFIG_IPV6)) return -EPFNOSUPPORT; use_ipv6 = true; @@ -2949,11 +2955,9 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, continue; if (tmp->cfg.vni == conf->vni && - (tmp->default_dst.remote_ip.sa.sa_family == AF_INET6 || - tmp->cfg.saddr.sa.sa_family == AF_INET6) == use_ipv6 && tmp->cfg.dst_port == conf->dst_port && - (tmp->cfg.flags & VXLAN_F_RCV_FLAGS) == - (conf->flags & VXLAN_F_RCV_FLAGS)) + (tmp->cfg.flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6)) == + (conf->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6))) return -EEXIST; } @@ -3084,22 +3088,35 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], } if (data[IFLA_VXLAN_GROUP]) { + if (changelink && (conf->remote_ip.sa.sa_family != AF_INET)) + return -EOPNOTSUPP; + conf->remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); + conf->remote_ip.sa.sa_family = AF_INET; } else if (data[IFLA_VXLAN_GROUP6]) { if (!IS_ENABLED(CONFIG_IPV6)) return -EPFNOSUPPORT; + if (changelink && (conf->remote_ip.sa.sa_family != AF_INET6)) + return -EOPNOTSUPP; + conf->remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]); conf->remote_ip.sa.sa_family = AF_INET6; } if (data[IFLA_VXLAN_LOCAL]) { + if (changelink && (conf->saddr.sa.sa_family != AF_INET)) + return -EOPNOTSUPP; + conf->saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]); conf->saddr.sa.sa_family = AF_INET; } else if (data[IFLA_VXLAN_LOCAL6]) { if (!IS_ENABLED(CONFIG_IPV6)) return -EPFNOSUPPORT; + if (changelink && (conf->saddr.sa.sa_family != AF_INET6)) + return -EOPNOTSUPP; + /* TODO: respect scope id */ conf->saddr.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_LOCAL6]); conf->saddr.sa.sa_family = AF_INET6; -- cgit v1.2.3 From 0f22a3c68d5fd1696dbc15c45d7ea375c865b7a1 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 19 Jun 2017 10:03:58 +0200 Subject: vxlan: check valid combinations of address scopes * Multicast addresses are never valid as local address * Link-local IPv6 unicast addresses may only be used as remote when the local address is link-local as well * Don't allow link-local IPv6 local/remote addresses without interface We also store in the flags field if link-local addresses are used for the follow-up patches that actually make VXLAN over link-local IPv6 work. Signed-off-by: Matthias Schiffer Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 00680cc597ac..d6d57317cbd5 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2907,11 +2907,35 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, if (conf->saddr.sa.sa_family != conf->remote_ip.sa.sa_family) return -EINVAL; + if (vxlan_addr_multicast(&conf->saddr)) + return -EINVAL; + if (conf->saddr.sa.sa_family == AF_INET6) { if (!IS_ENABLED(CONFIG_IPV6)) return -EPFNOSUPPORT; use_ipv6 = true; conf->flags |= VXLAN_F_IPV6; + + if (!(conf->flags & VXLAN_F_COLLECT_METADATA)) { + int local_type = + ipv6_addr_type(&conf->saddr.sin6.sin6_addr); + int remote_type = + ipv6_addr_type(&conf->remote_ip.sin6.sin6_addr); + + if (local_type & IPV6_ADDR_LINKLOCAL) { + if (!(remote_type & IPV6_ADDR_LINKLOCAL) && + (remote_type != IPV6_ADDR_ANY)) + return -EINVAL; + + conf->flags |= VXLAN_F_IPV6_LINKLOCAL; + } else { + if (remote_type == + (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL)) + return -EINVAL; + + conf->flags &= ~VXLAN_F_IPV6_LINKLOCAL; + } + } } if (conf->label && !use_ipv6) @@ -2937,6 +2961,11 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, if (vxlan_addr_multicast(&conf->remote_ip)) return -EINVAL; +#if IS_ENABLED(CONFIG_IPV6) + if (conf->flags & VXLAN_F_IPV6_LINKLOCAL) + return -EINVAL; +#endif + *lower = NULL; } -- cgit v1.2.3 From 87613de95041a88e426105d05a53acece52fd81e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 19 Jun 2017 10:03:59 +0200 Subject: vxlan: fix snooping for link-local IPv6 addresses If VXLAN is run over link-local IPv6 addresses, it is necessary to store the ifindex in the FDB entries. Otherwise, the used interface is undefined and unicast communication will most likely fail. Support for link-local IPv4 addresses should be possible as well, but as the semantics aren't as well defined as for IPv6, and there doesn't seem to be much interest in having the support, it's not implemented for now. Signed-off-by: Matthias Schiffer Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index d6d57317cbd5..45a8a5475f3d 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -957,16 +957,24 @@ out: */ static bool vxlan_snoop(struct net_device *dev, union vxlan_addr *src_ip, const u8 *src_mac, - __be32 vni) + u32 src_ifindex, __be32 vni) { struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_fdb *f; + u32 ifindex = 0; + +#if IS_ENABLED(CONFIG_IPV6) + if (src_ip->sa.sa_family == AF_INET6 && + (ipv6_addr_type(&src_ip->sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL)) + ifindex = src_ifindex; +#endif f = vxlan_find_mac(vxlan, src_mac, vni); if (likely(f)) { struct vxlan_rdst *rdst = first_remote_rcu(f); - if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip))) + if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip) && + rdst->remote_ifindex == ifindex)) return false; /* Don't migrate static entries, drop packets */ @@ -993,7 +1001,7 @@ static bool vxlan_snoop(struct net_device *dev, vxlan->cfg.dst_port, vni, vxlan->default_dst.remote_vni, - 0, NTF_SELF); + ifindex, NTF_SELF); spin_unlock(&vxlan->hash_lock); } @@ -1264,6 +1272,7 @@ static bool vxlan_set_mac(struct vxlan_dev *vxlan, struct sk_buff *skb, __be32 vni) { union vxlan_addr saddr; + u32 ifindex = skb->dev->ifindex; skb_reset_mac_header(skb); skb->protocol = eth_type_trans(skb, vxlan->dev); @@ -1285,7 +1294,7 @@ static bool vxlan_set_mac(struct vxlan_dev *vxlan, } if ((vxlan->cfg.flags & VXLAN_F_LEARN) && - vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, vni)) + vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex, vni)) return false; return true; @@ -1994,7 +2003,8 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, } if (dst_vxlan->cfg.flags & VXLAN_F_LEARN) - vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source, vni); + vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source, 0, + vni); u64_stats_update_begin(&tx_stats->syncp); tx_stats->tx_packets++; -- cgit v1.2.3 From 49f810f00fa347427fa8cba2197b303234842d25 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 19 Jun 2017 10:04:00 +0200 Subject: vxlan: allow multiple VXLANs with same VNI for IPv6 link-local addresses As link-local addresses are only valid for a single interface, we can allow to use the same VNI for multiple independent VXLANs, as long as the used interfaces are distinct. This way, VXLANs can always be used as a drop-in replacement for VLANs with greater ID space. This also extends VNI lookup to respect the ifindex when link-local IPv6 addresses are used, so using the same VNI on multiple interfaces can actually work. Signed-off-by: Matthias Schiffer Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 68 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 45a8a5475f3d..653b2bb32be1 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -226,7 +226,8 @@ static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family, return NULL; } -static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, __be32 vni) +static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, int ifindex, + __be32 vni) { struct vxlan_dev *vxlan; @@ -235,17 +236,27 @@ static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, __be32 vni) vni = 0; hlist_for_each_entry_rcu(vxlan, vni_head(vs, vni), hlist) { - if (vxlan->default_dst.remote_vni == vni) - return vxlan; + if (vxlan->default_dst.remote_vni != vni) + continue; + + if (IS_ENABLED(CONFIG_IPV6)) { + const struct vxlan_config *cfg = &vxlan->cfg; + + if ((cfg->flags & VXLAN_F_IPV6_LINKLOCAL) && + cfg->remote_ifindex != ifindex) + continue; + } + + return vxlan; } return NULL; } /* Look up VNI in a per net namespace table */ -static struct vxlan_dev *vxlan_find_vni(struct net *net, __be32 vni, - sa_family_t family, __be16 port, - u32 flags) +static struct vxlan_dev *vxlan_find_vni(struct net *net, int ifindex, + __be32 vni, sa_family_t family, + __be16 port, u32 flags) { struct vxlan_sock *vs; @@ -253,7 +264,7 @@ static struct vxlan_dev *vxlan_find_vni(struct net *net, __be32 vni, if (!vs) return NULL; - return vxlan_vs_find_vni(vs, vni); + return vxlan_vs_find_vni(vs, ifindex, vni); } /* Fill in neighbour message in skbuff. */ @@ -1360,7 +1371,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) vni = vxlan_vni(vxlan_hdr(skb)->vx_vni); - vxlan = vxlan_vs_find_vni(vs, vni); + vxlan = vxlan_vs_find_vni(vs, skb->dev->ifindex, vni); if (!vxlan) goto drop; @@ -2022,8 +2033,10 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, } static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, - struct vxlan_dev *vxlan, union vxlan_addr *daddr, - __be16 dst_port, __be32 vni, struct dst_entry *dst, + struct vxlan_dev *vxlan, + union vxlan_addr *daddr, + __be16 dst_port, int dst_ifindex, __be32 vni, + struct dst_entry *dst, u32 rt_flags) { #if IS_ENABLED(CONFIG_IPV6) @@ -2039,7 +2052,7 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, struct vxlan_dev *dst_vxlan; dst_release(dst); - dst_vxlan = vxlan_find_vni(vxlan->net, vni, + dst_vxlan = vxlan_find_vni(vxlan->net, dst_ifindex, vni, daddr->sa.sa_family, dst_port, vxlan->cfg.flags); if (!dst_vxlan) { @@ -2071,6 +2084,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct dst_entry *ndst = NULL; __be32 vni, label; __u8 tos, ttl; + int ifindex; int err; u32 flags = vxlan->cfg.flags; bool udp_sum = false; @@ -2091,6 +2105,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port; vni = (rdst->remote_vni) ? : default_vni; + ifindex = rdst->remote_ifindex; local_ip = vxlan->cfg.saddr; dst_cache = &rdst->dst_cache; md->gbp = skb->mark; @@ -2124,6 +2139,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dst = &remote_ip; dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port; vni = tunnel_id_to_key32(info->key.tun_id); + ifindex = 0; dst_cache = &info->dst_cache; if (info->options_len) md = ip_tunnel_info_opts(info); @@ -2141,8 +2157,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct rtable *rt; __be16 df = 0; - rt = vxlan_get_route(vxlan, dev, sock4, skb, - rdst ? rdst->remote_ifindex : 0, tos, + rt = vxlan_get_route(vxlan, dev, sock4, skb, ifindex, tos, dst->sin.sin_addr.s_addr, &local_ip.sin.sin_addr.s_addr, dst_port, src_port, @@ -2155,8 +2170,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, /* Bypass encapsulation if the destination is local */ if (!info) { err = encap_bypass_if_local(skb, dev, vxlan, dst, - dst_port, vni, &rt->dst, - rt->rt_flags); + dst_port, ifindex, vni, + &rt->dst, rt->rt_flags); if (err) goto out_unlock; } else if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT) { @@ -2178,8 +2193,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } else { struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock); - ndst = vxlan6_get_route(vxlan, dev, sock6, skb, - rdst ? rdst->remote_ifindex : 0, tos, + ndst = vxlan6_get_route(vxlan, dev, sock6, skb, ifindex, tos, label, &dst->sin6.sin6_addr, &local_ip.sin6.sin6_addr, dst_port, src_port, @@ -2194,8 +2208,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, u32 rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags; err = encap_bypass_if_local(skb, dev, vxlan, dst, - dst_port, vni, ndst, - rt6i_flags); + dst_port, ifindex, vni, + ndst, rt6i_flags); if (err) goto out_unlock; } @@ -2993,11 +3007,19 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, if (tmp == old) continue; - if (tmp->cfg.vni == conf->vni && - tmp->cfg.dst_port == conf->dst_port && - (tmp->cfg.flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6)) == + if (tmp->cfg.vni != conf->vni) + continue; + if (tmp->cfg.dst_port != conf->dst_port) + continue; + if ((tmp->cfg.flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6)) != (conf->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6))) - return -EEXIST; + continue; + + if ((conf->flags & VXLAN_F_IPV6_LINKLOCAL) && + tmp->cfg.remote_ifindex != conf->remote_ifindex) + continue; + + return -EEXIST; } return 0; -- cgit v1.2.3 From 5969c42768ed6d19e8a61d1ac60e5c8bee8fe9d0 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 19 Jun 2017 15:37:03 +0200 Subject: net-next: mediatek: print phy status changes for non DSA GMACs Currently PHY status changes are only printed for DSA ports. This patch adds code to also print status changes for non-fixed links. Signed-off-by: John Crispin Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 962975d192d1..24d5f1cad7f4 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -221,6 +221,9 @@ static void mtk_phy_link_adjust(struct net_device *dev) netif_carrier_on(dev); else netif_carrier_off(dev); + + if (!of_phy_is_fixed_link(mac->of_node)) + phy_print_status(dev->phydev); } static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, -- cgit v1.2.3 From 671d41e60dbd8943ce069137b312f834a483c582 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 19 Jun 2017 15:37:04 +0200 Subject: net-next: mediatek: add RX IRQ delay support The PDMA engine used for RX allows IRQ aggregation. The patch sets up the corresponding registers to aggregate 4 IRQs into one. Using aggregation reduces the load on the core handling to a quarter thus reducing IRQ latency and increasing RX performance by around 10%. Signed-off-by: John Crispin Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 +++- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 13 ++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 24d5f1cad7f4..92be59a1e4e7 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -1861,9 +1861,11 @@ static int mtk_hw_init(struct mtk_eth *eth) /* Enable RX VLan Offloading */ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + /* enable interrupt delay for RX */ + mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT); + /* disable delay and normal interrupt */ mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); - mtk_w32(eth, 0, MTK_PDMA_DELAY_INT); mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0); mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0); mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 3c46a3b613b9..e130c3b24c4c 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -125,7 +125,14 @@ #define MTK_PST_DRX_IDX_CFG(x) (MTK_PST_DRX_IDX0 << (x)) /* PDMA Delay Interrupt Register */ -#define MTK_PDMA_DELAY_INT 0xa0c +#define MTK_PDMA_DELAY_INT 0xa0c +#define MTK_PDMA_DELAY_RX_EN BIT(15) +#define MTK_PDMA_DELAY_RX_PINT 4 +#define MTK_PDMA_DELAY_RX_PINT_SHIFT 8 +#define MTK_PDMA_DELAY_RX_PTIME 4 +#define MTK_PDMA_DELAY_RX_DELAY \ + (MTK_PDMA_DELAY_RX_EN | MTK_PDMA_DELAY_RX_PTIME | \ + (MTK_PDMA_DELAY_RX_PINT << MTK_PDMA_DELAY_RX_PINT_SHIFT)) /* PDMA Interrupt Status Register */ #define MTK_PDMA_INT_STATUS 0xa20 @@ -206,6 +213,7 @@ /* QDMA Interrupt Status Register */ #define MTK_QMTK_INT_STATUS 0x1A18 +#define MTK_RX_DONE_DLY BIT(30) #define MTK_RX_DONE_INT3 BIT(19) #define MTK_RX_DONE_INT2 BIT(18) #define MTK_RX_DONE_INT1 BIT(17) @@ -214,8 +222,7 @@ #define MTK_TX_DONE_INT2 BIT(2) #define MTK_TX_DONE_INT1 BIT(1) #define MTK_TX_DONE_INT0 BIT(0) -#define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1 | \ - MTK_RX_DONE_INT2 | MTK_RX_DONE_INT3) +#define MTK_RX_DONE_INT MTK_RX_DONE_DLY #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) -- cgit v1.2.3 From 5cce0322cf8cd2c8073b2f8dac08c56e3f5f4acb Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 19 Jun 2017 15:37:05 +0200 Subject: net-next: mediatek: split IRQ register locking into TX and RX Originally the driver only utilised the new QDMA engine. The current code still assumes this is the case when locking the IRQ mask register. Since RX now runs on the old style PDMA engine we can add a second lock. This patch reduces the IRQ latency as the TX and RX path no longer need to wait on each other under heavy load. Signed-off-by: John Crispin Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 79 ++++++++++++++++++----------- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +- 2 files changed, 54 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 92be59a1e4e7..462d1e83e254 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -372,28 +372,48 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth) mdiobus_unregister(eth->mii_bus); } -static inline void mtk_irq_disable(struct mtk_eth *eth, - unsigned reg, u32 mask) +static inline void mtk_tx_irq_disable(struct mtk_eth *eth, u32 mask) { unsigned long flags; u32 val; - spin_lock_irqsave(ð->irq_lock, flags); - val = mtk_r32(eth, reg); - mtk_w32(eth, val & ~mask, reg); - spin_unlock_irqrestore(ð->irq_lock, flags); + spin_lock_irqsave(ð->tx_irq_lock, flags); + val = mtk_r32(eth, MTK_QDMA_INT_MASK); + mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK); + spin_unlock_irqrestore(ð->tx_irq_lock, flags); } -static inline void mtk_irq_enable(struct mtk_eth *eth, - unsigned reg, u32 mask) +static inline void mtk_tx_irq_enable(struct mtk_eth *eth, u32 mask) { unsigned long flags; u32 val; - spin_lock_irqsave(ð->irq_lock, flags); - val = mtk_r32(eth, reg); - mtk_w32(eth, val | mask, reg); - spin_unlock_irqrestore(ð->irq_lock, flags); + spin_lock_irqsave(ð->tx_irq_lock, flags); + val = mtk_r32(eth, MTK_QDMA_INT_MASK); + mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK); + spin_unlock_irqrestore(ð->tx_irq_lock, flags); +} + +static inline void mtk_rx_irq_disable(struct mtk_eth *eth, u32 mask) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(ð->rx_irq_lock, flags); + val = mtk_r32(eth, MTK_PDMA_INT_MASK); + mtk_w32(eth, val & ~mask, MTK_PDMA_INT_MASK); + spin_unlock_irqrestore(ð->rx_irq_lock, flags); +} + +static inline void mtk_rx_irq_enable(struct mtk_eth *eth, u32 mask) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(ð->rx_irq_lock, flags); + val = mtk_r32(eth, MTK_PDMA_INT_MASK); + mtk_w32(eth, val | mask, MTK_PDMA_INT_MASK); + spin_unlock_irqrestore(ð->rx_irq_lock, flags); } static int mtk_set_mac_address(struct net_device *dev, void *p) @@ -1101,7 +1121,7 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget) return budget; napi_complete(napi); - mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); return tx_done; } @@ -1135,7 +1155,7 @@ poll_again: goto poll_again; } napi_complete(napi); - mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); + mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); return rx_done + budget - remain_budget; } @@ -1670,7 +1690,7 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth) if (likely(napi_schedule_prep(ð->rx_napi))) { __napi_schedule(ð->rx_napi); - mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); + mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); } return IRQ_HANDLED; @@ -1682,7 +1702,7 @@ static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth) if (likely(napi_schedule_prep(ð->tx_napi))) { __napi_schedule(ð->tx_napi); - mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); } return IRQ_HANDLED; @@ -1694,11 +1714,11 @@ static void mtk_poll_controller(struct net_device *dev) struct mtk_mac *mac = netdev_priv(dev); struct mtk_eth *eth = mac->hw; - mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); - mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); + mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); mtk_handle_irq_rx(eth->irq[2], dev); - mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); - mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); + mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); } #endif @@ -1739,8 +1759,8 @@ static int mtk_open(struct net_device *dev) napi_enable(ð->tx_napi); napi_enable(ð->rx_napi); - mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); - mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); + mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); } atomic_inc(ð->dma_refcnt); @@ -1785,8 +1805,8 @@ static int mtk_stop(struct net_device *dev) if (!atomic_dec_and_test(ð->dma_refcnt)) return 0; - mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); - mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); + mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); napi_disable(ð->tx_napi); napi_disable(ð->rx_napi); @@ -1866,8 +1886,8 @@ static int mtk_hw_init(struct mtk_eth *eth) /* disable delay and normal interrupt */ mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); - mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0); - mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0); + mtk_tx_irq_disable(eth, ~0); + mtk_rx_irq_disable(eth, ~0); mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); mtk_w32(eth, 0, MTK_RST_GL); @@ -1938,8 +1958,8 @@ static void mtk_uninit(struct net_device *dev) phy_disconnect(dev->phydev); if (of_phy_is_fixed_link(mac->of_node)) of_phy_deregister_fixed_link(mac->of_node); - mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0); - mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0); + mtk_tx_irq_disable(eth, ~0); + mtk_rx_irq_disable(eth, ~0); } static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -2399,7 +2419,8 @@ static int mtk_probe(struct platform_device *pdev) return PTR_ERR(eth->base); spin_lock_init(ð->page_lock); - spin_lock_init(ð->irq_lock); + spin_lock_init(ð->tx_irq_lock); + spin_lock_init(ð->rx_irq_lock); eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mediatek,ethsys"); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index e130c3b24c4c..5868a09f623a 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -519,6 +519,8 @@ struct mtk_rx_ring { * @dev: The device pointer * @base: The mapped register i/o base * @page_lock: Make sure that register operations are atomic + * @tx_irq__lock: Make sure that IRQ register operations are atomic + * @rx_irq__lock: Make sure that IRQ register operations are atomic * @dummy_dev: we run 2 netdevs on 1 physical DMA ring and need a * dummy for NAPI to work * @netdev: The netdev instances @@ -547,7 +549,8 @@ struct mtk_eth { struct device *dev; void __iomem *base; spinlock_t page_lock; - spinlock_t irq_lock; + spinlock_t tx_irq_lock; + spinlock_t rx_irq_lock; struct net_device dummy_dev; struct net_device *netdev[MTK_MAX_DEVS]; struct mtk_mac *mac[MTK_MAX_DEVS]; -- cgit v1.2.3 From a2d5e7b4102deac784373464a8fd9f3eaa53afc0 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 19 Jun 2017 15:37:06 +0200 Subject: net-next: mediatek: set the rx_queue to 0 The get_rps_cpu() function will not do any RPS on the data flow when no queue is setup and always use the current cpu where the IRQ was handled to also handle the backlog. As we only have one physical queue we always set this to 0 unconditionally. Signed-off-by: John Crispin Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 462d1e83e254..adaaafc20532 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -992,6 +992,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, RX_DMA_VID(trxd.rxd3)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), RX_DMA_VID(trxd.rxd3)); + skb_record_rx_queue(skb, 0); napi_gro_receive(napi, skb); ring->data[idx] = new_data; -- cgit v1.2.3 From ca83697cdc9a2fe67957161933abeb703d7aff89 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Mon, 19 Jun 2017 16:00:22 +0200 Subject: net: phy: lxt: Export link partner advertising Provide link partner advertising information. Removed testing for gigabit modes, which is useless for a fast ethernet phy. Signed-off-by: Thomas Bogendoerfer Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/lxt.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index 8d198a1f0031..09d215177fff 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -152,7 +152,6 @@ static int lxt973a2_read_status(struct phy_device *phydev) int adv; int err; int lpa; - int lpagb = 0; /* Update the link, but return if there was an error */ err = lxt973a2_update_link(phydev); @@ -178,18 +177,15 @@ static int lxt973a2_read_status(struct phy_device *phydev) */ } while (lpa == adv && retry--); + phydev->lp_advertising = mii_lpa_to_ethtool_lpa_t(lpa); + lpa &= adv; phydev->speed = SPEED_10; phydev->duplex = DUPLEX_HALF; phydev->pause = phydev->asym_pause = 0; - if (lpagb & (LPA_1000FULL | LPA_1000HALF)) { - phydev->speed = SPEED_1000; - - if (lpagb & LPA_1000FULL) - phydev->duplex = DUPLEX_FULL; - } else if (lpa & (LPA_100FULL | LPA_100HALF)) { + if (lpa & (LPA_100FULL | LPA_100HALF)) { phydev->speed = SPEED_100; if (lpa & LPA_100FULL) @@ -222,6 +218,7 @@ static int lxt973a2_read_status(struct phy_device *phydev) phydev->speed = SPEED_10; phydev->pause = phydev->asym_pause = 0; + phydev->lp_advertising = 0; } return 0; -- cgit v1.2.3 From cb89ba243baf6e5f7ee1ddf491fa45e0cabccdd1 Mon Sep 17 00:00:00 2001 From: John Allen Date: Mon, 19 Jun 2017 11:27:53 -0500 Subject: ibmvnic: Return from ibmvnic_resume if not in VNIC_OPEN state If the ibmvnic driver is not in the VNIC_OPEN state, return from ibmvnic_resume callback. If we are not in the VNIC_OPEN state, interrupts may not be initialized and directly calling the interrupt handler will cause a crash. Signed-off-by: John Allen Reviewed-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 722daf55d757..013509544632 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3859,6 +3859,9 @@ static int ibmvnic_resume(struct device *dev) struct ibmvnic_adapter *adapter = netdev_priv(netdev); int i; + if (adapter->state != VNIC_OPEN) + return 0; + /* kick the interrupt handlers just in case we lost an interrupt */ for (i = 0; i < adapter->req_rx_queues; i++) ibmvnic_interrupt_rx(adapter->rx_scrq[i]->irq, -- cgit v1.2.3 From 9edfa7dab8112a012b349b7937f5444fdc21e8f9 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 19 Jun 2017 18:36:44 +0200 Subject: net: stmmac: enable TSO for IPv6 There is nothing in the IP that prevents us from enabling TSO for IPv6. Before patch: ftp fe80::2aa:bbff:fecc:1336%eth0 ftp> get /dev/zero 882512708 bytes received in 00:14 (56.11 MiB/s) After patch: ftp fe80::2aa:bbff:fecc:1336%eth0 ftp> get /dev/zero 1203326784 bytes received in 00:12 (94.52 MiB/s) Signed-off-by: Niklas Cassel Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 6a1cb59728fe..fefbf817399a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2965,7 +2965,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) /* Manage oversized TCP frames for GMAC4 device */ if (skb_is_gso(skb) && priv->tso) { - if (ip_hdr(skb)->protocol == IPPROTO_TCP) + if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) return stmmac_tso_xmit(skb, dev); } @@ -4126,7 +4126,7 @@ int stmmac_dvr_probe(struct device *device, NETIF_F_RXCSUM; if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) { - ndev->hw_features |= NETIF_F_TSO; + ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; priv->tso = true; dev_info(priv->device, "TSO feature enabled\n"); } -- cgit v1.2.3 From 7044f429e70d987cdc780f26a9b9951970645966 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan Date: Mon, 19 Jun 2017 16:28:44 -0700 Subject: enic: Fix format truncation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With -Wformat-truncation, gcc throws the following warning. Fix this by increasing the size of devname to accommodate 15 character netdev interface name and description. Remove length format precision for %s. We can fit entire name. Also increment the version. drivers/net/ethernet/cisco/enic/enic_main.c: In function ‘enic_open’: drivers/net/ethernet/cisco/enic/enic_main.c:1740:15: warning: ‘%u’ directive output may be truncated writing between 1 and 2 bytes into a region of size between 1 and 12 [-Wformat-truncation=] "%.11s-rx-%u", netdev->name, i); ^~ drivers/net/ethernet/cisco/enic/enic_main.c:1740:5: note: directive argument in the range [0, 16] "%.11s-rx-%u", netdev->name, i); ^~~~~~~~~~~~~ drivers/net/ethernet/cisco/enic/enic_main.c:1738:4: note: ‘snprintf’ output between 6 and 18 bytes into a destination of size 16 snprintf(enic->msix[intr].devname, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sizeof(enic->msix[intr].devname), ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "%.11s-rx-%u", netdev->name, i); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Govindarajulu Varadarajan Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic.h | 4 ++-- drivers/net/ethernet/cisco/enic/enic_main.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 2b23f46b34d3..ba032ac9ae86 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -33,7 +33,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.3.0.31" +#define DRV_VERSION "2.3.0.42" #define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 @@ -47,7 +47,7 @@ struct enic_msix_entry { int requested; - char devname[IFNAMSIZ]; + char devname[IFNAMSIZ + 8]; irqreturn_t (*isr)(int, void *); void *devid; cpumask_var_t affinity_mask; diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 6a9c8878aca0..d24ee1ad3be1 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1737,7 +1737,7 @@ static int enic_request_intr(struct enic *enic) intr = enic_msix_rq_intr(enic, i); snprintf(enic->msix[intr].devname, sizeof(enic->msix[intr].devname), - "%.11s-rx-%u", netdev->name, i); + "%s-rx-%u", netdev->name, i); enic->msix[intr].isr = enic_isr_msix; enic->msix[intr].devid = &enic->napi[i]; } @@ -1748,7 +1748,7 @@ static int enic_request_intr(struct enic *enic) intr = enic_msix_wq_intr(enic, i); snprintf(enic->msix[intr].devname, sizeof(enic->msix[intr].devname), - "%.11s-tx-%u", netdev->name, i); + "%s-tx-%u", netdev->name, i); enic->msix[intr].isr = enic_isr_msix; enic->msix[intr].devid = &enic->napi[wq]; } @@ -1756,14 +1756,14 @@ static int enic_request_intr(struct enic *enic) intr = enic_msix_err_intr(enic); snprintf(enic->msix[intr].devname, sizeof(enic->msix[intr].devname), - "%.11s-err", netdev->name); + "%s-err", netdev->name); enic->msix[intr].isr = enic_isr_msix_err; enic->msix[intr].devid = enic; intr = enic_msix_notify_intr(enic); snprintf(enic->msix[intr].devname, sizeof(enic->msix[intr].devname), - "%.11s-notify", netdev->name); + "%s-notify", netdev->name); enic->msix[intr].isr = enic_isr_msix_notify; enic->msix[intr].devid = enic; -- cgit v1.2.3 From 2063a5f52ad8006db90bb84b4d75bdfee842af28 Mon Sep 17 00:00:00 2001 From: Kittipon Meesompop Date: Tue, 20 Jun 2017 16:00:31 +0200 Subject: s390/qeth: add ipa return codes for bridgeport add ipa return codes for Bridgeport (HiperSockets and OSA) according to system level design. Signed-off-by: Kittipon Meesompop Reviewed-by: Julian Wiedmann Reviewed-by: Ursula Braun Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_mpc.c | 14 ++++++++++++++ drivers/s390/net/qeth_core_mpc.h | 18 ++++++++++++++++++ drivers/s390/net/qeth_l2_main.c | 34 +++++++++++++++++----------------- 3 files changed, 49 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index ab9b1376467f..6dd7d05e5693 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c @@ -170,12 +170,18 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { {IPA_RC_TRACE_ALREADY_ACTIVE, "trace already active"}, {IPA_RC_INVALID_FORMAT, "invalid format or length"}, {IPA_RC_DUP_IPV6_REMOTE, "ipv6 address already registered remote"}, + {IPA_RC_SBP_IQD_NOT_CONFIGURED, "Not configured for bridgeport"}, {IPA_RC_DUP_IPV6_HOME, "ipv6 address already registered"}, {IPA_RC_UNREGISTERED_ADDR, "Address not registered"}, {IPA_RC_NO_ID_AVAILABLE, "No identifiers available"}, {IPA_RC_ID_NOT_FOUND, "Identifier not found"}, + {IPA_RC_SBP_IQD_ANO_DEV_PRIMARY, "Primary bridgeport exists already"}, + {IPA_RC_SBP_IQD_CURRENT_SECOND, "Bridgeport is currently secondary"}, + {IPA_RC_SBP_IQD_LIMIT_SECOND, "Limit of secondary bridgeports reached"}, {IPA_RC_INVALID_IP_VERSION, "IP version incorrect"}, + {IPA_RC_SBP_IQD_CURRENT_PRIMARY, "Bridgeport is currently primary"}, {IPA_RC_LAN_FRAME_MISMATCH, "LAN and frame mismatch"}, + {IPA_RC_SBP_IQD_NO_QDIO_QUEUES, "QDIO queues not established"}, {IPA_RC_L2_UNSUPPORTED_CMD, "Unsupported layer 2 command"}, {IPA_RC_L2_DUP_MAC, "Duplicate MAC address"}, {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, @@ -187,6 +193,14 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, {IPA_RC_L2_VLAN_ID_NOT_FOUND, "L2 vlan id not found"}, + {IPA_RC_SBP_OSA_NOT_CONFIGURED, "Not configured for bridgeport"}, + {IPA_RC_SBP_OSA_OS_MISMATCH, "OS mismatch"}, + {IPA_RC_SBP_OSA_ANO_DEV_PRIMARY, "Primary bridgeport exists already"}, + {IPA_RC_SBP_OSA_CURRENT_SECOND, "Bridgeport is currently secondary"}, + {IPA_RC_SBP_OSA_LIMIT_SECOND, "Limit of secondary bridgeports reached"}, + {IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN, "Not authorized by zManager"}, + {IPA_RC_SBP_OSA_CURRENT_PRIMARY, "Bridgeport is currently primary"}, + {IPA_RC_SBP_OSA_NO_QDIO_QUEUES, "QDIO queues not established"}, {IPA_RC_DATA_MISMATCH, "Data field mismatch (v4/v6 mixed)"}, {IPA_RC_INVALID_MTU_SIZE, "Invalid MTU size"}, {IPA_RC_INVALID_LANTYPE, "Invalid LAN type"}, diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 45bbea2843bf..912e0107de8f 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -142,12 +142,18 @@ enum qeth_ipa_return_codes { IPA_RC_TRACE_ALREADY_ACTIVE = 0x0005, IPA_RC_INVALID_FORMAT = 0x0006, IPA_RC_DUP_IPV6_REMOTE = 0x0008, + IPA_RC_SBP_IQD_NOT_CONFIGURED = 0x000C, IPA_RC_DUP_IPV6_HOME = 0x0010, IPA_RC_UNREGISTERED_ADDR = 0x0011, IPA_RC_NO_ID_AVAILABLE = 0x0012, IPA_RC_ID_NOT_FOUND = 0x0013, + IPA_RC_SBP_IQD_ANO_DEV_PRIMARY = 0x0014, + IPA_RC_SBP_IQD_CURRENT_SECOND = 0x0018, + IPA_RC_SBP_IQD_LIMIT_SECOND = 0x001C, IPA_RC_INVALID_IP_VERSION = 0x0020, + IPA_RC_SBP_IQD_CURRENT_PRIMARY = 0x0024, IPA_RC_LAN_FRAME_MISMATCH = 0x0040, + IPA_RC_SBP_IQD_NO_QDIO_QUEUES = 0x00EB, IPA_RC_L2_UNSUPPORTED_CMD = 0x2003, IPA_RC_L2_DUP_MAC = 0x2005, IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, @@ -159,6 +165,14 @@ enum qeth_ipa_return_codes { IPA_RC_L2_INVALID_VLAN_ID = 0x2015, IPA_RC_L2_DUP_VLAN_ID = 0x2016, IPA_RC_L2_VLAN_ID_NOT_FOUND = 0x2017, + IPA_RC_SBP_OSA_NOT_CONFIGURED = 0x2B0C, + IPA_RC_SBP_OSA_OS_MISMATCH = 0x2B10, + IPA_RC_SBP_OSA_ANO_DEV_PRIMARY = 0x2B14, + IPA_RC_SBP_OSA_CURRENT_SECOND = 0x2B18, + IPA_RC_SBP_OSA_LIMIT_SECOND = 0x2B1C, + IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN = 0x2B20, + IPA_RC_SBP_OSA_CURRENT_PRIMARY = 0x2B24, + IPA_RC_SBP_OSA_NO_QDIO_QUEUES = 0x2BEB, IPA_RC_DATA_MISMATCH = 0xe001, IPA_RC_INVALID_MTU_SIZE = 0xe002, IPA_RC_INVALID_LANTYPE = 0xe003, @@ -187,6 +201,10 @@ enum qeth_ipa_return_codes { #define IPA_RC_INVALID_SUBCMD IPA_RC_IP_TABLE_FULL #define IPA_RC_HARDWARE_AUTH_ERROR IPA_RC_UNKNOWN_ERROR +/* for SETBRIDGEPORT (double occupancies) */ +#define IPA_RC_SBP_IQD_OS_MISMATCH IPA_RC_DUP_IPV6_HOME +#define IPA_RC_SBP_IQD_NOT_AUTHD_BY_ZMAN IPA_RC_INVALID_IP_VERSION + /* IPA function flags; each flag marks availability of respective function */ enum qeth_ipa_funcs { IPA_ARP_PROCESSING = 0x00000001L, diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index c6bc63b8b295..9e7f12aba55e 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1650,27 +1650,27 @@ static int qeth_bridgeport_makerc(struct qeth_card *card, if ((is_iqd && (cbctl->ipa_rc == IPA_RC_SUCCESS)) || (!is_iqd && (cbctl->ipa_rc == cbctl->cmd_rc))) switch (cbctl->cmd_rc) { - case 0x0000: + case IPA_RC_SUCCESS: rc = 0; break; - case 0x2B04: - case 0x0004: + case IPA_RC_L2_UNSUPPORTED_CMD: + case IPA_RC_UNSUPPORTED_COMMAND: rc = -EOPNOTSUPP; break; - case 0x2B0C: - case 0x000C: /* Not configured as bridge Port */ + case IPA_RC_SBP_OSA_NOT_CONFIGURED: + case IPA_RC_SBP_IQD_NOT_CONFIGURED: rc = -ENODEV; /* maybe not the best code here? */ dev_err(&card->gdev->dev, "The device is not configured as a Bridge Port\n"); break; - case 0x2B10: - case 0x0010: /* OS mismatch */ + case IPA_RC_SBP_OSA_OS_MISMATCH: + case IPA_RC_SBP_IQD_OS_MISMATCH: rc = -EPERM; dev_err(&card->gdev->dev, "A Bridge Port is already configured by a different operating system\n"); break; - case 0x2B14: - case 0x0014: /* Another device is Primary */ + case IPA_RC_SBP_OSA_ANO_DEV_PRIMARY: + case IPA_RC_SBP_IQD_ANO_DEV_PRIMARY: switch (setcmd) { case IPA_SBP_SET_PRIMARY_BRIDGE_PORT: rc = -EEXIST; @@ -1686,26 +1686,26 @@ static int qeth_bridgeport_makerc(struct qeth_card *card, rc = -EIO; } break; - case 0x2B18: - case 0x0018: /* This device is currently Secondary */ + case IPA_RC_SBP_OSA_CURRENT_SECOND: + case IPA_RC_SBP_IQD_CURRENT_SECOND: rc = -EBUSY; dev_err(&card->gdev->dev, "The device is already a secondary Bridge Port\n"); break; - case 0x2B1C: - case 0x001C: /* Limit for Secondary devices reached */ + case IPA_RC_SBP_OSA_LIMIT_SECOND: + case IPA_RC_SBP_IQD_LIMIT_SECOND: rc = -EEXIST; dev_err(&card->gdev->dev, "The LAN cannot have more secondary Bridge Ports\n"); break; - case 0x2B24: - case 0x0024: /* This device is currently Primary */ + case IPA_RC_SBP_OSA_CURRENT_PRIMARY: + case IPA_RC_SBP_IQD_CURRENT_PRIMARY: rc = -EBUSY; dev_err(&card->gdev->dev, "The device is already a primary Bridge Port\n"); break; - case 0x2B20: - case 0x0020: /* Not authorized by zManager */ + case IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN: + case IPA_RC_SBP_IQD_NOT_AUTHD_BY_ZMAN: rc = -EACCES; dev_err(&card->gdev->dev, "The device is not authorized to be a Bridge Port\n"); -- cgit v1.2.3 From 3cdc8a25297e4e0646c3e72671c95f065117a9fd Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 20 Jun 2017 16:00:32 +0200 Subject: s390/qeth: fix packing buffer statistics There's two spots in qeth_send_packet() where we don't accurately account for transmitted packing buffers in qeth's performance statistics: 1) when flushing the current buffer due to insufficient size, and the next buffer is not EMPTY, we need to account for that flushed buffer. 2) when synchronizing with the TX completion code, we reset flush_count and thus forget to account for any previously flushed buffers. Reported-by: Nils Hoppmann Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 08338f27c82c..13a55f1dee7a 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4103,7 +4103,8 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, flush_count); atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); - return -EBUSY; + rc = -EBUSY; + goto out; } } } @@ -4122,19 +4123,21 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, * In that case we will enter this loop */ while (atomic_dec_return(&queue->state)) { - flush_count = 0; start_index = queue->next_buf_to_fill; /* check if we can go back to non-packing state */ - flush_count += qeth_switch_to_nonpacking_if_needed(queue); + tmp = qeth_switch_to_nonpacking_if_needed(queue); /* * check if we need to flush a packing buffer to get a pci * flag out on the queue */ - if (!flush_count && !atomic_read(&queue->set_pci_flags_count)) - flush_count += qeth_prep_flush_pack_buffer(queue); - if (flush_count) - qeth_flush_buffers(queue, start_index, flush_count); + if (!tmp && !atomic_read(&queue->set_pci_flags_count)) + tmp = qeth_prep_flush_pack_buffer(queue); + if (tmp) { + qeth_flush_buffers(queue, start_index, tmp); + flush_count += tmp; + } } +out: /* at this point the queue is UNLOCKED again */ if (queue->card->options.performance_stats && do_pack) queue->card->perf_stats.bufs_sent_pack += flush_count; -- cgit v1.2.3 From ec61bd2fd2a27bf7368261b230ef54fe34d1cce3 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 20 Jun 2017 16:00:34 +0200 Subject: s390/qeth: use diag26c to get MAC address on L2 When a s390 guest runs on a z/VM host that's part of a SSI cluster, it can be migrated to a different host. In this case, the MAC address it originally obtained on the old host may be re-assigned to a new guest. This would result in address conflicts between the two guests. When running as z/VM guest, use the diag26c MAC Service to obtain a hypervisor-managed MAC address. The MAC Service is SSI-aware, and won't re-assign the address after the guest is migrated to a new host. This patch adds support for the z/VM MAC Service on L2 devices. Signed-off-by: Julian Wiedmann Acked-by: Ursula Braun Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 + drivers/s390/net/qeth_core_main.c | 61 +++++++++++++++++++++++++++++++++++++++ drivers/s390/net/qeth_l2_main.c | 16 ++++++++-- 3 files changed, 76 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 0efc54a4d82f..7a0ffc71b25d 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -986,6 +986,7 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *, int qeth_set_features(struct net_device *, netdev_features_t); int qeth_recover_features(struct net_device *); netdev_features_t qeth_fix_features(struct net_device *, netdev_features_t); +int qeth_vm_request_mac(struct qeth_card *card); /* exports for OSN */ int qeth_osn_assist(struct net_device *, void *, int); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 13a55f1dee7a..3b657d5b7e49 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include #include "qeth_core.h" @@ -4773,6 +4776,64 @@ static int qeth_query_card_info(struct qeth_card *card, (void *)carrier_info); } +/** + * qeth_vm_request_mac() - Request a hypervisor-managed MAC address + * @card: pointer to a qeth_card + * + * Returns + * 0, if a MAC address has been set for the card's netdevice + * a return code, for various error conditions + */ +int qeth_vm_request_mac(struct qeth_card *card) +{ + struct diag26c_mac_resp *response; + struct diag26c_mac_req *request; + struct ccw_dev_id id; + int rc; + + QETH_DBF_TEXT(SETUP, 2, "vmreqmac"); + + if (!card->dev) + return -ENODEV; + + request = kzalloc(sizeof(*request), GFP_KERNEL | GFP_DMA); + response = kzalloc(sizeof(*response), GFP_KERNEL | GFP_DMA); + if (!request || !response) { + rc = -ENOMEM; + goto out; + } + + ccw_device_get_id(CARD_DDEV(card), &id); + request->resp_buf_len = sizeof(*response); + request->resp_version = DIAG26C_VERSION2; + request->op_code = DIAG26C_GET_MAC; + request->devno = id.devno; + + rc = diag26c(request, response, DIAG26C_MAC_SERVICES); + if (rc) + goto out; + + if (request->resp_buf_len < sizeof(*response) || + response->version != request->resp_version) { + rc = -EIO; + QETH_DBF_TEXT(SETUP, 2, "badresp"); + QETH_DBF_HEX(SETUP, 2, &request->resp_buf_len, + sizeof(request->resp_buf_len)); + } else if (!is_valid_ether_addr(response->mac)) { + rc = -EINVAL; + QETH_DBF_TEXT(SETUP, 2, "badmac"); + QETH_DBF_HEX(SETUP, 2, response->mac, ETH_ALEN); + } else { + ether_addr_copy(card->dev->dev_addr, response->mac); + } + +out: + kfree(response); + kfree(request); + return rc; +} +EXPORT_SYMBOL_GPL(qeth_vm_request_mac); + static inline int qeth_get_qdio_q_format(struct qeth_card *card) { if (card->info.type == QETH_CARD_TYPE_IQD) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 9e7f12aba55e..ad110abfdd47 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "qeth_core.h" #include "qeth_l2.h" @@ -505,9 +506,19 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card) int rc = 0; char vendor_pre[] = {0x02, 0x00, 0x00}; - QETH_DBF_TEXT(SETUP, 2, "doL2init"); + QETH_DBF_TEXT(SETUP, 2, "l2reqmac"); QETH_DBF_TEXT_(SETUP, 2, "doL2%s", CARD_BUS_ID(card)); + if (MACHINE_IS_VM) { + rc = qeth_vm_request_mac(card); + if (!rc) + goto out; + QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %s: x%x\n", + CARD_BUS_ID(card), rc); + QETH_DBF_TEXT_(SETUP, 2, "err%04x", rc); + /* fall back to alternative mechanism: */ + } + if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) { rc = qeth_query_setadapterparms(card); if (rc) { @@ -528,11 +539,12 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card) QETH_DBF_TEXT_(SETUP, 2, "1err%04x", rc); return rc; } - QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, OSA_ADDR_LEN); } else { eth_random_addr(card->dev->dev_addr); memcpy(card->dev->dev_addr, vendor_pre, 3); } +out: + QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, card->dev->addr_len); return 0; } -- cgit v1.2.3 From 0c8493d90b6bb0f5c4fe9217db8f7203f24c0f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Wed, 24 May 2017 07:55:34 +0200 Subject: i40e: add XDP support for pass and drop actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds basic XDP support for i40e derived NICs. All XDP actions will end up in XDP_DROP. Signed-off-by: Björn Töpel Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 7 ++ drivers/net/ethernet/intel/i40e/i40e_main.c | 87 +++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_txrx.c | 130 +++++++++++++++++++++------- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 1 + 4 files changed, 194 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 395ca94faf80..d3195b29d53c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -645,6 +645,8 @@ struct i40e_vsi { u16 max_frame; u16 rx_buf_len; + struct bpf_prog *xdp_prog; + /* List of q_vectors allocated to this VSI */ struct i40e_q_vector **q_vectors; int num_q_vectors; @@ -972,4 +974,9 @@ i40e_status i40e_get_npar_bw_setting(struct i40e_pf *pf); i40e_status i40e_set_npar_bw_setting(struct i40e_pf *pf); i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf); void i40e_print_link_message(struct i40e_vsi *vsi, bool isup); + +static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi) +{ + return !!vsi->xdp_prog; +} #endif /* _I40E_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 98fb644a580e..89bbe32a5934 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -27,6 +27,7 @@ #include #include #include +#include /* Local includes */ #include "i40e.h" @@ -2395,6 +2396,18 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf) } } +/** + * i40e_max_xdp_frame_size - returns the maximum allowed frame size for XDP + * @vsi: the vsi + **/ +static int i40e_max_xdp_frame_size(struct i40e_vsi *vsi) +{ + if (PAGE_SIZE >= 8192 || (vsi->back->flags & I40E_FLAG_LEGACY_RX)) + return I40E_RXBUFFER_2048; + else + return I40E_RXBUFFER_3072; +} + /** * i40e_change_mtu - NDO callback to change the Maximum Transfer Unit * @netdev: network interface device structure @@ -2408,6 +2421,13 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu) struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; + if (i40e_enabled_xdp_vsi(vsi)) { + int frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + + if (frame_size > i40e_max_xdp_frame_size(vsi)) + return -EINVAL; + } + netdev_info(netdev, "changing MTU from %d to %d\n", netdev->mtu, new_mtu); netdev->mtu = new_mtu; @@ -9311,6 +9331,72 @@ out_err: return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); } +/** + * i40e_xdp_setup - add/remove an XDP program + * @vsi: VSI to changed + * @prog: XDP program + **/ +static int i40e_xdp_setup(struct i40e_vsi *vsi, + struct bpf_prog *prog) +{ + int frame_size = vsi->netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + struct i40e_pf *pf = vsi->back; + struct bpf_prog *old_prog; + bool need_reset; + int i; + + /* Don't allow frames that span over multiple buffers */ + if (frame_size > vsi->rx_buf_len) + return -EINVAL; + + if (!i40e_enabled_xdp_vsi(vsi) && !prog) + return 0; + + /* When turning XDP on->off/off->on we reset and rebuild the rings. */ + need_reset = (i40e_enabled_xdp_vsi(vsi) != !!prog); + + if (need_reset) + i40e_prep_for_reset(pf, true); + + old_prog = xchg(&vsi->xdp_prog, prog); + + if (need_reset) + i40e_reset_and_rebuild(pf, true, true); + + for (i = 0; i < vsi->num_queue_pairs; i++) + WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog); + + if (old_prog) + bpf_prog_put(old_prog); + + return 0; +} + +/** + * i40e_xdp - implements ndo_xdp for i40e + * @dev: netdevice + * @xdp: XDP command + **/ +static int i40e_xdp(struct net_device *dev, + struct netdev_xdp *xdp) +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + struct i40e_vsi *vsi = np->vsi; + + if (vsi->type != I40E_VSI_MAIN) + return -EINVAL; + + switch (xdp->command) { + case XDP_SETUP_PROG: + return i40e_xdp_setup(vsi, xdp->prog); + case XDP_QUERY_PROG: + xdp->prog_attached = i40e_enabled_xdp_vsi(vsi); + return 0; + default: + return -EINVAL; + } +} + static const struct net_device_ops i40e_netdev_ops = { .ndo_open = i40e_open, .ndo_stop = i40e_close, @@ -9343,6 +9429,7 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_features_check = i40e_features_check, .ndo_bridge_getlink = i40e_ndo_bridge_getlink, .ndo_bridge_setlink = i40e_ndo_bridge_setlink, + .ndo_xdp = i40e_xdp, }; /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index af554f3cda19..f744f843bc72 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -26,6 +26,7 @@ #include #include +#include #include "i40e.h" #include "i40e_trace.h" #include "i40e_prototype.h" @@ -1195,6 +1196,7 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring) void i40e_free_rx_resources(struct i40e_ring *rx_ring) { i40e_clean_rx_ring(rx_ring); + rx_ring->xdp_prog = NULL; kfree(rx_ring->rx_bi); rx_ring->rx_bi = NULL; @@ -1241,6 +1243,8 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring) rx_ring->next_to_clean = 0; rx_ring->next_to_use = 0; + rx_ring->xdp_prog = rx_ring->vsi->xdp_prog; + return 0; err: kfree(rx_ring->rx_bi); @@ -1593,6 +1597,7 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring, * i40e_cleanup_headers - Correct empty headers * @rx_ring: rx descriptor ring packet is being transacted on * @skb: pointer to current skb being fixed + * @rx_desc: pointer to the EOP Rx descriptor * * Also address the case where we are pulling data in on pages only * and as such no data is present in the skb header. @@ -1602,8 +1607,25 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring, * * Returns true if an error was encountered and skb was freed. **/ -static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb) +static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb, + union i40e_rx_desc *rx_desc) + { + /* XDP packets use error pointer so abort at this point */ + if (IS_ERR(skb)) + return true; + + /* ERR_MASK will only have valid bits if EOP set, and + * what we are doing here is actually checking + * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in + * the error field + */ + if (unlikely(i40e_test_staterr(rx_desc, + BIT(I40E_RXD_QW1_ERROR_SHIFT)))) { + dev_kfree_skb_any(skb); + return true; + } + /* if eth_skb_pad returns an error the skb was freed */ if (eth_skb_pad(skb)) return true; @@ -1776,7 +1798,7 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring, * i40e_construct_skb - Allocate skb and populate it * @rx_ring: rx descriptor ring to transact packets on * @rx_buffer: rx buffer to pull data from - * @size: size of buffer to add to skb + * @xdp: xdp_buff pointing to the data * * This function allocates an skb. It then populates it with the page * data from the current receive descriptor, taking care to set up the @@ -1784,9 +1806,9 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring, */ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, struct i40e_rx_buffer *rx_buffer, - unsigned int size) + struct xdp_buff *xdp) { - void *va = page_address(rx_buffer->page) + rx_buffer->page_offset; + unsigned int size = xdp->data_end - xdp->data; #if (PAGE_SIZE < 8192) unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2; #else @@ -1796,9 +1818,9 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, struct sk_buff *skb; /* prefetch first cache line of first page */ - prefetch(va); + prefetch(xdp->data); #if L1_CACHE_BYTES < 128 - prefetch(va + L1_CACHE_BYTES); + prefetch(xdp->data + L1_CACHE_BYTES); #endif /* allocate a skb to store the frags */ @@ -1811,10 +1833,11 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, /* Determine available headroom for copy */ headlen = size; if (headlen > I40E_RX_HDR_SIZE) - headlen = eth_get_headlen(va, I40E_RX_HDR_SIZE); + headlen = eth_get_headlen(xdp->data, I40E_RX_HDR_SIZE); /* align pull length to size of long to optimize memcpy performance */ - memcpy(__skb_put(skb, headlen), va, ALIGN(headlen, sizeof(long))); + memcpy(__skb_put(skb, headlen), xdp->data, + ALIGN(headlen, sizeof(long))); /* update all of the pointers */ size -= headlen; @@ -1841,16 +1864,16 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, * i40e_build_skb - Build skb around an existing buffer * @rx_ring: Rx descriptor ring to transact packets on * @rx_buffer: Rx buffer to pull data from - * @size: size of buffer to add to skb + * @xdp: xdp_buff pointing to the data * * This function builds an skb around an existing Rx buffer, taking care * to set up the skb correctly and avoid any memcpy overhead. */ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring, struct i40e_rx_buffer *rx_buffer, - unsigned int size) + struct xdp_buff *xdp) { - void *va = page_address(rx_buffer->page) + rx_buffer->page_offset; + unsigned int size = xdp->data_end - xdp->data; #if (PAGE_SIZE < 8192) unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2; #else @@ -1860,12 +1883,12 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring, struct sk_buff *skb; /* prefetch first cache line of first page */ - prefetch(va); + prefetch(xdp->data); #if L1_CACHE_BYTES < 128 - prefetch(va + L1_CACHE_BYTES); + prefetch(xdp->data + L1_CACHE_BYTES); #endif /* build an skb around the page buffer */ - skb = build_skb(va - I40E_SKB_PAD, truesize); + skb = build_skb(xdp->data_hard_start, truesize); if (unlikely(!skb)) return NULL; @@ -1944,6 +1967,46 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring, return true; } +#define I40E_XDP_PASS 0 +#define I40E_XDP_CONSUMED 1 + +/** + * i40e_run_xdp - run an XDP program + * @rx_ring: Rx ring being processed + * @xdp: XDP buffer containing the frame + **/ +static struct sk_buff *i40e_run_xdp(struct i40e_ring *rx_ring, + struct xdp_buff *xdp) +{ + int result = I40E_XDP_PASS; + struct bpf_prog *xdp_prog; + u32 act; + + rcu_read_lock(); + xdp_prog = READ_ONCE(rx_ring->xdp_prog); + + if (!xdp_prog) + goto xdp_out; + + act = bpf_prog_run_xdp(xdp_prog, xdp); + switch (act) { + case XDP_PASS: + break; + default: + bpf_warn_invalid_xdp_action(act); + case XDP_TX: + case XDP_ABORTED: + trace_xdp_exception(rx_ring->netdev, xdp_prog, act); + /* fallthrough -- handle aborts by dropping packet */ + case XDP_DROP: + result = I40E_XDP_CONSUMED; + break; + } +xdp_out: + rcu_read_unlock(); + return ERR_PTR(-result); +} + /** * i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf * @rx_ring: rx descriptor ring to transact packets on @@ -1966,6 +2029,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) while (likely(total_rx_packets < budget)) { struct i40e_rx_buffer *rx_buffer; union i40e_rx_desc *rx_desc; + struct xdp_buff xdp; unsigned int size; u16 vlan_tag; u8 rx_ptype; @@ -2006,12 +2070,27 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) rx_buffer = i40e_get_rx_buffer(rx_ring, size); /* retrieve a buffer from the ring */ - if (skb) + if (!skb) { + xdp.data = page_address(rx_buffer->page) + + rx_buffer->page_offset; + xdp.data_hard_start = xdp.data - + i40e_rx_offset(rx_ring); + xdp.data_end = xdp.data + size; + + skb = i40e_run_xdp(rx_ring, &xdp); + } + + if (IS_ERR(skb)) { + total_rx_bytes += size; + total_rx_packets++; + rx_buffer->pagecnt_bias++; + } else if (skb) { i40e_add_rx_frag(rx_ring, rx_buffer, skb, size); - else if (ring_uses_build_skb(rx_ring)) - skb = i40e_build_skb(rx_ring, rx_buffer, size); - else - skb = i40e_construct_skb(rx_ring, rx_buffer, size); + } else if (ring_uses_build_skb(rx_ring)) { + skb = i40e_build_skb(rx_ring, rx_buffer, &xdp); + } else { + skb = i40e_construct_skb(rx_ring, rx_buffer, &xdp); + } /* exit if we failed to retrieve a buffer */ if (!skb) { @@ -2026,18 +2105,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) if (i40e_is_non_eop(rx_ring, rx_desc, skb)) continue; - /* ERR_MASK will only have valid bits if EOP set, and - * what we are doing here is actually checking - * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in - * the error field - */ - if (unlikely(i40e_test_staterr(rx_desc, BIT(I40E_RXD_QW1_ERROR_SHIFT)))) { - dev_kfree_skb_any(skb); - skb = NULL; - continue; - } - - if (i40e_cleanup_headers(rx_ring, skb)) { + if (i40e_cleanup_headers(rx_ring, skb, rx_desc)) { skb = NULL; continue; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index f5de51124cae..31f0b162996f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -360,6 +360,7 @@ struct i40e_ring { void *desc; /* Descriptor ring memory */ struct device *dev; /* Used for DMA mapping */ struct net_device *netdev; /* netdev ring maps to */ + struct bpf_prog *xdp_prog; union { struct i40e_tx_buffer *tx_bi; struct i40e_rx_buffer *rx_bi; -- cgit v1.2.3 From 74608d17fe29b2cddceea609033019b32e8a0650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= Date: Wed, 24 May 2017 07:55:35 +0200 Subject: i40e: add support for XDP_TX action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds proper XDP_TX action support. For each Tx ring, an additional XDP Tx ring is allocated and setup. This version does the DMA mapping in the fast-path, which will penalize performance for IOMMU enabled systems. Further, debugfs support is not wired up for the XDP Tx rings. Signed-off-by: Björn Töpel Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 42 +++- drivers/net/ethernet/intel/i40e/i40e_main.c | 299 +++++++++++++++++++------ drivers/net/ethernet/intel/i40e/i40e_txrx.c | 118 +++++++++- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 11 + 5 files changed, 384 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index d3195b29d53c..4250ab55a9f1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -629,6 +629,7 @@ struct i40e_vsi { /* These are containers of ring pointers, allocated at run-time */ struct i40e_ring **rx_rings; struct i40e_ring **tx_rings; + struct i40e_ring **xdp_rings; /* XDP Tx rings */ u32 active_filters; u32 promisc_threshold; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 3d58762efbc0..9d3233c2c9cd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1299,6 +1299,17 @@ static void i40e_get_ringparam(struct net_device *netdev, ring->rx_jumbo_pending = 0; } +static bool i40e_active_tx_ring_index(struct i40e_vsi *vsi, u16 index) +{ + if (i40e_enabled_xdp_vsi(vsi)) { + return index < vsi->num_queue_pairs || + (index >= vsi->alloc_queue_pairs && + index < vsi->alloc_queue_pairs + vsi->num_queue_pairs); + } + + return index < vsi->num_queue_pairs; +} + static int i40e_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { @@ -1308,6 +1319,7 @@ static int i40e_set_ringparam(struct net_device *netdev, struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; u32 new_rx_count, new_tx_count; + u16 tx_alloc_queue_pairs; int timeout = 50; int i, err = 0; @@ -1345,6 +1357,8 @@ static int i40e_set_ringparam(struct net_device *netdev, for (i = 0; i < vsi->num_queue_pairs; i++) { vsi->tx_rings[i]->count = new_tx_count; vsi->rx_rings[i]->count = new_rx_count; + if (i40e_enabled_xdp_vsi(vsi)) + vsi->xdp_rings[i]->count = new_tx_count; } goto done; } @@ -1354,20 +1368,24 @@ static int i40e_set_ringparam(struct net_device *netdev, * to the Tx and Rx ring structs. */ - /* alloc updated Tx resources */ + /* alloc updated Tx and XDP Tx resources */ + tx_alloc_queue_pairs = vsi->alloc_queue_pairs * + (i40e_enabled_xdp_vsi(vsi) ? 2 : 1); if (new_tx_count != vsi->tx_rings[0]->count) { netdev_info(netdev, "Changing Tx descriptor count from %d to %d.\n", vsi->tx_rings[0]->count, new_tx_count); - tx_rings = kcalloc(vsi->alloc_queue_pairs, + tx_rings = kcalloc(tx_alloc_queue_pairs, sizeof(struct i40e_ring), GFP_KERNEL); if (!tx_rings) { err = -ENOMEM; goto done; } - for (i = 0; i < vsi->num_queue_pairs; i++) { - /* clone ring and setup updated count */ + for (i = 0; i < tx_alloc_queue_pairs; i++) { + if (!i40e_active_tx_ring_index(vsi, i)) + continue; + tx_rings[i] = *vsi->tx_rings[i]; tx_rings[i].count = new_tx_count; /* the desc and bi pointers will be reallocated in the @@ -1379,6 +1397,8 @@ static int i40e_set_ringparam(struct net_device *netdev, if (err) { while (i) { i--; + if (!i40e_active_tx_ring_index(vsi, i)) + continue; i40e_free_tx_resources(&tx_rings[i]); } kfree(tx_rings); @@ -1446,9 +1466,11 @@ rx_unwind: i40e_down(vsi); if (tx_rings) { - for (i = 0; i < vsi->num_queue_pairs; i++) { - i40e_free_tx_resources(vsi->tx_rings[i]); - *vsi->tx_rings[i] = tx_rings[i]; + for (i = 0; i < tx_alloc_queue_pairs; i++) { + if (i40e_active_tx_ring_index(vsi, i)) { + i40e_free_tx_resources(vsi->tx_rings[i]); + *vsi->tx_rings[i] = tx_rings[i]; + } } kfree(tx_rings); tx_rings = NULL; @@ -1479,8 +1501,10 @@ rx_unwind: free_tx: /* error cleanup if the Rx allocations failed after getting Tx */ if (tx_rings) { - for (i = 0; i < vsi->num_queue_pairs; i++) - i40e_free_tx_resources(&tx_rings[i]); + for (i = 0; i < tx_alloc_queue_pairs; i++) { + if (i40e_active_tx_ring_index(vsi, i)) + i40e_free_tx_resources(vsi->tx_rings[i]); + } kfree(tx_rings); tx_rings = NULL; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 89bbe32a5934..7e415bb5a7dc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -407,6 +407,27 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi) return &vsi->net_stats; } +/** + * i40e_get_netdev_stats_struct_tx - populate stats from a Tx ring + * @ring: Tx ring to get statistics from + * @stats: statistics entry to be updated + **/ +static void i40e_get_netdev_stats_struct_tx(struct i40e_ring *ring, + struct rtnl_link_stats64 *stats) +{ + u64 bytes, packets; + unsigned int start; + + do { + start = u64_stats_fetch_begin_irq(&ring->syncp); + packets = ring->stats.packets; + bytes = ring->stats.bytes; + } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); + + stats->tx_packets += packets; + stats->tx_bytes += bytes; +} + /** * i40e_get_netdev_stats_struct - Get statistics for netdev interface * @netdev: network interface device structure @@ -437,15 +458,8 @@ static void i40e_get_netdev_stats_struct(struct net_device *netdev, tx_ring = ACCESS_ONCE(vsi->tx_rings[i]); if (!tx_ring) continue; + i40e_get_netdev_stats_struct_tx(tx_ring, stats); - do { - start = u64_stats_fetch_begin_irq(&tx_ring->syncp); - packets = tx_ring->stats.packets; - bytes = tx_ring->stats.bytes; - } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start)); - - stats->tx_packets += packets; - stats->tx_bytes += bytes; rx_ring = &tx_ring[1]; do { @@ -456,6 +470,9 @@ static void i40e_get_netdev_stats_struct(struct net_device *netdev, stats->rx_packets += packets; stats->rx_bytes += bytes; + + if (i40e_enabled_xdp_vsi(vsi)) + i40e_get_netdev_stats_struct_tx(&rx_ring[1], stats); } rcu_read_unlock(); @@ -2814,6 +2831,12 @@ static int i40e_vsi_setup_tx_resources(struct i40e_vsi *vsi) for (i = 0; i < vsi->num_queue_pairs && !err; i++) err = i40e_setup_tx_descriptors(vsi->tx_rings[i]); + if (!i40e_enabled_xdp_vsi(vsi)) + return err; + + for (i = 0; i < vsi->num_queue_pairs && !err; i++) + err = i40e_setup_tx_descriptors(vsi->xdp_rings[i]); + return err; } @@ -2827,12 +2850,17 @@ static void i40e_vsi_free_tx_resources(struct i40e_vsi *vsi) { int i; - if (!vsi->tx_rings) - return; + if (vsi->tx_rings) { + for (i = 0; i < vsi->num_queue_pairs; i++) + if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) + i40e_free_tx_resources(vsi->tx_rings[i]); + } - for (i = 0; i < vsi->num_queue_pairs; i++) - if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) - i40e_free_tx_resources(vsi->tx_rings[i]); + if (vsi->xdp_rings) { + for (i = 0; i < vsi->num_queue_pairs; i++) + if (vsi->xdp_rings[i] && vsi->xdp_rings[i]->desc) + i40e_free_tx_resources(vsi->xdp_rings[i]); + } } /** @@ -3093,6 +3121,12 @@ static int i40e_vsi_configure_tx(struct i40e_vsi *vsi) for (i = 0; (i < vsi->num_queue_pairs) && !err; i++) err = i40e_configure_tx_ring(vsi->tx_rings[i]); + if (!i40e_enabled_xdp_vsi(vsi)) + return err; + + for (i = 0; (i < vsi->num_queue_pairs) && !err; i++) + err = i40e_configure_tx_ring(vsi->xdp_rings[i]); + return err; } @@ -3237,6 +3271,7 @@ static int i40e_vsi_configure(struct i40e_vsi *vsi) **/ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi) { + bool has_xdp = i40e_enabled_xdp_vsi(vsi); struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; u16 vector; @@ -3267,28 +3302,40 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi) /* Linked list for the queuepairs assigned to this vector */ wr32(hw, I40E_PFINT_LNKLSTN(vector - 1), qp); for (q = 0; q < q_vector->num_ringpairs; q++) { + u32 nextqp = has_xdp ? qp + vsi->alloc_queue_pairs : qp; u32 val; val = I40E_QINT_RQCTL_CAUSE_ENA_MASK | - (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | - (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | - (qp << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT)| - (I40E_QUEUE_TYPE_TX - << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); + (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | + (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | + (nextqp << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | + (I40E_QUEUE_TYPE_TX << + I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT); wr32(hw, I40E_QINT_RQCTL(qp), val); + if (has_xdp) { + val = I40E_QINT_TQCTL_CAUSE_ENA_MASK | + (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | + (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | + (qp << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | + (I40E_QUEUE_TYPE_TX << + I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); + + wr32(hw, I40E_QINT_TQCTL(nextqp), val); + } + val = I40E_QINT_TQCTL_CAUSE_ENA_MASK | - (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | - (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | - ((qp+1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT)| - (I40E_QUEUE_TYPE_RX - << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); + (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | + (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | + ((qp + 1) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | + (I40E_QUEUE_TYPE_RX << + I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); /* Terminate the linked list */ if (q == (q_vector->num_ringpairs - 1)) - val |= (I40E_QUEUE_END_OF_LIST - << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); + val |= (I40E_QUEUE_END_OF_LIST << + I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); wr32(hw, I40E_QINT_TQCTL(qp), val); qp++; @@ -3342,6 +3389,7 @@ static void i40e_enable_misc_int_causes(struct i40e_pf *pf) **/ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi) { + u32 nextqp = i40e_enabled_xdp_vsi(vsi) ? vsi->alloc_queue_pairs : 0; struct i40e_q_vector *q_vector = vsi->q_vectors[0]; struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; @@ -3362,12 +3410,22 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi) wr32(hw, I40E_PFINT_LNKLST0, 0); /* Associate the queue pair to the vector and enable the queue int */ - val = I40E_QINT_RQCTL_CAUSE_ENA_MASK | - (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | + val = I40E_QINT_RQCTL_CAUSE_ENA_MASK | + (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | + (nextqp << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT)| (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); wr32(hw, I40E_QINT_RQCTL(0), val); + if (i40e_enabled_xdp_vsi(vsi)) { + val = I40E_QINT_TQCTL_CAUSE_ENA_MASK | + (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)| + (I40E_QUEUE_TYPE_TX + << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); + + wr32(hw, I40E_QINT_TQCTL(nextqp), val); + } + val = I40E_QINT_TQCTL_CAUSE_ENA_MASK | (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | (I40E_QUEUE_END_OF_LIST << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT); @@ -3534,6 +3592,9 @@ static void i40e_vsi_disable_irq(struct i40e_vsi *vsi) for (i = 0; i < vsi->num_queue_pairs; i++) { wr32(hw, I40E_QINT_TQCTL(vsi->tx_rings[i]->reg_idx), 0); wr32(hw, I40E_QINT_RQCTL(vsi->rx_rings[i]->reg_idx), 0); + if (!i40e_enabled_xdp_vsi(vsi)) + continue; + wr32(hw, I40E_QINT_TQCTL(vsi->xdp_rings[i]->reg_idx), 0); } if (pf->flags & I40E_FLAG_MSIX_ENABLED) { @@ -3836,6 +3897,16 @@ static void i40e_map_vector_to_qp(struct i40e_vsi *vsi, int v_idx, int qp_idx) q_vector->tx.ring = tx_ring; q_vector->tx.count++; + /* Place XDP Tx ring in the same q_vector ring list as regular Tx */ + if (i40e_enabled_xdp_vsi(vsi)) { + struct i40e_ring *xdp_ring = vsi->xdp_rings[qp_idx]; + + xdp_ring->q_vector = q_vector; + xdp_ring->next = q_vector->tx.ring; + q_vector->tx.ring = xdp_ring; + q_vector->tx.count++; + } + rx_ring->q_vector = q_vector; rx_ring->next = q_vector->rx.ring; q_vector->rx.ring = rx_ring; @@ -4014,6 +4085,33 @@ static void i40e_control_tx_q(struct i40e_pf *pf, int pf_q, bool enable) wr32(hw, I40E_QTX_ENA(pf_q), tx_reg); } +/** + * i40e_control_wait_tx_q - Start/stop Tx queue and wait for completion + * @seid: VSI SEID + * @pf: the PF structure + * @pf_q: the PF queue to configure + * @is_xdp: true if the queue is used for XDP + * @enable: start or stop the queue + **/ +static int i40e_control_wait_tx_q(int seid, struct i40e_pf *pf, int pf_q, + bool is_xdp, bool enable) +{ + int ret; + + i40e_control_tx_q(pf, pf_q, enable); + + /* wait for the change to finish */ + ret = i40e_pf_txq_wait(pf, pf_q, enable); + if (ret) { + dev_info(&pf->pdev->dev, + "VSI seid %d %sTx ring %d %sable timeout\n", + seid, (is_xdp ? "XDP " : ""), pf_q, + (enable ? "en" : "dis")); + } + + return ret; +} + /** * i40e_vsi_control_tx - Start or stop a VSI's rings * @vsi: the VSI being configured @@ -4026,16 +4124,20 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) pf_q = vsi->base_queue; for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) { - i40e_control_tx_q(pf, pf_q, enable); + ret = i40e_control_wait_tx_q(vsi->seid, pf, + pf_q, + false /*is xdp*/, enable); + if (ret) + break; - /* wait for the change to finish */ - ret = i40e_pf_txq_wait(pf, pf_q, enable); - if (ret) { - dev_info(&pf->pdev->dev, - "VSI seid %d Tx ring %d %sable timeout\n", - vsi->seid, pf_q, (enable ? "en" : "dis")); + if (!i40e_enabled_xdp_vsi(vsi)) + continue; + + ret = i40e_control_wait_tx_q(vsi->seid, pf, + pf_q + vsi->alloc_queue_pairs, + true /*is xdp*/, enable); + if (ret) break; - } } return ret; @@ -4547,7 +4649,21 @@ int i40e_vsi_wait_queues_disabled(struct i40e_vsi *vsi) vsi->seid, pf_q); return ret; } - /* Check and wait for the Tx queue */ + + if (!i40e_enabled_xdp_vsi(vsi)) + goto wait_rx; + + /* Check and wait for the XDP Tx queue */ + ret = i40e_pf_txq_wait(pf, pf_q + vsi->alloc_queue_pairs, + false); + if (ret) { + dev_info(&pf->pdev->dev, + "VSI seid %d XDP Tx ring %d disable timeout\n", + vsi->seid, pf_q); + return ret; + } +wait_rx: + /* Check and wait for the Rx queue */ ret = i40e_pf_rxq_wait(pf, pf_q, false); if (ret) { dev_info(&pf->pdev->dev, @@ -5466,6 +5582,8 @@ void i40e_down(struct i40e_vsi *vsi) for (i = 0; i < vsi->num_queue_pairs; i++) { i40e_clean_tx_ring(vsi->tx_rings[i]); + if (i40e_enabled_xdp_vsi(vsi)) + i40e_clean_tx_ring(vsi->xdp_rings[i]); i40e_clean_rx_ring(vsi->rx_rings[i]); } @@ -7535,15 +7653,22 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi) **/ static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi, bool alloc_qvectors) { + struct i40e_ring **next_rings; int size; int ret = 0; - /* allocate memory for both Tx and Rx ring pointers */ - size = sizeof(struct i40e_ring *) * vsi->alloc_queue_pairs * 2; + /* allocate memory for both Tx, XDP Tx and Rx ring pointers */ + size = sizeof(struct i40e_ring *) * vsi->alloc_queue_pairs * + (i40e_enabled_xdp_vsi(vsi) ? 3 : 2); vsi->tx_rings = kzalloc(size, GFP_KERNEL); if (!vsi->tx_rings) return -ENOMEM; - vsi->rx_rings = &vsi->tx_rings[vsi->alloc_queue_pairs]; + next_rings = vsi->tx_rings + vsi->alloc_queue_pairs; + if (i40e_enabled_xdp_vsi(vsi)) { + vsi->xdp_rings = next_rings; + next_rings += vsi->alloc_queue_pairs; + } + vsi->rx_rings = next_rings; if (alloc_qvectors) { /* allocate memory for q_vector pointers */ @@ -7663,6 +7788,7 @@ static void i40e_vsi_free_arrays(struct i40e_vsi *vsi, bool free_qvectors) kfree(vsi->tx_rings); vsi->tx_rings = NULL; vsi->rx_rings = NULL; + vsi->xdp_rings = NULL; } /** @@ -7746,6 +7872,8 @@ static void i40e_vsi_clear_rings(struct i40e_vsi *vsi) kfree_rcu(vsi->tx_rings[i], rcu); vsi->tx_rings[i] = NULL; vsi->rx_rings[i] = NULL; + if (vsi->xdp_rings) + vsi->xdp_rings[i] = NULL; } } } @@ -7756,43 +7884,61 @@ static void i40e_vsi_clear_rings(struct i40e_vsi *vsi) **/ static int i40e_alloc_rings(struct i40e_vsi *vsi) { - struct i40e_ring *tx_ring, *rx_ring; + int i, qpv = i40e_enabled_xdp_vsi(vsi) ? 3 : 2; struct i40e_pf *pf = vsi->back; - int i; + struct i40e_ring *ring; /* Set basic values in the rings to be used later during open() */ for (i = 0; i < vsi->alloc_queue_pairs; i++) { /* allocate space for both Tx and Rx in one shot */ - tx_ring = kzalloc(sizeof(struct i40e_ring) * 2, GFP_KERNEL); - if (!tx_ring) + ring = kcalloc(qpv, sizeof(struct i40e_ring), GFP_KERNEL); + if (!ring) goto err_out; - tx_ring->queue_index = i; - tx_ring->reg_idx = vsi->base_queue + i; - tx_ring->ring_active = false; - tx_ring->vsi = vsi; - tx_ring->netdev = vsi->netdev; - tx_ring->dev = &pf->pdev->dev; - tx_ring->count = vsi->num_desc; - tx_ring->size = 0; - tx_ring->dcb_tc = 0; + ring->queue_index = i; + ring->reg_idx = vsi->base_queue + i; + ring->ring_active = false; + ring->vsi = vsi; + ring->netdev = vsi->netdev; + ring->dev = &pf->pdev->dev; + ring->count = vsi->num_desc; + ring->size = 0; + ring->dcb_tc = 0; if (vsi->back->flags & I40E_FLAG_WB_ON_ITR_CAPABLE) - tx_ring->flags = I40E_TXR_FLAGS_WB_ON_ITR; - tx_ring->tx_itr_setting = pf->tx_itr_default; - vsi->tx_rings[i] = tx_ring; - - rx_ring = &tx_ring[1]; - rx_ring->queue_index = i; - rx_ring->reg_idx = vsi->base_queue + i; - rx_ring->ring_active = false; - rx_ring->vsi = vsi; - rx_ring->netdev = vsi->netdev; - rx_ring->dev = &pf->pdev->dev; - rx_ring->count = vsi->num_desc; - rx_ring->size = 0; - rx_ring->dcb_tc = 0; - rx_ring->rx_itr_setting = pf->rx_itr_default; - vsi->rx_rings[i] = rx_ring; + ring->flags = I40E_TXR_FLAGS_WB_ON_ITR; + ring->tx_itr_setting = pf->tx_itr_default; + vsi->tx_rings[i] = ring++; + + if (!i40e_enabled_xdp_vsi(vsi)) + goto setup_rx; + + ring->queue_index = vsi->alloc_queue_pairs + i; + ring->reg_idx = vsi->base_queue + ring->queue_index; + ring->ring_active = false; + ring->vsi = vsi; + ring->netdev = NULL; + ring->dev = &pf->pdev->dev; + ring->count = vsi->num_desc; + ring->size = 0; + ring->dcb_tc = 0; + if (vsi->back->flags & I40E_FLAG_WB_ON_ITR_CAPABLE) + ring->flags = I40E_TXR_FLAGS_WB_ON_ITR; + set_ring_xdp(ring); + ring->tx_itr_setting = pf->tx_itr_default; + vsi->xdp_rings[i] = ring++; + +setup_rx: + ring->queue_index = i; + ring->reg_idx = vsi->base_queue + i; + ring->ring_active = false; + ring->vsi = vsi; + ring->netdev = vsi->netdev; + ring->dev = &pf->pdev->dev; + ring->count = vsi->num_desc; + ring->size = 0; + ring->dcb_tc = 0; + ring->rx_itr_setting = pf->rx_itr_default; + vsi->rx_rings[i] = ring; } return 0; @@ -9998,6 +10144,7 @@ vector_setup_out: **/ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi) { + u16 alloc_queue_pairs; struct i40e_pf *pf; u8 enabled_tc; int ret; @@ -10016,11 +10163,14 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi) if (ret) goto err_vsi; - ret = i40e_get_lump(pf, pf->qp_pile, vsi->alloc_queue_pairs, vsi->idx); + alloc_queue_pairs = vsi->alloc_queue_pairs * + (i40e_enabled_xdp_vsi(vsi) ? 2 : 1); + + ret = i40e_get_lump(pf, pf->qp_pile, alloc_queue_pairs, vsi->idx); if (ret < 0) { dev_info(&pf->pdev->dev, "failed to get tracking for %d queues for VSI %d err %d\n", - vsi->alloc_queue_pairs, vsi->seid, ret); + alloc_queue_pairs, vsi->seid, ret); goto err_vsi; } vsi->base_queue = ret; @@ -10076,6 +10226,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, { struct i40e_vsi *vsi = NULL; struct i40e_veb *veb = NULL; + u16 alloc_queue_pairs; int ret, i; int v_idx; @@ -10163,12 +10314,14 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, else if (type == I40E_VSI_SRIOV) vsi->vf_id = param1; /* assign it some queues */ - ret = i40e_get_lump(pf, pf->qp_pile, vsi->alloc_queue_pairs, - vsi->idx); + alloc_queue_pairs = vsi->alloc_queue_pairs * + (i40e_enabled_xdp_vsi(vsi) ? 2 : 1); + + ret = i40e_get_lump(pf, pf->qp_pile, alloc_queue_pairs, vsi->idx); if (ret < 0) { dev_info(&pf->pdev->dev, "failed to get tracking for %d queues for VSI %d err=%d\n", - vsi->alloc_queue_pairs, vsi->seid, ret); + alloc_queue_pairs, vsi->seid, ret); goto err_vsi; } vsi->base_queue = ret; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index f744f843bc72..b936febc315a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -630,6 +630,8 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, if (tx_buffer->skb) { if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB) kfree(tx_buffer->raw_buf); + else if (ring_is_xdp(ring)) + page_frag_free(tx_buffer->raw_buf); else dev_kfree_skb_any(tx_buffer->skb); if (dma_unmap_len(tx_buffer, len)) @@ -771,8 +773,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, total_bytes += tx_buf->bytecount; total_packets += tx_buf->gso_segs; - /* free the skb */ - napi_consume_skb(tx_buf->skb, napi_budget); + /* free the skb/XDP data */ + if (ring_is_xdp(tx_ring)) + page_frag_free(tx_buf->raw_buf); + else + napi_consume_skb(tx_buf->skb, napi_budget); /* unmap skb header data */ dma_unmap_single(tx_ring->dev, @@ -848,6 +853,9 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, tx_ring->arm_wb = true; } + if (ring_is_xdp(tx_ring)) + return !!budget; + /* notify netdev of completed buffers */ netdev_tx_completed_queue(txring_txq(tx_ring), total_packets, total_bytes); @@ -1969,6 +1977,10 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring, #define I40E_XDP_PASS 0 #define I40E_XDP_CONSUMED 1 +#define I40E_XDP_TX 2 + +static int i40e_xmit_xdp_ring(struct xdp_buff *xdp, + struct i40e_ring *xdp_ring); /** * i40e_run_xdp - run an XDP program @@ -1979,6 +1991,7 @@ static struct sk_buff *i40e_run_xdp(struct i40e_ring *rx_ring, struct xdp_buff *xdp) { int result = I40E_XDP_PASS; + struct i40e_ring *xdp_ring; struct bpf_prog *xdp_prog; u32 act; @@ -1992,9 +2005,12 @@ static struct sk_buff *i40e_run_xdp(struct i40e_ring *rx_ring, switch (act) { case XDP_PASS: break; + case XDP_TX: + xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index]; + result = i40e_xmit_xdp_ring(xdp, xdp_ring); + break; default: bpf_warn_invalid_xdp_action(act); - case XDP_TX: case XDP_ABORTED: trace_xdp_exception(rx_ring->netdev, xdp_prog, act); /* fallthrough -- handle aborts by dropping packet */ @@ -2007,6 +2023,27 @@ xdp_out: return ERR_PTR(-result); } +/** + * i40e_rx_buffer_flip - adjusted rx_buffer to point to an unused region + * @rx_ring: Rx ring + * @rx_buffer: Rx buffer to adjust + * @size: Size of adjustment + **/ +static void i40e_rx_buffer_flip(struct i40e_ring *rx_ring, + struct i40e_rx_buffer *rx_buffer, + unsigned int size) +{ +#if (PAGE_SIZE < 8192) + unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2; + + rx_buffer->page_offset ^= truesize; +#else + unsigned int truesize = SKB_DATA_ALIGN(i40e_rx_offset(rx_ring) + size); + + rx_buffer->page_offset += truesize; +#endif +} + /** * i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf * @rx_ring: rx descriptor ring to transact packets on @@ -2024,7 +2061,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) unsigned int total_rx_bytes = 0, total_rx_packets = 0; struct sk_buff *skb = rx_ring->skb; u16 cleaned_count = I40E_DESC_UNUSED(rx_ring); - bool failure = false; + bool failure = false, xdp_xmit = false; while (likely(total_rx_packets < budget)) { struct i40e_rx_buffer *rx_buffer; @@ -2081,9 +2118,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) } if (IS_ERR(skb)) { + if (PTR_ERR(skb) == -I40E_XDP_TX) { + xdp_xmit = true; + i40e_rx_buffer_flip(rx_ring, rx_buffer, size); + } else { + rx_buffer->pagecnt_bias++; + } total_rx_bytes += size; total_rx_packets++; - rx_buffer->pagecnt_bias++; } else if (skb) { i40e_add_rx_frag(rx_ring, rx_buffer, skb, size); } else if (ring_uses_build_skb(rx_ring)) { @@ -2131,6 +2173,19 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) total_rx_packets++; } + if (xdp_xmit) { + struct i40e_ring *xdp_ring; + + xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index]; + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. + */ + wmb(); + + writel(xdp_ring->next_to_use, xdp_ring->tail); + } + rx_ring->skb = skb; u64_stats_update_begin(&rx_ring->syncp); @@ -3187,6 +3242,59 @@ dma_error: return -1; } +/** + * i40e_xmit_xdp_ring - transmits an XDP buffer to an XDP Tx ring + * @xdp: data to transmit + * @xdp_ring: XDP Tx ring + **/ +static int i40e_xmit_xdp_ring(struct xdp_buff *xdp, + struct i40e_ring *xdp_ring) +{ + u32 size = xdp->data_end - xdp->data; + u16 i = xdp_ring->next_to_use; + struct i40e_tx_buffer *tx_bi; + struct i40e_tx_desc *tx_desc; + dma_addr_t dma; + + if (!unlikely(I40E_DESC_UNUSED(xdp_ring))) { + xdp_ring->tx_stats.tx_busy++; + return I40E_XDP_CONSUMED; + } + + dma = dma_map_single(xdp_ring->dev, xdp->data, size, DMA_TO_DEVICE); + if (dma_mapping_error(xdp_ring->dev, dma)) + return I40E_XDP_CONSUMED; + + tx_bi = &xdp_ring->tx_bi[i]; + tx_bi->bytecount = size; + tx_bi->gso_segs = 1; + tx_bi->raw_buf = xdp->data; + + /* record length, and DMA address */ + dma_unmap_len_set(tx_bi, len, size); + dma_unmap_addr_set(tx_bi, dma, dma); + + tx_desc = I40E_TX_DESC(xdp_ring, i); + tx_desc->buffer_addr = cpu_to_le64(dma); + tx_desc->cmd_type_offset_bsz = build_ctob(I40E_TX_DESC_CMD_ICRC + | I40E_TXD_CMD, + 0, size, 0); + + /* Make certain all of the status bits have been updated + * before next_to_watch is written. + */ + smp_wmb(); + + i++; + if (i == xdp_ring->count) + i = 0; + + tx_bi->next_to_watch = tx_desc; + xdp_ring->next_to_use = i; + + return I40E_XDP_TX; +} + /** * i40e_xmit_frame_ring - Sends buffer on Tx ring * @skb: send buffer diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 31f0b162996f..b288d58313a6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -396,6 +396,7 @@ struct i40e_ring { u16 flags; #define I40E_TXR_FLAGS_WB_ON_ITR BIT(0) #define I40E_RXR_FLAGS_BUILD_SKB_ENABLED BIT(1) +#define I40E_TXR_FLAGS_XDP BIT(2) /* stats structs */ struct i40e_queue_stats stats; @@ -438,6 +439,16 @@ static inline void clear_ring_build_skb_enabled(struct i40e_ring *ring) ring->flags &= ~I40E_RXR_FLAGS_BUILD_SKB_ENABLED; } +static inline bool ring_is_xdp(struct i40e_ring *ring) +{ + return !!(ring->flags & I40E_TXR_FLAGS_XDP); +} + +static inline void set_ring_xdp(struct i40e_ring *ring) +{ + ring->flags |= I40E_TXR_FLAGS_XDP; +} + enum i40e_latency_range { I40E_LOWEST_LATENCY = 0, I40E_LOW_LATENCY = 1, -- cgit v1.2.3 From 65c7006f234c9ede887d468f595f259a5c5cc552 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 7 Jun 2017 05:43:01 -0400 Subject: i40evf: assign num_active_queues inside i40evf_alloc_queues The variable num_active_queues represents the number of active queues we have for the device. We assign this pretty early in i40evf_init_subtask. Several code locations are written with loops over the tx_rings and rx_rings structures, which don't get allocated until i40evf_alloc_queues, and which get freed by i40evf_free_queues. These call sites were written under the assumption that tx_rings and rx_rings would always be allocated at least when num_active_queues is non-zero. Lets fix this by moving the assignment into the function where we allocate queues. We'll use a temporary variable for storage so that we don't assign the value in the adapter structure until after the rings have been set up. Finally, when we free the queues, we'll clear the value to ensure that we do not loop over the rings memory that no longer exists. This resolves a possible NULL pointer dereference in i40evf_get_ethtool_stats which could occur if the VF fails to recover from a reset, and then a user requests statistics. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 3a3ca965b242..7c213a347909 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1198,6 +1198,7 @@ static void i40evf_free_queues(struct i40evf_adapter *adapter) { if (!adapter->vsi_res) return; + adapter->num_active_queues = 0; kfree(adapter->tx_rings); adapter->tx_rings = NULL; kfree(adapter->rx_rings); @@ -1214,18 +1215,22 @@ static void i40evf_free_queues(struct i40evf_adapter *adapter) **/ static int i40evf_alloc_queues(struct i40evf_adapter *adapter) { - int i; + int i, num_active_queues; + + num_active_queues = min_t(int, + adapter->vsi_res->num_queue_pairs, + (int)(num_online_cpus())); - adapter->tx_rings = kcalloc(adapter->num_active_queues, + adapter->tx_rings = kcalloc(num_active_queues, sizeof(struct i40e_ring), GFP_KERNEL); if (!adapter->tx_rings) goto err_out; - adapter->rx_rings = kcalloc(adapter->num_active_queues, + adapter->rx_rings = kcalloc(num_active_queues, sizeof(struct i40e_ring), GFP_KERNEL); if (!adapter->rx_rings) goto err_out; - for (i = 0; i < adapter->num_active_queues; i++) { + for (i = 0; i < num_active_queues; i++) { struct i40e_ring *tx_ring; struct i40e_ring *rx_ring; @@ -1247,6 +1252,8 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter) rx_ring->rx_itr_setting = (I40E_ITR_DYNAMIC | I40E_ITR_RX_DEF); } + adapter->num_active_queues = num_active_queues; + return 0; err_out: @@ -2636,9 +2643,6 @@ static void i40evf_init_task(struct work_struct *work) adapter->watchdog_timer.data = (unsigned long)adapter; mod_timer(&adapter->watchdog_timer, jiffies + 1); - adapter->num_active_queues = min_t(int, - adapter->vsi_res->num_queue_pairs, - (int)(num_online_cpus())); adapter->tx_desc_count = I40EVF_DEFAULT_TXD; adapter->rx_desc_count = I40EVF_DEFAULT_RXD; err = i40evf_init_interrupt_scheme(adapter); -- cgit v1.2.3 From 7c32b1e650752408a8dcc7a85f1776c2e24ea1da Mon Sep 17 00:00:00 2001 From: Alice Michael Date: Wed, 7 Jun 2017 05:43:02 -0400 Subject: i40e/i40evf: update WOL and I40E_AQC_ADDR_VALID_MASK flags Update a few flags related to FW interactions. Copyright updated to 2017. Signed-off-by: Alice Michael Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 4 ++-- drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 5eb04114e13f..5d5f422cbae5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Driver - * Copyright(c) 2013 - 2016 Intel Corporation. + * Copyright(c) 2013 - 2017 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -531,7 +531,7 @@ struct i40e_aqc_mac_address_read { #define I40E_AQC_PORT_ADDR_VALID 0x40 #define I40E_AQC_WOL_ADDR_VALID 0x80 #define I40E_AQC_MC_MAG_EN_VALID 0x100 -#define I40E_AQC_ADDR_VALID_MASK 0x1F0 +#define I40E_AQC_ADDR_VALID_MASK 0x3F0 u8 reserved[6]; __le32 addr_high; __le32 addr_low; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index 91d8786d386d..83e63e55c4b4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 - 2016 Intel Corporation. + * Copyright(c) 2013 - 2017 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -528,7 +528,7 @@ struct i40e_aqc_mac_address_read { #define I40E_AQC_PORT_ADDR_VALID 0x40 #define I40E_AQC_WOL_ADDR_VALID 0x80 #define I40E_AQC_MC_MAG_EN_VALID 0x100 -#define I40E_AQC_ADDR_VALID_MASK 0x1F0 +#define I40E_AQC_ADDR_VALID_MASK 0x3F0 u8 reserved[6]; __le32 addr_high; __le32 addr_low; @@ -586,6 +586,7 @@ struct i40e_aqc_set_wol_filter { __le16 cmd_flags; #define I40E_AQC_SET_WOL_FILTER 0x8000 #define I40E_AQC_SET_WOL_FILTER_NO_TCO_WOL 0x4000 +#define I40E_AQC_SET_WOL_FILTER_WOL_PRESERVE_ON_PFR 0x2000 #define I40E_AQC_SET_WOL_FILTER_ACTION_CLEAR 0 #define I40E_AQC_SET_WOL_FILTER_ACTION_SET 1 __le16 valid_flags; -- cgit v1.2.3 From 59e331e36ef934791947a616cc578bf3c62a019c Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 7 Jun 2017 05:43:03 -0400 Subject: i40e: use dev_dbg instead of dev_info when warning about missing routine When searching for the vf_capability client routine, dev_info() was used, instead of the normal dev_dbg(). This causes the message to be displayed at standard log levels which can cause administrators to worry. Avoid this by using dev_dbg instead. Copyright updated to 2017. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_client.c b/drivers/net/ethernet/intel/i40e/i40e_client.c index 36f694ccdc09..1b1e2acbd07f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_client.c +++ b/drivers/net/ethernet/intel/i40e/i40e_client.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Driver - * Copyright(c) 2013 - 2015 Intel Corporation. + * Copyright(c) 2013 - 2017 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -273,8 +273,8 @@ int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id) if (!cdev || !cdev->client) goto out; if (!cdev->client->ops || !cdev->client->ops->vf_capable) { - dev_info(&pf->pdev->dev, - "Cannot locate client instance VF capability routine\n"); + dev_dbg(&pf->pdev->dev, + "Cannot locate client instance VF capability routine\n"); goto out; } if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) -- cgit v1.2.3 From 15d23b4c361f1449d44249bea127d2bdb981aa01 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 7 Jun 2017 05:43:04 -0400 Subject: i40e: comment that udp_port must be in host byte order The firmware expects the port number passed when setting up the UDP tunnel configuration to be in Little Endian format. The i40e_aq_add_udp_tunnel command byte swaps the value from host order to Little Endian. Since commit fe0b0cd97b4f ("i40e: send correct port number to AdminQ when enabling UDP tunnels") we've correctly sent the value in host order. Let's also add a comment to the function explaining that it must be in host order, as the port numbers are commonly stored as Big Endian values. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index cbad4eba7ae7..8e082a946411 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -3614,11 +3614,15 @@ i40e_status i40e_aq_get_cee_dcb_config(struct i40e_hw *hw, /** * i40e_aq_add_udp_tunnel * @hw: pointer to the hw struct - * @udp_port: the UDP port to add + * @udp_port: the UDP port to add in Host byte order * @header_len: length of the tunneling header length in DWords * @protocol_index: protocol index type * @filter_index: pointer to filter index * @cmd_details: pointer to command details structure or NULL + * + * Note: Firmware expects the udp_port value to be in Little Endian format, + * and this function will call cpu_to_le16 to convert from Host byte order to + * Little Endian order. **/ i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw, u16 udp_port, u8 protocol_index, -- cgit v1.2.3 From 1e99854715c79b3e2ebe09d80006aaff0f5c2335 Mon Sep 17 00:00:00 2001 From: Sudheer Mogilappagari Date: Wed, 7 Jun 2017 05:43:05 -0400 Subject: i40e: Fix potential out of bound array access This is a fix for the static code analysis issue where dcbcfg->numapps could be greater than size of array (i.e dcbcfg->app[I40E_DCBX_MAX_APPS]). The fix makes sure that the array is not accessed past the size of of the array (i.e. I40E_DCBX_MAX_APPS). Copyright updated to 2017. Signed-off-by: Sudheer Mogilappagari Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_dcb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c index 0fab3a9b51d9..bf1d67e184f7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Driver - * Copyright(c) 2013 - 2014 Intel Corporation. + * Copyright(c) 2013 - 2017 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -390,6 +390,8 @@ static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv, if (!dcbcfg->numapps) return; + if (dcbcfg->numapps > I40E_DCBX_MAX_APPS) + dcbcfg->numapps = I40E_DCBX_MAX_APPS; for (i = 0; i < dcbcfg->numapps; i++) { u8 up, selector; -- cgit v1.2.3 From 68fb13a7677475e5470ef6aba585da5c609ea2cb Mon Sep 17 00:00:00 2001 From: Greg Bowers Date: Wed, 7 Jun 2017 05:43:06 -0400 Subject: i40e: Support firmware CEE DCB UP to TC map re-definition Changes parsing of FW 4.33 AQ command Get CEE DCBX OPER CFG (0x0A07). Change is required because FW now creates the oper_prio_tc nibbles reversed from those in the CEE Priority Group sub-TLV. This change will only apply to FW 4.33 as future FW versions will use a different function to parse the CEE data. Signed-off-by: Greg Bowers Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_dcb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c index bf1d67e184f7..55079fe3ed63 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c @@ -620,14 +620,17 @@ static void i40e_cee_to_dcb_v1_config( /* CEE PG data to ETS config */ dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc; + /* Note that the FW creates the oper_prio_tc nibbles reversed + * from those in the CEE Priority Group sub-TLV. + */ for (i = 0; i < 4; i++) { - tc = (u8)((cee_cfg->oper_prio_tc[i] & - I40E_CEE_PGID_PRIO_1_MASK) >> - I40E_CEE_PGID_PRIO_1_SHIFT); - dcbcfg->etscfg.prioritytable[i*2] = tc; tc = (u8)((cee_cfg->oper_prio_tc[i] & I40E_CEE_PGID_PRIO_0_MASK) >> I40E_CEE_PGID_PRIO_0_SHIFT); + dcbcfg->etscfg.prioritytable[i * 2] = tc; + tc = (u8)((cee_cfg->oper_prio_tc[i] & + I40E_CEE_PGID_PRIO_1_MASK) >> + I40E_CEE_PGID_PRIO_1_SHIFT); dcbcfg->etscfg.prioritytable[i*2 + 1] = tc; } -- cgit v1.2.3 From 83d14c595e011f96c47e5fb09ddb51902e8367aa Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 7 Jun 2017 05:43:07 -0400 Subject: i40e: Add message for unsupported MFP mode This patch adds a check and message if the device is in MFP mode as changing RSS input set is not supported in MFP mode. Signed-off-by: Carolyn Wyborny Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 9d3233c2c9cd..9692a5294fa3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2711,6 +2711,12 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) u8 flow_pctype = 0; u64 i_set, i_setc; + if (pf->flags & I40E_FLAG_MFP_ENABLED) { + dev_err(&pf->pdev->dev, + "Change of RSS hash input set is not supported when MFP mode is enabled\n"); + return -EOPNOTSUPP; + } + /* RSS does not support anything other than hashing * to queues on src and dst IPs and ports */ -- cgit v1.2.3 From 4fc8c67639575e38fff41bb4bd01c601aba930ff Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 7 Jun 2017 05:43:08 -0400 Subject: i40e: genericize the partition bandwidth control Partition bandwidth control is not in just one form of MFP (multi-function partitioning), so make the code more generic and be sure to nudge the Tx scheduler for all MFP. Copyright updated to 2017. Signed-off-by: Shannon Nelson Signed-off-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 13 +++++---- drivers/net/ethernet/intel/i40e/i40e_main.c | 41 ++++++++++++++--------------- 2 files changed, 26 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 4250ab55a9f1..76395e695007 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Driver - * Copyright(c) 2013 - 2016 Intel Corporation. + * Copyright(c) 2013 - 2017 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -516,9 +516,8 @@ struct i40e_pf { bool ptp_tx; bool ptp_rx; u16 rss_table_size; /* HW RSS table size */ - /* These are only valid in NPAR modes */ - u32 npar_max_bw; - u32 npar_min_bw; + u32 max_bw; + u32 min_bw; u32 ioremap_len; u32 fd_inv; @@ -971,9 +970,9 @@ int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr); void i40e_ptp_init(struct i40e_pf *pf); void i40e_ptp_stop(struct i40e_pf *pf); int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi); -i40e_status i40e_get_npar_bw_setting(struct i40e_pf *pf); -i40e_status i40e_set_npar_bw_setting(struct i40e_pf *pf); -i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf); +i40e_status i40e_get_partition_bw_setting(struct i40e_pf *pf); +i40e_status i40e_set_partition_bw_setting(struct i40e_pf *pf); +i40e_status i40e_commit_partition_bw_setting(struct i40e_pf *pf); void i40e_print_link_message(struct i40e_vsi *vsi, bool isup); static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7e415bb5a7dc..8d7bd85933bb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Driver - * Copyright(c) 2013 - 2016 Intel Corporation. + * Copyright(c) 2013 - 2017 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -8740,10 +8740,10 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count) } /** - * i40e_get_npar_bw_setting - Retrieve BW settings for this PF partition + * i40e_get_partition_bw_setting - Retrieve BW settings for this PF partition * @pf: board private structure **/ -i40e_status i40e_get_npar_bw_setting(struct i40e_pf *pf) +i40e_status i40e_get_partition_bw_setting(struct i40e_pf *pf) { i40e_status status; bool min_valid, max_valid; @@ -8754,27 +8754,27 @@ i40e_status i40e_get_npar_bw_setting(struct i40e_pf *pf) if (!status) { if (min_valid) - pf->npar_min_bw = min_bw; + pf->min_bw = min_bw; if (max_valid) - pf->npar_max_bw = max_bw; + pf->max_bw = max_bw; } return status; } /** - * i40e_set_npar_bw_setting - Set BW settings for this PF partition + * i40e_set_partition_bw_setting - Set BW settings for this PF partition * @pf: board private structure **/ -i40e_status i40e_set_npar_bw_setting(struct i40e_pf *pf) +i40e_status i40e_set_partition_bw_setting(struct i40e_pf *pf) { struct i40e_aqc_configure_partition_bw_data bw_data; i40e_status status; /* Set the valid bit for this PF */ bw_data.pf_valid_bits = cpu_to_le16(BIT(pf->hw.pf_id)); - bw_data.max_bw[pf->hw.pf_id] = pf->npar_max_bw & I40E_ALT_BW_VALUE_MASK; - bw_data.min_bw[pf->hw.pf_id] = pf->npar_min_bw & I40E_ALT_BW_VALUE_MASK; + bw_data.max_bw[pf->hw.pf_id] = pf->max_bw & I40E_ALT_BW_VALUE_MASK; + bw_data.min_bw[pf->hw.pf_id] = pf->min_bw & I40E_ALT_BW_VALUE_MASK; /* Set the new bandwidths */ status = i40e_aq_configure_partition_bw(&pf->hw, &bw_data, NULL); @@ -8783,10 +8783,10 @@ i40e_status i40e_set_npar_bw_setting(struct i40e_pf *pf) } /** - * i40e_commit_npar_bw_setting - Commit BW settings for this PF partition + * i40e_commit_partition_bw_setting - Commit BW settings for this PF partition * @pf: board private structure **/ -i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf) +i40e_status i40e_commit_partition_bw_setting(struct i40e_pf *pf) { /* Commit temporary BW setting to permanent NVM image */ enum i40e_admin_queue_err last_aq_status; @@ -8905,16 +8905,19 @@ static int i40e_sw_init(struct i40e_pf *pf) if (pf->hw.func_caps.npar_enable || pf->hw.func_caps.flex10_enable) { pf->flags |= I40E_FLAG_MFP_ENABLED; dev_info(&pf->pdev->dev, "MFP mode Enabled\n"); - if (i40e_get_npar_bw_setting(pf)) + if (i40e_get_partition_bw_setting(pf)) { dev_warn(&pf->pdev->dev, - "Could not get NPAR bw settings\n"); - else + "Could not get partition bw settings\n"); + } else { dev_info(&pf->pdev->dev, - "Min BW = %8.8x, Max BW = %8.8x\n", - pf->npar_min_bw, pf->npar_max_bw); + "Partition BW Min = %8.8x, Max = %8.8x\n", + pf->min_bw, pf->max_bw); + + /* nudge the Tx scheduler */ + i40e_set_partition_bw_setting(pf); + } } - /* FW/NVM is not yet fixed in this regard */ if ((pf->hw.func_caps.fd_filters_guaranteed > 0) || (pf->hw.func_caps.fd_filters_best_effort > 0)) { pf->flags |= I40E_FLAG_FD_ATR_ENABLED; @@ -9017,10 +9020,6 @@ static int i40e_sw_init(struct i40e_pf *pf) mutex_init(&pf->switch_mutex); - /* If NPAR is enabled nudge the Tx scheduler */ - if (pf->hw.func_caps.npar_enable && (!i40e_get_npar_bw_setting(pf))) - i40e_set_npar_bw_setting(pf); - sw_init_done: return err; } -- cgit v1.2.3 From 5bbb2e2045449706a6daf092e5727998e4984c0b Mon Sep 17 00:00:00 2001 From: Filip Sadowski Date: Wed, 7 Jun 2017 05:43:09 -0400 Subject: i40e: Add support for OEM firmware version This patch adds support for OEM firmware version. If OEM specific adapter is detected ethtool reports OEM product version in firmware version string instead of etrack id. Signed-off-by: Filip Sadowski Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 48 ++++++++++++++++++++--------- drivers/net/ethernet/intel/i40e/i40e_main.c | 47 ++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 76395e695007..d616f698e155 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -103,6 +103,12 @@ (I40E_AQ_PHY_DEBUG_DISABLE_LINK_FW | \ I40E_AQ_PHY_DEBUG_DISABLE_ALL_LINK_FW) +#define I40E_OEM_EETRACK_ID 0xffffffff +#define I40E_OEM_GEN_SHIFT 24 +#define I40E_OEM_SNAP_MASK 0x00ff0000 +#define I40E_OEM_SNAP_SHIFT 16 +#define I40E_OEM_RELEASE_MASK 0x0000ffff + /* The values in here are decimal coded as hex as is the case in the NVM map*/ #define I40E_CURRENT_NVM_VERSION_HI 0x2 #define I40E_CURRENT_NVM_VERSION_LO 0x40 @@ -734,22 +740,36 @@ static inline char *i40e_nvm_version_str(struct i40e_hw *hw) { static char buf[32]; u32 full_ver; - u8 ver, patch; - u16 build; full_ver = hw->nvm.oem_ver; - ver = (u8)(full_ver >> I40E_OEM_VER_SHIFT); - build = (u16)((full_ver >> I40E_OEM_VER_BUILD_SHIFT) & - I40E_OEM_VER_BUILD_MASK); - patch = (u8)(full_ver & I40E_OEM_VER_PATCH_MASK); - - snprintf(buf, sizeof(buf), - "%x.%02x 0x%x %d.%d.%d", - (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) >> - I40E_NVM_VERSION_HI_SHIFT, - (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) >> - I40E_NVM_VERSION_LO_SHIFT, - hw->nvm.eetrack, ver, build, patch); + + if (hw->nvm.eetrack == I40E_OEM_EETRACK_ID) { + u8 gen, snap; + u16 release; + + gen = (u8)(full_ver >> I40E_OEM_GEN_SHIFT); + snap = (u8)((full_ver & I40E_OEM_SNAP_MASK) >> + I40E_OEM_SNAP_SHIFT); + release = (u16)(full_ver & I40E_OEM_RELEASE_MASK); + + snprintf(buf, sizeof(buf), "%x.%x.%x", gen, snap, release); + } else { + u8 ver, patch; + u16 build; + + ver = (u8)(full_ver >> I40E_OEM_VER_SHIFT); + build = (u16)((full_ver >> I40E_OEM_VER_BUILD_SHIFT) & + I40E_OEM_VER_BUILD_MASK); + patch = (u8)(full_ver & I40E_OEM_VER_PATCH_MASK); + + snprintf(buf, sizeof(buf), + "%x.%02x 0x%x %d.%d.%d", + (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) >> + I40E_NVM_VERSION_HI_SHIFT, + (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) >> + I40E_NVM_VERSION_LO_SHIFT, + hw->nvm.eetrack, ver, build, patch); + } return buf; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 8d7bd85933bb..8af6420826d1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7107,6 +7107,51 @@ static void i40e_send_version(struct i40e_pf *pf) i40e_aq_send_driver_version(&pf->hw, &dv, NULL); } +/** + * i40e_get_oem_version - get OEM specific version information + * @hw: pointer to the hardware structure + **/ +static void i40e_get_oem_version(struct i40e_hw *hw) +{ + u16 block_offset = 0xffff; + u16 block_length = 0; + u16 capabilities = 0; + u16 gen_snap = 0; + u16 release = 0; + +#define I40E_SR_NVM_OEM_VERSION_PTR 0x1B +#define I40E_NVM_OEM_LENGTH_OFFSET 0x00 +#define I40E_NVM_OEM_CAPABILITIES_OFFSET 0x01 +#define I40E_NVM_OEM_GEN_OFFSET 0x02 +#define I40E_NVM_OEM_RELEASE_OFFSET 0x03 +#define I40E_NVM_OEM_CAPABILITIES_MASK 0x000F +#define I40E_NVM_OEM_LENGTH 3 + + /* Check if pointer to OEM version block is valid. */ + i40e_read_nvm_word(hw, I40E_SR_NVM_OEM_VERSION_PTR, &block_offset); + if (block_offset == 0xffff) + return; + + /* Check if OEM version block has correct length. */ + i40e_read_nvm_word(hw, block_offset + I40E_NVM_OEM_LENGTH_OFFSET, + &block_length); + if (block_length < I40E_NVM_OEM_LENGTH) + return; + + /* Check if OEM version format is as expected. */ + i40e_read_nvm_word(hw, block_offset + I40E_NVM_OEM_CAPABILITIES_OFFSET, + &capabilities); + if ((capabilities & I40E_NVM_OEM_CAPABILITIES_MASK) != 0) + return; + + i40e_read_nvm_word(hw, block_offset + I40E_NVM_OEM_GEN_OFFSET, + &gen_snap); + i40e_read_nvm_word(hw, block_offset + I40E_NVM_OEM_RELEASE_OFFSET, + &release); + hw->nvm.oem_ver = (gen_snap << I40E_OEM_SNAP_SHIFT) | release; + hw->nvm.eetrack = I40E_OEM_EETRACK_ID; +} + /** * i40e_reset - wait for core reset to finish reset, reset pf if corer not seen * @pf: board private structure @@ -7154,6 +7199,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); goto clear_recovery; } + i40e_get_oem_version(&pf->hw); /* re-verify the eeprom if we just had an EMP reset */ if (test_and_clear_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state)) @@ -11338,6 +11384,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_pf_reset; } + i40e_get_oem_version(hw); /* provide nvm, fw, api versions */ dev_info(&pdev->dev, "fw %d.%d.%05d api %d.%d nvm %s\n", -- cgit v1.2.3 From e588723986845457942e8a1acb1e31cf18e8eb08 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Wed, 7 Jun 2017 05:43:10 -0400 Subject: i40e: fix disabling overflow promiscuous mode There exists a bug in which the driver does not correctly exit overflow promiscuous mode. This can occur if "too many" mac filters are added, putting the driver into overflow promiscuous mode, and the filters are then removed. When the failed filters are removed, the driver reports exiting overflow promiscuous mode which is correct, however traffic continues to be received as if in promiscuous mode still. The bug occurs because the conditional for toggling promiscuous mode was set to only execute when promiscuous mode was enabled and not when it was disabled as well. This patch fixes the conditional to correctly execute when promiscuous mode is toggled and not just enabled. Without this patch, the driver is unable to correctly exit overflow promiscuous mode. Signed-off-by: Alan Brady Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 8af6420826d1..b743eca879d5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2281,9 +2281,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) i40e_aq_str(hw, hw->aq.asq_last_status)); } } - if ((changed_flags & IFF_PROMISC) || - (promisc_changed && - test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state))) { + + if ((changed_flags & IFF_PROMISC) || promisc_changed) { bool cur_promisc; cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) || -- cgit v1.2.3 From 2e5c26ea0d0843074a1b8c868aae5c828c155569 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 7 Jun 2017 05:43:11 -0400 Subject: i40e: clear only cause_ena bit When disabling interrupts, we should only be clearing the CAUSE_ENA bit, not clearing the whole register. Clearing the whole register sets the NEXTQ_IDX field to 0 instead of 0x7ff which can confuse the Firmware in some reset sequences. Signed-off-by: Shannon Nelson Signed-off-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b743eca879d5..5d82ff54c7b0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3588,14 +3588,24 @@ static void i40e_vsi_disable_irq(struct i40e_vsi *vsi) int base = vsi->base_vector; int i; + /* disable interrupt causation from each queue */ for (i = 0; i < vsi->num_queue_pairs; i++) { - wr32(hw, I40E_QINT_TQCTL(vsi->tx_rings[i]->reg_idx), 0); - wr32(hw, I40E_QINT_RQCTL(vsi->rx_rings[i]->reg_idx), 0); + u32 val; + + val = rd32(hw, I40E_QINT_TQCTL(vsi->tx_rings[i]->reg_idx)); + val &= ~I40E_QINT_TQCTL_CAUSE_ENA_MASK; + wr32(hw, I40E_QINT_TQCTL(vsi->tx_rings[i]->reg_idx), val); + + val = rd32(hw, I40E_QINT_RQCTL(vsi->rx_rings[i]->reg_idx)); + val &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK; + wr32(hw, I40E_QINT_RQCTL(vsi->rx_rings[i]->reg_idx), val); + if (!i40e_enabled_xdp_vsi(vsi)) continue; wr32(hw, I40E_QINT_TQCTL(vsi->xdp_rings[i]->reg_idx), 0); } + /* disable each interrupt */ if (pf->flags & I40E_FLAG_MSIX_ENABLED) { for (i = vsi->base_vector; i < (vsi->num_q_vectors + vsi->base_vector); i++) -- cgit v1.2.3 From 7642984b08760b8d0ff7f4cfbe524bb53eb4cec2 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Wed, 7 Jun 2017 05:43:12 -0400 Subject: i40e: Handle PE_CRITERR properly with IWARP enabled When IWARP is enabled, we weren't clearing the PE_CRITERR, just logging it and removing it from the mask. We need to do a corer to reset the PE_CRITERR register, so set the bit for that as we handle the interrupt. We should also be checking for the error against the PFINT_ICR0 register, and only need to clear it in the value getting written to PFINT_ICR0_ENA. Signed-off-by: Catherine Sullivan Signed-off-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5d82ff54c7b0..c4328b4bec95 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3684,10 +3684,10 @@ static irqreturn_t i40e_intr(int irq, void *data) pf->sw_int_count++; if ((pf->flags & I40E_FLAG_IWARP_ENABLED) && - (ena_mask & I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK)) { + (icr0 & I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK)) { ena_mask &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; - icr0 &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; dev_dbg(&pf->pdev->dev, "cleared PE_CRITERR\n"); + set_bit(__I40E_CORE_RESET_REQUESTED, pf->state); } /* only q0 is used in MSI/Legacy mode, and none are used in MSIX */ -- cgit v1.2.3 From dfc4ff644674a133878aded9a86ab36c358f3138 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 7 Jun 2017 05:43:13 -0400 Subject: i40e: don't hold RTNL lock for the entire reset We recently refactored i40e_do_reset() and its friends to be able to hold the RTNL lock only for the portions that actually need to be protected. However, a separate refactoring added several new callers of these functions during the PCIe error recovery and suspend/resume cycles. When merging the changes together, it was not noticed that we could reduce the RTNL scope by letting the reset function handle the lock itself, as previously it was not possible. Fix this by replacing these call sites to indicate that the reset function should handle its own lock. This enables multiple PFs to reset or resume simultaneously without serializing the resets via the RTNL lock. The end result is that on systems with lots of PFs and VFs the resets don't stall waiting for each other to finish. It is probable that we can also do the same for i40e_do_reset_safe, but this author did not research that change carefully enough to be confident. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c4328b4bec95..2db93d3f6d23 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6566,9 +6566,7 @@ static void i40e_reset_subtask(struct i40e_pf *pf) if (reset_flags && !test_bit(__I40E_DOWN, pf->state) && !test_bit(__I40E_CONFIG_BUSY, pf->state)) { - rtnl_lock(); - i40e_do_reset(pf, reset_flags, true); - rtnl_unlock(); + i40e_do_reset(pf, reset_flags, false); } } @@ -11906,11 +11904,8 @@ static pci_ers_result_t i40e_pci_error_detected(struct pci_dev *pdev, } /* shutdown all operations */ - if (!test_bit(__I40E_SUSPENDED, pf->state)) { - rtnl_lock(); - i40e_prep_for_reset(pf, true); - rtnl_unlock(); - } + if (!test_bit(__I40E_SUSPENDED, pf->state)) + i40e_prep_for_reset(pf, false); /* Request a slot reset */ return PCI_ERS_RESULT_NEED_RESET; @@ -11976,9 +11971,7 @@ static void i40e_pci_error_resume(struct pci_dev *pdev) if (test_bit(__I40E_SUSPENDED, pf->state)) return; - rtnl_lock(); - i40e_handle_reset_warning(pf, true); - rtnl_unlock(); + i40e_handle_reset_warning(pf, false); } /** @@ -12058,9 +12051,7 @@ static void i40e_shutdown(struct pci_dev *pdev) if (pf->wol_en && (pf->flags & I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE)) i40e_enable_mc_magic_wake(pf); - rtnl_lock(); - i40e_prep_for_reset(pf, true); - rtnl_unlock(); + i40e_prep_for_reset(pf, false); wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0)); @@ -12092,9 +12083,7 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state) if (pf->wol_en && (pf->flags & I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE)) i40e_enable_mc_magic_wake(pf); - rtnl_lock(); - i40e_prep_for_reset(pf, true); - rtnl_unlock(); + i40e_prep_for_reset(pf, false); wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0)); wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0)); @@ -12140,9 +12129,7 @@ static int i40e_resume(struct pci_dev *pdev) /* handling the reset will rebuild the device state */ if (test_and_clear_bit(__I40E_SUSPENDED, pf->state)) { clear_bit(__I40E_DOWN, pf->state); - rtnl_lock(); - i40e_reset_and_rebuild(pf, false, true); - rtnl_unlock(); + i40e_reset_and_rebuild(pf, false, false); } return 0; -- cgit v1.2.3 From e509e59477083b09e808c8c20562983d34172bb9 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 16 Jun 2017 10:37:44 +0300 Subject: ath10k: use complete VHT chan width for 160MHz workaround The ath10k firmware doesn't announce its VHT channel width capabilities in the vht_cap information from the "service ready event" arguments. The driver must therefore check whether the 160MHz short GI bit is set and whether the driver still doesn't set the bits for the 160/80+80 MHz capabilities. The two bits for the channel width are a two bit integer and not two separate bits which cannot be parsed without the knowledge of the other bit. Using IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ (b10..) as a mask for this task doesn't make any sense. The correct mask for the VHT channel width should be used instead to make this check more readable. Signed-off-by: Ben Greear [sven.eckelmann@openmesh.com: separate 160Mhz workaround cleanup, add commit message] Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 48418f91396c..51551c1ec067 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4391,7 +4391,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) * mode until that's resolved. */ if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) && - !(ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) + (ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == 0) vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; mcs_map = 0; -- cgit v1.2.3 From cc914a55006eb16f0d46188fd1f50d1fa014dbc8 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 16 Jun 2017 10:37:45 +0300 Subject: ath10k: configure rxnss_override for QCA9984 QCA9984 hardware can do 4x4 at 80Mhz, but only 2x2 at 160Mhz. First, report this to user-space by setting the max-tx-speed and max-rx-speed vht capabilities. Second, if the peer rx-speed is configured, and if we are in 160 or 80+80 mode, and the peer rx-speed matches the max speed for 2x2 or 1x1 at 160Mhz (long guard interval), then use that info to set the peer_bw_rxnss_override appropriately. Without this, a 9984 firmware will not use 2x2 ratesets when transmitting to peer (it will be stuck at 1x1), because the firmware would not have configured the rxnss_override. Signed-off-by: Ben Greear [sven.eckelmann@openmesh.com: rebase, cleanup, drop 160Mhz workaround cleanup] Signed-off-by: Sven Eckelmann [kvalo@qca.qualcomm.com: use hw_params, rename the title] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 28 ++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 6 ++++++ drivers/net/wireless/ath/ath10k/mac.c | 26 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 7 ++++++- drivers/net/wireless/ath/ath10k/wmi.h | 3 +++ 5 files changed, 69 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 700efe3f6225..51d05d6138e5 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -72,6 +72,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA9887_HW_1_0_VERSION, @@ -93,6 +95,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA6174_HW_2_1_VERSION, @@ -113,6 +117,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA6174_HW_2_1_VERSION, @@ -133,6 +139,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA6174_HW_3_0_VERSION, @@ -153,6 +161,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA6174_HW_3_2_VERSION, @@ -176,6 +186,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_cpu_freq = 176000000, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -202,6 +214,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 4, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -229,6 +243,12 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 12, + + /* Can do only 2x2 VHT160 or 80+80. 1560Mbps is 4x4 80Mhz + * or 2x2 160Mhz, long-guard-interval. + */ + .vht160_mcs_rx_highest = 1560, + .vht160_mcs_tx_highest = 1560, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -255,6 +275,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 12, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -275,6 +297,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca988x_ops, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -297,6 +321,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .target_cpu_freq = 176000000, .decap_align_bytes = 4, .spectral_bin_discard = 0, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -324,6 +350,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 4, + .vht160_mcs_rx_highest = 0, + .vht160_mcs_tx_highest = 0, }, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index be3eea429ec6..97dc1479f44e 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -535,6 +535,12 @@ struct ath10k_hw_params { /* Number of bytes to be discarded for each FFT sample */ int spectral_bin_discard; + + /* The board may have a restricted NSS for 160 or 80+80 vs what it + * can do for 80Mhz. + */ + int vht160_mcs_rx_highest; + int vht160_mcs_tx_highest; }; struct htt_rx_desc; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 51551c1ec067..3658d6d5faa4 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2519,6 +2519,20 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", sta->addr, arg->peer_max_mpdu, arg->peer_flags); + + if (arg->peer_vht_rates.rx_max_rate && + (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) { + switch (arg->peer_vht_rates.rx_max_rate) { + case 1560: + /* Must be 2x2 at 160Mhz is all it can do. */ + arg->peer_bw_rxnss_override = 2; + break; + case 780: + /* Can only do 1x1 at 160Mhz (Long Guard Interval) */ + arg->peer_bw_rxnss_override = 1; + break; + } + } } static void ath10k_peer_assoc_h_qos(struct ath10k *ar, @@ -4362,6 +4376,7 @@ static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar) static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) { struct ieee80211_sta_vht_cap vht_cap = {0}; + struct ath10k_hw_params *hw = &ar->hw_params; u16 mcs_map; u32 val; int i; @@ -4408,6 +4423,17 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); + /* If we are supporting 160Mhz or 80+80, then the NIC may be able to do + * a restricted NSS for 160 or 80+80 vs what it can do for 80Mhz. Give + * user-space a clue if that is the case. + */ + if ((vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) && + (hw->vht160_mcs_rx_highest != 0 || + hw->vht160_mcs_tx_highest != 0)) { + vht_cap.vht_mcs.rx_highest = cpu_to_le16(hw->vht160_mcs_rx_highest); + vht_cap.vht_mcs.tx_highest = cpu_to_le16(hw->vht160_mcs_tx_highest); + } + return vht_cap; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 472b42bff7bf..140718c6ae90 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -6734,7 +6734,12 @@ ath10k_wmi_peer_assoc_fill_10_4(struct ath10k *ar, void *buf, struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf; ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg); - cmd->peer_bw_rxnss_override = 0; + if (arg->peer_bw_rxnss_override) + cmd->peer_bw_rxnss_override = + __cpu_to_le32((arg->peer_bw_rxnss_override - 1) | + BIT(PEER_BW_RXNSS_OVERRIDE_OFFSET)); + else + cmd->peer_bw_rxnss_override = 0; } static int diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 1b4865a55595..baa38c8f847c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6028,6 +6028,8 @@ struct wmi_10_2_peer_assoc_complete_cmd { __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */ } __packed; +#define PEER_BW_RXNSS_OVERRIDE_OFFSET 31 + struct wmi_10_4_peer_assoc_complete_cmd { struct wmi_10_2_peer_assoc_complete_cmd cmd; __le32 peer_bw_rxnss_override; @@ -6051,6 +6053,7 @@ struct wmi_peer_assoc_complete_arg { u32 peer_vht_caps; enum wmi_phy_mode peer_phymode; struct wmi_vht_rate_set_arg peer_vht_rates; + u32 peer_bw_rxnss_override; }; struct wmi_peer_add_wds_entry_cmd { -- cgit v1.2.3 From 6824834946a61cdbb1d7e4102c3931785b4ce733 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 16 Jun 2017 10:37:46 +0300 Subject: ath10k: set rxnss_override for QCA9888 QCA9888 supports VHT80 with 2x2. But it only support 1x1 with VHT160 or VHT80+80. Inform userspace and the the QCA firmware about that limitation whenever VHT80+80 or VHT160 is configured. Signed-off-by: Sven Eckelmann [kvalo@qca.qualcomm.com: use hw_params] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 51d05d6138e5..75c5c903c8a6 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -275,8 +275,12 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, .spectral_bin_discard = 12, - .vht160_mcs_rx_highest = 0, - .vht160_mcs_tx_highest = 0, + + /* Can do only 1x1 VHT160 or 80+80. 780Mbps is 2x2 80Mhz or + * 1x1 160Mhz, long-guard-interval. + */ + .vht160_mcs_rx_highest = 780, + .vht160_mcs_tx_highest = 780, }, { .id = QCA9377_HW_1_0_DEV_VERSION, -- cgit v1.2.3 From 5b49ee9f13c7c3079117fc07ee603656c809e6c2 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Fri, 16 Jun 2017 10:38:03 +0300 Subject: wil6210: prevent platform callbacks after uninit After calling platform_ops.uninit() it is still possible to invoke platform callbacks. To prevent this, zero platform_ops right after invoking uninit. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index bf9f26563c48..a874d8dfa198 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -191,6 +191,13 @@ static int wil_platform_rop_fw_recovery(void *wil_handle) return 0; } +static void wil_platform_ops_uninit(struct wil6210_priv *wil) +{ + if (wil->platform_ops.uninit) + wil->platform_ops.uninit(wil->platform_handle); + memset(&wil->platform_ops, 0, sizeof(wil->platform_ops)); +} + static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct wil6210_priv *wil; @@ -327,8 +334,7 @@ err_release_reg: err_disable_pdev: pci_disable_device(pdev); err_plat: - if (wil->platform_ops.uninit) - wil->platform_ops.uninit(wil->platform_handle); + wil_platform_ops_uninit(wil); if_free: wil_if_free(wil); @@ -357,8 +363,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) pci_iounmap(pdev, csr); pci_release_region(pdev, 0); pci_disable_device(pdev); - if (wil->platform_ops.uninit) - wil->platform_ops.uninit(wil->platform_handle); + wil_platform_ops_uninit(wil); wil_if_free(wil); } -- cgit v1.2.3 From fe9ee51e6a43a79d9c6bf92124b4db542157aed3 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Fri, 16 Jun 2017 10:38:04 +0300 Subject: wil6210: add support for PCIe D3hot in system suspend In order to preserve the connection in suspend/resume flow, wil6210 host allows going to PCIe D3hot state in suspend, instead of performing a full wil6210 device reset. This requires the platform ability to initiate wakeup in case of RX data. To check that, a new platform API is added. In addition, add cfg80211 suspend/resume callbacks implementation. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 38 ++++ drivers/net/wireless/ath/wil6210/debugfs.c | 49 +++++ drivers/net/wireless/ath/wil6210/interrupt.c | 6 + drivers/net/wireless/ath/wil6210/main.c | 7 +- drivers/net/wireless/ath/wil6210/pcie_bus.c | 50 ++++-- drivers/net/wireless/ath/wil6210/pm.c | 228 ++++++++++++++++++++++-- drivers/net/wireless/ath/wil6210/txrx.c | 71 ++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 26 +++ drivers/net/wireless/ath/wil6210/wil_platform.h | 7 +- drivers/net/wireless/ath/wil6210/wmi.c | 143 +++++++++++++++ drivers/net/wireless/ath/wil6210/wmi.h | 27 +-- 11 files changed, 603 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 567fe43b5cf8..0b5383a62d42 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1694,6 +1694,42 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, return wil_ps_update(wil, ps_profile); } +static int wil_cfg80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + /* Setting the wakeup trigger based on wow is TBD */ + + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 0; + } + + rc = wil_can_suspend(wil, false); + if (rc) + goto out; + + wil_dbg_pm(wil, "suspending\n"); + + wil_p2p_stop_discovery(wil); + + wil_abort_scan(wil, true); + +out: + return rc; +} + +static int wil_cfg80211_resume(struct wiphy *wiphy) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + wil_dbg_pm(wil, "resuming\n"); + + return 0; +} + static const struct cfg80211_ops wil_cfg80211_ops = { .add_virtual_intf = wil_cfg80211_add_iface, .del_virtual_intf = wil_cfg80211_del_iface, @@ -1725,6 +1761,8 @@ static const struct cfg80211_ops wil_cfg80211_ops = { .start_p2p_device = wil_cfg80211_start_p2p_device, .stop_p2p_device = wil_cfg80211_stop_p2p_device, .set_power_mgmt = wil_cfg80211_set_power_mgmt, + .suspend = wil_cfg80211_suspend, + .resume = wil_cfg80211_resume, }; static void wil_wiphy_init(struct wiphy *wiphy) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 5b0f9fc66bb6..f82506d276d3 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -509,6 +509,10 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, void *buf; size_t ret; + if (test_bit(wil_status_suspending, wil_blob->wil->status) || + test_bit(wil_status_suspended, wil_blob->wil->status)) + return 0; + if (pos < 0) return -EINVAL; @@ -1600,6 +1604,49 @@ static const struct file_operations fops_fw_version = { .llseek = seq_lseek, }; +/*---------suspend_stats---------*/ +static ssize_t wil_write_suspend_stats(struct file *file, + const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + + memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); + + return len; +} + +static ssize_t wil_read_suspend_stats(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + static char text[400]; + int n; + + n = snprintf(text, sizeof(text), + "Suspend statistics:\n" + "successful suspends:%ld failed suspends:%ld\n" + "successful resumes:%ld failed resumes:%ld\n" + "rejected by host:%ld rejected by device:%ld\n", + wil->suspend_stats.successful_suspends, + wil->suspend_stats.failed_suspends, + wil->suspend_stats.successful_resumes, + wil->suspend_stats.failed_resumes, + wil->suspend_stats.rejected_by_host, + wil->suspend_stats.rejected_by_device); + + n = min_t(int, n, sizeof(text)); + + return simple_read_from_buffer(user_buf, count, ppos, text, n); +} + +static const struct file_operations fops_suspend_stats = { + .read = wil_read_suspend_stats, + .write = wil_write_suspend_stats, + .open = simple_open, +}; + /*----------------*/ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, struct dentry *dbg) @@ -1652,6 +1699,7 @@ static const struct { {"led_blink_time", 0644, &fops_led_blink_time}, {"fw_capabilities", 0444, &fops_fw_capabilities}, {"fw_version", 0444, &fops_fw_version}, + {"suspend_stats", 0644, &fops_suspend_stats}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, @@ -1698,6 +1746,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(discovery_mode, 0644, doff_u8), WIL_FIELD(chip_revision, 0444, doff_u8), WIL_FIELD(abft_len, 0644, doff_u8), + WIL_FIELD(wakeup_trigger, 0644, doff_u8), {}, }; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index cab1e5c0e374..cad8a95c4e4e 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -467,6 +467,12 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) wil6210_unmask_irq_pseudo(wil); + if (wil->suspend_resp_rcvd) { + wil_dbg_irq(wil, "set suspend_resp_comp to true\n"); + wil->suspend_resp_comp = true; + wake_up_interruptible(&wil->wq); + } + return IRQ_HANDLED; } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 32086792dfc3..daf944a71901 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -576,6 +576,9 @@ int wil_priv_init(struct wil6210_priv *wil) wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT; + wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST | + WMI_WAKEUP_TRIGGER_BCAST; + return 0; out_wmi_wq: @@ -586,8 +589,10 @@ out_wmi_wq: void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps) { - if (wil->platform_ops.bus_request) + if (wil->platform_ops.bus_request) { + wil->bus_request_kbps = kbps; wil->platform_ops.bus_request(wil->platform_handle, kbps); + } } /** diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index a874d8dfa198..d571feb2370e 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -112,8 +112,6 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only); - pdev->msi_enabled = 0; - pci_set_master(pdev); wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx"); @@ -259,7 +257,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) } rc = pci_enable_device(pdev); - if (rc) { + if (rc && pdev->msi_enabled == 0) { wil_err(wil, "pci_enable_device failed, retry with MSI only\n"); /* Work around for platforms that can't allocate IRQ: @@ -274,6 +272,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_plat; } /* rollback to err_disable_pdev */ + pci_set_power_state(pdev, PCI_D0); rc = pci_request_region(pdev, 0, WIL_NAME); if (rc) { @@ -294,6 +293,15 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil_set_capabilities(wil); wil6210_clear_irq(wil); + wil->keep_radio_on_during_sleep = + wil->platform_ops.keep_radio_on_during_sleep && + wil->platform_ops.keep_radio_on_during_sleep( + wil->platform_handle) && + test_bit(WMI_FW_CAPABILITY_D3_SUSPEND, wil->fw_capabilities); + + wil_info(wil, "keep_radio_on_during_sleep (%d)\n", + wil->keep_radio_on_during_sleep); + /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { @@ -390,15 +398,16 @@ static int wil6210_suspend(struct device *dev, bool is_runtime) goto out; rc = wil_suspend(wil, is_runtime); - if (rc) - goto out; - - /* TODO: how do I bring card in low power state? */ - - /* disable bus mastering */ - pci_clear_master(pdev); - /* PCI will call pci_save_state(pdev) and pci_prepare_to_sleep(pdev) */ + if (!rc) { + wil->suspend_stats.successful_suspends++; + /* If platform device supports keep_radio_on_during_sleep + * it will control PCIe master + */ + if (!wil->keep_radio_on_during_sleep) + /* disable bus mastering */ + pci_clear_master(pdev); + } out: return rc; } @@ -411,12 +420,21 @@ static int wil6210_resume(struct device *dev, bool is_runtime) wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); - /* allow master */ - pci_set_master(pdev); - + /* If platform device supports keep_radio_on_during_sleep it will + * control PCIe master + */ + if (!wil->keep_radio_on_during_sleep) + /* allow master */ + pci_set_master(pdev); rc = wil_resume(wil, is_runtime); - if (rc) - pci_clear_master(pdev); + if (rc) { + wil_err(wil, "device failed to resume (%d)\n", rc); + wil->suspend_stats.failed_resumes++; + if (!wil->keep_radio_on_during_sleep) + pci_clear_master(pdev); + } else { + wil->suspend_stats.successful_resumes++; + } return rc; } diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 2ae4fe85cc8c..ce1f384e7f8e 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -15,6 +15,7 @@ */ #include "wil6210.h" +#include int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) { @@ -61,20 +62,170 @@ out: wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n", is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc); + if (rc) + wil->suspend_stats.rejected_by_host++; + return rc; } -int wil_suspend(struct wil6210_priv *wil, bool is_runtime) +static int wil_resume_keep_radio_on(struct wil6210_priv *wil) { int rc = 0; - struct net_device *ndev = wil_to_ndev(wil); - wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + /* wil_status_resuming will be cleared when getting + * WMI_TRAFFIC_RESUME_EVENTID + */ + set_bit(wil_status_resuming, wil->status); + clear_bit(wil_status_suspended, wil->status); + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wil_unmask_irq(wil); - if (test_bit(wil_status_suspended, wil->status)) { - wil_dbg_pm(wil, "trying to suspend while suspended\n"); - return 0; + wil6210_bus_request(wil, wil->bus_request_kbps_pre_suspend); + + /* Send WMI resume request to the device */ + rc = wmi_resume(wil); + if (rc) { + wil_err(wil, "device failed to resume (%d), resetting\n", rc); + rc = wil_down(wil); + if (rc) { + wil_err(wil, "wil_down failed (%d)\n", rc); + goto out; + } + rc = wil_up(wil); + if (rc) { + wil_err(wil, "wil_up failed (%d)\n", rc); + goto out; + } + } + + /* Wake all queues */ + if (test_bit(wil_status_fwconnected, wil->status)) + wil_update_net_queues_bh(wil, NULL, false); + +out: + if (rc) + set_bit(wil_status_suspended, wil->status); + return rc; +} + +static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) +{ + int rc = 0; + unsigned long start, data_comp_to; + + wil_dbg_pm(wil, "suspend keep radio on\n"); + + /* Prevent handling of new tx and wmi commands */ + set_bit(wil_status_suspending, wil->status); + wil_update_net_queues_bh(wil, NULL, true); + + if (!wil_is_tx_idle(wil)) { + wil_dbg_pm(wil, "Pending TX data, reject suspend\n"); + wil->suspend_stats.rejected_by_host++; + goto reject_suspend; + } + + if (!wil_is_rx_idle(wil)) { + wil_dbg_pm(wil, "Pending RX data, reject suspend\n"); + wil->suspend_stats.rejected_by_host++; + goto reject_suspend; + } + + if (!wil_is_wmi_idle(wil)) { + wil_dbg_pm(wil, "Pending WMI events, reject suspend\n"); + wil->suspend_stats.rejected_by_host++; + goto reject_suspend; + } + + /* Send WMI suspend request to the device */ + rc = wmi_suspend(wil); + if (rc) { + wil_dbg_pm(wil, "wmi_suspend failed, reject suspend (%d)\n", + rc); + goto reject_suspend; + } + + /* Wait for completion of the pending RX packets */ + start = jiffies; + data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS); + if (test_bit(wil_status_napi_en, wil->status)) { + while (!wil_is_rx_idle(wil)) { + if (time_after(jiffies, data_comp_to)) { + if (wil_is_rx_idle(wil)) + break; + wil_err(wil, + "TO waiting for idle RX, suspend failed\n"); + wil->suspend_stats.failed_suspends++; + goto resume_after_fail; + } + wil_dbg_ratelimited(wil, "rx vring is not empty -> NAPI\n"); + napi_synchronize(&wil->napi_rx); + msleep(20); + } + } + + /* In case of pending WMI events, reject the suspend + * and resume the device. + * This can happen if the device sent the WMI events before + * approving the suspend. + */ + if (!wil_is_wmi_idle(wil)) { + wil_err(wil, "suspend failed due to pending WMI events\n"); + wil->suspend_stats.failed_suspends++; + goto resume_after_fail; + } + + wil_mask_irq(wil); + + /* Disable device reset on PERST */ + wil_s(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + + if (wil->platform_ops.suspend) { + rc = wil->platform_ops.suspend(wil->platform_handle, true); + if (rc) { + wil_err(wil, "platform device failed to suspend (%d)\n", + rc); + wil->suspend_stats.failed_suspends++; + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wil_unmask_irq(wil); + goto resume_after_fail; + } + } + + /* Save the current bus request to return to the same in resume */ + wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps; + wil6210_bus_request(wil, 0); + + set_bit(wil_status_suspended, wil->status); + clear_bit(wil_status_suspending, wil->status); + + return rc; + +resume_after_fail: + set_bit(wil_status_resuming, wil->status); + clear_bit(wil_status_suspending, wil->status); + rc = wmi_resume(wil); + /* if resume succeeded, reject the suspend */ + if (!rc) { + rc = -EBUSY; + if (test_bit(wil_status_fwconnected, wil->status)) + wil_update_net_queues_bh(wil, NULL, false); } + return rc; + +reject_suspend: + clear_bit(wil_status_suspending, wil->status); + if (test_bit(wil_status_fwconnected, wil->status)) + wil_update_net_queues_bh(wil, NULL, false); + return -EBUSY; +} + +static int wil_suspend_radio_off(struct wil6210_priv *wil) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "suspend radio off\n"); /* if netif up, hardware is alive, shut it down */ if (ndev->flags & IFF_UP) { @@ -90,7 +241,7 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) wil_disable_irq(wil); if (wil->platform_ops.suspend) { - rc = wil->platform_ops.suspend(wil->platform_handle); + rc = wil->platform_ops.suspend(wil->platform_handle, false); if (rc) { wil_enable_irq(wil); goto out; @@ -100,6 +251,50 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) set_bit(wil_status_suspended, wil->status); out: + wil_dbg_pm(wil, "suspend radio off: %d\n", rc); + + return rc; +} + +static int wil_resume_radio_off(struct wil6210_priv *wil) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); + wil_enable_irq(wil); + /* if netif up, bring hardware up + * During open(), IFF_UP set after actual device method + * invocation. This prevent recursive call to wil_up() + * wil_status_suspended will be cleared in wil_reset + */ + if (ndev->flags & IFF_UP) + rc = wil_up(wil); + else + clear_bit(wil_status_suspended, wil->status); + + return rc; +} + +int wil_suspend(struct wil6210_priv *wil, bool is_runtime) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + bool keep_radio_on = ndev->flags & IFF_UP && + wil->keep_radio_on_during_sleep; + + wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 0; + } + + if (!keep_radio_on) + rc = wil_suspend_radio_off(wil); + else + rc = wil_suspend_keep_radio_on(wil); + wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); @@ -110,29 +305,24 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) { int rc = 0; struct net_device *ndev = wil_to_ndev(wil); + bool keep_radio_on = ndev->flags & IFF_UP && + wil->keep_radio_on_during_sleep; wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); if (wil->platform_ops.resume) { - rc = wil->platform_ops.resume(wil->platform_handle); + rc = wil->platform_ops.resume(wil->platform_handle, + keep_radio_on); if (rc) { wil_err(wil, "platform_ops.resume : %d\n", rc); goto out; } } - wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); - wil_enable_irq(wil); - - /* if netif up, bring hardware up - * During open(), IFF_UP set after actual device method - * invocation. This prevent recursive call to wil_up(). - * wil_status_suspended will be cleared in wil_reset - */ - if (ndev->flags & IFF_UP) - rc = wil_up(wil); + if (keep_radio_on) + rc = wil_resume_keep_radio_on(wil); else - clear_bit(wil_status_suspended, wil->status); + rc = wil_resume_radio_off(wil); out: wil_dbg_pm(wil, "resume: %s => %d\n", diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index edab4c0a900f..34ef57c7c782 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -104,6 +104,51 @@ static inline int wil_vring_avail_high(struct vring *vring) return wil_vring_avail_tx(vring) > wil_vring_wmark_high(vring); } +/* returns true when all tx vrings are empty */ +bool wil_is_tx_idle(struct wil6210_priv *wil) +{ + int i; + unsigned long data_comp_to; + + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + struct vring *vring = &wil->vring_tx[i]; + int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; + + spin_lock(&txdata->lock); + + if (!vring->va || !txdata->enabled) { + spin_unlock(&txdata->lock); + continue; + } + + data_comp_to = jiffies + msecs_to_jiffies( + WIL_DATA_COMPLETION_TO_MS); + if (test_bit(wil_status_napi_en, wil->status)) { + while (!wil_vring_is_empty(vring)) { + if (time_after(jiffies, data_comp_to)) { + wil_dbg_pm(wil, + "TO waiting for idle tx\n"); + spin_unlock(&txdata->lock); + return false; + } + wil_dbg_ratelimited(wil, + "tx vring is not empty -> NAPI\n"); + spin_unlock(&txdata->lock); + napi_synchronize(&wil->napi_tx); + msleep(20); + spin_lock(&txdata->lock); + if (!vring->va || !txdata->enabled) + break; + } + } + + spin_unlock(&txdata->lock); + } + + return true; +} + /* wil_val_in_range - check if value in [min,max) */ static inline bool wil_val_in_range(int val, int min, int max) { @@ -406,6 +451,18 @@ static inline int wil_is_back_req(u8 fc) (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); } +bool wil_is_rx_idle(struct wil6210_priv *wil) +{ + struct vring_rx_desc *_d; + struct vring *vring = &wil->vring_rx; + + _d = (struct vring_rx_desc *)&vring->va[vring->swhead].rx; + if (_d->dma.status & RX_DMA_STATUS_DU) + return false; + + return true; +} + /** * reap 1 frame from @swhead * @@ -1812,6 +1869,15 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, spin_lock(&txdata->lock); + if (test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status) || + test_bit(wil_status_resuming, wil->status)) { + wil_dbg_txrx(wil, + "suspend/resume in progress. drop packet\n"); + spin_unlock(&txdata->lock); + return -EINVAL; + } + rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring) (wil, vring, skb); @@ -1864,6 +1930,11 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil, return; } + /* Do not wake the queues in suspend flow */ + if (test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status)) + return; + /* check wake */ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { struct vring *cur_vring = &wil->vring_tx[i]; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index ca532c777b56..35f0554b20cc 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -83,6 +83,15 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) */ #define WIL_MAX_MPDU_OVERHEAD (62) +struct wil_suspend_stats { + unsigned long successful_suspends; + unsigned long failed_suspends; + unsigned long successful_resumes; + unsigned long failed_resumes; + unsigned long rejected_by_device; + unsigned long rejected_by_host; +}; + /* Calculate MAC buffer size for the firmware. It includes all overhead, * as it will go over the air, and need to be 8 byte aligned */ @@ -290,6 +299,8 @@ enum { #define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT(1) #define ISR_MISC_FW_ERROR BIT_DMA_EP_MISC_ICR_FW_INT(3) +#define WIL_DATA_COMPLETION_TO_MS 200 + /* Hardware definitions end */ struct fw_map { u32 from; /* linker address - from, inclusive */ @@ -418,7 +429,9 @@ enum { /* for wil6210_priv.status */ wil_status_irqen, /* FIXME: interrupts enabled - for debug */ wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ wil_status_resetting, /* reset in progress */ + wil_status_suspending, /* suspend in progress */ wil_status_suspended, /* suspend completed, device is suspended */ + wil_status_resuming, /* resume in progress */ wil_status_last /* keep last */ }; @@ -683,9 +696,12 @@ struct wil6210_priv { struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; u8 discovery_mode; u8 abft_len; + u8 wakeup_trigger; + struct wil_suspend_stats suspend_stats; void *platform_handle; struct wil_platform_ops platform_ops; + bool keep_radio_on_during_sleep; struct pmc_ctx pmc; @@ -708,6 +724,11 @@ struct wil6210_priv { struct notifier_block pm_notify; #endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ + + bool suspend_resp_rcvd; + bool suspend_resp_comp; + u32 bus_request_kbps; + u32 bus_request_kbps_pre_suspend; }; #define wil_to_wiphy(i) (i->wdev->wiphy) @@ -964,6 +985,11 @@ bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_resume(struct wil6210_priv *wil, bool is_runtime); +bool wil_is_wmi_idle(struct wil6210_priv *wil); +int wmi_resume(struct wil6210_priv *wil); +int wmi_suspend(struct wil6210_priv *wil); +bool wil_is_tx_idle(struct wil6210_priv *wil); +bool wil_is_rx_idle(struct wil6210_priv *wil); int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size); void wil_fw_core_dump(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index f8c41172a3f4..5d9e4bfcb045 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,10 +33,11 @@ enum wil_platform_event { */ struct wil_platform_ops { int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */); - int (*suspend)(void *handle); - int (*resume)(void *handle); + int (*suspend)(void *handle, bool keep_device_power); + int (*resume)(void *handle, bool device_powered_on); void (*uninit)(void *handle); int (*notify)(void *handle, enum wil_platform_event evt); + bool (*keep_radio_on_during_sleep)(void *handle); }; /** diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 93902cb2e8cf..26cf722e1495 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -37,6 +37,8 @@ module_param(led_id, byte, 0444); MODULE_PARM_DESC(led_id, " 60G device led enablement. Set the led ID (0-2) to enable"); +#define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200 + /** * WMI event receiving - theory of operations * @@ -233,6 +235,16 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) return -EAGAIN; } + /* Allow sending only suspend / resume commands during susepnd flow */ + if ((test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status) || + test_bit(wil_status_resuming, wil->status)) && + ((cmdid != WMI_TRAFFIC_SUSPEND_CMDID) && + (cmdid != WMI_TRAFFIC_RESUME_CMDID))) { + wil_err(wil, "WMI: reject send_command during suspend\n"); + return -EINVAL; + } + if (!head) { wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head); return -EINVAL; @@ -862,6 +874,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) return; } + if (test_bit(wil_status_suspended, wil->status)) { + wil_err(wil, "suspended. cannot handle WMI event\n"); + return; + } + for (n = 0;; n++) { u16 len; bool q; @@ -914,6 +931,15 @@ void wmi_recv_cmd(struct wil6210_priv *wil) struct wmi_cmd_hdr *wmi = &evt->event.wmi; u16 id = le16_to_cpu(wmi->command_id); u32 tstamp = le32_to_cpu(wmi->fw_timestamp); + if (test_bit(wil_status_resuming, wil->status)) { + if (id == WMI_TRAFFIC_RESUME_EVENTID) + clear_bit(wil_status_resuming, + wil->status); + else + wil_err(wil, + "WMI evt %d while resuming\n", + id); + } spin_lock_irqsave(&wil->wmi_ev_lock, flags); if (wil->reply_id && wil->reply_id == id) { if (wil->reply_buf) { @@ -921,6 +947,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil) min(len, wil->reply_size)); immed_reply = true; } + if (id == WMI_TRAFFIC_SUSPEND_EVENTID) { + wil_dbg_wmi(wil, + "set suspend_resp_rcvd\n"); + wil->suspend_resp_rcvd = true; + } } spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); @@ -1762,6 +1793,85 @@ void wmi_event_flush(struct wil6210_priv *wil) spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); } +int wmi_suspend(struct wil6210_priv *wil) +{ + int rc; + struct wmi_traffic_suspend_cmd cmd = { + .wakeup_trigger = wil->wakeup_trigger, + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_traffic_suspend_event evt; + } __packed reply; + u32 suspend_to = WIL_WAIT_FOR_SUSPEND_RESUME_COMP; + + wil->suspend_resp_rcvd = false; + wil->suspend_resp_comp = false; + + reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED; + + rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd), + WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply), + suspend_to); + if (rc) { + wil_err(wil, "wmi_call for suspend req failed, rc=%d\n", rc); + if (rc == -ETIME) + /* wmi_call TO */ + wil->suspend_stats.rejected_by_device++; + else + wil->suspend_stats.rejected_by_host++; + goto out; + } + + wil_dbg_wmi(wil, "waiting for suspend_response_completed\n"); + + rc = wait_event_interruptible_timeout(wil->wq, + wil->suspend_resp_comp, + msecs_to_jiffies(suspend_to)); + if (rc == 0) { + wil_err(wil, "TO waiting for suspend_response_completed\n"); + if (wil->suspend_resp_rcvd) + /* Device responded but we TO due to another reason */ + wil->suspend_stats.rejected_by_host++; + else + wil->suspend_stats.rejected_by_device++; + rc = -EBUSY; + goto out; + } + + wil_dbg_wmi(wil, "suspend_response_completed rcvd\n"); + if (reply.evt.status == WMI_TRAFFIC_SUSPEND_REJECTED) { + wil_dbg_pm(wil, "device rejected the suspend\n"); + wil->suspend_stats.rejected_by_device++; + } + rc = reply.evt.status; + +out: + wil->suspend_resp_rcvd = false; + wil->suspend_resp_comp = false; + + return rc; +} + +int wmi_resume(struct wil6210_priv *wil) +{ + int rc; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_traffic_resume_event evt; + } __packed reply; + + reply.evt.status = WMI_TRAFFIC_RESUME_FAILED; + + rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0, + WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply), + WIL_WAIT_FOR_SUSPEND_RESUME_COMP); + if (rc) + return rc; + + return reply.evt.status; +} + static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id, void *d, int len) { @@ -1851,3 +1961,36 @@ void wmi_event_worker(struct work_struct *work) } wil_dbg_wmi(wil, "event_worker: Finished\n"); } + +bool wil_is_wmi_idle(struct wil6210_priv *wil) +{ + ulong flags; + struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx; + bool rc = false; + + spin_lock_irqsave(&wil->wmi_ev_lock, flags); + + /* Check if there are pending WMI events in the events queue */ + if (!list_empty(&wil->pending_wmi_ev)) { + wil_dbg_pm(wil, "Pending WMI events in queue\n"); + goto out; + } + + /* Check if there is a pending WMI call */ + if (wil->reply_id) { + wil_dbg_pm(wil, "Pending WMI call\n"); + goto out; + } + + /* Check if there are pending RX events in mbox */ + r->head = wil_r(wil, RGF_MBOX + + offsetof(struct wil6210_mbox_ctl, rx.head)); + if (r->tail != r->head) + wil_dbg_pm(wil, "Pending WMI mbox events\n"); + else + rc = true; + +out: + spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index f7f5f4f801e3..256f63c57da0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -59,6 +59,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_DISABLE_AP_SME = 4, WMI_FW_CAPABILITY_WMI_ONLY = 5, WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7, + WMI_FW_CAPABILITY_D3_SUSPEND = 8, WMI_FW_CAPABILITY_MAX, }; @@ -157,7 +158,7 @@ enum wmi_command_id { WMI_FLASH_READ_CMDID = 0x902, WMI_FLASH_WRITE_CMDID = 0x903, /* Power management */ - WMI_TRAFFIC_DEFERRAL_CMDID = 0x904, + WMI_TRAFFIC_SUSPEND_CMDID = 0x904, WMI_TRAFFIC_RESUME_CMDID = 0x905, /* P2P */ WMI_P2P_CFG_CMDID = 0x910, @@ -500,8 +501,14 @@ struct wmi_port_delete_cmd { u8 reserved[3]; } __packed; -/* WMI_TRAFFIC_DEFERRAL_CMDID */ -struct wmi_traffic_deferral_cmd { +/* WMI_TRAFFIC_SUSPEND_CMD wakeup trigger bit mask values */ +enum wmi_wakeup_trigger { + WMI_WAKEUP_TRIGGER_UCAST = 0x01, + WMI_WAKEUP_TRIGGER_BCAST = 0x02, +}; + +/* WMI_TRAFFIC_SUSPEND_CMDID */ +struct wmi_traffic_suspend_cmd { /* Bit vector: bit[0] - wake on Unicast, bit[1] - wake on Broadcast */ u8 wakeup_trigger; } __packed; @@ -1084,7 +1091,7 @@ enum wmi_event_id { WMI_FLASH_READ_DONE_EVENTID = 0x1902, WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, /* Power management */ - WMI_TRAFFIC_DEFERRAL_EVENTID = 0x1904, + WMI_TRAFFIC_SUSPEND_EVENTID = 0x1904, WMI_TRAFFIC_RESUME_EVENTID = 0x1905, /* P2P */ WMI_P2P_CFG_DONE_EVENTID = 0x1910, @@ -1926,14 +1933,14 @@ struct wmi_link_maintain_cfg_read_done_event { struct wmi_link_maintain_cfg lm_cfg; } __packed; -enum wmi_traffic_deferral_status { - WMI_TRAFFIC_DEFERRAL_APPROVED = 0x0, - WMI_TRAFFIC_DEFERRAL_REJECTED = 0x1, +enum wmi_traffic_suspend_status { + WMI_TRAFFIC_SUSPEND_APPROVED = 0x0, + WMI_TRAFFIC_SUSPEND_REJECTED = 0x1, }; -/* WMI_TRAFFIC_DEFERRAL_EVENTID */ -struct wmi_traffic_deferral_event { - /* enum wmi_traffic_deferral_status_e */ +/* WMI_TRAFFIC_SUSPEND_EVENTID */ +struct wmi_traffic_suspend_event { + /* enum wmi_traffic_suspend_status_e */ u8 status; } __packed; -- cgit v1.2.3 From a520b49ec15576784774f77c914d7020fa7aef13 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Fri, 16 Jun 2017 10:38:05 +0300 Subject: wil6210: remove ioctl interface Wireless drivers should not be using ioctl interface, hence remove this interface for wil6210 driver. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/Makefile | 1 - drivers/net/wireless/ath/wil6210/ioctl.c | 180 ----------------------------- drivers/net/wireless/ath/wil6210/netdev.c | 8 -- drivers/net/wireless/ath/wil6210/wil6210.h | 1 - 4 files changed, 190 deletions(-) delete mode 100644 drivers/net/wireless/ath/wil6210/ioctl.c (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 89bf2f9eca1d..4ae21da78e9e 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -10,7 +10,6 @@ wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o wil6210-y += rx_reorder.o -wil6210-y += ioctl.o wil6210-y += fw.o wil6210-y += pm.o wil6210-y += pmc.o diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c deleted file mode 100644 index 1c49ad8f9478..000000000000 --- a/drivers/net/wireless/ath/wil6210/ioctl.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include "wil6210.h" -#include - -#define wil_hex_dump_ioctl(prefix_str, buf, len) \ - print_hex_dump_debug("DBG[IOC ]" prefix_str, \ - DUMP_PREFIX_OFFSET, 16, 1, buf, len, true) -#define wil_dbg_ioctl(wil, fmt, arg...) wil_dbg(wil, "DBG[IOC ]" fmt, ##arg) - -static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr, - uint32_t size, enum wil_memio_op op) -{ - void __iomem *a; - u32 off; - - switch (op & wil_mmio_addr_mask) { - case wil_mmio_addr_linker: - a = wmi_buffer(wil, cpu_to_le32(addr)); - break; - case wil_mmio_addr_ahb: - a = wmi_addr(wil, addr); - break; - case wil_mmio_addr_bar: - a = wmi_addr(wil, addr + WIL6210_FW_HOST_OFF); - break; - default: - wil_err(wil, "Unsupported address mode, op = 0x%08x\n", op); - return NULL; - } - - off = a - wil->csr; - if (size >= wil->bar_size - off) { - wil_err(wil, "Requested block does not fit into memory: " - "off = 0x%08x size = 0x%08x\n", off, size); - return NULL; - } - - return a; -} - -static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data) -{ - struct wil_memio io; - void __iomem *a; - bool need_copy = false; - - if (copy_from_user(&io, data, sizeof(io))) - return -EFAULT; - - wil_dbg_ioctl(wil, "IO: addr = 0x%08x val = 0x%08x op = 0x%08x\n", - io.addr, io.val, io.op); - - a = wil_ioc_addr(wil, io.addr, sizeof(u32), io.op); - if (!a) { - wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr, - io.op); - return -EINVAL; - } - /* operation */ - switch (io.op & wil_mmio_op_mask) { - case wil_mmio_read: - io.val = readl(a); - need_copy = true; - break; - case wil_mmio_write: - writel(io.val, a); - wmb(); /* make sure write propagated to HW */ - break; - default: - wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op); - return -EINVAL; - } - - if (need_copy) { - wil_dbg_ioctl(wil, "IO done: addr = 0x%08x" - " val = 0x%08x op = 0x%08x\n", - io.addr, io.val, io.op); - if (copy_to_user(data, &io, sizeof(io))) - return -EFAULT; - } - - return 0; -} - -static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data) -{ - struct wil_memio_block io; - void *block; - void __iomem *a; - int rc = 0; - - if (copy_from_user(&io, data, sizeof(io))) - return -EFAULT; - - wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n", - io.addr, io.size, io.op); - - /* size */ - if (io.size % 4) { - wil_err(wil, "size is not multiple of 4: 0x%08x\n", io.size); - return -EINVAL; - } - - a = wil_ioc_addr(wil, io.addr, io.size, io.op); - if (!a) { - wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr, - io.op); - return -EINVAL; - } - - block = kmalloc(io.size, GFP_USER); - if (!block) - return -ENOMEM; - - /* operation */ - switch (io.op & wil_mmio_op_mask) { - case wil_mmio_read: - wil_memcpy_fromio_32(block, a, io.size); - wil_hex_dump_ioctl("Read ", block, io.size); - if (copy_to_user(io.block, block, io.size)) { - rc = -EFAULT; - goto out_free; - } - break; - case wil_mmio_write: - if (copy_from_user(block, io.block, io.size)) { - rc = -EFAULT; - goto out_free; - } - wil_memcpy_toio_32(a, block, io.size); - wmb(); /* make sure write propagated to HW */ - wil_hex_dump_ioctl("Write ", block, io.size); - break; - default: - wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op); - rc = -EINVAL; - break; - } - -out_free: - kfree(block); - return rc; -} - -int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd) -{ - int ret; - - switch (cmd) { - case WIL_IOCTL_MEMIO: - ret = wil_ioc_memio_dword(wil, data); - break; - case WIL_IOCTL_MEMIO_BLOCK: - ret = wil_ioc_memio_block(wil, data); - break; - default: - wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd); - return -ENOIOCTLCMD; - } - - wil_dbg_ioctl(wil, "ioctl(0x%04x) -> %d\n", cmd, ret); - return ret; -} diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 708facd5f667..4a6ab2d0fdf1 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -42,20 +42,12 @@ static int wil_stop(struct net_device *ndev) return wil_down(wil); } -static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) -{ - struct wil6210_priv *wil = ndev_to_wil(ndev); - - return wil_ioctl(wil, ifr->ifr_data, cmd); -} - static const struct net_device_ops wil_netdev_ops = { .ndo_open = wil_open, .ndo_stop = wil_stop, .ndo_start_xmit = wil_start_xmit, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = wil_do_ioctl, }; static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 35f0554b20cc..d085ccfc7228 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -977,7 +977,6 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil); int wil_iftype_nl2wmi(enum nl80211_iftype type); -int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd); int wil_request_firmware(struct wil6210_priv *wil, const char *name, bool load); bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); -- cgit v1.2.3 From e1d20e22dd67cc2df0c235668ed42e91e6dddd58 Mon Sep 17 00:00:00 2001 From: yuan linyu Date: Wed, 21 Jun 2017 20:04:40 +0800 Subject: idsn: fix wrong skb_put() used in my commit b952f4dff2751252db073c27c0f8a16a416a2ddc, - *(u8 *)skb_put(skb_out, 1) = (u8)(accm >> 24); \ + skb_put(skb_out, (u8)(accm >> 24)); \ it should skb_put_u8() Fixes: b952f4dff275 ("net: manual clean code which call skb_put_[data:zero])") Signed-off-by: yuan linyu Signed-off-by: David S. Miller --- drivers/isdn/i4l/isdn_bsdcomp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index 5b64a1389a7c..99012c047751 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -472,7 +472,7 @@ static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb accm |= ((ent) << bitno); \ do { \ if (skb_out && skb_tailroom(skb_out) > 0) \ - skb_put(skb_out, (u8)(accm >> 24)); \ + skb_put_u8(skb_out, (u8)(accm >> 24)); \ accm <<= 8; \ bitno += 8; \ } while (bitno <= 24); \ -- cgit v1.2.3 From 1278bd149839f2281db45a910082ba143546a148 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 16 Jun 2017 15:14:49 +0200 Subject: brcmfmac: Use separate firmware for revision 0 of the brcm43430 chip The brcm43430 chip needs different firmware files for chip revision 0 and 1. The file currently in linux-firmware is for revision 1 only. This commit makes brcmfmac request brcmfmac43430a0-sdio.bin instead of brcmfmac43430-sdio.bin for revision 0 chips. Note that the behavior for revision 1 chips is not changed, ideally those would load brcmfmac43430a1-sdio.bin, but that will break existing setups. Signed-off-by: Hans de Goede Acked-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index e03450059b06..81f9594e03c5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -612,7 +612,9 @@ BRCMF_FW_NVRAM_DEF(43340, "brcmfmac43340-sdio.bin", "brcmfmac43340-sdio.txt"); BRCMF_FW_NVRAM_DEF(4335, "brcmfmac4335-sdio.bin", "brcmfmac4335-sdio.txt"); BRCMF_FW_NVRAM_DEF(43362, "brcmfmac43362-sdio.bin", "brcmfmac43362-sdio.txt"); BRCMF_FW_NVRAM_DEF(4339, "brcmfmac4339-sdio.bin", "brcmfmac4339-sdio.txt"); -BRCMF_FW_NVRAM_DEF(43430, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt"); +BRCMF_FW_NVRAM_DEF(43430A0, "brcmfmac43430a0-sdio.bin", "brcmfmac43430a0-sdio.txt"); +/* Note the names are not postfixed with a1 for backward compatibility */ +BRCMF_FW_NVRAM_DEF(43430A1, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt"); BRCMF_FW_NVRAM_DEF(43455, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt"); BRCMF_FW_NVRAM_DEF(4354, "brcmfmac4354-sdio.bin", "brcmfmac4354-sdio.txt"); BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-sdio.bin", "brcmfmac4356-sdio.txt"); @@ -630,7 +632,8 @@ static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFF, 43430), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356) -- cgit v1.2.3 From 9da96c5e7edd38f8f7457d86efb60d0e8a07191f Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Fri, 19 May 2017 23:02:40 +0800 Subject: rtlwifi: fix REG_USTIME_TSF register definition The REG_USTIME_TSF (US Time Tuning for TSF) definition of Realtek chips should be 0x55C. Signed-off-by: Kevin Lo Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/reg.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192ce/reg.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192de/reg.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/reg.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723be/reg.h | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/reg.h index 15400ee6c04b..0c0d64aea651 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/reg.h @@ -248,7 +248,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -256,6 +255,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/reg.h index 1bb7ed35812d..9e3b58a5d2bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/reg.h @@ -227,7 +227,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -235,6 +234,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/reg.h index b354b95936e2..d4c4e76a9244 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/reg.h @@ -255,7 +255,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -263,6 +262,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/reg.h index 306059f9b9cc..30938cd9fce5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/reg.h @@ -217,7 +217,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -225,6 +224,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/reg.h index 03581d2a5da0..95c4f8e206c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/reg.h @@ -261,7 +261,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -269,6 +268,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h index ed69dbe178ff..db8bc8a2de61 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/reg.h @@ -267,7 +267,6 @@ #define REG_RD_NAV_NXT 0x0544 #define REG_NAV_PROT_LEN 0x0546 #define REG_BCN_CTRL 0x0550 -#define REG_USTIME_TSF 0x0551 #define REG_MBID_NUM 0x0552 #define REG_DUAL_TSF_RST 0x0553 #define REG_BCN_INTERVAL 0x0554 @@ -275,6 +274,7 @@ #define REG_DRVERLYINT 0x0558 #define REG_BCNDMATIM 0x0559 #define REG_ATIMWND 0x055A +#define REG_USTIME_TSF 0x055C #define REG_BCN_MAX_ERR 0x055D #define REG_RXTSF_OFFSET_CCK 0x055E #define REG_RXTSF_OFFSET_OFDM 0x055F -- cgit v1.2.3 From 421ba82c676b21f706f9e26d24c8c2596810e599 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Wed, 14 Jun 2017 19:06:56 +0800 Subject: mwifiex: fixes the unexpected be printed log by default This patch uses WARN level is not printed by default. In some cases, some boards have always met the unused log be printed as follows. ... [23193.523182] mwifiex_pcie 0000:01:00.0: mwifiex_get_cfp: cannot find cfp by band 2 & channel=13 freq=0 [23378.633684] mwifiex_pcie 0000:01:00.0: mwifiex_get_cfp: cannot find cfp by band 2 & channel=13 freq=0 Due to we used the wifi default area was US and didn't support 12~14 channels. As Frequencies: * 2412 MHz [1] (30.0 dBm) * 2417 MHz [2] (30.0 dBm) * 2422 MHz [3] (30.0 dBm) * 2427 MHz [4] (30.0 dBm) * 2432 MHz [5] (30.0 dBm) * 2437 MHz [6] (30.0 dBm) * 2442 MHz [7] (30.0 dBm) * 2447 MHz [8] (30.0 dBm) * 2452 MHz [9] (30.0 dBm) * 2457 MHz [10] (30.0 dBm) * 2462 MHz [11] (30.0 dBm) * 2467 MHz [12] (disabled) * 2472 MHz [13] (disabled) * 2484 MHz [14] (disabled) Also, as the commit 1b499cb72f26b ("mwifiex: disable channel filtering feature in firmware"), it proved to be a feature to get better scan result from overlapping channel. Even there could be AP from overlapping channel (might be 12/13/14 in this case), it will be filtered depend on reg domain rules. e.g: ... if (ch->flags & IEEE80211_CHAN_DISABLED) continue; So it should not been an ERROR, use the WARN level to instead it for now. Signed-off-by: Caesar Wang Acked-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/cfp.c b/drivers/net/wireless/marvell/mwifiex/cfp.c index 1ff22055e54f..6e2994308526 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfp.c +++ b/drivers/net/wireless/marvell/mwifiex/cfp.c @@ -350,7 +350,7 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq) } } if (i == sband->n_channels) { - mwifiex_dbg(priv->adapter, ERROR, + mwifiex_dbg(priv->adapter, WARN, "%s: cannot find cfp by band %d\t" "& channel=%d freq=%d\n", __func__, band, channel, freq); -- cgit v1.2.3 From 7c26029f87a3865c0dd9e63c306314196cc48587 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 15 Jun 2017 16:59:25 +0800 Subject: mwifiex: debugfs: remove redunant check of mwifiex_dfs_dir debugfs_remove already check mwifiex_dfs_dir, so remove it. Signed-off-by: Shawn Lin Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/debugfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index ae2b69db5994..f6f105a7d3ff 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -1046,6 +1046,5 @@ mwifiex_debugfs_init(void) void mwifiex_debugfs_remove(void) { - if (mwifiex_dfs_dir) - debugfs_remove(mwifiex_dfs_dir); + debugfs_remove(mwifiex_dfs_dir); } -- cgit v1.2.3 From d2d1831723df183bcb37e008ec707ee3c3fddcef Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Fri, 16 Jun 2017 20:05:36 +0530 Subject: rsi: add usb RS9113 chipset support usb device id and vendor id for RS9113 chipset are included. So it can be used through usb interface. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index f5de6934f7ec..bcd7f454ef30 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -666,6 +666,7 @@ static const struct usb_device_id rsi_dev_table[] = { { USB_DEVICE(0x041B, 0x0301) }, { USB_DEVICE(0x041B, 0x0201) }, { USB_DEVICE(0x041B, 0x9330) }, + { USB_DEVICE(0x1618, 0x9113) }, { /* Blank */}, }; -- cgit v1.2.3 From 4833c953fd25389403102cede312d211248c3350 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 16 Jun 2017 20:05:37 +0530 Subject: rsi: use enum for FSM states Currently macros are used for FSM states. We will replace it with enum so that new state can be added easily without worrying about macro value. Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_main.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index ea4fc223cea7..833c66f53480 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -31,13 +31,15 @@ #define FSM_ZONE BIT(7) /* For State Machine Msgs */ #define ISR_ZONE BIT(8) /* For Interrupt Msgs */ -#define FSM_CARD_NOT_READY 0 -#define FSM_BOOT_PARAMS_SENT 1 -#define FSM_EEPROM_READ_MAC_ADDR 2 -#define FSM_RESET_MAC_SENT 3 -#define FSM_RADIO_CAPS_SENT 4 -#define FSM_BB_RF_PROG_SENT 5 -#define FSM_MAC_INIT_DONE 6 +enum RSI_FSM_STATES { + FSM_CARD_NOT_READY, + FSM_BOOT_PARAMS_SENT, + FSM_EEPROM_READ_MAC_ADDR, + FSM_RESET_MAC_SENT, + FSM_RADIO_CAPS_SENT, + FSM_BB_RF_PROG_SENT, + FSM_MAC_INIT_DONE +}; extern u32 rsi_zone_enabled; extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); -- cgit v1.2.3 From 015e367494c1d5f5d6405eae5419f7932e96139a Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Fri, 16 Jun 2017 20:05:38 +0530 Subject: rsi: Register interrupt handler before firmware load Before firmware load, sometimes false interrupts are received. System hang is observed if interrupt handler is not registered to receive these interrupts. Hence interrupt handler registration is moved before firmware load. We will drop these false interrupts as these are not from the device. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 1 + drivers/net/wireless/rsi/rsi_91x_sdio.c | 21 +++++++++++---------- drivers/net/wireless/rsi/rsi_main.h | 1 + 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 3d24e8ed74df..94e074d8bd4f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -733,6 +733,7 @@ int rsi_hal_device_init(struct rsi_hw *adapter) default: return -EINVAL; } + common->fsm_state = FSM_CARD_NOT_READY; return 0; } diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 2ef844adacf3..e5ea99bb2dd8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -139,6 +139,8 @@ static void rsi_handle_interrupt(struct sdio_func *function) { struct rsi_hw *adapter = sdio_get_drvdata(function); + if (adapter->priv->fsm_state == FSM_FW_NOT_LOADED) + return; sdio_release_host(function); rsi_interrupt_handler(adapter); sdio_claim_host(function); @@ -908,10 +910,19 @@ static int rsi_probe(struct sdio_func *pfunction, __func__); goto fail; } + sdio_claim_host(pfunction); + if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { + rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); + sdio_release_host(pfunction); + goto fail; + } + sdio_release_host(pfunction); + rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); if (rsi_hal_device_init(adapter)) { rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); sdio_claim_host(pfunction); + sdio_release_irq(pfunction); sdio_disable_func(pfunction); sdio_release_host(pfunction); goto fail; @@ -923,16 +934,6 @@ static int rsi_probe(struct sdio_func *pfunction, return -EIO; } - sdio_claim_host(pfunction); - if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { - rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); - sdio_release_host(pfunction); - goto fail; - } - - sdio_release_host(pfunction); - rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); - return 0; fail: rsi_91x_deinit(adapter); diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 833c66f53480..74ae0ac113ee 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -32,6 +32,7 @@ #define ISR_ZONE BIT(8) /* For Interrupt Msgs */ enum RSI_FSM_STATES { + FSM_FW_NOT_LOADED, FSM_CARD_NOT_READY, FSM_BOOT_PARAMS_SENT, FSM_EEPROM_READ_MAC_ADDR, -- cgit v1.2.3 From 61f2a6fcaab186e06dd8f2df0e40bc90b5111e60 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Fri, 16 Jun 2017 20:05:39 +0530 Subject: rsi: receive path enhancement for RS9113 RS9113 chipset supports Coex feature. Initial frame exchanges during device initialization happens on coex queue. This patch adds the handling for coex queue. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_main.c | 9 ++++++++- drivers/net/wireless/rsi/rsi_main.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index 8810862ae826..f1cde0ca81f9 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -123,9 +123,16 @@ int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len) queueno = rsi_get_queueno(frame_desc, offset); length = rsi_get_length(frame_desc, offset); - extended_desc = rsi_get_extended_desc(frame_desc, offset); + + /* Extended descriptor is valid for WLAN queues only */ + if (queueno == RSI_WIFI_DATA_Q || queueno == RSI_WIFI_MGMT_Q) + extended_desc = rsi_get_extended_desc(frame_desc, + offset); switch (queueno) { + case RSI_COEX_Q: + rsi_mgmt_pkt_recv(common, (frame_desc + offset)); + break; case RSI_WIFI_DATA_Q: skb = rsi_prepare_skb(common, (frame_desc + offset), diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index 74ae0ac113ee..f12e5d94bec2 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -63,6 +63,7 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define MAX_CONTINUOUS_VI_PKTS 4 /* Queue information */ +#define RSI_COEX_Q 0x0 #define RSI_WIFI_MGMT_Q 0x4 #define RSI_WIFI_DATA_Q 0x5 #define IEEE80211_MGMT_FRAME 0x00 -- cgit v1.2.3 From 1b1bed016509d08e6d286a90b9e37898d0774ef3 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Fri, 16 Jun 2017 20:05:40 +0530 Subject: rsi: configure new boot parameters to device Boot parameters are changed in new firmware. Also three new sdio sleep parameters are added for ultra low power save. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 20 +++++++++++++------- drivers/net/wireless/rsi/rsi_boot_params.h | 15 +++++++++------ 2 files changed, 22 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index fac87c06357b..b2950aa93c9c 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -45,10 +45,10 @@ static struct bootup_params boot_params_20 = { } }, .switch_clk_g = { - .switch_clk_info = cpu_to_le16(BIT(3)), - .bbp_lmac_clk_reg_val = cpu_to_le16(0x121), - .umac_clock_reg_config = 0x0, - .qspi_uart_clock_reg_config = 0x0 + .switch_clk_info = cpu_to_le16(0xb), + .bbp_lmac_clk_reg_val = cpu_to_le16(0x111), + .umac_clock_reg_config = cpu_to_le16(0x48), + .qspi_uart_clock_reg_config = cpu_to_le16(0x1211) } }, { @@ -106,7 +106,10 @@ static struct bootup_params boot_params_20 = { .wdt_prog_value = 0x0, .wdt_soc_rst_delay = 0x0, .dcdc_operation_mode = 0x0, - .soc_reset_wait_cnt = 0x0 + .soc_reset_wait_cnt = 0x0, + .waiting_time_at_fresh_sleep = 0x0, + .max_threshold_to_avoid_sleep = 0x0, + .beacon_resedue_alg_en = 0, }; static struct bootup_params boot_params_40 = { @@ -139,7 +142,7 @@ static struct bootup_params boot_params_40 = { .switch_clk_info = cpu_to_le16(0x09), .bbp_lmac_clk_reg_val = cpu_to_le16(0x1121), .umac_clock_reg_config = cpu_to_le16(0x48), - .qspi_uart_clock_reg_config = 0x0 + .qspi_uart_clock_reg_config = cpu_to_le16(0x1211) } }, { @@ -197,7 +200,10 @@ static struct bootup_params boot_params_40 = { .wdt_prog_value = 0x0, .wdt_soc_rst_delay = 0x0, .dcdc_operation_mode = 0x0, - .soc_reset_wait_cnt = 0x0 + .soc_reset_wait_cnt = 0x0, + .waiting_time_at_fresh_sleep = 0x0, + .max_threshold_to_avoid_sleep = 0x0, + .beacon_resedue_alg_en = 0, }; static u16 mcs[] = {13, 26, 39, 52, 78, 104, 117, 130}; diff --git a/drivers/net/wireless/rsi/rsi_boot_params.h b/drivers/net/wireless/rsi/rsi_boot_params.h index 5e2721f7909c..238ee96434ec 100644 --- a/drivers/net/wireless/rsi/rsi_boot_params.h +++ b/drivers/net/wireless/rsi/rsi_boot_params.h @@ -24,19 +24,19 @@ #define WIFI_AFEPLL_CONFIGS BIT(7) #define WIFI_SWITCH_CLK_CONFIGS BIT(8) -#define TA_PLL_M_VAL_20 8 -#define TA_PLL_N_VAL_20 1 +#define TA_PLL_M_VAL_20 9 +#define TA_PLL_N_VAL_20 0 #define TA_PLL_P_VAL_20 4 #define PLL960_M_VAL_20 0x14 #define PLL960_N_VAL_20 0 #define PLL960_P_VAL_20 5 -#define UMAC_CLK_40MHZ 40 +#define UMAC_CLK_40MHZ 80 -#define TA_PLL_M_VAL_40 46 -#define TA_PLL_N_VAL_40 3 -#define TA_PLL_P_VAL_40 3 +#define TA_PLL_M_VAL_40 9 +#define TA_PLL_N_VAL_40 0 +#define TA_PLL_P_VAL_40 4 #define PLL960_M_VAL_40 0x14 #define PLL960_N_VAL_40 0 @@ -122,5 +122,8 @@ struct bootup_params { /* dcdc modes configs */ __le32 dcdc_operation_mode; __le32 soc_reset_wait_cnt; + __le32 waiting_time_at_fresh_sleep; + __le32 max_threshold_to_avoid_sleep; + u8 beacon_resedue_alg_en; } __packed; #endif -- cgit v1.2.3 From 9920322ccd8e04733335d8f9c1ad34c2aae34951 Mon Sep 17 00:00:00 2001 From: Prameela Rani Garnepudi Date: Fri, 16 Jun 2017 20:12:05 +0530 Subject: rsi: add tx frame for common device configuration After successful loading of firmware, a CARD READY indication is received by host. Common device configuration parameters are sent to the device after this. It includes information like device operating mode (Wi-Fi alone or BT coex), power save related parameters, GPIO information etc. As device supports BT coex, this frame is send in COEX queue initially. Based on the operating mode, CARD READY indication is received from each protocol module in firmware i.e. WLAN, BT. Signed-off-by: Prameela Rani Garnepudi Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_hal.c | 3 +- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 100 ++++++++++++++++++++++++++++---- drivers/net/wireless/rsi/rsi_hal.h | 3 + drivers/net/wireless/rsi/rsi_main.h | 10 +++- drivers/net/wireless/rsi/rsi_mgmt.h | 76 ++++++++++++++++++++++++ 5 files changed, 178 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 94e074d8bd4f..c2303599c12e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -718,7 +718,8 @@ int rsi_hal_device_init(struct rsi_hw *adapter) { struct rsi_common *common = adapter->priv; - common->coex_mode = 1; + common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE; + common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE; adapter->device_model = RSI_DEV_9113; switch (adapter->device_model) { diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index b2950aa93c9c..83ce81a1d685 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -224,6 +224,12 @@ static void rsi_set_default_parameters(struct rsi_common *common) common->fsm_state = FSM_CARD_NOT_READY; common->iface_down = true; common->endpoint = EP_2GHZ_20MHZ; + common->driver_mode = 1; /* End to end mode */ + common->lp_ps_handshake_mode = 0; /* Default no handShake mode*/ + common->ulp_ps_handshake_mode = 2; /* Default PKT handShake mode*/ + common->rf_power_val = 0; /* Default 1.9V */ + common->wlan_rf_power_mode = 0; + common->obm_ant_sel_val = 2; } /** @@ -761,6 +767,53 @@ int rsi_hal_load_key(struct rsi_common *common, return rsi_send_internal_mgmt_frame(common, skb); } +/* + * This function sends the common device configuration parameters to device. + * This frame includes the useful information to make device works on + * specific operating mode. + */ +static int rsi_send_common_dev_params(struct rsi_common *common) +{ + struct sk_buff *skb; + u16 frame_len; + struct rsi_config_vals *dev_cfgs; + + frame_len = sizeof(struct rsi_config_vals); + + rsi_dbg(MGMT_TX_ZONE, "Sending common device config params\n"); + skb = dev_alloc_skb(frame_len); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Unable to allocate skb\n", __func__); + return -ENOMEM; + } + + memset(skb->data, 0, frame_len); + + dev_cfgs = (struct rsi_config_vals *)skb->data; + memset(dev_cfgs, 0, (sizeof(struct rsi_config_vals))); + + rsi_set_len_qno(&dev_cfgs->len_qno, (frame_len - FRAME_DESC_SZ), + RSI_COEX_Q); + dev_cfgs->pkt_type = COMMON_DEV_CONFIG; + + dev_cfgs->lp_ps_handshake = common->lp_ps_handshake_mode; + dev_cfgs->ulp_ps_handshake = common->ulp_ps_handshake_mode; + + dev_cfgs->unused_ulp_gpio = RSI_UNUSED_ULP_GPIO_BITMAP; + dev_cfgs->unused_soc_gpio_bitmap = + cpu_to_le32(RSI_UNUSED_SOC_GPIO_BITMAP); + + dev_cfgs->opermode = common->oper_mode; + dev_cfgs->wlan_rf_pwr_mode = common->wlan_rf_power_mode; + dev_cfgs->driver_mode = common->driver_mode; + dev_cfgs->region_code = NL80211_DFS_FCC; + dev_cfgs->antenna_sel_val = common->obm_ant_sel_val; + + skb_put(skb, frame_len); + + return rsi_send_internal_mgmt_frame(common, skb); +} + /* * rsi_load_bootup_params() - This function send bootup params to the firmware. * @common: Pointer to the driver private structure. @@ -1493,6 +1546,40 @@ out: return -EINVAL; } +static int rsi_handle_card_ready(struct rsi_common *common, u8 *msg) +{ + switch (common->fsm_state) { + case FSM_CARD_NOT_READY: + rsi_dbg(INIT_ZONE, "Card ready indication from Common HAL\n"); + rsi_set_default_parameters(common); + if (rsi_send_common_dev_params(common) < 0) + return -EINVAL; + common->fsm_state = FSM_COMMON_DEV_PARAMS_SENT; + break; + case FSM_COMMON_DEV_PARAMS_SENT: + rsi_dbg(INIT_ZONE, "Card ready indication from WLAN HAL\n"); + + /* Get usb buffer status register address */ + common->priv->usb_buffer_status_reg = *(u32 *)&msg[8]; + rsi_dbg(INFO_ZONE, "USB buffer status register = %x\n", + common->priv->usb_buffer_status_reg); + + if (rsi_load_bootup_params(common)) { + common->fsm_state = FSM_CARD_NOT_READY; + return -EINVAL; + } + common->fsm_state = FSM_BOOT_PARAMS_SENT; + break; + default: + rsi_dbg(ERR_ZONE, + "%s: card ready indication in invalid state %d.\n", + __func__, common->fsm_state); + return -EINVAL; + } + + return 0; +} + /** * rsi_mgmt_pkt_recv() - This function processes the management packets * recieved from the hardware. @@ -1505,7 +1592,6 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg) { s32 msg_len = (le16_to_cpu(*(__le16 *)&msg[0]) & 0x0fff); u16 msg_type = (msg[2]); - int ret; rsi_dbg(FSM_ZONE, "%s: Msg Len: %d, Msg Type: %4x\n", __func__, msg_len, msg_type); @@ -1515,17 +1601,7 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg) } else if (msg_type == CARD_READY_IND) { rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n", __func__); - if (common->fsm_state == FSM_CARD_NOT_READY) { - rsi_set_default_parameters(common); - - ret = rsi_load_bootup_params(common); - if (ret) - return ret; - else - common->fsm_state = FSM_BOOT_PARAMS_SENT; - } else { - return -EINVAL; - } + return rsi_handle_card_ready(common, msg); } else if (msg_type == TX_STATUS_IND) { if (msg[15] == PROBEREQ_CONFIRM) { common->mgmt_q_block = false; diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h index b95200df5b0f..902dc540849c 100644 --- a/drivers/net/wireless/rsi/rsi_hal.h +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -63,6 +63,9 @@ #define COMMAN_HAL_WAIT_FOR_CARD_READY 1 +#define RSI_DEV_OPMODE_WIFI_ALONE 1 +#define RSI_DEV_COEX_MODE_WIFI_ALONE 1 + struct bl_header { __le32 flags; __le32 image_no; diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index f12e5d94bec2..f3985250b593 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -34,6 +34,7 @@ enum RSI_FSM_STATES { FSM_FW_NOT_LOADED, FSM_CARD_NOT_READY, + FSM_COMMON_DEV_PARAMS_SENT, FSM_BOOT_PARAMS_SENT, FSM_EEPROM_READ_MAC_ADDR, FSM_RESET_MAC_SENT, @@ -210,8 +211,14 @@ struct rsi_common { struct cqm_info cqm_info; bool hw_data_qs_blocked; + u8 driver_mode; u8 coex_mode; - + u16 oper_mode; + u8 lp_ps_handshake_mode; + u8 ulp_ps_handshake_mode; + u8 rf_power_val; + u8 wlan_rf_power_mode; + u8 obm_ant_sel_val; int tx_power; u8 ant_in_use; }; @@ -234,6 +241,7 @@ struct rsi_hw { enum host_intf rsi_host_intf; u16 block_size; + u32 usb_buffer_status_reg; #ifdef CONFIG_RSI_DEBUGFS struct rsi_debugfs *dfsentry; u8 num_debugfs_entries; diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index dfbf7a50269b..dcb6db728cbd 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -205,6 +205,7 @@ enum cmd_frame_type { CW_MODE_REQ, PER_CMD_PKT, ANT_SEL_FRAME = 0x20, + COMMON_DEV_CONFIG = 0x28, RADIO_PARAMS_UPDATE = 0x29 }; @@ -282,6 +283,76 @@ struct rsi_radio_caps { __le16 preamble_type; } __packed; +/* ULP GPIO flags */ +#define RSI_GPIO_MOTION_SENSOR_ULP_WAKEUP BIT(0) +#define RSI_GPIO_SLEEP_IND_FROM_DEVICE BIT(1) +#define RSI_GPIO_2_ULP BIT(2) +#define RSI_GPIO_PUSH_BUTTON_ULP_WAKEUP BIT(3) + +/* SOC GPIO flags */ +#define RSI_GPIO_0_PSPI_CSN_0 BIT(0) +#define RSI_GPIO_1_PSPI_CSN_1 BIT(1) +#define RSI_GPIO_2_HOST_WAKEUP_INTR BIT(2) +#define RSI_GPIO_3_PSPI_DATA_0 BIT(3) +#define RSI_GPIO_4_PSPI_DATA_1 BIT(4) +#define RSI_GPIO_5_PSPI_DATA_2 BIT(5) +#define RSI_GPIO_6_PSPI_DATA_3 BIT(6) +#define RSI_GPIO_7_I2C_SCL BIT(7) +#define RSI_GPIO_8_I2C_SDA BIT(8) +#define RSI_GPIO_9_UART1_RX BIT(9) +#define RSI_GPIO_10_UART1_TX BIT(10) +#define RSI_GPIO_11_UART1_RTS_I2S_CLK BIT(11) +#define RSI_GPIO_12_UART1_CTS_I2S_WS BIT(12) +#define RSI_GPIO_13_DBG_UART_RX_I2S_DIN BIT(13) +#define RSI_GPIO_14_DBG_UART_RX_I2S_DOUT BIT(14) +#define RSI_GPIO_15_LP_WAKEUP_BOOT_BYPASS BIT(15) +#define RSI_GPIO_16_LED_0 BIT(16) +#define RSI_GPIO_17_BTCOEX_WLAN_ACT_EXT_ANT_SEL BIT(17) +#define RSI_GPIO_18_BTCOEX_BT_PRIO_EXT_ANT_SEL BIT(18) +#define RSI_GPIO_19_BTCOEX_BT_ACT_EXT_ON_OFF BIT(19) +#define RSI_GPIO_20_RF_RESET BIT(20) +#define RSI_GPIO_21_SLEEP_IND_FROM_DEVICE BIT(21) + +#define RSI_UNUSED_SOC_GPIO_BITMAP (RSI_GPIO_9_UART1_RX | \ + RSI_GPIO_10_UART1_TX | \ + RSI_GPIO_11_UART1_RTS_I2S_CLK | \ + RSI_GPIO_12_UART1_CTS_I2S_WS | \ + RSI_GPIO_13_DBG_UART_RX_I2S_DIN | \ + RSI_GPIO_14_DBG_UART_RX_I2S_DOUT | \ + RSI_GPIO_15_LP_WAKEUP_BOOT_BYPASS | \ + RSI_GPIO_17_BTCOEX_WLAN_ACT_EXT_ANT_SEL | \ + RSI_GPIO_18_BTCOEX_BT_PRIO_EXT_ANT_SEL | \ + RSI_GPIO_19_BTCOEX_BT_ACT_EXT_ON_OFF | \ + RSI_GPIO_21_SLEEP_IND_FROM_DEVICE) + +#define RSI_UNUSED_ULP_GPIO_BITMAP (RSI_GPIO_MOTION_SENSOR_ULP_WAKEUP | \ + RSI_GPIO_SLEEP_IND_FROM_DEVICE | \ + RSI_GPIO_2_ULP | \ + RSI_GPIO_PUSH_BUTTON_ULP_WAKEUP); +struct rsi_config_vals { + __le16 len_qno; + u8 pkt_type; + u8 misc_flags; + __le16 reserved1[6]; + u8 lp_ps_handshake; + u8 ulp_ps_handshake; + u8 sleep_config_params; /* 0 for no handshake, + * 1 for GPIO based handshake, + * 2 packet handshake + */ + u8 unused_ulp_gpio; + __le32 unused_soc_gpio_bitmap; + u8 ext_pa_or_bt_coex_en; + u8 opermode; + u8 wlan_rf_pwr_mode; + u8 bt_rf_pwr_mode; + u8 zigbee_rf_pwr_mode; + u8 driver_mode; + u8 region_code; + u8 antenna_sel_val; + u8 reserved2[16]; +} __packed; + static inline u32 rsi_get_queueno(u8 *addr, u16 offset) { return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12; @@ -307,6 +378,11 @@ static inline u8 rsi_get_channel(u8 *addr) return *(char *)(addr + 15); } +static inline void rsi_set_len_qno(__le16 *addr, u16 len, u8 qno) +{ + *addr = cpu_to_le16(len | ((qno & 7) << 12)); +} + int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg); int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode, u8 vap_status); -- cgit v1.2.3 From 87d8a9f35202c20411eaada9f4aced6e1781fb51 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:39 -0500 Subject: rtlwifi: btcoex: call bind to setup btcoex New btcoex add a function 'bind' to connect adapter, so we should call it during initializing. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 1 + drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 32cbbd0595ed..21d39973feab 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -600,6 +600,7 @@ bool halbtc_is_wifi_uplink(struct rtl_priv *adapter); extern struct btc_coexist gl_bt_coexist; bool exhalbtc_initlize_variables(void); +bool exhalbtc_bind_bt_coex_withadapter(void *adapter); void exhalbtc_init_hw_config(struct btc_coexist *btcoexist); void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist); void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index 3ab0cfe26513..7d4a94efe260 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -50,6 +50,7 @@ static struct rtl_btc_ops rtl_btc_operation = { void rtl_btc_init_variables(struct rtl_priv *rtlpriv) { exhalbtc_initlize_variables(); + exhalbtc_bind_bt_coex_withadapter(rtlpriv); } void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv) -- cgit v1.2.3 From 43f5644a90a030d6b801d5a6eb1e00914b816cae Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:40 -0500 Subject: rtlwifi: btcoex: set correct interface type and parameter. This commit fixies two problems. The first one is interface types (e.g. PCI) that are used to switch antenna, and the second is to add wifi_only parameter to give correct state. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 18 +++++++++++++----- .../wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 2 +- .../net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index f00d6e6ab69b..451039ac7b0a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -803,8 +803,6 @@ bool exhalbtc_initlize_variables(void) halbtc_dbg_init(); - btcoexist->chip_interface = BTC_INTF_UNKNOWN; - btcoexist->btc_read_1byte = halbtc_read_1byte; btcoexist->btc_write_1byte = halbtc_write_1byte; btcoexist->btc_write_1byte_bitmask = halbtc_bitmask_write_1byte; @@ -843,6 +841,18 @@ bool exhalbtc_bind_bt_coex_withadapter(void *adapter) if (btcoexist->binded) return false; + switch (rtlpriv->rtlhal.interface) { + case INTF_PCI: + btcoexist->chip_interface = BTC_INTF_PCI; + break; + case INTF_USB: + btcoexist->chip_interface = BTC_INTF_USB; + break; + default: + btcoexist->chip_interface = BTC_INTF_UNKNOWN; + break; + } + btcoexist->binded = true; btcoexist->statistics.cnt_bind++; @@ -912,10 +922,8 @@ void exhalbtc_pre_load_firmware(struct btc_coexist *btcoexist) } } -void exhalbtc_init_hw_config(struct btc_coexist *btcoexist) +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist, bool wifi_only) { - bool wifi_only = true; - if (!halbtc_is_bt_coexist_available(btcoexist)) return; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 21d39973feab..f9b87c12db09 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -601,7 +601,7 @@ extern struct btc_coexist gl_bt_coexist; bool exhalbtc_initlize_variables(void); bool exhalbtc_bind_bt_coex_withadapter(void *adapter); -void exhalbtc_init_hw_config(struct btc_coexist *btcoexist); +void exhalbtc_init_hw_config(struct btc_coexist *btcoexist, bool wifi_only); void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist); void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type); void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index 7d4a94efe260..9635c1478875 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -68,7 +68,7 @@ void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%s, bt_exist is %d\n", __func__, bt_exist); - exhalbtc_init_hw_config(&gl_bt_coexist); + exhalbtc_init_hw_config(&gl_bt_coexist, !bt_exist); exhalbtc_init_coex_dm(&gl_bt_coexist); } -- cgit v1.2.3 From f95d95a7cd5514549dcf6ba754f0ee834cce3e1f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:41 -0500 Subject: rtlwifi: btcoex: rtl8723be: fix ant_sel not work To make ant_sel work, we should call power_on_setting to set antenna correctly. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c | 3 +++ drivers/net/wireless/realtek/rtlwifi/wifi.h | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index a79f936bb394..0ce2900722f4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -846,6 +846,9 @@ static bool _rtl8723be_init_mac(struct ieee80211_hw *hw) return false; } + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_power_on_setting(rtlpriv); + bytetmp = rtl_read_byte(rtlpriv, REG_MULTI_FUNC_CTRL); rtl_write_byte(rtlpriv, REG_MULTI_FUNC_CTRL, bytetmp | BIT(3)); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index c0d2601bc55f..31fcf43e24c1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2534,6 +2534,7 @@ struct bt_coexist_info { struct rtl_btc_ops { void (*btc_init_variables) (struct rtl_priv *rtlpriv); void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv); + void (*btc_power_on_setting)(struct rtl_priv *rtlpriv); void (*btc_init_hw_config) (struct rtl_priv *rtlpriv); void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type); void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type); -- cgit v1.2.3 From e332e2a29448065bbdf298d4dc21ed4cc3bebb3f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:42 -0500 Subject: rtlwifi: Correct power save capability while init mac80211 Since the driver itself will enter power saving mode dynamically according to the traffic, we set hw capability SUPPORTS_PS and SUPPORTS_DYNAMIC_PS in case of fwctrl_lps. The process IEEE80211_CONF_CHANGE_PS in op_config is used by SW-LPS only, so we add constraints to avoid errors. Signed-off-by: Ping-Ke Shih Signed-off-by: vincent_fann Signed-off-by: shaofu Signed-off-by: Larry Finger Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 4 ++++ drivers/net/wireless/realtek/rtlwifi/core.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index bdc379178e87..6415ec03008f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -405,6 +405,10 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, PS_NULLFUNC_STACK); } + if (rtlpriv->psc.fwctrl_lps) { + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + } hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index a4f8e326a2bc..5053d8c73e29 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -629,7 +629,8 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) } /*For LPS */ - if (changed & IEEE80211_CONF_CHANGE_PS) { + if ((changed & IEEE80211_CONF_CHANGE_PS) && + rtlpriv->psc.swctrl_lps && !rtlpriv->psc.fwctrl_lps) { cancel_delayed_work(&rtlpriv->works.ps_work); cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); if (conf->flags & IEEE80211_CONF_PS) { -- cgit v1.2.3 From 79b64ed7a6b26fd896a8c0ba410e9704decf9c1f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:43 -0500 Subject: rtlwifi: extend debug_comp to u64 The number of debugging conditions now exceeds the capabilities of a 32-bit word. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/debug.c | 2 +- drivers/net/wireless/realtek/rtlwifi/debug.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/debug.c b/drivers/net/wireless/realtek/rtlwifi/debug.c index 7ecac6116d5d..38fef6dbb44b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/debug.c +++ b/drivers/net/wireless/realtek/rtlwifi/debug.c @@ -27,7 +27,7 @@ #include #ifdef CONFIG_RTLWIFI_DEBUG -void _rtl_dbg_trace(struct rtl_priv *rtlpriv, int comp, int level, +void _rtl_dbg_trace(struct rtl_priv *rtlpriv, u64 comp, int level, const char *fmt, ...) { if (unlikely((comp & rtlpriv->cfg->mod_params->debug_mask) && diff --git a/drivers/net/wireless/realtek/rtlwifi/debug.h b/drivers/net/wireless/realtek/rtlwifi/debug.h index bf5339f1c1bc..a4006104ee8a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/debug.h +++ b/drivers/net/wireless/realtek/rtlwifi/debug.h @@ -169,7 +169,7 @@ enum dbgp_flag_e { struct rtl_priv; __printf(4, 5) -void _rtl_dbg_trace(struct rtl_priv *rtlpriv, int comp, int level, +void _rtl_dbg_trace(struct rtl_priv *rtlpriv, u64 comp, int level, const char *fmt, ...); __printf(4, 5) @@ -198,7 +198,7 @@ struct rtl_priv; __printf(4, 5) static inline void RT_TRACE(struct rtl_priv *rtlpriv, - int comp, int level, + u64 comp, int level, const char *fmt, ...) { } @@ -211,7 +211,7 @@ static inline void RTPRINT(struct rtl_priv *rtlpriv, } static inline void RT_PRINT_DATA(struct rtl_priv *rtlpriv, - int comp, int level, + u64 comp, int level, const char *titlestring, const void *hexdata, size_t hexdatalen) { -- cgit v1.2.3 From 8479580b5267b40c4072ee57519f18f2b0359fbd Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:44 -0500 Subject: rtlwifi: Add TX report and disable key to force wait until report acked. When using EAPOL to do a PTK rekey, there is a possible race condition. When msg 3/4 is received, the supplicant will send msg 4/4 and install the new key immediately; however, the driver must make sure that msg 4/4 is sent before installing the new key. We use TX report to ensure it is sent. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 128 +++++++++++++++++++-- drivers/net/wireless/realtek/rtlwifi/base.h | 13 +++ drivers/net/wireless/realtek/rtlwifi/core.c | 2 + drivers/net/wireless/realtek/rtlwifi/debug.h | 1 + .../net/wireless/realtek/rtlwifi/rtl8188ee/sw.c | 2 +- .../net/wireless/realtek/rtlwifi/rtl8192ee/fw.c | 1 + .../net/wireless/realtek/rtlwifi/rtl8192ee/sw.c | 2 +- .../net/wireless/realtek/rtlwifi/rtl8192ee/trx.c | 3 + .../net/wireless/realtek/rtlwifi/rtl8192ee/trx.h | 14 +-- .../net/wireless/realtek/rtlwifi/rtl8723be/fw.c | 1 + .../net/wireless/realtek/rtlwifi/rtl8723be/trx.c | 3 + .../net/wireless/realtek/rtlwifi/rtl8723be/trx.h | 16 ++- .../net/wireless/realtek/rtlwifi/rtl8821ae/fw.c | 3 + .../net/wireless/realtek/rtlwifi/rtl8821ae/trx.c | 3 + .../net/wireless/realtek/rtlwifi/rtl8821ae/trx.h | 17 ++- drivers/net/wireless/realtek/rtlwifi/wifi.h | 10 ++ 16 files changed, 194 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 6415ec03008f..f9d249f85177 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1114,6 +1114,9 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, if (txrate) tcb_desc->hw_rate = txrate->hw_value; + if (rtl_is_tx_report_skb(hw, skb)) + tcb_desc->use_spe_rpt = 1; + if (ieee80211_is_data(fc)) { /* *we set data rate INX 0 @@ -1322,21 +1325,13 @@ static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc) ppsc->last_delaylps_stamp_jiffies = jiffies; } -/*should call before software enc*/ -u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, - bool is_enc) +static const u8 *rtl_skb_ether_type_ptr(struct ieee80211_hw *hw, + struct sk_buff *skb, bool is_enc) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - __le16 fc = rtl_get_fc(skb); - u16 ether_type; u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); u8 encrypt_header_len = 0; u8 offset; - const struct iphdr *ip; - - if (!ieee80211_is_data(fc)) - goto end; switch (rtlpriv->sec.pairwise_enc_algorithm) { case WEP40_ENCRYPTION: @@ -1356,10 +1351,29 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, offset = mac_hdr_len + SNAP_SIZE; if (is_enc) offset += encrypt_header_len; - ether_type = be16_to_cpup((__be16 *)(skb->data + offset)); + + return skb->data + offset; +} + +/*should call before software enc*/ +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, + bool is_enc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + __le16 fc = rtl_get_fc(skb); + u16 ether_type; + const u8 *ether_type_ptr; + const struct iphdr *ip; + + if (!ieee80211_is_data(fc)) + goto end; + + ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, is_enc); + ether_type = be16_to_cpup((__be16 *)ether_type_ptr); if (ETH_P_IP == ether_type) { - ip = (struct iphdr *)((u8 *)skb->data + offset + + ip = (struct iphdr *)((u8 *)ether_type_ptr + PROTOC_TYPE_SIZE); if (IPPROTO_UDP == ip->protocol) { struct udphdr *udp = (struct udphdr *)((u8 *)ip + @@ -1409,6 +1423,96 @@ end: } EXPORT_SYMBOL_GPL(rtl_is_special_data); +bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + u16 ether_type; + const u8 *ether_type_ptr; + + ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, true); + ether_type = be16_to_cpup((__be16 *)ether_type_ptr); + + /* EAPOL */ + if (ether_type == ETH_P_PAE) + return true; + + return false; +} + +static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + u16 sn; + + sn = atomic_inc_return(&tx_report->sn) & 0x0FFF; + + tx_report->last_sent_sn = sn; + tx_report->last_sent_time = jiffies; + + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG, + "Send TX-Report sn=0x%X\n", sn); + + return sn; +} + +void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, + struct ieee80211_hw *hw) +{ + if (ptcb_desc->use_spe_rpt) { + u16 sn = rtl_get_tx_report_sn(hw); + + SET_TX_DESC_SPE_RPT(pdesc, 1); + SET_TX_DESC_SW_DEFINE(pdesc, sn); + } +} +EXPORT_SYMBOL_GPL(rtl_get_tx_report); + +void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + u16 sn; + + sn = ((tmp_buf[7] & 0x0F) << 8) | tmp_buf[6]; + + tx_report->last_recv_sn = sn; + + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_DMESG, + "Recv TX-Report st=0x%02X sn=0x%X retry=0x%X\n", + tmp_buf[0], sn, tmp_buf[2]); +} +EXPORT_SYMBOL_GPL(rtl_tx_report_handler); + +bool rtl_check_tx_report_acked(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tx_report *tx_report = &rtlpriv->tx_report; + + if (tx_report->last_sent_sn == tx_report->last_recv_sn) + return true; + + if (time_before(tx_report->last_sent_time + 3 * HZ, jiffies)) { + RT_TRACE(rtlpriv, COMP_TX_REPORT, DBG_WARNING, + "Check TX-Report timeout!!\n"); + return true; /* 3 sec. (timeout) seen as acked */ + } + + return false; +} + +void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int i; + + for (i = 0; i < wait_ms; i++) { + if (rtl_check_tx_report_acked(hw)) + break; + usleep_range(1000, 2000); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + "Wait 1ms (%d/%d) to disable key.\n", i, wait_ms); + } +} /********************************************************* * * functions called by core.c diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index 02ff0c5624a7..a619fc92a9c0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -107,6 +107,11 @@ enum ap_peer { SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \ (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val)))) +#define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val) +#define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val) + int rtl_init_core(struct ieee80211_hw *hw); void rtl_deinit_core(struct ieee80211_hw *hw); void rtl_init_rx_config(struct ieee80211_hw *hw); @@ -123,6 +128,14 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, bool is_enc); +bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_get_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc, + struct ieee80211_hw *hw); +void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, + u8 c2h_cmd_len); +bool rtl_check_tx_report_acked(struct ieee80211_hw *hw); +void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms); + void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb); int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 5053d8c73e29..1a53a95d373b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1671,6 +1671,8 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, *so don't use rtl_cam_reset_all_entry *or clear all entry here. */ + rtl_wait_tx_report_acked(hw, 500); /* wait 500ms for TX ack */ + rtl_cam_delete_one_entry(hw, mac_addr, key_idx); break; default: diff --git a/drivers/net/wireless/realtek/rtlwifi/debug.h b/drivers/net/wireless/realtek/rtlwifi/debug.h index a4006104ee8a..947718001457 100644 --- a/drivers/net/wireless/realtek/rtlwifi/debug.h +++ b/drivers/net/wireless/realtek/rtlwifi/debug.h @@ -105,6 +105,7 @@ #define COMP_EASY_CONCURRENT COMP_USB /* reuse of this bit is OK */ #define COMP_BT_COEXIST BIT(30) #define COMP_IQK BIT(31) +#define COMP_TX_REPORT BIT_ULL(32) /*-------------------------------------------------------------- Define the rt_print components diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 7661cfa53032..774e72058d24 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -270,7 +270,7 @@ static struct rtl_hal_ops rtl8188ee_hal_ops = { static struct rtl_mod_params rtl88ee_mod_params = { .sw_crypto = false, - .inactiveps = false, + .inactiveps = true, .swctrl_lps = false, .fwctrl_lps = false, .msi_support = true, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index 1f42ce5f8f27..c6c9c66abe1f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -843,6 +843,7 @@ void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, case C2H_8192E_TX_REPORT: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE , "[C2H], C2H_8723BE_TX_REPORT!\n"); + rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); break; case C2H_8192E_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 48820bc497d8..eaa503b7c4b4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -253,7 +253,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { static struct rtl_mod_params rtl92ee_mod_params = { .sw_crypto = false, - .inactiveps = false, + .inactiveps = true, .swctrl_lps = false, .fwctrl_lps = true, .msi_support = true, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index b1864bb07c2c..55f238a2a310 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -731,6 +731,9 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); } + /* tx report */ + rtl_get_tx_report(ptcb_desc, pdesc, hw); + SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); if (ieee80211_is_mgmt(fc)) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h index 8053d1b12ec4..b0105c529010 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h @@ -159,7 +159,7 @@ #define SET_TX_DESC_NULL_0(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 1, __val) #define SET_TX_DESC_NULL_1(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 15, 1, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 15, 1, __val) #define SET_TX_DESC_BK(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val) #define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ @@ -167,7 +167,7 @@ #define SET_TX_DESC_RAW(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) #define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val) #define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) #define SET_TX_DESC_BT_NULL(__pdesc, __val) \ @@ -252,15 +252,15 @@ /* Dword 6 */ #define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 12, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val) #define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 3, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 16, 3, __val) #define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 19, 3, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 19, 3, __val) #define SET_TX_DESC_ANTSEL_C(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 22, 3, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 22, 3, __val) #define SET_TX_DESC_ANTSEL_D(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+24, 25, 3, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 25, 3, __val) /* Dword 7 */ #define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c index 4fc839b1d601..a7e31af2b5de 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c @@ -662,6 +662,7 @@ void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw, case C2H_8723B_TX_REPORT: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_TX_REPORT!\n"); + rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); break; case C2H_8723B_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c index 3c6ce994c6aa..0e8944119652 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c @@ -488,6 +488,9 @@ void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); } + /* tx report */ + rtl_get_tx_report(ptcb_desc, pdesc, hw); + /* ptcb_desc->use_driver_rate = true; */ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); if (ptcb_desc->hw_rate > DESC92C_RATEMCS0) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h index 8a9fe41ac15b..0274659f48ed 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h @@ -107,7 +107,7 @@ #define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val) #define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 14, 2, __val) #define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val) #define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ @@ -115,7 +115,7 @@ #define SET_TX_DESC_RAW(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) #define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val) #define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) #define SET_TX_DESC_BT_INT(__pdesc, __val) \ @@ -187,6 +187,18 @@ #define SET_TX_DESC_RTS_SC(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val) +#define SET_TX_DESC_MBSSID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 12, 4, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 16, 3, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 19, 3, __val) +#define SET_TX_DESC_ANTSEL_C(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 22, 3, __val) +#define SET_TX_DESC_ANTSEL_D(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 25, 3, __val) #define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index 73350103b736..5eeb0b1cafa4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -1873,6 +1873,9 @@ void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, case C2H_8812_DBG: RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "[C2H], C2H_8812_DBG!!\n"); break; + case C2H_8812_TX_REPORT: + rtl_tx_report_handler(hw, tmp_buf, c2h_cmd_len); + break; case C2H_8812_RA_RPT: rtl8821ae_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c index 03665e82065f..749818929e8f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c @@ -740,6 +740,9 @@ void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); } + /* tx report */ + rtl_get_tx_report(ptcb_desc, pdesc, hw); + /* ptcb_desc->use_driver_rate = true; */ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); if (ptcb_desc->hw_rate > DESC_RATEMCS0) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h index b6f3c564b8d1..9843a616dcec 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h @@ -114,7 +114,7 @@ #define SET_TX_DESC_RAW(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) #define SET_TX_DESC_SPE_RPT(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 8, 19, 1, __val) #define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) #define SET_TX_DESC_BT_INT(__pdesc, __val) \ @@ -185,8 +185,21 @@ #define SET_TX_DESC_RTS_SC(__pdesc, __val) \ SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_SW_DEFINE(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 0, 12, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 16, 3, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 19, 3, __val) +#define SET_TX_DESC_ANTSEL_C(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 22, 3, __val) +#define SET_TX_DESC_ANTSEL_D(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE((__pdesc) + 24, 25, 3, __val) +#define SET_TX_DESC_MBSSID(__pdesc, __val) \ + SET_BITS_TO_LE_4BYTE(i(__pdesc) + 24, 12, 4, __val) + #define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ - SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val) + SET_BITS_TO_LE_4BYTE((__pdesc) + 28, 0, 16, __val) #define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \ LE_BITS_TO_4BYTE(__pdesc+28, 0, 16) diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 31fcf43e24c1..8f3035b41e6f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1886,6 +1886,13 @@ struct rtl_efuse { u8 channel_plan; }; +struct rtl_tx_report { + atomic_t sn; + u16 last_sent_sn; + unsigned long last_sent_time; + u16 last_recv_sn; +}; + struct rtl_ps_ctl { bool pwrdomain_protect; bool in_powersavemode; @@ -2075,6 +2082,8 @@ struct rtl_tcb_desc { u8 use_driver_rate:1; u8 disable_ratefallback:1; + u8 use_spe_rpt:1; + u8 ratr_index; u8 mac_id; u8 hw_rate; @@ -2589,6 +2598,7 @@ struct rtl_priv { struct rtl_security sec; struct rtl_efuse efuse; struct rtl_led_ctl ledctl; + struct rtl_tx_report tx_report; struct rtl_ps_ctl psc; struct rate_adaptive ra; -- cgit v1.2.3 From 5b757ba757d4bcb0ea0ece2630b1d162dbd06d3e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:45 -0500 Subject: rtlwifi: Revise special packet notification to be readable format. We extend types of special packets to a enumeration from boolean value. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index f9d249f85177..897ec3cfa8c8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1313,14 +1313,15 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) } EXPORT_SYMBOL_GPL(rtl_action_proc); -static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc) +static void setup_special_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc, + int type) { struct ieee80211_hw *hw = rtlpriv->hw; rtlpriv->ra.is_special_data = true; if (rtlpriv->cfg->ops->get_btc_status()) rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( - rtlpriv, 1); + rtlpriv, type); rtl_lps_leave(hw); ppsc->last_delaylps_stamp_jiffies = jiffies; } @@ -1390,13 +1391,15 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, (is_tx) ? "Tx" : "Rx"); if (is_tx) - setup_arp_tx(rtlpriv, ppsc); + setup_special_tx(rtlpriv, ppsc, + PACKET_DHCP); + return true; } } } else if (ETH_P_ARP == ether_type) { if (is_tx) - setup_arp_tx(rtlpriv, ppsc); + setup_special_tx(rtlpriv, ppsc, PACKET_ARP); return true; } else if (ETH_P_PAE == ether_type) { @@ -1407,6 +1410,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, rtlpriv->ra.is_special_data = true; rtl_lps_leave(hw); ppsc->last_delaylps_stamp_jiffies = jiffies; + + setup_special_tx(rtlpriv, ppsc, PACKET_EAPOL); } return true; -- cgit v1.2.3 From 54685f9c7af17e2430deb289b4f255ea0dec42c9 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:46 -0500 Subject: rtlwifi: Add btcoex record_pwr_mode Add btcoex record pwr mode to control LPS's parameters and share time with BT. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c | 13 +++++++++++++ drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h | 1 + drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c | 7 ++++++- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h | 4 +++- drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c | 8 +++++++- drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h | 4 +++- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c | 7 ++++++- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h | 4 +++- drivers/net/wireless/realtek/rtlwifi/wifi.h | 1 + 9 files changed, 43 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index 9635c1478875..3b976dab712f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -45,8 +45,21 @@ static struct rtl_btc_ops rtl_btc_operation = { .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo, .btc_is_bt_disabled = rtl_btc_is_bt_disabled, .btc_special_packet_notify = rtl_btc_special_packet_notify, + .btc_record_pwr_mode = rtl_btc_record_pwr_mode, }; +void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len) +{ + u8 safe_len; + + safe_len = sizeof(gl_bt_coexist.pwr_mode_val); + + if (safe_len > len) + safe_len = len; + + memcpy(gl_bt_coexist.pwr_mode_val, buf, safe_len); +} + void rtl_btc_init_variables(struct rtl_priv *rtlpriv) { exhalbtc_initlize_variables(); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h index fff5117e1c4e..9eeb4fdeaec1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h @@ -43,6 +43,7 @@ bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv); bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type); +void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len); struct rtl_btc_ops *rtl_btc_get_ops_pointer(void); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index c6c9c66abe1f..c11f1c04f871 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -422,7 +422,8 @@ void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 u1_h2c_set_pwrmode[H2C_92E_PWEMODE_LENGTH] = { 0 }; struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 rlbm , power_state = 0; + u8 rlbm, power_state = 0, byte5 = 0x40; + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , "FW LPS mode = %d\n", mode); @@ -440,10 +441,14 @@ void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) else power_state |= FW_PWR_STATE_RF_OFF; SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", u1_h2c_set_pwrmode, H2C_92E_PWEMODE_LENGTH); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_record_pwr_mode(rtlpriv, u1_h2c_set_pwrmode, + H2C_92E_PWEMODE_LENGTH); rtl92ee_fill_h2c_cmd(hw, H2C_92E_SETPWRMODE, H2C_92E_PWEMODE_LENGTH, u1_h2c_set_pwrmode); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h index af8271967a88..b770f722daa6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.h @@ -37,7 +37,7 @@ #define USE_OLD_WOWLAN_DEBUG_FW 0 #define H2C_92E_RSVDPAGE_LOC_LEN 5 -#define H2C_92E_PWEMODE_LENGTH 5 +#define H2C_92E_PWEMODE_LENGTH 7 #define H2C_92E_JOINBSSRPT_LENGTH 1 #define H2C_92E_AP_OFFLOAD_LENGTH 3 #define H2C_92E_WOWLAN_LENGTH 3 @@ -154,6 +154,8 @@ enum rtl8192e_c2h_evt { SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __val) #define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__cmd, __val) \ SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BYTE5(__cmd, __val) \ + SET_BITS_TO_LE_1BYTE((__cmd) + 5, 0, 8, __val) #define GET_92E_H2CCMD_PWRMODE_PARM_MODE(__cmd) \ LE_BITS_TO_1BYTE(__cmd, 0, 8) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c index a7e31af2b5de..488376becdcb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c @@ -240,7 +240,9 @@ void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 u1_h2c_set_pwrmode[H2C_PWEMODE_LENGTH] = { 0 }; struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 rlbm, power_state = 0; + u8 rlbm, power_state = 0, byte5 = 0x40; + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); @@ -257,10 +259,14 @@ void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) else power_state |= FW_PWR_STATE_RF_OFF; SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", u1_h2c_set_pwrmode, H2C_PWEMODE_LENGTH); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_record_pwr_mode(rtlpriv, u1_h2c_set_pwrmode, + H2C_PWEMODE_LENGTH); rtl8723be_fill_h2c_cmd(hw, H2C_8723B_SETPWRMODE, H2C_PWEMODE_LENGTH, u1_h2c_set_pwrmode); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h index 2482b3bc2bfa..2de4edb62bca 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.h @@ -33,7 +33,7 @@ #define USE_OLD_WOWLAN_DEBUG_FW 0 -#define H2C_PWEMODE_LENGTH 5 +#define H2C_PWEMODE_LENGTH 7 /* Fw PS state for RPWM. *BIT[2:0] = HW state @@ -125,6 +125,8 @@ enum rtl8723b_c2h_evt { SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val) #define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__ph2ccmd, __val) \ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+4, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BYTE5(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd) + 5, 0, 8, __val) #define GET_88E_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd) \ LE_BITS_TO_1BYTE(__ph2ccmd, 0, 8) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index 5eeb0b1cafa4..96b8a9bdaf55 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -489,7 +489,8 @@ void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 u1_h2c_set_pwrmode[H2C_8821AE_PWEMODE_LENGTH] = { 0 }; struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 rlbm, power_state = 0; + u8 rlbm, power_state = 0, byte5 = 0x40; + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); @@ -508,10 +509,14 @@ void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) power_state |= FW_PWR_STATE_RF_OFF; SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); + SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n", u1_h2c_set_pwrmode, H2C_8821AE_PWEMODE_LENGTH); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_record_pwr_mode(rtlpriv, u1_h2c_set_pwrmode, + H2C_8821AE_PWEMODE_LENGTH); rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_SETPWRMODE, H2C_8821AE_PWEMODE_LENGTH, u1_h2c_set_pwrmode); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h index 98d871afd92a..32d46d7128f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.h @@ -42,7 +42,7 @@ #define USE_OLD_WOWLAN_DEBUG_FW 0 #define H2C_8821AE_RSVDPAGE_LOC_LEN 5 -#define H2C_8821AE_PWEMODE_LENGTH 5 +#define H2C_8821AE_PWEMODE_LENGTH 7 #define H2C_8821AE_JOINBSSRPT_LENGTH 1 #define H2C_8821AE_AP_OFFLOAD_LENGTH 3 #define H2C_8821AE_WOWLAN_LENGTH 3 @@ -218,6 +218,8 @@ enum rtl8821a_h2c_cmd { SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value) #define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__cmd, __value) \ SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __value) +#define SET_H2CCMD_PWRMODE_PARM_BYTE5(__cmd, __value) \ + SET_BITS_TO_LE_1BYTE((__cmd) + 5, 0, 8, __value) #define GET_8821AE_H2CCMD_PWRMODE_PARM_MODE(__cmd) \ LE_BITS_TO_1BYTE(__cmd, 0, 8) diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 8f3035b41e6f..41ebdb9d3627 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2560,6 +2560,7 @@ struct rtl_btc_ops { bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv); void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv, u8 pkt_type); + void (*btc_record_pwr_mode)(struct rtl_priv *rtlpriv, u8 *buf, u8 len); }; struct proxim { -- cgit v1.2.3 From 2635664e6e4a691ad6f1e0c13a04623cac3794da Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:47 -0500 Subject: rtlwifi: Add rx ampdu cfg for btcoexist. If RX ampdu is too long, BT will have less time. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 27 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtlwifi/base.h | 1 + .../realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 16 +++++++++++-- .../wireless/realtek/rtlwifi/btcoexist/rtl_btc.c | 12 ++++++++++ .../wireless/realtek/rtlwifi/btcoexist/rtl_btc.h | 2 ++ drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 ++ 6 files changed, 58 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 897ec3cfa8c8..c6fef54f6543 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1582,6 +1582,7 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_tid_data *tid_data; struct rtl_sta_info *sta_entry = NULL; + u8 reject_agg; if (sta == NULL) return -EINVAL; @@ -1589,6 +1590,14 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw, if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; + if (rtlpriv->cfg->ops->get_btc_status()) { + rtlpriv->btcoexist.btc_ops->btc_get_ampdu_cfg(rtlpriv, + &reject_agg, + NULL, NULL); + if (reject_agg) + return -EINVAL; + } + sta_entry = (struct rtl_sta_info *)sta->drv_priv; if (!sta_entry) return -ENXIO; @@ -1643,6 +1652,24 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw, return 0; } +void rtl_rx_ampdu_apply(struct rtl_priv *rtlpriv) +{ + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + u8 reject_agg, ctrl_agg_size = 0, agg_size; + + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_get_ampdu_cfg(rtlpriv, &reject_agg, + &ctrl_agg_size, &agg_size); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, + "Set RX AMPDU: coex - reject=%d, ctrl_agg_size=%d, size=%d", + reject_agg, ctrl_agg_size, agg_size); + + rtlpriv->hw->max_rx_aggregation_subframes = + (ctrl_agg_size ? agg_size : IEEE80211_MAX_AMPDU_BUF); +} +EXPORT_SYMBOL(rtl_rx_ampdu_apply); + /********************************************************* * * wq & timer callback functions diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index a619fc92a9c0..21fa4562f631 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -147,6 +147,7 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid); int rtl_rx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid); +void rtl_rx_ampdu_apply(struct rtl_priv *rtlpriv); void rtl_watchdog_wq_callback(void *data); void rtl_fwevt_wq_callback(void *data); void rtl_c2hcmd_wq_callback(void *data); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 451039ac7b0a..226927a752f8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -272,14 +272,24 @@ static void halbtc_disable_low_power(struct btc_coexist *btcoexist, static void halbtc_aggregation_check(struct btc_coexist *btcoexist) { bool need_to_act = false; + static unsigned long pre_time; + unsigned long cur_time = 0; + struct rtl_priv *rtlpriv = btcoexist->adapter; /* To void continuous deleteBA=>addBA=>deleteBA=>addBA * This function is not allowed to continuous called * It can only be called after 8 seconds */ + cur_time = jiffies; + if (jiffies_to_msecs(cur_time - pre_time) <= 8000) { + /* over 8 seconds you can execute this function again. */ + return; + } + pre_time = cur_time; + if (btcoexist->bt_info.reject_agg_pkt) { - ;/* TODO: reject */ + need_to_act = true; btcoexist->bt_info.pre_reject_agg_pkt = btcoexist->bt_info.reject_agg_pkt; } else { @@ -304,8 +314,10 @@ static void halbtc_aggregation_check(struct btc_coexist *btcoexist) btcoexist->bt_info.pre_agg_buf_size = btcoexist->bt_info.agg_buf_size; } - } + if (need_to_act) + rtl_rx_ampdu_apply(rtlpriv); + } } static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index 3b976dab712f..96c1ccbf70ac 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -46,6 +46,7 @@ static struct rtl_btc_ops rtl_btc_operation = { .btc_is_bt_disabled = rtl_btc_is_bt_disabled, .btc_special_packet_notify = rtl_btc_special_packet_notify, .btc_record_pwr_mode = rtl_btc_record_pwr_mode, + .btc_get_ampdu_cfg = rtl_btc_get_ampdu_cfg, }; void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len) @@ -60,6 +61,17 @@ void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len) memcpy(gl_bt_coexist.pwr_mode_val, buf, safe_len); } +void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, + u8 *ctrl_agg_size, u8 *agg_size) +{ + if (reject_agg) + *reject_agg = gl_bt_coexist.bt_info.reject_agg_pkt; + if (ctrl_agg_size) + *ctrl_agg_size = gl_bt_coexist.bt_info.bt_ctrl_agg_buf_size; + if (agg_size) + *agg_size = gl_bt_coexist.bt_info.agg_buf_size; +} + void rtl_btc_init_variables(struct rtl_priv *rtlpriv) { exhalbtc_initlize_variables(); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h index 9eeb4fdeaec1..c1c32d685c5d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h @@ -44,6 +44,8 @@ bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type); void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len); +void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, + u8 *ctrl_agg_size, u8 *agg_size); struct rtl_btc_ops *rtl_btc_get_ops_pointer(void); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 41ebdb9d3627..0591adedce76 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2561,6 +2561,8 @@ struct rtl_btc_ops { void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv, u8 pkt_type); void (*btc_record_pwr_mode)(struct rtl_priv *rtlpriv, u8 *buf, u8 len); + void (*btc_get_ampdu_cfg)(struct rtl_priv *rtlpriv, u8 *reject_agg, + u8 *ctrl_agg_size, u8 *agg_size); }; struct proxim { -- cgit v1.2.3 From c692205da18b53cedd965168470813fa1ea67f25 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:48 -0500 Subject: rtlwifi: add btc_is_bt_lps_on() for btcoexist If LPS is controlled by btcoex, this function tell driver LPS is on or off. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c | 6 ++++++ drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h | 1 + drivers/net/wireless/realtek/rtlwifi/wifi.h | 1 + 3 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index 96c1ccbf70ac..7ee2aa94fd2a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -46,6 +46,7 @@ static struct rtl_btc_ops rtl_btc_operation = { .btc_is_bt_disabled = rtl_btc_is_bt_disabled, .btc_special_packet_notify = rtl_btc_special_packet_notify, .btc_record_pwr_mode = rtl_btc_record_pwr_mode, + .btc_is_bt_lps_on = rtl_btc_is_bt_lps_on, .btc_get_ampdu_cfg = rtl_btc_get_ampdu_cfg, }; @@ -61,6 +62,11 @@ void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len) memcpy(gl_bt_coexist.pwr_mode_val, buf, safe_len); } +bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv) +{ + return gl_bt_coexist.bt_info.bt_lps_on; +} + void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, u8 *ctrl_agg_size, u8 *agg_size) { diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h index c1c32d685c5d..ed46f418eb91 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h @@ -44,6 +44,7 @@ bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type); void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len); +bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv); void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, u8 *ctrl_agg_size, u8 *agg_size); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 0591adedce76..23d869bcb90d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2563,6 +2563,7 @@ struct rtl_btc_ops { void (*btc_record_pwr_mode)(struct rtl_priv *rtlpriv, u8 *buf, u8 len); void (*btc_get_ampdu_cfg)(struct rtl_priv *rtlpriv, u8 *reject_agg, u8 *ctrl_agg_size, u8 *agg_size); + bool (*btc_is_bt_lps_on)(struct rtl_priv *rtlpriv); }; struct proxim { -- cgit v1.2.3 From 42213f2f359069eabf174dae3ffd2313d7d40996 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sun, 18 Jun 2017 11:12:49 -0500 Subject: rtlwifi: btcoexist control to enter/leave LPS To yield better user experience, have btcoex control LPS's parameters. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 8 +++ .../realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 7 ++- .../wireless/realtek/rtlwifi/btcoexist/rtl_btc.c | 18 ++++++ .../wireless/realtek/rtlwifi/btcoexist/rtl_btc.h | 3 + .../net/wireless/realtek/rtlwifi/rtl8192ee/fw.c | 63 ++++++++++++++++++--- .../net/wireless/realtek/rtlwifi/rtl8723be/fw.c | 63 ++++++++++++++++++--- .../net/wireless/realtek/rtlwifi/rtl8821ae/fw.c | 64 +++++++++++++++++++--- drivers/net/wireless/realtek/rtlwifi/wifi.h | 3 + 8 files changed, 203 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index c6fef54f6543..180850cb4671 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1802,12 +1802,20 @@ void rtl_watchdog_wq_callback(void *data) false; } + /* PS is controlled by coex. */ + if (rtlpriv->cfg->ops->get_btc_status() && + rtlpriv->btcoexist.btc_ops->btc_is_bt_ctrl_lps(rtlpriv)) + goto label_lps_done; + if (((rtlpriv->link_info.num_rx_inperiod + rtlpriv->link_info.num_tx_inperiod) > 8) || (rtlpriv->link_info.num_rx_inperiod > 2)) rtl_lps_leave(hw); else rtl_lps_enter(hw); + +label_lps_done: + ; } rtlpriv->link_info.num_rx_inperiod = 0; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 226927a752f8..eaa916a0727b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -242,14 +242,19 @@ static void halbtc_enter_lps(struct btc_coexist *btcoexist) } btcoexist->bt_info.bt_ctrl_lps = true; - btcoexist->bt_info.bt_lps_on = false; + btcoexist->bt_info.bt_lps_on = true; rtl_lps_enter(rtlpriv->mac80211.hw); } static void halbtc_normal_lps(struct btc_coexist *btcoexist) { + struct rtl_priv *rtlpriv; + + rtlpriv = btcoexist->adapter; + if (btcoexist->bt_info.bt_ctrl_lps) { btcoexist->bt_info.bt_lps_on = false; + rtl_lps_leave(rtlpriv->mac80211.hw); btcoexist->bt_info.bt_ctrl_lps = false; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index 7ee2aa94fd2a..4366c9817e1e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -46,6 +46,9 @@ static struct rtl_btc_ops rtl_btc_operation = { .btc_is_bt_disabled = rtl_btc_is_bt_disabled, .btc_special_packet_notify = rtl_btc_special_packet_notify, .btc_record_pwr_mode = rtl_btc_record_pwr_mode, + .btc_get_lps_val = rtl_btc_get_lps_val, + .btc_get_rpwm_val = rtl_btc_get_rpwm_val, + .btc_is_bt_ctrl_lps = rtl_btc_is_bt_ctrl_lps, .btc_is_bt_lps_on = rtl_btc_is_bt_lps_on, .btc_get_ampdu_cfg = rtl_btc_get_ampdu_cfg, }; @@ -62,6 +65,21 @@ void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len) memcpy(gl_bt_coexist.pwr_mode_val, buf, safe_len); } +u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv) +{ + return gl_bt_coexist.bt_info.lps_val; +} + +u8 rtl_btc_get_rpwm_val(struct rtl_priv *rtlpriv) +{ + return gl_bt_coexist.bt_info.rpwm_val; +} + +bool rtl_btc_is_bt_ctrl_lps(struct rtl_priv *rtlpriv) +{ + return gl_bt_coexist.bt_info.bt_ctrl_lps; +} + bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv) { return gl_bt_coexist.bt_info.bt_lps_on; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h index ed46f418eb91..6fe521cbe7f0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h @@ -44,6 +44,9 @@ bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type); void rtl_btc_record_pwr_mode(struct rtl_priv *rtlpriv, u8 *buf, u8 len); +u8 rtl_btc_get_lps_val(struct rtl_priv *rtlpriv); +u8 rtl_btc_get_rpwm_val(struct rtl_priv *rtlpriv); +bool rtl_btc_is_bt_ctrl_lps(struct rtl_priv *rtlpriv); bool rtl_btc_is_bt_lps_on(struct rtl_priv *rtlpriv); void rtl_btc_get_ampdu_cfg(struct rtl_priv *rtlpriv, u8 *reject_agg, u8 *ctrl_agg_size, u8 *agg_size); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index c11f1c04f871..2ba9e613a7f6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -422,24 +422,71 @@ void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 u1_h2c_set_pwrmode[H2C_92E_PWEMODE_LENGTH] = { 0 }; struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 rlbm, power_state = 0, byte5 = 0x40; + u8 rlbm, power_state = 0, byte5 = 0; + u8 awake_intvl; /* DTIM = (awake_intvl - 1) */ struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , "FW LPS mode = %d\n", mode); + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", + mode, bt_ctrl_lps); + + switch (mode) { + case FW_PS_MIN_MODE: + rlbm = 0; + awake_intvl = 2; + break; + case FW_PS_MAX_MODE: + rlbm = 1; + awake_intvl = 2; + break; + case FW_PS_DTIM_MODE: + rlbm = 2; + awake_intvl = ppsc->reg_max_lps_awakeintvl; + /* hw->conf.ps_dtim_period or mac->vif->bss_conf.dtim_period + * is only used in swlps. + */ + break; + default: + rlbm = 2; + awake_intvl = 4; + break; + } + + if (rtlpriv->mac80211.p2p) { + awake_intvl = 2; + rlbm = 1; + } + + if (mode == FW_PS_ACTIVE_MODE) { + byte5 = 0x40; + power_state = FW_PWR_STATE_ACTIVE; + } else { + if (bt_ctrl_lps) { + byte5 = btc_ops->btc_get_lps_val(rtlpriv); + power_state = btc_ops->btc_get_rpwm_val(rtlpriv); + + if ((rlbm == 2) && (byte5 & BIT(4))) { + /* Keep awake interval to 1 to prevent from + * decreasing coex performance + */ + awake_intvl = 2; + rlbm = 2; + } + } else { + byte5 = 0x40; + power_state = FW_PWR_STATE_RF_OFF; + } + } SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); - rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/ SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1); SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, - ppsc->reg_max_lps_awakeintvl); + awake_intvl); SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); - if (mode == FW_PS_ACTIVE_MODE) - power_state |= FW_PWR_STATE_ACTIVE; - else - power_state |= FW_PWR_STATE_RF_OFF; SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c index 488376becdcb..a37eb27cefe6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c @@ -240,24 +240,71 @@ void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 u1_h2c_set_pwrmode[H2C_PWEMODE_LENGTH] = { 0 }; struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 rlbm, power_state = 0, byte5 = 0x40; + u8 rlbm, power_state = 0, byte5 = 0; + u8 awake_intvl; /* DTIM = (awake_intvl - 1) */ struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", + mode, bt_ctrl_lps); + + switch (mode) { + case FW_PS_MIN_MODE: + rlbm = 0; + awake_intvl = 2; + break; + case FW_PS_MAX_MODE: + rlbm = 1; + awake_intvl = 2; + break; + case FW_PS_DTIM_MODE: + rlbm = 2; + awake_intvl = ppsc->reg_max_lps_awakeintvl; + /* hw->conf.ps_dtim_period or mac->vif->bss_conf.dtim_period + * is only used in swlps. + */ + break; + default: + rlbm = 2; + awake_intvl = 4; + break; + } + + if (rtlpriv->mac80211.p2p) { + awake_intvl = 2; + rlbm = 1; + } + + if (mode == FW_PS_ACTIVE_MODE) { + byte5 = 0x40; + power_state = FW_PWR_STATE_ACTIVE; + } else { + if (bt_ctrl_lps) { + byte5 = btc_ops->btc_get_lps_val(rtlpriv); + power_state = btc_ops->btc_get_rpwm_val(rtlpriv); + + if ((rlbm == 2) && (byte5 & BIT(4))) { + /* Keep awake interval to 1 to prevent from + * decreasing coex performance + */ + awake_intvl = 2; + rlbm = 2; + } + } else { + byte5 = 0x40; + power_state = FW_PWR_STATE_RF_OFF; + } + } SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); - rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/ SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1); SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, - ppsc->reg_max_lps_awakeintvl); + awake_intvl); SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); - if (mode == FW_PS_ACTIVE_MODE) - power_state |= FW_PWR_STATE_ACTIVE; - else - power_state |= FW_PWR_STATE_RF_OFF; SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index 96b8a9bdaf55..cc03f9813824 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -489,25 +489,71 @@ void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 u1_h2c_set_pwrmode[H2C_8821AE_PWEMODE_LENGTH] = { 0 }; struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - u8 rlbm, power_state = 0, byte5 = 0x40; + u8 rlbm, power_state = 0, byte5 = 0; + u8 awake_intvl; /* DTIM = (awake_intvl - 1) */ struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; + bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", + mode, bt_ctrl_lps); + + switch (mode) { + case FW_PS_MIN_MODE: + rlbm = 0; + awake_intvl = 2; + break; + case FW_PS_MAX_MODE: + rlbm = 1; + awake_intvl = 2; + break; + case FW_PS_DTIM_MODE: + rlbm = 2; + awake_intvl = ppsc->reg_max_lps_awakeintvl; + /* hw->conf.ps_dtim_period or mac->vif->bss_conf.dtim_period + * is only used in swlps. + */ + break; + default: + rlbm = 2; + awake_intvl = 4; + break; + } + + if (rtlpriv->mac80211.p2p) { + awake_intvl = 2; + rlbm = 1; + } + + if (mode == FW_PS_ACTIVE_MODE) { + byte5 = 0x40; + power_state = FW_PWR_STATE_ACTIVE; + } else { + if (bt_ctrl_lps) { + byte5 = btc_ops->btc_get_lps_val(rtlpriv); + power_state = btc_ops->btc_get_rpwm_val(rtlpriv); + + if ((rlbm == 2) && (byte5 & BIT(4))) { + /* Keep awake interval to 1 to prevent from + * decreasing coex performance + */ + awake_intvl = 2; + rlbm = 2; + } + } else { + byte5 = 0x40; + power_state = FW_PWR_STATE_RF_OFF; + } + } SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); - rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/ SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1); SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, - ppsc->reg_max_lps_awakeintvl); + awake_intvl); SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); - if (mode == FW_PS_ACTIVE_MODE) - power_state |= FW_PWR_STATE_ACTIVE; - else - power_state |= FW_PWR_STATE_RF_OFF; - SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state); SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 23d869bcb90d..49c0d2229274 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2561,6 +2561,9 @@ struct rtl_btc_ops { void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv, u8 pkt_type); void (*btc_record_pwr_mode)(struct rtl_priv *rtlpriv, u8 *buf, u8 len); + u8 (*btc_get_lps_val)(struct rtl_priv *rtlpriv); + u8 (*btc_get_rpwm_val)(struct rtl_priv *rtlpriv); + bool (*btc_is_bt_ctrl_lps)(struct rtl_priv *rtlpriv); void (*btc_get_ampdu_cfg)(struct rtl_priv *rtlpriv, u8 *reject_agg, u8 *ctrl_agg_size, u8 *agg_size); bool (*btc_is_bt_lps_on)(struct rtl_priv *rtlpriv); -- cgit v1.2.3 From 3f426c96895556bb49adfa52f3aeafdedb2d02e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 13 Jun 2017 18:02:03 +0200 Subject: brcmfmac: initialize oob irq data before request_irq() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes spin-forever in irq handler when IRQ is already asserted at request_irq() time. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 844c1e68ec03..984c1d0560b1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -108,12 +108,14 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) int ret = 0; u8 data; u32 addr, gpiocontrol; - unsigned long flags; pdata = &sdiodev->settings->bus.sdio; if (pdata->oob_irq_supported) { brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n", pdata->oob_irq_nr); + spin_lock_init(&sdiodev->irq_en_lock); + sdiodev->irq_en = true; + ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler, pdata->oob_irq_flags, "brcmf_oob_intr", &sdiodev->func[1]->dev); @@ -122,10 +124,6 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) return ret; } sdiodev->oob_irq_requested = true; - spin_lock_init(&sdiodev->irq_en_lock); - spin_lock_irqsave(&sdiodev->irq_en_lock, flags); - sdiodev->irq_en = true; - spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags); ret = enable_irq_wake(pdata->oob_irq_nr); if (ret != 0) { -- cgit v1.2.3 From b65c0c9b65a8fe2434bdc0a94e3767940f69aae9 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Wed, 21 Jun 2017 11:25:18 +0800 Subject: r8152: correct the definition Replace VLAN_HLEN and CRC_SIZE with ETH_FCS_LEN. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 8bc4573e0cd4..6cfffeff6108 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -569,7 +569,6 @@ enum rtl_register_content { #define RTL8152_MAX_TX 4 #define RTL8152_MAX_RX 10 #define INTBUFSIZE 2 -#define CRC_SIZE 4 #define TX_ALIGN 4 #define RX_ALIGN 8 @@ -588,12 +587,13 @@ enum rtl_register_content { #define BYTE_EN_END_MASK 0xf0 #define RTL8153_MAX_PACKET 9216 /* 9K */ -#define RTL8153_MAX_MTU (RTL8153_MAX_PACKET - VLAN_ETH_HLEN - VLAN_HLEN) -#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) +#define RTL8153_MAX_MTU (RTL8153_MAX_PACKET - VLAN_ETH_HLEN - \ + ETH_FCS_LEN) +#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) #define RTL8153_RMS RTL8153_MAX_PACKET #define RTL8152_TX_TIMEOUT (5 * HZ) #define RTL8152_NAPI_WEIGHT 64 -#define rx_reserved_size(x) ((x) + VLAN_ETH_HLEN + CRC_SIZE + \ +#define rx_reserved_size(x) ((x) + VLAN_ETH_HLEN + ETH_FCS_LEN + \ sizeof(struct rx_desc) + RX_ALIGN) /* rtl8152 flags */ @@ -770,7 +770,7 @@ static const int multicast_filter_limit = 32; static unsigned int agg_buf_sz = 16384; #define RTL_LIMITED_TSO_SIZE (agg_buf_sz - sizeof(struct tx_desc) - \ - VLAN_ETH_HLEN - VLAN_HLEN) + VLAN_ETH_HLEN - ETH_FCS_LEN) static int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) @@ -1928,7 +1928,7 @@ static int rx_bottom(struct r8152 *tp, int budget) if (urb->actual_length < len_used) break; - pkt_len -= CRC_SIZE; + pkt_len -= ETH_FCS_LEN; rx_data += sizeof(struct rx_desc); skb = napi_alloc_skb(napi, pkt_len); @@ -1952,7 +1952,7 @@ static int rx_bottom(struct r8152 *tp, int budget) } find_next_rx: - rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); + rx_data = rx_agg_align(rx_data + pkt_len + ETH_FCS_LEN); rx_desc = (struct rx_desc *)rx_data; len_used = (int)(rx_data - (u8 *)agg->head); len_used += sizeof(struct rx_desc); @@ -2242,7 +2242,7 @@ static void set_tx_qlen(struct r8152 *tp) { struct net_device *netdev = tp->netdev; - tp->tx_qlen = agg_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN + + tp->tx_qlen = agg_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN + sizeof(struct tx_desc)); } @@ -3439,7 +3439,7 @@ static void r8153_first_init(struct r8152 *tp) rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX); - ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + CRC_SIZE; + ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO); @@ -3489,7 +3489,7 @@ static void r8153_enter_oob(struct r8152 *tp) usleep_range(1000, 2000); } - ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + CRC_SIZE; + ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data); switch (tp->version) { @@ -4957,7 +4957,7 @@ static int rtl8152_change_mtu(struct net_device *dev, int new_mtu) dev->mtu = new_mtu; if (netif_running(dev)) { - u32 rms = new_mtu + VLAN_ETH_HLEN + CRC_SIZE; + u32 rms = new_mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, rms); -- cgit v1.2.3 From 8e8dddba72d81b78742b002bebc3cce1b23d3f84 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Wed, 21 Jun 2017 16:22:43 +0300 Subject: qed: Cleanup qed_roce before duplicating it The next patch in the series will duplicate qed_roce as part of code preprations for iWARP support. Do some cleanup before duplicating Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_roce.c | 51 +++++++----------------------- 1 file changed, 12 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 673f80aa690d..9dc41a899ef2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -35,11 +35,7 @@ #include #include #include -#include -#include #include -#include -#include #include #include #include @@ -48,10 +44,6 @@ #include #include #include -#include -#include -#include -#include #include "qed.h" #include "qed_cxt.h" #include "qed_hsi.h" @@ -61,10 +53,9 @@ #include "qed_ll2.h" #include "qed_mcp.h" #include "qed_reg_addr.h" -#include "qed_sp.h" #include "qed_roce.h" -#include "qed_ll2.h" -#include +#include +#include "qed_sp.h" static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid); @@ -100,13 +91,10 @@ static int qed_rdma_bmap_alloc(struct qed_hwfn *p_hwfn, bmap->max_count = max_count; - bmap->bitmap = kzalloc(BITS_TO_LONGS(max_count) * sizeof(long), + bmap->bitmap = kcalloc(BITS_TO_LONGS(max_count), sizeof(long), GFP_KERNEL); - if (!bmap->bitmap) { - DP_NOTICE(p_hwfn, - "qed bmap alloc failed: cannot allocate memory (bitmap)\n"); + if (!bmap->bitmap) return -ENOMEM; - } snprintf(bmap->name, QED_RDMA_MAX_BMAP_NAME, "%s", name); @@ -189,12 +177,8 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn, /* Allocate a struct with current pf rdma info */ p_rdma_info = kzalloc(sizeof(*p_rdma_info), GFP_KERNEL); - if (!p_rdma_info) { - DP_NOTICE(p_hwfn, - "qed rdma alloc failed: cannot allocate memory (rdma info). rc = %d\n", - rc); + if (!p_rdma_info) return rc; - } p_hwfn->p_rdma_info = p_rdma_info; p_rdma_info->proto = PROTOCOLID_ROCE; @@ -217,21 +201,13 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn, /* Allocate a struct with device params and fill it */ p_rdma_info->dev = kzalloc(sizeof(*p_rdma_info->dev), GFP_KERNEL); - if (!p_rdma_info->dev) { - DP_NOTICE(p_hwfn, - "qed rdma alloc failed: cannot allocate memory (rdma info dev). rc = %d\n", - rc); + if (!p_rdma_info->dev) goto free_rdma_info; - } /* Allocate a struct with port params and fill it */ p_rdma_info->port = kzalloc(sizeof(*p_rdma_info->port), GFP_KERNEL); - if (!p_rdma_info->port) { - DP_NOTICE(p_hwfn, - "qed rdma alloc failed: cannot allocate memory (rdma info port). rc = %d\n", - rc); + if (!p_rdma_info->port) goto free_rdma_dev; - } /* Allocate bit map for pd's */ rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->pd_map, RDMA_MAX_PDS, @@ -1108,6 +1084,7 @@ qed_rdma_destroy_cq(void *rdma_cxt, struct qed_sp_init_data init_data; struct qed_spq_entry *p_ent; dma_addr_t ramrod_res_phys; + enum protocol_type proto; int rc = -ENOMEM; DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", in_params->icid); @@ -1128,11 +1105,11 @@ qed_rdma_destroy_cq(void *rdma_cxt, init_data.cid = in_params->icid; init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - + proto = p_hwfn->p_rdma_info->proto; /* Send destroy CQ ramrod */ rc = qed_sp_init_request(p_hwfn, &p_ent, RDMA_RAMROD_DESTROY_CQ, - p_hwfn->p_rdma_info->proto, &init_data); + proto, &init_data); if (rc) goto err; @@ -1155,9 +1132,7 @@ qed_rdma_destroy_cq(void *rdma_cxt, qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->cq_map, (in_params->icid - - qed_cxt_get_proto_cid_start(p_hwfn, - p_hwfn-> - p_rdma_info->proto))); + qed_cxt_get_proto_cid_start(p_hwfn, proto))); spin_unlock_bh(&p_hwfn->p_rdma_info->lock); @@ -2153,10 +2128,8 @@ qed_rdma_create_qp(void *rdma_cxt, } qp = kzalloc(sizeof(*qp), GFP_KERNEL); - if (!qp) { - DP_NOTICE(p_hwfn, "Failed to allocate qed_rdma_qp\n"); + if (!qp) return NULL; - } rc = qed_roce_alloc_cid(p_hwfn, &qp->icid); qp->qpid = ((0xFF << 16) | qp->icid); -- cgit v1.2.3 From f1372ee11901336d287a4032fabe433d33586753 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Wed, 21 Jun 2017 16:22:44 +0300 Subject: qed: Duplicate qed_roce.[ch] to qed_rdma.[ch] This patch adds files that will contain common code for RoCE/iWARP. The files are currently identical to qed_roce.c / qed_roce.h and intentionally not added to the makefile. The next patch in the series will modify the files so that roce specific code is left in qed_roce and common roce/iwarp code will be placed in qed_rdma This patch is the result of a simple cp qed_rdma.c qed_roce.c cp qed_rdma.h qed_roce.h Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_rdma.c | 2805 ++++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_rdma.h | 178 ++ 2 files changed, 2983 insertions(+) create mode 100644 drivers/net/ethernet/qlogic/qed/qed_rdma.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_rdma.h (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c new file mode 100644 index 000000000000..9dc41a899ef2 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -0,0 +1,2805 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015-2017 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_cxt.h" +#include "qed_hsi.h" +#include "qed_hw.h" +#include "qed_init_ops.h" +#include "qed_int.h" +#include "qed_ll2.h" +#include "qed_mcp.h" +#include "qed_reg_addr.h" +#include "qed_roce.h" +#include +#include "qed_sp.h" + +static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid); + +static int +qed_roce_async_event(struct qed_hwfn *p_hwfn, + u8 fw_event_code, + u16 echo, union event_ring_data *data, u8 fw_return_code) +{ + if (fw_event_code == ROCE_ASYNC_EVENT_DESTROY_QP_DONE) { + u16 icid = + (u16)le32_to_cpu(data->rdma_data.rdma_destroy_qp_data.cid); + + /* icid release in this async event can occur only if the icid + * was offloaded to the FW. In case it wasn't offloaded this is + * handled in qed_roce_sp_destroy_qp. + */ + qed_roce_free_real_icid(p_hwfn, icid); + } else { + struct qed_rdma_events *events = &p_hwfn->p_rdma_info->events; + + events->affiliated_event(p_hwfn->p_rdma_info->events.context, + fw_event_code, + (void *)&data->rdma_data.async_handle); + } + + return 0; +} + +static int qed_rdma_bmap_alloc(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 max_count, char *name) +{ + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "max_count = %08x\n", max_count); + + bmap->max_count = max_count; + + bmap->bitmap = kcalloc(BITS_TO_LONGS(max_count), sizeof(long), + GFP_KERNEL); + if (!bmap->bitmap) + return -ENOMEM; + + snprintf(bmap->name, QED_RDMA_MAX_BMAP_NAME, "%s", name); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "0\n"); + return 0; +} + +static int qed_rdma_bmap_alloc_id(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 *id_num) +{ + *id_num = find_first_zero_bit(bmap->bitmap, bmap->max_count); + if (*id_num >= bmap->max_count) + return -EINVAL; + + __set_bit(*id_num, bmap->bitmap); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "%s bitmap: allocated id %d\n", + bmap->name, *id_num); + + return 0; +} + +static void qed_bmap_set_id(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 id_num) +{ + if (id_num >= bmap->max_count) + return; + + __set_bit(id_num, bmap->bitmap); +} + +static void qed_bmap_release_id(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 id_num) +{ + bool b_acquired; + + if (id_num >= bmap->max_count) + return; + + b_acquired = test_and_clear_bit(id_num, bmap->bitmap); + if (!b_acquired) { + DP_NOTICE(p_hwfn, "%s bitmap: id %d already released\n", + bmap->name, id_num); + return; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "%s bitmap: released id %d\n", + bmap->name, id_num); +} + +static int qed_bmap_test_id(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 id_num) +{ + if (id_num >= bmap->max_count) + return -1; + + return test_bit(id_num, bmap->bitmap); +} + +static bool qed_bmap_is_empty(struct qed_bmap *bmap) +{ + return bmap->max_count == find_first_bit(bmap->bitmap, bmap->max_count); +} + +static u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id) +{ + /* First sb id for RoCE is after all the l2 sb */ + return FEAT_NUM((struct qed_hwfn *)p_hwfn, QED_PF_L2_QUE) + rel_sb_id; +} + +static int qed_rdma_alloc(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_rdma_start_in_params *params) +{ + struct qed_rdma_info *p_rdma_info; + u32 num_cons, num_tasks; + int rc = -ENOMEM; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocating RDMA\n"); + + /* Allocate a struct with current pf rdma info */ + p_rdma_info = kzalloc(sizeof(*p_rdma_info), GFP_KERNEL); + if (!p_rdma_info) + return rc; + + p_hwfn->p_rdma_info = p_rdma_info; + p_rdma_info->proto = PROTOCOLID_ROCE; + + num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto, + NULL); + + p_rdma_info->num_qps = num_cons / 2; + + num_tasks = qed_cxt_get_proto_tid_count(p_hwfn, PROTOCOLID_ROCE); + + /* Each MR uses a single task */ + p_rdma_info->num_mrs = num_tasks; + + /* Queue zone lines are shared between RoCE and L2 in such a way that + * they can be used by each without obstructing the other. + */ + p_rdma_info->queue_zone_base = (u16)RESC_START(p_hwfn, QED_L2_QUEUE); + p_rdma_info->max_queue_zones = (u16)RESC_NUM(p_hwfn, QED_L2_QUEUE); + + /* Allocate a struct with device params and fill it */ + p_rdma_info->dev = kzalloc(sizeof(*p_rdma_info->dev), GFP_KERNEL); + if (!p_rdma_info->dev) + goto free_rdma_info; + + /* Allocate a struct with port params and fill it */ + p_rdma_info->port = kzalloc(sizeof(*p_rdma_info->port), GFP_KERNEL); + if (!p_rdma_info->port) + goto free_rdma_dev; + + /* Allocate bit map for pd's */ + rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->pd_map, RDMA_MAX_PDS, + "PD"); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to allocate pd_map, rc = %d\n", + rc); + goto free_rdma_port; + } + + /* Allocate DPI bitmap */ + rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->dpi_map, + p_hwfn->dpi_count, "DPI"); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to allocate DPI bitmap, rc = %d\n", rc); + goto free_pd_map; + } + + /* Allocate bitmap for cq's. The maximum number of CQs is bounded to + * twice the number of QPs. + */ + rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->cq_map, + p_rdma_info->num_qps * 2, "CQ"); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to allocate cq bitmap, rc = %d\n", rc); + goto free_dpi_map; + } + + /* Allocate bitmap for toggle bit for cq icids + * We toggle the bit every time we create or resize cq for a given icid. + * The maximum number of CQs is bounded to twice the number of QPs. + */ + rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->toggle_bits, + p_rdma_info->num_qps * 2, "Toggle"); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to allocate toogle bits, rc = %d\n", rc); + goto free_cq_map; + } + + /* Allocate bitmap for itids */ + rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->tid_map, + p_rdma_info->num_mrs, "MR"); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to allocate itids bitmaps, rc = %d\n", rc); + goto free_toggle_map; + } + + /* Allocate bitmap for cids used for qps. */ + rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->cid_map, num_cons, + "CID"); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to allocate cid bitmap, rc = %d\n", rc); + goto free_tid_map; + } + + /* Allocate bitmap for cids used for responders/requesters. */ + rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->real_cid_map, num_cons, + "REAL_CID"); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to allocate real cid bitmap, rc = %d\n", rc); + goto free_cid_map; + } + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocation successful\n"); + return 0; + +free_cid_map: + kfree(p_rdma_info->cid_map.bitmap); +free_tid_map: + kfree(p_rdma_info->tid_map.bitmap); +free_toggle_map: + kfree(p_rdma_info->toggle_bits.bitmap); +free_cq_map: + kfree(p_rdma_info->cq_map.bitmap); +free_dpi_map: + kfree(p_rdma_info->dpi_map.bitmap); +free_pd_map: + kfree(p_rdma_info->pd_map.bitmap); +free_rdma_port: + kfree(p_rdma_info->port); +free_rdma_dev: + kfree(p_rdma_info->dev); +free_rdma_info: + kfree(p_rdma_info); + + return rc; +} + +static void qed_rdma_bmap_free(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, bool check) +{ + int weight = bitmap_weight(bmap->bitmap, bmap->max_count); + int last_line = bmap->max_count / (64 * 8); + int last_item = last_line * 8 + + DIV_ROUND_UP(bmap->max_count % (64 * 8), 64); + u64 *pmap = (u64 *)bmap->bitmap; + int line, item, offset; + u8 str_last_line[200] = { 0 }; + + if (!weight || !check) + goto end; + + DP_NOTICE(p_hwfn, + "%s bitmap not free - size=%d, weight=%d, 512 bits per line\n", + bmap->name, bmap->max_count, weight); + + /* print aligned non-zero lines, if any */ + for (item = 0, line = 0; line < last_line; line++, item += 8) + if (bitmap_weight((unsigned long *)&pmap[item], 64 * 8)) + DP_NOTICE(p_hwfn, + "line 0x%04x: 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n", + line, + pmap[item], + pmap[item + 1], + pmap[item + 2], + pmap[item + 3], + pmap[item + 4], + pmap[item + 5], + pmap[item + 6], pmap[item + 7]); + + /* print last unaligned non-zero line, if any */ + if ((bmap->max_count % (64 * 8)) && + (bitmap_weight((unsigned long *)&pmap[item], + bmap->max_count - item * 64))) { + offset = sprintf(str_last_line, "line 0x%04x: ", line); + for (; item < last_item; item++) + offset += sprintf(str_last_line + offset, + "0x%016llx ", pmap[item]); + DP_NOTICE(p_hwfn, "%s\n", str_last_line); + } + +end: + kfree(bmap->bitmap); + bmap->bitmap = NULL; +} + +static void qed_rdma_resc_free(struct qed_hwfn *p_hwfn) +{ + struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; + + qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->cid_map, 1); + qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->pd_map, 1); + qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->dpi_map, 1); + qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->cq_map, 1); + qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->toggle_bits, 0); + qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->tid_map, 1); + + kfree(p_rdma_info->port); + kfree(p_rdma_info->dev); + + kfree(p_rdma_info); +} + +static void qed_rdma_free(struct qed_hwfn *p_hwfn) +{ + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Freeing RDMA\n"); + + qed_rdma_resc_free(p_hwfn); +} + +static void qed_rdma_get_guid(struct qed_hwfn *p_hwfn, u8 *guid) +{ + guid[0] = p_hwfn->hw_info.hw_mac_addr[0] ^ 2; + guid[1] = p_hwfn->hw_info.hw_mac_addr[1]; + guid[2] = p_hwfn->hw_info.hw_mac_addr[2]; + guid[3] = 0xff; + guid[4] = 0xfe; + guid[5] = p_hwfn->hw_info.hw_mac_addr[3]; + guid[6] = p_hwfn->hw_info.hw_mac_addr[4]; + guid[7] = p_hwfn->hw_info.hw_mac_addr[5]; +} + +static void qed_rdma_init_events(struct qed_hwfn *p_hwfn, + struct qed_rdma_start_in_params *params) +{ + struct qed_rdma_events *events; + + events = &p_hwfn->p_rdma_info->events; + + events->unaffiliated_event = params->events->unaffiliated_event; + events->affiliated_event = params->events->affiliated_event; + events->context = params->events->context; +} + +static void qed_rdma_init_devinfo(struct qed_hwfn *p_hwfn, + struct qed_rdma_start_in_params *params) +{ + struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev; + struct qed_dev *cdev = p_hwfn->cdev; + u32 pci_status_control; + u32 num_qps; + + /* Vendor specific information */ + dev->vendor_id = cdev->vendor_id; + dev->vendor_part_id = cdev->device_id; + dev->hw_ver = 0; + dev->fw_ver = (FW_MAJOR_VERSION << 24) | (FW_MINOR_VERSION << 16) | + (FW_REVISION_VERSION << 8) | (FW_ENGINEERING_VERSION); + + qed_rdma_get_guid(p_hwfn, (u8 *)&dev->sys_image_guid); + dev->node_guid = dev->sys_image_guid; + + dev->max_sge = min_t(u32, RDMA_MAX_SGE_PER_SQ_WQE, + RDMA_MAX_SGE_PER_RQ_WQE); + + if (cdev->rdma_max_sge) + dev->max_sge = min_t(u32, cdev->rdma_max_sge, dev->max_sge); + + dev->max_inline = ROCE_REQ_MAX_INLINE_DATA_SIZE; + + dev->max_inline = (cdev->rdma_max_inline) ? + min_t(u32, cdev->rdma_max_inline, dev->max_inline) : + dev->max_inline; + + dev->max_wqe = QED_RDMA_MAX_WQE; + dev->max_cnq = (u8)FEAT_NUM(p_hwfn, QED_RDMA_CNQ); + + /* The number of QPs may be higher than QED_ROCE_MAX_QPS, because + * it is up-aligned to 16 and then to ILT page size within qed cxt. + * This is OK in terms of ILT but we don't want to configure the FW + * above its abilities + */ + num_qps = ROCE_MAX_QPS; + num_qps = min_t(u64, num_qps, p_hwfn->p_rdma_info->num_qps); + dev->max_qp = num_qps; + + /* CQs uses the same icids that QPs use hence they are limited by the + * number of icids. There are two icids per QP. + */ + dev->max_cq = num_qps * 2; + + /* The number of mrs is smaller by 1 since the first is reserved */ + dev->max_mr = p_hwfn->p_rdma_info->num_mrs - 1; + dev->max_mr_size = QED_RDMA_MAX_MR_SIZE; + + /* The maximum CQE capacity per CQ supported. + * max number of cqes will be in two layer pbl, + * 8 is the pointer size in bytes + * 32 is the size of cq element in bytes + */ + if (params->cq_mode == QED_RDMA_CQ_MODE_32_BITS) + dev->max_cqe = QED_RDMA_MAX_CQE_32_BIT; + else + dev->max_cqe = QED_RDMA_MAX_CQE_16_BIT; + + dev->max_mw = 0; + dev->max_fmr = QED_RDMA_MAX_FMR; + dev->max_mr_mw_fmr_pbl = (PAGE_SIZE / 8) * (PAGE_SIZE / 8); + dev->max_mr_mw_fmr_size = dev->max_mr_mw_fmr_pbl * PAGE_SIZE; + dev->max_pkey = QED_RDMA_MAX_P_KEY; + + dev->max_qp_resp_rd_atomic_resc = RDMA_RING_PAGE_SIZE / + (RDMA_RESP_RD_ATOMIC_ELM_SIZE * 2); + dev->max_qp_req_rd_atomic_resc = RDMA_RING_PAGE_SIZE / + RDMA_REQ_RD_ATOMIC_ELM_SIZE; + dev->max_dev_resp_rd_atomic_resc = dev->max_qp_resp_rd_atomic_resc * + p_hwfn->p_rdma_info->num_qps; + dev->page_size_caps = QED_RDMA_PAGE_SIZE_CAPS; + dev->dev_ack_delay = QED_RDMA_ACK_DELAY; + dev->max_pd = RDMA_MAX_PDS; + dev->max_ah = p_hwfn->p_rdma_info->num_qps; + dev->max_stats_queues = (u8)RESC_NUM(p_hwfn, QED_RDMA_STATS_QUEUE); + + /* Set capablities */ + dev->dev_caps = 0; + SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_RNR_NAK, 1); + SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_PORT_ACTIVE_EVENT, 1); + SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_PORT_CHANGE_EVENT, 1); + SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_RESIZE_CQ, 1); + SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_BASE_MEMORY_EXT, 1); + SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_BASE_QUEUE_EXT, 1); + SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_ZBVA, 1); + SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_LOCAL_INV_FENCE, 1); + + /* Check atomic operations support in PCI configuration space. */ + pci_read_config_dword(cdev->pdev, + cdev->pdev->pcie_cap + PCI_EXP_DEVCTL2, + &pci_status_control); + + if (pci_status_control & PCI_EXP_DEVCTL2_LTR_EN) + SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_ATOMIC_OP, 1); +} + +static void qed_rdma_init_port(struct qed_hwfn *p_hwfn) +{ + struct qed_rdma_port *port = p_hwfn->p_rdma_info->port; + struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev; + + port->port_state = p_hwfn->mcp_info->link_output.link_up ? + QED_RDMA_PORT_UP : QED_RDMA_PORT_DOWN; + + port->max_msg_size = min_t(u64, + (dev->max_mr_mw_fmr_size * + p_hwfn->cdev->rdma_max_sge), + BIT(31)); + + port->pkey_bad_counter = 0; +} + +static int qed_rdma_init_hw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + u32 ll2_ethertype_en; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Initializing HW\n"); + p_hwfn->b_rdma_enabled_in_prs = false; + + qed_wr(p_hwfn, p_ptt, PRS_REG_ROCE_DEST_QP_MAX_PF, 0); + + p_hwfn->rdma_prs_search_reg = PRS_REG_SEARCH_ROCE; + + /* We delay writing to this reg until first cid is allocated. See + * qed_cxt_dynamic_ilt_alloc function for more details + */ + ll2_ethertype_en = qed_rd(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN); + qed_wr(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN, + (ll2_ethertype_en | 0x01)); + + if (qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_ROCE) % 2) { + DP_NOTICE(p_hwfn, "The first RoCE's cid should be even\n"); + return -EINVAL; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Initializing HW - Done\n"); + return 0; +} + +static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn, + struct qed_rdma_start_in_params *params, + struct qed_ptt *p_ptt) +{ + struct rdma_init_func_ramrod_data *p_ramrod; + struct qed_rdma_cnq_params *p_cnq_pbl_list; + struct rdma_init_func_hdr *p_params_header; + struct rdma_cnq_params *p_cnq_params; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + u32 cnq_id, sb_id; + u16 igu_sb_id; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Starting FW\n"); + + /* Save the number of cnqs for the function close ramrod */ + p_hwfn->p_rdma_info->num_cnqs = params->desired_cnq; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, RDMA_RAMROD_FUNC_INIT, + p_hwfn->p_rdma_info->proto, &init_data); + if (rc) + return rc; + + p_ramrod = &p_ent->ramrod.roce_init_func.rdma; + + p_params_header = &p_ramrod->params_header; + p_params_header->cnq_start_offset = (u8)RESC_START(p_hwfn, + QED_RDMA_CNQ_RAM); + p_params_header->num_cnqs = params->desired_cnq; + + if (params->cq_mode == QED_RDMA_CQ_MODE_16_BITS) + p_params_header->cq_ring_mode = 1; + else + p_params_header->cq_ring_mode = 0; + + for (cnq_id = 0; cnq_id < params->desired_cnq; cnq_id++) { + sb_id = qed_rdma_get_sb_id(p_hwfn, cnq_id); + igu_sb_id = qed_get_igu_sb_id(p_hwfn, sb_id); + p_ramrod->cnq_params[cnq_id].sb_num = cpu_to_le16(igu_sb_id); + p_cnq_params = &p_ramrod->cnq_params[cnq_id]; + p_cnq_pbl_list = ¶ms->cnq_pbl_list[cnq_id]; + + p_cnq_params->sb_index = p_hwfn->pf_params.rdma_pf_params.gl_pi; + p_cnq_params->num_pbl_pages = p_cnq_pbl_list->num_pbl_pages; + + DMA_REGPAIR_LE(p_cnq_params->pbl_base_addr, + p_cnq_pbl_list->pbl_ptr); + + /* we assume here that cnq_id and qz_offset are the same */ + p_cnq_params->queue_zone_num = + cpu_to_le16(p_hwfn->p_rdma_info->queue_zone_base + + cnq_id); + } + + return qed_spq_post(p_hwfn, p_ent, NULL); +} + +static int qed_rdma_alloc_tid(void *rdma_cxt, u32 *itid) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID\n"); + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + rc = qed_rdma_bmap_alloc_id(p_hwfn, + &p_hwfn->p_rdma_info->tid_map, itid); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + if (rc) + goto out; + + rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_TASK, *itid); +out: + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID - done, rc = %d\n", rc); + return rc; +} + +static int qed_rdma_reserve_lkey(struct qed_hwfn *p_hwfn) +{ + struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev; + + /* The first DPI is reserved for the Kernel */ + __set_bit(0, p_hwfn->p_rdma_info->dpi_map.bitmap); + + /* Tid 0 will be used as the key for "reserved MR". + * The driver should allocate memory for it so it can be loaded but no + * ramrod should be passed on it. + */ + qed_rdma_alloc_tid(p_hwfn, &dev->reserved_lkey); + if (dev->reserved_lkey != RDMA_RESERVED_LKEY) { + DP_NOTICE(p_hwfn, + "Reserved lkey should be equal to RDMA_RESERVED_LKEY\n"); + return -EINVAL; + } + + return 0; +} + +static int qed_rdma_setup(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_rdma_start_in_params *params) +{ + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA setup\n"); + + spin_lock_init(&p_hwfn->p_rdma_info->lock); + + qed_rdma_init_devinfo(p_hwfn, params); + qed_rdma_init_port(p_hwfn); + qed_rdma_init_events(p_hwfn, params); + + rc = qed_rdma_reserve_lkey(p_hwfn); + if (rc) + return rc; + + rc = qed_rdma_init_hw(p_hwfn, p_ptt); + if (rc) + return rc; + + qed_spq_register_async_cb(p_hwfn, PROTOCOLID_ROCE, + qed_roce_async_event); + + return qed_rdma_start_fw(p_hwfn, params, p_ptt); +} + +void qed_roce_stop(struct qed_hwfn *p_hwfn) +{ + struct qed_bmap *rcid_map = &p_hwfn->p_rdma_info->real_cid_map; + int wait_count = 0; + + /* when destroying a_RoCE QP the control is returned to the user after + * the synchronous part. The asynchronous part may take a little longer. + * We delay for a short while if an async destroy QP is still expected. + * Beyond the added delay we clear the bitmap anyway. + */ + while (bitmap_weight(rcid_map->bitmap, rcid_map->max_count)) { + msleep(100); + if (wait_count++ > 20) { + DP_NOTICE(p_hwfn, "cid bitmap wait timed out\n"); + break; + } + } + qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_ROCE); +} + +static int qed_rdma_stop(void *rdma_cxt) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct rdma_close_func_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + struct qed_ptt *p_ptt; + u32 ll2_ethertype_en; + int rc = -EBUSY; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA stop\n"); + + p_ptt = qed_ptt_acquire(p_hwfn); + if (!p_ptt) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Failed to acquire PTT\n"); + return rc; + } + + /* Disable RoCE search */ + qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 0); + p_hwfn->b_rdma_enabled_in_prs = false; + + qed_wr(p_hwfn, p_ptt, PRS_REG_ROCE_DEST_QP_MAX_PF, 0); + + ll2_ethertype_en = qed_rd(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN); + + qed_wr(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN, + (ll2_ethertype_en & 0xFFFE)); + + qed_roce_stop(p_hwfn); + qed_ptt_release(p_hwfn, p_ptt); + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + /* Stop RoCE */ + rc = qed_sp_init_request(p_hwfn, &p_ent, RDMA_RAMROD_FUNC_CLOSE, + p_hwfn->p_rdma_info->proto, &init_data); + if (rc) + goto out; + + p_ramrod = &p_ent->ramrod.rdma_close_func; + + p_ramrod->num_cnqs = p_hwfn->p_rdma_info->num_cnqs; + p_ramrod->cnq_start_offset = (u8)RESC_START(p_hwfn, QED_RDMA_CNQ_RAM); + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + +out: + qed_rdma_free(p_hwfn); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA stop done, rc = %d\n", rc); + return rc; +} + +static int qed_rdma_add_user(void *rdma_cxt, + struct qed_rdma_add_user_out_params *out_params) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + u32 dpi_start_offset; + u32 returned_id = 0; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Adding User\n"); + + /* Allocate DPI */ + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + rc = qed_rdma_bmap_alloc_id(p_hwfn, &p_hwfn->p_rdma_info->dpi_map, + &returned_id); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + + out_params->dpi = (u16)returned_id; + + /* Calculate the corresponding DPI address */ + dpi_start_offset = p_hwfn->dpi_start_offset; + + out_params->dpi_addr = (u64)((u8 __iomem *)p_hwfn->doorbells + + dpi_start_offset + + ((out_params->dpi) * p_hwfn->dpi_size)); + + out_params->dpi_phys_addr = p_hwfn->cdev->db_phys_addr + + dpi_start_offset + + ((out_params->dpi) * p_hwfn->dpi_size); + + out_params->dpi_size = p_hwfn->dpi_size; + out_params->wid_count = p_hwfn->wid_count; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Adding user - done, rc = %d\n", rc); + return rc; +} + +static struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct qed_rdma_port *p_port = p_hwfn->p_rdma_info->port; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA Query port\n"); + + /* Link may have changed */ + p_port->port_state = p_hwfn->mcp_info->link_output.link_up ? + QED_RDMA_PORT_UP : QED_RDMA_PORT_DOWN; + + p_port->link_speed = p_hwfn->mcp_info->link_output.speed; + + p_port->max_msg_size = RDMA_MAX_DATA_SIZE_IN_WQE; + + return p_port; +} + +static struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Query device\n"); + + /* Return struct with device parameters */ + return p_hwfn->p_rdma_info->dev; +} + +static void qed_rdma_free_tid(void *rdma_cxt, u32 itid) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "itid = %08x\n", itid); + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->tid_map, itid); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); +} + +static void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 qz_offset, u16 prod) +{ + struct qed_hwfn *p_hwfn; + u16 qz_num; + u32 addr; + + p_hwfn = (struct qed_hwfn *)rdma_cxt; + + if (qz_offset > p_hwfn->p_rdma_info->max_queue_zones) { + DP_NOTICE(p_hwfn, + "queue zone offset %d is too large (max is %d)\n", + qz_offset, p_hwfn->p_rdma_info->max_queue_zones); + return; + } + + qz_num = p_hwfn->p_rdma_info->queue_zone_base + qz_offset; + addr = GTT_BAR0_MAP_REG_USDM_RAM + + USTORM_COMMON_QUEUE_CONS_OFFSET(qz_num); + + REG_WR16(p_hwfn, addr, prod); + + /* keep prod updates ordered */ + wmb(); +} + +static int qed_fill_rdma_dev_info(struct qed_dev *cdev, + struct qed_dev_rdma_info *info) +{ + struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); + + memset(info, 0, sizeof(*info)); + + info->rdma_type = QED_RDMA_TYPE_ROCE; + info->user_dpm_enabled = (p_hwfn->db_bar_no_edpm == 0); + + qed_fill_dev_info(cdev, &info->common); + + return 0; +} + +static int qed_rdma_get_sb_start(struct qed_dev *cdev) +{ + int feat_num; + + if (cdev->num_hwfns > 1) + feat_num = FEAT_NUM(QED_LEADING_HWFN(cdev), QED_PF_L2_QUE); + else + feat_num = FEAT_NUM(QED_LEADING_HWFN(cdev), QED_PF_L2_QUE) * + cdev->num_hwfns; + + return feat_num; +} + +static int qed_rdma_get_min_cnq_msix(struct qed_dev *cdev) +{ + int n_cnq = FEAT_NUM(QED_LEADING_HWFN(cdev), QED_RDMA_CNQ); + int n_msix = cdev->int_params.rdma_msix_cnt; + + return min_t(int, n_cnq, n_msix); +} + +static int qed_rdma_set_int(struct qed_dev *cdev, u16 cnt) +{ + int limit = 0; + + /* Mark the fastpath as free/used */ + cdev->int_params.fp_initialized = cnt ? true : false; + + if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) { + DP_ERR(cdev, + "qed roce supports only MSI-X interrupts (detected %d).\n", + cdev->int_params.out.int_mode); + return -EINVAL; + } else if (cdev->int_params.fp_msix_cnt) { + limit = cdev->int_params.rdma_msix_cnt; + } + + if (!limit) + return -ENOMEM; + + return min_t(int, cnt, limit); +} + +static int qed_rdma_get_int(struct qed_dev *cdev, struct qed_int_info *info) +{ + memset(info, 0, sizeof(*info)); + + if (!cdev->int_params.fp_initialized) { + DP_INFO(cdev, + "Protocol driver requested interrupt information, but its support is not yet configured\n"); + return -EINVAL; + } + + if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { + int msix_base = cdev->int_params.rdma_msix_base; + + info->msix_cnt = cdev->int_params.rdma_msix_cnt; + info->msix = &cdev->int_params.msix_table[msix_base]; + + DP_VERBOSE(cdev, QED_MSG_RDMA, "msix_cnt = %d msix_base=%d\n", + info->msix_cnt, msix_base); + } + + return 0; +} + +static int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + u32 returned_id; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Alloc PD\n"); + + /* Allocates an unused protection domain */ + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + rc = qed_rdma_bmap_alloc_id(p_hwfn, + &p_hwfn->p_rdma_info->pd_map, &returned_id); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + + *pd = (u16)returned_id; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Alloc PD - done, rc = %d\n", rc); + return rc; +} + +static void qed_rdma_free_pd(void *rdma_cxt, u16 pd) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "pd = %08x\n", pd); + + /* Returns a previously allocated protection domain for reuse */ + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->pd_map, pd); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); +} + +static enum qed_rdma_toggle_bit +qed_rdma_toggle_bit_create_resize_cq(struct qed_hwfn *p_hwfn, u16 icid) +{ + struct qed_rdma_info *p_info = p_hwfn->p_rdma_info; + enum qed_rdma_toggle_bit toggle_bit; + u32 bmap_id; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", icid); + + /* the function toggle the bit that is related to a given icid + * and returns the new toggle bit's value + */ + bmap_id = icid - qed_cxt_get_proto_cid_start(p_hwfn, p_info->proto); + + spin_lock_bh(&p_info->lock); + toggle_bit = !test_and_change_bit(bmap_id, + p_info->toggle_bits.bitmap); + spin_unlock_bh(&p_info->lock); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QED_RDMA_TOGGLE_BIT_= %d\n", + toggle_bit); + + return toggle_bit; +} + +static int qed_rdma_create_cq(void *rdma_cxt, + struct qed_rdma_create_cq_in_params *params, + u16 *icid) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct qed_rdma_info *p_info = p_hwfn->p_rdma_info; + struct rdma_create_cq_ramrod_data *p_ramrod; + enum qed_rdma_toggle_bit toggle_bit; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + u32 returned_id, start_cid; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "cq_handle = %08x%08x\n", + params->cq_handle_hi, params->cq_handle_lo); + + /* Allocate icid */ + spin_lock_bh(&p_info->lock); + rc = qed_rdma_bmap_alloc_id(p_hwfn, &p_info->cq_map, &returned_id); + spin_unlock_bh(&p_info->lock); + + if (rc) { + DP_NOTICE(p_hwfn, "Can't create CQ, rc = %d\n", rc); + return rc; + } + + start_cid = qed_cxt_get_proto_cid_start(p_hwfn, + p_info->proto); + *icid = returned_id + start_cid; + + /* Check if icid requires a page allocation */ + rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_CXT, *icid); + if (rc) + goto err; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = *icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + /* Send create CQ ramrod */ + rc = qed_sp_init_request(p_hwfn, &p_ent, + RDMA_RAMROD_CREATE_CQ, + p_info->proto, &init_data); + if (rc) + goto err; + + p_ramrod = &p_ent->ramrod.rdma_create_cq; + + p_ramrod->cq_handle.hi = cpu_to_le32(params->cq_handle_hi); + p_ramrod->cq_handle.lo = cpu_to_le32(params->cq_handle_lo); + p_ramrod->dpi = cpu_to_le16(params->dpi); + p_ramrod->is_two_level_pbl = params->pbl_two_level; + p_ramrod->max_cqes = cpu_to_le32(params->cq_size); + DMA_REGPAIR_LE(p_ramrod->pbl_addr, params->pbl_ptr); + p_ramrod->pbl_num_pages = cpu_to_le16(params->pbl_num_pages); + p_ramrod->cnq_id = (u8)RESC_START(p_hwfn, QED_RDMA_CNQ_RAM) + + params->cnq_id; + p_ramrod->int_timeout = params->int_timeout; + + /* toggle the bit for every resize or create cq for a given icid */ + toggle_bit = qed_rdma_toggle_bit_create_resize_cq(p_hwfn, *icid); + + p_ramrod->toggle_bit = toggle_bit; + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + if (rc) { + /* restore toggle bit */ + qed_rdma_toggle_bit_create_resize_cq(p_hwfn, *icid); + goto err; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Created CQ, rc = %d\n", rc); + return rc; + +err: + /* release allocated icid */ + spin_lock_bh(&p_info->lock); + qed_bmap_release_id(p_hwfn, &p_info->cq_map, returned_id); + spin_unlock_bh(&p_info->lock); + DP_NOTICE(p_hwfn, "Create CQ failed, rc = %d\n", rc); + + return rc; +} + +static int +qed_rdma_destroy_cq(void *rdma_cxt, + struct qed_rdma_destroy_cq_in_params *in_params, + struct qed_rdma_destroy_cq_out_params *out_params) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct rdma_destroy_cq_output_params *p_ramrod_res; + struct rdma_destroy_cq_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + dma_addr_t ramrod_res_phys; + enum protocol_type proto; + int rc = -ENOMEM; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", in_params->icid); + + p_ramrod_res = + (struct rdma_destroy_cq_output_params *) + dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(struct rdma_destroy_cq_output_params), + &ramrod_res_phys, GFP_KERNEL); + if (!p_ramrod_res) { + DP_NOTICE(p_hwfn, + "qed destroy cq failed: cannot allocate memory (ramrod)\n"); + return rc; + } + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = in_params->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + proto = p_hwfn->p_rdma_info->proto; + /* Send destroy CQ ramrod */ + rc = qed_sp_init_request(p_hwfn, &p_ent, + RDMA_RAMROD_DESTROY_CQ, + proto, &init_data); + if (rc) + goto err; + + p_ramrod = &p_ent->ramrod.rdma_destroy_cq; + DMA_REGPAIR_LE(p_ramrod->output_params_addr, ramrod_res_phys); + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + if (rc) + goto err; + + out_params->num_cq_notif = le16_to_cpu(p_ramrod_res->cnq_num); + + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(struct rdma_destroy_cq_output_params), + p_ramrod_res, ramrod_res_phys); + + /* Free icid */ + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + + qed_bmap_release_id(p_hwfn, + &p_hwfn->p_rdma_info->cq_map, + (in_params->icid - + qed_cxt_get_proto_cid_start(p_hwfn, proto))); + + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Destroyed CQ, rc = %d\n", rc); + return rc; + +err: dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(struct rdma_destroy_cq_output_params), + p_ramrod_res, ramrod_res_phys); + + return rc; +} + +static void qed_rdma_set_fw_mac(u16 *p_fw_mac, u8 *p_qed_mac) +{ + p_fw_mac[0] = cpu_to_le16((p_qed_mac[0] << 8) + p_qed_mac[1]); + p_fw_mac[1] = cpu_to_le16((p_qed_mac[2] << 8) + p_qed_mac[3]); + p_fw_mac[2] = cpu_to_le16((p_qed_mac[4] << 8) + p_qed_mac[5]); +} + +static void qed_rdma_copy_gids(struct qed_rdma_qp *qp, __le32 *src_gid, + __le32 *dst_gid) +{ + u32 i; + + if (qp->roce_mode == ROCE_V2_IPV4) { + /* The IPv4 addresses shall be aligned to the highest word. + * The lower words must be zero. + */ + memset(src_gid, 0, sizeof(union qed_gid)); + memset(dst_gid, 0, sizeof(union qed_gid)); + src_gid[3] = cpu_to_le32(qp->sgid.ipv4_addr); + dst_gid[3] = cpu_to_le32(qp->dgid.ipv4_addr); + } else { + /* GIDs and IPv6 addresses coincide in location and size */ + for (i = 0; i < ARRAY_SIZE(qp->sgid.dwords); i++) { + src_gid[i] = cpu_to_le32(qp->sgid.dwords[i]); + dst_gid[i] = cpu_to_le32(qp->dgid.dwords[i]); + } + } +} + +static enum roce_flavor qed_roce_mode_to_flavor(enum roce_mode roce_mode) +{ + enum roce_flavor flavor; + + switch (roce_mode) { + case ROCE_V1: + flavor = PLAIN_ROCE; + break; + case ROCE_V2_IPV4: + flavor = RROCE_IPV4; + break; + case ROCE_V2_IPV6: + flavor = ROCE_V2_IPV6; + break; + default: + flavor = MAX_ROCE_MODE; + break; + } + return flavor; +} + +void qed_roce_free_cid_pair(struct qed_hwfn *p_hwfn, u16 cid) +{ + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->cid_map, cid); + qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->cid_map, cid + 1); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); +} + +static int qed_roce_alloc_cid(struct qed_hwfn *p_hwfn, u16 *cid) +{ + struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; + u32 responder_icid; + u32 requester_icid; + int rc; + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + rc = qed_rdma_bmap_alloc_id(p_hwfn, &p_rdma_info->cid_map, + &responder_icid); + if (rc) { + spin_unlock_bh(&p_rdma_info->lock); + return rc; + } + + rc = qed_rdma_bmap_alloc_id(p_hwfn, &p_rdma_info->cid_map, + &requester_icid); + + spin_unlock_bh(&p_rdma_info->lock); + if (rc) + goto err; + + /* the two icid's should be adjacent */ + if ((requester_icid - responder_icid) != 1) { + DP_NOTICE(p_hwfn, "Failed to allocate two adjacent qp's'\n"); + rc = -EINVAL; + goto err; + } + + responder_icid += qed_cxt_get_proto_cid_start(p_hwfn, + p_rdma_info->proto); + requester_icid += qed_cxt_get_proto_cid_start(p_hwfn, + p_rdma_info->proto); + + /* If these icids require a new ILT line allocate DMA-able context for + * an ILT page + */ + rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_CXT, responder_icid); + if (rc) + goto err; + + rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_CXT, requester_icid); + if (rc) + goto err; + + *cid = (u16)responder_icid; + return rc; + +err: + spin_lock_bh(&p_rdma_info->lock); + qed_bmap_release_id(p_hwfn, &p_rdma_info->cid_map, responder_icid); + qed_bmap_release_id(p_hwfn, &p_rdma_info->cid_map, requester_icid); + + spin_unlock_bh(&p_rdma_info->lock); + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Allocate CID - failed, rc = %d\n", rc); + return rc; +} + +static void qed_roce_set_real_cid(struct qed_hwfn *p_hwfn, u32 cid) +{ + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + qed_bmap_set_id(p_hwfn, &p_hwfn->p_rdma_info->real_cid_map, cid); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); +} + +static int qed_roce_sp_create_responder(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp) +{ + struct roce_create_qp_resp_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + enum roce_flavor roce_flavor; + struct qed_spq_entry *p_ent; + u16 regular_latency_queue; + enum protocol_type proto; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); + + /* Allocate DMA-able memory for IRQ */ + qp->irq_num_pages = 1; + qp->irq = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + RDMA_RING_PAGE_SIZE, + &qp->irq_phys_addr, GFP_KERNEL); + if (!qp->irq) { + rc = -ENOMEM; + DP_NOTICE(p_hwfn, + "qed create responder failed: cannot allocate memory (irq). rc = %d\n", + rc); + return rc; + } + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, ROCE_RAMROD_CREATE_QP, + PROTOCOLID_ROCE, &init_data); + if (rc) + goto err; + + p_ramrod = &p_ent->ramrod.roce_create_qp_resp; + + p_ramrod->flags = 0; + + roce_flavor = qed_roce_mode_to_flavor(qp->roce_mode); + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_RESP_RAMROD_DATA_ROCE_FLAVOR, roce_flavor); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_RESP_RAMROD_DATA_RDMA_RD_EN, + qp->incoming_rdma_read_en); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_RESP_RAMROD_DATA_RDMA_WR_EN, + qp->incoming_rdma_write_en); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_RESP_RAMROD_DATA_ATOMIC_EN, + qp->incoming_atomic_en); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_RESP_RAMROD_DATA_E2E_FLOW_CONTROL_EN, + qp->e2e_flow_control_en); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_RESP_RAMROD_DATA_SRQ_FLG, qp->use_srq); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_RESP_RAMROD_DATA_RESERVED_KEY_EN, + qp->fmr_and_reserved_lkey); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER, + qp->min_rnr_nak_timer); + + p_ramrod->max_ird = qp->max_rd_atomic_resp; + p_ramrod->traffic_class = qp->traffic_class_tos; + p_ramrod->hop_limit = qp->hop_limit_ttl; + p_ramrod->irq_num_pages = qp->irq_num_pages; + p_ramrod->p_key = cpu_to_le16(qp->pkey); + p_ramrod->flow_label = cpu_to_le32(qp->flow_label); + p_ramrod->dst_qp_id = cpu_to_le32(qp->dest_qp); + p_ramrod->mtu = cpu_to_le16(qp->mtu); + p_ramrod->initial_psn = cpu_to_le32(qp->rq_psn); + p_ramrod->pd = cpu_to_le16(qp->pd); + p_ramrod->rq_num_pages = cpu_to_le16(qp->rq_num_pages); + DMA_REGPAIR_LE(p_ramrod->rq_pbl_addr, qp->rq_pbl_ptr); + DMA_REGPAIR_LE(p_ramrod->irq_pbl_addr, qp->irq_phys_addr); + qed_rdma_copy_gids(qp, p_ramrod->src_gid, p_ramrod->dst_gid); + p_ramrod->qp_handle_for_async.hi = cpu_to_le32(qp->qp_handle_async.hi); + p_ramrod->qp_handle_for_async.lo = cpu_to_le32(qp->qp_handle_async.lo); + p_ramrod->qp_handle_for_cqe.hi = cpu_to_le32(qp->qp_handle.hi); + p_ramrod->qp_handle_for_cqe.lo = cpu_to_le32(qp->qp_handle.lo); + p_ramrod->cq_cid = cpu_to_le32((p_hwfn->hw_info.opaque_fid << 16) | + qp->rq_cq_id); + + regular_latency_queue = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD); + + p_ramrod->regular_latency_phy_queue = + cpu_to_le16(regular_latency_queue); + p_ramrod->low_latency_phy_queue = + cpu_to_le16(regular_latency_queue); + + p_ramrod->dpi = cpu_to_le16(qp->dpi); + + qed_rdma_set_fw_mac(p_ramrod->remote_mac_addr, qp->remote_mac_addr); + qed_rdma_set_fw_mac(p_ramrod->local_mac_addr, qp->local_mac_addr); + + p_ramrod->udp_src_port = qp->udp_src_port; + p_ramrod->vlan_id = cpu_to_le16(qp->vlan_id); + p_ramrod->srq_id.srq_idx = cpu_to_le16(qp->srq_id); + p_ramrod->srq_id.opaque_fid = cpu_to_le16(p_hwfn->hw_info.opaque_fid); + + p_ramrod->stats_counter_id = RESC_START(p_hwfn, QED_RDMA_STATS_QUEUE) + + qp->stats_queue; + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "rc = %d regular physical queue = 0x%x\n", rc, + regular_latency_queue); + + if (rc) + goto err; + + qp->resp_offloaded = true; + qp->cq_prod = 0; + + proto = p_hwfn->p_rdma_info->proto; + qed_roce_set_real_cid(p_hwfn, qp->icid - + qed_cxt_get_proto_cid_start(p_hwfn, proto)); + + return rc; + +err: + DP_NOTICE(p_hwfn, "create responder - failed, rc = %d\n", rc); + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + qp->irq_num_pages * RDMA_RING_PAGE_SIZE, + qp->irq, qp->irq_phys_addr); + + return rc; +} + +static int qed_roce_sp_create_requester(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp) +{ + struct roce_create_qp_req_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + enum roce_flavor roce_flavor; + struct qed_spq_entry *p_ent; + u16 regular_latency_queue; + enum protocol_type proto; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); + + /* Allocate DMA-able memory for ORQ */ + qp->orq_num_pages = 1; + qp->orq = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + RDMA_RING_PAGE_SIZE, + &qp->orq_phys_addr, GFP_KERNEL); + if (!qp->orq) { + rc = -ENOMEM; + DP_NOTICE(p_hwfn, + "qed create requester failed: cannot allocate memory (orq). rc = %d\n", + rc); + return rc; + } + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid + 1; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + ROCE_RAMROD_CREATE_QP, + PROTOCOLID_ROCE, &init_data); + if (rc) + goto err; + + p_ramrod = &p_ent->ramrod.roce_create_qp_req; + + p_ramrod->flags = 0; + + roce_flavor = qed_roce_mode_to_flavor(qp->roce_mode); + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_REQ_RAMROD_DATA_ROCE_FLAVOR, roce_flavor); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_REQ_RAMROD_DATA_FMR_AND_RESERVED_EN, + qp->fmr_and_reserved_lkey); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_REQ_RAMROD_DATA_SIGNALED_COMP, qp->signal_all); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT, qp->retry_cnt); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_REQ_RAMROD_DATA_RNR_NAK_CNT, + qp->rnr_retry_cnt); + + p_ramrod->max_ord = qp->max_rd_atomic_req; + p_ramrod->traffic_class = qp->traffic_class_tos; + p_ramrod->hop_limit = qp->hop_limit_ttl; + p_ramrod->orq_num_pages = qp->orq_num_pages; + p_ramrod->p_key = cpu_to_le16(qp->pkey); + p_ramrod->flow_label = cpu_to_le32(qp->flow_label); + p_ramrod->dst_qp_id = cpu_to_le32(qp->dest_qp); + p_ramrod->ack_timeout_val = cpu_to_le32(qp->ack_timeout); + p_ramrod->mtu = cpu_to_le16(qp->mtu); + p_ramrod->initial_psn = cpu_to_le32(qp->sq_psn); + p_ramrod->pd = cpu_to_le16(qp->pd); + p_ramrod->sq_num_pages = cpu_to_le16(qp->sq_num_pages); + DMA_REGPAIR_LE(p_ramrod->sq_pbl_addr, qp->sq_pbl_ptr); + DMA_REGPAIR_LE(p_ramrod->orq_pbl_addr, qp->orq_phys_addr); + qed_rdma_copy_gids(qp, p_ramrod->src_gid, p_ramrod->dst_gid); + p_ramrod->qp_handle_for_async.hi = cpu_to_le32(qp->qp_handle_async.hi); + p_ramrod->qp_handle_for_async.lo = cpu_to_le32(qp->qp_handle_async.lo); + p_ramrod->qp_handle_for_cqe.hi = cpu_to_le32(qp->qp_handle.hi); + p_ramrod->qp_handle_for_cqe.lo = cpu_to_le32(qp->qp_handle.lo); + p_ramrod->cq_cid = + cpu_to_le32((p_hwfn->hw_info.opaque_fid << 16) | qp->sq_cq_id); + + regular_latency_queue = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD); + + p_ramrod->regular_latency_phy_queue = + cpu_to_le16(regular_latency_queue); + p_ramrod->low_latency_phy_queue = + cpu_to_le16(regular_latency_queue); + + p_ramrod->dpi = cpu_to_le16(qp->dpi); + + qed_rdma_set_fw_mac(p_ramrod->remote_mac_addr, qp->remote_mac_addr); + qed_rdma_set_fw_mac(p_ramrod->local_mac_addr, qp->local_mac_addr); + + p_ramrod->udp_src_port = qp->udp_src_port; + p_ramrod->vlan_id = cpu_to_le16(qp->vlan_id); + p_ramrod->stats_counter_id = RESC_START(p_hwfn, QED_RDMA_STATS_QUEUE) + + qp->stats_queue; + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); + + if (rc) + goto err; + + qp->req_offloaded = true; + proto = p_hwfn->p_rdma_info->proto; + qed_roce_set_real_cid(p_hwfn, + qp->icid + 1 - + qed_cxt_get_proto_cid_start(p_hwfn, proto)); + + return rc; + +err: + DP_NOTICE(p_hwfn, "Create requested - failed, rc = %d\n", rc); + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + qp->orq_num_pages * RDMA_RING_PAGE_SIZE, + qp->orq, qp->orq_phys_addr); + return rc; +} + +static int qed_roce_sp_modify_responder(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + bool move_to_err, u32 modify_flags) +{ + struct roce_modify_qp_resp_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); + + if (move_to_err && !qp->resp_offloaded) + return 0; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + ROCE_EVENT_MODIFY_QP, + PROTOCOLID_ROCE, &init_data); + if (rc) { + DP_NOTICE(p_hwfn, "rc = %d\n", rc); + return rc; + } + + p_ramrod = &p_ent->ramrod.roce_modify_qp_resp; + + p_ramrod->flags = 0; + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_MOVE_TO_ERR_FLG, move_to_err); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_RD_EN, + qp->incoming_rdma_read_en); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_WR_EN, + qp->incoming_rdma_write_en); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_ATOMIC_EN, + qp->incoming_atomic_en); + + SET_FIELD(p_ramrod->flags, + ROCE_CREATE_QP_RESP_RAMROD_DATA_E2E_FLOW_CONTROL_EN, + qp->e2e_flow_control_en); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_OPS_EN_FLG, + GET_FIELD(modify_flags, + QED_RDMA_MODIFY_QP_VALID_RDMA_OPS_EN)); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_P_KEY_FLG, + GET_FIELD(modify_flags, QED_ROCE_MODIFY_QP_VALID_PKEY)); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_ADDRESS_VECTOR_FLG, + GET_FIELD(modify_flags, + QED_ROCE_MODIFY_QP_VALID_ADDRESS_VECTOR)); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_MAX_IRD_FLG, + GET_FIELD(modify_flags, + QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_RESP)); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER_FLG, + GET_FIELD(modify_flags, + QED_ROCE_MODIFY_QP_VALID_MIN_RNR_NAK_TIMER)); + + p_ramrod->fields = 0; + SET_FIELD(p_ramrod->fields, + ROCE_MODIFY_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER, + qp->min_rnr_nak_timer); + + p_ramrod->max_ird = qp->max_rd_atomic_resp; + p_ramrod->traffic_class = qp->traffic_class_tos; + p_ramrod->hop_limit = qp->hop_limit_ttl; + p_ramrod->p_key = cpu_to_le16(qp->pkey); + p_ramrod->flow_label = cpu_to_le32(qp->flow_label); + p_ramrod->mtu = cpu_to_le16(qp->mtu); + qed_rdma_copy_gids(qp, p_ramrod->src_gid, p_ramrod->dst_gid); + rc = qed_spq_post(p_hwfn, p_ent, NULL); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Modify responder, rc = %d\n", rc); + return rc; +} + +static int qed_roce_sp_modify_requester(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + bool move_to_sqd, + bool move_to_err, u32 modify_flags) +{ + struct roce_modify_qp_req_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); + + if (move_to_err && !(qp->req_offloaded)) + return 0; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid + 1; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + ROCE_EVENT_MODIFY_QP, + PROTOCOLID_ROCE, &init_data); + if (rc) { + DP_NOTICE(p_hwfn, "rc = %d\n", rc); + return rc; + } + + p_ramrod = &p_ent->ramrod.roce_modify_qp_req; + + p_ramrod->flags = 0; + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_MOVE_TO_ERR_FLG, move_to_err); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_MOVE_TO_SQD_FLG, move_to_sqd); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_EN_SQD_ASYNC_NOTIFY, + qp->sqd_async); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_P_KEY_FLG, + GET_FIELD(modify_flags, QED_ROCE_MODIFY_QP_VALID_PKEY)); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_ADDRESS_VECTOR_FLG, + GET_FIELD(modify_flags, + QED_ROCE_MODIFY_QP_VALID_ADDRESS_VECTOR)); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_MAX_ORD_FLG, + GET_FIELD(modify_flags, + QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_REQ)); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_RNR_NAK_CNT_FLG, + GET_FIELD(modify_flags, + QED_ROCE_MODIFY_QP_VALID_RNR_RETRY_CNT)); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT_FLG, + GET_FIELD(modify_flags, QED_ROCE_MODIFY_QP_VALID_RETRY_CNT)); + + SET_FIELD(p_ramrod->flags, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_ACK_TIMEOUT_FLG, + GET_FIELD(modify_flags, + QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT)); + + p_ramrod->fields = 0; + SET_FIELD(p_ramrod->fields, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT, qp->retry_cnt); + + SET_FIELD(p_ramrod->fields, + ROCE_MODIFY_QP_REQ_RAMROD_DATA_RNR_NAK_CNT, + qp->rnr_retry_cnt); + + p_ramrod->max_ord = qp->max_rd_atomic_req; + p_ramrod->traffic_class = qp->traffic_class_tos; + p_ramrod->hop_limit = qp->hop_limit_ttl; + p_ramrod->p_key = cpu_to_le16(qp->pkey); + p_ramrod->flow_label = cpu_to_le32(qp->flow_label); + p_ramrod->ack_timeout_val = cpu_to_le32(qp->ack_timeout); + p_ramrod->mtu = cpu_to_le16(qp->mtu); + qed_rdma_copy_gids(qp, p_ramrod->src_gid, p_ramrod->dst_gid); + rc = qed_spq_post(p_hwfn, p_ent, NULL); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Modify requester, rc = %d\n", rc); + return rc; +} + +static int qed_roce_sp_destroy_qp_responder(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + u32 *num_invalidated_mw, + u32 *cq_prod) +{ + struct roce_destroy_qp_resp_output_params *p_ramrod_res; + struct roce_destroy_qp_resp_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + dma_addr_t ramrod_res_phys; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); + + *num_invalidated_mw = 0; + *cq_prod = qp->cq_prod; + + if (!qp->resp_offloaded) { + /* If a responder was never offload, we need to free the cids + * allocated in create_qp as a FW async event will never arrive + */ + u32 cid; + + cid = qp->icid - + qed_cxt_get_proto_cid_start(p_hwfn, + p_hwfn->p_rdma_info->proto); + qed_roce_free_cid_pair(p_hwfn, (u16)cid); + + return 0; + } + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + ROCE_RAMROD_DESTROY_QP, + PROTOCOLID_ROCE, &init_data); + if (rc) + return rc; + + p_ramrod = &p_ent->ramrod.roce_destroy_qp_resp; + + p_ramrod_res = (struct roce_destroy_qp_resp_output_params *) + dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_ramrod_res), + &ramrod_res_phys, GFP_KERNEL); + + if (!p_ramrod_res) { + rc = -ENOMEM; + DP_NOTICE(p_hwfn, + "qed destroy responder failed: cannot allocate memory (ramrod). rc = %d\n", + rc); + return rc; + } + + DMA_REGPAIR_LE(p_ramrod->output_params_addr, ramrod_res_phys); + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + if (rc) + goto err; + + *num_invalidated_mw = le32_to_cpu(p_ramrod_res->num_invalidated_mw); + *cq_prod = le32_to_cpu(p_ramrod_res->cq_prod); + qp->cq_prod = *cq_prod; + + /* Free IRQ - only if ramrod succeeded, in case FW is still using it */ + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + qp->irq_num_pages * RDMA_RING_PAGE_SIZE, + qp->irq, qp->irq_phys_addr); + + qp->resp_offloaded = false; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Destroy responder, rc = %d\n", rc); + +err: + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(struct roce_destroy_qp_resp_output_params), + p_ramrod_res, ramrod_res_phys); + + return rc; +} + +static int qed_roce_sp_destroy_qp_requester(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + u32 *num_bound_mw) +{ + struct roce_destroy_qp_req_output_params *p_ramrod_res; + struct roce_destroy_qp_req_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + dma_addr_t ramrod_res_phys; + int rc = -ENOMEM; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); + + if (!qp->req_offloaded) + return 0; + + p_ramrod_res = (struct roce_destroy_qp_req_output_params *) + dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(*p_ramrod_res), + &ramrod_res_phys, GFP_KERNEL); + if (!p_ramrod_res) { + DP_NOTICE(p_hwfn, + "qed destroy requester failed: cannot allocate memory (ramrod)\n"); + return rc; + } + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid + 1; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, ROCE_RAMROD_DESTROY_QP, + PROTOCOLID_ROCE, &init_data); + if (rc) + goto err; + + p_ramrod = &p_ent->ramrod.roce_destroy_qp_req; + DMA_REGPAIR_LE(p_ramrod->output_params_addr, ramrod_res_phys); + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + if (rc) + goto err; + + *num_bound_mw = le32_to_cpu(p_ramrod_res->num_bound_mw); + + /* Free ORQ - only if ramrod succeeded, in case FW is still using it */ + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + qp->orq_num_pages * RDMA_RING_PAGE_SIZE, + qp->orq, qp->orq_phys_addr); + + qp->req_offloaded = false; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Destroy requester, rc = %d\n", rc); + +err: + dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_ramrod_res), + p_ramrod_res, ramrod_res_phys); + + return rc; +} + +static int qed_roce_query_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + struct qed_rdma_query_qp_out_params *out_params) +{ + struct roce_query_qp_resp_output_params *p_resp_ramrod_res; + struct roce_query_qp_req_output_params *p_req_ramrod_res; + struct roce_query_qp_resp_ramrod_data *p_resp_ramrod; + struct roce_query_qp_req_ramrod_data *p_req_ramrod; + struct qed_sp_init_data init_data; + dma_addr_t resp_ramrod_res_phys; + dma_addr_t req_ramrod_res_phys; + struct qed_spq_entry *p_ent; + bool rq_err_state; + bool sq_err_state; + bool sq_draining; + int rc = -ENOMEM; + + if ((!(qp->resp_offloaded)) && (!(qp->req_offloaded))) { + /* We can't send ramrod to the fw since this qp wasn't offloaded + * to the fw yet + */ + out_params->draining = false; + out_params->rq_psn = qp->rq_psn; + out_params->sq_psn = qp->sq_psn; + out_params->state = qp->cur_state; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "No QPs as no offload\n"); + return 0; + } + + if (!(qp->resp_offloaded)) { + DP_NOTICE(p_hwfn, + "The responder's qp should be offloded before requester's\n"); + return -EINVAL; + } + + /* Send a query responder ramrod to FW to get RQ-PSN and state */ + p_resp_ramrod_res = (struct roce_query_qp_resp_output_params *) + dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(*p_resp_ramrod_res), + &resp_ramrod_res_phys, GFP_KERNEL); + if (!p_resp_ramrod_res) { + DP_NOTICE(p_hwfn, + "qed query qp failed: cannot allocate memory (ramrod)\n"); + return rc; + } + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + rc = qed_sp_init_request(p_hwfn, &p_ent, ROCE_RAMROD_QUERY_QP, + PROTOCOLID_ROCE, &init_data); + if (rc) + goto err_resp; + + p_resp_ramrod = &p_ent->ramrod.roce_query_qp_resp; + DMA_REGPAIR_LE(p_resp_ramrod->output_params_addr, resp_ramrod_res_phys); + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + if (rc) + goto err_resp; + + out_params->rq_psn = le32_to_cpu(p_resp_ramrod_res->psn); + rq_err_state = GET_FIELD(le32_to_cpu(p_resp_ramrod_res->err_flag), + ROCE_QUERY_QP_RESP_OUTPUT_PARAMS_ERROR_FLG); + + dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_resp_ramrod_res), + p_resp_ramrod_res, resp_ramrod_res_phys); + + if (!(qp->req_offloaded)) { + /* Don't send query qp for the requester */ + out_params->sq_psn = qp->sq_psn; + out_params->draining = false; + + if (rq_err_state) + qp->cur_state = QED_ROCE_QP_STATE_ERR; + + out_params->state = qp->cur_state; + + return 0; + } + + /* Send a query requester ramrod to FW to get SQ-PSN and state */ + p_req_ramrod_res = (struct roce_query_qp_req_output_params *) + dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(*p_req_ramrod_res), + &req_ramrod_res_phys, + GFP_KERNEL); + if (!p_req_ramrod_res) { + rc = -ENOMEM; + DP_NOTICE(p_hwfn, + "qed query qp failed: cannot allocate memory (ramrod)\n"); + return rc; + } + + /* Get SPQ entry */ + init_data.cid = qp->icid + 1; + rc = qed_sp_init_request(p_hwfn, &p_ent, ROCE_RAMROD_QUERY_QP, + PROTOCOLID_ROCE, &init_data); + if (rc) + goto err_req; + + p_req_ramrod = &p_ent->ramrod.roce_query_qp_req; + DMA_REGPAIR_LE(p_req_ramrod->output_params_addr, req_ramrod_res_phys); + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + if (rc) + goto err_req; + + out_params->sq_psn = le32_to_cpu(p_req_ramrod_res->psn); + sq_err_state = GET_FIELD(le32_to_cpu(p_req_ramrod_res->flags), + ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_ERR_FLG); + sq_draining = + GET_FIELD(le32_to_cpu(p_req_ramrod_res->flags), + ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_SQ_DRAINING_FLG); + + dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_req_ramrod_res), + p_req_ramrod_res, req_ramrod_res_phys); + + out_params->draining = false; + + if (rq_err_state || sq_err_state) + qp->cur_state = QED_ROCE_QP_STATE_ERR; + else if (sq_draining) + out_params->draining = true; + out_params->state = qp->cur_state; + + return 0; + +err_req: + dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_req_ramrod_res), + p_req_ramrod_res, req_ramrod_res_phys); + return rc; +err_resp: + dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_resp_ramrod_res), + p_resp_ramrod_res, resp_ramrod_res_phys); + return rc; +} + +static int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) +{ + u32 num_invalidated_mw = 0; + u32 num_bound_mw = 0; + u32 cq_prod; + int rc; + + /* Destroys the specified QP */ + if ((qp->cur_state != QED_ROCE_QP_STATE_RESET) && + (qp->cur_state != QED_ROCE_QP_STATE_ERR) && + (qp->cur_state != QED_ROCE_QP_STATE_INIT)) { + DP_NOTICE(p_hwfn, + "QP must be in error, reset or init state before destroying it\n"); + return -EINVAL; + } + + if (qp->cur_state != QED_ROCE_QP_STATE_RESET) { + rc = qed_roce_sp_destroy_qp_responder(p_hwfn, qp, + &num_invalidated_mw, + &cq_prod); + if (rc) + return rc; + + /* Send destroy requester ramrod */ + rc = qed_roce_sp_destroy_qp_requester(p_hwfn, qp, + &num_bound_mw); + if (rc) + return rc; + + if (num_invalidated_mw != num_bound_mw) { + DP_NOTICE(p_hwfn, + "number of invalidate memory windows is different from bounded ones\n"); + return -EINVAL; + } + } + + return 0; +} + +static int qed_rdma_query_qp(void *rdma_cxt, + struct qed_rdma_qp *qp, + struct qed_rdma_query_qp_out_params *out_params) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); + + /* The following fields are filled in from qp and not FW as they can't + * be modified by FW + */ + out_params->mtu = qp->mtu; + out_params->dest_qp = qp->dest_qp; + out_params->incoming_atomic_en = qp->incoming_atomic_en; + out_params->e2e_flow_control_en = qp->e2e_flow_control_en; + out_params->incoming_rdma_read_en = qp->incoming_rdma_read_en; + out_params->incoming_rdma_write_en = qp->incoming_rdma_write_en; + out_params->dgid = qp->dgid; + out_params->flow_label = qp->flow_label; + out_params->hop_limit_ttl = qp->hop_limit_ttl; + out_params->traffic_class_tos = qp->traffic_class_tos; + out_params->timeout = qp->ack_timeout; + out_params->rnr_retry = qp->rnr_retry_cnt; + out_params->retry_cnt = qp->retry_cnt; + out_params->min_rnr_nak_timer = qp->min_rnr_nak_timer; + out_params->pkey_index = 0; + out_params->max_rd_atomic = qp->max_rd_atomic_req; + out_params->max_dest_rd_atomic = qp->max_rd_atomic_resp; + out_params->sqd_async = qp->sqd_async; + + rc = qed_roce_query_qp(p_hwfn, qp, out_params); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Query QP, rc = %d\n", rc); + return rc; +} + +static int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + int rc = 0; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); + + rc = qed_roce_destroy_qp(p_hwfn, qp); + + /* free qp params struct */ + kfree(qp); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QP destroyed\n"); + return rc; +} + +static struct qed_rdma_qp * +qed_rdma_create_qp(void *rdma_cxt, + struct qed_rdma_create_qp_in_params *in_params, + struct qed_rdma_create_qp_out_params *out_params) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct qed_rdma_qp *qp; + u8 max_stats_queues; + int rc; + + if (!rdma_cxt || !in_params || !out_params || !p_hwfn->p_rdma_info) { + DP_ERR(p_hwfn->cdev, + "qed roce create qp failed due to NULL entry (rdma_cxt=%p, in=%p, out=%p, roce_info=?\n", + rdma_cxt, in_params, out_params); + return NULL; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "qed rdma create qp called with qp_handle = %08x%08x\n", + in_params->qp_handle_hi, in_params->qp_handle_lo); + + /* Some sanity checks... */ + max_stats_queues = p_hwfn->p_rdma_info->dev->max_stats_queues; + if (in_params->stats_queue >= max_stats_queues) { + DP_ERR(p_hwfn->cdev, + "qed rdma create qp failed due to invalid statistics queue %d. maximum is %d\n", + in_params->stats_queue, max_stats_queues); + return NULL; + } + + qp = kzalloc(sizeof(*qp), GFP_KERNEL); + if (!qp) + return NULL; + + rc = qed_roce_alloc_cid(p_hwfn, &qp->icid); + qp->qpid = ((0xFF << 16) | qp->icid); + + DP_INFO(p_hwfn, "ROCE qpid=%x\n", qp->qpid); + + if (rc) { + kfree(qp); + return NULL; + } + + qp->cur_state = QED_ROCE_QP_STATE_RESET; + qp->qp_handle.hi = cpu_to_le32(in_params->qp_handle_hi); + qp->qp_handle.lo = cpu_to_le32(in_params->qp_handle_lo); + qp->qp_handle_async.hi = cpu_to_le32(in_params->qp_handle_async_hi); + qp->qp_handle_async.lo = cpu_to_le32(in_params->qp_handle_async_lo); + qp->use_srq = in_params->use_srq; + qp->signal_all = in_params->signal_all; + qp->fmr_and_reserved_lkey = in_params->fmr_and_reserved_lkey; + qp->pd = in_params->pd; + qp->dpi = in_params->dpi; + qp->sq_cq_id = in_params->sq_cq_id; + qp->sq_num_pages = in_params->sq_num_pages; + qp->sq_pbl_ptr = in_params->sq_pbl_ptr; + qp->rq_cq_id = in_params->rq_cq_id; + qp->rq_num_pages = in_params->rq_num_pages; + qp->rq_pbl_ptr = in_params->rq_pbl_ptr; + qp->srq_id = in_params->srq_id; + qp->req_offloaded = false; + qp->resp_offloaded = false; + qp->e2e_flow_control_en = qp->use_srq ? false : true; + qp->stats_queue = in_params->stats_queue; + + out_params->icid = qp->icid; + out_params->qp_id = qp->qpid; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Create QP, rc = %d\n", rc); + return qp; +} + +static int qed_roce_modify_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + enum qed_roce_qp_state prev_state, + struct qed_rdma_modify_qp_in_params *params) +{ + u32 num_invalidated_mw = 0, num_bound_mw = 0; + int rc = 0; + + /* Perform additional operations according to the current state and the + * next state + */ + if (((prev_state == QED_ROCE_QP_STATE_INIT) || + (prev_state == QED_ROCE_QP_STATE_RESET)) && + (qp->cur_state == QED_ROCE_QP_STATE_RTR)) { + /* Init->RTR or Reset->RTR */ + rc = qed_roce_sp_create_responder(p_hwfn, qp); + return rc; + } else if ((prev_state == QED_ROCE_QP_STATE_RTR) && + (qp->cur_state == QED_ROCE_QP_STATE_RTS)) { + /* RTR-> RTS */ + rc = qed_roce_sp_create_requester(p_hwfn, qp); + if (rc) + return rc; + + /* Send modify responder ramrod */ + rc = qed_roce_sp_modify_responder(p_hwfn, qp, false, + params->modify_flags); + return rc; + } else if ((prev_state == QED_ROCE_QP_STATE_RTS) && + (qp->cur_state == QED_ROCE_QP_STATE_RTS)) { + /* RTS->RTS */ + rc = qed_roce_sp_modify_responder(p_hwfn, qp, false, + params->modify_flags); + if (rc) + return rc; + + rc = qed_roce_sp_modify_requester(p_hwfn, qp, false, false, + params->modify_flags); + return rc; + } else if ((prev_state == QED_ROCE_QP_STATE_RTS) && + (qp->cur_state == QED_ROCE_QP_STATE_SQD)) { + /* RTS->SQD */ + rc = qed_roce_sp_modify_requester(p_hwfn, qp, true, false, + params->modify_flags); + return rc; + } else if ((prev_state == QED_ROCE_QP_STATE_SQD) && + (qp->cur_state == QED_ROCE_QP_STATE_SQD)) { + /* SQD->SQD */ + rc = qed_roce_sp_modify_responder(p_hwfn, qp, false, + params->modify_flags); + if (rc) + return rc; + + rc = qed_roce_sp_modify_requester(p_hwfn, qp, false, false, + params->modify_flags); + return rc; + } else if ((prev_state == QED_ROCE_QP_STATE_SQD) && + (qp->cur_state == QED_ROCE_QP_STATE_RTS)) { + /* SQD->RTS */ + rc = qed_roce_sp_modify_responder(p_hwfn, qp, false, + params->modify_flags); + if (rc) + return rc; + + rc = qed_roce_sp_modify_requester(p_hwfn, qp, false, false, + params->modify_flags); + + return rc; + } else if (qp->cur_state == QED_ROCE_QP_STATE_ERR) { + /* ->ERR */ + rc = qed_roce_sp_modify_responder(p_hwfn, qp, true, + params->modify_flags); + if (rc) + return rc; + + rc = qed_roce_sp_modify_requester(p_hwfn, qp, false, true, + params->modify_flags); + return rc; + } else if (qp->cur_state == QED_ROCE_QP_STATE_RESET) { + /* Any state -> RESET */ + u32 cq_prod; + + /* Send destroy responder ramrod */ + rc = qed_roce_sp_destroy_qp_responder(p_hwfn, + qp, + &num_invalidated_mw, + &cq_prod); + + if (rc) + return rc; + + qp->cq_prod = cq_prod; + + rc = qed_roce_sp_destroy_qp_requester(p_hwfn, qp, + &num_bound_mw); + + if (num_invalidated_mw != num_bound_mw) { + DP_NOTICE(p_hwfn, + "number of invalidate memory windows is different from bounded ones\n"); + return -EINVAL; + } + } else { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "0\n"); + } + + return rc; +} + +static int qed_rdma_modify_qp(void *rdma_cxt, + struct qed_rdma_qp *qp, + struct qed_rdma_modify_qp_in_params *params) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + enum qed_roce_qp_state prev_state; + int rc = 0; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x params->new_state=%d\n", + qp->icid, params->new_state); + + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); + return rc; + } + + if (GET_FIELD(params->modify_flags, + QED_RDMA_MODIFY_QP_VALID_RDMA_OPS_EN)) { + qp->incoming_rdma_read_en = params->incoming_rdma_read_en; + qp->incoming_rdma_write_en = params->incoming_rdma_write_en; + qp->incoming_atomic_en = params->incoming_atomic_en; + } + + /* Update QP structure with the updated values */ + if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_ROCE_MODE)) + qp->roce_mode = params->roce_mode; + if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_PKEY)) + qp->pkey = params->pkey; + if (GET_FIELD(params->modify_flags, + QED_ROCE_MODIFY_QP_VALID_E2E_FLOW_CONTROL_EN)) + qp->e2e_flow_control_en = params->e2e_flow_control_en; + if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_DEST_QP)) + qp->dest_qp = params->dest_qp; + if (GET_FIELD(params->modify_flags, + QED_ROCE_MODIFY_QP_VALID_ADDRESS_VECTOR)) { + /* Indicates that the following parameters have changed: + * Traffic class, flow label, hop limit, source GID, + * destination GID, loopback indicator + */ + qp->traffic_class_tos = params->traffic_class_tos; + qp->flow_label = params->flow_label; + qp->hop_limit_ttl = params->hop_limit_ttl; + + qp->sgid = params->sgid; + qp->dgid = params->dgid; + qp->udp_src_port = 0; + qp->vlan_id = params->vlan_id; + qp->mtu = params->mtu; + qp->lb_indication = params->lb_indication; + memcpy((u8 *)&qp->remote_mac_addr[0], + (u8 *)¶ms->remote_mac_addr[0], ETH_ALEN); + if (params->use_local_mac) { + memcpy((u8 *)&qp->local_mac_addr[0], + (u8 *)¶ms->local_mac_addr[0], ETH_ALEN); + } else { + memcpy((u8 *)&qp->local_mac_addr[0], + (u8 *)&p_hwfn->hw_info.hw_mac_addr, ETH_ALEN); + } + } + if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_RQ_PSN)) + qp->rq_psn = params->rq_psn; + if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_SQ_PSN)) + qp->sq_psn = params->sq_psn; + if (GET_FIELD(params->modify_flags, + QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_REQ)) + qp->max_rd_atomic_req = params->max_rd_atomic_req; + if (GET_FIELD(params->modify_flags, + QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_RESP)) + qp->max_rd_atomic_resp = params->max_rd_atomic_resp; + if (GET_FIELD(params->modify_flags, + QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT)) + qp->ack_timeout = params->ack_timeout; + if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_RETRY_CNT)) + qp->retry_cnt = params->retry_cnt; + if (GET_FIELD(params->modify_flags, + QED_ROCE_MODIFY_QP_VALID_RNR_RETRY_CNT)) + qp->rnr_retry_cnt = params->rnr_retry_cnt; + if (GET_FIELD(params->modify_flags, + QED_ROCE_MODIFY_QP_VALID_MIN_RNR_NAK_TIMER)) + qp->min_rnr_nak_timer = params->min_rnr_nak_timer; + + qp->sqd_async = params->sqd_async; + + prev_state = qp->cur_state; + if (GET_FIELD(params->modify_flags, + QED_RDMA_MODIFY_QP_VALID_NEW_STATE)) { + qp->cur_state = params->new_state; + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "qp->cur_state=%d\n", + qp->cur_state); + } + + rc = qed_roce_modify_qp(p_hwfn, qp, prev_state, params); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Modify QP, rc = %d\n", rc); + return rc; +} + +static int +qed_rdma_register_tid(void *rdma_cxt, + struct qed_rdma_register_tid_in_params *params) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct rdma_register_tid_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + enum rdma_tid_type tid_type; + u8 fw_return_code; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "itid = %08x\n", params->itid); + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, RDMA_RAMROD_REGISTER_MR, + p_hwfn->p_rdma_info->proto, &init_data); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); + return rc; + } + + if (p_hwfn->p_rdma_info->last_tid < params->itid) + p_hwfn->p_rdma_info->last_tid = params->itid; + + p_ramrod = &p_ent->ramrod.rdma_register_tid; + + p_ramrod->flags = 0; + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL, + params->pbl_two_level); + + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED, params->zbva); + + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR, params->phy_mr); + + /* Don't initialize D/C field, as it may override other bits. */ + if (!(params->tid_type == QED_RDMA_TID_FMR) && !(params->dma_mr)) + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG, + params->page_size_log - 12); + + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ, + params->remote_read); + + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE, + params->remote_write); + + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC, + params->remote_atomic); + + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE, + params->local_write); + + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ, params->local_read); + + SET_FIELD(p_ramrod->flags, + RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND, + params->mw_bind); + + SET_FIELD(p_ramrod->flags1, + RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG, + params->pbl_page_size_log - 12); + + SET_FIELD(p_ramrod->flags2, + RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR, params->dma_mr); + + switch (params->tid_type) { + case QED_RDMA_TID_REGISTERED_MR: + tid_type = RDMA_TID_REGISTERED_MR; + break; + case QED_RDMA_TID_FMR: + tid_type = RDMA_TID_FMR; + break; + case QED_RDMA_TID_MW_TYPE1: + tid_type = RDMA_TID_MW_TYPE1; + break; + case QED_RDMA_TID_MW_TYPE2A: + tid_type = RDMA_TID_MW_TYPE2A; + break; + default: + rc = -EINVAL; + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); + return rc; + } + SET_FIELD(p_ramrod->flags1, + RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE, tid_type); + + p_ramrod->itid = cpu_to_le32(params->itid); + p_ramrod->key = params->key; + p_ramrod->pd = cpu_to_le16(params->pd); + p_ramrod->length_hi = (u8)(params->length >> 32); + p_ramrod->length_lo = DMA_LO_LE(params->length); + if (params->zbva) { + /* Lower 32 bits of the registered MR address. + * In case of zero based MR, will hold FBO + */ + p_ramrod->va.hi = 0; + p_ramrod->va.lo = cpu_to_le32(params->fbo); + } else { + DMA_REGPAIR_LE(p_ramrod->va, params->vaddr); + } + DMA_REGPAIR_LE(p_ramrod->pbl_base, params->pbl_ptr); + + /* DIF */ + if (params->dif_enabled) { + SET_FIELD(p_ramrod->flags2, + RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG, 1); + DMA_REGPAIR_LE(p_ramrod->dif_error_addr, + params->dif_error_addr); + DMA_REGPAIR_LE(p_ramrod->dif_runt_addr, params->dif_runt_addr); + } + + rc = qed_spq_post(p_hwfn, p_ent, &fw_return_code); + if (rc) + return rc; + + if (fw_return_code != RDMA_RETURN_OK) { + DP_NOTICE(p_hwfn, "fw_return_code = %d\n", fw_return_code); + return -EINVAL; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Register TID, rc = %d\n", rc); + return rc; +} + +static int qed_rdma_deregister_tid(void *rdma_cxt, u32 itid) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct rdma_deregister_tid_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + struct qed_ptt *p_ptt; + u8 fw_return_code; + int rc; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "itid = %08x\n", itid); + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, RDMA_RAMROD_DEREGISTER_MR, + p_hwfn->p_rdma_info->proto, &init_data); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); + return rc; + } + + p_ramrod = &p_ent->ramrod.rdma_deregister_tid; + p_ramrod->itid = cpu_to_le32(itid); + + rc = qed_spq_post(p_hwfn, p_ent, &fw_return_code); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); + return rc; + } + + if (fw_return_code == RDMA_RETURN_DEREGISTER_MR_BAD_STATE_ERR) { + DP_NOTICE(p_hwfn, "fw_return_code = %d\n", fw_return_code); + return -EINVAL; + } else if (fw_return_code == RDMA_RETURN_NIG_DRAIN_REQ) { + /* Bit indicating that the TID is in use and a nig drain is + * required before sending the ramrod again + */ + p_ptt = qed_ptt_acquire(p_hwfn); + if (!p_ptt) { + rc = -EBUSY; + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to acquire PTT\n"); + return rc; + } + + rc = qed_mcp_drain(p_hwfn, p_ptt); + if (rc) { + qed_ptt_release(p_hwfn, p_ptt); + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Drain failed\n"); + return rc; + } + + qed_ptt_release(p_hwfn, p_ptt); + + /* Resend the ramrod */ + rc = qed_sp_init_request(p_hwfn, &p_ent, + RDMA_RAMROD_DEREGISTER_MR, + p_hwfn->p_rdma_info->proto, + &init_data); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to init sp-element\n"); + return rc; + } + + rc = qed_spq_post(p_hwfn, p_ent, &fw_return_code); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Ramrod failed\n"); + return rc; + } + + if (fw_return_code != RDMA_RETURN_OK) { + DP_NOTICE(p_hwfn, "fw_return_code = %d\n", + fw_return_code); + return rc; + } + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "De-registered TID, rc = %d\n", rc); + return rc; +} + +static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid) +{ + struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; + u32 start_cid, cid, xcid; + + /* an even icid belongs to a responder while an odd icid belongs to a + * requester. The 'cid' received as an input can be either. We calculate + * the "partner" icid and call it xcid. Only if both are free then the + * "cid" map can be cleared. + */ + start_cid = qed_cxt_get_proto_cid_start(p_hwfn, p_rdma_info->proto); + cid = icid - start_cid; + xcid = cid ^ 1; + + spin_lock_bh(&p_rdma_info->lock); + + qed_bmap_release_id(p_hwfn, &p_rdma_info->real_cid_map, cid); + if (qed_bmap_test_id(p_hwfn, &p_rdma_info->real_cid_map, xcid) == 0) { + qed_bmap_release_id(p_hwfn, &p_rdma_info->cid_map, cid); + qed_bmap_release_id(p_hwfn, &p_rdma_info->cid_map, xcid); + } + + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); +} + +static void *qed_rdma_get_rdma_ctx(struct qed_dev *cdev) +{ + return QED_LEADING_HWFN(cdev); +} + +static bool qed_rdma_allocated_qps(struct qed_hwfn *p_hwfn) +{ + bool result; + + /* if rdma info has not been allocated, naturally there are no qps */ + if (!p_hwfn->p_rdma_info) + return false; + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + if (!p_hwfn->p_rdma_info->cid_map.bitmap) + result = false; + else + result = !qed_bmap_is_empty(&p_hwfn->p_rdma_info->cid_map); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + return result; +} + +static void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + u32 val; + + val = (p_hwfn->dcbx_no_edpm || p_hwfn->db_bar_no_edpm) ? 0 : 1; + + qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DPM_ENABLE, val); + DP_VERBOSE(p_hwfn, (QED_MSG_DCB | QED_MSG_RDMA), + "Changing DPM_EN state to %d (DCBX=%d, DB_BAR=%d)\n", + val, p_hwfn->dcbx_no_edpm, p_hwfn->db_bar_no_edpm); +} + +void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + u8 val; + + /* if any QPs are already active, we want to disable DPM, since their + * context information contains information from before the latest DCBx + * update. Otherwise enable it. + */ + val = qed_rdma_allocated_qps(p_hwfn) ? true : false; + p_hwfn->dcbx_no_edpm = (u8)val; + + qed_rdma_dpm_conf(p_hwfn, p_ptt); +} + +void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + p_hwfn->db_bar_no_edpm = true; + + qed_rdma_dpm_conf(p_hwfn, p_ptt); +} + +static int qed_rdma_start(void *rdma_cxt, + struct qed_rdma_start_in_params *params) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct qed_ptt *p_ptt; + int rc = -EBUSY; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "desired_cnq = %08x\n", params->desired_cnq); + + p_ptt = qed_ptt_acquire(p_hwfn); + if (!p_ptt) + goto err; + + rc = qed_rdma_alloc(p_hwfn, p_ptt, params); + if (rc) + goto err1; + + rc = qed_rdma_setup(p_hwfn, p_ptt, params); + if (rc) + goto err2; + + qed_ptt_release(p_hwfn, p_ptt); + + return rc; + +err2: + qed_rdma_free(p_hwfn); +err1: + qed_ptt_release(p_hwfn, p_ptt); +err: + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA start - error, rc = %d\n", rc); + return rc; +} + +static int qed_rdma_init(struct qed_dev *cdev, + struct qed_rdma_start_in_params *params) +{ + return qed_rdma_start(QED_LEADING_HWFN(cdev), params); +} + +static void qed_rdma_remove_user(void *rdma_cxt, u16 dpi) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "dpi = %08x\n", dpi); + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->dpi_map, dpi); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); +} + +static int qed_roce_ll2_set_mac_filter(struct qed_dev *cdev, + u8 *old_mac_address, + u8 *new_mac_address) +{ + struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); + struct qed_ptt *p_ptt; + int rc = 0; + + p_ptt = qed_ptt_acquire(p_hwfn); + if (!p_ptt) { + DP_ERR(cdev, + "qed roce ll2 mac filter set: failed to acquire PTT\n"); + return -EINVAL; + } + + if (old_mac_address) + qed_llh_remove_mac_filter(p_hwfn, p_ptt, old_mac_address); + if (new_mac_address) + rc = qed_llh_add_mac_filter(p_hwfn, p_ptt, new_mac_address); + + qed_ptt_release(p_hwfn, p_ptt); + + if (rc) + DP_ERR(cdev, + "qed roce ll2 mac filter set: failed to add MAC filter\n"); + + return rc; +} + +static const struct qed_rdma_ops qed_rdma_ops_pass = { + .common = &qed_common_ops_pass, + .fill_dev_info = &qed_fill_rdma_dev_info, + .rdma_get_rdma_ctx = &qed_rdma_get_rdma_ctx, + .rdma_init = &qed_rdma_init, + .rdma_add_user = &qed_rdma_add_user, + .rdma_remove_user = &qed_rdma_remove_user, + .rdma_stop = &qed_rdma_stop, + .rdma_query_port = &qed_rdma_query_port, + .rdma_query_device = &qed_rdma_query_device, + .rdma_get_start_sb = &qed_rdma_get_sb_start, + .rdma_get_rdma_int = &qed_rdma_get_int, + .rdma_set_rdma_int = &qed_rdma_set_int, + .rdma_get_min_cnq_msix = &qed_rdma_get_min_cnq_msix, + .rdma_cnq_prod_update = &qed_rdma_cnq_prod_update, + .rdma_alloc_pd = &qed_rdma_alloc_pd, + .rdma_dealloc_pd = &qed_rdma_free_pd, + .rdma_create_cq = &qed_rdma_create_cq, + .rdma_destroy_cq = &qed_rdma_destroy_cq, + .rdma_create_qp = &qed_rdma_create_qp, + .rdma_modify_qp = &qed_rdma_modify_qp, + .rdma_query_qp = &qed_rdma_query_qp, + .rdma_destroy_qp = &qed_rdma_destroy_qp, + .rdma_alloc_tid = &qed_rdma_alloc_tid, + .rdma_free_tid = &qed_rdma_free_tid, + .rdma_register_tid = &qed_rdma_register_tid, + .rdma_deregister_tid = &qed_rdma_deregister_tid, + .ll2_acquire_connection = &qed_ll2_acquire_connection, + .ll2_establish_connection = &qed_ll2_establish_connection, + .ll2_terminate_connection = &qed_ll2_terminate_connection, + .ll2_release_connection = &qed_ll2_release_connection, + .ll2_post_rx_buffer = &qed_ll2_post_rx_buffer, + .ll2_prepare_tx_packet = &qed_ll2_prepare_tx_packet, + .ll2_set_fragment_of_tx_packet = &qed_ll2_set_fragment_of_tx_packet, + .ll2_set_mac_filter = &qed_roce_ll2_set_mac_filter, + .ll2_get_stats = &qed_ll2_get_stats, +}; + +const struct qed_rdma_ops *qed_get_rdma_ops(void) +{ + return &qed_rdma_ops_pass; +} +EXPORT_SYMBOL(qed_get_rdma_ops); diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.h b/drivers/net/ethernet/qlogic/qed/qed_rdma.h new file mode 100644 index 000000000000..b178d9994a45 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.h @@ -0,0 +1,178 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015-2017 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _QED_ROCE_H +#define _QED_ROCE_H +#include +#include +#include +#include +#include +#include +#include +#include +#include "qed.h" +#include "qed_dev_api.h" +#include "qed_hsi.h" +#include "qed_ll2.h" + +#define QED_RDMA_MAX_FMR (RDMA_MAX_TIDS) +#define QED_RDMA_MAX_P_KEY (1) +#define QED_RDMA_MAX_WQE (0x7FFF) +#define QED_RDMA_MAX_SRQ_WQE_ELEM (0x7FFF) +#define QED_RDMA_PAGE_SIZE_CAPS (0xFFFFF000) +#define QED_RDMA_ACK_DELAY (15) +#define QED_RDMA_MAX_MR_SIZE (0x10000000000ULL) +#define QED_RDMA_MAX_CQS (RDMA_MAX_CQS) +#define QED_RDMA_MAX_MRS (RDMA_MAX_TIDS) +/* Add 1 for header element */ +#define QED_RDMA_MAX_SRQ_ELEM_PER_WQE (RDMA_MAX_SGE_PER_RQ_WQE + 1) +#define QED_RDMA_MAX_SGE_PER_SRQ_WQE (RDMA_MAX_SGE_PER_RQ_WQE) +#define QED_RDMA_SRQ_WQE_ELEM_SIZE (16) +#define QED_RDMA_MAX_SRQS (32 * 1024) + +#define QED_RDMA_MAX_CQE_32_BIT (0x7FFFFFFF - 1) +#define QED_RDMA_MAX_CQE_16_BIT (0x7FFF - 1) + +enum qed_rdma_toggle_bit { + QED_RDMA_TOGGLE_BIT_CLEAR = 0, + QED_RDMA_TOGGLE_BIT_SET = 1 +}; + +#define QED_RDMA_MAX_BMAP_NAME (10) +struct qed_bmap { + unsigned long *bitmap; + u32 max_count; + char name[QED_RDMA_MAX_BMAP_NAME]; +}; + +struct qed_rdma_info { + /* spin lock to protect bitmaps */ + spinlock_t lock; + + struct qed_bmap cq_map; + struct qed_bmap pd_map; + struct qed_bmap tid_map; + struct qed_bmap qp_map; + struct qed_bmap srq_map; + struct qed_bmap cid_map; + struct qed_bmap real_cid_map; + struct qed_bmap dpi_map; + struct qed_bmap toggle_bits; + struct qed_rdma_events events; + struct qed_rdma_device *dev; + struct qed_rdma_port *port; + u32 last_tid; + u8 num_cnqs; + u32 num_qps; + u32 num_mrs; + u16 queue_zone_base; + u16 max_queue_zones; + enum protocol_type proto; +}; + +struct qed_rdma_qp { + struct regpair qp_handle; + struct regpair qp_handle_async; + u32 qpid; + u16 icid; + enum qed_roce_qp_state cur_state; + bool use_srq; + bool signal_all; + bool fmr_and_reserved_lkey; + + bool incoming_rdma_read_en; + bool incoming_rdma_write_en; + bool incoming_atomic_en; + bool e2e_flow_control_en; + + u16 pd; + u16 pkey; + u32 dest_qp; + u16 mtu; + u16 srq_id; + u8 traffic_class_tos; + u8 hop_limit_ttl; + u16 dpi; + u32 flow_label; + bool lb_indication; + u16 vlan_id; + u32 ack_timeout; + u8 retry_cnt; + u8 rnr_retry_cnt; + u8 min_rnr_nak_timer; + bool sqd_async; + union qed_gid sgid; + union qed_gid dgid; + enum roce_mode roce_mode; + u16 udp_src_port; + u8 stats_queue; + + /* requeseter */ + u8 max_rd_atomic_req; + u32 sq_psn; + u16 sq_cq_id; + u16 sq_num_pages; + dma_addr_t sq_pbl_ptr; + void *orq; + dma_addr_t orq_phys_addr; + u8 orq_num_pages; + bool req_offloaded; + + /* responder */ + u8 max_rd_atomic_resp; + u32 rq_psn; + u16 rq_cq_id; + u16 rq_num_pages; + dma_addr_t rq_pbl_ptr; + void *irq; + dma_addr_t irq_phys_addr; + u8 irq_num_pages; + bool resp_offloaded; + u32 cq_prod; + + u8 remote_mac_addr[6]; + u8 local_mac_addr[6]; + + void *shared_queue; + dma_addr_t shared_queue_phys_addr; +}; + +#if IS_ENABLED(CONFIG_QED_RDMA) +void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +#else +static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} + +static inline void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) {} +#endif +#endif -- cgit v1.2.3 From b71b9afdf6d6c1ca728fde2aa14bc71721cab34e Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Wed, 21 Jun 2017 16:22:45 +0300 Subject: qed: Split rdma content between qed_rdma and qed_roce This patch places common iWARP / RoCE code in qed_rdma and roce specific code in qed_roce There is one new function ( qed_roce_setup ) added, the rest of the patch removes content from the files and removes some static definitions. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/Makefile | 2 +- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_dev.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_rdma.c | 1123 +----------------- drivers/net/ethernet/qlogic/qed/qed_rdma.h | 39 +- drivers/net/ethernet/qlogic/qed/qed_roce.c | 1746 +--------------------------- drivers/net/ethernet/qlogic/qed/qed_roce.h | 151 +-- drivers/net/ethernet/qlogic/qed/qed_spq.c | 2 +- 9 files changed, 118 insertions(+), 2951 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile index 974929dcc74e..67452380b60e 100644 --- a/drivers/net/ethernet/qlogic/qed/Makefile +++ b/drivers/net/ethernet/qlogic/qed/Makefile @@ -5,6 +5,6 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \ qed_selftest.o qed_dcbx.o qed_debug.o qed_ptp.o qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o qed-$(CONFIG_QED_LL2) += qed_ll2.o -qed-$(CONFIG_QED_RDMA) += qed_roce.o +qed-$(CONFIG_QED_RDMA) += qed_roce.o qed_rdma.o qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o qed_ooo.o qed-$(CONFIG_QED_FCOE) += qed_fcoe.o diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index f888045e1ae9..eaca4578435d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -44,7 +44,7 @@ #include "qed_hsi.h" #include "qed_sp.h" #include "qed_sriov.h" -#include "qed_roce.h" +#include "qed_rdma.h" #ifdef CONFIG_DCB #include #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 8b140541736a..49667ad9042d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -62,7 +62,7 @@ #include "qed_sp.h" #include "qed_sriov.h" #include "qed_vf.h" -#include "qed_roce.h" +#include "qed_rdma.h" static DEFINE_SPINLOCK(qm_lock); diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index f9c51cb8585e..17f9b0a7b553 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -61,7 +61,7 @@ #include "qed_ooo.h" #include "qed_reg_addr.h" #include "qed_sp.h" -#include "qed_roce.h" +#include "qed_rdma.h" #define QED_LL2_RX_REGISTERED(ll2) ((ll2)->rx_queue.b_cb_registred) #define QED_LL2_TX_REGISTERED(ll2) ((ll2)->tx_queue.b_cb_registred) diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c index 9dc41a899ef2..cb620e008444 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -53,39 +53,14 @@ #include "qed_ll2.h" #include "qed_mcp.h" #include "qed_reg_addr.h" -#include "qed_roce.h" #include +#include "qed_rdma.h" +#include "qed_roce.h" #include "qed_sp.h" -static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid); - -static int -qed_roce_async_event(struct qed_hwfn *p_hwfn, - u8 fw_event_code, - u16 echo, union event_ring_data *data, u8 fw_return_code) -{ - if (fw_event_code == ROCE_ASYNC_EVENT_DESTROY_QP_DONE) { - u16 icid = - (u16)le32_to_cpu(data->rdma_data.rdma_destroy_qp_data.cid); - - /* icid release in this async event can occur only if the icid - * was offloaded to the FW. In case it wasn't offloaded this is - * handled in qed_roce_sp_destroy_qp. - */ - qed_roce_free_real_icid(p_hwfn, icid); - } else { - struct qed_rdma_events *events = &p_hwfn->p_rdma_info->events; - - events->affiliated_event(p_hwfn->p_rdma_info->events.context, - fw_event_code, - (void *)&data->rdma_data.async_handle); - } - - return 0; -} -static int qed_rdma_bmap_alloc(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 max_count, char *name) +int qed_rdma_bmap_alloc(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 max_count, char *name) { DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "max_count = %08x\n", max_count); @@ -102,8 +77,8 @@ static int qed_rdma_bmap_alloc(struct qed_hwfn *p_hwfn, return 0; } -static int qed_rdma_bmap_alloc_id(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 *id_num) +int qed_rdma_bmap_alloc_id(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 *id_num) { *id_num = find_first_zero_bit(bmap->bitmap, bmap->max_count); if (*id_num >= bmap->max_count) @@ -117,8 +92,8 @@ static int qed_rdma_bmap_alloc_id(struct qed_hwfn *p_hwfn, return 0; } -static void qed_bmap_set_id(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 id_num) +void qed_bmap_set_id(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 id_num) { if (id_num >= bmap->max_count) return; @@ -126,8 +101,8 @@ static void qed_bmap_set_id(struct qed_hwfn *p_hwfn, __set_bit(id_num, bmap->bitmap); } -static void qed_bmap_release_id(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 id_num) +void qed_bmap_release_id(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 id_num) { bool b_acquired; @@ -145,8 +120,8 @@ static void qed_bmap_release_id(struct qed_hwfn *p_hwfn, bmap->name, id_num); } -static int qed_bmap_test_id(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 id_num) +int qed_bmap_test_id(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 id_num) { if (id_num >= bmap->max_count) return -1; @@ -159,7 +134,7 @@ static bool qed_bmap_is_empty(struct qed_bmap *bmap) return bmap->max_count == find_first_bit(bmap->bitmap, bmap->max_count); } -static u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id) +u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id) { /* First sb id for RoCE is after all the l2 sb */ return FEAT_NUM((struct qed_hwfn *)p_hwfn, QED_PF_L2_QUE) + rel_sb_id; @@ -302,8 +277,8 @@ free_rdma_info: return rc; } -static void qed_rdma_bmap_free(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, bool check) +void qed_rdma_bmap_free(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, bool check) { int weight = bitmap_weight(bmap->bitmap, bmap->max_count); int last_line = bmap->max_count / (64 * 8); @@ -666,33 +641,12 @@ static int qed_rdma_setup(struct qed_hwfn *p_hwfn, if (rc) return rc; - qed_spq_register_async_cb(p_hwfn, PROTOCOLID_ROCE, - qed_roce_async_event); + qed_roce_setup(p_hwfn); return qed_rdma_start_fw(p_hwfn, params, p_ptt); } -void qed_roce_stop(struct qed_hwfn *p_hwfn) -{ - struct qed_bmap *rcid_map = &p_hwfn->p_rdma_info->real_cid_map; - int wait_count = 0; - - /* when destroying a_RoCE QP the control is returned to the user after - * the synchronous part. The asynchronous part may take a little longer. - * We delay for a short while if an async destroy QP is still expected. - * Beyond the added delay we clear the bitmap anyway. - */ - while (bitmap_weight(rcid_map->bitmap, rcid_map->max_count)) { - msleep(100); - if (wait_count++ > 20) { - DP_NOTICE(p_hwfn, "cid bitmap wait timed out\n"); - break; - } - } - qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_ROCE); -} - -static int qed_rdma_stop(void *rdma_cxt) +int qed_rdma_stop(void *rdma_cxt) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; struct rdma_close_func_ramrod_data *p_ramrod; @@ -1146,904 +1100,13 @@ err: dma_free_coherent(&p_hwfn->cdev->pdev->dev, return rc; } -static void qed_rdma_set_fw_mac(u16 *p_fw_mac, u8 *p_qed_mac) +void qed_rdma_set_fw_mac(u16 *p_fw_mac, u8 *p_qed_mac) { p_fw_mac[0] = cpu_to_le16((p_qed_mac[0] << 8) + p_qed_mac[1]); p_fw_mac[1] = cpu_to_le16((p_qed_mac[2] << 8) + p_qed_mac[3]); p_fw_mac[2] = cpu_to_le16((p_qed_mac[4] << 8) + p_qed_mac[5]); } -static void qed_rdma_copy_gids(struct qed_rdma_qp *qp, __le32 *src_gid, - __le32 *dst_gid) -{ - u32 i; - - if (qp->roce_mode == ROCE_V2_IPV4) { - /* The IPv4 addresses shall be aligned to the highest word. - * The lower words must be zero. - */ - memset(src_gid, 0, sizeof(union qed_gid)); - memset(dst_gid, 0, sizeof(union qed_gid)); - src_gid[3] = cpu_to_le32(qp->sgid.ipv4_addr); - dst_gid[3] = cpu_to_le32(qp->dgid.ipv4_addr); - } else { - /* GIDs and IPv6 addresses coincide in location and size */ - for (i = 0; i < ARRAY_SIZE(qp->sgid.dwords); i++) { - src_gid[i] = cpu_to_le32(qp->sgid.dwords[i]); - dst_gid[i] = cpu_to_le32(qp->dgid.dwords[i]); - } - } -} - -static enum roce_flavor qed_roce_mode_to_flavor(enum roce_mode roce_mode) -{ - enum roce_flavor flavor; - - switch (roce_mode) { - case ROCE_V1: - flavor = PLAIN_ROCE; - break; - case ROCE_V2_IPV4: - flavor = RROCE_IPV4; - break; - case ROCE_V2_IPV6: - flavor = ROCE_V2_IPV6; - break; - default: - flavor = MAX_ROCE_MODE; - break; - } - return flavor; -} - -void qed_roce_free_cid_pair(struct qed_hwfn *p_hwfn, u16 cid) -{ - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->cid_map, cid); - qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->cid_map, cid + 1); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); -} - -static int qed_roce_alloc_cid(struct qed_hwfn *p_hwfn, u16 *cid) -{ - struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; - u32 responder_icid; - u32 requester_icid; - int rc; - - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - rc = qed_rdma_bmap_alloc_id(p_hwfn, &p_rdma_info->cid_map, - &responder_icid); - if (rc) { - spin_unlock_bh(&p_rdma_info->lock); - return rc; - } - - rc = qed_rdma_bmap_alloc_id(p_hwfn, &p_rdma_info->cid_map, - &requester_icid); - - spin_unlock_bh(&p_rdma_info->lock); - if (rc) - goto err; - - /* the two icid's should be adjacent */ - if ((requester_icid - responder_icid) != 1) { - DP_NOTICE(p_hwfn, "Failed to allocate two adjacent qp's'\n"); - rc = -EINVAL; - goto err; - } - - responder_icid += qed_cxt_get_proto_cid_start(p_hwfn, - p_rdma_info->proto); - requester_icid += qed_cxt_get_proto_cid_start(p_hwfn, - p_rdma_info->proto); - - /* If these icids require a new ILT line allocate DMA-able context for - * an ILT page - */ - rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_CXT, responder_icid); - if (rc) - goto err; - - rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_CXT, requester_icid); - if (rc) - goto err; - - *cid = (u16)responder_icid; - return rc; - -err: - spin_lock_bh(&p_rdma_info->lock); - qed_bmap_release_id(p_hwfn, &p_rdma_info->cid_map, responder_icid); - qed_bmap_release_id(p_hwfn, &p_rdma_info->cid_map, requester_icid); - - spin_unlock_bh(&p_rdma_info->lock); - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Allocate CID - failed, rc = %d\n", rc); - return rc; -} - -static void qed_roce_set_real_cid(struct qed_hwfn *p_hwfn, u32 cid) -{ - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - qed_bmap_set_id(p_hwfn, &p_hwfn->p_rdma_info->real_cid_map, cid); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); -} - -static int qed_roce_sp_create_responder(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp) -{ - struct roce_create_qp_resp_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - enum roce_flavor roce_flavor; - struct qed_spq_entry *p_ent; - u16 regular_latency_queue; - enum protocol_type proto; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); - - /* Allocate DMA-able memory for IRQ */ - qp->irq_num_pages = 1; - qp->irq = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, - RDMA_RING_PAGE_SIZE, - &qp->irq_phys_addr, GFP_KERNEL); - if (!qp->irq) { - rc = -ENOMEM; - DP_NOTICE(p_hwfn, - "qed create responder failed: cannot allocate memory (irq). rc = %d\n", - rc); - return rc; - } - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = qp->icid; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, ROCE_RAMROD_CREATE_QP, - PROTOCOLID_ROCE, &init_data); - if (rc) - goto err; - - p_ramrod = &p_ent->ramrod.roce_create_qp_resp; - - p_ramrod->flags = 0; - - roce_flavor = qed_roce_mode_to_flavor(qp->roce_mode); - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_RESP_RAMROD_DATA_ROCE_FLAVOR, roce_flavor); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_RESP_RAMROD_DATA_RDMA_RD_EN, - qp->incoming_rdma_read_en); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_RESP_RAMROD_DATA_RDMA_WR_EN, - qp->incoming_rdma_write_en); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_RESP_RAMROD_DATA_ATOMIC_EN, - qp->incoming_atomic_en); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_RESP_RAMROD_DATA_E2E_FLOW_CONTROL_EN, - qp->e2e_flow_control_en); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_RESP_RAMROD_DATA_SRQ_FLG, qp->use_srq); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_RESP_RAMROD_DATA_RESERVED_KEY_EN, - qp->fmr_and_reserved_lkey); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER, - qp->min_rnr_nak_timer); - - p_ramrod->max_ird = qp->max_rd_atomic_resp; - p_ramrod->traffic_class = qp->traffic_class_tos; - p_ramrod->hop_limit = qp->hop_limit_ttl; - p_ramrod->irq_num_pages = qp->irq_num_pages; - p_ramrod->p_key = cpu_to_le16(qp->pkey); - p_ramrod->flow_label = cpu_to_le32(qp->flow_label); - p_ramrod->dst_qp_id = cpu_to_le32(qp->dest_qp); - p_ramrod->mtu = cpu_to_le16(qp->mtu); - p_ramrod->initial_psn = cpu_to_le32(qp->rq_psn); - p_ramrod->pd = cpu_to_le16(qp->pd); - p_ramrod->rq_num_pages = cpu_to_le16(qp->rq_num_pages); - DMA_REGPAIR_LE(p_ramrod->rq_pbl_addr, qp->rq_pbl_ptr); - DMA_REGPAIR_LE(p_ramrod->irq_pbl_addr, qp->irq_phys_addr); - qed_rdma_copy_gids(qp, p_ramrod->src_gid, p_ramrod->dst_gid); - p_ramrod->qp_handle_for_async.hi = cpu_to_le32(qp->qp_handle_async.hi); - p_ramrod->qp_handle_for_async.lo = cpu_to_le32(qp->qp_handle_async.lo); - p_ramrod->qp_handle_for_cqe.hi = cpu_to_le32(qp->qp_handle.hi); - p_ramrod->qp_handle_for_cqe.lo = cpu_to_le32(qp->qp_handle.lo); - p_ramrod->cq_cid = cpu_to_le32((p_hwfn->hw_info.opaque_fid << 16) | - qp->rq_cq_id); - - regular_latency_queue = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD); - - p_ramrod->regular_latency_phy_queue = - cpu_to_le16(regular_latency_queue); - p_ramrod->low_latency_phy_queue = - cpu_to_le16(regular_latency_queue); - - p_ramrod->dpi = cpu_to_le16(qp->dpi); - - qed_rdma_set_fw_mac(p_ramrod->remote_mac_addr, qp->remote_mac_addr); - qed_rdma_set_fw_mac(p_ramrod->local_mac_addr, qp->local_mac_addr); - - p_ramrod->udp_src_port = qp->udp_src_port; - p_ramrod->vlan_id = cpu_to_le16(qp->vlan_id); - p_ramrod->srq_id.srq_idx = cpu_to_le16(qp->srq_id); - p_ramrod->srq_id.opaque_fid = cpu_to_le16(p_hwfn->hw_info.opaque_fid); - - p_ramrod->stats_counter_id = RESC_START(p_hwfn, QED_RDMA_STATS_QUEUE) + - qp->stats_queue; - - rc = qed_spq_post(p_hwfn, p_ent, NULL); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "rc = %d regular physical queue = 0x%x\n", rc, - regular_latency_queue); - - if (rc) - goto err; - - qp->resp_offloaded = true; - qp->cq_prod = 0; - - proto = p_hwfn->p_rdma_info->proto; - qed_roce_set_real_cid(p_hwfn, qp->icid - - qed_cxt_get_proto_cid_start(p_hwfn, proto)); - - return rc; - -err: - DP_NOTICE(p_hwfn, "create responder - failed, rc = %d\n", rc); - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - qp->irq_num_pages * RDMA_RING_PAGE_SIZE, - qp->irq, qp->irq_phys_addr); - - return rc; -} - -static int qed_roce_sp_create_requester(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp) -{ - struct roce_create_qp_req_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - enum roce_flavor roce_flavor; - struct qed_spq_entry *p_ent; - u16 regular_latency_queue; - enum protocol_type proto; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); - - /* Allocate DMA-able memory for ORQ */ - qp->orq_num_pages = 1; - qp->orq = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, - RDMA_RING_PAGE_SIZE, - &qp->orq_phys_addr, GFP_KERNEL); - if (!qp->orq) { - rc = -ENOMEM; - DP_NOTICE(p_hwfn, - "qed create requester failed: cannot allocate memory (orq). rc = %d\n", - rc); - return rc; - } - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = qp->icid + 1; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, - ROCE_RAMROD_CREATE_QP, - PROTOCOLID_ROCE, &init_data); - if (rc) - goto err; - - p_ramrod = &p_ent->ramrod.roce_create_qp_req; - - p_ramrod->flags = 0; - - roce_flavor = qed_roce_mode_to_flavor(qp->roce_mode); - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_REQ_RAMROD_DATA_ROCE_FLAVOR, roce_flavor); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_REQ_RAMROD_DATA_FMR_AND_RESERVED_EN, - qp->fmr_and_reserved_lkey); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_REQ_RAMROD_DATA_SIGNALED_COMP, qp->signal_all); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT, qp->retry_cnt); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_REQ_RAMROD_DATA_RNR_NAK_CNT, - qp->rnr_retry_cnt); - - p_ramrod->max_ord = qp->max_rd_atomic_req; - p_ramrod->traffic_class = qp->traffic_class_tos; - p_ramrod->hop_limit = qp->hop_limit_ttl; - p_ramrod->orq_num_pages = qp->orq_num_pages; - p_ramrod->p_key = cpu_to_le16(qp->pkey); - p_ramrod->flow_label = cpu_to_le32(qp->flow_label); - p_ramrod->dst_qp_id = cpu_to_le32(qp->dest_qp); - p_ramrod->ack_timeout_val = cpu_to_le32(qp->ack_timeout); - p_ramrod->mtu = cpu_to_le16(qp->mtu); - p_ramrod->initial_psn = cpu_to_le32(qp->sq_psn); - p_ramrod->pd = cpu_to_le16(qp->pd); - p_ramrod->sq_num_pages = cpu_to_le16(qp->sq_num_pages); - DMA_REGPAIR_LE(p_ramrod->sq_pbl_addr, qp->sq_pbl_ptr); - DMA_REGPAIR_LE(p_ramrod->orq_pbl_addr, qp->orq_phys_addr); - qed_rdma_copy_gids(qp, p_ramrod->src_gid, p_ramrod->dst_gid); - p_ramrod->qp_handle_for_async.hi = cpu_to_le32(qp->qp_handle_async.hi); - p_ramrod->qp_handle_for_async.lo = cpu_to_le32(qp->qp_handle_async.lo); - p_ramrod->qp_handle_for_cqe.hi = cpu_to_le32(qp->qp_handle.hi); - p_ramrod->qp_handle_for_cqe.lo = cpu_to_le32(qp->qp_handle.lo); - p_ramrod->cq_cid = - cpu_to_le32((p_hwfn->hw_info.opaque_fid << 16) | qp->sq_cq_id); - - regular_latency_queue = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD); - - p_ramrod->regular_latency_phy_queue = - cpu_to_le16(regular_latency_queue); - p_ramrod->low_latency_phy_queue = - cpu_to_le16(regular_latency_queue); - - p_ramrod->dpi = cpu_to_le16(qp->dpi); - - qed_rdma_set_fw_mac(p_ramrod->remote_mac_addr, qp->remote_mac_addr); - qed_rdma_set_fw_mac(p_ramrod->local_mac_addr, qp->local_mac_addr); - - p_ramrod->udp_src_port = qp->udp_src_port; - p_ramrod->vlan_id = cpu_to_le16(qp->vlan_id); - p_ramrod->stats_counter_id = RESC_START(p_hwfn, QED_RDMA_STATS_QUEUE) + - qp->stats_queue; - - rc = qed_spq_post(p_hwfn, p_ent, NULL); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); - - if (rc) - goto err; - - qp->req_offloaded = true; - proto = p_hwfn->p_rdma_info->proto; - qed_roce_set_real_cid(p_hwfn, - qp->icid + 1 - - qed_cxt_get_proto_cid_start(p_hwfn, proto)); - - return rc; - -err: - DP_NOTICE(p_hwfn, "Create requested - failed, rc = %d\n", rc); - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - qp->orq_num_pages * RDMA_RING_PAGE_SIZE, - qp->orq, qp->orq_phys_addr); - return rc; -} - -static int qed_roce_sp_modify_responder(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp, - bool move_to_err, u32 modify_flags) -{ - struct roce_modify_qp_resp_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); - - if (move_to_err && !qp->resp_offloaded) - return 0; - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = qp->icid; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, - ROCE_EVENT_MODIFY_QP, - PROTOCOLID_ROCE, &init_data); - if (rc) { - DP_NOTICE(p_hwfn, "rc = %d\n", rc); - return rc; - } - - p_ramrod = &p_ent->ramrod.roce_modify_qp_resp; - - p_ramrod->flags = 0; - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_MOVE_TO_ERR_FLG, move_to_err); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_RD_EN, - qp->incoming_rdma_read_en); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_WR_EN, - qp->incoming_rdma_write_en); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_ATOMIC_EN, - qp->incoming_atomic_en); - - SET_FIELD(p_ramrod->flags, - ROCE_CREATE_QP_RESP_RAMROD_DATA_E2E_FLOW_CONTROL_EN, - qp->e2e_flow_control_en); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_OPS_EN_FLG, - GET_FIELD(modify_flags, - QED_RDMA_MODIFY_QP_VALID_RDMA_OPS_EN)); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_P_KEY_FLG, - GET_FIELD(modify_flags, QED_ROCE_MODIFY_QP_VALID_PKEY)); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_ADDRESS_VECTOR_FLG, - GET_FIELD(modify_flags, - QED_ROCE_MODIFY_QP_VALID_ADDRESS_VECTOR)); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_MAX_IRD_FLG, - GET_FIELD(modify_flags, - QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_RESP)); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER_FLG, - GET_FIELD(modify_flags, - QED_ROCE_MODIFY_QP_VALID_MIN_RNR_NAK_TIMER)); - - p_ramrod->fields = 0; - SET_FIELD(p_ramrod->fields, - ROCE_MODIFY_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER, - qp->min_rnr_nak_timer); - - p_ramrod->max_ird = qp->max_rd_atomic_resp; - p_ramrod->traffic_class = qp->traffic_class_tos; - p_ramrod->hop_limit = qp->hop_limit_ttl; - p_ramrod->p_key = cpu_to_le16(qp->pkey); - p_ramrod->flow_label = cpu_to_le32(qp->flow_label); - p_ramrod->mtu = cpu_to_le16(qp->mtu); - qed_rdma_copy_gids(qp, p_ramrod->src_gid, p_ramrod->dst_gid); - rc = qed_spq_post(p_hwfn, p_ent, NULL); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Modify responder, rc = %d\n", rc); - return rc; -} - -static int qed_roce_sp_modify_requester(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp, - bool move_to_sqd, - bool move_to_err, u32 modify_flags) -{ - struct roce_modify_qp_req_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); - - if (move_to_err && !(qp->req_offloaded)) - return 0; - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = qp->icid + 1; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, - ROCE_EVENT_MODIFY_QP, - PROTOCOLID_ROCE, &init_data); - if (rc) { - DP_NOTICE(p_hwfn, "rc = %d\n", rc); - return rc; - } - - p_ramrod = &p_ent->ramrod.roce_modify_qp_req; - - p_ramrod->flags = 0; - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_MOVE_TO_ERR_FLG, move_to_err); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_MOVE_TO_SQD_FLG, move_to_sqd); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_EN_SQD_ASYNC_NOTIFY, - qp->sqd_async); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_P_KEY_FLG, - GET_FIELD(modify_flags, QED_ROCE_MODIFY_QP_VALID_PKEY)); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_ADDRESS_VECTOR_FLG, - GET_FIELD(modify_flags, - QED_ROCE_MODIFY_QP_VALID_ADDRESS_VECTOR)); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_MAX_ORD_FLG, - GET_FIELD(modify_flags, - QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_REQ)); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_RNR_NAK_CNT_FLG, - GET_FIELD(modify_flags, - QED_ROCE_MODIFY_QP_VALID_RNR_RETRY_CNT)); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT_FLG, - GET_FIELD(modify_flags, QED_ROCE_MODIFY_QP_VALID_RETRY_CNT)); - - SET_FIELD(p_ramrod->flags, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_ACK_TIMEOUT_FLG, - GET_FIELD(modify_flags, - QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT)); - - p_ramrod->fields = 0; - SET_FIELD(p_ramrod->fields, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT, qp->retry_cnt); - - SET_FIELD(p_ramrod->fields, - ROCE_MODIFY_QP_REQ_RAMROD_DATA_RNR_NAK_CNT, - qp->rnr_retry_cnt); - - p_ramrod->max_ord = qp->max_rd_atomic_req; - p_ramrod->traffic_class = qp->traffic_class_tos; - p_ramrod->hop_limit = qp->hop_limit_ttl; - p_ramrod->p_key = cpu_to_le16(qp->pkey); - p_ramrod->flow_label = cpu_to_le32(qp->flow_label); - p_ramrod->ack_timeout_val = cpu_to_le32(qp->ack_timeout); - p_ramrod->mtu = cpu_to_le16(qp->mtu); - qed_rdma_copy_gids(qp, p_ramrod->src_gid, p_ramrod->dst_gid); - rc = qed_spq_post(p_hwfn, p_ent, NULL); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Modify requester, rc = %d\n", rc); - return rc; -} - -static int qed_roce_sp_destroy_qp_responder(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp, - u32 *num_invalidated_mw, - u32 *cq_prod) -{ - struct roce_destroy_qp_resp_output_params *p_ramrod_res; - struct roce_destroy_qp_resp_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - dma_addr_t ramrod_res_phys; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); - - *num_invalidated_mw = 0; - *cq_prod = qp->cq_prod; - - if (!qp->resp_offloaded) { - /* If a responder was never offload, we need to free the cids - * allocated in create_qp as a FW async event will never arrive - */ - u32 cid; - - cid = qp->icid - - qed_cxt_get_proto_cid_start(p_hwfn, - p_hwfn->p_rdma_info->proto); - qed_roce_free_cid_pair(p_hwfn, (u16)cid); - - return 0; - } - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = qp->icid; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, - ROCE_RAMROD_DESTROY_QP, - PROTOCOLID_ROCE, &init_data); - if (rc) - return rc; - - p_ramrod = &p_ent->ramrod.roce_destroy_qp_resp; - - p_ramrod_res = (struct roce_destroy_qp_resp_output_params *) - dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_ramrod_res), - &ramrod_res_phys, GFP_KERNEL); - - if (!p_ramrod_res) { - rc = -ENOMEM; - DP_NOTICE(p_hwfn, - "qed destroy responder failed: cannot allocate memory (ramrod). rc = %d\n", - rc); - return rc; - } - - DMA_REGPAIR_LE(p_ramrod->output_params_addr, ramrod_res_phys); - - rc = qed_spq_post(p_hwfn, p_ent, NULL); - if (rc) - goto err; - - *num_invalidated_mw = le32_to_cpu(p_ramrod_res->num_invalidated_mw); - *cq_prod = le32_to_cpu(p_ramrod_res->cq_prod); - qp->cq_prod = *cq_prod; - - /* Free IRQ - only if ramrod succeeded, in case FW is still using it */ - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - qp->irq_num_pages * RDMA_RING_PAGE_SIZE, - qp->irq, qp->irq_phys_addr); - - qp->resp_offloaded = false; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Destroy responder, rc = %d\n", rc); - -err: - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(struct roce_destroy_qp_resp_output_params), - p_ramrod_res, ramrod_res_phys); - - return rc; -} - -static int qed_roce_sp_destroy_qp_requester(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp, - u32 *num_bound_mw) -{ - struct roce_destroy_qp_req_output_params *p_ramrod_res; - struct roce_destroy_qp_req_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - dma_addr_t ramrod_res_phys; - int rc = -ENOMEM; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); - - if (!qp->req_offloaded) - return 0; - - p_ramrod_res = (struct roce_destroy_qp_req_output_params *) - dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(*p_ramrod_res), - &ramrod_res_phys, GFP_KERNEL); - if (!p_ramrod_res) { - DP_NOTICE(p_hwfn, - "qed destroy requester failed: cannot allocate memory (ramrod)\n"); - return rc; - } - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = qp->icid + 1; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, ROCE_RAMROD_DESTROY_QP, - PROTOCOLID_ROCE, &init_data); - if (rc) - goto err; - - p_ramrod = &p_ent->ramrod.roce_destroy_qp_req; - DMA_REGPAIR_LE(p_ramrod->output_params_addr, ramrod_res_phys); - - rc = qed_spq_post(p_hwfn, p_ent, NULL); - if (rc) - goto err; - - *num_bound_mw = le32_to_cpu(p_ramrod_res->num_bound_mw); - - /* Free ORQ - only if ramrod succeeded, in case FW is still using it */ - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - qp->orq_num_pages * RDMA_RING_PAGE_SIZE, - qp->orq, qp->orq_phys_addr); - - qp->req_offloaded = false; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Destroy requester, rc = %d\n", rc); - -err: - dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_ramrod_res), - p_ramrod_res, ramrod_res_phys); - - return rc; -} - -static int qed_roce_query_qp(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp, - struct qed_rdma_query_qp_out_params *out_params) -{ - struct roce_query_qp_resp_output_params *p_resp_ramrod_res; - struct roce_query_qp_req_output_params *p_req_ramrod_res; - struct roce_query_qp_resp_ramrod_data *p_resp_ramrod; - struct roce_query_qp_req_ramrod_data *p_req_ramrod; - struct qed_sp_init_data init_data; - dma_addr_t resp_ramrod_res_phys; - dma_addr_t req_ramrod_res_phys; - struct qed_spq_entry *p_ent; - bool rq_err_state; - bool sq_err_state; - bool sq_draining; - int rc = -ENOMEM; - - if ((!(qp->resp_offloaded)) && (!(qp->req_offloaded))) { - /* We can't send ramrod to the fw since this qp wasn't offloaded - * to the fw yet - */ - out_params->draining = false; - out_params->rq_psn = qp->rq_psn; - out_params->sq_psn = qp->sq_psn; - out_params->state = qp->cur_state; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "No QPs as no offload\n"); - return 0; - } - - if (!(qp->resp_offloaded)) { - DP_NOTICE(p_hwfn, - "The responder's qp should be offloded before requester's\n"); - return -EINVAL; - } - - /* Send a query responder ramrod to FW to get RQ-PSN and state */ - p_resp_ramrod_res = (struct roce_query_qp_resp_output_params *) - dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(*p_resp_ramrod_res), - &resp_ramrod_res_phys, GFP_KERNEL); - if (!p_resp_ramrod_res) { - DP_NOTICE(p_hwfn, - "qed query qp failed: cannot allocate memory (ramrod)\n"); - return rc; - } - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = qp->icid; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - rc = qed_sp_init_request(p_hwfn, &p_ent, ROCE_RAMROD_QUERY_QP, - PROTOCOLID_ROCE, &init_data); - if (rc) - goto err_resp; - - p_resp_ramrod = &p_ent->ramrod.roce_query_qp_resp; - DMA_REGPAIR_LE(p_resp_ramrod->output_params_addr, resp_ramrod_res_phys); - - rc = qed_spq_post(p_hwfn, p_ent, NULL); - if (rc) - goto err_resp; - - out_params->rq_psn = le32_to_cpu(p_resp_ramrod_res->psn); - rq_err_state = GET_FIELD(le32_to_cpu(p_resp_ramrod_res->err_flag), - ROCE_QUERY_QP_RESP_OUTPUT_PARAMS_ERROR_FLG); - - dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_resp_ramrod_res), - p_resp_ramrod_res, resp_ramrod_res_phys); - - if (!(qp->req_offloaded)) { - /* Don't send query qp for the requester */ - out_params->sq_psn = qp->sq_psn; - out_params->draining = false; - - if (rq_err_state) - qp->cur_state = QED_ROCE_QP_STATE_ERR; - - out_params->state = qp->cur_state; - - return 0; - } - - /* Send a query requester ramrod to FW to get SQ-PSN and state */ - p_req_ramrod_res = (struct roce_query_qp_req_output_params *) - dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(*p_req_ramrod_res), - &req_ramrod_res_phys, - GFP_KERNEL); - if (!p_req_ramrod_res) { - rc = -ENOMEM; - DP_NOTICE(p_hwfn, - "qed query qp failed: cannot allocate memory (ramrod)\n"); - return rc; - } - - /* Get SPQ entry */ - init_data.cid = qp->icid + 1; - rc = qed_sp_init_request(p_hwfn, &p_ent, ROCE_RAMROD_QUERY_QP, - PROTOCOLID_ROCE, &init_data); - if (rc) - goto err_req; - - p_req_ramrod = &p_ent->ramrod.roce_query_qp_req; - DMA_REGPAIR_LE(p_req_ramrod->output_params_addr, req_ramrod_res_phys); - - rc = qed_spq_post(p_hwfn, p_ent, NULL); - if (rc) - goto err_req; - - out_params->sq_psn = le32_to_cpu(p_req_ramrod_res->psn); - sq_err_state = GET_FIELD(le32_to_cpu(p_req_ramrod_res->flags), - ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_ERR_FLG); - sq_draining = - GET_FIELD(le32_to_cpu(p_req_ramrod_res->flags), - ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_SQ_DRAINING_FLG); - - dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_req_ramrod_res), - p_req_ramrod_res, req_ramrod_res_phys); - - out_params->draining = false; - - if (rq_err_state || sq_err_state) - qp->cur_state = QED_ROCE_QP_STATE_ERR; - else if (sq_draining) - out_params->draining = true; - out_params->state = qp->cur_state; - - return 0; - -err_req: - dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_req_ramrod_res), - p_req_ramrod_res, req_ramrod_res_phys); - return rc; -err_resp: - dma_free_coherent(&p_hwfn->cdev->pdev->dev, sizeof(*p_resp_ramrod_res), - p_resp_ramrod_res, resp_ramrod_res_phys); - return rc; -} - -static int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) -{ - u32 num_invalidated_mw = 0; - u32 num_bound_mw = 0; - u32 cq_prod; - int rc; - - /* Destroys the specified QP */ - if ((qp->cur_state != QED_ROCE_QP_STATE_RESET) && - (qp->cur_state != QED_ROCE_QP_STATE_ERR) && - (qp->cur_state != QED_ROCE_QP_STATE_INIT)) { - DP_NOTICE(p_hwfn, - "QP must be in error, reset or init state before destroying it\n"); - return -EINVAL; - } - - if (qp->cur_state != QED_ROCE_QP_STATE_RESET) { - rc = qed_roce_sp_destroy_qp_responder(p_hwfn, qp, - &num_invalidated_mw, - &cq_prod); - if (rc) - return rc; - - /* Send destroy requester ramrod */ - rc = qed_roce_sp_destroy_qp_requester(p_hwfn, qp, - &num_bound_mw); - if (rc) - return rc; - - if (num_invalidated_mw != num_bound_mw) { - DP_NOTICE(p_hwfn, - "number of invalidate memory windows is different from bounded ones\n"); - return -EINVAL; - } - } - - return 0; -} - static int qed_rdma_query_qp(void *rdma_cxt, struct qed_rdma_qp *qp, struct qed_rdma_query_qp_out_params *out_params) @@ -2170,114 +1233,6 @@ qed_rdma_create_qp(void *rdma_cxt, return qp; } -static int qed_roce_modify_qp(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp, - enum qed_roce_qp_state prev_state, - struct qed_rdma_modify_qp_in_params *params) -{ - u32 num_invalidated_mw = 0, num_bound_mw = 0; - int rc = 0; - - /* Perform additional operations according to the current state and the - * next state - */ - if (((prev_state == QED_ROCE_QP_STATE_INIT) || - (prev_state == QED_ROCE_QP_STATE_RESET)) && - (qp->cur_state == QED_ROCE_QP_STATE_RTR)) { - /* Init->RTR or Reset->RTR */ - rc = qed_roce_sp_create_responder(p_hwfn, qp); - return rc; - } else if ((prev_state == QED_ROCE_QP_STATE_RTR) && - (qp->cur_state == QED_ROCE_QP_STATE_RTS)) { - /* RTR-> RTS */ - rc = qed_roce_sp_create_requester(p_hwfn, qp); - if (rc) - return rc; - - /* Send modify responder ramrod */ - rc = qed_roce_sp_modify_responder(p_hwfn, qp, false, - params->modify_flags); - return rc; - } else if ((prev_state == QED_ROCE_QP_STATE_RTS) && - (qp->cur_state == QED_ROCE_QP_STATE_RTS)) { - /* RTS->RTS */ - rc = qed_roce_sp_modify_responder(p_hwfn, qp, false, - params->modify_flags); - if (rc) - return rc; - - rc = qed_roce_sp_modify_requester(p_hwfn, qp, false, false, - params->modify_flags); - return rc; - } else if ((prev_state == QED_ROCE_QP_STATE_RTS) && - (qp->cur_state == QED_ROCE_QP_STATE_SQD)) { - /* RTS->SQD */ - rc = qed_roce_sp_modify_requester(p_hwfn, qp, true, false, - params->modify_flags); - return rc; - } else if ((prev_state == QED_ROCE_QP_STATE_SQD) && - (qp->cur_state == QED_ROCE_QP_STATE_SQD)) { - /* SQD->SQD */ - rc = qed_roce_sp_modify_responder(p_hwfn, qp, false, - params->modify_flags); - if (rc) - return rc; - - rc = qed_roce_sp_modify_requester(p_hwfn, qp, false, false, - params->modify_flags); - return rc; - } else if ((prev_state == QED_ROCE_QP_STATE_SQD) && - (qp->cur_state == QED_ROCE_QP_STATE_RTS)) { - /* SQD->RTS */ - rc = qed_roce_sp_modify_responder(p_hwfn, qp, false, - params->modify_flags); - if (rc) - return rc; - - rc = qed_roce_sp_modify_requester(p_hwfn, qp, false, false, - params->modify_flags); - - return rc; - } else if (qp->cur_state == QED_ROCE_QP_STATE_ERR) { - /* ->ERR */ - rc = qed_roce_sp_modify_responder(p_hwfn, qp, true, - params->modify_flags); - if (rc) - return rc; - - rc = qed_roce_sp_modify_requester(p_hwfn, qp, false, true, - params->modify_flags); - return rc; - } else if (qp->cur_state == QED_ROCE_QP_STATE_RESET) { - /* Any state -> RESET */ - u32 cq_prod; - - /* Send destroy responder ramrod */ - rc = qed_roce_sp_destroy_qp_responder(p_hwfn, - qp, - &num_invalidated_mw, - &cq_prod); - - if (rc) - return rc; - - qp->cq_prod = cq_prod; - - rc = qed_roce_sp_destroy_qp_requester(p_hwfn, qp, - &num_bound_mw); - - if (num_invalidated_mw != num_bound_mw) { - DP_NOTICE(p_hwfn, - "number of invalidate memory windows is different from bounded ones\n"); - return -EINVAL; - } - } else { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "0\n"); - } - - return rc; -} - static int qed_rdma_modify_qp(void *rdma_cxt, struct qed_rdma_qp *qp, struct qed_rdma_modify_qp_in_params *params) @@ -2599,37 +1554,12 @@ static int qed_rdma_deregister_tid(void *rdma_cxt, u32 itid) return rc; } -static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid) -{ - struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; - u32 start_cid, cid, xcid; - - /* an even icid belongs to a responder while an odd icid belongs to a - * requester. The 'cid' received as an input can be either. We calculate - * the "partner" icid and call it xcid. Only if both are free then the - * "cid" map can be cleared. - */ - start_cid = qed_cxt_get_proto_cid_start(p_hwfn, p_rdma_info->proto); - cid = icid - start_cid; - xcid = cid ^ 1; - - spin_lock_bh(&p_rdma_info->lock); - - qed_bmap_release_id(p_hwfn, &p_rdma_info->real_cid_map, cid); - if (qed_bmap_test_id(p_hwfn, &p_rdma_info->real_cid_map, xcid) == 0) { - qed_bmap_release_id(p_hwfn, &p_rdma_info->cid_map, cid); - qed_bmap_release_id(p_hwfn, &p_rdma_info->cid_map, xcid); - } - - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); -} - static void *qed_rdma_get_rdma_ctx(struct qed_dev *cdev) { return QED_LEADING_HWFN(cdev); } -static bool qed_rdma_allocated_qps(struct qed_hwfn *p_hwfn) +bool qed_rdma_allocated_qps(struct qed_hwfn *p_hwfn) { bool result; @@ -2646,7 +1576,7 @@ static bool qed_rdma_allocated_qps(struct qed_hwfn *p_hwfn) return result; } -static void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { u32 val; @@ -2658,19 +1588,6 @@ static void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) val, p_hwfn->dcbx_no_edpm, p_hwfn->db_bar_no_edpm); } -void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) -{ - u8 val; - - /* if any QPs are already active, we want to disable DPM, since their - * context information contains information from before the latest DCBx - * update. Otherwise enable it. - */ - val = qed_rdma_allocated_qps(p_hwfn) ? true : false; - p_hwfn->dcbx_no_edpm = (u8)val; - - qed_rdma_dpm_conf(p_hwfn, p_ptt); -} void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.h b/drivers/net/ethernet/qlogic/qed/qed_rdma.h index b178d9994a45..1836ff1810b4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.h +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.h @@ -29,8 +29,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#ifndef _QED_ROCE_H -#define _QED_ROCE_H +#ifndef _QED_RDMA_H +#define _QED_RDMA_H #include #include #include @@ -42,7 +42,7 @@ #include "qed.h" #include "qed_dev_api.h" #include "qed_hsi.h" -#include "qed_ll2.h" +#include "qed_roce.h" #define QED_RDMA_MAX_FMR (RDMA_MAX_TIDS) #define QED_RDMA_MAX_P_KEY (1) @@ -168,11 +168,34 @@ struct qed_rdma_qp { #if IS_ENABLED(CONFIG_QED_RDMA) void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); -void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); #else -static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} - -static inline void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt) {} +static inline void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} +static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) {} #endif + +int +qed_rdma_bmap_alloc(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 max_count, char *name); + +void +qed_rdma_bmap_free(struct qed_hwfn *p_hwfn, struct qed_bmap *bmap, bool check); + +int +qed_rdma_bmap_alloc_id(struct qed_hwfn *p_hwfn, + struct qed_bmap *bmap, u32 *id_num); + +void +qed_bmap_set_id(struct qed_hwfn *p_hwfn, struct qed_bmap *bmap, u32 id_num); + +void +qed_bmap_release_id(struct qed_hwfn *p_hwfn, struct qed_bmap *bmap, u32 id_num); + +int +qed_bmap_test_id(struct qed_hwfn *p_hwfn, struct qed_bmap *bmap, u32 id_num); + +void qed_rdma_set_fw_mac(u16 *p_fw_mac, u8 *p_qed_mac); + +bool qed_rdma_allocated_qps(struct qed_hwfn *p_hwfn); #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 9dc41a899ef2..a8426936f837 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -53,8 +53,9 @@ #include "qed_ll2.h" #include "qed_mcp.h" #include "qed_reg_addr.h" -#include "qed_roce.h" #include +#include "qed_rdma.h" +#include "qed_roce.h" #include "qed_sp.h" static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid); @@ -64,1093 +65,44 @@ qed_roce_async_event(struct qed_hwfn *p_hwfn, u8 fw_event_code, u16 echo, union event_ring_data *data, u8 fw_return_code) { - if (fw_event_code == ROCE_ASYNC_EVENT_DESTROY_QP_DONE) { - u16 icid = - (u16)le32_to_cpu(data->rdma_data.rdma_destroy_qp_data.cid); - - /* icid release in this async event can occur only if the icid - * was offloaded to the FW. In case it wasn't offloaded this is - * handled in qed_roce_sp_destroy_qp. - */ - qed_roce_free_real_icid(p_hwfn, icid); - } else { - struct qed_rdma_events *events = &p_hwfn->p_rdma_info->events; - - events->affiliated_event(p_hwfn->p_rdma_info->events.context, - fw_event_code, - (void *)&data->rdma_data.async_handle); - } - - return 0; -} - -static int qed_rdma_bmap_alloc(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 max_count, char *name) -{ - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "max_count = %08x\n", max_count); - - bmap->max_count = max_count; - - bmap->bitmap = kcalloc(BITS_TO_LONGS(max_count), sizeof(long), - GFP_KERNEL); - if (!bmap->bitmap) - return -ENOMEM; - - snprintf(bmap->name, QED_RDMA_MAX_BMAP_NAME, "%s", name); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "0\n"); - return 0; -} - -static int qed_rdma_bmap_alloc_id(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 *id_num) -{ - *id_num = find_first_zero_bit(bmap->bitmap, bmap->max_count); - if (*id_num >= bmap->max_count) - return -EINVAL; - - __set_bit(*id_num, bmap->bitmap); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "%s bitmap: allocated id %d\n", - bmap->name, *id_num); - - return 0; -} - -static void qed_bmap_set_id(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 id_num) -{ - if (id_num >= bmap->max_count) - return; - - __set_bit(id_num, bmap->bitmap); -} - -static void qed_bmap_release_id(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 id_num) -{ - bool b_acquired; - - if (id_num >= bmap->max_count) - return; - - b_acquired = test_and_clear_bit(id_num, bmap->bitmap); - if (!b_acquired) { - DP_NOTICE(p_hwfn, "%s bitmap: id %d already released\n", - bmap->name, id_num); - return; - } - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "%s bitmap: released id %d\n", - bmap->name, id_num); -} - -static int qed_bmap_test_id(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, u32 id_num) -{ - if (id_num >= bmap->max_count) - return -1; - - return test_bit(id_num, bmap->bitmap); -} - -static bool qed_bmap_is_empty(struct qed_bmap *bmap) -{ - return bmap->max_count == find_first_bit(bmap->bitmap, bmap->max_count); -} - -static u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id) -{ - /* First sb id for RoCE is after all the l2 sb */ - return FEAT_NUM((struct qed_hwfn *)p_hwfn, QED_PF_L2_QUE) + rel_sb_id; -} - -static int qed_rdma_alloc(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_rdma_start_in_params *params) -{ - struct qed_rdma_info *p_rdma_info; - u32 num_cons, num_tasks; - int rc = -ENOMEM; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocating RDMA\n"); - - /* Allocate a struct with current pf rdma info */ - p_rdma_info = kzalloc(sizeof(*p_rdma_info), GFP_KERNEL); - if (!p_rdma_info) - return rc; - - p_hwfn->p_rdma_info = p_rdma_info; - p_rdma_info->proto = PROTOCOLID_ROCE; - - num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto, - NULL); - - p_rdma_info->num_qps = num_cons / 2; - - num_tasks = qed_cxt_get_proto_tid_count(p_hwfn, PROTOCOLID_ROCE); - - /* Each MR uses a single task */ - p_rdma_info->num_mrs = num_tasks; - - /* Queue zone lines are shared between RoCE and L2 in such a way that - * they can be used by each without obstructing the other. - */ - p_rdma_info->queue_zone_base = (u16)RESC_START(p_hwfn, QED_L2_QUEUE); - p_rdma_info->max_queue_zones = (u16)RESC_NUM(p_hwfn, QED_L2_QUEUE); - - /* Allocate a struct with device params and fill it */ - p_rdma_info->dev = kzalloc(sizeof(*p_rdma_info->dev), GFP_KERNEL); - if (!p_rdma_info->dev) - goto free_rdma_info; - - /* Allocate a struct with port params and fill it */ - p_rdma_info->port = kzalloc(sizeof(*p_rdma_info->port), GFP_KERNEL); - if (!p_rdma_info->port) - goto free_rdma_dev; - - /* Allocate bit map for pd's */ - rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->pd_map, RDMA_MAX_PDS, - "PD"); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Failed to allocate pd_map, rc = %d\n", - rc); - goto free_rdma_port; - } - - /* Allocate DPI bitmap */ - rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->dpi_map, - p_hwfn->dpi_count, "DPI"); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Failed to allocate DPI bitmap, rc = %d\n", rc); - goto free_pd_map; - } - - /* Allocate bitmap for cq's. The maximum number of CQs is bounded to - * twice the number of QPs. - */ - rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->cq_map, - p_rdma_info->num_qps * 2, "CQ"); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Failed to allocate cq bitmap, rc = %d\n", rc); - goto free_dpi_map; - } - - /* Allocate bitmap for toggle bit for cq icids - * We toggle the bit every time we create or resize cq for a given icid. - * The maximum number of CQs is bounded to twice the number of QPs. - */ - rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->toggle_bits, - p_rdma_info->num_qps * 2, "Toggle"); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Failed to allocate toogle bits, rc = %d\n", rc); - goto free_cq_map; - } - - /* Allocate bitmap for itids */ - rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->tid_map, - p_rdma_info->num_mrs, "MR"); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Failed to allocate itids bitmaps, rc = %d\n", rc); - goto free_toggle_map; - } - - /* Allocate bitmap for cids used for qps. */ - rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->cid_map, num_cons, - "CID"); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Failed to allocate cid bitmap, rc = %d\n", rc); - goto free_tid_map; - } - - /* Allocate bitmap for cids used for responders/requesters. */ - rc = qed_rdma_bmap_alloc(p_hwfn, &p_rdma_info->real_cid_map, num_cons, - "REAL_CID"); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Failed to allocate real cid bitmap, rc = %d\n", rc); - goto free_cid_map; - } - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocation successful\n"); - return 0; - -free_cid_map: - kfree(p_rdma_info->cid_map.bitmap); -free_tid_map: - kfree(p_rdma_info->tid_map.bitmap); -free_toggle_map: - kfree(p_rdma_info->toggle_bits.bitmap); -free_cq_map: - kfree(p_rdma_info->cq_map.bitmap); -free_dpi_map: - kfree(p_rdma_info->dpi_map.bitmap); -free_pd_map: - kfree(p_rdma_info->pd_map.bitmap); -free_rdma_port: - kfree(p_rdma_info->port); -free_rdma_dev: - kfree(p_rdma_info->dev); -free_rdma_info: - kfree(p_rdma_info); - - return rc; -} - -static void qed_rdma_bmap_free(struct qed_hwfn *p_hwfn, - struct qed_bmap *bmap, bool check) -{ - int weight = bitmap_weight(bmap->bitmap, bmap->max_count); - int last_line = bmap->max_count / (64 * 8); - int last_item = last_line * 8 + - DIV_ROUND_UP(bmap->max_count % (64 * 8), 64); - u64 *pmap = (u64 *)bmap->bitmap; - int line, item, offset; - u8 str_last_line[200] = { 0 }; - - if (!weight || !check) - goto end; - - DP_NOTICE(p_hwfn, - "%s bitmap not free - size=%d, weight=%d, 512 bits per line\n", - bmap->name, bmap->max_count, weight); - - /* print aligned non-zero lines, if any */ - for (item = 0, line = 0; line < last_line; line++, item += 8) - if (bitmap_weight((unsigned long *)&pmap[item], 64 * 8)) - DP_NOTICE(p_hwfn, - "line 0x%04x: 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n", - line, - pmap[item], - pmap[item + 1], - pmap[item + 2], - pmap[item + 3], - pmap[item + 4], - pmap[item + 5], - pmap[item + 6], pmap[item + 7]); - - /* print last unaligned non-zero line, if any */ - if ((bmap->max_count % (64 * 8)) && - (bitmap_weight((unsigned long *)&pmap[item], - bmap->max_count - item * 64))) { - offset = sprintf(str_last_line, "line 0x%04x: ", line); - for (; item < last_item; item++) - offset += sprintf(str_last_line + offset, - "0x%016llx ", pmap[item]); - DP_NOTICE(p_hwfn, "%s\n", str_last_line); - } - -end: - kfree(bmap->bitmap); - bmap->bitmap = NULL; -} - -static void qed_rdma_resc_free(struct qed_hwfn *p_hwfn) -{ - struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; - - qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->cid_map, 1); - qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->pd_map, 1); - qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->dpi_map, 1); - qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->cq_map, 1); - qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->toggle_bits, 0); - qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->tid_map, 1); - - kfree(p_rdma_info->port); - kfree(p_rdma_info->dev); - - kfree(p_rdma_info); -} - -static void qed_rdma_free(struct qed_hwfn *p_hwfn) -{ - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Freeing RDMA\n"); - - qed_rdma_resc_free(p_hwfn); -} - -static void qed_rdma_get_guid(struct qed_hwfn *p_hwfn, u8 *guid) -{ - guid[0] = p_hwfn->hw_info.hw_mac_addr[0] ^ 2; - guid[1] = p_hwfn->hw_info.hw_mac_addr[1]; - guid[2] = p_hwfn->hw_info.hw_mac_addr[2]; - guid[3] = 0xff; - guid[4] = 0xfe; - guid[5] = p_hwfn->hw_info.hw_mac_addr[3]; - guid[6] = p_hwfn->hw_info.hw_mac_addr[4]; - guid[7] = p_hwfn->hw_info.hw_mac_addr[5]; -} - -static void qed_rdma_init_events(struct qed_hwfn *p_hwfn, - struct qed_rdma_start_in_params *params) -{ - struct qed_rdma_events *events; - - events = &p_hwfn->p_rdma_info->events; - - events->unaffiliated_event = params->events->unaffiliated_event; - events->affiliated_event = params->events->affiliated_event; - events->context = params->events->context; -} - -static void qed_rdma_init_devinfo(struct qed_hwfn *p_hwfn, - struct qed_rdma_start_in_params *params) -{ - struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev; - struct qed_dev *cdev = p_hwfn->cdev; - u32 pci_status_control; - u32 num_qps; - - /* Vendor specific information */ - dev->vendor_id = cdev->vendor_id; - dev->vendor_part_id = cdev->device_id; - dev->hw_ver = 0; - dev->fw_ver = (FW_MAJOR_VERSION << 24) | (FW_MINOR_VERSION << 16) | - (FW_REVISION_VERSION << 8) | (FW_ENGINEERING_VERSION); - - qed_rdma_get_guid(p_hwfn, (u8 *)&dev->sys_image_guid); - dev->node_guid = dev->sys_image_guid; - - dev->max_sge = min_t(u32, RDMA_MAX_SGE_PER_SQ_WQE, - RDMA_MAX_SGE_PER_RQ_WQE); - - if (cdev->rdma_max_sge) - dev->max_sge = min_t(u32, cdev->rdma_max_sge, dev->max_sge); - - dev->max_inline = ROCE_REQ_MAX_INLINE_DATA_SIZE; - - dev->max_inline = (cdev->rdma_max_inline) ? - min_t(u32, cdev->rdma_max_inline, dev->max_inline) : - dev->max_inline; - - dev->max_wqe = QED_RDMA_MAX_WQE; - dev->max_cnq = (u8)FEAT_NUM(p_hwfn, QED_RDMA_CNQ); - - /* The number of QPs may be higher than QED_ROCE_MAX_QPS, because - * it is up-aligned to 16 and then to ILT page size within qed cxt. - * This is OK in terms of ILT but we don't want to configure the FW - * above its abilities - */ - num_qps = ROCE_MAX_QPS; - num_qps = min_t(u64, num_qps, p_hwfn->p_rdma_info->num_qps); - dev->max_qp = num_qps; - - /* CQs uses the same icids that QPs use hence they are limited by the - * number of icids. There are two icids per QP. - */ - dev->max_cq = num_qps * 2; - - /* The number of mrs is smaller by 1 since the first is reserved */ - dev->max_mr = p_hwfn->p_rdma_info->num_mrs - 1; - dev->max_mr_size = QED_RDMA_MAX_MR_SIZE; - - /* The maximum CQE capacity per CQ supported. - * max number of cqes will be in two layer pbl, - * 8 is the pointer size in bytes - * 32 is the size of cq element in bytes - */ - if (params->cq_mode == QED_RDMA_CQ_MODE_32_BITS) - dev->max_cqe = QED_RDMA_MAX_CQE_32_BIT; - else - dev->max_cqe = QED_RDMA_MAX_CQE_16_BIT; - - dev->max_mw = 0; - dev->max_fmr = QED_RDMA_MAX_FMR; - dev->max_mr_mw_fmr_pbl = (PAGE_SIZE / 8) * (PAGE_SIZE / 8); - dev->max_mr_mw_fmr_size = dev->max_mr_mw_fmr_pbl * PAGE_SIZE; - dev->max_pkey = QED_RDMA_MAX_P_KEY; - - dev->max_qp_resp_rd_atomic_resc = RDMA_RING_PAGE_SIZE / - (RDMA_RESP_RD_ATOMIC_ELM_SIZE * 2); - dev->max_qp_req_rd_atomic_resc = RDMA_RING_PAGE_SIZE / - RDMA_REQ_RD_ATOMIC_ELM_SIZE; - dev->max_dev_resp_rd_atomic_resc = dev->max_qp_resp_rd_atomic_resc * - p_hwfn->p_rdma_info->num_qps; - dev->page_size_caps = QED_RDMA_PAGE_SIZE_CAPS; - dev->dev_ack_delay = QED_RDMA_ACK_DELAY; - dev->max_pd = RDMA_MAX_PDS; - dev->max_ah = p_hwfn->p_rdma_info->num_qps; - dev->max_stats_queues = (u8)RESC_NUM(p_hwfn, QED_RDMA_STATS_QUEUE); - - /* Set capablities */ - dev->dev_caps = 0; - SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_RNR_NAK, 1); - SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_PORT_ACTIVE_EVENT, 1); - SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_PORT_CHANGE_EVENT, 1); - SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_RESIZE_CQ, 1); - SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_BASE_MEMORY_EXT, 1); - SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_BASE_QUEUE_EXT, 1); - SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_ZBVA, 1); - SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_LOCAL_INV_FENCE, 1); - - /* Check atomic operations support in PCI configuration space. */ - pci_read_config_dword(cdev->pdev, - cdev->pdev->pcie_cap + PCI_EXP_DEVCTL2, - &pci_status_control); - - if (pci_status_control & PCI_EXP_DEVCTL2_LTR_EN) - SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_ATOMIC_OP, 1); -} - -static void qed_rdma_init_port(struct qed_hwfn *p_hwfn) -{ - struct qed_rdma_port *port = p_hwfn->p_rdma_info->port; - struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev; - - port->port_state = p_hwfn->mcp_info->link_output.link_up ? - QED_RDMA_PORT_UP : QED_RDMA_PORT_DOWN; - - port->max_msg_size = min_t(u64, - (dev->max_mr_mw_fmr_size * - p_hwfn->cdev->rdma_max_sge), - BIT(31)); - - port->pkey_bad_counter = 0; -} - -static int qed_rdma_init_hw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) -{ - u32 ll2_ethertype_en; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Initializing HW\n"); - p_hwfn->b_rdma_enabled_in_prs = false; - - qed_wr(p_hwfn, p_ptt, PRS_REG_ROCE_DEST_QP_MAX_PF, 0); - - p_hwfn->rdma_prs_search_reg = PRS_REG_SEARCH_ROCE; - - /* We delay writing to this reg until first cid is allocated. See - * qed_cxt_dynamic_ilt_alloc function for more details - */ - ll2_ethertype_en = qed_rd(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN); - qed_wr(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN, - (ll2_ethertype_en | 0x01)); - - if (qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_ROCE) % 2) { - DP_NOTICE(p_hwfn, "The first RoCE's cid should be even\n"); - return -EINVAL; - } - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Initializing HW - Done\n"); - return 0; -} - -static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn, - struct qed_rdma_start_in_params *params, - struct qed_ptt *p_ptt) -{ - struct rdma_init_func_ramrod_data *p_ramrod; - struct qed_rdma_cnq_params *p_cnq_pbl_list; - struct rdma_init_func_hdr *p_params_header; - struct rdma_cnq_params *p_cnq_params; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - u32 cnq_id, sb_id; - u16 igu_sb_id; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Starting FW\n"); - - /* Save the number of cnqs for the function close ramrod */ - p_hwfn->p_rdma_info->num_cnqs = params->desired_cnq; - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, RDMA_RAMROD_FUNC_INIT, - p_hwfn->p_rdma_info->proto, &init_data); - if (rc) - return rc; - - p_ramrod = &p_ent->ramrod.roce_init_func.rdma; - - p_params_header = &p_ramrod->params_header; - p_params_header->cnq_start_offset = (u8)RESC_START(p_hwfn, - QED_RDMA_CNQ_RAM); - p_params_header->num_cnqs = params->desired_cnq; - - if (params->cq_mode == QED_RDMA_CQ_MODE_16_BITS) - p_params_header->cq_ring_mode = 1; - else - p_params_header->cq_ring_mode = 0; - - for (cnq_id = 0; cnq_id < params->desired_cnq; cnq_id++) { - sb_id = qed_rdma_get_sb_id(p_hwfn, cnq_id); - igu_sb_id = qed_get_igu_sb_id(p_hwfn, sb_id); - p_ramrod->cnq_params[cnq_id].sb_num = cpu_to_le16(igu_sb_id); - p_cnq_params = &p_ramrod->cnq_params[cnq_id]; - p_cnq_pbl_list = ¶ms->cnq_pbl_list[cnq_id]; - - p_cnq_params->sb_index = p_hwfn->pf_params.rdma_pf_params.gl_pi; - p_cnq_params->num_pbl_pages = p_cnq_pbl_list->num_pbl_pages; - - DMA_REGPAIR_LE(p_cnq_params->pbl_base_addr, - p_cnq_pbl_list->pbl_ptr); - - /* we assume here that cnq_id and qz_offset are the same */ - p_cnq_params->queue_zone_num = - cpu_to_le16(p_hwfn->p_rdma_info->queue_zone_base + - cnq_id); - } - - return qed_spq_post(p_hwfn, p_ent, NULL); -} - -static int qed_rdma_alloc_tid(void *rdma_cxt, u32 *itid) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID\n"); - - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - rc = qed_rdma_bmap_alloc_id(p_hwfn, - &p_hwfn->p_rdma_info->tid_map, itid); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); - if (rc) - goto out; - - rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_TASK, *itid); -out: - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocate TID - done, rc = %d\n", rc); - return rc; -} - -static int qed_rdma_reserve_lkey(struct qed_hwfn *p_hwfn) -{ - struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev; - - /* The first DPI is reserved for the Kernel */ - __set_bit(0, p_hwfn->p_rdma_info->dpi_map.bitmap); - - /* Tid 0 will be used as the key for "reserved MR". - * The driver should allocate memory for it so it can be loaded but no - * ramrod should be passed on it. - */ - qed_rdma_alloc_tid(p_hwfn, &dev->reserved_lkey); - if (dev->reserved_lkey != RDMA_RESERVED_LKEY) { - DP_NOTICE(p_hwfn, - "Reserved lkey should be equal to RDMA_RESERVED_LKEY\n"); - return -EINVAL; - } - - return 0; -} - -static int qed_rdma_setup(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_rdma_start_in_params *params) -{ - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA setup\n"); - - spin_lock_init(&p_hwfn->p_rdma_info->lock); - - qed_rdma_init_devinfo(p_hwfn, params); - qed_rdma_init_port(p_hwfn); - qed_rdma_init_events(p_hwfn, params); - - rc = qed_rdma_reserve_lkey(p_hwfn); - if (rc) - return rc; - - rc = qed_rdma_init_hw(p_hwfn, p_ptt); - if (rc) - return rc; - - qed_spq_register_async_cb(p_hwfn, PROTOCOLID_ROCE, - qed_roce_async_event); - - return qed_rdma_start_fw(p_hwfn, params, p_ptt); -} - -void qed_roce_stop(struct qed_hwfn *p_hwfn) -{ - struct qed_bmap *rcid_map = &p_hwfn->p_rdma_info->real_cid_map; - int wait_count = 0; - - /* when destroying a_RoCE QP the control is returned to the user after - * the synchronous part. The asynchronous part may take a little longer. - * We delay for a short while if an async destroy QP is still expected. - * Beyond the added delay we clear the bitmap anyway. - */ - while (bitmap_weight(rcid_map->bitmap, rcid_map->max_count)) { - msleep(100); - if (wait_count++ > 20) { - DP_NOTICE(p_hwfn, "cid bitmap wait timed out\n"); - break; - } - } - qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_ROCE); -} - -static int qed_rdma_stop(void *rdma_cxt) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - struct rdma_close_func_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - struct qed_ptt *p_ptt; - u32 ll2_ethertype_en; - int rc = -EBUSY; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA stop\n"); - - p_ptt = qed_ptt_acquire(p_hwfn); - if (!p_ptt) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Failed to acquire PTT\n"); - return rc; - } - - /* Disable RoCE search */ - qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 0); - p_hwfn->b_rdma_enabled_in_prs = false; - - qed_wr(p_hwfn, p_ptt, PRS_REG_ROCE_DEST_QP_MAX_PF, 0); - - ll2_ethertype_en = qed_rd(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN); - - qed_wr(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN, - (ll2_ethertype_en & 0xFFFE)); - - qed_roce_stop(p_hwfn); - qed_ptt_release(p_hwfn, p_ptt); - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - /* Stop RoCE */ - rc = qed_sp_init_request(p_hwfn, &p_ent, RDMA_RAMROD_FUNC_CLOSE, - p_hwfn->p_rdma_info->proto, &init_data); - if (rc) - goto out; - - p_ramrod = &p_ent->ramrod.rdma_close_func; - - p_ramrod->num_cnqs = p_hwfn->p_rdma_info->num_cnqs; - p_ramrod->cnq_start_offset = (u8)RESC_START(p_hwfn, QED_RDMA_CNQ_RAM); - - rc = qed_spq_post(p_hwfn, p_ent, NULL); - -out: - qed_rdma_free(p_hwfn); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA stop done, rc = %d\n", rc); - return rc; -} - -static int qed_rdma_add_user(void *rdma_cxt, - struct qed_rdma_add_user_out_params *out_params) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - u32 dpi_start_offset; - u32 returned_id = 0; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Adding User\n"); - - /* Allocate DPI */ - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - rc = qed_rdma_bmap_alloc_id(p_hwfn, &p_hwfn->p_rdma_info->dpi_map, - &returned_id); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); - - out_params->dpi = (u16)returned_id; - - /* Calculate the corresponding DPI address */ - dpi_start_offset = p_hwfn->dpi_start_offset; - - out_params->dpi_addr = (u64)((u8 __iomem *)p_hwfn->doorbells + - dpi_start_offset + - ((out_params->dpi) * p_hwfn->dpi_size)); - - out_params->dpi_phys_addr = p_hwfn->cdev->db_phys_addr + - dpi_start_offset + - ((out_params->dpi) * p_hwfn->dpi_size); - - out_params->dpi_size = p_hwfn->dpi_size; - out_params->wid_count = p_hwfn->wid_count; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Adding user - done, rc = %d\n", rc); - return rc; -} - -static struct qed_rdma_port *qed_rdma_query_port(void *rdma_cxt) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - struct qed_rdma_port *p_port = p_hwfn->p_rdma_info->port; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA Query port\n"); - - /* Link may have changed */ - p_port->port_state = p_hwfn->mcp_info->link_output.link_up ? - QED_RDMA_PORT_UP : QED_RDMA_PORT_DOWN; - - p_port->link_speed = p_hwfn->mcp_info->link_output.speed; - - p_port->max_msg_size = RDMA_MAX_DATA_SIZE_IN_WQE; - - return p_port; -} - -static struct qed_rdma_device *qed_rdma_query_device(void *rdma_cxt) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Query device\n"); - - /* Return struct with device parameters */ - return p_hwfn->p_rdma_info->dev; -} - -static void qed_rdma_free_tid(void *rdma_cxt, u32 itid) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "itid = %08x\n", itid); - - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->tid_map, itid); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); -} - -static void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 qz_offset, u16 prod) -{ - struct qed_hwfn *p_hwfn; - u16 qz_num; - u32 addr; - - p_hwfn = (struct qed_hwfn *)rdma_cxt; - - if (qz_offset > p_hwfn->p_rdma_info->max_queue_zones) { - DP_NOTICE(p_hwfn, - "queue zone offset %d is too large (max is %d)\n", - qz_offset, p_hwfn->p_rdma_info->max_queue_zones); - return; - } - - qz_num = p_hwfn->p_rdma_info->queue_zone_base + qz_offset; - addr = GTT_BAR0_MAP_REG_USDM_RAM + - USTORM_COMMON_QUEUE_CONS_OFFSET(qz_num); - - REG_WR16(p_hwfn, addr, prod); - - /* keep prod updates ordered */ - wmb(); -} - -static int qed_fill_rdma_dev_info(struct qed_dev *cdev, - struct qed_dev_rdma_info *info) -{ - struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); - - memset(info, 0, sizeof(*info)); - - info->rdma_type = QED_RDMA_TYPE_ROCE; - info->user_dpm_enabled = (p_hwfn->db_bar_no_edpm == 0); - - qed_fill_dev_info(cdev, &info->common); - - return 0; -} - -static int qed_rdma_get_sb_start(struct qed_dev *cdev) -{ - int feat_num; - - if (cdev->num_hwfns > 1) - feat_num = FEAT_NUM(QED_LEADING_HWFN(cdev), QED_PF_L2_QUE); - else - feat_num = FEAT_NUM(QED_LEADING_HWFN(cdev), QED_PF_L2_QUE) * - cdev->num_hwfns; - - return feat_num; -} - -static int qed_rdma_get_min_cnq_msix(struct qed_dev *cdev) -{ - int n_cnq = FEAT_NUM(QED_LEADING_HWFN(cdev), QED_RDMA_CNQ); - int n_msix = cdev->int_params.rdma_msix_cnt; - - return min_t(int, n_cnq, n_msix); -} - -static int qed_rdma_set_int(struct qed_dev *cdev, u16 cnt) -{ - int limit = 0; - - /* Mark the fastpath as free/used */ - cdev->int_params.fp_initialized = cnt ? true : false; - - if (cdev->int_params.out.int_mode != QED_INT_MODE_MSIX) { - DP_ERR(cdev, - "qed roce supports only MSI-X interrupts (detected %d).\n", - cdev->int_params.out.int_mode); - return -EINVAL; - } else if (cdev->int_params.fp_msix_cnt) { - limit = cdev->int_params.rdma_msix_cnt; - } - - if (!limit) - return -ENOMEM; - - return min_t(int, cnt, limit); -} - -static int qed_rdma_get_int(struct qed_dev *cdev, struct qed_int_info *info) -{ - memset(info, 0, sizeof(*info)); - - if (!cdev->int_params.fp_initialized) { - DP_INFO(cdev, - "Protocol driver requested interrupt information, but its support is not yet configured\n"); - return -EINVAL; - } - - if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) { - int msix_base = cdev->int_params.rdma_msix_base; - - info->msix_cnt = cdev->int_params.rdma_msix_cnt; - info->msix = &cdev->int_params.msix_table[msix_base]; - - DP_VERBOSE(cdev, QED_MSG_RDMA, "msix_cnt = %d msix_base=%d\n", - info->msix_cnt, msix_base); - } - - return 0; -} - -static int qed_rdma_alloc_pd(void *rdma_cxt, u16 *pd) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - u32 returned_id; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Alloc PD\n"); - - /* Allocates an unused protection domain */ - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - rc = qed_rdma_bmap_alloc_id(p_hwfn, - &p_hwfn->p_rdma_info->pd_map, &returned_id); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); - - *pd = (u16)returned_id; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Alloc PD - done, rc = %d\n", rc); - return rc; -} - -static void qed_rdma_free_pd(void *rdma_cxt, u16 pd) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "pd = %08x\n", pd); - - /* Returns a previously allocated protection domain for reuse */ - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->pd_map, pd); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); -} - -static enum qed_rdma_toggle_bit -qed_rdma_toggle_bit_create_resize_cq(struct qed_hwfn *p_hwfn, u16 icid) -{ - struct qed_rdma_info *p_info = p_hwfn->p_rdma_info; - enum qed_rdma_toggle_bit toggle_bit; - u32 bmap_id; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", icid); - - /* the function toggle the bit that is related to a given icid - * and returns the new toggle bit's value - */ - bmap_id = icid - qed_cxt_get_proto_cid_start(p_hwfn, p_info->proto); - - spin_lock_bh(&p_info->lock); - toggle_bit = !test_and_change_bit(bmap_id, - p_info->toggle_bits.bitmap); - spin_unlock_bh(&p_info->lock); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QED_RDMA_TOGGLE_BIT_= %d\n", - toggle_bit); - - return toggle_bit; -} - -static int qed_rdma_create_cq(void *rdma_cxt, - struct qed_rdma_create_cq_in_params *params, - u16 *icid) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - struct qed_rdma_info *p_info = p_hwfn->p_rdma_info; - struct rdma_create_cq_ramrod_data *p_ramrod; - enum qed_rdma_toggle_bit toggle_bit; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - u32 returned_id, start_cid; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "cq_handle = %08x%08x\n", - params->cq_handle_hi, params->cq_handle_lo); - - /* Allocate icid */ - spin_lock_bh(&p_info->lock); - rc = qed_rdma_bmap_alloc_id(p_hwfn, &p_info->cq_map, &returned_id); - spin_unlock_bh(&p_info->lock); - - if (rc) { - DP_NOTICE(p_hwfn, "Can't create CQ, rc = %d\n", rc); - return rc; - } - - start_cid = qed_cxt_get_proto_cid_start(p_hwfn, - p_info->proto); - *icid = returned_id + start_cid; - - /* Check if icid requires a page allocation */ - rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_CXT, *icid); - if (rc) - goto err; - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = *icid; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - /* Send create CQ ramrod */ - rc = qed_sp_init_request(p_hwfn, &p_ent, - RDMA_RAMROD_CREATE_CQ, - p_info->proto, &init_data); - if (rc) - goto err; - - p_ramrod = &p_ent->ramrod.rdma_create_cq; - - p_ramrod->cq_handle.hi = cpu_to_le32(params->cq_handle_hi); - p_ramrod->cq_handle.lo = cpu_to_le32(params->cq_handle_lo); - p_ramrod->dpi = cpu_to_le16(params->dpi); - p_ramrod->is_two_level_pbl = params->pbl_two_level; - p_ramrod->max_cqes = cpu_to_le32(params->cq_size); - DMA_REGPAIR_LE(p_ramrod->pbl_addr, params->pbl_ptr); - p_ramrod->pbl_num_pages = cpu_to_le16(params->pbl_num_pages); - p_ramrod->cnq_id = (u8)RESC_START(p_hwfn, QED_RDMA_CNQ_RAM) + - params->cnq_id; - p_ramrod->int_timeout = params->int_timeout; - - /* toggle the bit for every resize or create cq for a given icid */ - toggle_bit = qed_rdma_toggle_bit_create_resize_cq(p_hwfn, *icid); - - p_ramrod->toggle_bit = toggle_bit; - - rc = qed_spq_post(p_hwfn, p_ent, NULL); - if (rc) { - /* restore toggle bit */ - qed_rdma_toggle_bit_create_resize_cq(p_hwfn, *icid); - goto err; - } - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Created CQ, rc = %d\n", rc); - return rc; - -err: - /* release allocated icid */ - spin_lock_bh(&p_info->lock); - qed_bmap_release_id(p_hwfn, &p_info->cq_map, returned_id); - spin_unlock_bh(&p_info->lock); - DP_NOTICE(p_hwfn, "Create CQ failed, rc = %d\n", rc); - - return rc; -} - -static int -qed_rdma_destroy_cq(void *rdma_cxt, - struct qed_rdma_destroy_cq_in_params *in_params, - struct qed_rdma_destroy_cq_out_params *out_params) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - struct rdma_destroy_cq_output_params *p_ramrod_res; - struct rdma_destroy_cq_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - dma_addr_t ramrod_res_phys; - enum protocol_type proto; - int rc = -ENOMEM; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", in_params->icid); - - p_ramrod_res = - (struct rdma_destroy_cq_output_params *) - dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(struct rdma_destroy_cq_output_params), - &ramrod_res_phys, GFP_KERNEL); - if (!p_ramrod_res) { - DP_NOTICE(p_hwfn, - "qed destroy cq failed: cannot allocate memory (ramrod)\n"); - return rc; - } - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.cid = in_params->icid; - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - proto = p_hwfn->p_rdma_info->proto; - /* Send destroy CQ ramrod */ - rc = qed_sp_init_request(p_hwfn, &p_ent, - RDMA_RAMROD_DESTROY_CQ, - proto, &init_data); - if (rc) - goto err; - - p_ramrod = &p_ent->ramrod.rdma_destroy_cq; - DMA_REGPAIR_LE(p_ramrod->output_params_addr, ramrod_res_phys); - - rc = qed_spq_post(p_hwfn, p_ent, NULL); - if (rc) - goto err; - - out_params->num_cq_notif = le16_to_cpu(p_ramrod_res->cnq_num); - - dma_free_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(struct rdma_destroy_cq_output_params), - p_ramrod_res, ramrod_res_phys); - - /* Free icid */ - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - - qed_bmap_release_id(p_hwfn, - &p_hwfn->p_rdma_info->cq_map, - (in_params->icid - - qed_cxt_get_proto_cid_start(p_hwfn, proto))); - - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + if (fw_event_code == ROCE_ASYNC_EVENT_DESTROY_QP_DONE) { + u16 icid = + (u16)le32_to_cpu(data->rdma_data.rdma_destroy_qp_data.cid); - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Destroyed CQ, rc = %d\n", rc); - return rc; + /* icid release in this async event can occur only if the icid + * was offloaded to the FW. In case it wasn't offloaded this is + * handled in qed_roce_sp_destroy_qp. + */ + qed_roce_free_real_icid(p_hwfn, icid); + } else { + struct qed_rdma_events *events = &p_hwfn->p_rdma_info->events; -err: dma_free_coherent(&p_hwfn->cdev->pdev->dev, - sizeof(struct rdma_destroy_cq_output_params), - p_ramrod_res, ramrod_res_phys); + events->affiliated_event(p_hwfn->p_rdma_info->events.context, + fw_event_code, + (void *)&data->rdma_data.async_handle); + } - return rc; + return 0; } -static void qed_rdma_set_fw_mac(u16 *p_fw_mac, u8 *p_qed_mac) +void qed_roce_stop(struct qed_hwfn *p_hwfn) { - p_fw_mac[0] = cpu_to_le16((p_qed_mac[0] << 8) + p_qed_mac[1]); - p_fw_mac[1] = cpu_to_le16((p_qed_mac[2] << 8) + p_qed_mac[3]); - p_fw_mac[2] = cpu_to_le16((p_qed_mac[4] << 8) + p_qed_mac[5]); + struct qed_bmap *rcid_map = &p_hwfn->p_rdma_info->real_cid_map; + int wait_count = 0; + + /* when destroying a_RoCE QP the control is returned to the user after + * the synchronous part. The asynchronous part may take a little longer. + * We delay for a short while if an async destroy QP is still expected. + * Beyond the added delay we clear the bitmap anyway. + */ + while (bitmap_weight(rcid_map->bitmap, rcid_map->max_count)) { + msleep(100); + if (wait_count++ > 20) { + DP_NOTICE(p_hwfn, "cid bitmap wait timed out\n"); + break; + } + } + qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_ROCE); } static void qed_rdma_copy_gids(struct qed_rdma_qp *qp, __le32 *src_gid, @@ -1204,7 +156,7 @@ void qed_roce_free_cid_pair(struct qed_hwfn *p_hwfn, u16 cid) spin_unlock_bh(&p_hwfn->p_rdma_info->lock); } -static int qed_roce_alloc_cid(struct qed_hwfn *p_hwfn, u16 *cid) +int qed_roce_alloc_cid(struct qed_hwfn *p_hwfn, u16 *cid) { struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; u32 responder_icid; @@ -1864,9 +816,9 @@ err: return rc; } -static int qed_roce_query_qp(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp, - struct qed_rdma_query_qp_out_params *out_params) +int qed_roce_query_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + struct qed_rdma_query_qp_out_params *out_params) { struct roce_query_qp_resp_output_params *p_resp_ramrod_res; struct roce_query_qp_req_output_params *p_req_ramrod_res; @@ -2005,7 +957,7 @@ err_resp: return rc; } -static int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) +int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) { u32 num_invalidated_mw = 0; u32 num_bound_mw = 0; @@ -2044,136 +996,10 @@ static int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) return 0; } -static int qed_rdma_query_qp(void *rdma_cxt, - struct qed_rdma_qp *qp, - struct qed_rdma_query_qp_out_params *out_params) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); - - /* The following fields are filled in from qp and not FW as they can't - * be modified by FW - */ - out_params->mtu = qp->mtu; - out_params->dest_qp = qp->dest_qp; - out_params->incoming_atomic_en = qp->incoming_atomic_en; - out_params->e2e_flow_control_en = qp->e2e_flow_control_en; - out_params->incoming_rdma_read_en = qp->incoming_rdma_read_en; - out_params->incoming_rdma_write_en = qp->incoming_rdma_write_en; - out_params->dgid = qp->dgid; - out_params->flow_label = qp->flow_label; - out_params->hop_limit_ttl = qp->hop_limit_ttl; - out_params->traffic_class_tos = qp->traffic_class_tos; - out_params->timeout = qp->ack_timeout; - out_params->rnr_retry = qp->rnr_retry_cnt; - out_params->retry_cnt = qp->retry_cnt; - out_params->min_rnr_nak_timer = qp->min_rnr_nak_timer; - out_params->pkey_index = 0; - out_params->max_rd_atomic = qp->max_rd_atomic_req; - out_params->max_dest_rd_atomic = qp->max_rd_atomic_resp; - out_params->sqd_async = qp->sqd_async; - - rc = qed_roce_query_qp(p_hwfn, qp, out_params); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Query QP, rc = %d\n", rc); - return rc; -} - -static int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - int rc = 0; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); - - rc = qed_roce_destroy_qp(p_hwfn, qp); - - /* free qp params struct */ - kfree(qp); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QP destroyed\n"); - return rc; -} - -static struct qed_rdma_qp * -qed_rdma_create_qp(void *rdma_cxt, - struct qed_rdma_create_qp_in_params *in_params, - struct qed_rdma_create_qp_out_params *out_params) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - struct qed_rdma_qp *qp; - u8 max_stats_queues; - int rc; - - if (!rdma_cxt || !in_params || !out_params || !p_hwfn->p_rdma_info) { - DP_ERR(p_hwfn->cdev, - "qed roce create qp failed due to NULL entry (rdma_cxt=%p, in=%p, out=%p, roce_info=?\n", - rdma_cxt, in_params, out_params); - return NULL; - } - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "qed rdma create qp called with qp_handle = %08x%08x\n", - in_params->qp_handle_hi, in_params->qp_handle_lo); - - /* Some sanity checks... */ - max_stats_queues = p_hwfn->p_rdma_info->dev->max_stats_queues; - if (in_params->stats_queue >= max_stats_queues) { - DP_ERR(p_hwfn->cdev, - "qed rdma create qp failed due to invalid statistics queue %d. maximum is %d\n", - in_params->stats_queue, max_stats_queues); - return NULL; - } - - qp = kzalloc(sizeof(*qp), GFP_KERNEL); - if (!qp) - return NULL; - - rc = qed_roce_alloc_cid(p_hwfn, &qp->icid); - qp->qpid = ((0xFF << 16) | qp->icid); - - DP_INFO(p_hwfn, "ROCE qpid=%x\n", qp->qpid); - - if (rc) { - kfree(qp); - return NULL; - } - - qp->cur_state = QED_ROCE_QP_STATE_RESET; - qp->qp_handle.hi = cpu_to_le32(in_params->qp_handle_hi); - qp->qp_handle.lo = cpu_to_le32(in_params->qp_handle_lo); - qp->qp_handle_async.hi = cpu_to_le32(in_params->qp_handle_async_hi); - qp->qp_handle_async.lo = cpu_to_le32(in_params->qp_handle_async_lo); - qp->use_srq = in_params->use_srq; - qp->signal_all = in_params->signal_all; - qp->fmr_and_reserved_lkey = in_params->fmr_and_reserved_lkey; - qp->pd = in_params->pd; - qp->dpi = in_params->dpi; - qp->sq_cq_id = in_params->sq_cq_id; - qp->sq_num_pages = in_params->sq_num_pages; - qp->sq_pbl_ptr = in_params->sq_pbl_ptr; - qp->rq_cq_id = in_params->rq_cq_id; - qp->rq_num_pages = in_params->rq_num_pages; - qp->rq_pbl_ptr = in_params->rq_pbl_ptr; - qp->srq_id = in_params->srq_id; - qp->req_offloaded = false; - qp->resp_offloaded = false; - qp->e2e_flow_control_en = qp->use_srq ? false : true; - qp->stats_queue = in_params->stats_queue; - - out_params->icid = qp->icid; - out_params->qp_id = qp->qpid; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Create QP, rc = %d\n", rc); - return qp; -} - -static int qed_roce_modify_qp(struct qed_hwfn *p_hwfn, - struct qed_rdma_qp *qp, - enum qed_roce_qp_state prev_state, - struct qed_rdma_modify_qp_in_params *params) +int qed_roce_modify_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + enum qed_roce_qp_state prev_state, + struct qed_rdma_modify_qp_in_params *params) { u32 num_invalidated_mw = 0, num_bound_mw = 0; int rc = 0; @@ -2278,327 +1104,6 @@ static int qed_roce_modify_qp(struct qed_hwfn *p_hwfn, return rc; } -static int qed_rdma_modify_qp(void *rdma_cxt, - struct qed_rdma_qp *qp, - struct qed_rdma_modify_qp_in_params *params) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - enum qed_roce_qp_state prev_state; - int rc = 0; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x params->new_state=%d\n", - qp->icid, params->new_state); - - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); - return rc; - } - - if (GET_FIELD(params->modify_flags, - QED_RDMA_MODIFY_QP_VALID_RDMA_OPS_EN)) { - qp->incoming_rdma_read_en = params->incoming_rdma_read_en; - qp->incoming_rdma_write_en = params->incoming_rdma_write_en; - qp->incoming_atomic_en = params->incoming_atomic_en; - } - - /* Update QP structure with the updated values */ - if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_ROCE_MODE)) - qp->roce_mode = params->roce_mode; - if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_PKEY)) - qp->pkey = params->pkey; - if (GET_FIELD(params->modify_flags, - QED_ROCE_MODIFY_QP_VALID_E2E_FLOW_CONTROL_EN)) - qp->e2e_flow_control_en = params->e2e_flow_control_en; - if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_DEST_QP)) - qp->dest_qp = params->dest_qp; - if (GET_FIELD(params->modify_flags, - QED_ROCE_MODIFY_QP_VALID_ADDRESS_VECTOR)) { - /* Indicates that the following parameters have changed: - * Traffic class, flow label, hop limit, source GID, - * destination GID, loopback indicator - */ - qp->traffic_class_tos = params->traffic_class_tos; - qp->flow_label = params->flow_label; - qp->hop_limit_ttl = params->hop_limit_ttl; - - qp->sgid = params->sgid; - qp->dgid = params->dgid; - qp->udp_src_port = 0; - qp->vlan_id = params->vlan_id; - qp->mtu = params->mtu; - qp->lb_indication = params->lb_indication; - memcpy((u8 *)&qp->remote_mac_addr[0], - (u8 *)¶ms->remote_mac_addr[0], ETH_ALEN); - if (params->use_local_mac) { - memcpy((u8 *)&qp->local_mac_addr[0], - (u8 *)¶ms->local_mac_addr[0], ETH_ALEN); - } else { - memcpy((u8 *)&qp->local_mac_addr[0], - (u8 *)&p_hwfn->hw_info.hw_mac_addr, ETH_ALEN); - } - } - if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_RQ_PSN)) - qp->rq_psn = params->rq_psn; - if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_SQ_PSN)) - qp->sq_psn = params->sq_psn; - if (GET_FIELD(params->modify_flags, - QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_REQ)) - qp->max_rd_atomic_req = params->max_rd_atomic_req; - if (GET_FIELD(params->modify_flags, - QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_RESP)) - qp->max_rd_atomic_resp = params->max_rd_atomic_resp; - if (GET_FIELD(params->modify_flags, - QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT)) - qp->ack_timeout = params->ack_timeout; - if (GET_FIELD(params->modify_flags, QED_ROCE_MODIFY_QP_VALID_RETRY_CNT)) - qp->retry_cnt = params->retry_cnt; - if (GET_FIELD(params->modify_flags, - QED_ROCE_MODIFY_QP_VALID_RNR_RETRY_CNT)) - qp->rnr_retry_cnt = params->rnr_retry_cnt; - if (GET_FIELD(params->modify_flags, - QED_ROCE_MODIFY_QP_VALID_MIN_RNR_NAK_TIMER)) - qp->min_rnr_nak_timer = params->min_rnr_nak_timer; - - qp->sqd_async = params->sqd_async; - - prev_state = qp->cur_state; - if (GET_FIELD(params->modify_flags, - QED_RDMA_MODIFY_QP_VALID_NEW_STATE)) { - qp->cur_state = params->new_state; - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "qp->cur_state=%d\n", - qp->cur_state); - } - - rc = qed_roce_modify_qp(p_hwfn, qp, prev_state, params); - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Modify QP, rc = %d\n", rc); - return rc; -} - -static int -qed_rdma_register_tid(void *rdma_cxt, - struct qed_rdma_register_tid_in_params *params) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - struct rdma_register_tid_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - enum rdma_tid_type tid_type; - u8 fw_return_code; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "itid = %08x\n", params->itid); - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, RDMA_RAMROD_REGISTER_MR, - p_hwfn->p_rdma_info->proto, &init_data); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); - return rc; - } - - if (p_hwfn->p_rdma_info->last_tid < params->itid) - p_hwfn->p_rdma_info->last_tid = params->itid; - - p_ramrod = &p_ent->ramrod.rdma_register_tid; - - p_ramrod->flags = 0; - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL, - params->pbl_two_level); - - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED, params->zbva); - - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR, params->phy_mr); - - /* Don't initialize D/C field, as it may override other bits. */ - if (!(params->tid_type == QED_RDMA_TID_FMR) && !(params->dma_mr)) - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG, - params->page_size_log - 12); - - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ, - params->remote_read); - - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE, - params->remote_write); - - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC, - params->remote_atomic); - - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE, - params->local_write); - - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ, params->local_read); - - SET_FIELD(p_ramrod->flags, - RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND, - params->mw_bind); - - SET_FIELD(p_ramrod->flags1, - RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG, - params->pbl_page_size_log - 12); - - SET_FIELD(p_ramrod->flags2, - RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR, params->dma_mr); - - switch (params->tid_type) { - case QED_RDMA_TID_REGISTERED_MR: - tid_type = RDMA_TID_REGISTERED_MR; - break; - case QED_RDMA_TID_FMR: - tid_type = RDMA_TID_FMR; - break; - case QED_RDMA_TID_MW_TYPE1: - tid_type = RDMA_TID_MW_TYPE1; - break; - case QED_RDMA_TID_MW_TYPE2A: - tid_type = RDMA_TID_MW_TYPE2A; - break; - default: - rc = -EINVAL; - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); - return rc; - } - SET_FIELD(p_ramrod->flags1, - RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE, tid_type); - - p_ramrod->itid = cpu_to_le32(params->itid); - p_ramrod->key = params->key; - p_ramrod->pd = cpu_to_le16(params->pd); - p_ramrod->length_hi = (u8)(params->length >> 32); - p_ramrod->length_lo = DMA_LO_LE(params->length); - if (params->zbva) { - /* Lower 32 bits of the registered MR address. - * In case of zero based MR, will hold FBO - */ - p_ramrod->va.hi = 0; - p_ramrod->va.lo = cpu_to_le32(params->fbo); - } else { - DMA_REGPAIR_LE(p_ramrod->va, params->vaddr); - } - DMA_REGPAIR_LE(p_ramrod->pbl_base, params->pbl_ptr); - - /* DIF */ - if (params->dif_enabled) { - SET_FIELD(p_ramrod->flags2, - RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG, 1); - DMA_REGPAIR_LE(p_ramrod->dif_error_addr, - params->dif_error_addr); - DMA_REGPAIR_LE(p_ramrod->dif_runt_addr, params->dif_runt_addr); - } - - rc = qed_spq_post(p_hwfn, p_ent, &fw_return_code); - if (rc) - return rc; - - if (fw_return_code != RDMA_RETURN_OK) { - DP_NOTICE(p_hwfn, "fw_return_code = %d\n", fw_return_code); - return -EINVAL; - } - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Register TID, rc = %d\n", rc); - return rc; -} - -static int qed_rdma_deregister_tid(void *rdma_cxt, u32 itid) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - struct rdma_deregister_tid_ramrod_data *p_ramrod; - struct qed_sp_init_data init_data; - struct qed_spq_entry *p_ent; - struct qed_ptt *p_ptt; - u8 fw_return_code; - int rc; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "itid = %08x\n", itid); - - /* Get SPQ entry */ - memset(&init_data, 0, sizeof(init_data)); - init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; - - rc = qed_sp_init_request(p_hwfn, &p_ent, RDMA_RAMROD_DEREGISTER_MR, - p_hwfn->p_rdma_info->proto, &init_data); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); - return rc; - } - - p_ramrod = &p_ent->ramrod.rdma_deregister_tid; - p_ramrod->itid = cpu_to_le32(itid); - - rc = qed_spq_post(p_hwfn, p_ent, &fw_return_code); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = %d\n", rc); - return rc; - } - - if (fw_return_code == RDMA_RETURN_DEREGISTER_MR_BAD_STATE_ERR) { - DP_NOTICE(p_hwfn, "fw_return_code = %d\n", fw_return_code); - return -EINVAL; - } else if (fw_return_code == RDMA_RETURN_NIG_DRAIN_REQ) { - /* Bit indicating that the TID is in use and a nig drain is - * required before sending the ramrod again - */ - p_ptt = qed_ptt_acquire(p_hwfn); - if (!p_ptt) { - rc = -EBUSY; - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Failed to acquire PTT\n"); - return rc; - } - - rc = qed_mcp_drain(p_hwfn, p_ptt); - if (rc) { - qed_ptt_release(p_hwfn, p_ptt); - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Drain failed\n"); - return rc; - } - - qed_ptt_release(p_hwfn, p_ptt); - - /* Resend the ramrod */ - rc = qed_sp_init_request(p_hwfn, &p_ent, - RDMA_RAMROD_DEREGISTER_MR, - p_hwfn->p_rdma_info->proto, - &init_data); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Failed to init sp-element\n"); - return rc; - } - - rc = qed_spq_post(p_hwfn, p_ent, &fw_return_code); - if (rc) { - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "Ramrod failed\n"); - return rc; - } - - if (fw_return_code != RDMA_RETURN_OK) { - DP_NOTICE(p_hwfn, "fw_return_code = %d\n", - fw_return_code); - return rc; - } - } - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "De-registered TID, rc = %d\n", rc); - return rc; -} - static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid) { struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; @@ -2624,40 +1129,6 @@ static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid) spin_unlock_bh(&p_hwfn->p_rdma_info->lock); } -static void *qed_rdma_get_rdma_ctx(struct qed_dev *cdev) -{ - return QED_LEADING_HWFN(cdev); -} - -static bool qed_rdma_allocated_qps(struct qed_hwfn *p_hwfn) -{ - bool result; - - /* if rdma info has not been allocated, naturally there are no qps */ - if (!p_hwfn->p_rdma_info) - return false; - - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - if (!p_hwfn->p_rdma_info->cid_map.bitmap) - result = false; - else - result = !qed_bmap_is_empty(&p_hwfn->p_rdma_info->cid_map); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); - return result; -} - -static void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) -{ - u32 val; - - val = (p_hwfn->dcbx_no_edpm || p_hwfn->db_bar_no_edpm) ? 0 : 1; - - qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DPM_ENABLE, val); - DP_VERBOSE(p_hwfn, (QED_MSG_DCB | QED_MSG_RDMA), - "Changing DPM_EN state to %d (DCBX=%d, DB_BAR=%d)\n", - val, p_hwfn->dcbx_no_edpm, p_hwfn->db_bar_no_edpm); -} - void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { u8 val; @@ -2672,134 +1143,9 @@ void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) qed_rdma_dpm_conf(p_hwfn, p_ptt); } -void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) -{ - p_hwfn->db_bar_no_edpm = true; - - qed_rdma_dpm_conf(p_hwfn, p_ptt); -} - -static int qed_rdma_start(void *rdma_cxt, - struct qed_rdma_start_in_params *params) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - struct qed_ptt *p_ptt; - int rc = -EBUSY; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, - "desired_cnq = %08x\n", params->desired_cnq); - - p_ptt = qed_ptt_acquire(p_hwfn); - if (!p_ptt) - goto err; - - rc = qed_rdma_alloc(p_hwfn, p_ptt, params); - if (rc) - goto err1; - - rc = qed_rdma_setup(p_hwfn, p_ptt, params); - if (rc) - goto err2; - - qed_ptt_release(p_hwfn, p_ptt); - - return rc; - -err2: - qed_rdma_free(p_hwfn); -err1: - qed_ptt_release(p_hwfn, p_ptt); -err: - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "RDMA start - error, rc = %d\n", rc); - return rc; -} - -static int qed_rdma_init(struct qed_dev *cdev, - struct qed_rdma_start_in_params *params) -{ - return qed_rdma_start(QED_LEADING_HWFN(cdev), params); -} - -static void qed_rdma_remove_user(void *rdma_cxt, u16 dpi) -{ - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "dpi = %08x\n", dpi); - - spin_lock_bh(&p_hwfn->p_rdma_info->lock); - qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->dpi_map, dpi); - spin_unlock_bh(&p_hwfn->p_rdma_info->lock); -} - -static int qed_roce_ll2_set_mac_filter(struct qed_dev *cdev, - u8 *old_mac_address, - u8 *new_mac_address) +int qed_roce_setup(struct qed_hwfn *p_hwfn) { - struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); - struct qed_ptt *p_ptt; - int rc = 0; - - p_ptt = qed_ptt_acquire(p_hwfn); - if (!p_ptt) { - DP_ERR(cdev, - "qed roce ll2 mac filter set: failed to acquire PTT\n"); - return -EINVAL; - } - - if (old_mac_address) - qed_llh_remove_mac_filter(p_hwfn, p_ptt, old_mac_address); - if (new_mac_address) - rc = qed_llh_add_mac_filter(p_hwfn, p_ptt, new_mac_address); - - qed_ptt_release(p_hwfn, p_ptt); - - if (rc) - DP_ERR(cdev, - "qed roce ll2 mac filter set: failed to add MAC filter\n"); - - return rc; + return qed_spq_register_async_cb(p_hwfn, PROTOCOLID_ROCE, + qed_roce_async_event); } -static const struct qed_rdma_ops qed_rdma_ops_pass = { - .common = &qed_common_ops_pass, - .fill_dev_info = &qed_fill_rdma_dev_info, - .rdma_get_rdma_ctx = &qed_rdma_get_rdma_ctx, - .rdma_init = &qed_rdma_init, - .rdma_add_user = &qed_rdma_add_user, - .rdma_remove_user = &qed_rdma_remove_user, - .rdma_stop = &qed_rdma_stop, - .rdma_query_port = &qed_rdma_query_port, - .rdma_query_device = &qed_rdma_query_device, - .rdma_get_start_sb = &qed_rdma_get_sb_start, - .rdma_get_rdma_int = &qed_rdma_get_int, - .rdma_set_rdma_int = &qed_rdma_set_int, - .rdma_get_min_cnq_msix = &qed_rdma_get_min_cnq_msix, - .rdma_cnq_prod_update = &qed_rdma_cnq_prod_update, - .rdma_alloc_pd = &qed_rdma_alloc_pd, - .rdma_dealloc_pd = &qed_rdma_free_pd, - .rdma_create_cq = &qed_rdma_create_cq, - .rdma_destroy_cq = &qed_rdma_destroy_cq, - .rdma_create_qp = &qed_rdma_create_qp, - .rdma_modify_qp = &qed_rdma_modify_qp, - .rdma_query_qp = &qed_rdma_query_qp, - .rdma_destroy_qp = &qed_rdma_destroy_qp, - .rdma_alloc_tid = &qed_rdma_alloc_tid, - .rdma_free_tid = &qed_rdma_free_tid, - .rdma_register_tid = &qed_rdma_register_tid, - .rdma_deregister_tid = &qed_rdma_deregister_tid, - .ll2_acquire_connection = &qed_ll2_acquire_connection, - .ll2_establish_connection = &qed_ll2_establish_connection, - .ll2_terminate_connection = &qed_ll2_terminate_connection, - .ll2_release_connection = &qed_ll2_release_connection, - .ll2_post_rx_buffer = &qed_ll2_post_rx_buffer, - .ll2_prepare_tx_packet = &qed_ll2_prepare_tx_packet, - .ll2_set_fragment_of_tx_packet = &qed_ll2_set_fragment_of_tx_packet, - .ll2_set_mac_filter = &qed_roce_ll2_set_mac_filter, - .ll2_get_stats = &qed_ll2_get_stats, -}; - -const struct qed_rdma_ops *qed_get_rdma_ops(void) -{ - return &qed_rdma_ops_pass; -} -EXPORT_SYMBOL(qed_get_rdma_ops); diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.h b/drivers/net/ethernet/qlogic/qed/qed_roce.h index b178d9994a45..f801f39fde61 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.h +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.h @@ -32,147 +32,28 @@ #ifndef _QED_ROCE_H #define _QED_ROCE_H #include -#include -#include -#include #include -#include -#include -#include -#include "qed.h" -#include "qed_dev_api.h" -#include "qed_hsi.h" -#include "qed_ll2.h" - -#define QED_RDMA_MAX_FMR (RDMA_MAX_TIDS) -#define QED_RDMA_MAX_P_KEY (1) -#define QED_RDMA_MAX_WQE (0x7FFF) -#define QED_RDMA_MAX_SRQ_WQE_ELEM (0x7FFF) -#define QED_RDMA_PAGE_SIZE_CAPS (0xFFFFF000) -#define QED_RDMA_ACK_DELAY (15) -#define QED_RDMA_MAX_MR_SIZE (0x10000000000ULL) -#define QED_RDMA_MAX_CQS (RDMA_MAX_CQS) -#define QED_RDMA_MAX_MRS (RDMA_MAX_TIDS) -/* Add 1 for header element */ -#define QED_RDMA_MAX_SRQ_ELEM_PER_WQE (RDMA_MAX_SGE_PER_RQ_WQE + 1) -#define QED_RDMA_MAX_SGE_PER_SRQ_WQE (RDMA_MAX_SGE_PER_RQ_WQE) -#define QED_RDMA_SRQ_WQE_ELEM_SIZE (16) -#define QED_RDMA_MAX_SRQS (32 * 1024) - -#define QED_RDMA_MAX_CQE_32_BIT (0x7FFFFFFF - 1) -#define QED_RDMA_MAX_CQE_16_BIT (0x7FFF - 1) - -enum qed_rdma_toggle_bit { - QED_RDMA_TOGGLE_BIT_CLEAR = 0, - QED_RDMA_TOGGLE_BIT_SET = 1 -}; - -#define QED_RDMA_MAX_BMAP_NAME (10) -struct qed_bmap { - unsigned long *bitmap; - u32 max_count; - char name[QED_RDMA_MAX_BMAP_NAME]; -}; - -struct qed_rdma_info { - /* spin lock to protect bitmaps */ - spinlock_t lock; - - struct qed_bmap cq_map; - struct qed_bmap pd_map; - struct qed_bmap tid_map; - struct qed_bmap qp_map; - struct qed_bmap srq_map; - struct qed_bmap cid_map; - struct qed_bmap real_cid_map; - struct qed_bmap dpi_map; - struct qed_bmap toggle_bits; - struct qed_rdma_events events; - struct qed_rdma_device *dev; - struct qed_rdma_port *port; - u32 last_tid; - u8 num_cnqs; - u32 num_qps; - u32 num_mrs; - u16 queue_zone_base; - u16 max_queue_zones; - enum protocol_type proto; -}; - -struct qed_rdma_qp { - struct regpair qp_handle; - struct regpair qp_handle_async; - u32 qpid; - u16 icid; - enum qed_roce_qp_state cur_state; - bool use_srq; - bool signal_all; - bool fmr_and_reserved_lkey; - - bool incoming_rdma_read_en; - bool incoming_rdma_write_en; - bool incoming_atomic_en; - bool e2e_flow_control_en; - - u16 pd; - u16 pkey; - u32 dest_qp; - u16 mtu; - u16 srq_id; - u8 traffic_class_tos; - u8 hop_limit_ttl; - u16 dpi; - u32 flow_label; - bool lb_indication; - u16 vlan_id; - u32 ack_timeout; - u8 retry_cnt; - u8 rnr_retry_cnt; - u8 min_rnr_nak_timer; - bool sqd_async; - union qed_gid sgid; - union qed_gid dgid; - enum roce_mode roce_mode; - u16 udp_src_port; - u8 stats_queue; - - /* requeseter */ - u8 max_rd_atomic_req; - u32 sq_psn; - u16 sq_cq_id; - u16 sq_num_pages; - dma_addr_t sq_pbl_ptr; - void *orq; - dma_addr_t orq_phys_addr; - u8 orq_num_pages; - bool req_offloaded; - - /* responder */ - u8 max_rd_atomic_resp; - u32 rq_psn; - u16 rq_cq_id; - u16 rq_num_pages; - dma_addr_t rq_pbl_ptr; - void *irq; - dma_addr_t irq_phys_addr; - u8 irq_num_pages; - bool resp_offloaded; - u32 cq_prod; - - u8 remote_mac_addr[6]; - u8 local_mac_addr[6]; - - void *shared_queue; - dma_addr_t shared_queue_phys_addr; -}; #if IS_ENABLED(CONFIG_QED_RDMA) -void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); #else -static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} - static inline void qed_roce_dpm_dcbx(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {} #endif + +int qed_roce_setup(struct qed_hwfn *p_hwfn); +void qed_roce_stop(struct qed_hwfn *p_hwfn); +int qed_roce_init_hw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); +int qed_roce_alloc_cid(struct qed_hwfn *p_hwfn, u16 *cid); +int qed_roce_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp); + +int qed_roce_query_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + struct qed_rdma_query_qp_out_params *out_params); + +int qed_roce_modify_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + enum qed_roce_qp_state prev_state, + struct qed_rdma_modify_qp_in_params *params); + #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index 78954d2c596e..be48d9abd001 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -54,7 +54,7 @@ #include "qed_reg_addr.h" #include "qed_sp.h" #include "qed_sriov.h" -#include "qed_roce.h" +#include "qed_rdma.h" /*************************************************************************** * Structures & Definitions -- cgit v1.2.3 From 7003cdd6a121e7bdb8a05eb1931f9549a36ea723 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Wed, 21 Jun 2017 16:22:46 +0300 Subject: qed*: Rename qed_roce_if.h to qed_rdma_if.h Rename the qed_roce_if file to qed_rdma_if as it represents a common interface for RoCE and iWARP. this commit affects RDMA/qedr as well. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/infiniband/hw/qedr/qedr.h | 2 +- drivers/infiniband/hw/qedr/qedr_cm.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_rdma.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_rdma.h | 2 +- drivers/net/ethernet/qlogic/qed/qed_roce.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 2376019a48ae..15365d5a0e19 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include "qedr_hsi_rdma.h" diff --git a/drivers/infiniband/hw/qedr/qedr_cm.c b/drivers/infiniband/hw/qedr/qedr_cm.c index eb3dce72fc21..4689e802b332 100644 --- a/drivers/infiniband/hw/qedr/qedr_cm.c +++ b/drivers/infiniband/hw/qedr/qedr_cm.c @@ -44,7 +44,7 @@ #include #include -#include +#include #include "qedr.h" #include "verbs.h" #include diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c index cb620e008444..df76e212f86e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -53,7 +53,7 @@ #include "qed_ll2.h" #include "qed_mcp.h" #include "qed_reg_addr.h" -#include +#include #include "qed_rdma.h" #include "qed_roce.h" #include "qed_sp.h" diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.h b/drivers/net/ethernet/qlogic/qed/qed_rdma.h index 1836ff1810b4..d91e5c4069a6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.h +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.h @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include "qed.h" #include "qed_dev_api.h" #include "qed_hsi.h" diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index a8426936f837..e53adc3d009b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -53,7 +53,7 @@ #include "qed_ll2.h" #include "qed_mcp.h" #include "qed_reg_addr.h" -#include +#include #include "qed_rdma.h" #include "qed_roce.h" #include "qed_sp.h" -- cgit v1.2.3 From 78aedd327982ddd3cbb6ffc58f6fe0179cb6238b Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Wed, 18 Jan 2017 14:28:53 +0200 Subject: net/mlx5e: Build SKB with exact frag_size Build the SKB over the receive packet instead of the whole page. Getting the SKB's linear data and shared_info closer improves locality. In addition, this opens up the possibility to make use of other parts of the page in the downstream page-reuse patch. Fixes: 1bfecfca565c ("net/mlx5e: Build RX SKB on demand") Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 6 +----- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 4 +++- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 5d9ace493d85..6af1fbe62082 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -72,6 +72,8 @@ #define MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE_MPW 0x6 #define MLX5_RX_HEADROOM NET_SKB_PAD +#define MLX5_SKB_FRAG_SZ(len) (SKB_DATA_ALIGN(len) + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) #define MLX5_MPWRQ_MIN_LOG_STRIDE_SZ(mdev) \ (6 + MLX5_CAP_GEN(mdev, cache_line_128byte)) /* HW restriction */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 167bca50320a..c991c1e9ea1f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -639,11 +639,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, byte_count = rq->buff.wqe_sz; /* calc the required page order */ - frag_sz = rq->rx_headroom + - byte_count /* packet data */ + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - frag_sz = SKB_DATA_ALIGN(frag_sz); - + frag_sz = MLX5_SKB_FRAG_SZ(rq->rx_headroom + byte_count); npages = DIV_ROUND_UP(frag_sz, PAGE_SIZE); rq->buff.page_order = order_base_2(npages); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index abf6d2fcfe0f..2eef4e701ab3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -740,6 +740,7 @@ struct sk_buff *skb_from_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe, void *va, *data; u16 rx_headroom = rq->rx_headroom; bool consumed; + u32 frag_size; di = &rq->dma_info[wqe_counter]; va = page_address(di->page); @@ -764,7 +765,8 @@ struct sk_buff *skb_from_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe, if (consumed) return NULL; /* page/packet was consumed by XDP */ - skb = build_skb(va, RQ_PAGE_SIZE(rq)); + frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt); + skb = build_skb(va, frag_size); if (unlikely(!skb)) { rq->stats.buff_alloc_err++; mlx5e_page_release(rq, di, true); -- cgit v1.2.3 From bce2b2bf66825a56f66229980a30884704cba3d2 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Tue, 31 Jan 2017 16:48:59 +0200 Subject: net/mlx5e: Enhance RX SKB headroom logic In the RX memory scheme of non Striding RQ, we use linear SKBs. Keeping NET_IP_ALIGN in headroom can improve performance on some archs. In addition, take this headroom into account when calculating the LRO WQE size. These are not needed in Striding RQ as they're done implicitly within the non-linear SKB allocation. Fixes: 1bfecfca565c ("net/mlx5e: Build RX SKB on demand") Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 14 ++++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 6af1fbe62082..00ff2a1651e7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -217,6 +217,7 @@ struct mlx5e_cq_moder { struct mlx5e_params { u8 log_sq_size; u8 rq_wq_type; + u16 rq_headroom; u8 mpwqe_log_stride_sz; u8 mpwqe_log_num_strides; u8 log_rq_size; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index c991c1e9ea1f..66173e5545ce 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -96,9 +96,12 @@ void mlx5e_set_rq_type_params(struct mlx5_core_dev *mdev, params->log_rq_size = is_kdump_kernel() ? MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE : MLX5E_PARAMS_DEFAULT_LOG_RQ_SIZE; + params->rq_headroom = params->xdp_prog ? + XDP_PACKET_HEADROOM : MLX5_RX_HEADROOM; + params->rq_headroom += NET_IP_ALIGN; /* Extra room needed for build_skb */ - params->lro_wqe_sz -= MLX5_RX_HEADROOM + + params->lro_wqe_sz -= params->rq_headroom + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); } @@ -579,13 +582,8 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, goto err_rq_wq_destroy; } - if (rq->xdp_prog) { - rq->buff.map_dir = DMA_BIDIRECTIONAL; - rq->rx_headroom = XDP_PACKET_HEADROOM; - } else { - rq->buff.map_dir = DMA_FROM_DEVICE; - rq->rx_headroom = MLX5_RX_HEADROOM; - } + rq->buff.map_dir = rq->xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE; + rq->rx_headroom = params->rq_headroom; switch (rq->wq_type) { case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ: -- cgit v1.2.3 From accd58833237d4ad835f7f176303ac2b582704e3 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Sun, 29 Jan 2017 17:42:26 +0200 Subject: net/mlx5e: Introduce RX Page-Reuse Introduce a Page-Reuse mechanism in non-Striding RQ RX datapath. A WQE (RX descriptor) buffer is a page, that in most cases was fully wasted on a packet that is much smaller, requiring a new page for the next round. In this patch, we implement a page-reuse mechanism, that resembles a `SW Striding RQ`. We allow the WQE to reuse its allocated page as much as it could, until the page is fully consumed. In each round, the WQE is capable of receiving packet of maximal size (MTU). Yet, upon the reception of a packet, the WQE knows the actual packet size, and consumes the exact amount of memory needed to build a linear SKB. Then, it updates the buffer pointer within the page accordingly, for the next round. Feature is mutually exclusive with XDP (packet-per-page) and LRO (session size is a power of two, needs unused page). Performance tests: iperf tcp tests show huge gain: -------------------------------------------- num streams | BW before | BW after | ratio | 1 | 22.2 | 30.9 | 1.39x | 8 | 64.2 | 93.6 | 1.46x | 64 | 56.7 | 91.4 | 1.61x | -------------------------------------------- Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 12 ++- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 28 +++-- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 119 ++++++++++++++++----- drivers/net/ethernet/mellanox/mlx5/core/en_stats.h | 4 + 4 files changed, 126 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 00ff2a1651e7..709f500ef16f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -448,6 +448,11 @@ struct mlx5e_dma_info { dma_addr_t addr; }; +struct mlx5e_wqe_frag_info { + struct mlx5e_dma_info di; + u32 offset; +}; + struct mlx5e_umr_dma_info { __be64 *mtt; dma_addr_t mtt_addr; @@ -509,7 +514,12 @@ struct mlx5e_rq { struct mlx5_wq_ll wq; union { - struct mlx5e_dma_info *dma_info; + struct { + struct mlx5e_wqe_frag_info *frag_info; + u32 frag_sz; /* max possible skb frag_sz */ + bool page_reuse; + bool xdp_xmit; + } wqe; struct { struct mlx5e_mpw_info *info; void *mtt_no_align; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 66173e5545ce..9f99f624004f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -200,6 +200,7 @@ static void mlx5e_update_sw_counters(struct mlx5e_priv *priv) s->rx_buff_alloc_err += rq_stats->buff_alloc_err; s->rx_cqe_compress_blks += rq_stats->cqe_compress_blks; s->rx_cqe_compress_pkts += rq_stats->cqe_compress_pkts; + s->rx_page_reuse += rq_stats->page_reuse; s->rx_cache_reuse += rq_stats->cache_reuse; s->rx_cache_full += rq_stats->cache_full; s->rx_cache_empty += rq_stats->cache_empty; @@ -550,7 +551,6 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, void *rqc = rqp->rqc; void *rqc_wq = MLX5_ADDR_OF(rqc, rqc, wq); u32 byte_count; - u32 frag_sz; int npages; int wq_sz; int err; @@ -614,9 +614,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, goto err_destroy_umr_mkey; break; default: /* MLX5_WQ_TYPE_LINKED_LIST */ - rq->dma_info = kzalloc_node(wq_sz * sizeof(*rq->dma_info), - GFP_KERNEL, cpu_to_node(c->cpu)); - if (!rq->dma_info) { + rq->wqe.frag_info = + kzalloc_node(wq_sz * sizeof(*rq->wqe.frag_info), + GFP_KERNEL, cpu_to_node(c->cpu)); + if (!rq->wqe.frag_info) { err = -ENOMEM; goto err_rq_wq_destroy; } @@ -625,7 +626,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, rq->handle_rx_cqe = c->priv->profile->rx_handlers.handle_rx_cqe; if (!rq->handle_rx_cqe) { - kfree(rq->dma_info); + kfree(rq->wqe.frag_info); err = -EINVAL; netdev_err(c->netdev, "RX handler of RQ is not set, err %d\n", err); goto err_rq_wq_destroy; @@ -634,11 +635,12 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, rq->buff.wqe_sz = params->lro_en ? params->lro_wqe_sz : MLX5E_SW2HW_MTU(c->priv, c->netdev->mtu); + rq->wqe.page_reuse = !params->xdp_prog && !params->lro_en; byte_count = rq->buff.wqe_sz; /* calc the required page order */ - frag_sz = MLX5_SKB_FRAG_SZ(rq->rx_headroom + byte_count); - npages = DIV_ROUND_UP(frag_sz, PAGE_SIZE); + rq->wqe.frag_sz = MLX5_SKB_FRAG_SZ(rq->rx_headroom + byte_count); + npages = DIV_ROUND_UP(rq->wqe.frag_sz, PAGE_SIZE); rq->buff.page_order = order_base_2(npages); byte_count |= MLX5_HW_START_PADDING; @@ -683,7 +685,7 @@ static void mlx5e_free_rq(struct mlx5e_rq *rq) mlx5_core_destroy_mkey(rq->mdev, &rq->umr_mkey); break; default: /* MLX5_WQ_TYPE_LINKED_LIST */ - kfree(rq->dma_info); + kfree(rq->wqe.frag_info); } for (i = rq->page_cache.head; i != rq->page_cache.tail; @@ -865,6 +867,16 @@ static void mlx5e_free_rx_descs(struct mlx5e_rq *rq) mlx5_wq_ll_pop(&rq->wq, wqe_ix_be, &wqe->next.next_wqe_index); } + + if (rq->wq_type == MLX5_WQ_TYPE_LINKED_LIST && rq->wqe.page_reuse) { + /* Clean outstanding pages on handled WQEs that decided to do page-reuse, + * but yet to be re-posted. + */ + int wq_sz = mlx5_wq_ll_get_size(&rq->wq); + + for (wqe_ix = 0; wqe_ix < wq_sz; wqe_ix++) + rq->dealloc_wqe(rq, wqe_ix); + } } static int mlx5e_open_rq(struct mlx5e_channel *c, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 2eef4e701ab3..5f3c138c948d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -160,6 +160,11 @@ static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq, #define RQ_PAGE_SIZE(rq) ((1 << rq->buff.page_order) << PAGE_SHIFT) +static inline bool mlx5e_page_is_reserved(struct page *page) +{ + return page_is_pfmemalloc(page) || page_to_nid(page) != numa_node_id(); +} + static inline bool mlx5e_rx_cache_put(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info) { @@ -238,22 +243,54 @@ void mlx5e_page_release(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info, put_page(dma_info->page); } +static inline bool mlx5e_page_reuse(struct mlx5e_rq *rq, + struct mlx5e_wqe_frag_info *wi) +{ + return rq->wqe.page_reuse && wi->di.page && + (wi->offset + rq->wqe.frag_sz <= RQ_PAGE_SIZE(rq)) && + !mlx5e_page_is_reserved(wi->di.page); +} + int mlx5e_alloc_rx_wqe(struct mlx5e_rq *rq, struct mlx5e_rx_wqe *wqe, u16 ix) { - struct mlx5e_dma_info *di = &rq->dma_info[ix]; + struct mlx5e_wqe_frag_info *wi = &rq->wqe.frag_info[ix]; - if (unlikely(mlx5e_page_alloc_mapped(rq, di))) - return -ENOMEM; + /* check if page exists, hence can be reused */ + if (!wi->di.page) { + if (unlikely(mlx5e_page_alloc_mapped(rq, &wi->di))) + return -ENOMEM; + wi->offset = 0; + } - wqe->data.addr = cpu_to_be64(di->addr + rq->rx_headroom); + wqe->data.addr = cpu_to_be64(wi->di.addr + wi->offset + + rq->rx_headroom); return 0; } +static inline void mlx5e_free_rx_wqe(struct mlx5e_rq *rq, + struct mlx5e_wqe_frag_info *wi) +{ + mlx5e_page_release(rq, &wi->di, true); + wi->di.page = NULL; +} + +static inline void mlx5e_free_rx_wqe_reuse(struct mlx5e_rq *rq, + struct mlx5e_wqe_frag_info *wi) +{ + if (mlx5e_page_reuse(rq, wi)) { + rq->stats.page_reuse++; + return; + } + + mlx5e_free_rx_wqe(rq, wi); +} + void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix) { - struct mlx5e_dma_info *di = &rq->dma_info[ix]; + struct mlx5e_wqe_frag_info *wi = &rq->wqe.frag_info[ix]; - mlx5e_page_release(rq, di, true); + if (wi->di.page) + mlx5e_free_rx_wqe(rq, wi); } static inline int mlx5e_mpwqe_strides_per_page(struct mlx5e_rq *rq) @@ -650,7 +687,6 @@ static inline bool mlx5e_xmit_xdp_frame(struct mlx5e_rq *rq, if (unlikely(dma_len < MLX5E_XDP_MIN_INLINE || MLX5E_SW2HW_MTU(rq->channel->priv, rq->netdev->mtu) < dma_len)) { rq->stats.xdp_drop++; - mlx5e_page_release(rq, di, true); return false; } @@ -661,7 +697,6 @@ static inline bool mlx5e_xmit_xdp_frame(struct mlx5e_rq *rq, sq->db.doorbell = false; } rq->stats.xdp_tx_full++; - mlx5e_page_release(rq, di, true); return false; } @@ -686,10 +721,15 @@ static inline bool mlx5e_xmit_xdp_frame(struct mlx5e_rq *rq, cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | MLX5_OPCODE_SEND); + /* move page to reference to sq responsibility, + * and mark so it's not put back in page-cache. + */ + rq->wqe.xdp_xmit = true; sq->db.di[pi] = *di; sq->pc++; sq->db.doorbell = true; + rq->stats.xdp_tx++; return true; } @@ -726,36 +766,34 @@ static inline int mlx5e_xdp_handle(struct mlx5e_rq *rq, trace_xdp_exception(rq->netdev, prog, act); case XDP_DROP: rq->stats.xdp_drop++; - mlx5e_page_release(rq, di, true); return true; } } static inline struct sk_buff *skb_from_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe, - u16 wqe_counter, u32 cqe_bcnt) + struct mlx5e_wqe_frag_info *wi, u32 cqe_bcnt) { - struct mlx5e_dma_info *di; + struct mlx5e_dma_info *di = &wi->di; struct sk_buff *skb; void *va, *data; u16 rx_headroom = rq->rx_headroom; bool consumed; u32 frag_size; - di = &rq->dma_info[wqe_counter]; - va = page_address(di->page); + va = page_address(di->page) + wi->offset; data = va + rx_headroom; + frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt); dma_sync_single_range_for_cpu(rq->pdev, - di->addr, - rx_headroom, - rq->buff.wqe_sz, + di->addr + wi->offset, + 0, frag_size, DMA_FROM_DEVICE); prefetch(data); + wi->offset += frag_size; if (unlikely((cqe->op_own >> 4) != MLX5_CQE_RESP_SEND)) { rq->stats.wqe_err++; - mlx5e_page_release(rq, di, true); return NULL; } @@ -765,17 +803,14 @@ struct sk_buff *skb_from_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe, if (consumed) return NULL; /* page/packet was consumed by XDP */ - frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt); skb = build_skb(va, frag_size); if (unlikely(!skb)) { rq->stats.buff_alloc_err++; - mlx5e_page_release(rq, di, true); return NULL; } - /* queue up for recycling ..*/ + /* queue up for recycling/reuse */ page_ref_inc(di->page); - mlx5e_page_release(rq, di, true); skb_reserve(skb, rx_headroom); skb_put(skb, cqe_bcnt); @@ -785,6 +820,7 @@ struct sk_buff *skb_from_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe, void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) { + struct mlx5e_wqe_frag_info *wi; struct mlx5e_rx_wqe *wqe; __be16 wqe_counter_be; struct sk_buff *skb; @@ -794,15 +830,27 @@ void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) wqe_counter_be = cqe->wqe_counter; wqe_counter = be16_to_cpu(wqe_counter_be); wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter); + wi = &rq->wqe.frag_info[wqe_counter]; cqe_bcnt = be32_to_cpu(cqe->byte_cnt); - skb = skb_from_cqe(rq, cqe, wqe_counter, cqe_bcnt); - if (!skb) + skb = skb_from_cqe(rq, cqe, wi, cqe_bcnt); + if (!skb) { + /* probably for XDP */ + if (rq->wqe.xdp_xmit) { + wi->di.page = NULL; + rq->wqe.xdp_xmit = false; + /* do not return page to cache, it will be returned on XDP_TX completion */ + goto wq_ll_pop; + } + /* probably an XDP_DROP, save the page-reuse checks */ + mlx5e_free_rx_wqe(rq, wi); goto wq_ll_pop; + } mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb); napi_gro_receive(rq->cq.napi, skb); + mlx5e_free_rx_wqe_reuse(rq, wi); wq_ll_pop: mlx5_wq_ll_pop(&rq->wq, wqe_counter_be, &wqe->next.next_wqe_index); @@ -814,6 +862,7 @@ void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *rep = rpriv->rep; + struct mlx5e_wqe_frag_info *wi; struct mlx5e_rx_wqe *wqe; struct sk_buff *skb; __be16 wqe_counter_be; @@ -823,11 +872,21 @@ void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) wqe_counter_be = cqe->wqe_counter; wqe_counter = be16_to_cpu(wqe_counter_be); wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter); + wi = &rq->wqe.frag_info[wqe_counter]; cqe_bcnt = be32_to_cpu(cqe->byte_cnt); - skb = skb_from_cqe(rq, cqe, wqe_counter, cqe_bcnt); - if (!skb) + skb = skb_from_cqe(rq, cqe, wi, cqe_bcnt); + if (!skb) { + if (rq->wqe.xdp_xmit) { + wi->di.page = NULL; + rq->wqe.xdp_xmit = false; + /* do not return page to cache, it will be returned on XDP_TX completion */ + goto wq_ll_pop; + } + /* probably an XDP_DROP, save the page-reuse checks */ + mlx5e_free_rx_wqe(rq, wi); goto wq_ll_pop; + } mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb); @@ -836,6 +895,7 @@ void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) napi_gro_receive(rq->cq.napi, skb); + mlx5e_free_rx_wqe_reuse(rq, wi); wq_ll_pop: mlx5_wq_ll_pop(&rq->wq, wqe_counter_be, &wqe->next.next_wqe_index); @@ -1096,6 +1156,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq, void mlx5i_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) { + struct mlx5e_wqe_frag_info *wi; struct mlx5e_rx_wqe *wqe; __be16 wqe_counter_be; struct sk_buff *skb; @@ -1105,16 +1166,18 @@ void mlx5i_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) wqe_counter_be = cqe->wqe_counter; wqe_counter = be16_to_cpu(wqe_counter_be); wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter); + wi = &rq->wqe.frag_info[wqe_counter]; cqe_bcnt = be32_to_cpu(cqe->byte_cnt); - skb = skb_from_cqe(rq, cqe, wqe_counter, cqe_bcnt); + skb = skb_from_cqe(rq, cqe, wi, cqe_bcnt); if (!skb) - goto wq_ll_pop; + goto wq_free_wqe; mlx5i_complete_rx_cqe(rq, cqe, cqe_bcnt, skb); napi_gro_receive(rq->cq.napi, skb); -wq_ll_pop: +wq_free_wqe: + mlx5e_free_rx_wqe_reuse(rq, wi); mlx5_wq_ll_pop(&rq->wq, wqe_counter_be, &wqe->next.next_wqe_index); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h index fda247587ff6..e65517eafc58 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h @@ -79,6 +79,7 @@ struct mlx5e_sw_stats { u64 rx_buff_alloc_err; u64 rx_cqe_compress_blks; u64 rx_cqe_compress_pkts; + u64 rx_page_reuse; u64 rx_cache_reuse; u64 rx_cache_full; u64 rx_cache_empty; @@ -117,6 +118,7 @@ static const struct counter_desc sw_stats_desc[] = { { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_buff_alloc_err) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_blks) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_pkts) }, + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_page_reuse) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_reuse) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_full) }, { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_empty) }, @@ -319,6 +321,7 @@ struct mlx5e_rq_stats { u64 buff_alloc_err; u64 cqe_compress_blks; u64 cqe_compress_pkts; + u64 page_reuse; u64 cache_reuse; u64 cache_full; u64 cache_empty; @@ -341,6 +344,7 @@ static const struct counter_desc rq_stats_desc[] = { { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, buff_alloc_err) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cqe_compress_blks) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cqe_compress_pkts) }, + { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, page_reuse) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cache_reuse) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cache_full) }, { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cache_empty) }, -- cgit v1.2.3 From 1f97a5265f1ba990c8ac200fb1e31db4f6ff5bea Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 6 Jun 2017 20:13:08 +0300 Subject: net/mlx5e: Relocate the TC match on ip tos offload code section The code section for offloading matches on ip tos (L3) should come before and not after the one that deals with tcp/udp (L4) matches. Otherwise, we might come up with wrong min-inline requirement, when one attempts to match on both L3 and L4. Fixes: fd7da28b280d ('net/mlx5e: Offload TC matching on ip tos / traffic-class') Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 46 ++++++++++++------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index b9170c5e7a82..633a91a71218 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -888,6 +888,29 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, *min_inline = MLX5_INLINE_MODE_IP; } + if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IP)) { + struct flow_dissector_key_ip *key = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_IP, + f->key); + struct flow_dissector_key_ip *mask = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_IP, + f->mask); + + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn, mask->tos & 0x3); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, key->tos & 0x3); + + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp, mask->tos >> 2); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, key->tos >> 2); + + if (mask->tos) + *min_inline = MLX5_INLINE_MODE_IP; + + if (mask->ttl) /* currently not supported */ + return -EOPNOTSUPP; + } + if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) { struct flow_dissector_key_ports *key = skb_flow_dissector_target(f->dissector, @@ -931,29 +954,6 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, *min_inline = MLX5_INLINE_MODE_TCP_UDP; } - if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IP)) { - struct flow_dissector_key_ip *key = - skb_flow_dissector_target(f->dissector, - FLOW_DISSECTOR_KEY_IP, - f->key); - struct flow_dissector_key_ip *mask = - skb_flow_dissector_target(f->dissector, - FLOW_DISSECTOR_KEY_IP, - f->mask); - - MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn, mask->tos & 0x3); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, key->tos & 0x3); - - MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp, mask->tos >> 2); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, key->tos >> 2); - - if (mask->tos) - *min_inline = MLX5_INLINE_MODE_IP; - - if (mask->ttl) /* currently not supported */ - return -EOPNOTSUPP; - } - if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_TCP)) { struct flow_dissector_key_tcp *key = skb_flow_dissector_target(f->dissector, -- cgit v1.2.3 From a8ade55ffd1c1acef053a2d05f30e91a1c114f58 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Wed, 7 Jun 2017 17:49:56 +0300 Subject: net/mlx5e: Offload TC matching on ip ttl Enable offloading of TC matching on ip ttl / hop-limit As matching on ttl is supported only by newer HW brands (ConnectX-5), we should do capability check before attempting to offload that. Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 633a91a71218..382dede903a3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -904,11 +904,16 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp, mask->tos >> 2); MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, key->tos >> 2); - if (mask->tos) - *min_inline = MLX5_INLINE_MODE_IP; + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ttl_hoplimit, mask->ttl); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ttl_hoplimit, key->ttl); - if (mask->ttl) /* currently not supported */ + if (mask->ttl && + !MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, + ft_field_support.outer_ipv4_ttl)) return -EOPNOTSUPP; + + if (mask->tos || mask->ttl) + *min_inline = MLX5_INLINE_MODE_IP; } if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) { -- cgit v1.2.3 From a8e4f0c4ced7cd41c61ebe5b8fef37f8a5fda8b5 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 13 Jun 2017 11:30:01 +0300 Subject: net/mlx5e: Use macro for TC header re-write offload field mapping Use a macro for the static mapping between the enumeration of field supported by the firmware for header re-write to the corresponding network header field. This improves the readability of the code and doesn't change any functionality. Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 54 +++++++++++++------------ 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 382dede903a3..0318d6f6e1da 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1058,32 +1058,36 @@ struct mlx5_fields { u32 offset; }; +#define OFFLOAD(fw_field, size, field, off) \ + {MLX5_ACTION_IN_FIELD_OUT_ ## fw_field, size, offsetof(struct pedit_headers, field) + (off)} + static struct mlx5_fields fields[] = { - {MLX5_ACTION_IN_FIELD_OUT_DMAC_47_16, 4, offsetof(struct pedit_headers, eth.h_dest[0])}, - {MLX5_ACTION_IN_FIELD_OUT_DMAC_15_0, 2, offsetof(struct pedit_headers, eth.h_dest[4])}, - {MLX5_ACTION_IN_FIELD_OUT_SMAC_47_16, 4, offsetof(struct pedit_headers, eth.h_source[0])}, - {MLX5_ACTION_IN_FIELD_OUT_SMAC_15_0, 2, offsetof(struct pedit_headers, eth.h_source[4])}, - {MLX5_ACTION_IN_FIELD_OUT_ETHERTYPE, 2, offsetof(struct pedit_headers, eth.h_proto)}, - - {MLX5_ACTION_IN_FIELD_OUT_IP_TTL, 1, offsetof(struct pedit_headers, ip4.ttl)}, - {MLX5_ACTION_IN_FIELD_OUT_SIPV4, 4, offsetof(struct pedit_headers, ip4.saddr)}, - {MLX5_ACTION_IN_FIELD_OUT_DIPV4, 4, offsetof(struct pedit_headers, ip4.daddr)}, - - {MLX5_ACTION_IN_FIELD_OUT_SIPV6_127_96, 4, offsetof(struct pedit_headers, ip6.saddr.s6_addr32[0])}, - {MLX5_ACTION_IN_FIELD_OUT_SIPV6_95_64, 4, offsetof(struct pedit_headers, ip6.saddr.s6_addr32[1])}, - {MLX5_ACTION_IN_FIELD_OUT_SIPV6_63_32, 4, offsetof(struct pedit_headers, ip6.saddr.s6_addr32[2])}, - {MLX5_ACTION_IN_FIELD_OUT_SIPV6_31_0, 4, offsetof(struct pedit_headers, ip6.saddr.s6_addr32[3])}, - {MLX5_ACTION_IN_FIELD_OUT_DIPV6_127_96, 4, offsetof(struct pedit_headers, ip6.daddr.s6_addr32[0])}, - {MLX5_ACTION_IN_FIELD_OUT_DIPV6_95_64, 4, offsetof(struct pedit_headers, ip6.daddr.s6_addr32[1])}, - {MLX5_ACTION_IN_FIELD_OUT_DIPV6_63_32, 4, offsetof(struct pedit_headers, ip6.daddr.s6_addr32[2])}, - {MLX5_ACTION_IN_FIELD_OUT_DIPV6_31_0, 4, offsetof(struct pedit_headers, ip6.daddr.s6_addr32[3])}, - - {MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT, 2, offsetof(struct pedit_headers, tcp.source)}, - {MLX5_ACTION_IN_FIELD_OUT_TCP_DPORT, 2, offsetof(struct pedit_headers, tcp.dest)}, - {MLX5_ACTION_IN_FIELD_OUT_TCP_FLAGS, 1, offsetof(struct pedit_headers, tcp.ack_seq) + 5}, - - {MLX5_ACTION_IN_FIELD_OUT_UDP_SPORT, 2, offsetof(struct pedit_headers, udp.source)}, - {MLX5_ACTION_IN_FIELD_OUT_UDP_DPORT, 2, offsetof(struct pedit_headers, udp.dest)}, + OFFLOAD(DMAC_47_16, 4, eth.h_dest[0], 0), + OFFLOAD(DMAC_47_16, 4, eth.h_dest[0], 0), + OFFLOAD(DMAC_15_0, 2, eth.h_dest[4], 0), + OFFLOAD(SMAC_47_16, 4, eth.h_source[0], 0), + OFFLOAD(SMAC_15_0, 2, eth.h_source[4], 0), + OFFLOAD(ETHERTYPE, 2, eth.h_proto, 0), + + OFFLOAD(IP_TTL, 1, ip4.ttl, 0), + OFFLOAD(SIPV4, 4, ip4.saddr, 0), + OFFLOAD(DIPV4, 4, ip4.daddr, 0), + + OFFLOAD(SIPV6_127_96, 4, ip6.saddr.s6_addr32[0], 0), + OFFLOAD(SIPV6_95_64, 4, ip6.saddr.s6_addr32[1], 0), + OFFLOAD(SIPV6_63_32, 4, ip6.saddr.s6_addr32[2], 0), + OFFLOAD(SIPV6_31_0, 4, ip6.saddr.s6_addr32[3], 0), + OFFLOAD(DIPV6_127_96, 4, ip6.daddr.s6_addr32[0], 0), + OFFLOAD(DIPV6_95_64, 4, ip6.daddr.s6_addr32[1], 0), + OFFLOAD(DIPV6_63_32, 4, ip6.daddr.s6_addr32[2], 0), + OFFLOAD(DIPV6_31_0, 4, ip6.daddr.s6_addr32[3], 0), + + OFFLOAD(TCP_SPORT, 2, tcp.source, 0), + OFFLOAD(TCP_DPORT, 2, tcp.dest, 0), + OFFLOAD(TCP_FLAGS, 1, tcp.ack_seq, 5), + + OFFLOAD(UDP_SPORT, 2, udp.source, 0), + OFFLOAD(UDP_DPORT, 2, udp.dest, 0), }; /* On input attr->num_mod_hdr_actions tells how many HW actions can be parsed at -- cgit v1.2.3 From 0c0316f516f51e6fcd0b23d61c37f9f5f846f978 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 13 Jun 2017 11:09:57 +0300 Subject: net/mlx5e: Add header re-write offloading of IPv6 hop-limit For environments where flow-based ipv6 router is offloaded. Signed-off-by: Or Gerlitz Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 0318d6f6e1da..3c536f560dd2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1081,6 +1081,7 @@ static struct mlx5_fields fields[] = { OFFLOAD(DIPV6_95_64, 4, ip6.daddr.s6_addr32[1], 0), OFFLOAD(DIPV6_63_32, 4, ip6.daddr.s6_addr32[2], 0), OFFLOAD(DIPV6_31_0, 4, ip6.daddr.s6_addr32[3], 0), + OFFLOAD(IPV6_HOPLIMIT, 1, ip6.hop_limit, 0), OFFLOAD(TCP_SPORT, 2, tcp.source, 0), OFFLOAD(TCP_DPORT, 2, tcp.dest, 0), -- cgit v1.2.3 From c2df61376bf68c6532f75916a66c1473e1c99866 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 6 Jun 2017 17:40:54 +0300 Subject: mlxfw: Make the module selectable There are upcoming NIC (mlx5) use-cases where people want to avoid building the mlxfw module, allow for that. The mlxsw module is untouched and keeps selecting mlxfw. Signed-off-by: Or Gerlitz Acked-by: Yotam Gigi Reviewed-by: Jiri Pirko Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlxfw/Kconfig | 8 +++++++- drivers/net/ethernet/mellanox/mlxfw/mlxfw.h | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxfw/Kconfig b/drivers/net/ethernet/mellanox/mlxfw/Kconfig index 2b21af8a2b1d..186ebe783f97 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxfw/Kconfig @@ -3,5 +3,11 @@ # config MLXFW - tristate "mlxfw" if COMPILE_TEST + tristate "Mellanox Technologies firmware flash module" + ---help--- + This driver supports Mellanox Technologies Firmware + flashing common logic. + + To compile this driver as a module, choose M here: the + module will be called mlxfw. select XZ_DEC diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h index beea4ba83495..9ca85383aa35 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h @@ -96,7 +96,16 @@ struct mlxfw_dev { u16 psid_size; }; +#if IS_ENABLED(CONFIG_MLXFW) int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, const struct firmware *firmware); +#else +static inline +int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + const struct firmware *firmware) +{ + return -EOPNOTSUPP; +} +#endif #endif -- cgit v1.2.3 From d2ad488b0073bd1a2c3f5d2ea50a7eb632103e5d Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 18 Apr 2017 16:41:57 +0300 Subject: net/mlx5: Add helper functions to set/query MCC/MCDA/MCQI registers To be used by the mlx5 callbacks exposed to the mlxfw module. Signed-off-by: Or Gerlitz Signed-off-by: Yotam Gigi Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 114 +++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index e9489e8d08bb..3a3c4fbc7168 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -223,3 +223,117 @@ int mlx5_cmd_force_teardown_hca(struct mlx5_core_dev *dev) return 0; } + +enum mlxsw_reg_mcc_instruction { + MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01, + MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02, + MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03, + MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04, + MLX5_REG_MCC_INSTRUCTION_ACTIVATE = 0x06, + MLX5_REG_MCC_INSTRUCTION_CANCEL = 0x08, +}; + +static int mlx5_reg_mcc_set(struct mlx5_core_dev *dev, + enum mlxsw_reg_mcc_instruction instr, + u16 component_index, u32 update_handle, + u32 component_size) +{ + u32 out[MLX5_ST_SZ_DW(mcc_reg)]; + u32 in[MLX5_ST_SZ_DW(mcc_reg)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(mcc_reg, in, instruction, instr); + MLX5_SET(mcc_reg, in, component_index, component_index); + MLX5_SET(mcc_reg, in, update_handle, update_handle); + MLX5_SET(mcc_reg, in, component_size, component_size); + + return mlx5_core_access_reg(dev, in, sizeof(in), out, + sizeof(out), MLX5_REG_MCC, 0, 1); +} + +static int mlx5_reg_mcc_query(struct mlx5_core_dev *dev, + u32 *update_handle, u8 *error_code, + u8 *control_state) +{ + u32 out[MLX5_ST_SZ_DW(mcc_reg)]; + u32 in[MLX5_ST_SZ_DW(mcc_reg)]; + int err; + + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + MLX5_SET(mcc_reg, in, update_handle, *update_handle); + + err = mlx5_core_access_reg(dev, in, sizeof(in), out, + sizeof(out), MLX5_REG_MCC, 0, 0); + if (err) + goto out; + + *update_handle = MLX5_GET(mcc_reg, out, update_handle); + *error_code = MLX5_GET(mcc_reg, out, error_code); + *control_state = MLX5_GET(mcc_reg, out, control_state); + +out: + return err; +} + +static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev, + u32 update_handle, + u32 offset, u16 size, + u8 *data) +{ + int err, in_size = MLX5_ST_SZ_BYTES(mcda_reg) + size; + u32 out[MLX5_ST_SZ_DW(mcda_reg)]; + int i, j, dw_size = size >> 2; + __be32 data_element; + u32 *in; + + in = kzalloc(in_size, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(mcda_reg, in, update_handle, update_handle); + MLX5_SET(mcda_reg, in, offset, offset); + MLX5_SET(mcda_reg, in, size, size); + + for (i = 0; i < dw_size; i++) { + j = i * 4; + data_element = htonl(*(u32 *)&data[j]); + memcpy(MLX5_ADDR_OF(mcda_reg, in, data) + j, &data_element, 4); + } + + err = mlx5_core_access_reg(dev, in, in_size, out, + sizeof(out), MLX5_REG_MCDA, 0, 1); + kfree(in); + return err; +} + +static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev, + u16 component_index, + u32 *max_component_size, + u8 *log_mcda_word_size, + u16 *mcda_max_write_size) +{ + u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_ST_SZ_DW(mcqi_cap)]; + int offset = MLX5_ST_SZ_DW(mcqi_reg); + u32 in[MLX5_ST_SZ_DW(mcqi_reg)]; + int err; + + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + + MLX5_SET(mcqi_reg, in, component_index, component_index); + MLX5_SET(mcqi_reg, in, data_size, MLX5_ST_SZ_BYTES(mcqi_cap)); + + err = mlx5_core_access_reg(dev, in, sizeof(in), out, + sizeof(out), MLX5_REG_MCQI, 0, 0); + if (err) + goto out; + + *max_component_size = MLX5_GET(mcqi_cap, out + offset, max_component_size); + *log_mcda_word_size = MLX5_GET(mcqi_cap, out + offset, log_mcda_word_size); + *mcda_max_write_size = MLX5_GET(mcqi_cap, out + offset, mcda_max_write_size); + +out: + return err; +} -- cgit v1.2.3 From 62bd22cf326dc4ac5be673c11cef4602dc1f5e47 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 18 Apr 2017 15:55:33 +0300 Subject: net/mlx5: Add mlxfw callbacks Add mlx5 implementation for the ones defined by the mlxfw shared module to be used while flashing the device firmware. The callbacks do their job through the MCQI, MCC and MCDA registers. Signed-off-by: Or Gerlitz Signed-off-by: Yotam Gigi Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 154 +++++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/mlx5_core.h | 3 + 2 files changed, 157 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 3a3c4fbc7168..fa33d59ab485 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -34,6 +34,7 @@ #include #include #include "mlx5_core.h" +#include "../../mlxfw/mlxfw.h" static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out, int outlen) @@ -337,3 +338,156 @@ static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev, out: return err; } + +struct mlx5_mlxfw_dev { + struct mlxfw_dev mlxfw_dev; + struct mlx5_core_dev *mlx5_core_dev; +}; + +static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev, + u16 component_index, u32 *p_max_size, + u8 *p_align_bits, u16 *p_max_write_size) +{ + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + + return mlx5_reg_mcqi_query(dev, component_index, p_max_size, + p_align_bits, p_max_write_size); +} + +static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle) +{ + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + u8 control_state, error_code; + int err; + + *fwhandle = 0; + err = mlx5_reg_mcc_query(dev, fwhandle, &error_code, &control_state); + if (err) + return err; + + if (control_state != MLXFW_FSM_STATE_IDLE) + return -EBUSY; + + return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE, + 0, *fwhandle, 0); +} + +static int mlx5_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + u16 component_index, u32 component_size) +{ + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + + return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_UPDATE_COMPONENT, + component_index, fwhandle, component_size); +} + +static int mlx5_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + u8 *data, u16 size, u32 offset) +{ + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + + return mlx5_reg_mcda_set(dev, fwhandle, offset, size, data); +} + +static int mlx5_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + u16 component_index) +{ + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + + return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_VERIFY_COMPONENT, + component_index, fwhandle, 0); +} + +static int mlx5_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) +{ + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + + return mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_ACTIVATE, 0, + fwhandle, 0); +} + +static int mlx5_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + enum mlxfw_fsm_state *fsm_state, + enum mlxfw_fsm_state_err *fsm_state_err) +{ + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + u8 control_state, error_code; + int err; + + err = mlx5_reg_mcc_query(dev, &fwhandle, &error_code, &control_state); + if (err) + return err; + + *fsm_state = control_state; + *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code, + MLXFW_FSM_STATE_ERR_MAX); + return 0; +} + +static void mlx5_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) +{ + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + + mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0); +} + +static void mlx5_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) +{ + struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = + container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); + struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; + + mlx5_reg_mcc_set(dev, MLX5_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0, + fwhandle, 0); +} + +static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = { + .component_query = mlx5_component_query, + .fsm_lock = mlx5_fsm_lock, + .fsm_component_update = mlx5_fsm_component_update, + .fsm_block_download = mlx5_fsm_block_download, + .fsm_component_verify = mlx5_fsm_component_verify, + .fsm_activate = mlx5_fsm_activate, + .fsm_query_state = mlx5_fsm_query_state, + .fsm_cancel = mlx5_fsm_cancel, + .fsm_release = mlx5_fsm_release +}; + +int mlx5_firmware_flash(struct mlx5_core_dev *dev, + const struct firmware *firmware) +{ + struct mlx5_mlxfw_dev mlx5_mlxfw_dev = { + .mlxfw_dev = { + .ops = &mlx5_mlxfw_dev_ops, + .psid = dev->board_id, + .psid_size = strlen(dev->board_id), + }, + .mlx5_core_dev = dev + }; + + if (!MLX5_CAP_GEN(dev, mcam_reg) || + !MLX5_CAP_MCAM_REG(dev, mcqi) || + !MLX5_CAP_MCAM_REG(dev, mcc) || + !MLX5_CAP_MCAM_REG(dev, mcda)) { + pr_info("%s flashing isn't supported by the running FW\n", __func__); + return -EOPNOTSUPP; + } + + return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev, firmware); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 5ccdf43e58a6..6a3d6bef7dd4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -37,6 +37,7 @@ #include #include #include +#include #define DRIVER_NAME "mlx5_core" #define DRIVER_VERSION "5.0-0" @@ -153,6 +154,8 @@ int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size); int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode); int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode); +int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw); + void mlx5e_init(void); void mlx5e_cleanup(void); -- cgit v1.2.3 From 3ffaabecd1a1a014a484f293c311b8ecb0545541 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 18 Apr 2017 17:48:46 +0300 Subject: net/mlx5e: Support the flash device ethtool callback This callback further invokes the mlxfw module to flash the new firmware file to the device. As the firmware flash process takes about 20 seconds and ethtool takes the rtnl lock during the flash_device callback, we release the rtnl lock at the beginning of the flash process and take it again before leaving the callback. This way, rtnl is not held during the process. To make sure the device does not get deleted while being flashed, we take a reference to it before releasing rtnl lock. Signed-off-by: Or Gerlitz Signed-off-by: Yotam Gigi Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 ++ .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 35 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 709f500ef16f..eef0a50e2388 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -1060,6 +1060,8 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal); int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv, struct ethtool_ts_info *info); +int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, + struct ethtool_flash *flash); /* mlx5e generic netdev management API */ struct net_device* diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 169435d8aa1e..16b1e96a7050 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -1795,6 +1795,40 @@ static int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) return err; } +int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, + struct ethtool_flash *flash) +{ + struct mlx5_core_dev *mdev = priv->mdev; + struct net_device *dev = priv->netdev; + const struct firmware *fw; + int err; + + if (flash->region != ETHTOOL_FLASH_ALL_REGIONS) + return -EOPNOTSUPP; + + err = request_firmware_direct(&fw, flash->data, &dev->dev); + if (err) + return err; + + dev_hold(dev); + rtnl_unlock(); + + err = mlx5_firmware_flash(mdev, fw); + release_firmware(fw); + + rtnl_lock(); + dev_put(dev); + return err; +} + +static int mlx5e_flash_device(struct net_device *dev, + struct ethtool_flash *flash) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + return mlx5e_ethtool_flash_device(priv, flash); +} + const struct ethtool_ops mlx5e_ethtool_ops = { .get_drvinfo = mlx5e_get_drvinfo, .get_link = ethtool_op_get_link, @@ -1815,6 +1849,7 @@ const struct ethtool_ops mlx5e_ethtool_ops = { .set_rxfh = mlx5e_set_rxfh, .get_rxnfc = mlx5e_get_rxnfc, .set_rxnfc = mlx5e_set_rxnfc, + .flash_device = mlx5e_flash_device, .get_tunable = mlx5e_get_tunable, .set_tunable = mlx5e_set_tunable, .get_pauseparam = mlx5e_get_pauseparam, -- cgit v1.2.3 From e2e086c196b297f84c625d53471e3edc022db565 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 21 May 2017 18:25:46 +0300 Subject: net/mlx5e: IPoIB, Support the flash device ethtool callback This callback further invokes the mlxfw module to flash the new firmware file to the device. Signed-off-by: Or Gerlitz Signed-off-by: Yotam Gigi Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c index bf686f0fde5d..eb04e97d8765 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c @@ -121,6 +121,14 @@ static int mlx5i_get_ts_info(struct net_device *netdev, return mlx5e_ethtool_get_ts_info(priv, info); } +static int mlx5i_flash_device(struct net_device *netdev, + struct ethtool_flash *flash) +{ + struct mlx5e_priv *priv = mlx5i_epriv(netdev); + + return mlx5e_ethtool_flash_device(priv, flash); +} + const struct ethtool_ops mlx5i_ethtool_ops = { .get_drvinfo = mlx5i_get_drvinfo, .get_strings = mlx5i_get_strings, @@ -128,6 +136,7 @@ const struct ethtool_ops mlx5i_ethtool_ops = { .get_ethtool_stats = mlx5i_get_ethtool_stats, .get_ringparam = mlx5i_get_ringparam, .set_ringparam = mlx5i_set_ringparam, + .flash_device = mlx5i_flash_device, .get_channels = mlx5i_get_channels, .set_channels = mlx5i_set_channels, .get_coalesce = mlx5i_get_coalesce, -- cgit v1.2.3 From b381f783baa5b755f065df347f738f303b62e948 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 19 Jun 2017 21:50:52 +0200 Subject: liquidio: stop using huge static buffer, save 4096k in .data Only compile-tested - I don't have the hardware. >From code inspection, octeon_pci_write_core_mem() appears to be safe wrt unaligned source. In any case, u8 fbuf[] was not guaranteed to be aligned anyway. Signed-off-by: Denys Vlasenko CC: Felix Manlunas CC: Prasad Kanneganti CC: Derek Chickles CC: David Miller CC: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org Acked-by: Felix Manlunas Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/octeon_console.c | 6 +----- drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c | 4 ++-- drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_console.c b/drivers/net/ethernet/cavium/liquidio/octeon_console.c index 53f38d05f7c2..e08f7600f986 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_console.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_console.c @@ -724,13 +724,11 @@ static int octeon_console_read(struct octeon_device *oct, u32 console_num, } #define FBUF_SIZE (4 * 1024 * 1024) -u8 fbuf[FBUF_SIZE]; int octeon_download_firmware(struct octeon_device *oct, const u8 *data, size_t size) { int ret = 0; - u8 *p = fbuf; u32 crc32_result; u64 load_addr; u32 image_len; @@ -805,10 +803,8 @@ int octeon_download_firmware(struct octeon_device *oct, const u8 *data, else size = FBUF_SIZE; - memcpy(p, data, size); - /* download the image */ - octeon_pci_write_core_mem(oct, load_addr, p, (u32)size); + octeon_pci_write_core_mem(oct, load_addr, data, (u32)size); data += size; rem -= (u32)size; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c index 5cd96e7d426c..4c85ae643b7b 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c @@ -167,10 +167,10 @@ octeon_pci_read_core_mem(struct octeon_device *oct, void octeon_pci_write_core_mem(struct octeon_device *oct, u64 coreaddr, - u8 *buf, + const u8 *buf, u32 len) { - __octeon_pci_rw_core_mem(oct, coreaddr, buf, len, 0); + __octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)buf, len, 0); } u64 octeon_read_device_mem64(struct octeon_device *oct, u64 coreaddr) diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h index bae2fdd89503..47a3ff5f9b1e 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h @@ -66,7 +66,7 @@ octeon_pci_read_core_mem(struct octeon_device *oct, void octeon_pci_write_core_mem(struct octeon_device *oct, u64 coreaddr, - u8 *buf, + const u8 *buf, u32 len); #endif -- cgit v1.2.3 From bbad7c2138d494f8af1d48f2140228633535dd14 Mon Sep 17 00:00:00 2001 From: Myron Stowe Date: Tue, 20 Jun 2017 11:21:26 -0600 Subject: net/mlx5e: Use device ID defines Use Mellanox device ID definitions in the driver's mlx5 ID table so tools such as 'grep' and 'cscope' can be used to help find correlated material (such as INTx Masking quirks: d76d2fe05fd PCI: Convert Mellanox broken INTx quirks to be for listed devices only). No functional change intended. Signed-off-by: Myron Stowe Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index db55ba457901..c7f75e12c13b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1556,11 +1556,11 @@ static void shutdown(struct pci_dev *pdev) } static const struct pci_device_id mlx5_core_pci_table[] = { - { PCI_VDEVICE(MELLANOX, 0x1011) }, /* Connect-IB */ + { PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_CONNECTIB) }, { PCI_VDEVICE(MELLANOX, 0x1012), MLX5_PCI_DEV_IS_VF}, /* Connect-IB VF */ - { PCI_VDEVICE(MELLANOX, 0x1013) }, /* ConnectX-4 */ + { PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_CONNECTX4) }, { PCI_VDEVICE(MELLANOX, 0x1014), MLX5_PCI_DEV_IS_VF}, /* ConnectX-4 VF */ - { PCI_VDEVICE(MELLANOX, 0x1015) }, /* ConnectX-4LX */ + { PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_CONNECTX4_LX) }, { PCI_VDEVICE(MELLANOX, 0x1016), MLX5_PCI_DEV_IS_VF}, /* ConnectX-4LX VF */ { PCI_VDEVICE(MELLANOX, 0x1017) }, /* ConnectX-5, PCIe 3.0 */ { PCI_VDEVICE(MELLANOX, 0x1018), MLX5_PCI_DEV_IS_VF}, /* ConnectX-5 VF */ -- cgit v1.2.3 From 2da55390a96ad2245edfaca77669c10088523d39 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 20 Jun 2017 22:40:46 +0200 Subject: net: phy: smsc: fix buffer overflow in memcpy The memcpy annotation triggers for a fixed-length buffer copy: In file included from /git/arm-soc/arch/arm64/include/asm/processor.h:30:0, from /git/arm-soc/arch/arm64/include/asm/spinlock.h:21, from /git/arm-soc/include/linux/spinlock.h:87, from /git/arm-soc/include/linux/seqlock.h:35, from /git/arm-soc/include/linux/time.h:5, from /git/arm-soc/include/linux/stat.h:21, from /git/arm-soc/include/linux/module.h:10, from /git/arm-soc/drivers/net/phy/smsc.c:20: In function 'memcpy', inlined from 'smsc_get_strings' at /git/arm-soc/drivers/net/phy/smsc.c:166:3: /git/arm-soc/include/linux/string.h:309:4: error: call to '__read_overflow2' declared with attribute error: detected read beyond size of object passed as 2nd parameter Using strncpy instead of memcpy should do the right thing here. Fixes: 030a89028db0 ("net: phy: smsc: Implement PHY statistics") Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/phy/smsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 1b8204be064c..2306bfae057f 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -163,7 +163,7 @@ static void smsc_get_strings(struct phy_device *phydev, u8 *data) int i; for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) { - memcpy(data + i * ETH_GSTRING_LEN, + strncpy(data + i * ETH_GSTRING_LEN, smsc_hw_stats[i].string, ETH_GSTRING_LEN); } } -- cgit v1.2.3 From 288ccb75b8fbf554d3fe21d1f91dbf489f10c6d4 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 21 Jun 2017 14:53:00 -0500 Subject: ibmvnic: Fix incorrectly defined ibmvnic_request_map_rsp structure This reserved area should be eight bytes in length instead of four. As a result, the return codes in the REQUEST_MAP_RSP descriptors were not being properly handled. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 7e2300e64a47..2d525c761b75 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -595,7 +595,7 @@ struct ibmvnic_request_map_rsp { u8 cmd; u8 reserved1; u8 map_id; - u8 reserved2[4]; + u8 reserved2[8]; struct ibmvnic_rc rc; } __packed __aligned(8); -- cgit v1.2.3 From f3be0cbc722c8de2f45c5d9f71f1b21da85554fd Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 21 Jun 2017 14:53:01 -0500 Subject: ibmvnic: Fix error handling when registering long-term-mapped buffers The patch stores the return code of the REQUEST_MAP_RSP sub-CRQ command in the private data structure, where it can be later checked during device open or a reset. In the case of a reset, the mapping request to the vNIC Server may fail, especially in the case of a partition migration. The driver attempts to handle this by re-allocating the buffer and re-sending the mapping request. The original error handling implementation was removed. The separate function handling the REQUEST_MAP response message was also removed, since it is now simple enough to be handled in the ibmvnic_handle_crq function. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 79 ++++++++++++++++---------------------- drivers/net/ethernet/ibm/ibmvnic.h | 1 + 2 files changed, 35 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 013509544632..aab69dd018d4 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -163,16 +163,6 @@ static long h_reg_sub_crq(unsigned long unit_address, unsigned long token, return rc; } -static void reset_long_term_buff(struct ibmvnic_adapter *adapter, - struct ibmvnic_long_term_buff *ltb) -{ - memset(ltb->buff, 0, ltb->size); - - init_completion(&adapter->fw_done); - send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); - wait_for_completion(&adapter->fw_done); -} - static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb, int size) { @@ -193,6 +183,12 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); wait_for_completion(&adapter->fw_done); + + if (adapter->fw_done_rc) { + dev_err(dev, "Couldn't map long term buffer,rc = %d\n", + adapter->fw_done_rc); + return -1; + } return 0; } @@ -210,6 +206,24 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter, dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); } +static int reset_long_term_buff(struct ibmvnic_adapter *adapter, + struct ibmvnic_long_term_buff *ltb) +{ + memset(ltb->buff, 0, ltb->size); + + init_completion(&adapter->fw_done); + send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); + wait_for_completion(&adapter->fw_done); + + if (adapter->fw_done_rc) { + dev_info(&adapter->vdev->dev, + "Reset failed, attempting to free and reallocate buffer\n"); + free_long_term_buff(adapter, ltb); + return alloc_long_term_buff(adapter, ltb, ltb->size); + } + return 0; +} + static void deactivate_rx_pools(struct ibmvnic_adapter *adapter) { int i; @@ -366,13 +380,15 @@ static int reset_rx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_rx_pool *rx_pool; int rx_scrqs; - int i, j; + int i, j, rc; rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); for (i = 0; i < rx_scrqs; i++) { rx_pool = &adapter->rx_pool[i]; - reset_long_term_buff(adapter, &rx_pool->long_term_buff); + rc = reset_long_term_buff(adapter, &rx_pool->long_term_buff); + if (rc) + return rc; for (j = 0; j < rx_pool->size; j++) rx_pool->free_map[j] = j; @@ -494,13 +510,15 @@ static int reset_tx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_tx_pool *tx_pool; int tx_scrqs; - int i, j; + int i, j, rc; tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); for (i = 0; i < tx_scrqs; i++) { tx_pool = &adapter->tx_pool[i]; - reset_long_term_buff(adapter, &tx_pool->long_term_buff); + rc = reset_long_term_buff(adapter, &tx_pool->long_term_buff); + if (rc) + return rc; memset(tx_pool->tx_buff, 0, adapter->req_tx_entries_per_subcrq * @@ -3075,36 +3093,6 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq, return 0; } -static void handle_request_map_rsp(union ibmvnic_crq *crq, - struct ibmvnic_adapter *adapter) -{ - struct device *dev = &adapter->vdev->dev; - u8 map_id = crq->request_map_rsp.map_id; - int tx_subcrqs; - int rx_subcrqs; - long rc; - int i; - - tx_subcrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); - rx_subcrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); - - rc = crq->request_map_rsp.rc.code; - if (rc) { - dev_err(dev, "Error %ld in REQUEST_MAP_RSP\n", rc); - adapter->map_id--; - /* need to find and zero tx/rx_pool map_id */ - for (i = 0; i < tx_subcrqs; i++) { - if (adapter->tx_pool[i].long_term_buff.map_id == map_id) - adapter->tx_pool[i].long_term_buff.map_id = 0; - } - for (i = 0; i < rx_subcrqs; i++) { - if (adapter->rx_pool[i].long_term_buff.map_id == map_id) - adapter->rx_pool[i].long_term_buff.map_id = 0; - } - } - complete(&adapter->fw_done); -} - static void handle_request_unmap_rsp(union ibmvnic_crq *crq, struct ibmvnic_adapter *adapter) { @@ -3385,7 +3373,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, handle_query_map_rsp(crq, adapter); break; case REQUEST_MAP_RSP: - handle_request_map_rsp(crq, adapter); + adapter->fw_done_rc = crq->request_map_rsp.rc.code; + complete(&adapter->fw_done); break; case REQUEST_UNMAP_RSP: handle_request_unmap_rsp(crq, adapter); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 2d525c761b75..8eff6e15f4bb 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -988,6 +988,7 @@ struct ibmvnic_adapter { spinlock_t error_list_lock; struct completion fw_done; + int fw_done_rc; /* partner capabilities */ u64 min_tx_queues; -- cgit v1.2.3 From 6d659237657c64e9e2a930865da4c777239b678e Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Wed, 21 Jun 2017 15:41:02 -0500 Subject: ibmvnic: Correct return code checking for ibmvnic_init during probe The update to ibmvnic_init to allow an EAGAIN return code broke the calling of ibmvnic_init from ibmvnic_probe. The code now will return from this point in the probe routine if anything other than EAGAIN is returned. The check should be to see if rc is non-zero and not equal to EAGAIN. Without this fix, the vNIC driver can return 0 (success) from its probe routine due to ibmvnic_init returning zero, but before completing the probe process and registering with the netdev layer. Fixes: 6a2fb0e99f9c (ibmvnic: driver initialization for kdump/kexec) Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index aab69dd018d4..87db1eb5cc44 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -3726,7 +3726,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) do { rc = ibmvnic_init(adapter); - if (rc != EAGAIN) { + if (rc && rc != EAGAIN) { free_netdev(netdev); return rc; } -- cgit v1.2.3 From dedb459e13f05824bc33d2d861e9b576bfc8d0bb Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Wed, 21 Jun 2017 16:40:46 -0700 Subject: hv_netvsc: Remove unnecessary var link_state from struct netvsc_device_info We simply use rndis_device->link_state in the netdev_dbg. The variable, link_state from struct netvsc_device_info, is not used anywhere else. Signed-off-by: Haiyang Zhang Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 5 +++-- drivers/net/hyperv/rndis_filter.c | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index b30a3c2f772b..ced947d25793 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -146,7 +146,6 @@ struct hv_netvsc_packet { struct netvsc_device_info { unsigned char mac_adr[ETH_ALEN]; - bool link_state; /* 0 - link up, 1 - link down */ int ring_size; u32 max_num_vrss_chns; u32 num_chn; @@ -165,7 +164,7 @@ struct rndis_device { struct net_device *ndev; enum rndis_device_state state; - bool link_state; + atomic_t new_req_id; spinlock_t request_lock; @@ -173,6 +172,8 @@ struct rndis_device { struct work_struct mcast_work; + bool link_state; /* 0 - link up, 1 - link down */ + u8 hw_mac_adr[ETH_ALEN]; u8 rss_key[NETVSC_HASH_KEYLEN]; u16 ind_table[ITAB_NUM]; diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index cb79cd081f42..85c00e1c52b6 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1185,11 +1185,9 @@ int rndis_filter_device_add(struct hv_device *dev, rndis_filter_query_device_link_status(rndis_device); - device_info->link_state = rndis_device->link_state; - netdev_dbg(net, "Device MAC %pM link state %s\n", rndis_device->hw_mac_adr, - device_info->link_state ? "down" : "up"); + rndis_device->link_state ? "down" : "up"); if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_5) return 0; -- cgit v1.2.3 From 53fa1a6f33520f01f9dbee48369074b34d77616b Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Wed, 21 Jun 2017 16:40:47 -0700 Subject: hv_netvsc: Fix the carrier state error when data path is off When the VF NIC is opened, the synthetic NIC's carrier state is set to off. This tells the host to transitions data path to the VF device. But if startup script or user manipulates the admin state of the netvsc device directly for example: # ifconfig eth0 down # ifconfig eth0 up Then the carrier state of the synthetic NIC would be on, even though the data path was still over the VF NIC. This patch sets the carrier state of synthetic NIC with consideration of the related VF state. Signed-off-by: Haiyang Zhang Reviewed-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 2 ++ drivers/net/hyperv/netvsc.c | 2 ++ drivers/net/hyperv/netvsc_drv.c | 8 +++++--- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index ced947d25793..d6c25580f8dd 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -717,6 +717,8 @@ struct net_device_context { u32 vf_alloc; /* Serial number of the VF to team with */ u32 vf_serial; + + bool datapath; /* 0 - synthetic, 1 - VF nic */ }; /* Per channel data */ diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 7c5ed8fe7a4f..0a9167dd72fb 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -57,6 +57,8 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf) sizeof(struct nvsp_message), (unsigned long)init_pkt, VM_PKT_DATA_INBAND, 0); + + net_device_ctx->datapath = vf; } static struct netvsc_device *alloc_net_device(void) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 9a6c5864bc04..991372150463 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -68,7 +68,8 @@ static void netvsc_set_multicast_list(struct net_device *net) static int netvsc_open(struct net_device *net) { - struct netvsc_device *nvdev = net_device_to_netvsc_device(net); + struct net_device_context *ndev_ctx = netdev_priv(net); + struct netvsc_device *nvdev = ndev_ctx->nvdev; struct rndis_device *rdev; int ret = 0; @@ -84,7 +85,7 @@ static int netvsc_open(struct net_device *net) netif_tx_wake_all_queues(net); rdev = nvdev->extension; - if (!rdev->link_state) + if (!rdev->link_state && !ndev_ctx->datapath) netif_carrier_on(net); return ret; @@ -1284,7 +1285,8 @@ static void netvsc_link_change(struct work_struct *w) case RNDIS_STATUS_MEDIA_CONNECT: if (rdev->link_state) { rdev->link_state = false; - netif_carrier_on(net); + if (!ndev_ctx->datapath) + netif_carrier_on(net); netif_tx_wake_all_queues(net); } else { notify = true; -- cgit v1.2.3 From c5d5287ef0f763e836bf94659b3a6080358373f1 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Thu, 22 Jun 2017 08:17:57 +0200 Subject: stmmac: pci: Make stmmac_pci_info structure constant By removing the PCI device reference from the structure and passing it as parameters to the interested functions, we can make quark_pci_info const. Signed-off-by: Jan Kiszka Reviewed-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 22f910795be4..0efe42659a37 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -38,17 +38,17 @@ struct stmmac_pci_dmi_data { }; struct stmmac_pci_info { - struct pci_dev *pdev; - int (*setup)(struct plat_stmmacenet_data *plat, - struct stmmac_pci_info *info); + int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat, + const struct stmmac_pci_info *info); struct stmmac_pci_dmi_data *dmi; }; -static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info) +static int stmmac_pci_find_phy_addr(struct pci_dev *pdev, + const struct stmmac_pci_info *info) { const char *name = dmi_get_system_info(DMI_BOARD_NAME); const char *asset_tag = dmi_get_system_info(DMI_BOARD_ASSET_TAG); - unsigned int func = PCI_FUNC(info->pdev->devfn); + unsigned int func = PCI_FUNC(pdev->devfn); struct stmmac_pci_dmi_data *dmi; /* @@ -114,10 +114,10 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat) /* TODO: AXI */ } -static int quark_default_data(struct plat_stmmacenet_data *plat, - struct stmmac_pci_info *info) +static int quark_default_data(struct pci_dev *pdev, + struct plat_stmmacenet_data *plat, + const struct stmmac_pci_info *info) { - struct pci_dev *pdev = info->pdev; int ret; /* Set common default data first */ @@ -127,7 +127,7 @@ static int quark_default_data(struct plat_stmmacenet_data *plat, * Refuse to load the driver and register net device if MAC controller * does not connect to any PHY interface. */ - ret = stmmac_pci_find_phy_addr(info); + ret = stmmac_pci_find_phy_addr(pdev, info); if (ret < 0) return ret; @@ -175,7 +175,7 @@ static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = { {} }; -static struct stmmac_pci_info quark_pci_info = { +static const struct stmmac_pci_info quark_pci_info = { .setup = quark_default_data, .dmi = quark_pci_dmi_data, }; @@ -237,9 +237,8 @@ static int stmmac_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); if (info) { - info->pdev = pdev; if (info->setup) { - ret = info->setup(plat, info); + ret = info->setup(pdev, plat, info); if (ret) return ret; } -- cgit v1.2.3 From b6a4c8f013ea2dd1ead7ee14b44712189a7bc6c6 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Thu, 22 Jun 2017 08:17:58 +0200 Subject: stmmac: pci: Use stmmac_pci_info for all devices Make stmmac_default_data compatible with stmmac_pci_info.setup and use an info structure for all devices. This allows to make the probing more regular. Signed-off-by: Jan Kiszka Reviewed-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 36 +++++++++++++++--------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 0efe42659a37..d3d74e526e17 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -100,7 +100,9 @@ static void common_default_data(struct plat_stmmacenet_data *plat) plat->rx_queues_cfg[0].pkt_route = 0x0; } -static void stmmac_default_data(struct plat_stmmacenet_data *plat) +static int stmmac_default_data(struct pci_dev *pdev, + struct plat_stmmacenet_data *plat, + const struct stmmac_pci_info *info) { /* Set common default data first */ common_default_data(plat); @@ -112,8 +114,14 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat) plat->dma_cfg->pbl = 32; plat->dma_cfg->pblx8 = true; /* TODO: AXI */ + + return 0; } +static const struct stmmac_pci_info stmmac_pci_info = { + .setup = stmmac_default_data, +}; + static int quark_default_data(struct pci_dev *pdev, struct plat_stmmacenet_data *plat, const struct stmmac_pci_info *info) @@ -236,14 +244,9 @@ static int stmmac_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - if (info) { - if (info->setup) { - ret = info->setup(pdev, plat, info); - if (ret) - return ret; - } - } else - stmmac_default_data(plat); + ret = info->setup(pdev, plat, info); + if (ret) + return ret; pci_enable_msi(pdev); @@ -269,14 +272,21 @@ static void stmmac_pci_remove(struct pci_dev *pdev) static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_suspend, stmmac_resume); -#define STMMAC_VENDOR_ID 0x700 +/* synthetic ID, no official vendor */ +#define PCI_VENDOR_ID_STMMAC 0x700 + #define STMMAC_QUARK_ID 0x0937 #define STMMAC_DEVICE_ID 0x1108 +#define STMMAC_DEVICE(vendor_id, dev_id, info) { \ + PCI_VDEVICE(vendor_id, dev_id), \ + .driver_data = (kernel_ulong_t)&info \ + } + static const struct pci_device_id stmmac_id_table[] = { - {PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)}, - {PCI_VDEVICE(INTEL, STMMAC_QUARK_ID), (kernel_ulong_t)&quark_pci_info}, + STMMAC_DEVICE(STMMAC, STMMAC_DEVICE_ID, stmmac_pci_info), + STMMAC_DEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_MAC, stmmac_pci_info), + STMMAC_DEVICE(INTEL, STMMAC_QUARK_ID, quark_pci_info), {} }; -- cgit v1.2.3 From c5f657e49c878756f21349f9e4b0f1c9631d5352 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Thu, 22 Jun 2017 08:17:59 +0200 Subject: stmmac: pci: Make stmmac_pci_find_phy_addr truly generic Move the special case for the early Galileo firmware into quark_default_setup. This allows to use stmmac_pci_find_phy_addr for non-quark cases. Signed-off-by: Jan Kiszka Reviewed-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index d3d74e526e17..f44ae49eb11c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -51,12 +51,8 @@ static int stmmac_pci_find_phy_addr(struct pci_dev *pdev, unsigned int func = PCI_FUNC(pdev->devfn); struct stmmac_pci_dmi_data *dmi; - /* - * Galileo boards with old firmware don't support DMI. We always return - * 1 here, so at least first found MAC controller would be probed. - */ if (!name) - return 1; + return -ENODEV; for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) { if (!strcmp(dmi->name, name) && dmi->func == func) { @@ -136,8 +132,18 @@ static int quark_default_data(struct pci_dev *pdev, * does not connect to any PHY interface. */ ret = stmmac_pci_find_phy_addr(pdev, info); - if (ret < 0) - return ret; + if (ret < 0) { + /* Return error to the caller on DMI enabled boards. */ + if (dmi_get_system_info(DMI_BOARD_NAME)) + return ret; + + /* + * Galileo boards with old firmware don't support DMI. We always + * use 1 here as PHY address, so at least the first found MAC + * controller would be probed. + */ + ret = 1; + } plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn); plat->phy_addr = ret; -- cgit v1.2.3 From 7bc519b3ea04026877242328d2fe73cc8e6102bd Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Thu, 22 Jun 2017 08:18:00 +0200 Subject: stmmac: pci: Select quark_pci_dmi_data from quark_default_data No need to carry this reference in stmmac_pci_info - the Quark-specific setup handler knows that it needs to use the Quark-specific DMI table. This also allows to drop the stmmac_pci_info reference from the setup handler parameter list. Signed-off-by: Jan Kiszka Reviewed-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 83 +++++++++++------------- 1 file changed, 39 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index f44ae49eb11c..a6e10d3ced5c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -38,13 +38,11 @@ struct stmmac_pci_dmi_data { }; struct stmmac_pci_info { - int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat, - const struct stmmac_pci_info *info); - struct stmmac_pci_dmi_data *dmi; + int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat); }; static int stmmac_pci_find_phy_addr(struct pci_dev *pdev, - const struct stmmac_pci_info *info) + struct stmmac_pci_dmi_data *dmi_data) { const char *name = dmi_get_system_info(DMI_BOARD_NAME); const char *asset_tag = dmi_get_system_info(DMI_BOARD_ASSET_TAG); @@ -54,7 +52,7 @@ static int stmmac_pci_find_phy_addr(struct pci_dev *pdev, if (!name) return -ENODEV; - for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) { + for (dmi = dmi_data; dmi->name && *dmi->name; dmi++) { if (!strcmp(dmi->name, name) && dmi->func == func) { /* If asset tag is provided, match on it as well. */ if (dmi->asset_tag && strcmp(dmi->asset_tag, asset_tag)) @@ -97,8 +95,7 @@ static void common_default_data(struct plat_stmmacenet_data *plat) } static int stmmac_default_data(struct pci_dev *pdev, - struct plat_stmmacenet_data *plat, - const struct stmmac_pci_info *info) + struct plat_stmmacenet_data *plat) { /* Set common default data first */ common_default_data(plat); @@ -118,9 +115,40 @@ static const struct stmmac_pci_info stmmac_pci_info = { .setup = stmmac_default_data, }; +static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = { + { + .name = "Galileo", + .func = 6, + .phy_addr = 1, + }, + { + .name = "GalileoGen2", + .func = 6, + .phy_addr = 1, + }, + { + .name = "SIMATIC IOT2000", + .asset_tag = "6ES7647-0AA00-0YA2", + .func = 6, + .phy_addr = 1, + }, + { + .name = "SIMATIC IOT2000", + .asset_tag = "6ES7647-0AA00-1YA2", + .func = 6, + .phy_addr = 1, + }, + { + .name = "SIMATIC IOT2000", + .asset_tag = "6ES7647-0AA00-1YA2", + .func = 7, + .phy_addr = 1, + }, + {} +}; + static int quark_default_data(struct pci_dev *pdev, - struct plat_stmmacenet_data *plat, - const struct stmmac_pci_info *info) + struct plat_stmmacenet_data *plat) { int ret; @@ -131,7 +159,7 @@ static int quark_default_data(struct pci_dev *pdev, * Refuse to load the driver and register net device if MAC controller * does not connect to any PHY interface. */ - ret = stmmac_pci_find_phy_addr(pdev, info); + ret = stmmac_pci_find_phy_addr(pdev, quark_pci_dmi_data); if (ret < 0) { /* Return error to the caller on DMI enabled boards. */ if (dmi_get_system_info(DMI_BOARD_NAME)) @@ -157,41 +185,8 @@ static int quark_default_data(struct pci_dev *pdev, return 0; } -static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = { - { - .name = "Galileo", - .func = 6, - .phy_addr = 1, - }, - { - .name = "GalileoGen2", - .func = 6, - .phy_addr = 1, - }, - { - .name = "SIMATIC IOT2000", - .asset_tag = "6ES7647-0AA00-0YA2", - .func = 6, - .phy_addr = 1, - }, - { - .name = "SIMATIC IOT2000", - .asset_tag = "6ES7647-0AA00-1YA2", - .func = 6, - .phy_addr = 1, - }, - { - .name = "SIMATIC IOT2000", - .asset_tag = "6ES7647-0AA00-1YA2", - .func = 7, - .phy_addr = 1, - }, - {} -}; - static const struct stmmac_pci_info quark_pci_info = { .setup = quark_default_data, - .dmi = quark_pci_dmi_data, }; /** @@ -250,7 +245,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - ret = info->setup(pdev, plat, info); + ret = info->setup(pdev, plat); if (ret) return ret; -- cgit v1.2.3 From 8d78b69091845386b6096f3adae98f28b9bf96ed Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Thu, 22 Jun 2017 08:18:01 +0200 Subject: stmmac: pci: Use dmi_system_id table for retrieving PHY addresses Avoids reimplementation of DMI matching in stmmac_pci_find_phy_addr. Signed-off-by: Jan Kiszka Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 97 ++++++++++++++++-------- 1 file changed, 64 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index a6e10d3ced5c..8d375e51a526 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -30,36 +30,39 @@ * negative value of the address means that MAC controller is not connected * with PHY. */ -struct stmmac_pci_dmi_data { - const char *name; - const char *asset_tag; +struct stmmac_pci_func_data { unsigned int func; int phy_addr; }; +struct stmmac_pci_dmi_data { + const struct stmmac_pci_func_data *func; + size_t nfuncs; +}; + struct stmmac_pci_info { int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat); }; static int stmmac_pci_find_phy_addr(struct pci_dev *pdev, - struct stmmac_pci_dmi_data *dmi_data) + const struct dmi_system_id *dmi_list) { - const char *name = dmi_get_system_info(DMI_BOARD_NAME); - const char *asset_tag = dmi_get_system_info(DMI_BOARD_ASSET_TAG); - unsigned int func = PCI_FUNC(pdev->devfn); - struct stmmac_pci_dmi_data *dmi; - - if (!name) + const struct stmmac_pci_func_data *func_data; + const struct stmmac_pci_dmi_data *dmi_data; + const struct dmi_system_id *dmi_id; + int func = PCI_FUNC(pdev->devfn); + size_t n; + + dmi_id = dmi_first_match(dmi_list); + if (!dmi_id) return -ENODEV; - for (dmi = dmi_data; dmi->name && *dmi->name; dmi++) { - if (!strcmp(dmi->name, name) && dmi->func == func) { - /* If asset tag is provided, match on it as well. */ - if (dmi->asset_tag && strcmp(dmi->asset_tag, asset_tag)) - continue; - return dmi->phy_addr; - } - } + dmi_data = dmi_id->driver_data; + func_data = dmi_data->func; + + for (n = 0; n < dmi_data->nfuncs; n++, func_data++) + if (func_data->func == func) + return func_data->phy_addr; return -ENODEV; } @@ -115,34 +118,62 @@ static const struct stmmac_pci_info stmmac_pci_info = { .setup = stmmac_default_data, }; -static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = { +static const struct stmmac_pci_func_data galileo_stmmac_func_data[] = { { - .name = "Galileo", .func = 6, .phy_addr = 1, }, +}; + +static const struct stmmac_pci_dmi_data galileo_stmmac_dmi_data = { + .func = galileo_stmmac_func_data, + .nfuncs = ARRAY_SIZE(galileo_stmmac_func_data), +}; + +static const struct stmmac_pci_func_data iot2040_stmmac_func_data[] = { { - .name = "GalileoGen2", .func = 6, .phy_addr = 1, }, { - .name = "SIMATIC IOT2000", - .asset_tag = "6ES7647-0AA00-0YA2", - .func = 6, + .func = 7, .phy_addr = 1, }, +}; + +static const struct stmmac_pci_dmi_data iot2040_stmmac_dmi_data = { + .func = iot2040_stmmac_func_data, + .nfuncs = ARRAY_SIZE(iot2040_stmmac_func_data), +}; + +static const struct dmi_system_id quark_pci_dmi[] = { { - .name = "SIMATIC IOT2000", - .asset_tag = "6ES7647-0AA00-1YA2", - .func = 6, - .phy_addr = 1, + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"), + }, + .driver_data = (void *)&galileo_stmmac_dmi_data, }, { - .name = "SIMATIC IOT2000", - .asset_tag = "6ES7647-0AA00-1YA2", - .func = 7, - .phy_addr = 1, + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"), + }, + .driver_data = (void *)&galileo_stmmac_dmi_data, + }, + { + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), + DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG, + "6ES7647-0AA00-0YA2"), + }, + .driver_data = (void *)&galileo_stmmac_dmi_data, + }, + { + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), + DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG, + "6ES7647-0AA00-1YA2"), + }, + .driver_data = (void *)&iot2040_stmmac_dmi_data, }, {} }; @@ -159,7 +190,7 @@ static int quark_default_data(struct pci_dev *pdev, * Refuse to load the driver and register net device if MAC controller * does not connect to any PHY interface. */ - ret = stmmac_pci_find_phy_addr(pdev, quark_pci_dmi_data); + ret = stmmac_pci_find_phy_addr(pdev, quark_pci_dmi); if (ret < 0) { /* Return error to the caller on DMI enabled boards. */ if (dmi_get_system_info(DMI_BOARD_NAME)) -- cgit v1.2.3 From e0af22d9fd16d1cc2910a68d204e1767be2f8f14 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 22 Jun 2017 14:23:18 +0200 Subject: net: mvpp2: add comments about smp_processor_id() usage A previous commit modified a number of smp_processor_id() used in migration-enabled contexts into get_cpu/put_cpu sections. However, a few smp_processor_id() calls remain in the driver, and this commit adds comments explaining why they can be kept. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index ca4b55c60682..4b3bf37c8038 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -4162,7 +4162,10 @@ static inline void mvpp2_interrupts_disable(struct mvpp2_port *port) MVPP2_ISR_DISABLE_INTERRUPT(cpu_mask)); } -/* Mask the current CPU's Rx/Tx interrupts */ +/* Mask the current CPU's Rx/Tx interrupts + * Called by on_each_cpu(), guaranteed to run with migration disabled, + * using smp_processor_id() is OK. + */ static void mvpp2_interrupts_mask(void *arg) { struct mvpp2_port *port = arg; @@ -4171,7 +4174,10 @@ static void mvpp2_interrupts_mask(void *arg) MVPP2_ISR_RX_TX_MASK_REG(port->id), 0); } -/* Unmask the current CPU's Rx/Tx interrupts */ +/* Unmask the current CPU's Rx/Tx interrupts. + * Called by on_each_cpu(), guaranteed to run with migration disabled, + * using smp_processor_id() is OK. + */ static void mvpp2_interrupts_unmask(void *arg) { struct mvpp2_port *port = arg; @@ -4554,7 +4560,11 @@ mvpp2_txq_next_desc_get(struct mvpp2_tx_queue *txq) return txq->descs + tx_desc; } -/* Update HW with number of aggregated Tx descriptors to be sent */ +/* Update HW with number of aggregated Tx descriptors to be sent + * + * Called only from mvpp2_tx(), so migration is disabled, using + * smp_processor_id() is OK. + */ static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending) { /* aggregated access - relevant TXQ number is written in TX desc */ @@ -4565,6 +4575,9 @@ static void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending) /* Check if there are enough free descriptors in aggregated txq. * If not, update the number of occupied descriptors and repeat the check. + * + * Called only from mvpp2_tx(), so migration is disabled, using + * smp_processor_id() is OK. */ static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv, struct mvpp2_tx_queue *aggr_txq, int num) @@ -4583,7 +4596,12 @@ static int mvpp2_aggr_desc_num_check(struct mvpp2 *priv, return 0; } -/* Reserved Tx descriptors allocation request */ +/* Reserved Tx descriptors allocation request + * + * Called only from mvpp2_txq_reserved_desc_num_proc(), itself called + * only by mvpp2_tx(), so migration is disabled, using + * smp_processor_id() is OK. + */ static int mvpp2_txq_alloc_reserved_desc(struct mvpp2 *priv, struct mvpp2_tx_queue *txq, int num) { @@ -4687,6 +4705,10 @@ static u32 mvpp2_txq_desc_csum(int l3_offs, int l3_proto, /* Get number of sent descriptors and decrement counter. * The number of sent descriptors is returned. * Per-CPU access + * + * Called only from mvpp2_txq_done(), called from mvpp2_tx() + * (migration disabled) and from the TX completion tasklet (migration + * disabled) so using smp_processor_id() is OK. */ static inline int mvpp2_txq_sent_desc_proc(struct mvpp2_port *port, struct mvpp2_tx_queue *txq) @@ -4701,6 +4723,9 @@ static inline int mvpp2_txq_sent_desc_proc(struct mvpp2_port *port, MVPP2_TRANSMITTED_COUNT_OFFSET; } +/* Called through on_each_cpu(), so runs on all CPUs, with migration + * disabled, therefore using smp_processor_id() is OK. + */ static void mvpp2_txq_sent_counter_clear(void *arg) { struct mvpp2_port *port = arg; -- cgit v1.2.3 From 8f3f6e5fd19fab5708d56601e360b92076b1eb82 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 22 Jun 2017 14:23:19 +0200 Subject: net: mvpp2: remove unused mvpp2_bm_cookie_pool_set() function This function is not used in the driver, remove it. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index 4b3bf37c8038..aad763c8b619 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -3917,17 +3917,6 @@ static void *mvpp2_buf_alloc(struct mvpp2_port *port, return data; } -/* Set pool number in a BM cookie */ -static inline u32 mvpp2_bm_cookie_pool_set(u32 cookie, int pool) -{ - u32 bm; - - bm = cookie & ~(0xFF << MVPP2_BM_COOKIE_POOL_OFFS); - bm |= ((pool & 0xFF) << MVPP2_BM_COOKIE_POOL_OFFS); - - return bm; -} - /* Release buffer to BM */ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, dma_addr_t buf_dma_addr, -- cgit v1.2.3 From 7d7627ba1cb4d1e364e7ba9c3f57947b411424e3 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 22 Jun 2017 14:23:20 +0200 Subject: net: mvpp2: remove mvpp2_pool_refill() When all a function does is calling another function with the exact same arguments, in the exact same order, you know it's time to remove said function. Which is exactly what this commit does. Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index aad763c8b619..48d21c1e09f2 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -3953,14 +3953,6 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, put_cpu(); } -/* Refill BM pool */ -static void mvpp2_pool_refill(struct mvpp2_port *port, int pool, - dma_addr_t dma_addr, - phys_addr_t phys_addr) -{ - mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); -} - /* Allocate buffers for the pool */ static int mvpp2_bm_bufs_add(struct mvpp2_port *port, struct mvpp2_bm_pool *bm_pool, int buf_num) @@ -5015,7 +5007,7 @@ static void mvpp2_rxq_drop_pkts(struct mvpp2_port *port, pool = (status & MVPP2_RXD_BM_POOL_ID_MASK) >> MVPP2_RXD_BM_POOL_ID_OFFS; - mvpp2_pool_refill(port, pool, + mvpp2_bm_pool_put(port, pool, mvpp2_rxdesc_dma_addr_get(port, rx_desc), mvpp2_rxdesc_cookie_get(port, rx_desc)); } @@ -5469,7 +5461,7 @@ static int mvpp2_rx_refill(struct mvpp2_port *port, if (!buf) return -ENOMEM; - mvpp2_pool_refill(port, pool, dma_addr, phys_addr); + mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); return 0; } @@ -5553,7 +5545,7 @@ err_drop_frame: dev->stats.rx_errors++; mvpp2_rx_error(port, rx_desc); /* Return the buffer to the pool */ - mvpp2_pool_refill(port, pool, dma_addr, phys_addr); + mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); continue; } -- cgit v1.2.3 From 664e968be329352d2ed2566e43965a25421b1646 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Wed, 5 Apr 2017 10:35:18 +0300 Subject: iwlwifi: mvm: remove txq EMPTYING_DELBA state for DQA In DQA mode, there is no need to wait for the TXQ to clear out after getting a DELBA, since traffic can continue running on the queue. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index bc52739eeb25..c76ffe1476b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2814,8 +2814,13 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, "ssn = %d, next_recl = %d\n", tid_data->ssn, tid_data->next_reclaimed); - /* There are still packets for this RA / TID in the HW */ - if (tid_data->ssn != tid_data->next_reclaimed) { + /* + * There are still packets for this RA / TID in the HW. + * Not relevant for DQA mode, since there is no need to disable + * the queue. + */ + if (!iwl_mvm_is_dqa_supported(mvm) && + tid_data->ssn != tid_data->next_reclaimed) { tid_data->state = IWL_EMPTYING_HW_QUEUE_DELBA; err = 0; break; -- cgit v1.2.3 From 0ec971fdaddfcab72e5104e35774f489991f1f68 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Apr 2017 10:32:58 +0200 Subject: iwlwifi: remove resp_pkt NULL checks Contrary to what some of the comments say, if rfkill was asserted the transport will return -ERFKILL instead of success, if CMD_WANT_SKB was set, so it's not necessary to check cmd.resp_pkt for being NULL if the return code was success. Validate that this is true in iwl_trans_send_cmd(). Most of the other code modifications were done with the following spatch: @@ struct iwl_host_cmd cmd; identifier pkt; @@ <... ( pkt = cmd.resp_pkt; ... -if (!pkt) { ... } | pkt = cmd.resp_pkt; ... -if (WARN_ON(!pkt)) { ... } | -if (!cmd.resp_pkt) { ... } ) ...> Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 12 ------------ drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 4 ---- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 3 --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 5 ----- 5 files changed, 3 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index c0871f8f2c68..dcf596217d9e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -143,6 +143,9 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) if (!(cmd->flags & CMD_ASYNC)) lock_map_release(&trans->sync_cmd_lockdep_map); + if (WARN_ON((cmd->flags & CMD_WANT_SKB) && !ret && !cmd->resp_pkt)) + return -EIO; + return ret; } IWL_EXPORT_SYMBOL(iwl_trans_send_cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 119a3bd92c50..0493a03ec3ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1795,12 +1795,6 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return ERR_PTR(ret); } - /* RF-kill already asserted again... */ - if (!cmd.resp_pkt) { - fw_status = ERR_PTR(-ERFKILL); - goto out_free_resp; - } - status_size = sizeof(*fw_status); len = iwl_rx_packet_payload_len(cmd.resp_pkt); @@ -1925,12 +1919,6 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, return ret; } - /* RF-kill already asserted again... */ - if (!cmd.resp_pkt) { - ret = -ERFKILL; - goto out_free_resp; - } - len = iwl_rx_packet_payload_len(cmd.resp_pkt); if (len < sizeof(*query)) { IWL_ERR(mvm, "Invalid scan offload profiles query response!\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 87b9ebfc653e..beead0bc08c9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -118,10 +118,6 @@ static int iwl_nvm_write_chunk(struct iwl_mvm *mvm, u16 section, return ret; pkt = cmd.resp_pkt; - if (!pkt) { - IWL_ERR(mvm, "Error in NVM_ACCESS response\n"); - return -EINVAL; - } /* Extract & check NVM write response */ nvm_resp = (void *)pkt->data; if (le16_to_cpu(nvm_resp->status) != READ_NVM_CHUNK_SUCCEED) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 1da55e4a1048..c9686e31b32e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1611,9 +1611,6 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) if (ret) goto out; - if (!get_status_cmd.resp_pkt) - goto out; - status = (void *)get_status_cmd.resp_pkt->data; wakeup_reasons = le32_to_cpu(status->wakeup_reasons); qos_seq = status->qos_seq_ctr; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 8f4f176e204e..cc5a56818db8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -168,11 +168,6 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, } pkt = cmd->resp_pkt; - /* Can happen if RFKILL is asserted */ - if (!pkt) { - ret = 0; - goto out_free_resp; - } resp_len = iwl_rx_packet_payload_len(pkt); if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { -- cgit v1.2.3 From f45f979dc208c96bb13a229381be2c1e4bf3afb3 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Thu, 23 Mar 2017 11:08:59 +0200 Subject: iwlwifi: mvm: disable dbg data collect when fw isn't alive If FW isn't alive, trying to collect debug data will result in errors both in driver and in the collected data, so just warn and leave the collecting function in this case. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index c66baf1e1443..d5cb47e2fe44 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -915,6 +915,10 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, if (trigger) delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); + if (WARN(mvm->trans->state == IWL_TRANS_NO_FW, + "Can't collect dbg data when FW isn't alive\n")) + return -EIO; + if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status)) return -EBUSY; -- cgit v1.2.3 From 85aeb58cec1a7a0395e14b45a7c6c1a9dad209fe Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Thu, 30 Mar 2017 19:43:53 +0300 Subject: iwlwifi: mvm: Enable security on new TX API Install GTKs on AP side for new TX API. Don't add IV space, it's added by the HW. While at that fix GCMP abnd GCMP-256 GTK installation which work similarly to the new TX API. Signed-off-by: David Spinadel Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 12 ++- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 108 ++++++++++++++-------- 2 files changed, 80 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 08f86e77eba5..05041d37773b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2883,7 +2883,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: - key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + if (!iwl_mvm_has_new_tx_api(mvm)) + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; break; case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_BIP_GMAC_128: @@ -2929,8 +2930,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ret = -EOPNOTSUPP; else ret = 0; - key->hw_key_idx = STA_KEY_IDX_INVALID; - break; + + if (key->cipher != WLAN_CIPHER_SUITE_GCMP && + key->cipher != WLAN_CIPHER_SUITE_GCMP_256 && + !iwl_mvm_has_new_tx_api(mvm)) { + key->hw_key_idx = STA_KEY_IDX_INVALID; + break; + } } /* During FW restart, in order to restore the state as it was, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index c76ffe1476b4..59cd2486a449 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2980,7 +2980,7 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm, } static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, - struct iwl_mvm_sta *mvm_sta, + u32 sta_id, struct ieee80211_key_conf *key, bool mcast, u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags, u8 key_offset) @@ -2998,6 +2998,9 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, bool new_api = fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TKIP_MIC_KEYS); + if (sta_id == IWL_MVM_INVALID_STA) + return -EINVAL; + keyidx = (key->keyidx << STA_KEY_FLG_KEYID_POS) & STA_KEY_FLG_KEYID_MSK; key_flags = cpu_to_le16(keyidx); @@ -3056,7 +3059,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, u.cmd.common.key_offset = key_offset; u.cmd.common.key_flags = key_flags; - u.cmd.common.sta_id = mvm_sta->sta_id; + u.cmd.common.sta_id = sta_id; if (new_api) { u.cmd.transmit_seq_cnt = cpu_to_le64(pn); @@ -3189,19 +3192,37 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, u8 key_offset, bool mcast) { - struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); int ret; const u8 *addr; struct ieee80211_key_seq seq; u16 p1k[5]; + u32 sta_id; + + if (sta) { + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); + + sta_id = mvm_sta->sta_id; + } else if (vif->type == NL80211_IFTYPE_AP && + !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + sta_id = mvmvif->mcast_sta.sta_id; + } else { + IWL_ERR(mvm, "Failed to find station id\n"); + return -EINVAL; + } switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_TKIP: + if (vif->type == NL80211_IFTYPE_AP) { + ret = -EINVAL; + break; + } addr = iwl_mvm_get_mac_addr(mvm, vif, sta); /* get phase 1 key from mac80211 */ ieee80211_get_key_rx_seq(keyconf, 0, &seq); ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); - ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, + ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, seq.tkip.iv32, p1k, 0, key_offset); break; case WLAN_CIPHER_SUITE_CCMP: @@ -3209,11 +3230,11 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: - ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, + ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, 0, NULL, 0, key_offset); break; default: - ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, + ret = iwl_mvm_send_sta_key(mvm, sta_id, keyconf, mcast, 0, NULL, 0, key_offset); } @@ -3234,6 +3255,9 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, int ret, size; u32 status; + if (sta_id == IWL_MVM_INVALID_STA) + return -EINVAL; + key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & STA_KEY_FLG_KEYID_MSK); key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); @@ -3277,42 +3301,48 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); struct iwl_mvm_sta *mvm_sta; - u8 sta_id; + u8 sta_id = IWL_MVM_INVALID_STA; int ret; static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0}; lockdep_assert_held(&mvm->mutex); - /* Get the station id from the mvm local station table */ - mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); - if (!mvm_sta) { - IWL_ERR(mvm, "Failed to find station\n"); - return -EINVAL; - } - sta_id = mvm_sta->sta_id; + if (vif->type != NL80211_IFTYPE_AP || + keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + /* Get the station id from the mvm local station table */ + mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); + if (!mvm_sta) { + IWL_ERR(mvm, "Failed to find station\n"); + return -EINVAL; + } + sta_id = mvm_sta->sta_id; - if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) { - ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false); - goto end; - } + if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) { + ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, + false); + goto end; + } - /* - * It is possible that the 'sta' parameter is NULL, and thus - * there is a need to retrieve the sta from the local station table. - */ - if (!sta) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - if (IS_ERR_OR_NULL(sta)) { - IWL_ERR(mvm, "Invalid station id\n"); - return -EINVAL; + /* + * It is possible that the 'sta' parameter is NULL, and thus + * there is a need to retrieve the sta from the local station + * table. + */ + if (!sta) { + sta = rcu_dereference_protected( + mvm->fw_id_to_mac_id[sta_id], + lockdep_is_held(&mvm->mutex)); + if (IS_ERR_OR_NULL(sta)) { + IWL_ERR(mvm, "Invalid station id\n"); + return -EINVAL; + } } - } - if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) - return -EINVAL; + if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) + return -EINVAL; + } /* If the key_offset is not pre-assigned, we need to find a * new offset to use. In normal cases, the offset is not @@ -3342,8 +3372,9 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, * to the same key slot (offset). * If this fails, remove the original as well. */ - if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || - keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { + if ((keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || + keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) && + sta) { ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, !mcast); if (ret) { @@ -3377,6 +3408,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); if (mvm_sta) sta_id = mvm_sta->sta_id; + else if (!sta && vif->type == NL80211_IFTYPE_AP && mcast) + sta_id = iwl_mvm_vif_from_mac80211(vif)->mcast_sta.sta_id; + IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", keyconf->keyidx, sta_id); @@ -3399,7 +3433,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, } mvm->fw_key_deleted[keyconf->hw_key_idx] = 0; - if (!mvm_sta) { + if (sta && !mvm_sta) { IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); return 0; } @@ -3430,7 +3464,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta); if (WARN_ON_ONCE(!mvm_sta)) goto unlock; - iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, + iwl_mvm_send_sta_key(mvm, mvm_sta->sta_id, keyconf, mcast, iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx); unlock: -- cgit v1.2.3 From 6f2f019495f637375b6d9dbbfa164b5b1e9d5583 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 30 Mar 2017 23:08:03 +0300 Subject: iwlwifi: mvm: avoid unnecessary cache trashing in Tx path When sending a Tx Command with a Tx packet, we allocate the Tx command separately from the payload of the packet. The WiFi MAC header is then copied into the buffer that was allocated for the Tx Command. This means that this buffer needs to be big enough to contain both. This is why it is allocated with iwl_trans_alloc_tx_cmd which returns a pointer to a newly allocated not zeroed struct iwl_device_cmd. The Tx command has a few bit fields and hence it needs to be zeroed, but all the rest of the buffer doesn't need to be zeroed since it will either be memcopy'ed with the MAC header, or not even sent to the device. This means that we don't need to zero all the iwl_device_cmd structure, but rather only the size of the iwl_tx_cmd structure. Since sizeof(iwl_tx_cmd) - sizeof(iwl_tx_cmd) is about 260 bytes, this can avoid touching 4 cache lines for each packet. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index aa3a3f336929..63b938028144 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -473,7 +473,10 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, if (unlikely(!dev_cmd)) return NULL; - memset(dev_cmd, 0, sizeof(*dev_cmd)); + /* Make sure we zero enough of dev_cmd */ + BUILD_BUG_ON(sizeof(struct iwl_tx_cmd_gen2) > sizeof(*tx_cmd)); + + memset(dev_cmd, 0, sizeof(dev_cmd->hdr) + sizeof(*tx_cmd)); dev_cmd->hdr.cmd = TX_CMD; if (iwl_mvm_has_new_tx_api(mvm)) { -- cgit v1.2.3 From aeb8012cdfb5dded160295c92e6bfdb6ae5e8aa1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Apr 2017 09:45:18 +0200 Subject: iwlwifi: mvm: remove pointless num_stored condition Since we exit if buf->num_stored is 0, there's no need to check it again later. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 966cd7543629..36fd8c87027c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -503,7 +503,7 @@ void iwl_mvm_reorder_timer_expired(unsigned long data) buf->sta_id, sn); iwl_mvm_release_frames(buf->mvm, sta, NULL, buf, sn); rcu_read_unlock(); - } else if (buf->num_stored) { + } else { /* * If no frame expired and there are stored frames, index is now * pointing to the first unexpired frame - modify timer -- cgit v1.2.3 From f8565f3329d62dab724b43db3f6ed60b608333fa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Apr 2017 10:29:06 +0200 Subject: iwlwifi: pcie: fix TVQM queue ID range check The queue ID should never be 512 either, so correct the check to be >= instead of just >. Fixes: 310181ec34e2 ("iwlwifi: move to TVQM mode") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 6e186501f43c..8f00019cd3b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1076,7 +1076,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, rsp = (void *)hcmd.resp_pkt->data; qid = le16_to_cpu(rsp->queue_number); - if (qid > ARRAY_SIZE(trans_pcie->txq)) { + if (qid >= ARRAY_SIZE(trans_pcie->txq)) { WARN_ONCE(1, "queue index %d unsupported", qid); ret = -EIO; goto error_free_resp; -- cgit v1.2.3 From a9c50726ce3279646e2e22314b0917455a3c5e86 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Apr 2017 11:14:28 +0200 Subject: iwlwifi: mvm: avoid variable shadowing Avoid one kind of symbol shadowing another in iwl_mvm_flush_sta() by renaming the function parameter. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 9a9163f64553..cdd13bc343e6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1370,7 +1370,7 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status); static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } #endif int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags); -int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool int_sta, u32 flags); +int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags); void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 63b938028144..da05801c9ca1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1904,11 +1904,11 @@ int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags) return ret; } -int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool int_sta, u32 flags) +int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags) { u32 mask; - if (int_sta) { + if (internal) { struct iwl_mvm_int_sta *int_sta = sta; mask = int_sta->tfd_queue_msk; -- cgit v1.2.3 From 40e86a3619a1e84ad73c716c943f65fc38eb1e28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Apr 2017 09:58:50 +0200 Subject: iwlwifi: mvm: use scnprintf() instead of snprintf() It's safer to use scnprintf() here because the buffer might be too short for the full format strings. In most cases this isn't true because of external limits on the values. In one case, this fixes a stack data leak. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 5d475b4850ae..a7ac281e5cde 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1304,11 +1304,11 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file, char buf[30] = {}; int len; - len = snprintf(buf, sizeof(buf) - 1, - "traffic=%d\ndbgfs=%d\nvcmd=%d\n", - mvmvif->low_latency_traffic, - mvmvif->low_latency_dbgfs, - mvmvif->low_latency_vcmd); + len = scnprintf(buf, sizeof(buf) - 1, + "traffic=%d\ndbgfs=%d\nvcmd=%d\n", + mvmvif->low_latency_traffic, + mvmvif->low_latency_dbgfs, + mvmvif->low_latency_vcmd); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -1385,10 +1385,12 @@ static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file, struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); char buf[8]; + int len; - snprintf(buf, sizeof(buf), "0x%04x\n", mvmvif->mvm->dbgfs_rx_phyinfo); + len = scnprintf(buf, sizeof(buf), "0x%04x\n", + mvmvif->mvm->dbgfs_rx_phyinfo); - return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } static void iwl_dbgfs_quota_check(void *data, u8 *mac, @@ -1439,7 +1441,7 @@ static ssize_t iwl_dbgfs_quota_min_read(struct file *file, char buf[10]; int len; - len = snprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min); + len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -- cgit v1.2.3 From f3779f476b85701acc3d7ec0eb9b099c2060e7c9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Mar 2017 11:22:54 +0100 Subject: iwlwifi: use bitfield.h for some registers Letting the preprocessor/compiler generate the shift/mask by itself is a win for readability, so use bitfield.h for some registers. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 10 +++++----- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 17 +++++++++-------- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 14 +++++++------- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 6 ++---- 4 files changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 2a992277c671..77be149276b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -66,6 +66,7 @@ #define __iwl_fh_h__ #include +#include /****************************/ /* Flow Handler Definitions */ @@ -478,13 +479,12 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define RFH_GEN_CFG 0xA09800 #define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0) #define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1) -#define RFH_GEN_CFG_RB_CHUNK_SIZE_POS 4 +#define RFH_GEN_CFG_RB_CHUNK_SIZE BIT(4) #define RFH_GEN_CFG_RB_CHUNK_SIZE_128 1 #define RFH_GEN_CFG_RB_CHUNK_SIZE_64 0 -#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00 -#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS 8 - -#define DEFAULT_RXQ_NUM 0 +/* the driver assumes everywhere that the default RXQ is 0 */ +#define RFH_GEN_CFG_DEFAULT_RXQ_NUM 0xF00 +#define RFH_GEN_CFG_VAL(_n, _v) FIELD_PREP(RFH_GEN_CFG_ ## _n, _v) /* end of 9000 rx series registers */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 77efbb78e867..6772c59b7764 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -66,6 +66,7 @@ #ifndef __iwl_prph_h__ #define __iwl_prph_h__ +#include /* * Registers in this file are internal, not PCI bus memory mapped. @@ -247,14 +248,14 @@ #define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19) #define SCD_QUEUE_STTS_REG_MSK (0x017F0000) -#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8) -#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) -#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) -#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) -#define SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0) -#define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) -#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) -#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) +#define SCD_QUEUE_CTX_REG1_CREDIT (0x00FFFF00) +#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT (0xFF000000) +#define SCD_QUEUE_CTX_REG1_VAL(_n, _v) FIELD_PREP(SCD_QUEUE_CTX_REG1_ ## _n, _v) + +#define SCD_QUEUE_CTX_REG2_WIN_SIZE (0x0000007F) +#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT (0x007F0000) +#define SCD_QUEUE_CTX_REG2_VAL(_n, _v) FIELD_PREP(SCD_QUEUE_CTX_REG2_ ## _n, _v) + #define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0) #define SCD_GP_CTRL_AUTO_ACTIVE_MODE BIT(18) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 1da2de205cdf..293f4b2c1955 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -845,14 +845,14 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) * Set RX DMA chunk size to 64B for IOSF and 128B for PCIe * Default queue is 0 */ - iwl_write_prph_no_grab(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP | - (DEFAULT_RXQ_NUM << - RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) | + iwl_write_prph_no_grab(trans, RFH_GEN_CFG, + RFH_GEN_CFG_RFH_DMA_SNOOP | + RFH_GEN_CFG_VAL(DEFAULT_RXQ_NUM, 0) | RFH_GEN_CFG_SERVICE_DMA_SNOOP | - (trans->cfg->integrated ? - RFH_GEN_CFG_RB_CHUNK_SIZE_64 : - RFH_GEN_CFG_RB_CHUNK_SIZE_128) << - RFH_GEN_CFG_RB_CHUNK_SIZE_POS); + RFH_GEN_CFG_VAL(RB_CHUNK_SIZE, + trans->cfg->integrated ? + RFH_GEN_CFG_RB_CHUNK_SIZE_64 : + RFH_GEN_CFG_RB_CHUNK_SIZE_128)); /* Enable the relevant rx queues */ iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, enabled); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 61b171ee32ba..94ab01164f66 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1344,10 +1344,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), - ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & - SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | - ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + SCD_QUEUE_CTX_REG2_VAL(WIN_SIZE, frame_limit) | + SCD_QUEUE_CTX_REG2_VAL(FRAME_LIMIT, frame_limit)); /* Set up status area in SRAM, map to Tx DMA/FIFO, activate */ iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), -- cgit v1.2.3 From 2f0282db41194c0099a019b2761911d6c69cbdb9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 20 Apr 2017 10:29:03 +0200 Subject: iwlwifi: mvm: track and report IBSS manager status to mac80211 Shaul reported that when iwlmvm was sending beacons, it didn't properly also take ownership of the probe responses. This is because the whole mac80211 callback (tx_last_beacon) wasn't implemented. Fix that to make IBSS discovery work better. Reported-by: Shaul Triebitz Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 9 +++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +++ 3 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index d573ac739414..50a71da2e96e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1457,6 +1457,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, beacon_notify_hdr = &beacon->beacon_notify_hdr; mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); + mvm->ibss_manager = beacon->ibss_mgr_status != 0; agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr); status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 05041d37773b..75ec567ab9e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3737,6 +3737,13 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, return ret; } +static int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + return mvm->ibss_manager; +} + static int iwl_mvm_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) @@ -4338,6 +4345,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .join_ibss = iwl_mvm_start_ap_ibss, .leave_ibss = iwl_mvm_stop_ap_ibss, + .tx_last_beacon = iwl_mvm_tx_last_beacon, + .set_tim = iwl_mvm_set_tim, .channel_switch = iwl_mvm_channel_switch, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index cdd13bc343e6..a4bee9c740e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1021,6 +1021,9 @@ struct iwl_mvm { /* system time of last beacon (for AP/GO interface) */ u32 ap_last_beacon_gp2; + /* indicates that we transmitted the last beacon */ + bool ibss_manager; + bool lar_regdom_set; enum iwl_mcc_source mcc_src; -- cgit v1.2.3 From f28b9361247360b64e0c6cf0bdd72ff5b5815a33 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 12 Apr 2017 12:42:12 +0300 Subject: iwlwifi: mvm: make D0I3_END_CMD sync during system resume There is no need to send D0I3_END_CMD as ASYNC during the system resume flow. Additionally, the other flags used are meaningless in this case (they were just copied from the runtime resume flow), so remove them all. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 0493a03ec3ed..f5b65c1ef42f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2076,9 +2076,6 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE | - CMD_WAKE_UP_TRANS; - mutex_lock(&mvm->mutex); /* get the BSS vif pointer again */ @@ -2144,7 +2141,7 @@ out_iterate: out: if (unified_image && !ret) { - ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); + ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL); if (!ret) /* D3 ended successfully - no need to reset device */ return 0; } -- cgit v1.2.3 From fcea37b2cf23f615252c424c217975f08da3c50d Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 12 Apr 2017 16:33:41 +0300 Subject: iwlwifi: mvm: support D0I3_END_CMD at the start of resume New FW versions require the D0I3_END_CMD to be sent as the first command to the FW in the resume flow. If the TLV is set, send that command first, otherwise keep the original behavior (i.e. send last). Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 52616f3c0184..a216657b3c60 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -353,6 +353,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38, IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39, IWL_UCODE_TLV_CAPA_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)40, + IWL_UCODE_TLV_CAPA_D0I3_END_FIRST = (__force iwl_ucode_tlv_capa_t)41, IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index f5b65c1ef42f..0028325fa22d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -2075,6 +2075,8 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) bool keep = false; bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); + bool d0i3_first = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_D0I3_END_FIRST); mutex_lock(&mvm->mutex); @@ -2095,6 +2097,15 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) /* query SRAM first in case we want event logging */ iwl_mvm_read_d3_sram(mvm); + if (d0i3_first) { + ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL); + if (ret < 0) { + IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n", + ret); + goto err; + } + } + /* * Query the current location and source from the D3 firmware so we * can play it back when we re-intiailize the D0 firmware @@ -2140,9 +2151,14 @@ out_iterate: iwl_mvm_d3_disconnect_iter, keep ? vif : NULL); out: + /* no need to reset the device in unified images, if successful */ if (unified_image && !ret) { + /* nothing else to do if we already sent D0I3_END_CMD */ + if (d0i3_first) + return 0; + ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL); - if (!ret) /* D3 ended successfully - no need to reset device */ + if (!ret) return 0; } -- cgit v1.2.3 From e9eb0fa247cc61858e2b61e7242f870b1bfb67c2 Mon Sep 17 00:00:00 2001 From: Mordechai Goodstein Date: Thu, 30 Mar 2017 14:43:15 +0300 Subject: iwlwifi: mvm: change the firmware name loading The firmware moved the development from a0 MAC to z0. z0 is using the same RFID and device ID as a0 so we only need to switch the name. Signed-off-by: Mordechai Goodstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index 63a4183c0de7..4634c46d1eb4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -74,7 +74,7 @@ #define IWL_A000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-" #define IWL_A000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" -#define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-a0-hrcdb-a0-" +#define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-" #define IWL_A000_HR_MODULE_FIRMWARE(api) \ IWL_A000_HR_FW_PRE "-" __stringify(api) ".ucode" -- cgit v1.2.3 From 28269897c6cd668ff093da8a123099659376504b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Apr 2017 10:17:57 +0200 Subject: iwlwifi: mvm: make iwl_mvm_update_mcc() easier to follow Some static checkers (e.g. smatch) complain about the logic, saying that resp_cp might be leaked. Clearly that isn't true, but making the logic easier to follow does not result in any significant code changes and makes the code more readable by moving the NULL check closer to its source. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 29 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index beead0bc08c9..ad8bd90deed2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -779,6 +779,10 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels * sizeof(__le32); resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); + if (!resp_cp) { + resp_cp = ERR_PTR(-ENOMEM); + goto exit; + } } else { struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = (void *)pkt->data; @@ -786,21 +790,18 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels * sizeof(__le32); resp_cp = kzalloc(resp_len, GFP_KERNEL); - - if (resp_cp) { - resp_cp->status = mcc_resp_v1->status; - resp_cp->mcc = mcc_resp_v1->mcc; - resp_cp->cap = mcc_resp_v1->cap; - resp_cp->source_id = mcc_resp_v1->source_id; - resp_cp->n_channels = mcc_resp_v1->n_channels; - memcpy(resp_cp->channels, mcc_resp_v1->channels, - n_channels * sizeof(__le32)); + if (!resp_cp) { + resp_cp = ERR_PTR(-ENOMEM); + goto exit; } - } - if (!resp_cp) { - ret = -ENOMEM; - goto exit; + resp_cp->status = mcc_resp_v1->status; + resp_cp->mcc = mcc_resp_v1->mcc; + resp_cp->cap = mcc_resp_v1->cap; + resp_cp->source_id = mcc_resp_v1->source_id; + resp_cp->n_channels = mcc_resp_v1->n_channels; + memcpy(resp_cp->channels, mcc_resp_v1->channels, + n_channels * sizeof(__le32)); } status = le32_to_cpu(resp_cp->status); @@ -820,8 +821,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, exit: iwl_free_resp(&cmd); - if (ret) - return ERR_PTR(ret); return resp_cp; } -- cgit v1.2.3 From 8f6438f72a5f6f8c49a7d9b4a1e87f56d6faaf2b Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 24 Apr 2017 09:24:37 +0300 Subject: iwlwifi: mvm: rs: add logs for the wrong antenna case In case that rate's antenna is wrong at the init stage, it's very hard to say what went wrong. Add debug data to the already existing WARN_ON_ONCE. Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index f3236ea7edb5..127017efdd87 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -131,6 +131,7 @@ enum iwl_led_mode { /* Antenna presence definitions */ #define ANT_NONE 0x0 +#define ANT_INVALID 0xff #define ANT_A BIT(0) #define ANT_B BIT(1) #define ANT_C BIT(2) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index aa785cf3cf68..a02dda8d9ea3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -2836,7 +2836,11 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rs_get_initial_rate(mvm, sta, lq_sta, band, rate); rs_init_optimal_rate(mvm, sta, lq_sta); - WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); + WARN_ONCE(rate->ant != ANT_A && rate->ant != ANT_B, + "ant: 0x%x, chains 0x%x, fw tx ant: 0x%x, nvm tx ant: 0x%x\n", + rate->ant, lq_sta->pers.chains, mvm->fw->valid_tx_ant, + mvm->nvm_data ? mvm->nvm_data->valid_tx_ant : ANT_INVALID); + tbl->column = rs_get_column_from_rate(rate); rs_set_expected_tpt_table(lq_sta, tbl); -- cgit v1.2.3 From 3a6e168baa7097bcd747c1689cff509297c6d612 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Apr 2017 09:55:36 +0200 Subject: iwlwifi: pcie: pull out common rfkill IRQ handling code There's no point in duplicating exactly the same code here for legacy and MSI-X interrupts, so pull it out into a new function to call in both places. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 82 +++++++++++----------------- 1 file changed, 33 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 293f4b2c1955..c27d6f711abf 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1509,6 +1509,36 @@ static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans) return inta; } +static void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct isr_statistics *isr_stats = &trans_pcie->isr_stats; + bool hw_rfkill; + + mutex_lock(&trans_pcie->mutex); + hw_rfkill = iwl_is_rfkill_set(trans); + if (hw_rfkill) + set_bit(STATUS_RFKILL, &trans->status); + + IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", + hw_rfkill ? "disable radio" : "enable radio"); + + isr_stats->rfkill++; + + iwl_trans_pcie_rf_kill(trans, hw_rfkill); + mutex_unlock(&trans_pcie->mutex); + + if (hw_rfkill) { + if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, + &trans->status)) + IWL_DEBUG_RF_KILL(trans, + "Rfkill while SYNC HCMD in flight\n"); + wake_up(&trans_pcie->wait_command_queue); + } else { + clear_bit(STATUS_RFKILL, &trans->status); + } +} + irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) { struct iwl_trans *trans = dev_id; @@ -1632,30 +1662,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) /* HW RF KILL switch toggled */ if (inta & CSR_INT_BIT_RF_KILL) { - bool hw_rfkill; - - mutex_lock(&trans_pcie->mutex); - hw_rfkill = iwl_is_rfkill_set(trans); - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - - IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", - hw_rfkill ? "disable radio" : "enable radio"); - - isr_stats->rfkill++; - - iwl_trans_pcie_rf_kill(trans, hw_rfkill); - mutex_unlock(&trans_pcie->mutex); - if (hw_rfkill) { - if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, - &trans->status)) - IWL_DEBUG_RF_KILL(trans, - "Rfkill while SYNC HCMD in flight\n"); - wake_up(&trans_pcie->wait_command_queue); - } else { - clear_bit(STATUS_RFKILL, &trans->status); - } - + iwl_pcie_handle_rfkill_irq(trans); handled |= CSR_INT_BIT_RF_KILL; } @@ -1982,31 +1989,8 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) } /* HW RF KILL switch toggled */ - if (inta_hw & MSIX_HW_INT_CAUSES_REG_RF_KILL) { - bool hw_rfkill; - - mutex_lock(&trans_pcie->mutex); - hw_rfkill = iwl_is_rfkill_set(trans); - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - - IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", - hw_rfkill ? "disable radio" : "enable radio"); - - isr_stats->rfkill++; - - iwl_trans_pcie_rf_kill(trans, hw_rfkill); - mutex_unlock(&trans_pcie->mutex); - if (hw_rfkill) { - if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, - &trans->status)) - IWL_DEBUG_RF_KILL(trans, - "Rfkill while SYNC HCMD in flight\n"); - wake_up(&trans_pcie->wait_command_queue); - } else { - clear_bit(STATUS_RFKILL, &trans->status); - } - } + if (inta_hw & MSIX_HW_INT_CAUSES_REG_RF_KILL) + iwl_pcie_handle_rfkill_irq(trans); if (inta_hw & MSIX_HW_INT_CAUSES_REG_HW_ERR) { IWL_ERR(trans, -- cgit v1.2.3 From fa4de7f7c349d0fca751d1ad331c1fa8f528a47d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Apr 2017 09:58:25 +0200 Subject: iwlwifi: pcie: add fake RF-kill to debugfs In order to debug "hardware" RF-kill flows, add a low-level hook to allow changing the "hardware" RF-kill from debugfs. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 10 +++++- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 40 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 4b7be7ba9780..17bd95614483 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -404,6 +404,7 @@ struct iwl_trans_pcie { int ict_index; bool use_ict; bool is_down; + bool debug_rfkill; struct isr_statistics isr_stats; spinlock_t irq_lock; @@ -675,6 +676,8 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) } } +void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans); + static inline void iwl_wake_queue(struct iwl_trans *trans, struct iwl_txq *txq) { @@ -713,7 +716,12 @@ static inline u8 get_cmd_index(struct iwl_txq *q, u32 index) static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) { - lockdep_assert_held(&IWL_TRANS_GET_PCIE_TRANS(trans)->mutex); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + lockdep_assert_held(&trans_pcie->mutex); + + if (trans_pcie->debug_rfkill) + return true; return !(iwl_read32(trans, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index c27d6f711abf..b6b04e72521e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1509,7 +1509,7 @@ static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans) return inta; } -static void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans) +void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct isr_statistics *isr_stats = &trans_pcie->isr_stats; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index a3c5d3b195ad..6c4f8e377fb9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2461,11 +2461,50 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, return ret; } +static ssize_t iwl_dbgfs_rfkill_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + char buf[100]; + int pos; + + pos = scnprintf(buf, sizeof(buf), "debug: %d\nhw: %d\n", + trans_pcie->debug_rfkill, + !(iwl_read32(trans, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_rfkill_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + bool old = trans_pcie->debug_rfkill; + int ret; + + ret = kstrtobool_from_user(user_buf, count, &trans_pcie->debug_rfkill); + if (ret) + return ret; + if (old == trans_pcie->debug_rfkill) + return count; + IWL_WARN(trans, "changing debug rfkill %d->%d\n", + old, trans_pcie->debug_rfkill); + iwl_pcie_handle_rfkill_irq(trans); + + return count; +} + DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_READ_FILE_OPS(tx_queue); DEBUGFS_WRITE_FILE_OPS(csr); +DEBUGFS_READ_WRITE_FILE_OPS(rfkill); /* Create the debugfs files and directories */ int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) @@ -2477,6 +2516,7 @@ int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(csr, dir, S_IWUSR); DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); + DEBUGFS_ADD_FILE(rfkill, dir, S_IWUSR | S_IRUSR); return 0; err: -- cgit v1.2.3 From 6ad0435991482107664f65b7ae3fd588f10149d4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Apr 2017 10:21:18 +0200 Subject: iwlwifi: mvm: don't warn in queue sync on RF-kill If we happen to be in or get into the queue sync when RF-kill is asserted, we return from there and warn since there are still queue sync notifications outstanding. These can't ever come though, because we're in RF-kill, so don't WARN then. While at it, also move the warning to the appropriate place, if the request is not synchronous then we shouldn't warn, but currently always will. To make it fast, also trigger the waitq when on rfkill assert. Fixes: 0636b938214c ("iwlwifi: mvm: implement driver RX queues sync command") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 8 +++++--- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 75ec567ab9e2..2449be6f95a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4277,11 +4277,13 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, goto out; } - if (notif->sync) + if (notif->sync) { ret = wait_event_timeout(mvm->rx_sync_waitq, - atomic_read(&mvm->queue_sync_counter) == 0, + atomic_read(&mvm->queue_sync_counter) == 0 || + iwl_mvm_is_radio_killed(mvm), HZ); - WARN_ON_ONCE(!ret); + WARN_ON_ONCE(!ret && !iwl_mvm_is_radio_killed(mvm)); + } out: atomic_set(&mvm->queue_sync_counter, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index c9686e31b32e..30fc756b5b01 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1094,6 +1094,16 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) iwl_mvm_start_mac_queues(mvm, mq); } +static void iwl_mvm_set_rfkill_state(struct iwl_mvm *mvm) +{ + bool state = iwl_mvm_is_radio_killed(mvm); + + if (state) + wake_up(&mvm->rx_sync_waitq); + + wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state); +} + void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) { if (state) @@ -1101,7 +1111,7 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) else clear_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); - wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); + iwl_mvm_set_rfkill_state(mvm); } static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) @@ -1114,7 +1124,7 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) else clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); - wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); + iwl_mvm_set_rfkill_state(mvm); /* iwl_run_init_mvm_ucode is waiting for results, abort it */ if (calibrating) -- cgit v1.2.3 From 326477e4858cd6b1e0e067ecf2d6a8252ef41994 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Apr 2017 13:41:20 +0200 Subject: iwlwifi: pcie: don't report RF-kill enabled while shutting down When toggling the RF-kill pin quickly in succession, the driver can get rather confused because it might be in the process of shutting down, expecting all commands to go through quickly due to rfkill, but the transport already thinks the device is accessible again, even though it previously shut it down. This leads to bugs, and I even observed a kernel panic. Avoid this by making the PCIe code only report that the radio is enabled again after the higher layers actually decided to shut it off. This also pulls out this common RF-kill checking code into a common function called by both transport generations and also moves it to the direct method - in the internal helper we don't really care about the RF-kill status anymore since we won't report it up until the stop anyway. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 6 +- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 12 ++-- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 4 +- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 20 ++++-- .../net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 28 ++------ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 82 ++++++++++++++-------- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 4 +- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 4 +- 9 files changed, 88 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index dcf596217d9e..784bdd0ed233 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -117,7 +117,7 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) int ret; if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status))) + test_bit(STATUS_RFKILL_OPMODE, &trans->status))) return -ERFKILL; if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index a150da3c824b..2e975c0be045 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -322,7 +322,8 @@ enum iwl_d3_status { * @STATUS_DEVICE_ENABLED: APM is enabled * @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up) * @STATUS_INT_ENABLED: interrupts are enabled - * @STATUS_RFKILL: the HW RFkill switch is in KILL position + * @STATUS_RFKILL_HW: the actual HW state of the RF-kill switch + * @STATUS_RFKILL_OPMODE: RF-kill state reported to opmode * @STATUS_FW_ERROR: the fw is in error state * @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands * are sent @@ -334,7 +335,8 @@ enum iwl_trans_status { STATUS_DEVICE_ENABLED, STATUS_TPOWER_PMI, STATUS_INT_ENABLED, - STATUS_RFKILL, + STATUS_RFKILL_HW, + STATUS_RFKILL_OPMODE, STATUS_FW_ERROR, STATUS_TRANS_GOING_IDLE, STATUS_TRANS_IDLE, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 2d92d3708619..a8fb77483313 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -766,7 +766,6 @@ static int iwl_pci_resume(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct iwl_trans *trans = pci_get_drvdata(pdev); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - bool hw_rfkill; /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if @@ -783,16 +782,13 @@ static int iwl_pci_resume(struct device *device) return 0; /* - * Enable rfkill interrupt (in order to keep track of - * the rfkill status). Must be locked to avoid processing - * a possible rfkill interrupt between reading the state - * and calling iwl_trans_pcie_rf_kill() with it. + * Enable rfkill interrupt (in order to keep track of the rfkill + * status). Must be locked to avoid processing a possible rfkill + * interrupt while in iwl_trans_check_hw_rf_kill(). */ mutex_lock(&trans_pcie->mutex); iwl_enable_rfkill_int(trans); - - hw_rfkill = iwl_is_rfkill_set(trans); - iwl_trans_pcie_rf_kill(trans, hw_rfkill); + iwl_trans_check_hw_rf_kill(trans); mutex_unlock(&trans_pcie->mutex); return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 17bd95614483..644c0e583f32 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -403,7 +403,7 @@ struct iwl_trans_pcie { dma_addr_t ict_tbl_dma; int ict_index; bool use_ict; - bool is_down; + bool is_down, opmode_down; bool debug_rfkill; struct isr_statistics isr_stats; @@ -775,6 +775,8 @@ void iwl_pcie_apm_config(struct iwl_trans *trans); int iwl_pcie_prepare_card_hw(struct iwl_trans *trans); void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); +void iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans, + bool was_in_rfkill); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); int iwl_queue_space(const struct iwl_txq *q); int iwl_pcie_apm_stop_master(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index b6b04e72521e..6eef2e789426 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1513,19 +1513,27 @@ void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct isr_statistics *isr_stats = &trans_pcie->isr_stats; - bool hw_rfkill; + bool hw_rfkill, prev, report; mutex_lock(&trans_pcie->mutex); + prev = test_bit(STATUS_RFKILL_OPMODE, &trans->status); hw_rfkill = iwl_is_rfkill_set(trans); - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); + if (hw_rfkill) { + set_bit(STATUS_RFKILL_OPMODE, &trans->status); + set_bit(STATUS_RFKILL_HW, &trans->status); + } + if (trans_pcie->opmode_down) + report = hw_rfkill; + else + report = test_bit(STATUS_RFKILL_OPMODE, &trans->status); IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", hw_rfkill ? "disable radio" : "enable radio"); isr_stats->rfkill++; - iwl_trans_pcie_rf_kill(trans, hw_rfkill); + if (prev != report) + iwl_trans_pcie_rf_kill(trans, report); mutex_unlock(&trans_pcie->mutex); if (hw_rfkill) { @@ -1535,7 +1543,9 @@ void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans) "Rfkill while SYNC HCMD in flight\n"); wake_up(&trans_pcie->wait_command_queue); } else { - clear_bit(STATUS_RFKILL, &trans->status); + clear_bit(STATUS_RFKILL_HW, &trans->status); + if (trans_pcie->opmode_down) + clear_bit(STATUS_RFKILL_OPMODE, &trans->status); } } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index ac60a282d6de..e84c5ff389a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -150,7 +150,6 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - bool hw_rfkill, was_hw_rfkill; lockdep_assert_held(&trans_pcie->mutex); @@ -159,8 +158,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; - was_hw_rfkill = iwl_is_rfkill_set(trans); - /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); @@ -217,7 +214,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); clear_bit(STATUS_INT_ENABLED, &trans->status); clear_bit(STATUS_TPOWER_PMI, &trans->status); - clear_bit(STATUS_RFKILL, &trans->status); /* * Even if we stop the HW, we still want the RF kill @@ -225,26 +221,6 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) */ iwl_enable_rfkill_int(trans); - /* - * Check again since the RF kill state may have changed while - * all the interrupts were disabled, in this case we couldn't - * receive the RF kill interrupt and update the state in the - * op_mode. - * Don't call the op_mode if the rkfill state hasn't changed. - * This allows the op_mode to call stop_device from the rfkill - * notification without endless recursion. Under very rare - * circumstances, we might have a small recursion if the rfkill - * state changed exactly now while we were called from stop_device. - * This is very unlikely but can happen and is supported. - */ - hw_rfkill = iwl_is_rfkill_set(trans); - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - else - clear_bit(STATUS_RFKILL, &trans->status); - if (hw_rfkill != was_hw_rfkill) - iwl_trans_pcie_rf_kill(trans, hw_rfkill); - /* re-take ownership to prevent other users from stealing the device */ iwl_pcie_prepare_card_hw(trans); } @@ -252,9 +228,13 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + bool was_in_rfkill; mutex_lock(&trans_pcie->mutex); + trans_pcie->opmode_down = true; + was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status); _iwl_trans_pcie_gen2_stop_device(trans, low_power); + iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill); mutex_unlock(&trans_pcie->mutex); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 6c4f8e377fb9..959a3d5ece67 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -996,14 +996,24 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill = iwl_is_rfkill_set(trans); + bool prev = test_bit(STATUS_RFKILL_OPMODE, &trans->status); + bool report; - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - else - clear_bit(STATUS_RFKILL, &trans->status); + if (hw_rfkill) { + set_bit(STATUS_RFKILL_HW, &trans->status); + set_bit(STATUS_RFKILL_OPMODE, &trans->status); + } else { + clear_bit(STATUS_RFKILL_HW, &trans->status); + if (trans_pcie->opmode_down) + clear_bit(STATUS_RFKILL_OPMODE, &trans->status); + } + + report = test_bit(STATUS_RFKILL_OPMODE, &trans->status); - iwl_trans_pcie_rf_kill(trans, hw_rfkill); + if (prev != report) + iwl_trans_pcie_rf_kill(trans, report); return hw_rfkill; } @@ -1128,7 +1138,6 @@ static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie) static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - bool hw_rfkill, was_hw_rfkill; lockdep_assert_held(&trans_pcie->mutex); @@ -1137,8 +1146,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = true; - was_hw_rfkill = iwl_is_rfkill_set(trans); - /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); @@ -1199,7 +1206,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); clear_bit(STATUS_INT_ENABLED, &trans->status); clear_bit(STATUS_TPOWER_PMI, &trans->status); - clear_bit(STATUS_RFKILL, &trans->status); /* * Even if we stop the HW, we still want the RF kill @@ -1207,26 +1213,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) */ iwl_enable_rfkill_int(trans); - /* - * Check again since the RF kill state may have changed while - * all the interrupts were disabled, in this case we couldn't - * receive the RF kill interrupt and update the state in the - * op_mode. - * Don't call the op_mode if the rkfill state hasn't changed. - * This allows the op_mode to call stop_device from the rfkill - * notification without endless recursion. Under very rare - * circumstances, we might have a small recursion if the rfkill - * state changed exactly now while we were called from stop_device. - * This is very unlikely but can happen and is supported. - */ - hw_rfkill = iwl_is_rfkill_set(trans); - if (hw_rfkill) - set_bit(STATUS_RFKILL, &trans->status); - else - clear_bit(STATUS_RFKILL, &trans->status); - if (hw_rfkill != was_hw_rfkill) - iwl_trans_pcie_rf_kill(trans, hw_rfkill); - /* re-take ownership to prevent other users from stealing the device */ iwl_pcie_prepare_card_hw(trans); } @@ -1339,12 +1325,45 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) iwl_pcie_tx_start(trans, scd_addr); } +void iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans, + bool was_in_rfkill) +{ + bool hw_rfkill; + + /* + * Check again since the RF kill state may have changed while + * all the interrupts were disabled, in this case we couldn't + * receive the RF kill interrupt and update the state in the + * op_mode. + * Don't call the op_mode if the rkfill state hasn't changed. + * This allows the op_mode to call stop_device from the rfkill + * notification without endless recursion. Under very rare + * circumstances, we might have a small recursion if the rfkill + * state changed exactly now while we were called from stop_device. + * This is very unlikely but can happen and is supported. + */ + hw_rfkill = iwl_is_rfkill_set(trans); + if (hw_rfkill) { + set_bit(STATUS_RFKILL_HW, &trans->status); + set_bit(STATUS_RFKILL_OPMODE, &trans->status); + } else { + clear_bit(STATUS_RFKILL_HW, &trans->status); + clear_bit(STATUS_RFKILL_OPMODE, &trans->status); + } + if (hw_rfkill != was_in_rfkill) + iwl_trans_pcie_rf_kill(trans, hw_rfkill); +} + static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + bool was_in_rfkill; mutex_lock(&trans_pcie->mutex); + trans_pcie->opmode_down = true; + was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status); _iwl_trans_pcie_stop_device(trans, low_power); + iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill); mutex_unlock(&trans_pcie->mutex); } @@ -1355,6 +1374,8 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) lockdep_assert_held(&trans_pcie->mutex); + IWL_WARN(trans, "reporting RF_KILL (radio %s)\n", + state ? "disabled" : "enabled"); if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) { if (trans->cfg->gen2) _iwl_trans_pcie_gen2_stop_device(trans, true); @@ -1646,6 +1667,8 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) /* From now on, the op_mode will be kept updated about RF kill state */ iwl_enable_rfkill_int(trans); + trans_pcie->opmode_down = false; + /* Set is_down to false here so that...*/ trans_pcie->is_down = false; @@ -3005,6 +3028,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); trans_pcie->trans = trans; + trans_pcie->opmode_down = true; spin_lock_init(&trans_pcie->irq_lock); spin_lock_init(&trans_pcie->reg_lock); mutex_init(&trans_pcie->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 8f00019cd3b4..464a435a4440 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -863,7 +863,7 @@ static int iwl_pcie_gen2_send_hcmd_sync(struct iwl_trans *trans, } if (!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status)) { + test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); ret = -ERFKILL; goto cancel; @@ -900,7 +900,7 @@ int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { if (!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status)) { + test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", cmd->id); return -ERFKILL; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 94ab01164f66..0a6e36a8a0bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1874,7 +1874,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, } if (!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status)) { + test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); ret = -ERFKILL; goto cancel; @@ -1911,7 +1911,7 @@ cancel: int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { if (!(cmd->flags & CMD_SEND_IN_RFKILL) && - test_bit(STATUS_RFKILL, &trans->status)) { + test_bit(STATUS_RFKILL_OPMODE, &trans->status)) { IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", cmd->id); return -ERFKILL; -- cgit v1.2.3 From 302b5e9e7df00938720719d4371263e8e852e5ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Apr 2017 11:38:29 +0200 Subject: iwlwifi: pcie: remove pointless debugfs parsing for csr file We don't actually care about the value at all, just making sure that we can successfully parse a single integer value, but that's entirely pointless - remove it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 959a3d5ece67..280b14ace175 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2450,16 +2450,6 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file, size_t count, loff_t *ppos) { struct iwl_trans *trans = file->private_data; - char buf[8]; - int buf_size; - int csr; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &csr) != 1) - return -EFAULT; iwl_pcie_dump_csr(trans); -- cgit v1.2.3 From 87afe9b0f4af44443f88a29458fcebe56385d771 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Apr 2017 12:50:32 +0200 Subject: iwlwifi: mvm: document status bits Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index a4bee9c740e0..0b5e92c1483e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1081,6 +1081,18 @@ struct iwl_mvm { #define IWL_MAC80211_GET_MVM(_hw) \ IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv)) +/** + * enum iwl_mvm_status - MVM status bits + * @IWL_MVM_STATUS_HW_RFKILL: HW RF-kill is asserted + * @IWL_MVM_STATUS_HW_CTKILL: CT-kill is active + * @IWL_MVM_STATUS_ROC_RUNNING: remain-on-channel is running + * @IWL_MVM_STATUS_IN_HW_RESTART: HW restart is active + * @IWL_MVM_STATUS_IN_D0I3: NIC is in D0i3 + * @IWL_MVM_STATUS_ROC_AUX_RUNNING: AUX remain-on-channel is running + * @IWL_MVM_STATUS_D3_RECONFIG: D3 reconfiguration is being done + * @IWL_MVM_STATUS_DUMPING_FW_LOG: FW log is being dumped + * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running + */ enum iwl_mvm_status { IWL_MVM_STATUS_HW_RFKILL, IWL_MVM_STATUS_HW_CTKILL, -- cgit v1.2.3 From dd32162da4e5b3c9c81adf9a1f6e3a839a35d5f0 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Wed, 5 Apr 2017 16:25:11 +0300 Subject: iwlwifi: mvm: support aggregations on A000 HW On A000 HW, the SCD rdptr has only 8 bits allocated for it, thus when checking if a queue is full, or when checking if the SSN is equal to the TID's next_reclaimed, A000 HW should trim the SSN. Fix this by "normalizing" the SSN to wrap around 0xFF when comparing to the next_reclaimed on A000 HW. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 27 +++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 8 ++----- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 15 ++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 2 +- 6 files changed, 42 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 2449be6f95a5..d608ce8305c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2395,7 +2395,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, __set_bit(tid_data->txq_id, &txqs); - if (iwl_mvm_tid_queued(tid_data) == 0) + if (iwl_mvm_tid_queued(mvm, tid_data) == 0) continue; __set_bit(tid, &tids); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 30fc756b5b01..3a8c95162811 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1323,7 +1323,7 @@ static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm, * for offloading in order to prevent reuse of the same * qos seq counters. */ - if (iwl_mvm_tid_queued(tid_data)) + if (iwl_mvm_tid_queued(mvm, tid_data)) continue; if (tid_data->state != IWL_AGG_OFF) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 59cd2486a449..0249300c4600 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2529,6 +2529,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data; + u16 normalized_ssn; int txq_id; int ret; @@ -2616,7 +2617,15 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmsta->sta_id, tid, txq_id, tid_data->ssn, tid_data->next_reclaimed); - if (tid_data->ssn == tid_data->next_reclaimed) { + /* + * In A000 HW, the next_reclaimed index is only 8 bit, so we'll need + * to align the wrap around of ssn so we compare relevant values. + */ + normalized_ssn = tid_data->ssn; + if (mvm->trans->cfg->gen2) + normalized_ssn &= 0xff; + + if (normalized_ssn == tid_data->next_reclaimed) { tid_data->state = IWL_AGG_STARTING; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); } else { @@ -3540,7 +3549,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, return; } - n_queued = iwl_mvm_tid_queued(tid_data); + n_queued = iwl_mvm_tid_queued(mvm, tid_data); if (n_queued > remaining) { more_data = true; remaining = 0; @@ -3722,3 +3731,17 @@ void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif) rcu_read_unlock(); } + +u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data) +{ + u16 sn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); + + /* + * In A000 HW, the next_reclaimed index is only 8 bit, so we'll need + * to align the wrap around of ssn so we compare relevant values. + */ + if (mvm->trans->cfg->gen2) + sn &= 0xff; + + return ieee80211_sn_sub(sn, tid_data->next_reclaimed); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 357ff2bf75c1..05fecbe87da4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -341,12 +341,6 @@ struct iwl_mvm_tid_data { bool is_tid_active; }; -static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) -{ - return ieee80211_sn_sub(IEEE80211_SEQ_TO_SN(tid_data->seq_number), - tid_data->next_reclaimed); -} - struct iwl_mvm_key_pn { struct rcu_head rcu_head; struct { @@ -447,6 +441,8 @@ struct iwl_mvm_sta { u8 avg_energy; }; +u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data); + static inline struct iwl_mvm_sta * iwl_mvm_sta_from_mac80211(struct ieee80211_sta *sta) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index da05801c9ca1..288505114153 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1129,13 +1129,14 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; struct ieee80211_vif *vif = mvmsta->vif; + u16 normalized_ssn; lockdep_assert_held(&mvmsta->lock); if ((tid_data->state == IWL_AGG_ON || tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA || iwl_mvm_is_dqa_supported(mvm)) && - iwl_mvm_tid_queued(tid_data) == 0) { + iwl_mvm_tid_queued(mvm, tid_data) == 0) { /* * Now that this aggregation or DQA queue is empty tell * mac80211 so it knows we no longer have frames buffered for @@ -1144,7 +1145,15 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, ieee80211_sta_set_buffered(sta, tid, false); } - if (tid_data->ssn != tid_data->next_reclaimed) + /* + * In A000 HW, the next_reclaimed index is only 8 bit, so we'll need + * to align the wrap around of ssn so we compare relevant values. + */ + normalized_ssn = tid_data->ssn; + if (mvm->trans->cfg->gen2) + normalized_ssn &= 0xff; + + if (normalized_ssn != tid_data->next_reclaimed) return; switch (tid_data->state) { @@ -1488,7 +1497,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, if (mvmsta->sleep_tx_count) { mvmsta->sleep_tx_count--; if (mvmsta->sleep_tx_count && - !iwl_mvm_tid_queued(tid_data)) { + !iwl_mvm_tid_queued(mvm, tid_data)) { /* * The number of frames in the queue * dropped to 0 even if we sent less diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index cc5a56818db8..dc8104d846f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1181,7 +1181,7 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, /* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { /* If some TFDs are still queued - don't mark TID as inactive */ - if (iwl_mvm_tid_queued(&mvmsta->tid_data[tid])) + if (iwl_mvm_tid_queued(mvm, &mvmsta->tid_data[tid])) tid_bitmap &= ~BIT(tid); } -- cgit v1.2.3 From 078f11311f40007a836467e7ab0b311978fe4adb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Apr 2017 11:37:40 +0200 Subject: iwlwifi: pcie: use kstrtou32_from_user() Use kstrtou32_from_user() in debugfs instead of open-coding it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 280b14ace175..67343b10b0da 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2428,17 +2428,12 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, struct iwl_trans *trans = file->private_data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct isr_statistics *isr_stats = &trans_pcie->isr_stats; - - char buf[8]; - int buf_size; u32 reset_flag; + int ret; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%x", &reset_flag) != 1) - return -EFAULT; + ret = kstrtou32_from_user(user_buf, count, 16, &reset_flag); + if (ret) + return ret; if (reset_flag == 0) memset(isr_stats, 0, sizeof(*isr_stats)); -- cgit v1.2.3 From 550aba9b8dce109725a87cdcc8268f56dfd32af0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Apr 2017 13:34:29 +0200 Subject: iwlwifi: mvm: better link scan notification results length Show the name of the member (scanned_channels) that provides the length with some better markup. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h index d27c67b67015..f8e92026bdc6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h @@ -769,7 +769,7 @@ struct iwl_scan_offload_profiles_query { * @last_channel: last channel that was scanned * @start_tsf: TSF timer in usecs of the scan start time for the mac specified * in &struct iwl_scan_req_umac. - * @results: array of scan results, only "scanned_channels" of them are valid + * @results: array of scan results, length in @scanned_channels */ struct iwl_umac_scan_iter_complete_notif { __le32 uid; -- cgit v1.2.3 From 99f2064e15afcf81b5af22bc7c996cd5c182baf5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:46 +0300 Subject: NFC: pn544: Switch to devm_acpi_dev_add_driver_gpios() Switch to use managed variant of acpi_dev_add_driver_gpios() to simplify error path and fix potentially wrong assignment if ->probe() fails. Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544/i2c.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index fedde9d46ab6..4b14740edb67 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -904,7 +904,7 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, phy->i2c_dev = client; i2c_set_clientdata(client, phy); - r = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_pn544_gpios); + r = devm_acpi_dev_add_driver_gpios(dev, acpi_pn544_gpios); if (r) dev_dbg(dev, "Unable to add GPIO mapping table\n"); @@ -958,7 +958,6 @@ static int pn544_hci_i2c_remove(struct i2c_client *client) if (phy->powered) pn544_hci_i2c_disable(phy); - acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev)); return 0; } -- cgit v1.2.3 From 394671e79ee6e9e23ddd673ba5bbae5887f97182 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:47 +0300 Subject: NFC: st21nfca: Add GPIO ACPI mapping table In order to make GPIO ACPI library stricter prepare users of gpiod_get_index() to correctly behave when there no mapping is provided by firmware. Here we add explicit mapping between _CRS GpioIo() resources and their names used in the driver. Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 4bff76baa341..3621290807f6 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -501,14 +501,25 @@ static struct nfc_phy_ops i2c_phy_ops = { .disable = st21nfca_hci_i2c_disable, }; +static const struct acpi_gpio_params enable_gpios = { 1, 0, false }; + +static const struct acpi_gpio_mapping acpi_st21nfca_gpios[] = { + { "enable-gpios", &enable_gpios, 1 }, + {}, +}; + static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client) { struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client); struct device *dev = &client->dev; + int ret; + + ret = devm_acpi_dev_add_driver_gpios(dev, acpi_st21nfca_gpios); + if (ret) + return ret; /* Get EN GPIO from ACPI */ - phy->gpiod_ena = devm_gpiod_get_index(dev, ST21NFCA_GPIO_NAME_EN, 1, - GPIOD_OUT_LOW); + phy->gpiod_ena = devm_gpiod_get(dev, ST21NFCA_GPIO_NAME_EN, GPIOD_OUT_LOW); if (IS_ERR(phy->gpiod_ena)) { nfc_err(dev, "Unable to get ENABLE GPIO\n"); return PTR_ERR(phy->gpiod_ena); @@ -523,8 +534,7 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client) struct device *dev = &client->dev; /* Get GPIO from device tree */ - phy->gpiod_ena = devm_gpiod_get_index(dev, ST21NFCA_GPIO_NAME_EN, 0, - GPIOD_OUT_HIGH); + phy->gpiod_ena = devm_gpiod_get(dev, ST21NFCA_GPIO_NAME_EN, GPIOD_OUT_HIGH); if (IS_ERR(phy->gpiod_ena)) { nfc_err(dev, "Failed to request enable pin\n"); return PTR_ERR(phy->gpiod_ena); -- cgit v1.2.3 From d31748be2ba37b29bc051f1b5ce2f30294db2cc1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:48 +0300 Subject: NFC: st21nfca: Get rid of code duplication in ->probe() Since OF and ACPI case almost the same get rid of code duplication by moving gpiod_get() calls directly to ->probe(). Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 62 ++++++++-------------------------------------- 1 file changed, 10 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 3621290807f6..cd1f7bfa75eb 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -61,8 +61,6 @@ #define ST21NFCA_HCI_DRIVER_NAME "st21nfca_hci" #define ST21NFCA_HCI_I2C_DRIVER_NAME "st21nfca_hci_i2c" -#define ST21NFCA_GPIO_NAME_EN "enable" - struct st21nfca_i2c_phy { struct i2c_client *i2c_dev; struct nfc_hci_dev *hdev; @@ -508,44 +506,10 @@ static const struct acpi_gpio_mapping acpi_st21nfca_gpios[] = { {}, }; -static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client) -{ - struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client); - struct device *dev = &client->dev; - int ret; - - ret = devm_acpi_dev_add_driver_gpios(dev, acpi_st21nfca_gpios); - if (ret) - return ret; - - /* Get EN GPIO from ACPI */ - phy->gpiod_ena = devm_gpiod_get(dev, ST21NFCA_GPIO_NAME_EN, GPIOD_OUT_LOW); - if (IS_ERR(phy->gpiod_ena)) { - nfc_err(dev, "Unable to get ENABLE GPIO\n"); - return PTR_ERR(phy->gpiod_ena); - } - - return 0; -} - -static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client) -{ - struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client); - struct device *dev = &client->dev; - - /* Get GPIO from device tree */ - phy->gpiod_ena = devm_gpiod_get(dev, ST21NFCA_GPIO_NAME_EN, GPIOD_OUT_HIGH); - if (IS_ERR(phy->gpiod_ena)) { - nfc_err(dev, "Failed to request enable pin\n"); - return PTR_ERR(phy->gpiod_ena); - } - - return 0; -} - static int st21nfca_hci_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct st21nfca_i2c_phy *phy; int r; @@ -572,21 +536,15 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client, mutex_init(&phy->phy_lock); i2c_set_clientdata(client, phy); - if (client->dev.of_node) { - r = st21nfca_hci_i2c_of_request_resources(client); - if (r) { - nfc_err(&client->dev, "No platform data\n"); - return r; - } - } else if (ACPI_HANDLE(&client->dev)) { - r = st21nfca_hci_i2c_acpi_request_resources(client); - if (r) { - nfc_err(&client->dev, "Cannot get ACPI data\n"); - return r; - } - } else { - nfc_err(&client->dev, "st21nfca platform resources not available\n"); - return -ENODEV; + r = devm_acpi_dev_add_driver_gpios(dev, acpi_st21nfca_gpios); + if (r) + dev_dbg(dev, "Unable to add GPIO mapping table\n"); + + /* Get EN GPIO from resource provider */ + phy->gpiod_ena = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(phy->gpiod_ena)) { + nfc_err(dev, "Unable to get ENABLE GPIO\n"); + return PTR_ERR(phy->gpiod_ena); } phy->se_status.is_ese_present = -- cgit v1.2.3 From 8597c0920d6f4af66d2100b93599b0c0850dffdd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:49 +0300 Subject: NFC: fdp: Convert I2C driver to ->probe_new() There is no platform code that uses i2c module table. Remove it altogether and adjust ->probe() to be ->probe_new(). Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/fdp/i2c.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index e0baec848ff2..8a66b1845f27 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -281,8 +281,7 @@ vsc_read_err: *clock_type, *clock_freq, *fw_vsc_cfg != NULL ? "yes" : "no"); } -static int fdp_nci_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int fdp_nci_i2c_probe(struct i2c_client *client) { struct fdp_i2c_phy *phy; struct device *dev = &client->dev; @@ -360,12 +359,6 @@ static int fdp_nci_i2c_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id fdp_nci_i2c_id_table[] = { - {"int339a", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, fdp_nci_i2c_id_table); - static const struct acpi_device_id fdp_nci_i2c_acpi_match[] = { {"INT339A", 0}, {} @@ -377,8 +370,7 @@ static struct i2c_driver fdp_nci_i2c_driver = { .name = FDP_I2C_DRIVER_NAME, .acpi_match_table = ACPI_PTR(fdp_nci_i2c_acpi_match), }, - .id_table = fdp_nci_i2c_id_table, - .probe = fdp_nci_i2c_probe, + .probe_new = fdp_nci_i2c_probe, .remove = fdp_nci_i2c_remove, }; module_i2c_driver(fdp_nci_i2c_driver); -- cgit v1.2.3 From 7b9fcda91e18f13905e07f0145cc7efbe0e503dc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:50 +0300 Subject: NFC: fdp: Convert to use devres API It looks like there are two leftovers, at least one of which can leak the resource (IRQ). Convert both places to use managed variants of the functions. Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/fdp/fdp.c | 15 ++++----------- drivers/nfc/fdp/i2c.c | 10 +++++----- 2 files changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/fdp/fdp.c b/drivers/nfc/fdp/fdp.c index badd8167ac73..ec50027b0d8b 100644 --- a/drivers/nfc/fdp/fdp.c +++ b/drivers/nfc/fdp/fdp.c @@ -749,11 +749,9 @@ int fdp_nci_probe(struct fdp_i2c_phy *phy, struct nfc_phy_ops *phy_ops, u32 protocols; int r; - info = kzalloc(sizeof(struct fdp_nci_info), GFP_KERNEL); - if (!info) { - r = -ENOMEM; - goto err_info_alloc; - } + info = devm_kzalloc(dev, sizeof(struct fdp_nci_info), GFP_KERNEL); + if (!info) + return -ENOMEM; info->phy = phy; info->phy_ops = phy_ops; @@ -775,8 +773,7 @@ int fdp_nci_probe(struct fdp_i2c_phy *phy, struct nfc_phy_ops *phy_ops, tx_tailroom); if (!ndev) { nfc_err(dev, "Cannot allocate nfc ndev\n"); - r = -ENOMEM; - goto err_alloc_ndev; + return -ENOMEM; } r = nci_register_device(ndev); @@ -792,9 +789,6 @@ int fdp_nci_probe(struct fdp_i2c_phy *phy, struct nfc_phy_ops *phy_ops, err_regdev: nci_free_device(ndev); -err_alloc_ndev: - kfree(info); -err_info_alloc: return r; } EXPORT_SYMBOL(fdp_nci_probe); @@ -808,7 +802,6 @@ void fdp_nci_remove(struct nci_dev *ndev) nci_unregister_device(ndev); nci_free_device(ndev); - kfree(info); } EXPORT_SYMBOL(fdp_nci_remove); diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index 8a66b1845f27..c955f1f5139d 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -303,8 +303,7 @@ static int fdp_nci_i2c_probe(struct i2c_client *client) return -ENODEV; } - phy = devm_kzalloc(dev, sizeof(struct fdp_i2c_phy), - GFP_KERNEL); + phy = devm_kzalloc(dev, sizeof(struct fdp_i2c_phy), GFP_KERNEL); if (!phy) return -ENOMEM; @@ -312,9 +311,10 @@ static int fdp_nci_i2c_probe(struct i2c_client *client) phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD; i2c_set_clientdata(client, phy); - r = request_threaded_irq(client->irq, NULL, fdp_nci_i2c_irq_thread_fn, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - FDP_I2C_DRIVER_NAME, phy); + r = devm_request_threaded_irq(dev, client->irq, + NULL, fdp_nci_i2c_irq_thread_fn, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + FDP_I2C_DRIVER_NAME, phy); if (r < 0) { nfc_err(&client->dev, "Unable to register IRQ handler\n"); -- cgit v1.2.3 From a5d410949ab0a8934e9352dad08ad588beae3395 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:51 +0300 Subject: NFC: fdp: Add GPIO ACPI mapping table In order to make GPIO ACPI library stricter prepare users of gpiod_get_index() to correctly behave when there no mapping is provided by firmware. Here we add explicit mapping between _CRS GpioIo() resources and their names used in the driver. Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/fdp/i2c.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index c955f1f5139d..c4da50e07bbc 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -27,7 +27,6 @@ #define FDP_I2C_DRIVER_NAME "fdp_nci_i2c" -#define FDP_DP_POWER_GPIO_NAME "power" #define FDP_DP_CLOCK_TYPE_NAME "clock-type" #define FDP_DP_CLOCK_FREQ_NAME "clock-freq" #define FDP_DP_FW_VSC_CFG_NAME "fw-vsc-cfg" @@ -281,6 +280,13 @@ vsc_read_err: *clock_type, *clock_freq, *fw_vsc_cfg != NULL ? "yes" : "no"); } +static const struct acpi_gpio_params power_gpios = { 0, 0, false }; + +static const struct acpi_gpio_mapping acpi_fdp_gpios[] = { + { "power-gpios", &power_gpios, 1 }, + {}, +}; + static int fdp_nci_i2c_probe(struct i2c_client *client) { struct fdp_i2c_phy *phy; @@ -321,10 +327,12 @@ static int fdp_nci_i2c_probe(struct i2c_client *client) return r; } - /* Requesting the power gpio */ - phy->power_gpio = devm_gpiod_get(dev, FDP_DP_POWER_GPIO_NAME, - GPIOD_OUT_LOW); + r = devm_acpi_dev_add_driver_gpios(dev, acpi_fdp_gpios); + if (r) + dev_dbg(dev, "Unable to add GPIO mapping table\n"); + /* Requesting the power gpio */ + phy->power_gpio = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW); if (IS_ERR(phy->power_gpio)) { nfc_err(dev, "Power GPIO request failed\n"); return PTR_ERR(phy->power_gpio); -- cgit v1.2.3 From 61a04101c8a486dec586b2657bffede1b3b979f3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:52 +0300 Subject: NFC: st-nci: Get rid of platform data Legacy platform data must go away. We are on the safe side here since there are no users of it in the kernel. If anyone by any odd reason needs it the GPIO lookup tables and built-in device properties at your service. Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 43 ++----------------------------------------- drivers/nfc/st-nci/spi.c | 43 ++----------------------------------------- 2 files changed, 4 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 9dfae0efa922..6d3d8e43fa50 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "st-nci.h" @@ -40,6 +39,7 @@ #define ST_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */ #define ST_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */ +#define ST_NCI_DRIVER_NAME "st_nci" #define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c" #define ST_NCI_GPIO_NAME_RESET "reset" @@ -281,41 +281,10 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client) return 0; } -static int st_nci_i2c_request_resources(struct i2c_client *client) -{ - struct st_nci_nfc_platform_data *pdata; - struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); - int r; - - pdata = client->dev.platform_data; - if (pdata == NULL) { - nfc_err(&client->dev, "No platform data\n"); - return -EINVAL; - } - - /* store for later use */ - phy->gpio_reset = pdata->gpio_reset; - phy->irq_polarity = pdata->irq_polarity; - - r = devm_gpio_request_one(&client->dev, - phy->gpio_reset, GPIOF_OUT_INIT_HIGH, - ST_NCI_GPIO_NAME_RESET); - if (r) { - pr_err("%s : reset gpio_request failed\n", __FILE__); - return r; - } - - phy->se_status.is_ese_present = pdata->is_ese_present; - phy->se_status.is_uicc_present = pdata->is_uicc_present; - - return 0; -} - static int st_nci_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct st_nci_i2c_phy *phy; - struct st_nci_nfc_platform_data *pdata; int r; dev_dbg(&client->dev, "%s\n", __func__); @@ -335,20 +304,12 @@ static int st_nci_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, phy); - pdata = client->dev.platform_data; - if (!pdata && client->dev.of_node) { + if (client->dev.of_node) { r = st_nci_i2c_of_request_resources(client); if (r) { nfc_err(&client->dev, "No platform data\n"); return r; } - } else if (pdata) { - r = st_nci_i2c_request_resources(client); - if (r) { - nfc_err(&client->dev, - "Cannot get platform resources\n"); - return r; - } } else if (ACPI_HANDLE(&client->dev)) { r = st_nci_i2c_acpi_request_resources(client); if (r) { diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index 89e341eba3eb..ee8ea708d5b7 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "st-nci.h" @@ -41,6 +40,7 @@ #define ST_NCI_SPI_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */ #define ST_NCI_SPI_MAX_SIZE 250 /* req 4.2.1 */ +#define ST_NCI_DRIVER_NAME "st_nci" #define ST_NCI_SPI_DRIVER_NAME "st_nci_spi" #define ST_NCI_GPIO_NAME_RESET "reset" @@ -296,40 +296,9 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev) return 0; } -static int st_nci_spi_request_resources(struct spi_device *dev) -{ - struct st_nci_nfc_platform_data *pdata; - struct st_nci_spi_phy *phy = spi_get_drvdata(dev); - int r; - - pdata = dev->dev.platform_data; - if (pdata == NULL) { - nfc_err(&dev->dev, "No platform data\n"); - return -EINVAL; - } - - /* store for later use */ - phy->gpio_reset = pdata->gpio_reset; - phy->irq_polarity = pdata->irq_polarity; - - r = devm_gpio_request_one(&dev->dev, - phy->gpio_reset, GPIOF_OUT_INIT_HIGH, - ST_NCI_GPIO_NAME_RESET); - if (r) { - pr_err("%s : reset gpio_request failed\n", __FILE__); - return r; - } - - phy->se_status.is_ese_present = pdata->is_ese_present; - phy->se_status.is_uicc_present = pdata->is_uicc_present; - - return 0; -} - static int st_nci_spi_probe(struct spi_device *dev) { struct st_nci_spi_phy *phy; - struct st_nci_nfc_platform_data *pdata; int r; dev_dbg(&dev->dev, "%s\n", __func__); @@ -351,20 +320,12 @@ static int st_nci_spi_probe(struct spi_device *dev) spi_set_drvdata(dev, phy); - pdata = dev->dev.platform_data; - if (!pdata && dev->dev.of_node) { + if (dev->dev.of_node) { r = st_nci_spi_of_request_resources(dev); if (r) { nfc_err(&dev->dev, "No platform data\n"); return r; } - } else if (pdata) { - r = st_nci_spi_request_resources(dev); - if (r) { - nfc_err(&dev->dev, - "Cannot get platform resources\n"); - return r; - } } else if (ACPI_HANDLE(&dev->dev)) { r = st_nci_spi_acpi_request_resources(dev); if (r) { -- cgit v1.2.3 From 1af9fea6be9de6e86f628e66c0eae996c49dbe80 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:53 +0300 Subject: NFC: st-nci: Get rid of "interesting" use of interrupt polarity I2C and SPI frameworks followed by IRQ framework do set interrupt polarity correctly if it's properly specified in firmware (ACPI or DT). Get rid of the redundant trick when requesting interrupt. Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 8 +------- drivers/nfc/st-nci/spi.c | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 6d3d8e43fa50..bdfbd543e671 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -51,7 +50,6 @@ struct st_nci_i2c_phy { bool irq_active; unsigned int gpio_reset; - unsigned int irq_polarity; struct st_nci_se_status se_status; }; @@ -225,8 +223,6 @@ static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) phy->gpio_reset = desc_to_gpio(gpiod_reset); - phy->irq_polarity = irq_get_trigger_type(client->irq); - phy->se_status.is_ese_present = false; phy->se_status.is_uicc_present = false; @@ -271,8 +267,6 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client) } phy->gpio_reset = gpio; - phy->irq_polarity = irq_get_trigger_type(client->irq); - phy->se_status.is_ese_present = of_property_read_bool(pp, "ese-present"); phy->se_status.is_uicc_present = @@ -333,7 +327,7 @@ static int st_nci_i2c_probe(struct i2c_client *client, phy->irq_active = true; r = devm_request_threaded_irq(&client->dev, client->irq, NULL, st_nci_irq_thread_fn, - phy->irq_polarity | IRQF_ONESHOT, + IRQF_ONESHOT, ST_NCI_DRIVER_NAME, phy); if (r < 0) nfc_err(&client->dev, "Unable to register IRQ handler\n"); diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index ee8ea708d5b7..4585e205778b 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -52,7 +51,6 @@ struct st_nci_spi_phy { bool irq_active; unsigned int gpio_reset; - unsigned int irq_polarity; struct st_nci_se_status se_status; }; @@ -240,8 +238,6 @@ static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) phy->gpio_reset = desc_to_gpio(gpiod_reset); - phy->irq_polarity = irq_get_trigger_type(spi_dev->irq); - phy->se_status.is_ese_present = false; phy->se_status.is_uicc_present = false; @@ -286,8 +282,6 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev) } phy->gpio_reset = gpio; - phy->irq_polarity = irq_get_trigger_type(dev->irq); - phy->se_status.is_ese_present = of_property_read_bool(pp, "ese-present"); phy->se_status.is_uicc_present = @@ -349,7 +343,7 @@ static int st_nci_spi_probe(struct spi_device *dev) phy->irq_active = true; r = devm_request_threaded_irq(&dev->dev, dev->irq, NULL, st_nci_irq_thread_fn, - phy->irq_polarity | IRQF_ONESHOT, + IRQF_ONESHOT, ST_NCI_SPI_DRIVER_NAME, phy); if (r < 0) nfc_err(&dev->dev, "Unable to register IRQ handler\n"); -- cgit v1.2.3 From a89e68f118e96b165555f7c64fee8aaff7bb7fb3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:54 +0300 Subject: NFC: st-nci: Covert to use GPIO descriptor Since we got rid of platform data, the driver may use GPIO descriptor directly. Looking deeply to the use of the GPIO pin it looks like it should be a GPIO based reset control rather than custom GPIO handling. But this is out of scope of the change. Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 39 ++++++++++++--------------------------- drivers/nfc/st-nci/spi.c | 47 ++++++++++++++++------------------------------- 2 files changed, 28 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index bdfbd543e671..93a621e27d4e 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -19,13 +19,12 @@ #include #include -#include #include -#include #include #include #include #include +#include #include "st-nci.h" @@ -49,7 +48,7 @@ struct st_nci_i2c_phy { bool irq_active; - unsigned int gpio_reset; + struct gpio_desc *gpiod_reset; struct st_nci_se_status se_status; }; @@ -58,9 +57,9 @@ static int st_nci_i2c_enable(void *phy_id) { struct st_nci_i2c_phy *phy = phy_id; - gpio_set_value(phy->gpio_reset, 0); + gpiod_set_value(phy->gpiod_reset, 0); usleep_range(10000, 15000); - gpio_set_value(phy->gpio_reset, 1); + gpiod_set_value(phy->gpiod_reset, 1); usleep_range(80000, 85000); if (phy->ndlc->powered == 0 && phy->irq_active == 0) { @@ -209,20 +208,17 @@ static struct nfc_phy_ops i2c_phy_ops = { static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) { struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); - struct gpio_desc *gpiod_reset; struct device *dev = &client->dev; u8 tmp; /* Get RESET GPIO from ACPI */ - gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1, - GPIOD_OUT_HIGH); - if (IS_ERR(gpiod_reset)) { + phy->gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, + 1, GPIOD_OUT_HIGH); + if (IS_ERR(phy->gpiod_reset)) { nfc_err(dev, "Unable to get RESET GPIO\n"); return -ENODEV; } - phy->gpio_reset = desc_to_gpio(gpiod_reset); - phy->se_status.is_ese_present = false; phy->se_status.is_uicc_present = false; @@ -242,30 +238,19 @@ static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) static int st_nci_i2c_of_request_resources(struct i2c_client *client) { struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); + struct device *dev = &client->dev; struct device_node *pp; - int gpio; - int r; pp = client->dev.of_node; if (!pp) return -ENODEV; /* Get GPIO from device tree */ - gpio = of_get_named_gpio(pp, "reset-gpios", 0); - if (gpio < 0) { - nfc_err(&client->dev, - "Failed to retrieve reset-gpios from device tree\n"); - return gpio; - } - - /* GPIO request and configuration */ - r = devm_gpio_request_one(&client->dev, gpio, - GPIOF_OUT_INIT_HIGH, ST_NCI_GPIO_NAME_RESET); - if (r) { - nfc_err(&client->dev, "Failed to request reset pin\n"); - return r; + phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(phy->gpiod_reset)) { + nfc_err(dev, "Unable to get RESET GPIO\n"); + return PTR_ERR(phy->gpiod_reset); } - phy->gpio_reset = gpio; phy->se_status.is_ese_present = of_property_read_bool(pp, "ese-present"); diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index 4585e205778b..2834f6984608 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -19,13 +19,12 @@ #include #include -#include #include -#include #include #include #include #include +#include #include #include "st-nci.h" @@ -50,7 +49,7 @@ struct st_nci_spi_phy { bool irq_active; - unsigned int gpio_reset; + struct gpio_desc *gpiod_reset; struct st_nci_se_status se_status; }; @@ -59,9 +58,9 @@ static int st_nci_spi_enable(void *phy_id) { struct st_nci_spi_phy *phy = phy_id; - gpio_set_value(phy->gpio_reset, 0); + gpiod_set_value(phy->gpiod_reset, 0); usleep_range(10000, 15000); - gpio_set_value(phy->gpio_reset, 1); + gpiod_set_value(phy->gpiod_reset, 1); usleep_range(80000, 85000); if (phy->ndlc->powered == 0 && phy->irq_active == 0) { @@ -224,20 +223,17 @@ static struct nfc_phy_ops spi_phy_ops = { static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) { struct st_nci_spi_phy *phy = spi_get_drvdata(spi_dev); - struct gpio_desc *gpiod_reset; struct device *dev = &spi_dev->dev; u8 tmp; /* Get RESET GPIO from ACPI */ - gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1, - GPIOD_OUT_HIGH); - if (IS_ERR(gpiod_reset)) { + phy->gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, + 1, GPIOD_OUT_HIGH); + if (IS_ERR(phy->gpiod_reset)) { nfc_err(dev, "Unable to get RESET GPIO\n"); - return -ENODEV; + return PTR_ERR(phy->gpiod_reset); } - phy->gpio_reset = desc_to_gpio(gpiod_reset); - phy->se_status.is_ese_present = false; phy->se_status.is_uicc_present = false; @@ -254,33 +250,22 @@ static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) return 0; } -static int st_nci_spi_of_request_resources(struct spi_device *dev) +static int st_nci_spi_of_request_resources(struct spi_device *spi) { - struct st_nci_spi_phy *phy = spi_get_drvdata(dev); + struct st_nci_spi_phy *phy = spi_get_drvdata(spi); + struct device *dev = &spi->dev; struct device_node *pp; - int gpio; - int r; - pp = dev->dev.of_node; + pp = spi->dev.of_node; if (!pp) return -ENODEV; /* Get GPIO from device tree */ - gpio = of_get_named_gpio(pp, "reset-gpios", 0); - if (gpio < 0) { - nfc_err(&dev->dev, - "Failed to retrieve reset-gpios from device tree\n"); - return gpio; - } - - /* GPIO request and configuration */ - r = devm_gpio_request_one(&dev->dev, gpio, - GPIOF_OUT_INIT_HIGH, ST_NCI_GPIO_NAME_RESET); - if (r) { - nfc_err(&dev->dev, "Failed to request reset pin\n"); - return r; + phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(phy->gpiod_reset)) { + nfc_err(dev, "Unable to get RESET GPIO\n"); + return PTR_ERR(phy->gpiod_reset); } - phy->gpio_reset = gpio; phy->se_status.is_ese_present = of_property_read_bool(pp, "ese-present"); -- cgit v1.2.3 From 75719b2b7a03729f403aed55bec938c6d2784690 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:55 +0300 Subject: NFC: st-nci: Use unified device properties API meaningfully Use unified device properties API in meaningful way. Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 30 ++++++------------------------ drivers/nfc/st-nci/spi.c | 29 +++++------------------------ 2 files changed, 11 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 93a621e27d4e..2ee381586f14 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -209,7 +209,6 @@ static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) { struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); struct device *dev = &client->dev; - u8 tmp; /* Get RESET GPIO from ACPI */ phy->gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, @@ -219,19 +218,6 @@ static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) return -ENODEV; } - phy->se_status.is_ese_present = false; - phy->se_status.is_uicc_present = false; - - if (device_property_present(dev, "ese-present")) { - device_property_read_u8(dev, "ese-present", &tmp); - phy->se_status.is_ese_present = tmp; - } - - if (device_property_present(dev, "uicc-present")) { - device_property_read_u8(dev, "uicc-present", &tmp); - phy->se_status.is_uicc_present = tmp; - } - return 0; } @@ -239,11 +225,6 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client) { struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); struct device *dev = &client->dev; - struct device_node *pp; - - pp = client->dev.of_node; - if (!pp) - return -ENODEV; /* Get GPIO from device tree */ phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); @@ -252,17 +233,13 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client) return PTR_ERR(phy->gpiod_reset); } - phy->se_status.is_ese_present = - of_property_read_bool(pp, "ese-present"); - phy->se_status.is_uicc_present = - of_property_read_bool(pp, "uicc-present"); - return 0; } static int st_nci_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct st_nci_i2c_phy *phy; int r; @@ -301,6 +278,11 @@ static int st_nci_i2c_probe(struct i2c_client *client, return -ENODEV; } + phy->se_status.is_ese_present = + device_property_read_bool(dev, "ese-present"); + phy->se_status.is_uicc_present = + device_property_read_bool(dev, "uicc-present"); + r = ndlc_probe(phy, &i2c_phy_ops, &client->dev, ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM, &phy->ndlc, &phy->se_status); diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index 2834f6984608..383bf69163ef 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -224,7 +224,6 @@ static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) { struct st_nci_spi_phy *phy = spi_get_drvdata(spi_dev); struct device *dev = &spi_dev->dev; - u8 tmp; /* Get RESET GPIO from ACPI */ phy->gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, @@ -234,19 +233,6 @@ static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) return PTR_ERR(phy->gpiod_reset); } - phy->se_status.is_ese_present = false; - phy->se_status.is_uicc_present = false; - - if (device_property_present(dev, "ese-present")) { - device_property_read_u8(dev, "ese-present", &tmp); - tmp = phy->se_status.is_ese_present; - } - - if (device_property_present(dev, "uicc-present")) { - device_property_read_u8(dev, "uicc-present", &tmp); - tmp = phy->se_status.is_uicc_present; - } - return 0; } @@ -254,11 +240,6 @@ static int st_nci_spi_of_request_resources(struct spi_device *spi) { struct st_nci_spi_phy *phy = spi_get_drvdata(spi); struct device *dev = &spi->dev; - struct device_node *pp; - - pp = spi->dev.of_node; - if (!pp) - return -ENODEV; /* Get GPIO from device tree */ phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); @@ -267,11 +248,6 @@ static int st_nci_spi_of_request_resources(struct spi_device *spi) return PTR_ERR(phy->gpiod_reset); } - phy->se_status.is_ese_present = - of_property_read_bool(pp, "ese-present"); - phy->se_status.is_uicc_present = - of_property_read_bool(pp, "uicc-present"); - return 0; } @@ -317,6 +293,11 @@ static int st_nci_spi_probe(struct spi_device *dev) return -ENODEV; } + phy->se_status.is_ese_present = + device_property_read_bool(&dev->dev, "ese-present"); + phy->se_status.is_uicc_present = + device_property_read_bool(&dev->dev, "uicc-present"); + r = ndlc_probe(phy, &spi_phy_ops, &dev->dev, ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM, &phy->ndlc, &phy->se_status); -- cgit v1.2.3 From 85d23e772931e347c145fa78db3c48f29e169838 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:56 +0300 Subject: NFC: st-nci: Add GPIO ACPI mapping table In order to make GPIO ACPI library stricter prepare users of gpiod_get_index() to correctly behave when there no mapping is provided by firmware. Here we add explicit mapping between _CRS GpioIo() resources and their names used in the driver. Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 17 +++++++++++++---- drivers/nfc/st-nci/spi.c | 17 +++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 2ee381586f14..edda253b07fe 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -40,8 +40,6 @@ #define ST_NCI_DRIVER_NAME "st_nci" #define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c" -#define ST_NCI_GPIO_NAME_RESET "reset" - struct st_nci_i2c_phy { struct i2c_client *i2c_dev; struct llt_ndlc *ndlc; @@ -205,14 +203,25 @@ static struct nfc_phy_ops i2c_phy_ops = { .disable = st_nci_i2c_disable, }; +static const struct acpi_gpio_params reset_gpios = { 1, 0, false }; + +static const struct acpi_gpio_mapping acpi_st_nci_gpios[] = { + { "reset-gpios", &reset_gpios, 1 }, + {}, +}; + static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) { struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); struct device *dev = &client->dev; + int r; + + r = devm_acpi_dev_add_driver_gpios(dev, acpi_st_nci_gpios); + if (r) + return r; /* Get RESET GPIO from ACPI */ - phy->gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, - 1, GPIOD_OUT_HIGH); + phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(phy->gpiod_reset)) { nfc_err(dev, "Unable to get RESET GPIO\n"); return -ENODEV; diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index 383bf69163ef..99ecf92edc8c 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -41,8 +41,6 @@ #define ST_NCI_DRIVER_NAME "st_nci" #define ST_NCI_SPI_DRIVER_NAME "st_nci_spi" -#define ST_NCI_GPIO_NAME_RESET "reset" - struct st_nci_spi_phy { struct spi_device *spi_dev; struct llt_ndlc *ndlc; @@ -220,14 +218,25 @@ static struct nfc_phy_ops spi_phy_ops = { .disable = st_nci_spi_disable, }; +static const struct acpi_gpio_params reset_gpios = { 1, 0, false }; + +static const struct acpi_gpio_mapping acpi_st_nci_gpios[] = { + { "reset-gpios", &reset_gpios, 1 }, + {}, +}; + static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) { struct st_nci_spi_phy *phy = spi_get_drvdata(spi_dev); struct device *dev = &spi_dev->dev; + int r; + + r = devm_acpi_dev_add_driver_gpios(dev, acpi_st_nci_gpios); + if (r) + return r; /* Get RESET GPIO from ACPI */ - phy->gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, - 1, GPIOD_OUT_HIGH); + phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(phy->gpiod_reset)) { nfc_err(dev, "Unable to get RESET GPIO\n"); return PTR_ERR(phy->gpiod_reset); -- cgit v1.2.3 From c745120e343abfbcf5c9239e09cae4a3cf651fa0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jun 2017 13:08:57 +0300 Subject: NFC: st-nci: Get rid of code duplication in ->probe() Since OF and ACPI case almost the same get rid of code duplication by moving gpiod_get() calls directly to ->probe(). Signed-off-by: Andy Shevchenko Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 61 +++++++----------------------------------------- drivers/nfc/st-nci/spi.c | 60 +++++++---------------------------------------- 2 files changed, 18 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index edda253b07fe..515f08d037fb 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -210,41 +210,6 @@ static const struct acpi_gpio_mapping acpi_st_nci_gpios[] = { {}, }; -static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) -{ - struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); - struct device *dev = &client->dev; - int r; - - r = devm_acpi_dev_add_driver_gpios(dev, acpi_st_nci_gpios); - if (r) - return r; - - /* Get RESET GPIO from ACPI */ - phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(phy->gpiod_reset)) { - nfc_err(dev, "Unable to get RESET GPIO\n"); - return -ENODEV; - } - - return 0; -} - -static int st_nci_i2c_of_request_resources(struct i2c_client *client) -{ - struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); - struct device *dev = &client->dev; - - /* Get GPIO from device tree */ - phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(phy->gpiod_reset)) { - nfc_err(dev, "Unable to get RESET GPIO\n"); - return PTR_ERR(phy->gpiod_reset); - } - - return 0; -} - static int st_nci_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -260,8 +225,7 @@ static int st_nci_i2c_probe(struct i2c_client *client, return -ENODEV; } - phy = devm_kzalloc(&client->dev, sizeof(struct st_nci_i2c_phy), - GFP_KERNEL); + phy = devm_kzalloc(dev, sizeof(struct st_nci_i2c_phy), GFP_KERNEL); if (!phy) return -ENOMEM; @@ -269,21 +233,14 @@ static int st_nci_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, phy); - if (client->dev.of_node) { - r = st_nci_i2c_of_request_resources(client); - if (r) { - nfc_err(&client->dev, "No platform data\n"); - return r; - } - } else if (ACPI_HANDLE(&client->dev)) { - r = st_nci_i2c_acpi_request_resources(client); - if (r) { - nfc_err(&client->dev, "Cannot get ACPI data\n"); - return r; - } - } else { - nfc_err(&client->dev, - "st_nci platform resources not available\n"); + r = devm_acpi_dev_add_driver_gpios(dev, acpi_st_nci_gpios); + if (r) + dev_dbg(dev, "Unable to add GPIO mapping table\n"); + + /* Get RESET GPIO */ + phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(phy->gpiod_reset)) { + nfc_err(dev, "Unable to get RESET GPIO\n"); return -ENODEV; } diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index 99ecf92edc8c..14705591b0fb 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -225,41 +225,6 @@ static const struct acpi_gpio_mapping acpi_st_nci_gpios[] = { {}, }; -static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) -{ - struct st_nci_spi_phy *phy = spi_get_drvdata(spi_dev); - struct device *dev = &spi_dev->dev; - int r; - - r = devm_acpi_dev_add_driver_gpios(dev, acpi_st_nci_gpios); - if (r) - return r; - - /* Get RESET GPIO from ACPI */ - phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(phy->gpiod_reset)) { - nfc_err(dev, "Unable to get RESET GPIO\n"); - return PTR_ERR(phy->gpiod_reset); - } - - return 0; -} - -static int st_nci_spi_of_request_resources(struct spi_device *spi) -{ - struct st_nci_spi_phy *phy = spi_get_drvdata(spi); - struct device *dev = &spi->dev; - - /* Get GPIO from device tree */ - phy->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(phy->gpiod_reset)) { - nfc_err(dev, "Unable to get RESET GPIO\n"); - return PTR_ERR(phy->gpiod_reset); - } - - return 0; -} - static int st_nci_spi_probe(struct spi_device *dev) { struct st_nci_spi_phy *phy; @@ -284,22 +249,15 @@ static int st_nci_spi_probe(struct spi_device *dev) spi_set_drvdata(dev, phy); - if (dev->dev.of_node) { - r = st_nci_spi_of_request_resources(dev); - if (r) { - nfc_err(&dev->dev, "No platform data\n"); - return r; - } - } else if (ACPI_HANDLE(&dev->dev)) { - r = st_nci_spi_acpi_request_resources(dev); - if (r) { - nfc_err(&dev->dev, "Cannot get ACPI data\n"); - return r; - } - } else { - nfc_err(&dev->dev, - "st_nci platform resources not available\n"); - return -ENODEV; + r = devm_acpi_dev_add_driver_gpios(&dev->dev, acpi_st_nci_gpios); + if (r) + dev_dbg(&dev->dev, "Unable to add GPIO mapping table\n"); + + /* Get RESET GPIO */ + phy->gpiod_reset = devm_gpiod_get(&dev->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(phy->gpiod_reset)) { + nfc_err(&dev->dev, "Unable to get RESET GPIO\n"); + return PTR_ERR(phy->gpiod_reset); } phy->se_status.is_ese_present = -- cgit v1.2.3 From e1038535106e73e48204ec3bfe5a428fe6cb35cb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 24 Apr 2017 14:36:02 +0100 Subject: NFC: trf7970a: fix check of clock frequencies, use && instead of || The "or" condition (clk_freq != TRF7970A_27MHZ_CLOCK_FREQUENCY) || (clk_freq != TRF7970A_13MHZ_CLOCK_FREQUE) will always be true because clk_freq cannot be equal to two different values at the same time. Use the && operator instead of || to fix this. Detected by CoverityScan, CID#1430468 ("Constant expression result") Fixes: 837eb4d21ecde7 ("NFC: trf7970a: add device tree option for 27MHz clock") Signed-off-by: Colin Ian King Acked-by: Geoff Lansberry Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 28b942ea15fb..914463a0e7b3 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -2059,7 +2059,7 @@ static int trf7970a_probe(struct spi_device *spi) } of_property_read_u32(np, "clock-frequency", &clk_freq); - if ((clk_freq != TRF7970A_27MHZ_CLOCK_FREQUENCY) || + if ((clk_freq != TRF7970A_27MHZ_CLOCK_FREQUENCY) && (clk_freq != TRF7970A_13MHZ_CLOCK_FREQUENCY)) { dev_err(trf->dev, "clock-frequency (%u Hz) unsupported\n", clk_freq); -- cgit v1.2.3 From a81d1ab3cad77e20c2df8baef0a35a4980fc511c Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Thu, 15 Jun 2017 10:46:17 -0700 Subject: Revert "NFC: trf7970a: Handle extra byte in response to Type 5 RMB commands" This reverts commit ab714817d7e891608d31f6996b1e4c43cf2bf342. The original commit was designed to handle a bug in the trf7970a NFC controller where an extra byte was returned in Read Multiple Blocks (RMB) command responses. However, it has become less clear whether it is a bug in the trf7970a or in the tag. In addition, it was assumed that the extra byte was always returned but it turns out that is not always the case. The result is that a byte of good data is trimmed off when the extra byte is not present ultimately causing the neard deamon to fail the read. Since the trf7970a driver does not have the context to know when to trim the byte or not, remove the code from the trf7970a driver all together (and move it up to the neard daemon). This has the added benefit of simplifying the kernel driver and putting the extra complexity into userspace. CC: Rob Herring CC: devicetree@vger.kernel.org Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 914463a0e7b3..6ee7b038823d 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -150,7 +150,6 @@ */ #define TRF7970A_QUIRK_IRQ_STATUS_READ BIT(0) #define TRF7970A_QUIRK_EN2_MUST_STAY_LOW BIT(1) -#define TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE BIT(2) /* Direct commands */ #define TRF7970A_CMD_IDLE 0x00 @@ -449,7 +448,6 @@ struct trf7970a { u8 md_rf_tech; u8 tx_cmd; bool issue_eof; - bool adjust_resp_len; struct gpio_desc *en_gpiod; struct gpio_desc *en2_gpiod; struct mutex lock; @@ -630,13 +628,6 @@ static void trf7970a_send_upstream(struct trf7970a *trf) trf->aborting = false; } - if (trf->adjust_resp_len) { - if (trf->rx_skb) - skb_trim(trf->rx_skb, trf->rx_skb->len - 1); - - trf->adjust_resp_len = false; - } - trf->cb(trf->ddev, trf->cb_arg, trf->rx_skb); trf->rx_skb = NULL; @@ -1459,15 +1450,10 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) trf->iso_ctrl = iso_ctrl; } - if (trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) { - if (trf7970a_is_iso15693_write_or_lock(req[1]) && - (req[0] & ISO15693_REQ_FLAG_OPTION)) - trf->issue_eof = true; - else if ((trf->quirks & - TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE) && - (req[1] == ISO15693_CMD_READ_MULTIPLE_BLOCK)) - trf->adjust_resp_len = true; - } + if ((trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) && + trf7970a_is_iso15693_write_or_lock(req[1]) && + (req[0] & ISO15693_REQ_FLAG_OPTION)) + trf->issue_eof = true; } return 0; @@ -2032,9 +2018,6 @@ static int trf7970a_probe(struct spi_device *spi) return ret; } - if (of_property_read_bool(np, "t5t-rmb-extra-byte-quirk")) - trf->quirks |= TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE; - if (of_property_read_bool(np, "irq-status-read-quirk")) trf->quirks |= TRF7970A_QUIRK_IRQ_STATUS_READ; -- cgit v1.2.3 From 6f874bafacf053b87887f4149fc117e2b1096138 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 30 May 2017 15:43:07 -0500 Subject: NFC: add NULL checks to avoid potential NULL pointer dereference NULL checks at line 457: if (!link0 || !link1) {, implies that both pointers link0 and link1 might be NULL. Function nfcsim_link_free() dereference pointers link0 and link1. Add NULL checks before calling nfcsim_link_free() to avoid a potential NULL pointer dereference. Addresses-Coverity-ID: 1364857 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcsim.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcsim.c b/drivers/nfc/nfcsim.c index a466e7978466..33449820e754 100644 --- a/drivers/nfc/nfcsim.c +++ b/drivers/nfc/nfcsim.c @@ -482,8 +482,10 @@ static int __init nfcsim_init(void) exit_err: pr_err("Failed to initialize nfcsim driver (%d)\n", rc); - nfcsim_link_free(link0); - nfcsim_link_free(link1); + if (link0) + nfcsim_link_free(link0); + if (link1) + nfcsim_link_free(link1); return rc; } -- cgit v1.2.3 From 640e32c9ee55a7938eb7d629a87f46a94f77a87f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 23 Jun 2017 09:37:38 +0100 Subject: Bluetooth: hci_serdev: make hci_serdev_client_ops static The structure hci_serdev_client_ops does not need to be in global scope and is not modified, so make it static. Cleans up sparse warning: "symbol 'hci_serdev_client_ops' was not declared. Should it be static?" Signed-off-by: Colin Ian King Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_serdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 7de0edc0ff8c..aea930101dd2 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -31,7 +31,7 @@ #include "hci_uart.h" -struct serdev_device_ops hci_serdev_client_ops; +static struct serdev_device_ops hci_serdev_client_ops; static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) { @@ -268,7 +268,7 @@ static int hci_uart_receive_buf(struct serdev_device *serdev, const u8 *data, return count; } -struct serdev_device_ops hci_serdev_client_ops = { +static struct serdev_device_ops hci_serdev_client_ops = { .receive_buf = hci_uart_receive_buf, .write_wakeup = hci_uart_write_wakeup, }; -- cgit v1.2.3 From 78c1acf35fcd528ff4c76057d5724ac00e0f7fff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 May 2017 12:53:22 +0200 Subject: iwlwifi: simplify data tracepoint There's no need to calculate the data_len outside of the tracepoint, since it's always skb->len - hdr_len, which are both available inside. Simplify the callers and move the calculation in. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h | 11 ++++++----- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 3 +-- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h index d80312b46f16..a80e4202cd03 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h @@ -35,19 +35,20 @@ TRACE_EVENT(iwlwifi_dev_tx_data, TP_PROTO(const struct device *dev, - struct sk_buff *skb, - u8 hdr_len, size_t data_len), - TP_ARGS(dev, skb, hdr_len, data_len), + struct sk_buff *skb, u8 hdr_len), + TP_ARGS(dev, skb, hdr_len), TP_STRUCT__entry( DEV_ENTRY - __dynamic_array(u8, data, iwl_trace_data(skb) ? data_len : 0) + __dynamic_array(u8, data, + iwl_trace_data(skb) ? skb->len - hdr_len : 0) ), TP_fast_assign( DEV_ASSIGN; if (iwl_trace_data(skb)) skb_copy_bits(skb, hdr_len, - __get_dynamic_array(data), data_len); + __get_dynamic_array(data), + skb->len - hdr_len); ), TP_printk("[%s] TX frame data", __get_str(dev)) ); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 464a435a4440..a0b237b58b3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -469,8 +469,7 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, skb->data + hdr_len, tb2_len); - trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len, - skb->len - hdr_len); + trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); return tfd; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 0a6e36a8a0bf..98cccaeeecdd 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1979,8 +1979,7 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, trans_pcie->tfd_size, &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, skb->data + hdr_len, tb2_len); - trace_iwlwifi_dev_tx_data(trans->dev, skb, - hdr_len, skb->len - hdr_len); + trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); return 0; } -- cgit v1.2.3 From 8790fce4f696ed55195283d26685cc0edaea63a8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 May 2017 13:04:40 +0200 Subject: iwlwifi: fix TX tracing for non-linear SKBs When sending non-linear SKBs that should be included in the regular TX tracing completely (and not be pushed into the tx_data tracing), the (tracing) code didn't correctly take the fact that they were non-linear into account and added only the skb head portion. This probably never really triggered, since those frames we want traced fully are most likely linear anyway, but the code gets easier to understand and we lose an argument to the tracing function, so overall fixing this is better. Fixes: 206eea783385 ("iwlwifi: pcie: support frag SKBs") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h | 19 ++++++++++++------- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 5 ++--- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 5 ++--- 3 files changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h index f02e2c89abbb..7f16dcce0995 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h @@ -2,7 +2,7 @@ * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -91,8 +91,8 @@ TRACE_EVENT(iwlwifi_dev_tx, TP_PROTO(const struct device *dev, struct sk_buff *skb, void *tfd, size_t tfdlen, void *buf0, size_t buf0_len, - void *buf1, size_t buf1_len), - TP_ARGS(dev, skb, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len), + int hdr_len), + TP_ARGS(dev, skb, tfd, tfdlen, buf0, buf0_len, hdr_len), TP_STRUCT__entry( DEV_ENTRY @@ -105,15 +105,20 @@ TRACE_EVENT(iwlwifi_dev_tx, * for the possible padding). */ __dynamic_array(u8, buf0, buf0_len) - __dynamic_array(u8, buf1, iwl_trace_data(skb) ? 0 : buf1_len) + __dynamic_array(u8, buf1, hdr_len > 0 && iwl_trace_data(skb) ? + 0 : skb->len - hdr_len) ), TP_fast_assign( DEV_ASSIGN; - __entry->framelen = buf0_len + buf1_len; + __entry->framelen = buf0_len; + if (hdr_len > 0) + __entry->framelen += skb->len - hdr_len; memcpy(__get_dynamic_array(tfd), tfd, tfdlen); memcpy(__get_dynamic_array(buf0), buf0, buf0_len); - if (!iwl_trace_data(skb)) - memcpy(__get_dynamic_array(buf1), buf1, buf1_len); + if (hdr_len > 0 && !iwl_trace_data(skb)) + skb_copy_bits(skb, hdr_len, + __get_dynamic_array(buf1), + skb->len - hdr_len); ), TP_printk("[%s] TX %.2x (%zu bytes)", __get_str(dev), ((u8 *)__get_dynamic_array(buf0))[0], diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index a0b237b58b3d..a3795ba0d7b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -249,7 +249,7 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, IEEE80211_CCMP_HDR_LEN : 0; trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), - &dev_cmd->hdr, start_len, NULL, 0); + &dev_cmd->hdr, start_len, 0); ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); @@ -467,8 +467,7 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, } trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, - IWL_FIRST_TB_SIZE + tb1_len, - skb->data + hdr_len, tb2_len); + IWL_FIRST_TB_SIZE + tb1_len, hdr_len); trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); return tfd; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 98cccaeeecdd..be38dd3a6d93 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1978,7 +1978,7 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), trans_pcie->tfd_size, &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, - skb->data + hdr_len, tb2_len); + hdr_len); trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len); return 0; } @@ -2051,8 +2051,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, trace_iwlwifi_dev_tx(trans->dev, skb, iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), trans_pcie->tfd_size, - &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, - NULL, 0); + &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, 0); ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); -- cgit v1.2.3 From d490e09784a9d0a63f831e5f1104b4826e666b0c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 May 2017 12:16:48 +0200 Subject: iwlwifi: pcie: fix command completion name debug When the command name is printed on command completion, the wrong group is used, leading to the wrong name being printed. Fix this by using the group ID without inappropriately mangling it through iwl_cmd_groupid() - it's already a u8. Also, while at it, use it from the same place as the command ID, everything else is just confusing. Fixes: ab02165ccec4 ("iwlwifi: add wide firmware command infrastructure for TX") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index be38dd3a6d93..6b19ccc0ae41 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1706,7 +1706,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); - u8 group_id = iwl_cmd_groupid(pkt->hdr.group_id); + u8 group_id; u32 cmd_id; int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); @@ -1732,6 +1732,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, cmd_index = get_cmd_index(txq, index); cmd = txq->entries[cmd_index].cmd; meta = &txq->entries[cmd_index].meta; + group_id = cmd->hdr.group_id; cmd_id = iwl_cmd_id(cmd->hdr.cmd, group_id, 0); iwl_pcie_tfd_unmap(trans, meta, txq, index); -- cgit v1.2.3 From 7b7cab79b8e7f904b22312b83989b2ba785a700c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 2 May 2017 13:01:49 +0200 Subject: iwlwifi: mvm: docs: fix enum link, provide TX response link Fix the enum link by adding the missing & and provide the link to the TX response documentation. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index c30e0e95b0b0..a5a8616dad6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -488,7 +488,7 @@ enum iwl_tx_agg_status { /** * struct agg_tx_status - per packet TX aggregation status - * @status: enum iwl_tx_agg_status + * @status: See &enum iwl_tx_agg_status * @sequence: Sequence # for this frame's Tx cmd (not SSN!) */ struct agg_tx_status { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index cc6af9bd4e10..7a52fb6b4924 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -216,7 +216,8 @@ enum iwl_legacy_cmds { FW_GET_ITEM_CMD = 0x1a, /** - * @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2 + * @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2, + * response in &struct iwl_mvm_tx_resp */ TX_CMD = 0x1c, -- cgit v1.2.3 From 3e73148406c67615bbe8d166d2c22efc3995e305 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Wed, 3 May 2017 18:47:46 +0300 Subject: iwlwifi: mvm: fix fw monitor 7000 HW recollecting To stop and start the FW monitor in the 7000 HW family we need to use a different bit, otherwise after stopping it for the first time - it won't get restarted. Use the correct bitmask. Note: This fix is only for DRAM collection mode. For other modes, an additional fix will be needed. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3a8c95162811..4e66cc662120 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1181,9 +1181,13 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) /* start recording again if the firmware is not crashed */ if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) && - mvm->fw->dbg_dest_tlv) + mvm->fw->dbg_dest_tlv) { iwl_clear_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); + iwl_clear_bits_prph(mvm->trans, + MON_BUFF_SAMPLE_CTL, 0x1); + iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x1); + } } else { u32 in_sample = iwl_read_prph(mvm->trans, DBGC_IN_SAMPLE); u32 out_ctrl = iwl_read_prph(mvm->trans, DBGC_OUT_CTRL); -- cgit v1.2.3 From a6a621934e2e041ad4a8b55ef273731794e936ed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 May 2017 21:56:04 +0200 Subject: iwlwifi: mvm: disentangle union in TX status struct This improves documentation, since kernel-doc can't deal with the union well. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 73 ++++++++++++++++++---- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 3 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 9 ++- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 3 +- 4 files changed, 69 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index a5a8616dad6f..0562ce406249 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -513,7 +513,7 @@ struct agg_tx_status { #define IWL_MVM_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4) /** - * struct iwl_mvm_tx_resp - notifies that fw is TXing a packet + * struct iwl_mvm_tx_resp_v3 - notifies that fw is TXing a packet * ( REPLY_TX = 0x1c ) * @frame_count: 1 no aggregation, >1 aggregation * @bt_kill_count: num of times blocked by bluetooth (unused for agg) @@ -540,7 +540,63 @@ struct agg_tx_status { * @tx_queue: TX queue for this response * @status: for non-agg: frame status TX_STATUS_* * for agg: status of 1st frame, AGG_TX_STATE_*; other frame status fields - * follow this one, up to frame_count. + * follow this one, up to frame_count. Length in @frame_count. + * + * After the array of statuses comes the SSN of the SCD. Look at + * %iwl_mvm_get_scd_ssn for more details. + */ +struct iwl_mvm_tx_resp_v3 { + u8 frame_count; + u8 bt_kill_count; + u8 failure_rts; + u8 failure_frame; + __le32 initial_rate; + __le16 wireless_media_time; + + u8 pa_status; + u8 pa_integ_res_a[3]; + u8 pa_integ_res_b[3]; + u8 pa_integ_res_c[3]; + __le16 measurement_req_id; + u8 reduced_tpc; + u8 reserved; + + __le32 tfd_info; + __le16 seq_ctl; + __le16 byte_cnt; + u8 tlc_info; + u8 ra_tid; + __le16 frame_ctrl; + struct agg_tx_status status[]; +} __packed; /* TX_RSP_API_S_VER_3 */ + +/** + * struct iwl_mvm_tx_resp - notifies that fw is TXing a packet + * ( REPLY_TX = 0x1c ) + * @frame_count: 1 no aggregation, >1 aggregation + * @bt_kill_count: num of times blocked by bluetooth (unused for agg) + * @failure_rts: num of failures due to unsuccessful RTS + * @failure_frame: num failures due to no ACK (unused for agg) + * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the + * Tx of all the batch. RATE_MCS_* + * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK. + * for agg: RTS + CTS + aggregation tx time + block-ack time. + * in usec. + * @pa_status: tx power info + * @pa_integ_res_a: tx power info + * @pa_integ_res_b: tx power info + * @pa_integ_res_c: tx power info + * @measurement_req_id: tx power info + * @reduced_tpc: transmit power reduction used + * @reserved: reserved + * @tfd_info: TFD information set by the FH + * @seq_ctl: sequence control from the Tx cmd + * @byte_cnt: byte count from the Tx cmd + * @tlc_info: TLC rate info + * @ra_tid: bits [3:0] = ra, bits [7:4] = tid + * @frame_ctrl: frame control + * @tx_queue: TX queue for this response + * @status: for non-agg: frame status TX_STATUS_* * For version 6 TX response isn't received for aggregation at all. * * After the array of statuses comes the SSN of the SCD. Look at @@ -568,16 +624,9 @@ struct iwl_mvm_tx_resp { u8 tlc_info; u8 ra_tid; __le16 frame_ctrl; - union { - struct { - struct agg_tx_status status; - } v3;/* TX_RSP_API_S_VER_3 */ - struct { - __le16 tx_queue; - __le16 reserved2; - struct agg_tx_status status; - } v6; - }; + __le16 tx_queue; + __le16 reserved2; + struct agg_tx_status status; } __packed; /* TX_RSP_API_S_VER_6 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 7a52fb6b4924..dc613b604914 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -217,7 +217,8 @@ enum iwl_legacy_cmds { /** * @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2, - * response in &struct iwl_mvm_tx_resp + * response in &struct iwl_mvm_tx_resp or + * &struct iwl_mvm_tx_resp_v3 */ TX_CMD = 0x1c, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 0b5e92c1483e..e616472afd45 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1296,14 +1296,13 @@ static inline bool iwl_mvm_is_cdb_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CDB_SUPPORT); } -static inline struct agg_tx_status* -iwl_mvm_get_agg_status(struct iwl_mvm *mvm, - struct iwl_mvm_tx_resp *tx_resp) +static inline struct agg_tx_status * +iwl_mvm_get_agg_status(struct iwl_mvm *mvm, void *tx_resp) { if (iwl_mvm_has_new_tx_api(mvm)) - return &tx_resp->v6.status; + return &((struct iwl_mvm_tx_resp *)tx_resp)->status; else - return &tx_resp->v3.status; + return ((struct iwl_mvm_tx_resp_v3 *)tx_resp)->status; } static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 288505114153..02f293b711fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1331,6 +1331,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, struct ieee80211_sta *sta; u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); + /* struct iwl_mvm_tx_resp_v3 is almost the same */ struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid); int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); @@ -1348,7 +1349,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, __skb_queue_head_init(&skbs); if (iwl_mvm_has_new_tx_api(mvm)) - txq_id = le16_to_cpu(tx_resp->v6.tx_queue); + txq_id = le16_to_cpu(tx_resp->tx_queue); seq_ctl = le16_to_cpu(tx_resp->seq_ctl); -- cgit v1.2.3 From e6138c9ca59293052bae8d7e2db247ab3d0c3ee1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 May 2017 10:00:03 +0200 Subject: iwlwifi: mvm: add documentation for enum iwl_debug_cmds Add kernel-doc documentation for enum iwl_debug_cmds, linking the structures used by the commands. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index dc613b604914..224d10b1b076 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -554,9 +554,26 @@ enum iwl_regulatory_and_nvm_subcmd_ids { NVM_GET_INFO = 0x2, }; +/** + * enum iwl_debug_cmds - debug commands + */ enum iwl_debug_cmds { + /** + * @LMAC_RD_WR: + * LMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and + * &struct iwl_dbg_mem_access_rsp + */ LMAC_RD_WR = 0x0, + /** + * @UMAC_RD_WR: + * UMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and + * &struct iwl_dbg_mem_access_rsp + */ UMAC_RD_WR = 0x1, + /** + * @MFU_ASSERT_DUMP_NTF: + * &struct iwl_mfu_assert_dump_notif + */ MFU_ASSERT_DUMP_NTF = 0xFE, }; -- cgit v1.2.3 From d98d6fb9f167978eea79c7379301963053c5319c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 May 2017 11:01:32 +0200 Subject: iwlwifi: document transmit buffer bits better Properly document the transmit buffer bits using an enum and kernel-doc documentation. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 77be149276b6..66e5db41e559 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -655,6 +655,17 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) { return (sizeof(addr) > sizeof(u32) ? upper_32_bits(addr) : 0) & 0xF; } + +/** + * enum iwl_tfd_tb_hi_n_len - TB hi_n_len bits + * @TB_HI_N_LEN_ADDR_HI_MSK: high 4 bits (to make it 36) of DMA address + * @TB_HI_N_LEN_LEN_MSK: length of the TB + */ +enum iwl_tfd_tb_hi_n_len { + TB_HI_N_LEN_ADDR_HI_MSK = 0xf, + TB_HI_N_LEN_LEN_MSK = 0xfff0, +}; + /** * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor * @@ -662,8 +673,7 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) * * @lo: low [31:0] portion of the dma address of TX buffer * every even is unaligned on 16 bit boundary - * @hi_n_len 0-3 [35:32] portion of dma - * 4-15 length of the tx buffer + * @hi_n_len: &enum iwl_tfd_tb_hi_n_len */ struct iwl_tfd_tb { __le32 lo; -- cgit v1.2.3 From 1dad3e0a313c42f8ade19f6987aedb857c4d07d0 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 3 May 2017 15:09:52 +0300 Subject: iwlwifi: remove useless iwl_free_nvm_data() function This function just calls kfree(), so it only obscures the code without bringing any benefits. Remove it. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h | 9 --------- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 3 files changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index b49848683587..4c8f9f1a5532 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1513,7 +1513,7 @@ out_destroy_workqueue: out_free_eeprom_blob: kfree(priv->eeprom_blob); out_free_eeprom: - iwl_free_nvm_data(priv->nvm_data); + kfree(priv->nvm_data); out_free_hw: ieee80211_free_hw(priv->hw); out: @@ -1532,7 +1532,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) iwl_tt_exit(priv); kfree(priv->eeprom_blob); - iwl_free_nvm_data(priv->nvm_data); + kfree(priv->nvm_data); /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h index e04a91d70a15..b33888991b94 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h @@ -121,15 +121,6 @@ struct iwl_nvm_data * iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg, const u8 *eeprom, size_t eeprom_size); -/** - * iwl_free_nvm_data - free NVM data - * @data: the data to free - */ -static inline void iwl_free_nvm_data(struct iwl_nvm_data *data) -{ - kfree(data); -} - int iwl_nvm_check_version(struct iwl_nvm_data *data, struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 4e66cc662120..fc2c607013fb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -849,7 +849,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) iwl_phy_db_free(mvm->phy_db); mvm->phy_db = NULL; - iwl_free_nvm_data(mvm->nvm_data); + kfree(mvm->nvm_data); for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++) kfree(mvm->nvm_sections[i].data); -- cgit v1.2.3 From 946af0079cd260546d3773e7ff5409f49949371d Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 3 May 2017 15:12:09 +0300 Subject: iwlwifi: mvm: fix nvm_data leak We allocate nvm_data in iwl_mvm_nvm_get_from_fw(). If something goes wrong after the allocation (i.e. if no valid MAC address is valid), we should free nvm_data before returning an error. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index ad8bd90deed2..efdcffbaac6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -596,7 +596,7 @@ int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm) if (!is_valid_ether_addr(mvm->nvm_data->hw_addr)) { IWL_ERR(trans, "no valid mac address was found\n"); ret = -EINVAL; - goto out; + goto err_free; } /* Initialize general data */ @@ -628,7 +628,11 @@ int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm) mvm->nvm_data->valid_rx_ant & mvm->fw->valid_rx_ant, rsp->regulatory.lar_enabled && lar_fw_supported); - ret = 0; + iwl_free_resp(&hcmd); + return 0; + +err_free: + kfree(mvm->nvm_data); out: iwl_free_resp(&hcmd); return ret; -- cgit v1.2.3 From 6b28f9784c394f0692e160f81b07c82cb64af160 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 5 May 2017 08:51:24 +0300 Subject: iwlwifi: mvm: fix the recovery flow while connecting In BSS mode in the disconnection flow, mac80211 removes the AP station before the vif is set to unassociated. Our firmware wants it the other way around: first set the vif as unassociated, and then remove the AP station. In order to bridge between those two different behaviors, iwlmvm doesn't remove the station from the firmware when mac80211 removes it, but only after the vif is set to unassociated. The implementation is in iwl_mvm_bss_info_changed_station: if (assoc state was modified && mvmvif->ap_sta_id is VALID && assoc state is now UNASSC) remove_the_station_from_the_firmware() During the recovery flow, mac80211 re-adds the AP station and then reconfigures the vif. Since the vif is not associated, and then, we enter the if above (which was intended to be taken in the disconnection flow only) and remove the station we just added. This defeats the recovery flow. Fix this by not removing the AP station in this flow if we are in recovery flow. Cc: stable@vger.kernel.org Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 32 ++++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index d608ce8305c7..d04a88c6c593 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1988,14 +1988,32 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false), "Failed to update SF upon disassociation\n"); - /* remove AP station now that the MAC is unassoc */ - ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); - if (ret) - IWL_ERR(mvm, "failed to remove AP station\n"); + /* + * If we get an assert during the connection (after the + * station has been added, but before the vif is set + * to associated), mac80211 will re-add the station and + * then configure the vif. Since the vif is not + * associated, we would remove the station here and + * this would fail the recovery. + */ + if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, + &mvm->status)) { + /* + * Remove AP station now that + * the MAC is unassoc + */ + ret = iwl_mvm_rm_sta_id(mvm, vif, + mvmvif->ap_sta_id); + if (ret) + IWL_ERR(mvm, + "failed to remove AP station\n"); + + if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) + mvm->d0i3_ap_sta_id = + IWL_MVM_INVALID_STA; + mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; + } - if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) - mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; - mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; /* remove quota for this interface */ ret = iwl_mvm_update_quotas(mvm, false, NULL); if (ret) -- cgit v1.2.3 From ffd6fd45616672ee1ba122ea54d47fa8fe1dd8d8 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 5 May 2017 17:55:24 +0300 Subject: iwlwifi: pcie: don't disable bh when handling FW errors When we started using threaded irqs, all the opmode calls were changed to be called with local_bh disabled. The reason for this was it was that mac80211 needs that. When we are handling FW errors, mac80211 is not involved, so we don't need it. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 6eef2e789426..fa5f39f72d22 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1413,11 +1413,9 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) return; } - local_bh_disable(); /* The STATUS_FW_ERROR bit is set in this function. This must happen * before we wake up the command caller, to ensure a proper cleanup. */ iwl_trans_fw_error(trans); - local_bh_enable(); for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { if (!trans_pcie->txq[i]) -- cgit v1.2.3 From 6b54ebf73b3e5adc2cab3abc6cb37ca66fa74ae2 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 5 May 2017 16:11:24 +0300 Subject: iwlwifi: mvm: reset the HW before dumping if HW error is detected If the hardware is stuck, we can't read any of the memory we need to dump it, so we end up printing only 0xa5a5a5a5, which is useless. To solve this, poke the hardware by triggering a reset and re-enabling the clocks if we detect a HW error. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index dc8104d846f9..e7cc8e05615a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -69,6 +69,7 @@ #include "iwl-debug.h" #include "iwl-io.h" #include "iwl-prph.h" +#include "iwl-csr.h" #include "fw-dbg.h" #include "mvm.h" #include "fw-api-rs.h" @@ -497,6 +498,7 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) { struct iwl_trans *trans = mvm->trans; struct iwl_error_event_table table; + u32 val; if (mvm->cur_ucode == IWL_UCODE_INIT) { if (!base) @@ -515,6 +517,36 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) return; } + /* check if there is a HW error */ + val = iwl_trans_read_mem32(trans, base); + if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) { + int err; + + IWL_ERR(trans, "HW error, resetting before reading\n"); + + /* reset the device */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + usleep_range(1000, 2000); + + /* set INIT_DONE flag */ + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* and wait for clock stabilization */ + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + udelay(2); + + err = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); + if (err < 0) { + IWL_DEBUG_INFO(trans, + "Failed to reset the card for the dump\n"); + return; + } + } + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { -- cgit v1.2.3 From 59df97f7223636399f425a5e76586218c48d791e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 7 May 2017 13:31:55 +0300 Subject: iwlwifi: mvm: don't mark TIDs that are not idle wrt BA as inactive A TID may not have traffic but still have a BA agreement active (or being setup / torn down) since a BA agreement can be triggered by a debugfs hook. Just avoid to consider such a TID as inactive to make the logic safer. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index e7cc8e05615a..8ba8b71dd1a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1215,6 +1215,10 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, /* If some TFDs are still queued - don't mark TID as inactive */ if (iwl_mvm_tid_queued(mvm, &mvmsta->tid_data[tid])) tid_bitmap &= ~BIT(tid); + + /* Don't mark as inactive any TID that has an active BA */ + if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) + tid_bitmap &= ~BIT(tid); } /* If all TIDs in the queue are inactive - mark queue as inactive. */ -- cgit v1.2.3 From dcfbd67b4b8d5223d5362aac9af267387a32f568 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 7 May 2017 15:00:31 +0300 Subject: iwlwifi: add a W/A for a scheduler hardware bug In case we need to move the scheduler write pointer by steps of 0x40, 0x80 or 0xc0, the scheduler gets stuck. This leads to hardware error interrupts with status: 0x5A5A5A5A or alike. In order to work around this, detect in the transport layer that we are going to hit this case and tell iwlmvm to increment the sequence number of the packets. This allows to keep the requirement that the WiFi sequence number is in sync with the index in the scheduler Tx queue and it also allows to avoid the problematic sequence. This means that from time to time, we will start a queue from ssn + 1, but that shouldn't be a problem since we don't switch to new queues for AMPDU now that we have DQA which allows to keep the same queue while toggling the AMPDU state. This bug has been fixed on 9000 devices and up. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 13 +++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 17 ++++++-- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 50 ++++++++++++---------- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 22 +++++++++- 6 files changed, 72 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 2e975c0be045..57db6250a329 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -482,7 +482,9 @@ struct iwl_trans_txq_scd_cfg { * iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before * this one. The op_mode must not configure the HCMD queue. The scheduler * configuration may be %NULL, in which case the hardware will not be - * configured. May sleep. + * configured. If true is returned, the operation mode needs to increment + * the sequence number of the packets routed to this queue because of a + * hardware scheduler bug. May sleep. * @txq_disable: de-configure a Tx queue to send AMPDUs * Must be atomic * @txq_set_shared_mode: change Tx queue shared/unshared marking @@ -544,7 +546,7 @@ struct iwl_trans_ops { void (*reclaim)(struct iwl_trans *trans, int queue, int ssn, struct sk_buff_head *skbs); - void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, + bool (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int queue_wdg_timeout); void (*txq_disable)(struct iwl_trans *trans, int queue, @@ -952,7 +954,7 @@ static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, trans->ops->txq_disable(trans, queue, configure_scd); } -static inline void +static inline bool iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int queue_wdg_timeout) @@ -961,10 +963,11 @@ iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return; + return false; } - trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout); + return trans->ops->txq_enable(trans, queue, ssn, + cfg, queue_wdg_timeout); } static inline void diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index e616472afd45..7171928872de 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1744,7 +1744,7 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) } /* hw scheduler queue config */ -void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, +bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout); int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 0249300c4600..aa41ee8ed916 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -758,7 +758,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, bool using_inactive_queue = false, same_sta = false; unsigned long disable_agg_tids = 0; enum iwl_mvm_agg_state queue_state; - bool shared_queue = false; + bool shared_queue = false, inc_ssn; int ssn; unsigned long tfd_queue_mask; int ret; @@ -885,8 +885,12 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, } ssn = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - iwl_mvm_enable_txq(mvm, queue, mac_queue, ssn, &cfg, - wdg_timeout); + inc_ssn = iwl_mvm_enable_txq(mvm, queue, mac_queue, + ssn, &cfg, wdg_timeout); + if (inc_ssn) { + ssn = (ssn + 1) & IEEE80211_SCTL_SEQ; + le16_add_cpu(&hdr->seq_ctrl, 0x10); + } /* * Mark queue as shared in transport if shared @@ -898,6 +902,13 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, iwl_trans_txq_set_shared_mode(mvm->trans, queue, true); spin_lock_bh(&mvmsta->lock); + /* + * This looks racy, but it is not. We have only one packet for + * this ra/tid in our Tx path since we stop the Qdisc when we + * need to allocate a new TFD queue. + */ + if (inc_ssn) + mvmsta->tid_data[tid].seq_number += 0x10; mvmsta->tid_data[tid].txq_id = queue; mvmsta->tid_data[tid].is_tid_active = true; mvmsta->tfd_queue_msk |= BIT(queue); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 8ba8b71dd1a4..0093e78dd571 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -757,35 +757,39 @@ int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, return queue; } -void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, +bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout) { + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .action = SCD_CFG_ENABLE_QUEUE, + .window = cfg->frame_limit, + .sta_id = cfg->sta_id, + .ssn = cpu_to_le16(ssn), + .tx_fifo = cfg->fifo, + .aggregate = cfg->aggregate, + .tid = cfg->tid, + }; + bool inc_ssn; + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) - return; + return false; /* Send the enabling command if we need to */ - if (iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, - cfg->sta_id, cfg->tid)) { - struct iwl_scd_txq_cfg_cmd cmd = { - .scd_queue = queue, - .action = SCD_CFG_ENABLE_QUEUE, - .window = cfg->frame_limit, - .sta_id = cfg->sta_id, - .ssn = cpu_to_le16(ssn), - .tx_fifo = cfg->fifo, - .aggregate = cfg->aggregate, - .tid = cfg->tid, - }; - - iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, - wdg_timeout); - WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, - sizeof(struct iwl_scd_txq_cfg_cmd), - &cmd), - "Failed to configure queue %d on FIFO %d\n", queue, - cfg->fifo); - } + if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, + cfg->sta_id, cfg->tid)) + return false; + + inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, + NULL, wdg_timeout); + if (inc_ssn) + le16_add_cpu(&cmd.ssn, 1); + + WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), + "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); + + return inc_ssn; } int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 644c0e583f32..4295b8409720 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -516,7 +516,7 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans); void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); int iwl_pcie_tx_stop(struct iwl_trans *trans); void iwl_pcie_tx_free(struct iwl_trans *trans); -void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, +bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout); void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 6b19ccc0ae41..9087b1fccaee 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1277,13 +1277,14 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) -void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, +bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = trans_pcie->txq[txq_id]; int fifo = -1; + bool scd_bug = false; if (test_and_set_bit(txq_id, trans_pcie->queue_used)) WARN_ONCE(1, "queue %d already used - expect issues", txq_id); @@ -1324,6 +1325,23 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, ssn = txq->read_ptr; } + } else { + /* + * If we need to move the SCD write pointer by steps of + * 0x40, 0x80 or 0xc0, it gets stuck. Avoids this and let + * the op_mode know by returning true later. + * Do this only in case cfg is NULL since this trick can + * be done only if we have DQA enabled which is true for mvm + * only. And mvm never sets a cfg pointer. + * This is really ugly, but this is the easiest way out for + * this sad hardware issue. + * This bug has been fixed on devices 9000 and up. + */ + scd_bug = !trans->cfg->mq_rx_supported && + !((ssn - txq->write_ptr) & 0x3f) && + (ssn != txq->write_ptr); + if (scd_bug) + ssn++; } /* Place first TFD at index corresponding to start sequence number. @@ -1367,6 +1385,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, "Activate queue %d WrPtr: %d\n", txq_id, ssn & 0xff); } + + return scd_bug; } void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id, -- cgit v1.2.3 From e8c8935efd7d47e8ae18067a898ee1a93dfbc5fc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 5 May 2017 17:24:06 +0200 Subject: iwlwifi: pcie: make iwl_pcie_apm_stop_master() return void Nothing ever checks the return value of iwl_pcie_apm_stop_master(), so there's no point in it having one - make it return void. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 4295b8409720..1f4bc933f0f2 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -779,7 +779,7 @@ void iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans, bool was_in_rfkill); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); int iwl_queue_space(const struct iwl_txq *q); -int iwl_pcie_apm_stop_master(struct iwl_trans *trans); +void iwl_pcie_apm_stop_master(struct iwl_trans *trans); void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie); int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num, bool cmd_queue); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 67343b10b0da..106e822308c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -448,9 +448,9 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) ~SHR_APMG_XTAL_CFG_XTAL_ON_REQ); } -int iwl_pcie_apm_stop_master(struct iwl_trans *trans) +void iwl_pcie_apm_stop_master(struct iwl_trans *trans) { - int ret = 0; + int ret; /* stop device's busmaster DMA activity */ iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); @@ -462,8 +462,6 @@ int iwl_pcie_apm_stop_master(struct iwl_trans *trans) IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); IWL_DEBUG_INFO(trans, "stop master\n"); - - return ret; } static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) -- cgit v1.2.3 From b56697272564ce9d073ad9159d28d123f3dcae8b Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Tue, 9 May 2017 16:40:01 +0300 Subject: iwlwifi: mvm: set assoc_beacon_arrive_time When updating the mac context after association, assoc_beacon_arrive_time is not being set, which causes the FW to set a wrong TSF to the MAC. Fix this by setting the assoc_beacon_arrive_time when updating the mac context after association. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 50a71da2e96e..f06751598fb8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -846,6 +846,8 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, cpu_to_le64(vif->bss_conf.sync_tsf + dtim_offs); ctxt_sta->dtim_time = cpu_to_le32(vif->bss_conf.sync_device_ts + dtim_offs); + ctxt_sta->assoc_beacon_arrive_time = + cpu_to_le32(vif->bss_conf.sync_device_ts); IWL_DEBUG_INFO(mvm, "DTIM TBTT is 0x%llx/0x%x, offset %d\n", le64_to_cpu(ctxt_sta->dtim_tsf), -- cgit v1.2.3 From a509a248bb31ea013c4c2b6801297a2d82eecd43 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 10 May 2017 08:49:41 +0300 Subject: iwlwifi: mvm: reset the fw_dump_desc pointer after ASSERT When we get an ASSERT, the fw_dump_desc pointer points to iwl_mvm_dump_desc_assert which can't be freed since it is a global. We still need to NULL'ify the pointer when we call iwl_mvm_free_fw_dump_desc otherwise we will hit int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, const struct iwl_mvm_dump_desc *desc, const struct iwl_fw_dbg_trigger_tlv *trigger) { if (WARN_ON(mvm->fw_dump_desc)) iwl_mvm_free_fw_dump_desc(mvm); Fixes: b6eaa45aa18b ("iwlwifi: mvm: add the cause of the firmware dump in the dump") Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index d5cb47e2fe44..1602b360353c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -319,10 +319,8 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm) { - if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert) - return; - - kfree(mvm->fw_dump_desc); + if (mvm->fw_dump_desc != &iwl_mvm_dump_desc_assert) + kfree(mvm->fw_dump_desc); mvm->fw_dump_desc = NULL; } -- cgit v1.2.3 From d167e81ad452c317271078076a5999c820d28016 Mon Sep 17 00:00:00 2001 From: Mordechai Goodstein Date: Wed, 10 May 2017 16:42:53 +0300 Subject: iwlwifi: mvm: support new flush API This new API allows flushing queues based on station ID and TID in A000 devices. One reason for using this is that tfd_queue_mask is only good for 32 queues, which is not enough for A000 devices. Signed-off-by: Sara Sharon Signed-off-by: Mordechai Goodstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 19 ++++++-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 14 +++++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 12 +++-- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 51 ++++++++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 44 ++++++++++++++----- 6 files changed, 100 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 744dc069ff23..c2a1aeef74ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -119,19 +119,30 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { int ret; - u32 scd_q_msk; + u32 flush_arg; if (!iwl_mvm_firmware_running(mvm) || mvm->cur_ucode != IWL_UCODE_REGULAR) return -EIO; - if (sscanf(buf, "%x", &scd_q_msk) != 1) + if (kstrtou32(buf, 0, &flush_arg)) return -EINVAL; - IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk); + if (iwl_mvm_has_new_tx_api(mvm)) { + IWL_DEBUG_TX_QUEUES(mvm, + "FLUSHING all tids queues on sta_id = %d\n", + flush_arg); + mutex_lock(&mvm->mutex); + ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFF, 0) ? : count; + mutex_unlock(&mvm->mutex); + return ret; + } + + IWL_DEBUG_TX_QUEUES(mvm, "FLUSHING queues mask to flush = 0x%x\n", + flush_arg); mutex_lock(&mvm->mutex); - ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, 0) ? : count; + ret = iwl_mvm_flush_tx_path(mvm, flush_arg, 0) ? : count; mutex_unlock(&mvm->mutex); return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 0562ce406249..a37c584b0b48 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -846,12 +846,24 @@ enum iwl_dump_control { * @flush_ctl: control flags * @reserved: reserved */ -struct iwl_tx_path_flush_cmd { +struct iwl_tx_path_flush_cmd_v1 { __le32 queues_ctl; __le16 flush_ctl; __le16 reserved; } __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_1 */ +/** + * struct iwl_tx_path_flush_cmd -- queue/FIFO flush command + * @sta_id: station ID to flush + * @tid_mask: TID mask to flush + * @reserved: reserved + */ +struct iwl_tx_path_flush_cmd { + __le32 sta_id; + __le16 tid_mask; + __le16 reserved; +} __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_2 */ + /* Available options for the SCD_QUEUE_CFG HCMD */ enum iwl_scd_cfg_actions { SCD_CFG_DISABLE_QUEUE = 0x0, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 7171928872de..3b1f15873034 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1385,6 +1385,8 @@ static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; } #endif int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags); int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags); +int iwl_mvm_flush_sta_tids(struct iwl_mvm *mvm, u32 sta_id, + u16 tids, u32 flags); void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index fc2c607013fb..2e4bfe9f07ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1477,9 +1477,15 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) synchronize_net(); /* Flush the hw queues, in case something got queued during entry */ - ret = iwl_mvm_flush_tx_path(mvm, iwl_mvm_flushable_queues(mvm), flags); - if (ret) - return ret; + /* TODO new tx api */ + if (iwl_mvm_has_new_tx_api(mvm)) { + WARN_ONCE(1, "d0i3: Need to implement flush TX queue\n"); + } else { + ret = iwl_mvm_flush_tx_path(mvm, iwl_mvm_flushable_queues(mvm), + flags); + if (ret) + return ret; + } /* configure wowlan configuration only if needed */ if (mvm->d0i3_ap_sta_id != IWL_MVM_INVALID_STA) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index aa41ee8ed916..02f35a929606 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -734,7 +734,6 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm, spin_lock_bh(&mvmsta->lock); mvmsta->tid_data[tid].txq_id = queue; mvmsta->tid_data[tid].is_tid_active = true; - mvmsta->tfd_queue_msk |= BIT(queue); spin_unlock_bh(&mvmsta->lock); return 0; @@ -2004,8 +2003,6 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvm->probe_queue = queue; else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) mvm->p2p_dev_queue = queue; - - bsta->tfd_queue_msk |= BIT(queue); } return 0; @@ -2015,29 +2012,32 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int queue; lockdep_assert_held(&mvm->mutex); iwl_mvm_flush_sta(mvm, &mvmvif->bcast_sta, true, 0); - if (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_ADHOC) - iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue, - IWL_MAX_TID_COUNT, 0); - - if (mvmvif->bcast_sta.tfd_queue_msk & BIT(mvm->probe_queue)) { - iwl_mvm_disable_txq(mvm, mvm->probe_queue, - vif->hw_queue[0], IWL_MAX_TID_COUNT, - 0); - mvmvif->bcast_sta.tfd_queue_msk &= ~BIT(mvm->probe_queue); + switch (vif->type) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + queue = mvm->probe_queue; + break; + case NL80211_IFTYPE_P2P_DEVICE: + queue = mvm->p2p_dev_queue; + break; + default: + WARN(1, "Can't free bcast queue on vif type %d\n", + vif->type); + return; } - if (mvmvif->bcast_sta.tfd_queue_msk & BIT(mvm->p2p_dev_queue)) { - iwl_mvm_disable_txq(mvm, mvm->p2p_dev_queue, - vif->hw_queue[0], IWL_MAX_TID_COUNT, - 0); - mvmvif->bcast_sta.tfd_queue_msk &= ~BIT(mvm->p2p_dev_queue); - } + iwl_mvm_disable_txq(mvm, queue, vif->hw_queue[0], IWL_MAX_TID_COUNT, 0); + if (iwl_mvm_has_new_tx_api(mvm)) + return; + + WARN_ON(!(mvmvif->bcast_sta.tfd_queue_msk & BIT(queue))); + mvmvif->bcast_sta.tfd_queue_msk &= ~BIT(queue); } /* Send the FW a request to remove the station from it's internal data @@ -2913,14 +2913,17 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (old_state >= IWL_AGG_ON) { iwl_mvm_drain_sta(mvm, mvmsta, true); - if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), 0)) - IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); - if (iwl_mvm_has_new_tx_api(mvm)) + if (iwl_mvm_has_new_tx_api(mvm)) { + if (iwl_mvm_flush_sta_tids(mvm, mvmsta->sta_id, + BIT(tid), 0)) + IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); iwl_trans_wait_txq_empty(mvm->trans, txq_id); - - else + } else { + if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), 0)) + IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(txq_id)); + } iwl_mvm_drain_sta(mvm, mvmsta, false); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 02f293b711fd..157a75394763 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1902,11 +1902,13 @@ out: int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags) { int ret; - struct iwl_tx_path_flush_cmd flush_cmd = { + struct iwl_tx_path_flush_cmd_v1 flush_cmd = { .queues_ctl = cpu_to_le32(tfd_msk), .flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH), }; + WARN_ON(iwl_mvm_has_new_tx_api(mvm)); + ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags, sizeof(flush_cmd), &flush_cmd); if (ret) @@ -1914,19 +1916,41 @@ int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags) return ret; } -int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags) +int iwl_mvm_flush_sta_tids(struct iwl_mvm *mvm, u32 sta_id, + u16 tids, u32 flags) { - u32 mask; + int ret; + struct iwl_tx_path_flush_cmd flush_cmd = { + .sta_id = cpu_to_le32(sta_id), + .tid_mask = cpu_to_le16(tids), + }; - if (internal) { - struct iwl_mvm_int_sta *int_sta = sta; + WARN_ON(!iwl_mvm_has_new_tx_api(mvm)); - mask = int_sta->tfd_queue_msk; - } else { - struct iwl_mvm_sta *mvm_sta = sta; + ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags, + sizeof(flush_cmd), &flush_cmd); + if (ret) + IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret); + return ret; +} - mask = mvm_sta->tfd_queue_msk; +int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags) +{ + struct iwl_mvm_int_sta *int_sta = sta; + struct iwl_mvm_sta *mvm_sta = sta; + + if (iwl_mvm_has_new_tx_api(mvm)) { + if (internal) + return iwl_mvm_flush_sta_tids(mvm, int_sta->sta_id, + BIT(IWL_MGMT_TID), flags); + + return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id, + 0xFF, flags); } - return iwl_mvm_flush_tx_path(mvm, mask, flags); + if (internal) + return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk, + flags); + + return iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, flags); } -- cgit v1.2.3 From a8d011446b4c62f5438b2a9724333c1efedfb26b Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 10 May 2017 11:24:58 +0300 Subject: iwlwifi: mvm: document assoc_beacon_arrive_time Document the assoc_beacon_arrive_time element in the iwl_mac_data_sta struct. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h index aa5aaf7c940d..1d970bf0d735 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h @@ -199,6 +199,7 @@ struct iwl_mac_data_ibss { * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated * @listen_interval: in beacon intervals, applicable only when associated * @assoc_id: unique ID assigned by the AP during association + * @assoc_beacon_arrive_time: TSF of first beacon after association */ struct iwl_mac_data_sta { __le32 is_assoc; -- cgit v1.2.3 From 4409e72b7113c891e4e28d432d4b459c02e88efb Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 9 May 2017 22:46:19 +0300 Subject: iwlwifi: mvm: print base HW address during init It's sometimes hard to find out which HW address the iwlwifi device is using, for instance when reading crouded sniffer logs. To make it easier, print out an info level message with the HW address as soon as we know it. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 070f3dfb94ce..5c08f4d40f6a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -640,6 +640,8 @@ static int iwl_set_hw_address(struct iwl_trans *trans, return -EINVAL; } + IWL_INFO(trans, "base HW address: %pM\n", data->hw_addr); + return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index efdcffbaac6f..dac7e542a190 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -599,6 +599,8 @@ int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm) goto err_free; } + IWL_INFO(trans, "base HW address: %pM\n", mvm->nvm_data->hw_addr); + /* Initialize general data */ mvm->nvm_data->nvm_version = le16_to_cpu(rsp->general.nvm_version); -- cgit v1.2.3 From d74a61fc6bed9698b10427a2424556f1cefb6135 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 9 May 2017 23:47:18 +0300 Subject: iwlwifi: pcie: reduce unwanted noise in the logs The driver prints "L1 Enabled - LTR Enabled" all the time as dev_info, which is just useless noise in most cases. Convert this to IWL_DEBUG_POWER() so we don't pollute the log unnecessarily but still can get this info on demand. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 106e822308c7..233b6734c237 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -224,9 +224,9 @@ void iwl_pcie_apm_config(struct iwl_trans *trans) pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap); trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN; - dev_info(trans->dev, "L1 %sabled - LTR %sabled\n", - (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis", - trans->ltr_enabled ? "En" : "Dis"); + IWL_DEBUG_POWER(trans, "L1 %sabled - LTR %sabled\n", + (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis", + trans->ltr_enabled ? "En" : "Dis"); } /* -- cgit v1.2.3 From 7d75f32e09c80da8e7ac383e07fb2bbdd8df4d56 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 10 May 2017 13:03:01 +0300 Subject: iwlwifi: pcie: delete the Tx queue timer earlier upon firmware crash When the firmware crashes, the transmit queues can't make any progress. This is why we stop the counter that monitor the transmit queues' activity. The call that notifies the error to the op_mode may take a bit of time, so stop the timer of the transmit queues earlier. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index fa5f39f72d22..a5c0f69423d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1413,16 +1413,16 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) return; } - /* The STATUS_FW_ERROR bit is set in this function. This must happen - * before we wake up the command caller, to ensure a proper cleanup. */ - iwl_trans_fw_error(trans); - for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { if (!trans_pcie->txq[i]) continue; del_timer(&trans_pcie->txq[i]->stuck_timer); } + /* The STATUS_FW_ERROR bit is set in this function. This must happen + * before we wake up the command caller, to ensure a proper cleanup. */ + iwl_trans_fw_error(trans); + clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); wake_up(&trans_pcie->wait_command_queue); } -- cgit v1.2.3 From 3b9449bb1df756cd16bfe50616392fb7caa1211d Mon Sep 17 00:00:00 2001 From: Chaya Rachel Ivgi Date: Mon, 8 May 2017 15:14:01 +0300 Subject: iwlwifi: mvm: fix typo in CTDP_CMD_OPERATION_REPORT description Signed-off-by: Chaya Rachel Ivgi Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 224d10b1b076..b84e8ddbbbc9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -2130,7 +2130,7 @@ struct ct_kill_notif { * enum ctdp_cmd_operation - CTDP command operations * @CTDP_CMD_OPERATION_START: update the current budget * @CTDP_CMD_OPERATION_STOP: stop ctdp -* @CTDP_CMD_OPERATION_REPORT: get the avgerage budget +* @CTDP_CMD_OPERATION_REPORT: get the average budget */ enum iwl_mvm_ctdp_cmd_operation { CTDP_CMD_OPERATION_START = 0x1, -- cgit v1.2.3 From c00ee467b3bf73c9505b1ea308a263ae3c5aab5d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 May 2017 15:35:06 +0200 Subject: iwlwifi: pcie: work around suspend/resume issue In some platforms, having the device enabled with certain radio frontends causes the platform to not be able to resume properly from suspend, regardless of the wakeup cause. This was traced to a hardware issue with the integrated 9000-series A-step variant. Set the right hardware bit to disable the problematic state. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 4 ++++ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 11 +++++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 36fb20168598..e239b1d92cf9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -153,6 +153,10 @@ /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +/* host chicken bits */ +#define CSR_HOST_CHICKEN (CSR_BASE + 0x204) +#define CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME BIT(19) + /* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 233b6734c237..5778ba2278d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3134,6 +3134,17 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } } + /* + * 9000-series integrated A-step has a problem with suspend/resume + * and sometimes even causes the whole platform to get stuck. This + * workaround makes the hardware not go into the problematic state. + */ + if (trans->cfg->integrated && + trans->cfg->device_family == IWL_DEVICE_FAMILY_9000 && + CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP) + iwl_set_bit(trans, CSR_HOST_CHICKEN, + CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME); + trans->hw_rf_id = iwl_read32(trans, CSR_HW_RF_ID); iwl_pcie_set_interrupt_capa(pdev, trans); -- cgit v1.2.3 From 6d759b02f4121595bf4212662e73c26573dab61a Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Mon, 15 May 2017 18:26:33 +0300 Subject: iwlwifi: mvm: support TX on MONITOR iface When trying to TX through a monitor interface, the conditions in iwl_mvm_tx_skb_non_sta() don't match and the frame tries to go out from an usued TXQ. Add a check for monitor iface, and use the AUX queue in such a case. In non-DQA mode the frame is sent through the static-allocated queues anyway, so the problem is in DQA mode only. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 157a75394763..c89bb453c496 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -651,6 +651,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) info.control.vif->type == NL80211_IFTYPE_STATION && queue != mvm->aux_queue) { queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE; + } else if (iwl_mvm_is_dqa_supported(mvm) && + info.control.vif->type == NL80211_IFTYPE_MONITOR) { + queue = mvm->aux_queue; } } -- cgit v1.2.3 From c443b5accedaef8e1d6faf7a1bb921670a90a3d0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:05 -0700 Subject: nfp: xdp: move driver XDP setup into a separate function In preparation of XDP offload flags move the driver setup into a function. Otherwise the number of conditions in one function would make it slightly hard to follow. The offload handler may now be called with NULL prog, even if no offload is currently active, but that's fine, offload code can handle that. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 2bdddd1ae666..f2188b9c3628 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3274,10 +3274,11 @@ static void nfp_net_del_vxlan_port(struct net_device *netdev, nfp_net_set_vxlan_port(nn, idx, 0); } -static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) +static int +nfp_net_xdp_setup_drv(struct nfp_net *nn, struct bpf_prog *prog, + struct netlink_ext_ack *extack) { struct bpf_prog *old_prog = nn->dp.xdp_prog; - struct bpf_prog *prog = xdp->prog; struct nfp_net_dp *dp; int err; @@ -3286,7 +3287,6 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) if (prog && nn->dp.xdp_prog) { prog = xchg(&nn->dp.xdp_prog, prog); bpf_prog_put(prog); - nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); return 0; } @@ -3300,13 +3300,26 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) dp->rx_dma_off = prog ? XDP_PACKET_HEADROOM - nn->dp.rx_offset : 0; /* We need RX reconfig to remap the buffers (BIDIR vs FROM_DEV) */ - err = nfp_net_ring_reconfig(nn, dp, xdp->extack); + err = nfp_net_ring_reconfig(nn, dp, extack); if (err) return err; if (old_prog) bpf_prog_put(old_prog); + return 0; +} + +static int +nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, + struct netlink_ext_ack *extack) +{ + int err; + + err = nfp_net_xdp_setup_drv(nn, prog, extack); + if (err) + return err; + nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); return 0; @@ -3318,7 +3331,7 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) switch (xdp->command) { case XDP_SETUP_PROG: - return nfp_net_xdp_setup(nn, xdp); + return nfp_net_xdp_setup(nn, xdp->prog, xdp->extack); case XDP_QUERY_PROG: xdp->prog_attached = !!nn->dp.xdp_prog; xdp->prog_id = nn->dp.xdp_prog ? nn->dp.xdp_prog->aux->id : 0; -- cgit v1.2.3 From 9f82fca9422eab3877ab2b697ccc5eef44c63b54 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:06 -0700 Subject: nfp: bpf: don't offload XDP programs in DRV_MODE DRV_MODE means that user space wants the program to be run in the driver. Do not try to offload. Only offload if no mode flags have been specified. Remember what the mode is when the program is installed and refuse new setup requests if there is already a program loaded in a different mode. This should leave it open for us to implement simultaneous loading of two programs - one in the drv path and another to the NIC later. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 3 +++ drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 02fd8d4e253c..7952fbfb94d6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -541,6 +541,7 @@ struct nfp_net_dp { * @rss_cfg: RSS configuration * @rss_key: RSS secret key * @rss_itbl: RSS indirection table + * @xdp_flags: Flags with which XDP prog was loaded * @max_r_vecs: Number of allocated interrupt vectors for RX/TX * @max_tx_rings: Maximum number of TX rings supported by the Firmware * @max_rx_rings: Maximum number of RX rings supported by the Firmware @@ -590,6 +591,8 @@ struct nfp_net { u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ]; u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ]; + u32 xdp_flags; + unsigned int max_tx_rings; unsigned int max_rx_rings; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index f2188b9c3628..9563615cf4b7 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3311,16 +3311,23 @@ nfp_net_xdp_setup_drv(struct nfp_net *nn, struct bpf_prog *prog, } static int -nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, +nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags, struct netlink_ext_ack *extack) { + struct bpf_prog *offload_prog; int err; + if (nn->dp.xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES) + return -EBUSY; + + offload_prog = flags & XDP_FLAGS_DRV_MODE ? NULL : prog; + err = nfp_net_xdp_setup_drv(nn, prog, extack); if (err) return err; - nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); + nfp_app_xdp_offload(nn->app, nn, offload_prog); + nn->xdp_flags = flags; return 0; } @@ -3331,7 +3338,8 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) switch (xdp->command) { case XDP_SETUP_PROG: - return nfp_net_xdp_setup(nn, xdp->prog, xdp->extack); + return nfp_net_xdp_setup(nn, xdp->prog, xdp->flags, + xdp->extack); case XDP_QUERY_PROG: xdp->prog_attached = !!nn->dp.xdp_prog; xdp->prog_id = nn->dp.xdp_prog ? nn->dp.xdp_prog->aux->id : 0; -- cgit v1.2.3 From 6a8ef5428c9fb5b589c2c912889d157abb50dd61 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:07 -0700 Subject: nfp: bpf: release the reference on offloaded programs The xdp_prog member of the adapter's data path structure is used for XDP in driver mode. In case a XDP program is loaded with in HW-only mode, we need to store it somewhere else. Add a new XDP prog pointer in the main structure and use that when we need to know whether any XDP program is loaded, not only a driver mode one. Only release our reference on adapter free instead of immediately after netdev unregister to allow offload to be disabled first. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 2 ++ .../net/ethernet/netronome/nfp/nfp_net_common.c | 34 +++++++++------------- 2 files changed, 15 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 7952fbfb94d6..b7446793106d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -542,6 +542,7 @@ struct nfp_net_dp { * @rss_key: RSS secret key * @rss_itbl: RSS indirection table * @xdp_flags: Flags with which XDP prog was loaded + * @xdp_prog: XDP prog (for ctrl path, both DRV and HW modes) * @max_r_vecs: Number of allocated interrupt vectors for RX/TX * @max_tx_rings: Maximum number of TX rings supported by the Firmware * @max_rx_rings: Maximum number of RX rings supported by the Firmware @@ -592,6 +593,7 @@ struct nfp_net { u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ]; u32 xdp_flags; + struct bpf_prog *xdp_prog; unsigned int max_tx_rings; unsigned int max_rx_rings; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 9563615cf4b7..35b4530a7e02 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3278,15 +3278,10 @@ static int nfp_net_xdp_setup_drv(struct nfp_net *nn, struct bpf_prog *prog, struct netlink_ext_ack *extack) { - struct bpf_prog *old_prog = nn->dp.xdp_prog; struct nfp_net_dp *dp; - int err; - if (!prog && !nn->dp.xdp_prog) - return 0; - if (prog && nn->dp.xdp_prog) { - prog = xchg(&nn->dp.xdp_prog, prog); - bpf_prog_put(prog); + if (!prog == !nn->dp.xdp_prog) { + WRITE_ONCE(nn->dp.xdp_prog, prog); return 0; } @@ -3300,14 +3295,7 @@ nfp_net_xdp_setup_drv(struct nfp_net *nn, struct bpf_prog *prog, dp->rx_dma_off = prog ? XDP_PACKET_HEADROOM - nn->dp.rx_offset : 0; /* We need RX reconfig to remap the buffers (BIDIR vs FROM_DEV) */ - err = nfp_net_ring_reconfig(nn, dp, extack); - if (err) - return err; - - if (old_prog) - bpf_prog_put(old_prog); - - return 0; + return nfp_net_ring_reconfig(nn, dp, extack); } static int @@ -3317,7 +3305,7 @@ nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags, struct bpf_prog *offload_prog; int err; - if (nn->dp.xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES) + if (nn->xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES) return -EBUSY; offload_prog = flags & XDP_FLAGS_DRV_MODE ? NULL : prog; @@ -3327,6 +3315,10 @@ nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags, return err; nfp_app_xdp_offload(nn->app, nn, offload_prog); + + if (nn->xdp_prog) + bpf_prog_put(nn->xdp_prog); + nn->xdp_prog = prog; nn->xdp_flags = flags; return 0; @@ -3341,8 +3333,8 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) return nfp_net_xdp_setup(nn, xdp->prog, xdp->flags, xdp->extack); case XDP_QUERY_PROG: - xdp->prog_attached = !!nn->dp.xdp_prog; - xdp->prog_id = nn->dp.xdp_prog ? nn->dp.xdp_prog->aux->id : 0; + xdp->prog_attached = !!nn->xdp_prog; + xdp->prog_id = nn->xdp_prog ? nn->xdp_prog->aux->id : 0; return 0; default: return -EINVAL; @@ -3500,6 +3492,9 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, bool needs_netdev, */ void nfp_net_free(struct nfp_net *nn) { + if (nn->xdp_prog) + bpf_prog_put(nn->xdp_prog); + if (nn->dp.netdev) free_netdev(nn->dp.netdev); else @@ -3757,7 +3752,4 @@ void nfp_net_clean(struct nfp_net *nn) return; unregister_netdev(nn->dp.netdev); - - if (nn->dp.xdp_prog) - bpf_prog_put(nn->dp.xdp_prog); } -- cgit v1.2.3 From cafa92ac255337517ca2466ab05ca9f24c0ca9de Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:08 -0700 Subject: nfp: bpf: add support for XDP_FLAGS_HW_MODE Respect the XDP_FLAGS_HW_MODE. When it's set install the program on the NIC and skip enabling XDP in the driver. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 35b4530a7e02..c9fc1df1823e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3302,19 +3302,25 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags, struct netlink_ext_ack *extack) { - struct bpf_prog *offload_prog; + struct bpf_prog *drv_prog, *offload_prog; int err; if (nn->xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES) return -EBUSY; + /* Load both when no flags set to allow easy activation of driver path + * when program is replaced by one which can't be offloaded. + */ + drv_prog = flags & XDP_FLAGS_HW_MODE ? NULL : prog; offload_prog = flags & XDP_FLAGS_DRV_MODE ? NULL : prog; - err = nfp_net_xdp_setup_drv(nn, prog, extack); + err = nfp_net_xdp_setup_drv(nn, drv_prog, extack); if (err) return err; - nfp_app_xdp_offload(nn->app, nn, offload_prog); + err = nfp_app_xdp_offload(nn->app, nn, offload_prog); + if (err && flags & XDP_FLAGS_HW_MODE) + return err; if (nn->xdp_prog) bpf_prog_put(nn->xdp_prog); @@ -3330,6 +3336,7 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) switch (xdp->command) { case XDP_SETUP_PROG: + case XDP_SETUP_PROG_HW: return nfp_net_xdp_setup(nn, xdp->prog, xdp->flags, xdp->extack); case XDP_QUERY_PROG: -- cgit v1.2.3 From 149d7a572ae124385973bf1c8e4d80b3f07d8bd4 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:10 -0700 Subject: nfp: xdp: report if program is offloaded Make use of just added XDP_ATTACHED_HW. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index c9fc1df1823e..2134493ec8a8 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3341,6 +3341,8 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) xdp->extack); case XDP_QUERY_PROG: xdp->prog_attached = !!nn->xdp_prog; + if (nn->dp.bpf_offload_xdp) + xdp->prog_attached = XDP_ATTACHED_HW; xdp->prog_id = nn->xdp_prog ? nn->xdp_prog->aux->id : 0; return 0; default: -- cgit v1.2.3 From 72de46556f8a291b2c72ea1fa22275ffef85e4f9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 22 Jun 2017 17:17:29 +0100 Subject: net: stmmac: make some functions static The functions dwmac4_dma_init_rx_chan, dwmac4_dma_init_tx_chan and dwmac4_dma_init_channel do not need to be in global scope, so them static. Cleans up sparse warnings: "symbol 'dwmac4_dma_init_rx_chan' was not declared. Should it be static?" "symbol 'dwmac4_dma_init_tx_chan' was not declared. Should it be static?" "symbol 'dwmac4_dma_init_channel' was not declared. Should it be static?" Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index eec8463057fd..e84831e1b63b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -71,9 +71,9 @@ static void dwmac4_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) writel(value, ioaddr + DMA_SYS_BUS_MODE); } -void dwmac4_dma_init_rx_chan(void __iomem *ioaddr, - struct stmmac_dma_cfg *dma_cfg, - u32 dma_rx_phy, u32 chan) +static void dwmac4_dma_init_rx_chan(void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, + u32 dma_rx_phy, u32 chan) { u32 value; u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl; @@ -85,9 +85,9 @@ void dwmac4_dma_init_rx_chan(void __iomem *ioaddr, writel(dma_rx_phy, ioaddr + DMA_CHAN_RX_BASE_ADDR(chan)); } -void dwmac4_dma_init_tx_chan(void __iomem *ioaddr, - struct stmmac_dma_cfg *dma_cfg, - u32 dma_tx_phy, u32 chan) +static void dwmac4_dma_init_tx_chan(void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, + u32 dma_tx_phy, u32 chan) { u32 value; u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl; @@ -99,8 +99,8 @@ void dwmac4_dma_init_tx_chan(void __iomem *ioaddr, writel(dma_tx_phy, ioaddr + DMA_CHAN_TX_BASE_ADDR(chan)); } -void dwmac4_dma_init_channel(void __iomem *ioaddr, - struct stmmac_dma_cfg *dma_cfg, u32 chan) +static void dwmac4_dma_init_channel(void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, u32 chan) { u32 value; -- cgit v1.2.3 From d1497638b6fedccaef875a5d9f09b3fe4ffbd22d Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:50 +0300 Subject: net: ena: change return value for unsupported features unsupported return value return -EOPNOTSUPP instead of -EPERM. Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_com.c | 22 +++++++++++----------- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 10 +++------- drivers/net/ethernet/amazon/ena/ena_netdev.c | 20 ++++++++++---------- 3 files changed, 24 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index f5b237e0bd60..02752d5b5b60 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -494,7 +494,7 @@ static int ena_com_comp_status_to_errno(u8 comp_status) case ENA_ADMIN_RESOURCE_ALLOCATION_FAILURE: return -ENOMEM; case ENA_ADMIN_UNSUPPORTED_OPCODE: - return -EPERM; + return -EOPNOTSUPP; case ENA_ADMIN_BAD_OPCODE: case ENA_ADMIN_MALFORMED_REQUEST: case ENA_ADMIN_ILLEGAL_PARAMETER: @@ -786,7 +786,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev, if (!ena_com_check_supported_feature_id(ena_dev, feature_id)) { pr_debug("Feature %d isn't supported\n", feature_id); - return -EPERM; + return -EOPNOTSUPP; } memset(&get_cmd, 0x0, sizeof(get_cmd)); @@ -1324,7 +1324,7 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag) if ((get_resp.u.aenq.supported_groups & groups_flag) != groups_flag) { pr_warn("Trying to set unsupported aenq events. supported flag: %x asked flag: %x\n", get_resp.u.aenq.supported_groups, groups_flag); - return -EPERM; + return -EOPNOTSUPP; } memset(&cmd, 0x0, sizeof(cmd)); @@ -1909,7 +1909,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, int mtu) if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_MTU)) { pr_debug("Feature %d isn't supported\n", ENA_ADMIN_MTU); - return -EPERM; + return -EOPNOTSUPP; } memset(&cmd, 0x0, sizeof(cmd)); @@ -1963,7 +1963,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) ENA_ADMIN_RSS_HASH_FUNCTION)) { pr_debug("Feature %d isn't supported\n", ENA_ADMIN_RSS_HASH_FUNCTION); - return -EPERM; + return -EOPNOTSUPP; } /* Validate hash function is supported */ @@ -1975,7 +1975,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) if (get_resp.u.flow_hash_func.supported_func & (1 << rss->hash_func)) { pr_err("Func hash %d isn't supported by device, abort\n", rss->hash_func); - return -EPERM; + return -EOPNOTSUPP; } memset(&cmd, 0x0, sizeof(cmd)); @@ -2034,7 +2034,7 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, if (!((1 << func) & get_resp.u.flow_hash_func.supported_func)) { pr_err("Flow hash function %d isn't supported\n", func); - return -EPERM; + return -EOPNOTSUPP; } switch (func) { @@ -2127,7 +2127,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev) ENA_ADMIN_RSS_HASH_INPUT)) { pr_debug("Feature %d isn't supported\n", ENA_ADMIN_RSS_HASH_INPUT); - return -EPERM; + return -EOPNOTSUPP; } memset(&cmd, 0x0, sizeof(cmd)); @@ -2208,7 +2208,7 @@ int ena_com_set_default_hash_ctrl(struct ena_com_dev *ena_dev) pr_err("hash control doesn't support all the desire configuration. proto %x supported %x selected %x\n", i, hash_ctrl->supported_fields[i].fields, hash_ctrl->selected_fields[i].fields); - return -EPERM; + return -EOPNOTSUPP; } } @@ -2286,7 +2286,7 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev) ena_dev, ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG)) { pr_debug("Feature %d isn't supported\n", ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG); - return -EPERM; + return -EOPNOTSUPP; } ret = ena_com_ind_tbl_convert_to_device(ena_dev); @@ -2553,7 +2553,7 @@ int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev) ENA_ADMIN_INTERRUPT_MODERATION); if (rc) { - if (rc == -EPERM) { + if (rc == -EOPNOTSUPP) { pr_debug("Feature %d isn't supported\n", ENA_ADMIN_INTERRUPT_MODERATION); rc = 0; diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 3ee55e2fd694..d51a67f4df02 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -539,12 +539,8 @@ static int ena_get_rss_hash(struct ena_com_dev *ena_dev, } rc = ena_com_get_hash_ctrl(ena_dev, proto, &hash_fields); - if (rc) { - /* If device don't have permission, return unsupported */ - if (rc == -EPERM) - rc = -EOPNOTSUPP; + if (rc) return rc; - } cmd->data = ena_flow_hash_to_flow_type(hash_fields); @@ -612,7 +608,7 @@ static int ena_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info) rc = -EOPNOTSUPP; } - return (rc == -EPERM) ? -EOPNOTSUPP : rc; + return rc; } static int ena_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info, @@ -638,7 +634,7 @@ static int ena_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info, rc = -EOPNOTSUPP; } - return (rc == -EPERM) ? -EOPNOTSUPP : rc; + return rc; } static u32 ena_get_rxfh_indir_size(struct net_device *netdev) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 4f16ed38bcf3..8d4f65ea985c 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1446,7 +1446,7 @@ static int ena_rss_configure(struct ena_adapter *adapter) /* In case the RSS table wasn't initialized by probe */ if (!ena_dev->rss.tbl_log_size) { rc = ena_rss_init_default(adapter); - if (rc && (rc != -EPERM)) { + if (rc && (rc != -EOPNOTSUPP)) { netif_err(adapter, ifup, adapter->netdev, "Failed to init RSS rc: %d\n", rc); return rc; @@ -1455,17 +1455,17 @@ static int ena_rss_configure(struct ena_adapter *adapter) /* Set indirect table */ rc = ena_com_indirect_table_set(ena_dev); - if (unlikely(rc && rc != -EPERM)) + if (unlikely(rc && rc != -EOPNOTSUPP)) return rc; /* Configure hash function (if supported) */ rc = ena_com_set_hash_function(ena_dev); - if (unlikely(rc && (rc != -EPERM))) + if (unlikely(rc && (rc != -EOPNOTSUPP))) return rc; /* Configure hash inputs (if supported) */ rc = ena_com_set_hash_ctrl(ena_dev); - if (unlikely(rc && (rc != -EPERM))) + if (unlikely(rc && (rc != -EOPNOTSUPP))) return rc; return 0; @@ -2144,7 +2144,7 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev) rc = ena_com_set_host_attributes(ena_dev); if (rc) { - if (rc == -EPERM) + if (rc == -EOPNOTSUPP) pr_warn("Cannot set host attributes\n"); else pr_err("Cannot set host attributes\n"); @@ -2181,7 +2181,7 @@ static void ena_config_debug_area(struct ena_adapter *adapter) rc = ena_com_set_host_attributes(adapter->ena_dev); if (rc) { - if (rc == -EPERM) + if (rc == -EOPNOTSUPP) netif_warn(adapter, drv, adapter->netdev, "Cannot set host attributes\n"); else @@ -2886,7 +2886,7 @@ static int ena_rss_init_default(struct ena_adapter *adapter) val = ethtool_rxfh_indir_default(i, adapter->num_queues); rc = ena_com_indirect_table_fill_entry(ena_dev, i, ENA_IO_RXQ_IDX(val)); - if (unlikely(rc && (rc != -EPERM))) { + if (unlikely(rc && (rc != -EOPNOTSUPP))) { dev_err(dev, "Cannot fill indirect table\n"); goto err_fill_indir; } @@ -2894,13 +2894,13 @@ static int ena_rss_init_default(struct ena_adapter *adapter) rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_CRC32, NULL, ENA_HASH_KEY_SIZE, 0xFFFFFFFF); - if (unlikely(rc && (rc != -EPERM))) { + if (unlikely(rc && (rc != -EOPNOTSUPP))) { dev_err(dev, "Cannot fill hash function\n"); goto err_fill_indir; } rc = ena_com_set_default_hash_ctrl(ena_dev); - if (unlikely(rc && (rc != -EPERM))) { + if (unlikely(rc && (rc != -EOPNOTSUPP))) { dev_err(dev, "Cannot fill hash control\n"); goto err_fill_indir; } @@ -3114,7 +3114,7 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_worker_destroy; } rc = ena_rss_init_default(adapter); - if (rc && (rc != -EPERM)) { + if (rc && (rc != -EOPNOTSUPP)) { dev_err(&pdev->dev, "Cannot init RSS rc: %d\n", rc); goto err_free_msix; } -- cgit v1.2.3 From 82ef30f13be0b4fea70a9c6215f7cff40bb3be63 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:51 +0300 Subject: net: ena: add hardware hints capability to the driver With this patch, ENA device can update the ena driver about the desired timeout values: These values are part of the "hardware hints" which are transmitted to the driver as Asynchronous event through ENA async event notification queue. In case the ENA device does not support this capability, the driver will use its own default values. Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_admin_defs.h | 31 +++++++++++ drivers/net/ethernet/amazon/ena/ena_com.c | 38 +++++++++++--- drivers/net/ethernet/amazon/ena/ena_com.h | 6 +++ drivers/net/ethernet/amazon/ena/ena_netdev.c | 66 ++++++++++++++++++++++-- drivers/net/ethernet/amazon/ena/ena_netdev.h | 5 ++ drivers/net/ethernet/amazon/ena/ena_regs_defs.h | 2 + 6 files changed, 137 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h index 5b6509d59716..305dc1996b4e 100644 --- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h @@ -70,6 +70,8 @@ enum ena_admin_aq_feature_id { ENA_ADMIN_MAX_QUEUES_NUM = 2, + ENA_ADMIN_HW_HINTS = 3, + ENA_ADMIN_RSS_HASH_FUNCTION = 10, ENA_ADMIN_STATELESS_OFFLOAD_CONFIG = 11, @@ -749,6 +751,31 @@ struct ena_admin_feature_rss_ind_table { struct ena_admin_rss_ind_table_entry inline_entry; }; +/* When hint value is 0, driver should use it's own predefined value */ +struct ena_admin_ena_hw_hints { + /* value in ms */ + u16 mmio_read_timeout; + + /* value in ms */ + u16 driver_watchdog_timeout; + + /* Per packet tx completion timeout. value in ms */ + u16 missing_tx_completion_timeout; + + u16 missed_tx_completion_count_threshold_to_reset; + + /* value in ms */ + u16 admin_completion_tx_timeout; + + u16 netdev_wd_timeout; + + u16 max_tx_sgl_size; + + u16 max_rx_sgl_size; + + u16 reserved[8]; +}; + struct ena_admin_get_feat_cmd { struct ena_admin_aq_common_desc aq_common_descriptor; @@ -782,6 +809,8 @@ struct ena_admin_get_feat_resp { struct ena_admin_feature_rss_ind_table ind_table; struct ena_admin_feature_intr_moder_desc intr_moderation; + + struct ena_admin_ena_hw_hints hw_hints; } u; }; @@ -857,6 +886,8 @@ enum ena_admin_aenq_notification_syndrom { ENA_ADMIN_SUSPEND = 0, ENA_ADMIN_RESUME = 1, + + ENA_ADMIN_UPDATE_HINTS = 2, }; struct ena_admin_aenq_entry { diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 02752d5b5b60..65d53d501139 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -511,7 +511,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c unsigned long flags, timeout; int ret; - timeout = jiffies + ADMIN_CMD_TIMEOUT_US; + timeout = jiffies + usecs_to_jiffies(admin_queue->completion_timeout); while (1) { spin_lock_irqsave(&admin_queue->q_lock, flags); @@ -561,7 +561,8 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com int ret; wait_for_completion_timeout(&comp_ctx->wait_event, - usecs_to_jiffies(ADMIN_CMD_TIMEOUT_US)); + usecs_to_jiffies( + admin_queue->completion_timeout)); /* In case the command wasn't completed find out the root cause. * There might be 2 kinds of errors @@ -601,12 +602,15 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; volatile struct ena_admin_ena_mmio_req_read_less_resp *read_resp = mmio_read->read_resp; - u32 mmio_read_reg, ret; + u32 mmio_read_reg, ret, i; unsigned long flags; - int i; + u32 timeout = mmio_read->reg_read_to; might_sleep(); + if (timeout == 0) + timeout = ENA_REG_READ_TIMEOUT; + /* If readless is disabled, perform regular read */ if (!mmio_read->readless_supported) return readl(ena_dev->reg_bar + offset); @@ -627,14 +631,14 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) writel(mmio_read_reg, ena_dev->reg_bar + ENA_REGS_MMIO_REG_READ_OFF); - for (i = 0; i < ENA_REG_READ_TIMEOUT; i++) { + for (i = 0; i < timeout; i++) { if (read_resp->req_id == mmio_read->seq_num) break; udelay(1); } - if (unlikely(i == ENA_REG_READ_TIMEOUT)) { + if (unlikely(i == timeout)) { pr_err("reading reg failed for timeout. expected: req id[%hu] offset[%hu] actual: req id[%hu] offset[%hu]\n", mmio_read->seq_num, offset, read_resp->req_id, read_resp->reg_off); @@ -1730,6 +1734,20 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, memcpy(&get_feat_ctx->offload, &get_resp.u.offload, sizeof(get_resp.u.offload)); + /* Driver hints isn't mandatory admin command. So in case the + * command isn't supported set driver hints to 0 + */ + rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS); + + if (!rc) + memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, + sizeof(get_resp.u.hw_hints)); + else if (rc == -EOPNOTSUPP) + memset(&get_feat_ctx->hw_hints, 0x0, + sizeof(get_feat_ctx->hw_hints)); + else + return rc; + return 0; } @@ -1855,6 +1873,14 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev) return rc; } + timeout = (cap & ENA_REGS_CAPS_ADMIN_CMD_TO_MASK) >> + ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT; + if (timeout) + /* the resolution of timeout reg is 100ms */ + ena_dev->admin_queue.completion_timeout = timeout * 100000; + else + ena_dev->admin_queue.completion_timeout = ADMIN_CMD_TIMEOUT_US; + return 0; } diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index c9b33ee5f258..630c09ad35a5 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -97,6 +97,8 @@ #define ENA_INTR_MODER_LEVEL_STRIDE 2 #define ENA_INTR_BYTE_COUNT_NOT_SUPPORTED 0xFFFFFF +#define ENA_HW_HINTS_NO_TIMEOUT 0xFFFF + enum ena_intr_moder_level { ENA_INTR_MODER_LOWEST = 0, ENA_INTR_MODER_LOW, @@ -232,7 +234,9 @@ struct ena_com_stats_admin { struct ena_com_admin_queue { void *q_dmadev; spinlock_t q_lock; /* spinlock for the admin queue */ + struct ena_comp_ctx *comp_ctx; + u32 completion_timeout; u16 q_depth; struct ena_com_admin_cq cq; struct ena_com_admin_sq sq; @@ -267,6 +271,7 @@ struct ena_com_aenq { struct ena_com_mmio_read { struct ena_admin_ena_mmio_req_read_less_resp *read_resp; dma_addr_t read_resp_dma_addr; + u32 reg_read_to; /* in us */ u16 seq_num; bool readless_supported; /* spin lock to ensure a single outstanding read */ @@ -336,6 +341,7 @@ struct ena_com_dev_get_features_ctx { struct ena_admin_device_attr_feature_desc dev_attr; struct ena_admin_feature_aenq_desc aenq; struct ena_admin_feature_offload_desc offload; + struct ena_admin_ena_hw_hints hw_hints; }; struct ena_com_create_io_ctx { diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 8d4f65ea985c..1ee06e11654c 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2577,7 +2577,7 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter, tx_buf = &tx_ring->tx_buffer_info[i]; last_jiffies = tx_buf->last_jiffies; if (unlikely(last_jiffies && - time_is_before_jiffies(last_jiffies + TX_TIMEOUT))) { + time_is_before_jiffies(last_jiffies + adapter->missing_tx_completion_to))) { if (!tx_buf->print_once) netif_notice(adapter, tx_err, adapter->netdev, "Found a Tx that wasn't completed on time, qid %d, index %d.\n", @@ -2586,10 +2586,11 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter, tx_buf->print_once = 1; missed_tx++; - if (unlikely(missed_tx > MAX_NUM_OF_TIMEOUTED_PACKETS)) { + if (unlikely(missed_tx > adapter->missing_tx_completion_threshold)) { netif_err(adapter, tx_err, adapter->netdev, "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n", - missed_tx, MAX_NUM_OF_TIMEOUTED_PACKETS); + missed_tx, + adapter->missing_tx_completion_threshold); set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); return -EIO; } @@ -2613,6 +2614,9 @@ static void check_for_missing_tx_completions(struct ena_adapter *adapter) if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) return; + if (adapter->missing_tx_completion_to == ENA_HW_HINTS_NO_TIMEOUT) + return; + budget = ENA_MONITORED_TX_QUEUES; for (i = adapter->last_monitored_tx_qid; i < adapter->num_queues; i++) { @@ -2690,8 +2694,11 @@ static void check_for_missing_keep_alive(struct ena_adapter *adapter) if (!adapter->wd_state) return; - keep_alive_expired = round_jiffies(adapter->last_keep_alive_jiffies - + ENA_DEVICE_KALIVE_TIMEOUT); + if (adapter->keep_alive_timeout == ENA_HW_HINTS_NO_TIMEOUT) + return; + + keep_alive_expired = round_jiffies(adapter->last_keep_alive_jiffies + + adapter->keep_alive_timeout); if (unlikely(time_is_before_jiffies(keep_alive_expired))) { netif_err(adapter, drv, adapter->netdev, "Keep alive watchdog timeout.\n"); @@ -2714,6 +2721,44 @@ static void check_for_admin_com_state(struct ena_adapter *adapter) } } +static void ena_update_hints(struct ena_adapter *adapter, + struct ena_admin_ena_hw_hints *hints) +{ + struct net_device *netdev = adapter->netdev; + + if (hints->admin_completion_tx_timeout) + adapter->ena_dev->admin_queue.completion_timeout = + hints->admin_completion_tx_timeout * 1000; + + if (hints->mmio_read_timeout) + /* convert to usec */ + adapter->ena_dev->mmio_read.reg_read_to = + hints->mmio_read_timeout * 1000; + + if (hints->missed_tx_completion_count_threshold_to_reset) + adapter->missing_tx_completion_threshold = + hints->missed_tx_completion_count_threshold_to_reset; + + if (hints->missing_tx_completion_timeout) { + if (hints->missing_tx_completion_timeout == ENA_HW_HINTS_NO_TIMEOUT) + adapter->missing_tx_completion_to = ENA_HW_HINTS_NO_TIMEOUT; + else + adapter->missing_tx_completion_to = + msecs_to_jiffies(hints->missing_tx_completion_timeout); + } + + if (hints->netdev_wd_timeout) + netdev->watchdog_timeo = msecs_to_jiffies(hints->netdev_wd_timeout); + + if (hints->driver_watchdog_timeout) { + if (hints->driver_watchdog_timeout == ENA_HW_HINTS_NO_TIMEOUT) + adapter->keep_alive_timeout = ENA_HW_HINTS_NO_TIMEOUT; + else + adapter->keep_alive_timeout = + msecs_to_jiffies(hints->driver_watchdog_timeout); + } +} + static void ena_update_host_info(struct ena_admin_host_info *host_info, struct net_device *netdev) { @@ -3136,6 +3181,11 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&adapter->reset_task, ena_fw_reset_device); adapter->last_keep_alive_jiffies = jiffies; + adapter->keep_alive_timeout = ENA_DEVICE_KALIVE_TIMEOUT; + adapter->missing_tx_completion_to = TX_TIMEOUT; + adapter->missing_tx_completion_threshold = MAX_NUM_OF_TIMEOUTED_PACKETS; + + ena_update_hints(adapter, &get_feat_ctx.hw_hints); setup_timer(&adapter->timer_service, ena_timer_service, (unsigned long)adapter); @@ -3337,6 +3387,7 @@ static void ena_notification(void *adapter_data, struct ena_admin_aenq_entry *aenq_e) { struct ena_adapter *adapter = (struct ena_adapter *)adapter_data; + struct ena_admin_ena_hw_hints *hints; WARN(aenq_e->aenq_common_desc.group != ENA_ADMIN_NOTIFICATION, "Invalid group(%x) expected %x\n", @@ -3354,6 +3405,11 @@ static void ena_notification(void *adapter_data, case ENA_ADMIN_RESUME: queue_work(ena_wq, &adapter->resume_io_task); break; + case ENA_ADMIN_UPDATE_HINTS: + hints = (struct ena_admin_ena_hw_hints *) + (&aenq_e->inline_data_w4); + ena_update_hints(adapter, hints); + break; default: netif_err(adapter, drv, adapter->netdev, "Invalid aenq notification link state %d\n", diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index a4d3d5e21068..c5fe4aa926ae 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -280,6 +280,8 @@ struct ena_adapter { int msix_vecs; + u32 missing_tx_completion_threshold; + u32 tx_usecs, rx_usecs; /* interrupt moderation */ u32 tx_frames, rx_frames; /* interrupt moderation */ @@ -293,6 +295,9 @@ struct ena_adapter { u8 mac_addr[ETH_ALEN]; + unsigned long keep_alive_timeout; + unsigned long missing_tx_completion_to; + char name[ENA_NAME_MAX_LEN]; unsigned long flags; diff --git a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h index 26097a2b6030..c3891c521075 100644 --- a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h @@ -78,6 +78,8 @@ #define ENA_REGS_CAPS_RESET_TIMEOUT_MASK 0x3e #define ENA_REGS_CAPS_DMA_ADDR_WIDTH_SHIFT 8 #define ENA_REGS_CAPS_DMA_ADDR_WIDTH_MASK 0xff00 +#define ENA_REGS_CAPS_ADMIN_CMD_TO_SHIFT 16 +#define ENA_REGS_CAPS_ADMIN_CMD_TO_MASK 0xf0000 /* aq_caps register */ #define ENA_REGS_AQ_CAPS_AQ_DEPTH_MASK 0xffff -- cgit v1.2.3 From 917501109cf4ea4c47991f593111338811369bf5 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:52 +0300 Subject: net: ena: change sizeof() argument to be the type pointer Instead of using: memset(ptr, 0x0, sizeof(struct ...)) use: memset(ptr, 0x0, sizeor(*ptr)) Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_com.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 65d53d501139..2721c70492a1 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -329,7 +329,7 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, size_t size; int dev_node = 0; - memset(&io_sq->desc_addr, 0x0, sizeof(struct ena_com_io_desc_addr)); + memset(&io_sq->desc_addr, 0x0, sizeof(io_sq->desc_addr)); io_sq->desc_entry_size = (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) ? @@ -383,7 +383,7 @@ static int ena_com_init_io_cq(struct ena_com_dev *ena_dev, size_t size; int prev_node = 0; - memset(&io_cq->cdesc_addr, 0x0, sizeof(struct ena_com_io_desc_addr)); + memset(&io_cq->cdesc_addr, 0x0, sizeof(io_cq->cdesc_addr)); /* Use the basic completion descriptor for Rx */ io_cq->cdesc_entry_size_in_bytes = @@ -685,7 +685,7 @@ static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev, u8 direction; int ret; - memset(&destroy_cmd, 0x0, sizeof(struct ena_admin_aq_destroy_sq_cmd)); + memset(&destroy_cmd, 0x0, sizeof(destroy_cmd)); if (io_sq->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) direction = ENA_ADMIN_SQ_DIRECTION_TX; @@ -967,7 +967,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, u8 direction; int ret; - memset(&create_cmd, 0x0, sizeof(struct ena_admin_aq_create_sq_cmd)); + memset(&create_cmd, 0x0, sizeof(create_cmd)); create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_SQ; @@ -1159,7 +1159,7 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev, struct ena_admin_acq_create_cq_resp_desc cmd_completion; int ret; - memset(&create_cmd, 0x0, sizeof(struct ena_admin_aq_create_cq_cmd)); + memset(&create_cmd, 0x0, sizeof(create_cmd)); create_cmd.aq_common_descriptor.opcode = ENA_ADMIN_CREATE_CQ; @@ -1267,7 +1267,7 @@ int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev, struct ena_admin_acq_destroy_cq_resp_desc destroy_resp; int ret; - memset(&destroy_cmd, 0x0, sizeof(struct ena_admin_aq_destroy_sq_cmd)); + memset(&destroy_cmd, 0x0, sizeof(destroy_cmd)); destroy_cmd.cq_idx = io_cq->idx; destroy_cmd.aq_common_descriptor.opcode = ENA_ADMIN_DESTROY_CQ; @@ -1623,8 +1623,8 @@ int ena_com_create_io_queue(struct ena_com_dev *ena_dev, io_sq = &ena_dev->io_sq_queues[ctx->qid]; io_cq = &ena_dev->io_cq_queues[ctx->qid]; - memset(io_sq, 0x0, sizeof(struct ena_com_io_sq)); - memset(io_cq, 0x0, sizeof(struct ena_com_io_cq)); + memset(io_sq, 0x0, sizeof(*io_sq)); + memset(io_cq, 0x0, sizeof(*io_cq)); /* Init CQ */ io_cq->q_depth = ctx->queue_size; -- cgit v1.2.3 From e2eed0e307f671e37f3829dfec5dbb1fba826a15 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:53 +0300 Subject: net: ena: add reset reason for each device FLR For each device reset, log to the device what is the cause the reset occur. Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_com.c | 5 +++- drivers/net/ethernet/amazon/ena/ena_com.h | 4 +++- drivers/net/ethernet/amazon/ena/ena_netdev.c | 17 +++++++++---- drivers/net/ethernet/amazon/ena/ena_netdev.h | 2 ++ drivers/net/ethernet/amazon/ena/ena_regs_defs.h | 32 +++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 2721c70492a1..f6e1d30523a6 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -1825,7 +1825,8 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data) writel((u32)aenq->head, dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); } -int ena_com_dev_reset(struct ena_com_dev *ena_dev) +int ena_com_dev_reset(struct ena_com_dev *ena_dev, + enum ena_regs_reset_reason_types reset_reason) { u32 stat, timeout, cap, reset_val; int rc; @@ -1853,6 +1854,8 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev) /* start reset */ reset_val = ENA_REGS_DEV_CTL_DEV_RESET_MASK; + reset_val |= (reset_reason << ENA_REGS_DEV_CTL_RESET_REASON_SHIFT) & + ENA_REGS_DEV_CTL_RESET_REASON_MASK; writel(reset_val, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF); /* Write again the MMIO read request address */ diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index 630c09ad35a5..7b784f8a06a6 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -420,10 +420,12 @@ void ena_com_admin_destroy(struct ena_com_dev *ena_dev); /* ena_com_dev_reset - Perform device FLR to the device. * @ena_dev: ENA communication layer struct + * @reset_reason: Specify what is the trigger for the reset in case of an error. * * @return - 0 on success, negative value on failure. */ -int ena_com_dev_reset(struct ena_com_dev *ena_dev); +int ena_com_dev_reset(struct ena_com_dev *ena_dev, + enum ena_regs_reset_reason_types reset_reason); /* ena_com_create_io_queue - Create io queue. * @ena_dev: ENA communication layer struct diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 1ee06e11654c..0d35a4cc3525 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -87,6 +87,7 @@ static void ena_tx_timeout(struct net_device *dev) if (test_and_set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) return; + adapter->reset_reason = ENA_REGS_RESET_OS_NETDEV_WD; u64_stats_update_begin(&adapter->syncp); adapter->dev_stats.tx_timeout++; u64_stats_update_end(&adapter->syncp); @@ -670,6 +671,7 @@ static int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id) u64_stats_update_end(&tx_ring->syncp); /* Trigger device reset */ + tx_ring->adapter->reset_reason = ENA_REGS_RESET_INV_TX_REQ_ID; set_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags); return -EFAULT; } @@ -1055,6 +1057,7 @@ error: u64_stats_update_end(&rx_ring->syncp); /* Too many desc from the device. Trigger reset */ + adapter->reset_reason = ENA_REGS_RESET_TOO_MANY_RX_DESCS; set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); return 0; @@ -1720,7 +1723,7 @@ static void ena_down(struct ena_adapter *adapter) if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) { int rc; - rc = ena_com_dev_reset(adapter->ena_dev); + rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason); if (rc) dev_err(&adapter->pdev->dev, "Device reset failed\n"); } @@ -2353,7 +2356,7 @@ static int ena_device_init(struct ena_com_dev *ena_dev, struct pci_dev *pdev, readless_supported = !(pdev->revision & ENA_MMIO_DISABLE_REG_READ); ena_com_set_mmio_read_mode(ena_dev, readless_supported); - rc = ena_com_dev_reset(ena_dev); + rc = ena_com_dev_reset(ena_dev, ENA_REGS_RESET_NORMAL); if (rc) { dev_err(dev, "Can not reset device\n"); goto err_mmio_read_less; @@ -2512,6 +2515,7 @@ static void ena_fw_reset_device(struct work_struct *work) ena_com_mmio_reg_read_request_destroy(ena_dev); + adapter->reset_reason = ENA_REGS_RESET_NORMAL; clear_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); /* Finish with the destroy part. Start the init part */ @@ -2591,6 +2595,8 @@ static int check_missing_comp_in_queue(struct ena_adapter *adapter, "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n", missed_tx, adapter->missing_tx_completion_threshold); + adapter->reset_reason = + ENA_REGS_RESET_MISS_TX_CMPL; set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); return -EIO; } @@ -2705,6 +2711,7 @@ static void check_for_missing_keep_alive(struct ena_adapter *adapter) u64_stats_update_begin(&adapter->syncp); adapter->dev_stats.wd_expired++; u64_stats_update_end(&adapter->syncp); + adapter->reset_reason = ENA_REGS_RESET_KEEP_ALIVE_TO; set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); } } @@ -2717,6 +2724,7 @@ static void check_for_admin_com_state(struct ena_adapter *adapter) u64_stats_update_begin(&adapter->syncp); adapter->dev_stats.admin_q_pause++; u64_stats_update_end(&adapter->syncp); + adapter->reset_reason = ENA_REGS_RESET_ADMIN_TO; set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); } } @@ -3121,6 +3129,7 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ena_set_conf_feat_params(adapter, &get_feat_ctx); adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); + adapter->reset_reason = ENA_REGS_RESET_NORMAL; adapter->tx_ring_size = queue_size; adapter->rx_ring_size = queue_size; @@ -3205,7 +3214,7 @@ err_rss: ena_com_delete_debug_area(ena_dev); ena_com_rss_destroy(ena_dev); err_free_msix: - ena_com_dev_reset(ena_dev); + ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR); ena_free_mgmnt_irq(adapter); pci_free_irq_vectors(adapter->pdev); err_worker_destroy: @@ -3288,7 +3297,7 @@ static void ena_remove(struct pci_dev *pdev) /* Reset the device only if the device is running. */ if (test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)) - ena_com_dev_reset(ena_dev); + ena_com_dev_reset(ena_dev, adapter->reset_reason); ena_free_mgmnt_irq(adapter); diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index c5fe4aa926ae..ccbb14cc3038 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -327,6 +327,8 @@ struct ena_adapter { /* last queue index that was checked for uncompleted tx packets */ u32 last_monitored_tx_qid; + + enum ena_regs_reset_reason_types reset_reason; }; void ena_set_ethtool_ops(struct net_device *netdev); diff --git a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h index c3891c521075..9aec43c5bba8 100644 --- a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h @@ -32,6 +32,36 @@ #ifndef _ENA_REGS_H_ #define _ENA_REGS_H_ +enum ena_regs_reset_reason_types { + ENA_REGS_RESET_NORMAL = 0, + + ENA_REGS_RESET_KEEP_ALIVE_TO = 1, + + ENA_REGS_RESET_ADMIN_TO = 2, + + ENA_REGS_RESET_MISS_TX_CMPL = 3, + + ENA_REGS_RESET_INV_RX_REQ_ID = 4, + + ENA_REGS_RESET_INV_TX_REQ_ID = 5, + + ENA_REGS_RESET_TOO_MANY_RX_DESCS = 6, + + ENA_REGS_RESET_INIT_ERR = 7, + + ENA_REGS_RESET_DRIVER_INVALID_STATE = 8, + + ENA_REGS_RESET_OS_TRIGGER = 9, + + ENA_REGS_RESET_OS_NETDEV_WD = 10, + + ENA_REGS_RESET_SHUTDOWN = 11, + + ENA_REGS_RESET_USER_TRIGGER = 12, + + ENA_REGS_RESET_GENERIC = 13, +}; + /* ena_registers offsets */ #define ENA_REGS_VERSION_OFF 0x0 #define ENA_REGS_CONTROLLER_VERSION_OFF 0x4 @@ -104,6 +134,8 @@ #define ENA_REGS_DEV_CTL_QUIESCENT_MASK 0x4 #define ENA_REGS_DEV_CTL_IO_RESUME_SHIFT 3 #define ENA_REGS_DEV_CTL_IO_RESUME_MASK 0x8 +#define ENA_REGS_DEV_CTL_RESET_REASON_SHIFT 28 +#define ENA_REGS_DEV_CTL_RESET_REASON_MASK 0xf0000000 /* dev_sts register */ #define ENA_REGS_DEV_STS_READY_MASK 0x1 -- cgit v1.2.3 From ad974baef2a17a170fe837ad19f10dcab63e9470 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:54 +0300 Subject: net: ena: add support for out of order rx buffers refill ENA driver post Rx buffers through the Rx submission queue for the ENA device to fill them with receive packets. Each Rx buffer is marked with req_id in the Rx descriptor. Newer ENA devices could consume the posted Rx buffer in out of order, and as result the corresponding Rx completion queue will have Rx completion descriptors with non contiguous req_id(s) In this change the driver holds two rings. The first ring (called free_rx_ids) is a mapping ring. It holds all the unused request ids. The values in this ring are from 0 to ring_size -1. When the driver wants to allocate a new Rx buffer it uses the head of free_rx_ids and uses it's value as the index for rx_buffer_info ring. The req_id is also written to the Rx descriptor Upon Rx completion, The driver took the req_id from the completion descriptor and uses it as index in rx_buffer_info. The req_id is then return to the free_rx_ids ring. This patch also adds statistics to inform when the driver receive out of range or unused req_id. Note: free_rx_ids is only accessible from the napi handler, so no locking is required Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_eth_com.c | 5 ++ drivers/net/ethernet/amazon/ena/ena_ethtool.c | 1 + drivers/net/ethernet/amazon/ena/ena_netdev.c | 83 ++++++++++++++++++++++----- drivers/net/ethernet/amazon/ena/ena_netdev.h | 11 +++- 4 files changed, 83 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c index f999305e1363..b11e573ad57a 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c @@ -493,6 +493,11 @@ int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, u16 *req_id) if (cdesc_phase != expected_phase) return -EAGAIN; + if (unlikely(cdesc->req_id >= io_cq->q_depth)) { + pr_err("Invalid req id %d\n", cdesc->req_id); + return -EINVAL; + } + ena_com_cq_inc_head(io_cq); *req_id = READ_ONCE(cdesc->req_id); diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index d51a67f4df02..b1212debc2e1 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -93,6 +93,7 @@ static const struct ena_stats ena_stats_rx_strings[] = { ENA_STAT_RX_ENTRY(dma_mapping_err), ENA_STAT_RX_ENTRY(bad_desc_num), ENA_STAT_RX_ENTRY(rx_copybreak_pkt), + ENA_STAT_RX_ENTRY(bad_req_id), ENA_STAT_RX_ENTRY(empty_rx_ring), }; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 0d35a4cc3525..fcbcd188a132 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -304,6 +304,24 @@ static void ena_free_all_io_tx_resources(struct ena_adapter *adapter) ena_free_tx_resources(adapter, i); } +static inline int validate_rx_req_id(struct ena_ring *rx_ring, u16 req_id) +{ + if (likely(req_id < rx_ring->ring_size)) + return 0; + + netif_err(rx_ring->adapter, rx_err, rx_ring->netdev, + "Invalid rx req_id: %hu\n", req_id); + + u64_stats_update_begin(&rx_ring->syncp); + rx_ring->rx_stats.bad_req_id++; + u64_stats_update_end(&rx_ring->syncp); + + /* Trigger device reset */ + rx_ring->adapter->reset_reason = ENA_REGS_RESET_INV_RX_REQ_ID; + set_bit(ENA_FLAG_TRIGGER_RESET, &rx_ring->adapter->flags); + return -EFAULT; +} + /* ena_setup_rx_resources - allocate I/O Rx resources (Descriptors) * @adapter: network interface device structure * @qid: queue index @@ -315,7 +333,7 @@ static int ena_setup_rx_resources(struct ena_adapter *adapter, { struct ena_ring *rx_ring = &adapter->rx_ring[qid]; struct ena_irq *ena_irq = &adapter->irq_tbl[ENA_IO_IRQ_IDX(qid)]; - int size, node; + int size, node, i; if (rx_ring->rx_buffer_info) { netif_err(adapter, ifup, adapter->netdev, @@ -336,6 +354,20 @@ static int ena_setup_rx_resources(struct ena_adapter *adapter, return -ENOMEM; } + size = sizeof(u16) * rx_ring->ring_size; + rx_ring->free_rx_ids = vzalloc_node(size, node); + if (!rx_ring->free_rx_ids) { + rx_ring->free_rx_ids = vzalloc(size); + if (!rx_ring->free_rx_ids) { + vfree(rx_ring->rx_buffer_info); + return -ENOMEM; + } + } + + /* Req id ring for receiving RX pkts out of order */ + for (i = 0; i < rx_ring->ring_size; i++) + rx_ring->free_rx_ids[i] = i; + /* Reset rx statistics */ memset(&rx_ring->rx_stats, 0x0, sizeof(rx_ring->rx_stats)); @@ -359,6 +391,9 @@ static void ena_free_rx_resources(struct ena_adapter *adapter, vfree(rx_ring->rx_buffer_info); rx_ring->rx_buffer_info = NULL; + + vfree(rx_ring->free_rx_ids); + rx_ring->free_rx_ids = NULL; } /* ena_setup_all_rx_resources - allocate I/O Rx queues resources for all queues @@ -464,15 +499,22 @@ static void ena_free_rx_page(struct ena_ring *rx_ring, static int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num) { - u16 next_to_use; + u16 next_to_use, req_id; u32 i; int rc; next_to_use = rx_ring->next_to_use; for (i = 0; i < num; i++) { - struct ena_rx_buffer *rx_info = - &rx_ring->rx_buffer_info[next_to_use]; + struct ena_rx_buffer *rx_info; + + req_id = rx_ring->free_rx_ids[next_to_use]; + rc = validate_rx_req_id(rx_ring, req_id); + if (unlikely(rc < 0)) + break; + + rx_info = &rx_ring->rx_buffer_info[req_id]; + rc = ena_alloc_rx_page(rx_ring, rx_info, __GFP_COLD | GFP_ATOMIC | __GFP_COMP); @@ -484,7 +526,7 @@ static int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num) } rc = ena_com_add_single_rx_desc(rx_ring->ena_com_io_sq, &rx_info->ena_buf, - next_to_use); + req_id); if (unlikely(rc)) { netif_warn(rx_ring->adapter, rx_status, rx_ring->netdev, "failed to add buffer for rx queue %d\n", @@ -789,13 +831,14 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, u16 *next_to_clean) { struct sk_buff *skb; - struct ena_rx_buffer *rx_info = - &rx_ring->rx_buffer_info[*next_to_clean]; - u32 len; - u32 buf = 0; + struct ena_rx_buffer *rx_info; + u16 len, req_id, buf = 0; void *va; - len = ena_bufs[0].len; + len = ena_bufs[buf].len; + req_id = ena_bufs[buf].req_id; + rx_info = &rx_ring->rx_buffer_info[req_id]; + if (unlikely(!rx_info->page)) { netif_err(rx_ring->adapter, rx_err, rx_ring->netdev, "Page is NULL\n"); @@ -867,13 +910,18 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, skb->len, skb->data_len); rx_info->page = NULL; + + rx_ring->free_rx_ids[*next_to_clean] = req_id; *next_to_clean = ENA_RX_RING_IDX_NEXT(*next_to_clean, rx_ring->ring_size); if (likely(--descs == 0)) break; - rx_info = &rx_ring->rx_buffer_info[*next_to_clean]; - len = ena_bufs[++buf].len; + + buf++; + len = ena_bufs[buf].len; + req_id = ena_bufs[buf].req_id; + rx_info = &rx_ring->rx_buffer_info[req_id]; } while (1); return skb; @@ -974,6 +1022,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, int rc = 0; int total_len = 0; int rx_copybreak_pkt = 0; + int i; netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, "%s qid %d\n", __func__, rx_ring->qid); @@ -1003,9 +1052,13 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, /* exit if we failed to retrieve a buffer */ if (unlikely(!skb)) { - next_to_clean = ENA_RX_RING_IDX_ADD(next_to_clean, - ena_rx_ctx.descs, - rx_ring->ring_size); + for (i = 0; i < ena_rx_ctx.descs; i++) { + rx_ring->free_tx_ids[next_to_clean] = + rx_ring->ena_bufs[i].req_id; + next_to_clean = + ENA_RX_RING_IDX_NEXT(next_to_clean, + rx_ring->ring_size); + } break; } diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index ccbb14cc3038..5edc3da96ce5 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -194,12 +194,19 @@ struct ena_stats_rx { u64 dma_mapping_err; u64 bad_desc_num; u64 rx_copybreak_pkt; + u64 bad_req_id; u64 empty_rx_ring; }; struct ena_ring { - /* Holds the empty requests for TX out of order completions */ - u16 *free_tx_ids; + union { + /* Holds the empty requests for TX/RX + * out of order completions + */ + u16 *free_tx_ids; + u16 *free_rx_ids; + }; + union { struct ena_tx_buffer *tx_buffer_info; struct ena_rx_buffer *rx_buffer_info; -- cgit v1.2.3 From 06443684daede6ded1fab8f8729249436fb0cd8e Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:55 +0300 Subject: net: ena: allow the driver to work with small number of msix vectors Current driver tries to allocate msix vectors as the number of the negotiated io queues. (with another msix vector for management). If pci_alloc_irq_vectors() fails, the driver aborts the probe and the ENA network device is never brought up. With this patch, the driver's logic will reduce the number of IO queues to the number of allocated msix vectors (minus one for management) instead of failing probe(). Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 65 ++++++++++++++++++++-------- drivers/net/ethernet/amazon/ena/ena_netdev.h | 6 ++- 2 files changed, 51 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index fcbcd188a132..04aade842097 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1269,9 +1269,20 @@ static irqreturn_t ena_intr_msix_io(int irq, void *data) return IRQ_HANDLED; } +/* Reserve a single MSI-X vector for management (admin + aenq). + * plus reserve one vector for each potential io queue. + * the number of potential io queues is the minimum of what the device + * supports and the number of vCPUs. + */ static int ena_enable_msix(struct ena_adapter *adapter, int num_queues) { - int msix_vecs, rc; + int msix_vecs, irq_cnt; + + if (test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) { + netif_err(adapter, probe, adapter->netdev, + "Error, MSI-X is already enabled\n"); + return -EPERM; + } /* Reserved the max msix vectors we might need */ msix_vecs = ENA_MAX_MSIX_VEC(num_queues); @@ -1279,25 +1290,28 @@ static int ena_enable_msix(struct ena_adapter *adapter, int num_queues) netif_dbg(adapter, probe, adapter->netdev, "trying to enable MSI-X, vectors %d\n", msix_vecs); - rc = pci_alloc_irq_vectors(adapter->pdev, msix_vecs, msix_vecs, - PCI_IRQ_MSIX); - if (rc < 0) { + irq_cnt = pci_alloc_irq_vectors(adapter->pdev, ENA_MIN_MSIX_VEC, + msix_vecs, PCI_IRQ_MSIX); + + if (irq_cnt < 0) { netif_err(adapter, probe, adapter->netdev, - "Failed to enable MSI-X, vectors %d rc %d\n", - msix_vecs, rc); + "Failed to enable MSI-X. irq_cnt %d\n", irq_cnt); return -ENOSPC; } - netif_dbg(adapter, probe, adapter->netdev, "enable MSI-X, vectors %d\n", - msix_vecs); - - if (msix_vecs >= 1) { - if (ena_init_rx_cpu_rmap(adapter)) - netif_warn(adapter, probe, adapter->netdev, - "Failed to map IRQs to CPUs\n"); + if (irq_cnt != msix_vecs) { + netif_notice(adapter, probe, adapter->netdev, + "enable only %d MSI-X (out of %d), reduce the number of queues\n", + irq_cnt, msix_vecs); + adapter->num_queues = irq_cnt - ENA_ADMIN_MSIX_VEC; } - adapter->msix_vecs = msix_vecs; + if (ena_init_rx_cpu_rmap(adapter)) + netif_warn(adapter, probe, adapter->netdev, + "Failed to map IRQs to CPUs\n"); + + adapter->msix_vecs = irq_cnt; + set_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags); return 0; } @@ -1374,6 +1388,12 @@ static int ena_request_io_irq(struct ena_adapter *adapter) struct ena_irq *irq; int rc = 0, i, k; + if (!test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) { + netif_err(adapter, ifup, adapter->netdev, + "Failed to request I/O IRQ: MSI-X is not enabled\n"); + return -EINVAL; + } + for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) { irq = &adapter->irq_tbl[i]; rc = request_irq(irq->vector, irq->handler, flags, irq->name, @@ -1432,6 +1452,12 @@ static void ena_free_io_irq(struct ena_adapter *adapter) } } +static void ena_disable_msix(struct ena_adapter *adapter) +{ + if (test_and_clear_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) + pci_free_irq_vectors(adapter->pdev); +} + static void ena_disable_io_intr_sync(struct ena_adapter *adapter) { int i; @@ -2520,7 +2546,8 @@ static int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter, return 0; err_disable_msix: - pci_free_irq_vectors(adapter->pdev); + ena_disable_msix(adapter); + return rc; } @@ -2558,7 +2585,7 @@ static void ena_fw_reset_device(struct work_struct *work) ena_free_mgmnt_irq(adapter); - pci_free_irq_vectors(adapter->pdev); + ena_disable_msix(adapter); ena_com_abort_admin_commands(ena_dev); @@ -2610,7 +2637,7 @@ static void ena_fw_reset_device(struct work_struct *work) return; err_disable_msix: ena_free_mgmnt_irq(adapter); - pci_free_irq_vectors(adapter->pdev); + ena_disable_msix(adapter); err_device_destroy: ena_com_admin_destroy(ena_dev); err: @@ -3269,7 +3296,7 @@ err_rss: err_free_msix: ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR); ena_free_mgmnt_irq(adapter); - pci_free_irq_vectors(adapter->pdev); + ena_disable_msix(adapter); err_worker_destroy: ena_com_destroy_interrupt_moderation(ena_dev); del_timer(&adapter->timer_service); @@ -3354,7 +3381,7 @@ static void ena_remove(struct pci_dev *pdev) ena_free_mgmnt_irq(adapter); - pci_free_irq_vectors(adapter->pdev); + ena_disable_msix(adapter); free_netdev(netdev); diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 5edc3da96ce5..86b0f0dbae65 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -58,7 +58,10 @@ #define DEVICE_NAME "Elastic Network Adapter (ENA)" /* 1 for AENQ + ADMIN */ -#define ENA_MAX_MSIX_VEC(io_queues) (1 + (io_queues)) +#define ENA_ADMIN_MSIX_VEC 1 +#define ENA_MAX_MSIX_VEC(io_queues) (ENA_ADMIN_MSIX_VEC + (io_queues)) + +#define ENA_MIN_MSIX_VEC 2 #define ENA_REG_BAR 0 #define ENA_MEM_BAR 2 @@ -267,6 +270,7 @@ enum ena_flags_t { ENA_FLAG_DEVICE_RUNNING, ENA_FLAG_DEV_UP, ENA_FLAG_LINK_UP, + ENA_FLAG_MSIX_ENABLED, ENA_FLAG_TRIGGER_RESET }; -- cgit v1.2.3 From e745dafab0340edaa522b43fd36b38e646c2963d Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:56 +0300 Subject: net: ena: use napi_schedule_irqoff when possible Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 04aade842097..424b4d7e642f 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1264,7 +1264,7 @@ static irqreturn_t ena_intr_msix_io(int irq, void *data) { struct ena_napi *ena_napi = data; - napi_schedule(&ena_napi->napi); + napi_schedule_irqoff(&ena_napi->napi); return IRQ_HANDLED; } -- cgit v1.2.3 From 4265114d5391ed92d7860472c7c8dfe866707106 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:57 +0300 Subject: net: ena: separate skb allocation to dedicated function Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 44 +++++++++++++++++----------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 424b4d7e642f..7dee448157bb 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -825,6 +825,28 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) return tx_pkts; } +static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, bool frags) +{ + struct sk_buff *skb; + + if (frags) + skb = napi_get_frags(rx_ring->napi); + else + skb = netdev_alloc_skb_ip_align(rx_ring->netdev, + rx_ring->rx_copybreak); + + if (unlikely(!skb)) { + u64_stats_update_begin(&rx_ring->syncp); + rx_ring->rx_stats.skb_alloc_fail++; + u64_stats_update_end(&rx_ring->syncp); + netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev, + "Failed to allocate skb. frags: %d\n", frags); + return NULL; + } + + return skb; +} + static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, struct ena_com_rx_buf_info *ena_bufs, u32 descs, @@ -854,16 +876,9 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, prefetch(va + NET_IP_ALIGN); if (len <= rx_ring->rx_copybreak) { - skb = netdev_alloc_skb_ip_align(rx_ring->netdev, - rx_ring->rx_copybreak); - if (unlikely(!skb)) { - u64_stats_update_begin(&rx_ring->syncp); - rx_ring->rx_stats.skb_alloc_fail++; - u64_stats_update_end(&rx_ring->syncp); - netif_err(rx_ring->adapter, rx_err, rx_ring->netdev, - "Failed to allocate skb\n"); + skb = ena_alloc_skb(rx_ring, false); + if (unlikely(!skb)) return NULL; - } netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, "rx allocated small packet. len %d. data_len %d\n", @@ -882,20 +897,15 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, skb_put(skb, len); skb->protocol = eth_type_trans(skb, rx_ring->netdev); + rx_ring->free_rx_ids[*next_to_clean] = req_id; *next_to_clean = ENA_RX_RING_IDX_ADD(*next_to_clean, descs, rx_ring->ring_size); return skb; } - skb = napi_get_frags(rx_ring->napi); - if (unlikely(!skb)) { - netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, - "Failed allocating skb\n"); - u64_stats_update_begin(&rx_ring->syncp); - rx_ring->rx_stats.skb_alloc_fail++; - u64_stats_update_end(&rx_ring->syncp); + skb = ena_alloc_skb(rx_ring, true); + if (unlikely(!skb)) return NULL; - } do { dma_unmap_page(rx_ring->dev, -- cgit v1.2.3 From 3ae5907c61587ed8327484bfdda87de0257ea73f Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:58 +0300 Subject: net: ena: use lower_32_bits()/upper_32_bits() to split dma address In ena_com_mem_addr_set(), use the above functions to split dma address to the lower 32 bits and the higher 16 bits. Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_com.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index f6e1d30523a6..52beba8c7a39 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -99,8 +99,8 @@ static inline int ena_com_mem_addr_set(struct ena_com_dev *ena_dev, return -EINVAL; } - ena_addr->mem_addr_low = (u32)addr; - ena_addr->mem_addr_high = (u64)addr >> 32; + ena_addr->mem_addr_low = lower_32_bits(addr); + ena_addr->mem_addr_high = (u16)upper_32_bits(addr); return 0; } -- cgit v1.2.3 From 11a9a460199f35f6cbd9d65516a262060cba4fec Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:21:59 +0300 Subject: net: ena: update driver's rx drop statistics rx drop counter is reported by the device in the keep-alive event. update the driver's counter with the device counter. Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 7dee448157bb..f7dc22f65d9f 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -3478,8 +3478,17 @@ static void ena_keep_alive_wd(void *adapter_data, struct ena_admin_aenq_entry *aenq_e) { struct ena_adapter *adapter = (struct ena_adapter *)adapter_data; + struct ena_admin_aenq_keep_alive_desc *desc; + u64 rx_drops; + desc = (struct ena_admin_aenq_keep_alive_desc *)aenq_e; adapter->last_keep_alive_jiffies = jiffies; + + rx_drops = ((u64)desc->rx_drops_high << 32) | desc->rx_drops_low; + + u64_stats_update_begin(&adapter->syncp); + adapter->dev_stats.rx_drops = rx_drops; + u64_stats_update_end(&adapter->syncp); } static void ena_notification(void *adapter_data, -- cgit v1.2.3 From 8523899912b6958ef471d2393c016f87dc4f0354 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Fri, 23 Jun 2017 11:22:00 +0300 Subject: net: ena: update ena driver to version 1.2.0 Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 86b0f0dbae65..29bb5704260b 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -44,15 +44,15 @@ #include "ena_eth_com.h" #define DRV_MODULE_VER_MAJOR 1 -#define DRV_MODULE_VER_MINOR 1 -#define DRV_MODULE_VER_SUBMINOR 7 +#define DRV_MODULE_VER_MINOR 2 +#define DRV_MODULE_VER_SUBMINOR 0 #define DRV_MODULE_NAME "ena" #ifndef DRV_MODULE_VERSION #define DRV_MODULE_VERSION \ __stringify(DRV_MODULE_VER_MAJOR) "." \ __stringify(DRV_MODULE_VER_MINOR) "." \ - __stringify(DRV_MODULE_VER_SUBMINOR) + __stringify(DRV_MODULE_VER_SUBMINOR) "k" #endif #define DEVICE_NAME "Elastic Network Adapter (ENA)" -- cgit v1.2.3 From 193c4c2845f7c6b37a4886d747f47b1dff64600a Mon Sep 17 00:00:00 2001 From: Arjun Vynipadath Date: Fri, 23 Jun 2017 19:14:36 +0530 Subject: cxgb4: Update T6 Buffer Group and Channel Mappings We were using t4_get_mps_bg_map() for both t4_get_port_stats() to determine which MPS Buffer Groups to report statistics on for a given Port, and also for t4_sge_alloc_rxq() to provide a TP Ingress Channel Congestion Map. For T4/T5 these are actually the same values (because they are ~somewhat~ related), but for T6 they should return different values (T6 has Port 0 associated with MPS Buffer Group 0 (with MPS Buffer Group 1 silently cascading off) and Port 1 is associated with MPS Buffer Group 2 (with 3 cascading off)). Based on the original work by Casey Leedom Signed-off-by: Arjun Vynipadath Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 3 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 4 +- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 91 +++++++++++++++++++++---- 3 files changed, 80 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index b7a92ebab3cf..f60a64bd6c41 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1434,7 +1434,8 @@ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, u32 t4_read_rss_pf_map(struct adapter *adapter); u32 t4_read_rss_pf_mask(struct adapter *adapter); -unsigned int t4_get_mps_bg_map(struct adapter *adapter, int idx); +unsigned int t4_get_mps_bg_map(struct adapter *adapter, int pidx); +unsigned int t4_get_tp_ch_map(struct adapter *adapter, int pidx); void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]); void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]); int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index b3753ed74cec..f41507e040da 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -843,8 +843,8 @@ static int setup_sge_queues(struct adapter *adap) adap->msi_idx, &q->fl, t4_ethrx_handler, NULL, - t4_get_mps_bg_map(adap, - pi->tx_chan)); + t4_get_tp_ch_map(adap, + pi->tx_chan)); if (err) goto freeout; q->rspq.idx = j; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index d5e316d5481e..4d9ef3f6fe4c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -5442,28 +5442,89 @@ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) /** * t4_get_mps_bg_map - return the buffer groups associated with a port * @adap: the adapter - * @idx: the port index + * @pidx: the port index * * Returns a bitmap indicating which MPS buffer groups are associated * with the given port. Bit i is set if buffer group i is used by the * port. */ -unsigned int t4_get_mps_bg_map(struct adapter *adap, int idx) +unsigned int t4_get_mps_bg_map(struct adapter *adap, int pidx) { - u32 n = NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A)); + unsigned int nports = 1 << NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A)); + unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); - if (n == 0) - return idx == 0 ? 0xf : 0; - /* In T6 (which is a 2 port card), - * port 0 is mapped to channel 0 and port 1 is mapped to channel 1. - * For 2 port T4/T5 adapter, - * port 0 is mapped to channel 0 and 1, - * port 1 is mapped to channel 2 and 3. - */ - if ((n == 1) && - (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5)) - return idx < 2 ? (3 << (2 * idx)) : 0; - return 1 << idx; + if (pidx >= nports) { + dev_warn(adap->pdev_dev, "MPS Port Index %d >= Nports %d\n", + pidx, nports); + return 0; + } + + switch (chip_version) { + case CHELSIO_T4: + case CHELSIO_T5: + switch (nports) { + case 1: return 0xf; + case 2: return 3 << (2 * pidx); + case 4: return 1 << pidx; + } + break; + + case CHELSIO_T6: + switch (nports) { + case 2: return 1 << (2 * pidx); + } + break; + } + + dev_err(adap->pdev_dev, "Need MPS Buffer Group Map for Chip %0x, Nports %d\n", + chip_version, nports); + return 0; +} + +/** + * t4_get_tp_ch_map - return TP ingress channels associated with a port + * @adapter: the adapter + * @pidx: the port index + * + * Returns a bitmap indicating which TP Ingress Channels are associated + * with a given Port. Bit i is set if TP Ingress Channel i is used by + * the Port. + */ +unsigned int t4_get_tp_ch_map(struct adapter *adap, int pidx) +{ + unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); + unsigned int nports = 1 << NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A)); + + if (pidx >= nports) { + dev_warn(adap->pdev_dev, "TP Port Index %d >= Nports %d\n", + pidx, nports); + return 0; + } + + switch (chip_version) { + case CHELSIO_T4: + case CHELSIO_T5: + /* Note that this happens to be the same values as the MPS + * Buffer Group Map for these Chips. But we replicate the code + * here because they're really separate concepts. + */ + switch (nports) { + case 1: return 0xf; + case 2: return 3 << (2 * pidx); + case 4: return 1 << pidx; + } + break; + + case CHELSIO_T6: + switch (nports) { + case 2: return 1 << pidx; + } + break; + } + + dev_err(adap->pdev_dev, "Need TP Channel Map for Chip %0x, Nports %d\n", + chip_version, nports); + return 0; } /** -- cgit v1.2.3 From 8f46d46715a12f509e13200033a1ed4d6cf335ff Mon Sep 17 00:00:00 2001 From: Arjun Vynipadath Date: Fri, 23 Jun 2017 19:14:37 +0530 Subject: cxgb4: Use Firmware params to get buffer-group map Buffer group mappings can be obtained using FW_PARAMs cmd for newer FW. Since some of the bg_maps are obtained in atomic context, created another t4_query_params_ns(), that wont sleep when awaiting mbox cmd completion. Signed-off-by: Casey Leedom Signed-off-by: Arjun Vynipadath Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 10 ++- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 108 ++++++++++++++++++++++---- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 1 + 3 files changed, 101 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index f60a64bd6c41..451c138ff6ea 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -362,6 +362,11 @@ struct adapter_params { unsigned int max_ordird_qp; /* Max read depth per RDMA QP */ unsigned int max_ird_adapter; /* Max read depth per adapter */ bool fr_nsmr_tpte_wr_support; /* FW support for FR_NSMR_TPTE_WR */ + + /* MPS Buffer Group Map[per Port]. Bit i is set if buffer group i is + * used by the Port + */ + u8 mps_bg_map[MAX_NPORTS]; /* MPS Buffer Group Map */ }; /* State needed to monitor the forward progress of SGE Ingress DMA activities @@ -1495,9 +1500,12 @@ int t4_fw_initialize(struct adapter *adap, unsigned int mbox); int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int nparams, const u32 *params, u32 *val); +int t4_query_params_ns(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int nparams, const u32 *params, + u32 *val); int t4_query_params_rw(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int nparams, const u32 *params, - u32 *val, int rw); + u32 *val, int rw, bool sleep_ok); int t4_set_params_timeout(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int nparams, const u32 *params, diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 4d9ef3f6fe4c..82bf7aac6cdb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3540,7 +3540,7 @@ int t4_load_phy_fw(struct adapter *adap, FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD)); val = phy_fw_size; ret = t4_query_params_rw(adap, adap->mbox, adap->pf, 0, 1, - ¶m, &val, 1); + ¶m, &val, 1, true); if (ret < 0) return ret; mtype = val >> 8; @@ -5440,24 +5440,21 @@ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) } /** - * t4_get_mps_bg_map - return the buffer groups associated with a port + * compute_mps_bg_map - compute the MPS Buffer Group Map for a Port * @adap: the adapter * @pidx: the port index * - * Returns a bitmap indicating which MPS buffer groups are associated - * with the given port. Bit i is set if buffer group i is used by the - * port. + * Computes and returns a bitmap indicating which MPS buffer groups are + * associated with the given Port. Bit i is set if buffer group i is + * used by the Port. */ -unsigned int t4_get_mps_bg_map(struct adapter *adap, int pidx) +static inline unsigned int compute_mps_bg_map(struct adapter *adapter, + int pidx) { - unsigned int nports = 1 << NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A)); - unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); + unsigned int chip_version, nports; - if (pidx >= nports) { - dev_warn(adap->pdev_dev, "MPS Port Index %d >= Nports %d\n", - pidx, nports); - return 0; - } + chip_version = CHELSIO_CHIP_VERSION(adapter->params.chip); + nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A)); switch (chip_version) { case CHELSIO_T4: @@ -5476,11 +5473,78 @@ unsigned int t4_get_mps_bg_map(struct adapter *adap, int pidx) break; } - dev_err(adap->pdev_dev, "Need MPS Buffer Group Map for Chip %0x, Nports %d\n", + dev_err(adapter->pdev_dev, "Need MPS Buffer Group Map for Chip %0x, Nports %d\n", chip_version, nports); + return 0; } +/** + * t4_get_mps_bg_map - return the buffer groups associated with a port + * @adapter: the adapter + * @pidx: the port index + * + * Returns a bitmap indicating which MPS buffer groups are associated + * with the given Port. Bit i is set if buffer group i is used by the + * Port. + */ +unsigned int t4_get_mps_bg_map(struct adapter *adapter, int pidx) +{ + u8 *mps_bg_map; + unsigned int nports; + + nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A)); + if (pidx >= nports) { + CH_WARN(adapter, "MPS Port Index %d >= Nports %d\n", + pidx, nports); + return 0; + } + + /* If we've already retrieved/computed this, just return the result. + */ + mps_bg_map = adapter->params.mps_bg_map; + if (mps_bg_map[pidx]) + return mps_bg_map[pidx]; + + /* Newer Firmware can tell us what the MPS Buffer Group Map is. + * If we're talking to such Firmware, let it tell us. If the new + * API isn't supported, revert back to old hardcoded way. The value + * obtained from Firmware is encoded in below format: + * + * val = (( MPSBGMAP[Port 3] << 24 ) | + * ( MPSBGMAP[Port 2] << 16 ) | + * ( MPSBGMAP[Port 1] << 8 ) | + * ( MPSBGMAP[Port 0] << 0 )) + */ + if (adapter->flags & FW_OK) { + u32 param, val; + int ret; + + param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_MPSBGMAP)); + ret = t4_query_params_ns(adapter, adapter->mbox, adapter->pf, + 0, 1, ¶m, &val); + if (!ret) { + int p; + + /* Store the BG Map for all of the Ports in order to + * avoid more calls to the Firmware in the future. + */ + for (p = 0; p < MAX_NPORTS; p++, val >>= 8) + mps_bg_map[p] = val & 0xff; + + return mps_bg_map[pidx]; + } + } + + /* Either we're not talking to the Firmware or we're dealing with + * older Firmware which doesn't support the new API to get the MPS + * Buffer Group Map. Fall back to computing it ourselves. + */ + mps_bg_map[pidx] = compute_mps_bg_map(adapter, pidx); + return mps_bg_map[pidx]; +} + /** * t4_get_tp_ch_map - return TP ingress channels associated with a port * @adapter: the adapter @@ -6639,13 +6703,14 @@ int t4_fw_initialize(struct adapter *adap, unsigned int mbox) * @params: the parameter names * @val: the parameter values * @rw: Write and read flag + * @sleep_ok: if true, we may sleep awaiting mbox cmd completion * * Reads the value of FW or device parameters. Up to 7 parameters can be * queried at once. */ int t4_query_params_rw(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int nparams, const u32 *params, - u32 *val, int rw) + u32 *val, int rw, bool sleep_ok) { int i, ret; struct fw_params_cmd c; @@ -6668,7 +6733,7 @@ int t4_query_params_rw(struct adapter *adap, unsigned int mbox, unsigned int pf, p++; } - ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); if (ret == 0) for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2) *val++ = be32_to_cpu(*p); @@ -6679,7 +6744,16 @@ int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int nparams, const u32 *params, u32 *val) { - return t4_query_params_rw(adap, mbox, pf, vf, nparams, params, val, 0); + return t4_query_params_rw(adap, mbox, pf, vf, nparams, params, val, 0, + true); +} + +int t4_query_params_ns(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int nparams, const u32 *params, + u32 *val) +{ + return t4_query_params_rw(adap, mbox, pf, vf, nparams, params, val, 0, + false); } /** diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index f47461aa658b..f2ffc1f6b8be 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -1123,6 +1123,7 @@ enum fw_params_param_dev { FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17, FW_PARAMS_PARAM_DEV_FWCACHE = 0x18, FW_PARAMS_PARAM_DEV_RI_FR_NSMR_TPTE_WR = 0x1C, + FW_PARAMS_PARAM_DEV_MPSBGMAP = 0x1E, }; /* -- cgit v1.2.3 From 40bc8b065e8fd3928270481c89d78e317d62cf24 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 23 Jun 2017 10:33:15 -0700 Subject: net: bcmgenet: Remove special handling of "internal" phy-mode The PHY library now supports an "internal" phy-mode, thus making our custom parsing code now unnecessary. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 285676f8da6b..071fcbd14e6a 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -251,11 +251,8 @@ int bcmgenet_mii_config(struct net_device *dev) priv->ext_phy = !priv->internal_phy && (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); - if (priv->internal_phy) - priv->phy_interface = PHY_INTERFACE_MODE_NA; - switch (priv->phy_interface) { - case PHY_INTERFACE_MODE_NA: + case PHY_INTERFACE_MODE_INTERNAL: case PHY_INTERFACE_MODE_MOCA: /* Irrespective of the actually configured PHY speed (100 or * 1000) GENETv4 only has an internal GPHY so we will just end @@ -471,7 +468,6 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) { struct device_node *dn = priv->pdev->dev.of_node; struct device *kdev = &priv->pdev->dev; - const char *phy_mode_str = NULL; struct phy_device *phydev = NULL; char *compat; int phy_mode; @@ -510,23 +506,19 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) /* Get the link mode */ phy_mode = of_get_phy_mode(dn); + if (phy_mode < 0) { + dev_err(kdev, "invalid PHY mode property\n"); + return phy_mode; + } + priv->phy_interface = phy_mode; /* We need to specifically look up whether this PHY interface is internal * or not *before* we even try to probe the PHY driver over MDIO as we * may have shut down the internal PHY for power saving purposes. */ - if (phy_mode < 0) { - ret = of_property_read_string(dn, "phy-mode", &phy_mode_str); - if (ret < 0) { - dev_err(kdev, "invalid PHY mode property\n"); - return ret; - } - - priv->phy_interface = PHY_INTERFACE_MODE_NA; - if (!strcasecmp(phy_mode_str, "internal")) - priv->internal_phy = true; - } + if (priv->phy_interface == PHY_INTERFACE_MODE_INTERNAL) + priv->internal_phy = true; /* Make sure we initialize MoCA PHYs with a link down */ if (phy_mode == PHY_INTERFACE_MODE_MOCA) { -- cgit v1.2.3 From bedd00c81b30a7c5f1fbe144f2db9c9864073b27 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 23 Jun 2017 10:33:16 -0700 Subject: net: dsa: bcm_sf2: Remove special handling of "internal" phy-mode The PHY library now supports an "internal" phy-mode, thus making our custom parsing code now unnecessary. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 76e98e8ed315..648f91b58d1e 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -498,10 +498,8 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, struct device_node *dn) { struct device_node *port; - const char *phy_mode_str; int mode; unsigned int port_num; - int ret; priv->moca_port = -1; @@ -515,15 +513,11 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, * time */ mode = of_get_phy_mode(port); - if (mode < 0) { - ret = of_property_read_string(port, "phy-mode", - &phy_mode_str); - if (ret < 0) - continue; - - if (!strcasecmp(phy_mode_str, "internal")) - priv->int_phy_mask |= 1 << port_num; - } + if (mode < 0) + continue; + + if (mode == PHY_INTERFACE_MODE_INTERNAL) + priv->int_phy_mask |= 1 << port_num; if (mode == PHY_INTERFACE_MODE_MOCA) priv->moca_port = port_num; -- cgit v1.2.3 From 9daee04ae17fb886008ba222fe8150fcc1d0d8cb Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 23 Jun 2017 22:11:59 +0200 Subject: nfp: devlink add support for getting eswitch mode Add app callback for reporting eswitch mode. Non-SRIOV apps should not implement this callback, nfp_app code will then respond with -EOPNOTSUPP. Signed-off-by: Jakub Kicinski Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_app.h | 15 +++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index f5e373fa8c3b..0fee14ffa081 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -34,6 +34,8 @@ #ifndef _NFP_APP_H #define _NFP_APP_H 1 +#include + struct bpf_prog; struct net_device; struct pci_dev; @@ -70,6 +72,7 @@ extern const struct nfp_app_type app_bpf; * @setup_tc: setup TC ndo * @tc_busy: TC HW offload busy (rules loaded) * @xdp_offload: offload an XDP program + * @eswitch_mode_get: get SR-IOV eswitch mode */ struct nfp_app_type { enum nfp_app_id id; @@ -95,6 +98,8 @@ struct nfp_app_type { bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn); int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn, struct bpf_prog *prog); + + enum devlink_eswitch_mode (*eswitch_mode_get)(struct nfp_app *app); }; /** @@ -216,6 +221,16 @@ static inline void nfp_app_ctrl_rx(struct nfp_app *app, struct sk_buff *skb) app->type->ctrl_msg_rx(app, skb); } +static inline int nfp_app_eswitch_mode_get(struct nfp_app *app, u16 *mode) +{ + if (!app->type->eswitch_mode_get) + return -EOPNOTSUPP; + + *mode = app->type->eswitch_mode_get(app); + + return 0; +} + const char *nfp_app_mip_name(struct nfp_app *app); struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index 2609a0f28e81..6c9f29c2e975 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -149,9 +149,27 @@ out: return ret; } +static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) +{ + struct nfp_pf *pf = devlink_priv(devlink); + int ret; + + mutex_lock(&pf->lock); + if (!pf->app) { + ret = -EBUSY; + goto out; + } + ret = nfp_app_eswitch_mode_get(pf->app, mode); +out: + mutex_unlock(&pf->lock); + + return ret; +} + const struct devlink_ops nfp_devlink_ops = { .port_split = nfp_devlink_port_split, .port_unsplit = nfp_devlink_port_unsplit, + .eswitch_mode_get = nfp_devlink_eswitch_mode_get, }; int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port) -- cgit v1.2.3 From a7ceb9905eed38454d28c293afc2f0acb7915d00 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 23 Jun 2017 22:12:00 +0200 Subject: nfp: move physical port init into a helper Move MAC/PHY port init into a helper to make it easier to reuse it in the representor code. Signed-off-by: Jakub Kicinski Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_app_nic.c | 23 ++++++---------------- drivers/net/ethernet/netronome/nfp/nfp_port.c | 25 ++++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_port.h | 3 +++ 3 files changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c index 83c65e6291ee..7b966bd3d214 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c @@ -42,6 +42,8 @@ static int nfp_app_nic_vnic_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, struct nfp_net *nn, unsigned int id) { + int err; + if (!pf->eth_tbl) return 0; @@ -49,26 +51,13 @@ nfp_app_nic_vnic_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, if (IS_ERR(nn->port)) return PTR_ERR(nn->port); - nn->port->eth_id = id; - nn->port->eth_port = nfp_net_find_port(pf->eth_tbl, id); - - /* Check if vNIC has external port associated and cfg is OK */ - if (!nn->port->eth_port) { - nfp_err(app->cpp, - "NSP port entries don't match vNICs (no entry for port #%d)\n", - id); + err = nfp_port_init_phy_port(pf, app, nn->port, id); + if (err) { nfp_port_free(nn->port); - return -EINVAL; - } - if (nn->port->eth_port->override_changed) { - nfp_warn(app->cpp, - "Config changed for port #%d, reboot required before port will be operational\n", - id); - nn->port->type = NFP_PORT_INVALID; - return 1; + return err; } - return 0; + return nn->port->type == NFP_PORT_INVALID; } int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index a17410ac01ab..19bceeb82225 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -33,6 +33,7 @@ #include +#include "nfpcore/nfp_cpp.h" #include "nfpcore/nfp_nsp.h" #include "nfp_app.h" #include "nfp_main.h" @@ -112,6 +113,30 @@ nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len) return 0; } +int nfp_port_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, + struct nfp_port *port, unsigned int id) +{ + port->eth_id = id; + port->eth_port = nfp_net_find_port(pf->eth_tbl, id); + + /* Check if vNIC has external port associated and cfg is OK */ + if (!port->eth_port) { + nfp_err(app->cpp, + "NSP port entries don't match vNICs (no entry for port #%d)\n", + id); + return -EINVAL; + } + if (port->eth_port->override_changed) { + nfp_warn(app->cpp, + "Config changed for port #%d, reboot required before port will be operational\n", + id); + port->type = NFP_PORT_INVALID; + return 0; + } + + return 0; +} + struct nfp_port * nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, struct net_device *netdev) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 4d1a9b3fed41..fb28c7071987 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -104,6 +104,9 @@ nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type, struct net_device *netdev); void nfp_port_free(struct nfp_port *port); +int nfp_port_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, + struct nfp_port *port, unsigned int id); + int nfp_net_refresh_eth_port(struct nfp_port *port); void nfp_net_refresh_port_table(struct nfp_port *port); int nfp_net_refresh_port_table_sync(struct nfp_pf *pf); -- cgit v1.2.3 From a5950182c00eb6d53a68db9f6b6c878f795657f6 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 23 Jun 2017 22:12:01 +0200 Subject: nfp: map mac_stats and vf_cfg BARs If present map mac_stats and vf_cfg BARs. These will be used by representor netdevs to read statistics for phys port and vf representors. Also provide defines describing the layout of the mac_stats area. Similar defines are already present for the cf_cfg area. Based in part on work by Jakub Kicinski. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.h | 8 ++ drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 122 +++++++++++++++------ drivers/net/ethernet/netronome/nfp/nfp_port.h | 60 ++++++++++ .../net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 2 + .../ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c | 5 +- 5 files changed, 164 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 88724f8d0dcd..aa69d4101eb9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -68,6 +68,10 @@ struct nfp_rtsym_table; * @data_vnic_bar: Pointer to the CPP area for the data vNICs' BARs * @ctrl_vnic_bar: Pointer to the CPP area for the ctrl vNIC's BAR * @qc_area: Pointer to the CPP area for the queues + * @mac_stats_bar: Pointer to the CPP area for the MAC stats + * @mac_stats_mem: Pointer to mapped MAC stats area + * @vf_cfg_bar: Pointer to the CPP area for the VF configuration BAR + * @vf_cfg_mem: Pointer to mapped VF configuration area * @irq_entries: Array of MSI-X entries for all vNICs * @limit_vfs: Number of VFs supported by firmware (~0 for PCI limit) * @num_vfs: Number of SR-IOV VFs enabled @@ -97,6 +101,10 @@ struct nfp_pf { struct nfp_cpp_area *data_vnic_bar; struct nfp_cpp_area *ctrl_vnic_bar; struct nfp_cpp_area *qc_area; + struct nfp_cpp_area *mac_stats_bar; + u8 __iomem *mac_stats_mem; + struct nfp_cpp_area *vf_cfg_bar; + u8 __iomem *vf_cfg_mem; struct msix_entry *irq_entries; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index bc2bc0886176..911b764d7641 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -235,10 +235,8 @@ nfp_net_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt, nfp_cppcore_pcie_unit(pf->cpp)); sym = nfp_rtsym_lookup(pf->rtbl, pf_symbol); - if (!sym) { - nfp_err(pf->cpp, "Failed to find PF symbol %s\n", pf_symbol); + if (!sym) return (u8 __iomem *)ERR_PTR(-ENOENT); - } if (sym->size < min_size) { nfp_err(pf->cpp, "PF symbol %s too small\n", pf_symbol); @@ -486,6 +484,7 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride) NFP_PF_CSR_SLICE_SIZE, &pf->ctrl_vnic_bar); if (IS_ERR(ctrl_bar)) { + nfp_err(pf->cpp, "Failed to find data vNIC memory symbol\n"); err = PTR_ERR(ctrl_bar); goto err_free; } @@ -570,6 +569,80 @@ static void nfp_net_pf_app_stop(struct nfp_pf *pf) nfp_net_pf_app_stop_ctrl(pf); } +static void nfp_net_pci_unmap_mem(struct nfp_pf *pf) +{ + if (pf->vf_cfg_bar) + nfp_cpp_area_release_free(pf->vf_cfg_bar); + if (pf->mac_stats_bar) + nfp_cpp_area_release_free(pf->mac_stats_bar); + nfp_cpp_area_release_free(pf->qc_area); + nfp_cpp_area_release_free(pf->data_vnic_bar); +} + +static int nfp_net_pci_map_mem(struct nfp_pf *pf) +{ + u32 ctrl_bar_sz; + u8 __iomem *mem; + int err; + + ctrl_bar_sz = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE; + mem = nfp_net_pf_map_rtsym(pf, "net.ctrl", "_pf%d_net_bar0", + ctrl_bar_sz, &pf->data_vnic_bar); + if (IS_ERR(mem)) { + nfp_err(pf->cpp, "Failed to find data vNIC memory symbol\n"); + err = PTR_ERR(mem); + if (!pf->fw_loaded && err == -ENOENT) + err = -EPROBE_DEFER; + return err; + } + + pf->mac_stats_mem = nfp_net_pf_map_rtsym(pf, "net.macstats", + "_mac_stats", + NFP_MAC_STATS_SIZE * + (pf->eth_tbl->max_index + 1), + &pf->mac_stats_bar); + if (IS_ERR(pf->mac_stats_mem)) { + if (PTR_ERR(pf->mac_stats_mem) != -ENOENT) { + err = PTR_ERR(pf->mac_stats_mem); + goto err_unmap_ctrl; + } + pf->mac_stats_mem = NULL; + } + + pf->vf_cfg_mem = nfp_net_pf_map_rtsym(pf, "net.vfcfg", + "_pf%d_net_vf_bar", + NFP_NET_CFG_BAR_SZ * + pf->limit_vfs, &pf->vf_cfg_bar); + if (IS_ERR(pf->vf_cfg_mem)) { + if (PTR_ERR(pf->vf_cfg_mem) != -ENOENT) { + err = PTR_ERR(pf->vf_cfg_mem); + goto err_unmap_mac_stats; + } + pf->vf_cfg_mem = NULL; + } + + mem = nfp_net_map_area(pf->cpp, "net.qc", 0, 0, + NFP_PCIE_QUEUE(0), NFP_QCP_QUEUE_AREA_SZ, + &pf->qc_area); + if (IS_ERR(mem)) { + nfp_err(pf->cpp, "Failed to map Queue Controller area.\n"); + err = PTR_ERR(mem); + goto err_unmap_vf_cfg; + } + + return 0; + +err_unmap_vf_cfg: + if (pf->vf_cfg_bar) + nfp_cpp_area_release_free(pf->vf_cfg_bar); +err_unmap_mac_stats: + if (pf->mac_stats_bar) + nfp_cpp_area_release_free(pf->mac_stats_bar); +err_unmap_ctrl: + nfp_cpp_area_release_free(pf->data_vnic_bar); + return err; +} + static void nfp_net_pci_remove_finish(struct nfp_pf *pf) { nfp_net_pf_app_stop(pf); @@ -577,11 +650,8 @@ static void nfp_net_pci_remove_finish(struct nfp_pf *pf) nfp_net_debugfs_dir_clean(&pf->ddir); nfp_net_pf_free_irqs(pf); - nfp_net_pf_app_clean(pf); - - nfp_cpp_area_release_free(pf->qc_area); - nfp_cpp_area_release_free(pf->data_vnic_bar); + nfp_net_pci_unmap_mem(pf); } static int @@ -706,7 +776,6 @@ int nfp_net_pci_probe(struct nfp_pf *pf) { struct nfp_net_fw_version fw_ver; u8 __iomem *ctrl_bar, *qc_bar; - u32 ctrl_bar_sz; int stride; int err; @@ -725,14 +794,15 @@ int nfp_net_pci_probe(struct nfp_pf *pf) goto err_unlock; } - ctrl_bar_sz = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE; - ctrl_bar = nfp_net_pf_map_rtsym(pf, "net.ctrl", "_pf%d_net_bar0", - ctrl_bar_sz, &pf->data_vnic_bar); - if (IS_ERR(ctrl_bar)) { - err = PTR_ERR(ctrl_bar); - if (!pf->fw_loaded && err == -ENOENT) - err = -EPROBE_DEFER; + err = nfp_net_pci_map_mem(pf); + if (err) goto err_unlock; + + ctrl_bar = nfp_cpp_area_iomem(pf->data_vnic_bar); + qc_bar = nfp_cpp_area_iomem(pf->qc_area); + if (!ctrl_bar || !qc_bar) { + err = -EIO; + goto err_unmap; } nfp_net_get_fw_version(&fw_ver, ctrl_bar); @@ -740,7 +810,7 @@ int nfp_net_pci_probe(struct nfp_pf *pf) nfp_err(pf->cpp, "Unknown Firmware ABI %d.%d.%d.%d\n", fw_ver.resv, fw_ver.class, fw_ver.major, fw_ver.minor); err = -EINVAL; - goto err_ctrl_unmap; + goto err_unmap; } /* Determine stride */ @@ -757,23 +827,13 @@ int nfp_net_pci_probe(struct nfp_pf *pf) fw_ver.resv, fw_ver.class, fw_ver.major, fw_ver.minor); err = -EINVAL; - goto err_ctrl_unmap; + goto err_unmap; } } - /* Map queues */ - qc_bar = nfp_net_map_area(pf->cpp, "net.qc", 0, 0, - NFP_PCIE_QUEUE(0), NFP_QCP_QUEUE_AREA_SZ, - &pf->qc_area); - if (IS_ERR(qc_bar)) { - nfp_err(pf->cpp, "Failed to map Queue Controller area.\n"); - err = PTR_ERR(qc_bar); - goto err_ctrl_unmap; - } - err = nfp_net_pf_app_init(pf, qc_bar, stride); if (err) - goto err_unmap_qc; + goto err_unmap; pf->ddir = nfp_net_debugfs_device_add(pf->pdev); @@ -807,10 +867,8 @@ err_free_vnics: err_clean_ddir: nfp_net_debugfs_dir_clean(&pf->ddir); nfp_net_pf_app_clean(pf); -err_unmap_qc: - nfp_cpp_area_release_free(pf->qc_area); -err_ctrl_unmap: - nfp_cpp_area_release_free(pf->data_vnic_bar); +err_unmap: + nfp_net_pci_unmap_mem(pf); err_unlock: mutex_unlock(&pf->lock); cancel_work_sync(&pf->port_refresh_work); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index fb28c7071987..f472bea4ec2b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -114,4 +114,64 @@ int nfp_net_refresh_port_table_sync(struct nfp_pf *pf); int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port); void nfp_devlink_port_unregister(struct nfp_port *port); +/** + * Mac stats (0x0000 - 0x0200) + * all counters are 64bit. + */ +#define NFP_MAC_STATS_BASE 0x0000 +#define NFP_MAC_STATS_SIZE 0x0200 + +#define NFP_MAC_STATS_RX_IN_OCTETS (NFP_MAC_STATS_BASE + 0x000) +#define NFP_MAC_STATS_RX_FRAME_TOO_LONG_ERRORS (NFP_MAC_STATS_BASE + 0x010) +#define NFP_MAC_STATS_RX_RANGE_LENGTH_ERRORS (NFP_MAC_STATS_BASE + 0x018) +#define NFP_MAC_STATS_RX_VLAN_REVEIVE_OK (NFP_MAC_STATS_BASE + 0x020) +#define NFP_MAC_STATS_RX_IN_ERRORS (NFP_MAC_STATS_BASE + 0x028) +#define NFP_MAC_STATS_RX_IN_BROADCAST_PKTS (NFP_MAC_STATS_BASE + 0x030) +#define NFP_MAC_STATS_RX_STATS_DROP_EVENTS (NFP_MAC_STATS_BASE + 0x038) +#define NFP_MAC_STATS_RX_ALIGNMENT_ERRORS (NFP_MAC_STATS_BASE + 0x040) +#define NFP_MAC_STATS_RX_PAUSE_MAC_CTRL_FRAMES (NFP_MAC_STATS_BASE + 0x048) +#define NFP_MAC_STATS_RX_FRAMES_RECEIVED_OK (NFP_MAC_STATS_BASE + 0x050) +#define NFP_MAC_STATS_RX_FRAME_CHECK_SEQUENCE_ERRORS (NFP_MAC_STATS_BASE + 0x058) +#define NFP_MAC_STATS_RX_UNICAST_PKTS (NFP_MAC_STATS_BASE + 0x060) +#define NFP_MAC_STATS_RX_MULTICAST_PKTS (NFP_MAC_STATS_BASE + 0x068) +#define NFP_MAC_STATS_RX_STATS_PKTS (NFP_MAC_STATS_BASE + 0x070) +#define NFP_MAC_STATS_RX_STATS_UNDERSIZE_PKTS (NFP_MAC_STATS_BASE + 0x078) +#define NFP_MAC_STATS_RX_STATS_PKTS_64_OCTETS (NFP_MAC_STATS_BASE + 0x080) +#define NFP_MAC_STATS_RX_STATS_PKTS_65_TO_127_OCTETS (NFP_MAC_STATS_BASE + 0x088) +#define NFP_MAC_STATS_RX_STATS_PKTS_512_TO_1023_OCTETS (NFP_MAC_STATS_BASE + 0x090) +#define NFP_MAC_STATS_RX_STATS_PKTS_1024_TO_1518_OCTETS (NFP_MAC_STATS_BASE + 0x098) +#define NFP_MAC_STATS_RX_STATS_JABBERS (NFP_MAC_STATS_BASE + 0x0a0) +#define NFP_MAC_STATS_RX_STATS_FRAGMENTS (NFP_MAC_STATS_BASE + 0x0a8) +#define NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS2 (NFP_MAC_STATS_BASE + 0x0b0) +#define NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS3 (NFP_MAC_STATS_BASE + 0x0b8) +#define NFP_MAC_STATS_RX_STATS_PKTS_128_TO_255_OCTETS (NFP_MAC_STATS_BASE + 0x0c0) +#define NFP_MAC_STATS_RX_STATS_PKTS_256_TO_511_OCTETS (NFP_MAC_STATS_BASE + 0x0c8) +#define NFP_MAC_STATS_RX_STATS_PKTS_1519_TO_MAX_OCTETS (NFP_MAC_STATS_BASE + 0x0d0) +#define NFP_MAC_STATS_RX_OVERSIZE_PKTS (NFP_MAC_STATS_BASE + 0x0d8) +#define NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS0 (NFP_MAC_STATS_BASE + 0x0e0) +#define NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS1 (NFP_MAC_STATS_BASE + 0x0e8) +#define NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS4 (NFP_MAC_STATS_BASE + 0x0f0) +#define NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS5 (NFP_MAC_STATS_BASE + 0x0f8) +#define NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS6 (NFP_MAC_STATS_BASE + 0x100) +#define NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS7 (NFP_MAC_STATS_BASE + 0x108) +#define NFP_MAC_STATS_RX_MAC_CTRL_FRAMES_RECEIVED (NFP_MAC_STATS_BASE + 0x110) +#define NFP_MAC_STATS_RX_MAC_HEAD_DROP (NFP_MAC_STATS_BASE + 0x118) + +#define NFP_MAC_STATS_TX_QUEUE_DROP (NFP_MAC_STATS_BASE + 0x138) +#define NFP_MAC_STATS_TX_OUT_OCTETS (NFP_MAC_STATS_BASE + 0x140) +#define NFP_MAC_STATS_TX_VLAN_TRANSMITTED_OK (NFP_MAC_STATS_BASE + 0x150) +#define NFP_MAC_STATS_TX_OUT_ERRORS (NFP_MAC_STATS_BASE + 0x158) +#define NFP_MAC_STATS_TX_BROADCAST_PKTS (NFP_MAC_STATS_BASE + 0x160) +#define NFP_MAC_STATS_TX_PKTS_64_OCTETS (NFP_MAC_STATS_BASE + 0x168) +#define NFP_MAC_STATS_TX_PKTS_256_TO_511_OCTETS (NFP_MAC_STATS_BASE + 0x170) +#define NFP_MAC_STATS_TX_PKTS_512_TO_1023_OCTETS (NFP_MAC_STATS_BASE + 0x178) +#define NFP_MAC_STATS_TX_PAUSE_MAC_CTRL_FRAMES (NFP_MAC_STATS_BASE + 0x180) +#define NFP_MAC_STATS_TX_FRAMES_TRANSMITTED_OK (NFP_MAC_STATS_BASE + 0x188) +#define NFP_MAC_STATS_TX_UNICAST_PKTS (NFP_MAC_STATS_BASE + 0x190) +#define NFP_MAC_STATS_TX_MULTICAST_PKTS (NFP_MAC_STATS_BASE + 0x198) +#define NFP_MAC_STATS_TX_PKTS_65_TO_127_OCTETS (NFP_MAC_STATS_BASE + 0x1a0) +#define NFP_MAC_STATS_TX_PKTS_127_TO_512_OCTETS (NFP_MAC_STATS_BASE + 0x1a8) +#define NFP_MAC_STATS_TX_PKTS_128_TO_1518_OCTETS (NFP_MAC_STATS_BASE + 0x1b0) +#define NFP_MAC_STATS_TX_PKTS_1518_TO_MAX_OCTETS (NFP_MAC_STATS_BASE + 0x1b8) + #endif diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index 26d7dcea4fd9..e2f028027c6f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -76,6 +76,7 @@ enum nfp_eth_aneg { /** * struct nfp_eth_table - ETH table information * @count: number of table entries + * @max_index: max of @index fields of all @ports * @ports: table of ports * * @eth_index: port index according to legacy ethX numbering @@ -101,6 +102,7 @@ enum nfp_eth_aneg { */ struct nfp_eth_table { unsigned int count; + unsigned int max_index; struct nfp_eth_table_port { unsigned int eth_index; unsigned int index; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c index b0f8785c064f..c2bc36e8649f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c @@ -190,7 +190,9 @@ nfp_eth_calc_port_geometry(struct nfp_cpp *cpp, struct nfp_eth_table *table) { unsigned int i, j; - for (i = 0; i < table->count; i++) + for (i = 0; i < table->count; i++) { + table->max_index = max(table->max_index, table->ports[i].index); + for (j = 0; j < table->count; j++) { if (table->ports[i].label_port != table->ports[j].label_port) @@ -208,6 +210,7 @@ nfp_eth_calc_port_geometry(struct nfp_cpp *cpp, struct nfp_eth_table *table) table->ports[i].is_split = true; } + } } static void -- cgit v1.2.3 From 5de73ee46704c22097e46bfc276a05360d3a1ba7 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 23 Jun 2017 22:12:02 +0200 Subject: nfp: general representor implementation Provide infrastructure to create and destroy representors of a given type. Parts based on work by Bert van Leeuwen, Benjamin LaHaise, and Jakub Kicinski. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 1 + drivers/net/ethernet/netronome/nfp/nfp_app.c | 20 +++ drivers/net/ethernet/netronome/nfp/nfp_app.h | 18 +++ drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 156 ++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_net_repr.h | 92 +++++++++++++ 5 files changed, 287 insertions(+) create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_net_repr.c create mode 100644 drivers/net/ethernet/netronome/nfp/nfp_net_repr.h (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 5ad9a557f06a..a401113035f5 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -22,6 +22,7 @@ nfp-objs := \ nfp_net_common.o \ nfp_net_ethtool.o \ nfp_net_main.o \ + nfp_net_repr.o \ nfp_netvf_main.o \ nfp_port.o \ bpf/main.o \ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index 396b93f54823..c9ccb0f94604 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -38,6 +38,7 @@ #include "nfpcore/nfp_nffw.h" #include "nfp_app.h" #include "nfp_main.h" +#include "nfp_net_repr.h" static const struct nfp_app_type *apps[] = { &app_nic, @@ -68,6 +69,25 @@ struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size) return skb; } +struct nfp_reprs * +nfp_app_reprs_set(struct nfp_app *app, enum nfp_repr_type type, + struct nfp_reprs *reprs) +{ + struct nfp_reprs *old; + + old = rcu_dereference_protected(app->reprs[type], + lockdep_is_held(&app->pf->lock)); + if (reprs && old) { + old = ERR_PTR(-EBUSY); + goto exit_unlock; + } + + rcu_assign_pointer(app->reprs[type], reprs); + +exit_unlock: + return old; +} + struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id) { struct nfp_app *app; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index 0fee14ffa081..af023a0491e7 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -36,6 +36,8 @@ #include +#include "nfp_net_repr.h" + struct bpf_prog; struct net_device; struct pci_dev; @@ -73,6 +75,7 @@ extern const struct nfp_app_type app_bpf; * @tc_busy: TC HW offload busy (rules loaded) * @xdp_offload: offload an XDP program * @eswitch_mode_get: get SR-IOV eswitch mode + * @repr_get: get representor netdev */ struct nfp_app_type { enum nfp_app_id id; @@ -100,6 +103,7 @@ struct nfp_app_type { struct bpf_prog *prog); enum devlink_eswitch_mode (*eswitch_mode_get)(struct nfp_app *app); + struct net_device *(*repr_get)(struct nfp_app *app, u32 id); }; /** @@ -108,6 +112,7 @@ struct nfp_app_type { * @pf: backpointer to NFP PF structure * @cpp: pointer to the CPP handle * @ctrl: pointer to ctrl vNIC struct + * @reprs: array of pointers to representors * @type: pointer to const application ops and info */ struct nfp_app { @@ -116,6 +121,7 @@ struct nfp_app { struct nfp_cpp *cpp; struct nfp_net *ctrl; + struct nfp_reprs __rcu *reprs[NFP_REPR_TYPE_MAX + 1]; const struct nfp_app_type *type; }; @@ -231,6 +237,18 @@ static inline int nfp_app_eswitch_mode_get(struct nfp_app *app, u16 *mode) return 0; } +static inline struct net_device *nfp_app_repr_get(struct nfp_app *app, u32 id) +{ + if (unlikely(!app || !app->type->repr_get)) + return NULL; + + return app->type->repr_get(app, id); +} + +struct nfp_reprs * +nfp_app_reprs_set(struct nfp_app *app, enum nfp_repr_type type, + struct nfp_reprs *reprs); + const char *nfp_app_mip_name(struct nfp_app *app); struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c new file mode 100644 index 000000000000..8e02f843ae92 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "nfpcore/nfp_cpp.h" +#include "nfp_app.h" +#include "nfp_main.h" +#include "nfp_net_repr.h" +#include "nfp_port.h" + +static void nfp_repr_clean(struct nfp_repr *repr) +{ + unregister_netdev(repr->netdev); + dst_release((struct dst_entry *)repr->dst); + nfp_port_free(repr->port); +} + +static struct lock_class_key nfp_repr_netdev_xmit_lock_key; +static struct lock_class_key nfp_repr_netdev_addr_lock_key; + +static void nfp_repr_set_lockdep_class_one(struct net_device *dev, + struct netdev_queue *txq, + void *_unused) +{ + lockdep_set_class(&txq->_xmit_lock, &nfp_repr_netdev_xmit_lock_key); +} + +static void nfp_repr_set_lockdep_class(struct net_device *dev) +{ + lockdep_set_class(&dev->addr_list_lock, &nfp_repr_netdev_addr_lock_key); + netdev_for_each_tx_queue(dev, nfp_repr_set_lockdep_class_one, NULL); +} + +int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, + const struct net_device_ops *netdev_ops, u32 cmsg_port_id, + struct nfp_port *port, struct net_device *pf_netdev) +{ + struct nfp_repr *repr = netdev_priv(netdev); + int err; + + nfp_repr_set_lockdep_class(netdev); + + repr->port = port; + repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, GFP_KERNEL); + if (!repr->dst) + return -ENOMEM; + repr->dst->u.port_info.port_id = cmsg_port_id; + repr->dst->u.port_info.lower_dev = pf_netdev; + + netdev->netdev_ops = netdev_ops; + + err = register_netdev(netdev); + if (err) + goto err_clean; + + return 0; + +err_clean: + dst_release((struct dst_entry *)repr->dst); + return err; +} + +struct net_device *nfp_repr_alloc(struct nfp_app *app) +{ + struct net_device *netdev; + struct nfp_repr *repr; + + netdev = alloc_etherdev(sizeof(*repr)); + if (!netdev) + return NULL; + + repr = netdev_priv(netdev); + repr->netdev = netdev; + repr->app = app; + + return netdev; +} + +static void nfp_repr_clean_and_free(struct nfp_repr *repr) +{ + nfp_info(repr->app->cpp, "Destroying Representor(%s)\n", + repr->netdev->name); + nfp_repr_clean(repr); + free_netdev(repr->netdev); +} + +void nfp_reprs_clean_and_free(struct nfp_reprs *reprs) +{ + unsigned int i; + + for (i = 0; i < reprs->num_reprs; i++) + if (reprs->reprs[i]) + nfp_repr_clean_and_free(netdev_priv(reprs->reprs[i])); + + kfree(reprs); +} + +void +nfp_reprs_clean_and_free_by_type(struct nfp_app *app, + enum nfp_repr_type type) +{ + struct nfp_reprs *reprs; + + reprs = nfp_app_reprs_set(app, type, NULL); + if (!reprs) + return; + + synchronize_rcu(); + nfp_reprs_clean_and_free(reprs); +} + +struct nfp_reprs *nfp_reprs_alloc(unsigned int num_reprs) +{ + struct nfp_reprs *reprs; + + reprs = kzalloc(sizeof(*reprs) + + num_reprs * sizeof(struct net_device *), GFP_KERNEL); + if (!reprs) + return NULL; + reprs->num_reprs = num_reprs; + + return reprs; +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h new file mode 100644 index 000000000000..98064f3c2623 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef NFP_NET_REPR_H +#define NFP_NET_REPR_H + +struct metadata_dst; +struct nfp_net; +struct nfp_port; + +/** + * struct nfp_reprs - container for representor netdevs + * @num_reprs: Number of elements in reprs array + * @reprs: Array of representor netdevs + */ +struct nfp_reprs { + unsigned int num_reprs; + struct net_device *reprs[0]; +}; + +/** + * struct nfp_repr - priv data for representor netdevs + * @netdev: Back pointer to netdev + * @dst: Destination for packet TX + * @port: Port of representor + * @app: APP handle + */ +struct nfp_repr { + struct net_device *netdev; + struct metadata_dst *dst; + struct nfp_port *port; + struct nfp_app *app; +}; + +/** + * enum nfp_repr_type - type of representor + * @NFP_REPR_TYPE_PHYS_PORT: external NIC port + * @NFP_REPR_TYPE_PF: physical function + * @NFP_REPR_TYPE_VF: virtual function + */ +enum nfp_repr_type { + NFP_REPR_TYPE_PHYS_PORT, + NFP_REPR_TYPE_PF, + NFP_REPR_TYPE_VF, + + __NFP_REPR_TYPE_MAX, +}; +#define NFP_REPR_TYPE_MAX (__NFP_REPR_TYPE_MAX - 1) + +int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, + const struct net_device_ops *netdev_ops, + u32 cmsg_port_id, struct nfp_port *port, + struct net_device *pf_netdev); +struct net_device *nfp_repr_alloc(struct nfp_app *app); +void +nfp_reprs_clean_and_free(struct nfp_reprs *reprs); +void +nfp_reprs_clean_and_free_by_type(struct nfp_app *app, + enum nfp_repr_type type); +struct nfp_reprs *nfp_reprs_alloc(unsigned int num_reprs); + +#endif /* NFP_NET_REPR_H */ -- cgit v1.2.3 From eadfa4c3be99eaf15670681e6ffa4d995b73594c Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 23 Jun 2017 22:12:03 +0200 Subject: nfp: add stats and xmit helpers for representors Provide helpers for stats and xmit on representor netdevs. Parts based on work by Bert van Leeuwen, Benjamin LaHaise and Jakub Kicinski. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 199 +++++++++++++++++++++- drivers/net/ethernet/netronome/nfp/nfp_net_repr.h | 28 +++ 2 files changed, 226 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 8e02f843ae92..44adcc5df11e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -32,15 +32,198 @@ */ #include +#include #include #include #include "nfpcore/nfp_cpp.h" #include "nfp_app.h" #include "nfp_main.h" +#include "nfp_net_ctrl.h" #include "nfp_net_repr.h" #include "nfp_port.h" +static void +nfp_repr_inc_tx_stats(struct net_device *netdev, unsigned int len, + int tx_status) +{ + struct nfp_repr *repr = netdev_priv(netdev); + struct nfp_repr_pcpu_stats *stats; + + if (unlikely(tx_status != NET_XMIT_SUCCESS && + tx_status != NET_XMIT_CN)) { + this_cpu_inc(repr->stats->tx_drops); + return; + } + + stats = this_cpu_ptr(repr->stats); + u64_stats_update_begin(&stats->syncp); + stats->tx_packets++; + stats->tx_bytes += len; + u64_stats_update_end(&stats->syncp); +} + +void nfp_repr_inc_rx_stats(struct net_device *netdev, unsigned int len) +{ + struct nfp_repr *repr = netdev_priv(netdev); + struct nfp_repr_pcpu_stats *stats; + + stats = this_cpu_ptr(repr->stats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += len; + u64_stats_update_end(&stats->syncp); +} + +static void +nfp_repr_phy_port_get_stats64(const struct nfp_app *app, u8 phy_port, + struct rtnl_link_stats64 *stats) +{ + u8 __iomem *mem; + + mem = app->pf->mac_stats_mem + phy_port * NFP_MAC_STATS_SIZE; + + /* TX and RX stats are flipped as we are returning the stats as seen + * at the switch port corresponding to the phys port. + */ + stats->tx_packets = readq(mem + NFP_MAC_STATS_RX_FRAMES_RECEIVED_OK); + stats->tx_bytes = readq(mem + NFP_MAC_STATS_RX_IN_OCTETS); + stats->tx_dropped = readq(mem + NFP_MAC_STATS_RX_IN_ERRORS); + + stats->rx_packets = readq(mem + NFP_MAC_STATS_TX_FRAMES_TRANSMITTED_OK); + stats->rx_bytes = readq(mem + NFP_MAC_STATS_TX_OUT_OCTETS); + stats->rx_dropped = readq(mem + NFP_MAC_STATS_TX_OUT_ERRORS); +} + +static void +nfp_repr_vf_get_stats64(const struct nfp_app *app, u8 vf, + struct rtnl_link_stats64 *stats) +{ + u8 __iomem *mem; + + mem = app->pf->vf_cfg_mem + vf * NFP_NET_CFG_BAR_SZ; + + /* TX and RX stats are flipped as we are returning the stats as seen + * at the switch port corresponding to the VF. + */ + stats->tx_packets = readq(mem + NFP_NET_CFG_STATS_RX_FRAMES); + stats->tx_bytes = readq(mem + NFP_NET_CFG_STATS_RX_OCTETS); + stats->tx_dropped = readq(mem + NFP_NET_CFG_STATS_RX_DISCARDS); + + stats->rx_packets = readq(mem + NFP_NET_CFG_STATS_TX_FRAMES); + stats->rx_bytes = readq(mem + NFP_NET_CFG_STATS_TX_OCTETS); + stats->rx_dropped = readq(mem + NFP_NET_CFG_STATS_TX_DISCARDS); +} + +static void +nfp_repr_pf_get_stats64(const struct nfp_app *app, u8 pf, + struct rtnl_link_stats64 *stats) +{ + u8 __iomem *mem; + + if (pf) + return; + + mem = nfp_cpp_area_iomem(app->pf->data_vnic_bar); + + stats->tx_packets = readq(mem + NFP_NET_CFG_STATS_RX_FRAMES); + stats->tx_bytes = readq(mem + NFP_NET_CFG_STATS_RX_OCTETS); + stats->tx_dropped = readq(mem + NFP_NET_CFG_STATS_RX_DISCARDS); + + stats->rx_packets = readq(mem + NFP_NET_CFG_STATS_TX_FRAMES); + stats->rx_bytes = readq(mem + NFP_NET_CFG_STATS_TX_OCTETS); + stats->rx_dropped = readq(mem + NFP_NET_CFG_STATS_TX_DISCARDS); +} + +void +nfp_repr_get_stats64(const struct nfp_app *app, enum nfp_repr_type type, + u8 port, struct rtnl_link_stats64 *stats) +{ + switch (type) { + case NFP_REPR_TYPE_PHYS_PORT: + nfp_repr_phy_port_get_stats64(app, port, stats); + break; + case NFP_REPR_TYPE_PF: + nfp_repr_pf_get_stats64(app, port, stats); + break; + case NFP_REPR_TYPE_VF: + nfp_repr_vf_get_stats64(app, port, stats); + default: + break; + } +} + +bool +nfp_repr_has_offload_stats(const struct net_device *dev, int attr_id) +{ + switch (attr_id) { + case IFLA_OFFLOAD_XSTATS_CPU_HIT: + return true; + } + + return false; +} + +static int +nfp_repr_get_host_stats64(const struct net_device *netdev, + struct rtnl_link_stats64 *stats) +{ + struct nfp_repr *repr = netdev_priv(netdev); + int i; + + for_each_possible_cpu(i) { + u64 tbytes, tpkts, tdrops, rbytes, rpkts; + struct nfp_repr_pcpu_stats *repr_stats; + unsigned int start; + + repr_stats = per_cpu_ptr(repr->stats, i); + do { + start = u64_stats_fetch_begin_irq(&repr_stats->syncp); + tbytes = repr_stats->tx_bytes; + tpkts = repr_stats->tx_packets; + tdrops = repr_stats->tx_drops; + rbytes = repr_stats->rx_bytes; + rpkts = repr_stats->rx_packets; + } while (u64_stats_fetch_retry_irq(&repr_stats->syncp, start)); + + stats->tx_bytes += tbytes; + stats->tx_packets += tpkts; + stats->tx_dropped += tdrops; + stats->rx_bytes += rbytes; + stats->rx_packets += rpkts; + } + + return 0; +} + +int nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev, + void *stats) +{ + switch (attr_id) { + case IFLA_OFFLOAD_XSTATS_CPU_HIT: + return nfp_repr_get_host_stats64(dev, stats); + } + + return -EINVAL; +} + +netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct nfp_repr *repr = netdev_priv(netdev); + unsigned int len = skb->len; + int ret; + + skb_dst_drop(skb); + dst_hold((struct dst_entry *)repr->dst); + skb_dst_set(skb, (struct dst_entry *)repr->dst); + skb->dev = repr->dst->u.port_info.lower_dev; + + ret = dev_queue_xmit(skb); + nfp_repr_inc_tx_stats(netdev, len, ret); + + return ret; +} + static void nfp_repr_clean(struct nfp_repr *repr) { unregister_netdev(repr->netdev); @@ -93,6 +276,12 @@ err_clean: return err; } +static void nfp_repr_free(struct nfp_repr *repr) +{ + free_percpu(repr->stats); + free_netdev(repr->netdev); +} + struct net_device *nfp_repr_alloc(struct nfp_app *app) { struct net_device *netdev; @@ -106,7 +295,15 @@ struct net_device *nfp_repr_alloc(struct nfp_app *app) repr->netdev = netdev; repr->app = app; + repr->stats = netdev_alloc_pcpu_stats(struct nfp_repr_pcpu_stats); + if (!repr->stats) + goto err_free_netdev; + return netdev; + +err_free_netdev: + free_netdev(netdev); + return NULL; } static void nfp_repr_clean_and_free(struct nfp_repr *repr) @@ -114,7 +311,7 @@ static void nfp_repr_clean_and_free(struct nfp_repr *repr) nfp_info(repr->app->cpp, "Destroying Representor(%s)\n", repr->netdev->name); nfp_repr_clean(repr); - free_netdev(repr->netdev); + nfp_repr_free(repr); } void nfp_reprs_clean_and_free(struct nfp_reprs *reprs) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h index 98064f3c2623..c5ed6611f708 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h @@ -48,18 +48,38 @@ struct nfp_reprs { struct net_device *reprs[0]; }; +/** + * struct nfp_repr_pcpu_stats + * @rx_packets: Received packets + * @rx_bytes: Received bytes + * @tx_packets: Transmitted packets + * @tx_bytes: Transmitted dropped + * @tx_drops: Packets dropped on transmit + * @syncp: Reference count + */ +struct nfp_repr_pcpu_stats { + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + u64 tx_drops; + struct u64_stats_sync syncp; +}; + /** * struct nfp_repr - priv data for representor netdevs * @netdev: Back pointer to netdev * @dst: Destination for packet TX * @port: Port of representor * @app: APP handle + * @stats: Statistic of packets hitting CPU */ struct nfp_repr { struct net_device *netdev; struct metadata_dst *dst; struct nfp_port *port; struct nfp_app *app; + struct nfp_repr_pcpu_stats __percpu *stats; }; /** @@ -77,6 +97,14 @@ enum nfp_repr_type { }; #define NFP_REPR_TYPE_MAX (__NFP_REPR_TYPE_MAX - 1) +void nfp_repr_inc_rx_stats(struct net_device *netdev, unsigned int len); +void +nfp_repr_get_stats64(const struct nfp_app *app, enum nfp_repr_type type, + u8 port, struct rtnl_link_stats64 *stats); +bool nfp_repr_has_offload_stats(const struct net_device *dev, int attr_id); +int nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev, + void *stats); +netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev); int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, const struct net_device_ops *netdev_ops, u32 cmsg_port_id, struct nfp_port *port, -- cgit v1.2.3 From 758238f2e7a645630c3fead7577c3fa5a36c6ad7 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 23 Jun 2017 22:12:04 +0200 Subject: nfp: app callbacks for SRIOV Add app-callbacks for app-specific initialisation of SRIOV. Disabling SRIOV is brought forward in nfp_pci_remove() so that nfp_app_sriov_disable is called while the app still exists. This is intended to be used to implement representor netdevs for virtual ports. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_app.h | 18 ++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_main.c | 42 +++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index af023a0491e7..ff2d43615808 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -75,6 +75,8 @@ extern const struct nfp_app_type app_bpf; * @tc_busy: TC HW offload busy (rules loaded) * @xdp_offload: offload an XDP program * @eswitch_mode_get: get SR-IOV eswitch mode + * @sriov_enable: app-specific sriov initialisation + * @sriov_disable: app-specific sriov clean-up * @repr_get: get representor netdev */ struct nfp_app_type { @@ -102,6 +104,9 @@ struct nfp_app_type { int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn, struct bpf_prog *prog); + int (*sriov_enable)(struct nfp_app *app, int num_vfs); + void (*sriov_disable)(struct nfp_app *app); + enum devlink_eswitch_mode (*eswitch_mode_get)(struct nfp_app *app); struct net_device *(*repr_get)(struct nfp_app *app, u32 id); }; @@ -237,6 +242,19 @@ static inline int nfp_app_eswitch_mode_get(struct nfp_app *app, u16 *mode) return 0; } +static inline int nfp_app_sriov_enable(struct nfp_app *app, int num_vfs) +{ + if (!app || !app->type->sriov_enable) + return -EOPNOTSUPP; + return app->type->sriov_enable(app, num_vfs); +} + +static inline void nfp_app_sriov_disable(struct nfp_app *app) +{ + if (app && app->type->sriov_disable) + app->type->sriov_disable(app); +} + static inline struct net_device *nfp_app_repr_get(struct nfp_app *app, u32 id) { if (unlikely(!app || !app->type->repr_get)) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 4e59dcb78c36..748e54cc885e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -54,6 +54,7 @@ #include "nfpcore/nfp6000_pcie.h" +#include "nfp_app.h" #include "nfp_main.h" #include "nfp_net.h" @@ -97,28 +98,45 @@ static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs) struct nfp_pf *pf = pci_get_drvdata(pdev); int err; + mutex_lock(&pf->lock); + if (num_vfs > pf->limit_vfs) { nfp_info(pf->cpp, "Firmware limits number of VFs to %u\n", pf->limit_vfs); - return -EINVAL; + err = -EINVAL; + goto err_unlock; + } + + err = nfp_app_sriov_enable(pf->app, num_vfs); + if (err) { + dev_warn(&pdev->dev, "App specific PCI sriov configuration failed: %d\n", + err); + goto err_unlock; } err = pci_enable_sriov(pdev, num_vfs); if (err) { dev_warn(&pdev->dev, "Failed to enable PCI sriov: %d\n", err); - return err; + goto err_app_sriov_disable; } pf->num_vfs = num_vfs; dev_dbg(&pdev->dev, "Created %d VFs.\n", pf->num_vfs); + mutex_unlock(&pf->lock); return num_vfs; + +err_app_sriov_disable: + nfp_app_sriov_disable(pf->app); +err_unlock: + mutex_unlock(&pf->lock); + return err; #endif return 0; } -static int nfp_pcie_sriov_disable(struct pci_dev *pdev) +static int __nfp_pcie_sriov_disable(struct pci_dev *pdev) { #ifdef CONFIG_PCI_IOV struct nfp_pf *pf = pci_get_drvdata(pdev); @@ -132,6 +150,8 @@ static int nfp_pcie_sriov_disable(struct pci_dev *pdev) return -EPERM; } + nfp_app_sriov_disable(pf->app); + pf->num_vfs = 0; pci_disable_sriov(pdev); @@ -140,6 +160,18 @@ static int nfp_pcie_sriov_disable(struct pci_dev *pdev) return 0; } +static int nfp_pcie_sriov_disable(struct pci_dev *pdev) +{ + struct nfp_pf *pf = pci_get_drvdata(pdev); + int err; + + mutex_lock(&pf->lock); + err = __nfp_pcie_sriov_disable(pdev); + mutex_unlock(&pf->lock); + + return err; +} + static int nfp_pcie_sriov_configure(struct pci_dev *pdev, int num_vfs) { if (num_vfs == 0) @@ -431,11 +463,11 @@ static void nfp_pci_remove(struct pci_dev *pdev) devlink = priv_to_devlink(pf); - nfp_net_pci_remove(pf); - nfp_pcie_sriov_disable(pdev); pci_sriov_set_totalvfs(pf->pdev, 0); + nfp_net_pci_remove(pf); + devlink_unregister(devlink); kfree(pf->rtbl); -- cgit v1.2.3 From 93da7d9660ee6117672a4a9233d80600220de675 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 23 Jun 2017 22:12:05 +0200 Subject: nfp: provide nfp_port to of nfp_net_get_mac_addr() Provide port rather than vNIC as parameter of nfp_net_get_mac_addr. This is to allow this function to be used by representor netdevs where a vNIC may have more than one physical port none of which are associated with the vNIC. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_app_nic.c | 2 +- drivers/net/ethernet/netronome/nfp/nfp_main.h | 3 ++- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 25 +++++++++++------------ 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c index 7b966bd3d214..c11a6c34e217 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c @@ -69,7 +69,7 @@ int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn, if (err) return err < 0 ? err : 0; - nfp_net_get_mac_addr(app->pf, nn, id); + nfp_net_get_mac_addr(app->pf, nn->port, id); return 0; } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index aa69d4101eb9..edc14dc78674 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -58,6 +58,7 @@ struct nfp_hwinfo; struct nfp_mip; struct nfp_net; struct nfp_nsp_identify; +struct nfp_port; struct nfp_rtsym_table; /** @@ -147,7 +148,7 @@ void nfp_hwmon_unregister(struct nfp_pf *pf); struct nfp_eth_table_port * nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id); void -nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id); +nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_port *port, unsigned int id); bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 911b764d7641..cfcbc3b9a9aa 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -135,25 +135,24 @@ err_area: /** * nfp_net_get_mac_addr() - Get the MAC address. * @pf: NFP PF handle - * @nn: NFP Network structure + * @port: NFP port structure * @id: NFP port id * * First try to get the MAC address from NSP ETH table. If that * fails try HWInfo. As a last resort generate a random address. */ void -nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id) +nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_port *port, unsigned int id) { struct nfp_eth_table_port *eth_port; - struct nfp_net_dp *dp = &nn->dp; u8 mac_addr[ETH_ALEN]; const char *mac_str; char name[32]; - eth_port = __nfp_port_get_eth_port(nn->port); + eth_port = __nfp_port_get_eth_port(port); if (eth_port) { - ether_addr_copy(dp->netdev->dev_addr, eth_port->mac_addr); - ether_addr_copy(dp->netdev->perm_addr, eth_port->mac_addr); + ether_addr_copy(port->netdev->dev_addr, eth_port->mac_addr); + ether_addr_copy(port->netdev->perm_addr, eth_port->mac_addr); return; } @@ -161,22 +160,22 @@ nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id) mac_str = nfp_hwinfo_lookup(pf->hwinfo, name); if (!mac_str) { - dev_warn(dp->dev, "Can't lookup MAC address. Generate\n"); - eth_hw_addr_random(dp->netdev); + nfp_warn(pf->cpp, "Can't lookup MAC address. Generate\n"); + eth_hw_addr_random(port->netdev); return; } if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) { - dev_warn(dp->dev, - "Can't parse MAC address (%s). Generate.\n", mac_str); - eth_hw_addr_random(dp->netdev); + nfp_warn(pf->cpp, "Can't parse MAC address (%s). Generate.\n", + mac_str); + eth_hw_addr_random(port->netdev); return; } - ether_addr_copy(dp->netdev->dev_addr, mac_addr); - ether_addr_copy(dp->netdev->perm_addr, mac_addr); + ether_addr_copy(port->netdev->dev_addr, mac_addr); + ether_addr_copy(port->netdev->perm_addr, mac_addr); } struct nfp_eth_table_port * -- cgit v1.2.3 From 91bf82ca9eed1aa3e700a1b9fcaaa7922df6a4c7 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 23 Jun 2017 22:12:06 +0200 Subject: nfp: add support for tx/rx with metadata portid Allow tx/rx with metadata port id. This will be used for tx/rx of representor netdevs acting as upper-devices while a pf netdev acts as a lower-device. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 1 + .../net/ethernet/netronome/nfp/nfp_net_common.c | 57 +++++++++++++++++++--- 2 files changed, 52 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index b7446793106d..b1fa77bd708b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -318,6 +318,7 @@ struct nfp_meta_parsed { u8 csum_type; u32 hash; u32 mark; + u32 portid; __wsum csum; }; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 2134493ec8a8..2e728543e840 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -755,6 +755,26 @@ static void nfp_net_tx_xmit_more_flush(struct nfp_net_tx_ring *tx_ring) tx_ring->wr_ptr_add = 0; } +static int nfp_net_prep_port_id(struct sk_buff *skb) +{ + struct metadata_dst *md_dst = skb_metadata_dst(skb); + unsigned char *data; + + if (likely(!md_dst)) + return 0; + if (unlikely(md_dst->type != METADATA_HW_PORT_MUX)) + return 0; + + if (unlikely(skb_cow_head(skb, 8))) + return -ENOMEM; + + data = skb_push(skb, 8); + put_unaligned_be32(NFP_NET_META_PORTID, data); + put_unaligned_be32(md_dst->u.port_info.port_id, data + 4); + + return 8; +} + /** * nfp_net_tx() - Main transmit entry point * @skb: SKB to transmit @@ -767,6 +787,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) struct nfp_net *nn = netdev_priv(netdev); const struct skb_frag_struct *frag; struct nfp_net_tx_desc *txd, txdg; + int f, nr_frags, wr_idx, md_bytes; struct nfp_net_tx_ring *tx_ring; struct nfp_net_r_vector *r_vec; struct nfp_net_tx_buf *txbuf; @@ -774,8 +795,6 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) struct nfp_net_dp *dp; dma_addr_t dma_addr; unsigned int fsize; - int f, nr_frags; - int wr_idx; u16 qidx; dp = &nn->dp; @@ -797,6 +816,13 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } + md_bytes = nfp_net_prep_port_id(skb); + if (unlikely(md_bytes < 0)) { + nfp_net_tx_xmit_more_flush(tx_ring); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + /* Start with the head skbuf */ dma_addr = dma_map_single(dp->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); @@ -815,7 +841,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) /* Build TX descriptor */ txd = &tx_ring->txds[wr_idx]; - txd->offset_eop = (nr_frags == 0) ? PCIE_DESC_TX_EOP : 0; + txd->offset_eop = (nr_frags ? 0 : PCIE_DESC_TX_EOP) | md_bytes; txd->dma_len = cpu_to_le16(skb_headlen(skb)); nfp_desc_set_dma_addr(txd, dma_addr); txd->data_len = cpu_to_le16(skb->len); @@ -855,7 +881,7 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev) *txd = txdg; txd->dma_len = cpu_to_le16(fsize); nfp_desc_set_dma_addr(txd, dma_addr); - txd->offset_eop = + txd->offset_eop |= (f == nr_frags - 1) ? PCIE_DESC_TX_EOP : 0; } @@ -1450,6 +1476,10 @@ nfp_net_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, meta->mark = get_unaligned_be32(data); data += 4; break; + case NFP_NET_META_PORTID: + meta->portid = get_unaligned_be32(data); + data += 4; + break; case NFP_NET_META_CSUM: meta->csum_type = CHECKSUM_COMPLETE; meta->csum = @@ -1594,6 +1624,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) struct nfp_net_rx_buf *rxbuf; struct nfp_net_rx_desc *rxd; struct nfp_meta_parsed meta; + struct net_device *netdev; dma_addr_t new_dma_addr; void *new_frag; @@ -1672,7 +1703,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) } if (xdp_prog && !(rxd->rxd.flags & PCIE_DESC_RX_BPF && - dp->bpf_offload_xdp)) { + dp->bpf_offload_xdp) && !meta.portid) { unsigned int dma_off; void *hard_start; int act; @@ -1718,6 +1749,20 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) continue; } + if (likely(!meta.portid)) { + netdev = dp->netdev; + } else { + struct nfp_net *nn; + + nn = netdev_priv(dp->netdev); + netdev = nfp_app_repr_get(nn->app, meta.portid); + if (unlikely(!netdev)) { + nfp_net_rx_drop(dp, r_vec, rx_ring, rxbuf, skb); + continue; + } + nfp_repr_inc_rx_stats(netdev, pkt_len); + } + nfp_net_dma_unmap_rx(dp, rxbuf->dma_addr); nfp_net_rx_give_one(dp, rx_ring, new_frag, new_dma_addr); @@ -1729,7 +1774,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget) skb_set_hash(skb, meta.hash, meta.hash_type); skb_record_rx_queue(skb, rx_ring->idx); - skb->protocol = eth_type_trans(skb, dp->netdev); + skb->protocol = eth_type_trans(skb, netdev); nfp_net_rx_csum(dp, r_vec, rxd, &meta, skb); -- cgit v1.2.3 From 948faa46c05b5fb48f0bd39df426596197fa5d7e Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 23 Jun 2017 22:12:07 +0200 Subject: nfp: add support for control messages for flower app In preparation for adding a new flower app - targeted at offloading the flower classifier - provide support for control message that it will use to communicate with the NFP. Based in part on work by Bert van Leeuwen. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 1 + drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 159 +++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 116 +++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_app.c | 5 +- drivers/net/ethernet/netronome/nfp/nfp_app.h | 3 +- 5 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/netronome/nfp/flower/cmsg.c create mode 100644 drivers/net/ethernet/netronome/nfp/flower/cmsg.h (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index a401113035f5..e14f62863add 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -27,6 +27,7 @@ nfp-objs := \ nfp_port.o \ bpf/main.o \ bpf/offload.o \ + flower/cmsg.o \ nic/main.o ifeq ($(CONFIG_BPF_SYSCALL),y) diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c new file mode 100644 index 000000000000..7761be436726 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2015-2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#include "../nfpcore/nfp_cpp.h" +#include "../nfp_net_repr.h" +#include "./cmsg.h" + +#define nfp_flower_cmsg_warn(app, fmt, args...) \ + do { \ + if (net_ratelimit()) \ + nfp_warn((app)->cpp, fmt, ## args); \ + } while (0) + +static struct nfp_flower_cmsg_hdr * +nfp_flower_cmsg_get_hdr(struct sk_buff *skb) +{ + return (struct nfp_flower_cmsg_hdr *)skb->data; +} + +static void *nfp_flower_cmsg_get_data(struct sk_buff *skb) +{ + return (unsigned char *)skb->data + NFP_FLOWER_CMSG_HLEN; +} + +static struct sk_buff * +nfp_flower_cmsg_alloc(struct nfp_app *app, unsigned int size, + enum nfp_flower_cmsg_type_port type) +{ + struct nfp_flower_cmsg_hdr *ch; + struct sk_buff *skb; + + size += NFP_FLOWER_CMSG_HLEN; + + skb = nfp_app_ctrl_msg_alloc(app, size, GFP_KERNEL); + if (!skb) + return NULL; + + ch = nfp_flower_cmsg_get_hdr(skb); + ch->pad = 0; + ch->version = NFP_FLOWER_CMSG_VER1; + ch->type = type; + skb_put(skb, size); + + return skb; +} + +int nfp_flower_cmsg_portmod(struct net_device *netdev, bool carrier_ok) +{ + struct nfp_repr *repr = netdev_priv(netdev); + struct nfp_flower_cmsg_portmod *msg; + struct sk_buff *skb; + + skb = nfp_flower_cmsg_alloc(repr->app, sizeof(*msg), + NFP_FLOWER_CMSG_TYPE_PORT_MOD); + if (!skb) + return -ENOMEM; + + msg = nfp_flower_cmsg_get_data(skb); + msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id); + msg->reserved = 0; + msg->info = carrier_ok; + msg->mtu = cpu_to_be16(netdev->mtu); + + nfp_ctrl_tx(repr->app->ctrl, skb); + + return 0; +} + +static void +nfp_flower_cmsg_portmod_rx(struct nfp_app *app, struct sk_buff *skb) +{ + struct nfp_flower_cmsg_portmod *msg; + struct net_device *netdev; + bool link; + + msg = nfp_flower_cmsg_get_data(skb); + link = msg->info & NFP_FLOWER_CMSG_PORTMOD_INFO_LINK; + + rcu_read_lock(); + netdev = nfp_app_repr_get(app, be32_to_cpu(msg->portnum)); + if (!netdev) { + nfp_flower_cmsg_warn(app, "ctrl msg for unknown port 0x%08x\n", + be32_to_cpu(msg->portnum)); + rcu_read_unlock(); + return; + } + + if (link) { + netif_carrier_on(netdev); + rtnl_lock(); + dev_set_mtu(netdev, be16_to_cpu(msg->mtu)); + rtnl_unlock(); + } else { + netif_carrier_off(netdev); + } + rcu_read_unlock(); +} + +void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb) +{ + struct nfp_flower_cmsg_hdr *cmsg_hdr; + enum nfp_flower_cmsg_type_port type; + + cmsg_hdr = nfp_flower_cmsg_get_hdr(skb); + + if (unlikely(cmsg_hdr->version != NFP_FLOWER_CMSG_VER1)) { + nfp_flower_cmsg_warn(app, "Cannot handle repr control version %u\n", + cmsg_hdr->version); + goto out; + } + + type = cmsg_hdr->type; + switch (type) { + case NFP_FLOWER_CMSG_TYPE_PORT_MOD: + nfp_flower_cmsg_portmod_rx(app, skb); + break; + default: + nfp_flower_cmsg_warn(app, "Cannot handle invalid repr control type %u\n", + type); + } + +out: + dev_kfree_skb_any(skb); +} diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h new file mode 100644 index 000000000000..2eeddada7f4d --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef NFP_FLOWER_CMSG_H +#define NFP_FLOWER_CMSG_H + +#include +#include +#include + +#include "../nfp_app.h" + +/* The base header for a control message packet. + * Defines an 8-bit version, and an 8-bit type, padded + * to a 32-bit word. Rest of the packet is type-specific. + */ +struct nfp_flower_cmsg_hdr { + __be16 pad; + u8 type; + u8 version; +}; + +#define NFP_FLOWER_CMSG_HLEN sizeof(struct nfp_flower_cmsg_hdr) +#define NFP_FLOWER_CMSG_VER1 1 + +/* Types defined for port related control messages */ +enum nfp_flower_cmsg_type_port { + NFP_FLOWER_CMSG_TYPE_PORT_MOD = 8, + NFP_FLOWER_CMSG_TYPE_PORT_ECHO = 16, + NFP_FLOWER_CMSG_TYPE_MAX = 32, +}; + +/* NFP_FLOWER_CMSG_TYPE_PORT_MOD */ +struct nfp_flower_cmsg_portmod { + __be32 portnum; + u8 reserved; + u8 info; + __be16 mtu; +}; + +#define NFP_FLOWER_CMSG_PORTMOD_INFO_LINK BIT(0) + +enum nfp_flower_cmsg_port_type { + NFP_FLOWER_CMSG_PORT_TYPE_UNSPEC = 0x0, + NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT = 0x1, + NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT = 0x2, +}; + +enum nfp_flower_cmsg_port_vnic_type { + NFP_FLOWER_CMSG_PORT_VNIC_TYPE_VF = 0x0, + NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF = 0x1, + NFP_FLOWER_CMSG_PORT_VNIC_TYPE_CTRL = 0x2, +}; + +#define NFP_FLOWER_CMSG_PORT_TYPE GENMASK(31, 28) +#define NFP_FLOWER_CMSG_PORT_SYS_ID GENMASK(27, 24) +#define NFP_FLOWER_CMSG_PORT_NFP_ID GENMASK(23, 22) +#define NFP_FLOWER_CMSG_PORT_PCI GENMASK(15, 14) +#define NFP_FLOWER_CMSG_PORT_VNIC_TYPE GENMASK(13, 12) +#define NFP_FLOWER_CMSG_PORT_VNIC GENMASK(11, 6) +#define NFP_FLOWER_CMSG_PORT_PCIE_Q GENMASK(5, 0) +#define NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM GENMASK(7, 0) + +static inline u32 nfp_flower_cmsg_phys_port(u8 phys_port) +{ + return FIELD_PREP(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, phys_port) | + FIELD_PREP(NFP_FLOWER_CMSG_PORT_TYPE, + NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT); +} + +static inline u32 +nfp_flower_cmsg_pcie_port(u8 nfp_pcie, enum nfp_flower_cmsg_port_vnic_type type, + u8 vnic, u8 q) +{ + return FIELD_PREP(NFP_FLOWER_CMSG_PORT_PCI, nfp_pcie) | + FIELD_PREP(NFP_FLOWER_CMSG_PORT_VNIC_TYPE, type) | + FIELD_PREP(NFP_FLOWER_CMSG_PORT_VNIC, vnic) | + FIELD_PREP(NFP_FLOWER_CMSG_PORT_PCIE_Q, q) | + FIELD_PREP(NFP_FLOWER_CMSG_PORT_TYPE, + NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT); +} + +int nfp_flower_cmsg_portmod(struct net_device *netdev, bool carrier_ok); +void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb); + +#endif diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index c9ccb0f94604..2b71050dc5e4 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -52,14 +52,15 @@ const char *nfp_app_mip_name(struct nfp_app *app) return nfp_mip_name(app->pf->mip); } -struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size) +struct sk_buff * +nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size, gfp_t priority) { struct sk_buff *skb; if (nfp_app_ctrl_has_meta(app)) size += 8; - skb = alloc_skb(size, GFP_ATOMIC); + skb = alloc_skb(size, priority); if (!skb) return NULL; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index ff2d43615808..36949b3e91c1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -268,7 +268,8 @@ nfp_app_reprs_set(struct nfp_app *app, enum nfp_repr_type type, struct nfp_reprs *reprs); const char *nfp_app_mip_name(struct nfp_app *app); -struct sk_buff *nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size); +struct sk_buff * +nfp_app_ctrl_msg_alloc(struct nfp_app *app, unsigned int size, gfp_t priority); struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id); void nfp_app_free(struct nfp_app *app); -- cgit v1.2.3 From 1025351a88a49cb2fed7d023858ce182718c0c43 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 23 Jun 2017 22:12:08 +0200 Subject: nfp: add flower app Add app for flower offload. At this point the PF netdev and phys port representor netdevs are initialised. Follow-up work will add support for VF and PF representors and beyond that offloading the flower classifier. Based in part on work by Benjamin LaHaise and Bert van Leeuwen. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 1 + drivers/net/ethernet/netronome/nfp/flower/main.c | 294 +++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_app.c | 1 + drivers/net/ethernet/netronome/nfp/nfp_app.h | 4 + 4 files changed, 300 insertions(+) create mode 100644 drivers/net/ethernet/netronome/nfp/flower/main.c (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index e14f62863add..10b556b2c59d 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -28,6 +28,7 @@ nfp-objs := \ bpf/main.o \ bpf/offload.o \ flower/cmsg.o \ + flower/main.o \ nic/main.o ifeq ($(CONFIG_BPF_SYSCALL),y) diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c new file mode 100644 index 000000000000..54d8180317ec --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "../nfpcore/nfp_cpp.h" +#include "../nfpcore/nfp_nsp.h" +#include "../nfp_app.h" +#include "../nfp_main.h" +#include "../nfp_net.h" +#include "../nfp_net_repr.h" +#include "../nfp_port.h" +#include "./cmsg.h" + +/** + * struct nfp_flower_priv - Flower APP per-vNIC priv data + * @nn: Pointer to vNIC + */ +struct nfp_flower_priv { + struct nfp_net *nn; +}; + +static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn) +{ + return "FLOWER"; +} + +static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app) +{ + return DEVLINK_ESWITCH_MODE_SWITCHDEV; +} + +static enum nfp_repr_type +nfp_flower_repr_get_type_and_port(struct nfp_app *app, u32 port_id, u8 *port) +{ + switch (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port_id)) { + case NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT: + *port = FIELD_GET(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, + port_id); + return NFP_REPR_TYPE_PHYS_PORT; + + case NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT: + *port = FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC, port_id); + if (FIELD_GET(NFP_FLOWER_CMSG_PORT_VNIC_TYPE, port_id) == + NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF) + return NFP_REPR_TYPE_PF; + else + return NFP_REPR_TYPE_VF; + } + + return NFP_FLOWER_CMSG_PORT_TYPE_UNSPEC; +} + +static struct net_device * +nfp_flower_repr_get(struct nfp_app *app, u32 port_id) +{ + enum nfp_repr_type repr_type; + struct nfp_reprs *reprs; + u8 port = 0; + + repr_type = nfp_flower_repr_get_type_and_port(app, port_id, &port); + + reprs = rcu_dereference(app->reprs[repr_type]); + if (!reprs) + return NULL; + + if (port >= reprs->num_reprs) + return NULL; + + return reprs->reprs[port]; +} + +static void +nfp_flower_repr_netdev_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats) +{ + struct nfp_repr *repr = netdev_priv(netdev); + enum nfp_repr_type type; + u32 port_id; + u8 port = 0; + + port_id = repr->dst->u.port_info.port_id; + type = nfp_flower_repr_get_type_and_port(repr->app, port_id, &port); + nfp_repr_get_stats64(repr->app, type, port, stats); +} + +static int nfp_flower_repr_netdev_open(struct net_device *netdev) +{ + int err; + + err = nfp_flower_cmsg_portmod(netdev, true); + if (err) + return err; + + netif_carrier_on(netdev); + netif_tx_wake_all_queues(netdev); + + return 0; +} + +static int nfp_flower_repr_netdev_stop(struct net_device *netdev) +{ + netif_carrier_off(netdev); + netif_tx_disable(netdev); + + return nfp_flower_cmsg_portmod(netdev, false); +} + +static const struct net_device_ops nfp_flower_repr_netdev_ops = { + .ndo_open = nfp_flower_repr_netdev_open, + .ndo_stop = nfp_flower_repr_netdev_stop, + .ndo_start_xmit = nfp_repr_xmit, + .ndo_get_stats64 = nfp_flower_repr_netdev_get_stats64, + .ndo_has_offload_stats = nfp_repr_has_offload_stats, + .ndo_get_offload_stats = nfp_repr_get_offload_stats, +}; + +static void nfp_flower_stop(struct nfp_app *app) +{ + nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); +} + +static int nfp_flower_start(struct nfp_app *app) +{ + struct nfp_eth_table *eth_tbl = app->pf->eth_tbl; + struct nfp_flower_priv *priv = app->priv; + struct nfp_reprs *reprs, *old_reprs; + unsigned int i; + int err; + + reprs = nfp_reprs_alloc(eth_tbl->max_index + 1); + if (!reprs) + return -ENOMEM; + + for (i = 0; i < eth_tbl->count; i++) { + int phys_port = eth_tbl->ports[i].index; + struct nfp_port *port; + u32 cmsg_port_id; + + reprs->reprs[phys_port] = nfp_repr_alloc(app); + if (!reprs->reprs[phys_port]) { + err = -ENOMEM; + goto err_reprs_clean; + } + + port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, + reprs->reprs[phys_port]); + if (IS_ERR(port)) { + err = PTR_ERR(port); + goto err_reprs_clean; + } + err = nfp_port_init_phy_port(app->pf, app, port, i); + if (err) { + nfp_port_free(port); + goto err_reprs_clean; + } + + SET_NETDEV_DEV(reprs->reprs[phys_port], &priv->nn->pdev->dev); + nfp_net_get_mac_addr(app->pf, port, + eth_tbl->ports[i].eth_index); + + cmsg_port_id = nfp_flower_cmsg_phys_port(phys_port); + err = nfp_repr_init(app, reprs->reprs[phys_port], + &nfp_flower_repr_netdev_ops, + cmsg_port_id, port, priv->nn->dp.netdev); + if (err) { + nfp_port_free(port); + goto err_reprs_clean; + } + + nfp_info(app->cpp, "Phys Port %d Representor(%s) created\n", + phys_port, reprs->reprs[phys_port]->name); + } + + old_reprs = nfp_app_reprs_set(app, NFP_REPR_TYPE_PHYS_PORT, reprs); + if (IS_ERR(old_reprs)) { + err = PTR_ERR(old_reprs); + goto err_reprs_clean; + } + + return 0; +err_reprs_clean: + nfp_reprs_clean_and_free(reprs); + return err; +} + +static void nfp_flower_vnic_clean(struct nfp_app *app, struct nfp_net *nn) +{ + kfree(app->priv); + app->priv = NULL; +} + +static int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn, + unsigned int id) +{ + struct nfp_flower_priv *priv; + + if (id > 0) { + nfp_warn(app->cpp, "FlowerNIC doesn't support more than one data vNIC\n"); + goto err_invalid_port; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + app->priv = priv; + priv->nn = nn; + + eth_hw_addr_random(nn->dp.netdev); + netif_keep_dst(nn->dp.netdev); + + return 0; + +err_invalid_port: + nn->port = nfp_port_alloc(app, NFP_PORT_INVALID, nn->dp.netdev); + return PTR_ERR_OR_ZERO(nn->port); +} + +static int nfp_flower_init(struct nfp_app *app) +{ + const struct nfp_pf *pf = app->pf; + + if (!pf->eth_tbl) { + nfp_warn(app->cpp, "FlowerNIC requires eth table\n"); + return -EINVAL; + } + + if (!pf->mac_stats_bar) { + nfp_warn(app->cpp, "FlowerNIC requires mac_stats BAR\n"); + return -EINVAL; + } + + if (!pf->vf_cfg_bar) { + nfp_warn(app->cpp, "FlowerNIC requires vf_cfg BAR\n"); + return -EINVAL; + } + + return 0; +} + +const struct nfp_app_type app_flower = { + .id = NFP_APP_FLOWER_NIC, + .name = "flower", + .ctrl_has_meta = true, + + .extra_cap = nfp_flower_extra_cap, + + .init = nfp_flower_init, + + .vnic_init = nfp_flower_vnic_init, + .vnic_clean = nfp_flower_vnic_clean, + + .start = nfp_flower_start, + .stop = nfp_flower_stop, + + .ctrl_msg_rx = nfp_flower_cmsg_rx, + + .eswitch_mode_get = eswitch_mode_get, + .repr_get = nfp_flower_repr_get, +}; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index 2b71050dc5e4..5620de05c996 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -43,6 +43,7 @@ static const struct nfp_app_type *apps[] = { &app_nic, &app_bpf, + &app_flower, }; const char *nfp_app_mip_name(struct nfp_app *app) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index 36949b3e91c1..ae2d02753d1a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -52,10 +52,12 @@ struct nfp_net; enum nfp_app_id { NFP_APP_CORE_NIC = 0x1, NFP_APP_BPF_NIC = 0x2, + NFP_APP_FLOWER_NIC = 0x3, }; extern const struct nfp_app_type app_nic; extern const struct nfp_app_type app_bpf; +extern const struct nfp_app_type app_flower; /** * struct nfp_app_type - application definition @@ -119,6 +121,7 @@ struct nfp_app_type { * @ctrl: pointer to ctrl vNIC struct * @reprs: array of pointers to representors * @type: pointer to const application ops and info + * @priv: app-specific priv data */ struct nfp_app { struct pci_dev *pdev; @@ -129,6 +132,7 @@ struct nfp_app { struct nfp_reprs __rcu *reprs[NFP_REPR_TYPE_MAX + 1]; const struct nfp_app_type *type; + void *priv; }; bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb); -- cgit v1.2.3 From 24a021ed77ef8d090bf15ad1ac24d29fcfe9a410 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 23 Jun 2017 22:12:09 +0200 Subject: nfp: add VF and PF representors to flower app Initialise VF and PF representors in flower app. Based in part on work by Benjamin LaHaise, Bert van Leeuwen and Jakub Kicinski. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.c | 85 +++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 54d8180317ec..8e5ca6b4bb33 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -149,15 +149,80 @@ static const struct net_device_ops nfp_flower_repr_netdev_ops = { .ndo_get_offload_stats = nfp_repr_get_offload_stats, }; +static void nfp_flower_sriov_disable(struct nfp_app *app) +{ + nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF); +} + +static int +nfp_flower_spawn_vnic_reprs(struct nfp_app *app, + enum nfp_flower_cmsg_port_vnic_type vnic_type, + enum nfp_repr_type repr_type, unsigned int cnt) +{ + u8 nfp_pcie = nfp_cppcore_pcie_unit(app->pf->cpp); + struct nfp_flower_priv *priv = app->priv; + struct nfp_reprs *reprs, *old_reprs; + const u8 queue = 0; + int i, err; + + reprs = nfp_reprs_alloc(cnt); + if (!reprs) + return -ENOMEM; + + for (i = 0; i < cnt; i++) { + u32 port_id; + + reprs->reprs[i] = nfp_repr_alloc(app); + if (!reprs->reprs[i]) { + err = -ENOMEM; + goto err_reprs_clean; + } + + eth_hw_addr_random(reprs->reprs[i]); + + port_id = nfp_flower_cmsg_pcie_port(nfp_pcie, vnic_type, + i, queue); + err = nfp_repr_init(app, reprs->reprs[i], + &nfp_flower_repr_netdev_ops, + port_id, NULL, priv->nn->dp.netdev); + if (err) + goto err_reprs_clean; + + nfp_info(app->cpp, "%s%d Representor(%s) created\n", + repr_type == NFP_REPR_TYPE_PF ? "PF" : "VF", i, + reprs->reprs[i]->name); + } + + old_reprs = nfp_app_reprs_set(app, repr_type, reprs); + if (IS_ERR(old_reprs)) { + err = PTR_ERR(old_reprs); + goto err_reprs_clean; + } + + return 0; +err_reprs_clean: + nfp_reprs_clean_and_free(reprs); + return err; +} + +static int nfp_flower_sriov_enable(struct nfp_app *app, int num_vfs) +{ + return nfp_flower_spawn_vnic_reprs(app, + NFP_FLOWER_CMSG_PORT_VNIC_TYPE_VF, + NFP_REPR_TYPE_VF, num_vfs); +} + static void nfp_flower_stop(struct nfp_app *app) { + nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF); nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); + } -static int nfp_flower_start(struct nfp_app *app) +static int +nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv) { struct nfp_eth_table *eth_tbl = app->pf->eth_tbl; - struct nfp_flower_priv *priv = app->priv; struct nfp_reprs *reprs, *old_reprs; unsigned int i; int err; @@ -218,6 +283,19 @@ err_reprs_clean: return err; } +static int nfp_flower_start(struct nfp_app *app) +{ + int err; + + err = nfp_flower_spawn_phy_reprs(app, app->priv); + if (err) + return err; + + return nfp_flower_spawn_vnic_reprs(app, + NFP_FLOWER_CMSG_PORT_VNIC_TYPE_PF, + NFP_REPR_TYPE_PF, 1); +} + static void nfp_flower_vnic_clean(struct nfp_app *app, struct nfp_net *nn) { kfree(app->priv); @@ -289,6 +367,9 @@ const struct nfp_app_type app_flower = { .ctrl_msg_rx = nfp_flower_cmsg_rx, + .sriov_enable = nfp_flower_sriov_enable, + .sriov_disable = nfp_flower_sriov_disable, + .eswitch_mode_get = eswitch_mode_get, .repr_get = nfp_flower_repr_get, }; -- cgit v1.2.3 From 64b2f72671a9a8cbea1aa575d3ea3998987e8c53 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 23 Jun 2017 18:17:04 +0300 Subject: net: dsa: mv88e6xxx: fix error code in mv88e6390_serdes_power() We're accidentally returning the wrong variable. "cmode" is uninitialized at this point so it causes a static checker warning. Fixes: 6335e9f2446b ("net: dsa: mv88e6xxx: mv88e6390X SERDES support") Signed-off-by: Dan Carpenter Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/serdes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 411b4f522792..f3c01119b3d1 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -192,7 +192,7 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) err = mv88e6xxx_port_get_cmode(chip, port, &cmode); if (err) - return cmode; + return err; switch (port) { case 2: -- cgit v1.2.3 From 03eb3eb4d4d56414efbe05a5521b2fc4ce175cb7 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 23 Jun 2017 14:33:28 -0500 Subject: net: qcom/emac: add shutdown function The shutdown function halts all DMA and interrupts, so that all operations are discontinued when the system shuts down, e.g. via kexec or a forced reboot. Tested-by: Tyler Baicar Signed-off-by: Timur Tabi Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/emac/emac.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index 98a326faea29..77c5c929f141 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -762,6 +762,19 @@ static int emac_remove(struct platform_device *pdev) return 0; } +static void emac_shutdown(struct platform_device *pdev) +{ + struct net_device *netdev = dev_get_drvdata(&pdev->dev); + struct emac_adapter *adpt = netdev_priv(netdev); + struct emac_sgmii *sgmii = &adpt->phy; + + /* Closing the SGMII turns off its interrupts */ + sgmii->close(adpt); + + /* Resetting the MAC turns off all DMA and its interrupts */ + emac_mac_reset(adpt); +} + static struct platform_driver emac_platform_driver = { .probe = emac_probe, .remove = emac_remove, @@ -770,6 +783,7 @@ static struct platform_driver emac_platform_driver = { .of_match_table = emac_dt_match, .acpi_match_table = ACPI_PTR(emac_acpi_match), }, + .shutdown = emac_shutdown, }; module_platform_driver(emac_platform_driver); -- cgit v1.2.3 From 867ae6abc24967188db0914de170512e36592eb3 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 23 Jun 2017 14:33:29 -0500 Subject: net: qcom/emac: do not reset the EMAC during initialization On ACPI systems, the driver depends on firmware pre-initializing the EMAC because we don't have access to the clocks, and the EMAC has specific clock programming requirements. Therefore, we don't want to reset the EMAC while we are completing the initialization. Tested-by: Richard Ruigrok Signed-off-by: Timur Tabi Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/emac/emac.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index 77c5c929f141..746d94e28470 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -683,8 +683,6 @@ static int emac_probe(struct platform_device *pdev) goto err_undo_mdiobus; } - emac_mac_reset(adpt); - /* set hw features */ netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_RX | -- cgit v1.2.3 From ceef551faacb1783040d9c1a10d4baad9548f37e Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Fri, 23 Jun 2017 14:33:30 -0500 Subject: net: qcom/emac: add support for emulation systems On emulation systems, the EMAC's internal PHY ("SGMII") is not present, but is not needed for network functionality. So just display a warning message and ignore the SGMII. Tested-by: Philip Elcan Tested-by: Adam Wallis Signed-off-by: Timur Tabi Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/emac/emac-sgmii.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c index 18c184ee1f3c..29ba37a08372 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c @@ -297,6 +297,14 @@ static const struct of_device_id emac_sgmii_dt_match[] = { {} }; +/* Dummy function for systems without an internal PHY. This avoids having + * to check for NULL pointers before calling the functions. + */ +static int emac_sgmii_dummy(struct emac_adapter *adpt) +{ + return 0; +} + int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt) { struct platform_device *sgmii_pdev = NULL; @@ -311,8 +319,19 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt) emac_sgmii_acpi_match); if (!dev) { - dev_err(&pdev->dev, "cannot find internal phy node\n"); - return -ENODEV; + dev_warn(&pdev->dev, "cannot find internal phy node\n"); + /* There is typically no internal PHY on emulation + * systems, so if we can't find the node, assume + * we are on an emulation system and stub-out + * support for the internal PHY. These systems only + * use ACPI. + */ + phy->open = emac_sgmii_dummy; + phy->close = emac_sgmii_dummy; + phy->link_up = emac_sgmii_dummy; + phy->link_down = emac_sgmii_dummy; + + return 0; } sgmii_pdev = to_platform_device(dev); -- cgit v1.2.3 From dacdbb4dfc1a1a1378df8ebc914d4fe82259ed46 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Fri, 23 Jun 2017 16:54:10 +0200 Subject: net: macb: add fixed-link node support In case the MACB is directly connected to a non-mdio PHY/device, it should be possible to provide a fixed link configuration in the DT. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 98 ++++++++++++++++++++++--------------- drivers/net/ethernet/cadence/macb.h | 1 + 2 files changed, 60 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 4b0168bcbc8a..3ae9d8071ded 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -425,32 +425,40 @@ static int macb_mii_probe(struct net_device *dev) int phy_irq; int ret; - phydev = phy_find_first(bp->mii_bus); - if (!phydev) { - netdev_err(dev, "no PHY found\n"); - return -ENXIO; - } + if (bp->phy_node) { + phydev = of_phy_connect(dev, bp->phy_node, + &macb_handle_link_change, 0, + bp->phy_interface); + if (!phydev) + return -ENODEV; + } else { + phydev = phy_find_first(bp->mii_bus); + if (!phydev) { + netdev_err(dev, "no PHY found\n"); + return -ENXIO; + } - pdata = dev_get_platdata(&bp->pdev->dev); - if (pdata) { - if (gpio_is_valid(pdata->phy_irq_pin)) { - ret = devm_gpio_request(&bp->pdev->dev, - pdata->phy_irq_pin, "phy int"); - if (!ret) { - phy_irq = gpio_to_irq(pdata->phy_irq_pin); - phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq; + pdata = dev_get_platdata(&bp->pdev->dev); + if (pdata) { + if (gpio_is_valid(pdata->phy_irq_pin)) { + ret = devm_gpio_request(&bp->pdev->dev, + pdata->phy_irq_pin, "phy int"); + if (!ret) { + phy_irq = gpio_to_irq(pdata->phy_irq_pin); + phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq; + } + } else { + phydev->irq = PHY_POLL; } - } else { - phydev->irq = PHY_POLL; } - } - /* attach the mac to the phy */ - ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, - bp->phy_interface); - if (ret) { - netdev_err(dev, "Could not attach to PHY\n"); - return ret; + /* attach the mac to the phy */ + ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, + bp->phy_interface); + if (ret) { + netdev_err(dev, "Could not attach to PHY\n"); + return ret; + } } /* mask with MAC supported features */ @@ -499,26 +507,37 @@ static int macb_mii_init(struct macb *bp) np = bp->pdev->dev.of_node; if (np) { - /* try dt phy registration */ - err = of_mdiobus_register(bp->mii_bus, np); + if (of_phy_is_fixed_link(np)) { + if (of_phy_register_fixed_link(np) < 0) { + dev_err(&bp->pdev->dev, + "broken fixed-link specification\n"); + goto err_out_unregister_bus; + } + bp->phy_node = of_node_get(np); - /* fallback to standard phy registration if no phy were - * found during dt phy registration - */ - if (!err && !phy_find_first(bp->mii_bus)) { - for (i = 0; i < PHY_MAX_ADDR; i++) { - struct phy_device *phydev; - - phydev = mdiobus_scan(bp->mii_bus, i); - if (IS_ERR(phydev) && - PTR_ERR(phydev) != -ENODEV) { - err = PTR_ERR(phydev); - break; + err = mdiobus_register(bp->mii_bus); + } else { + /* try dt phy registration */ + err = of_mdiobus_register(bp->mii_bus, np); + + /* fallback to standard phy registration if no phy were + * found during dt phy registration + */ + if (!err && !phy_find_first(bp->mii_bus)) { + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *phydev; + + phydev = mdiobus_scan(bp->mii_bus, i); + if (IS_ERR(phydev) && + PTR_ERR(phydev) != -ENODEV) { + err = PTR_ERR(phydev); + break; + } } - } - if (err) - goto err_out_unregister_bus; + if (err) + goto err_out_unregister_bus; + } } } else { for (i = 0; i < PHY_MAX_ADDR; i++) @@ -3438,6 +3457,7 @@ static int macb_remove(struct platform_device *pdev) clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); clk_disable_unprepare(bp->rx_clk); + of_node_put(bp->phy_node); free_netdev(dev); } diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index ec037b0fa2a4..2510661102ba 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -930,6 +930,7 @@ struct macb { struct macb_or_gem_ops macbgem_ops; struct mii_bus *mii_bus; + struct device_node *phy_node; int link; int speed; int duplex; -- cgit v1.2.3 From 7a3f4a185169b195c33f1c54f33a44eba2d6aa96 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 25 Jun 2017 23:55:59 +0200 Subject: net: add netlink_ext_ack argument to rtnl_link_ops.newlink Add support for extended error reporting. Signed-off-by: Matthias Schiffer Acked-by: David Ahern Signed-off-by: David S. Miller --- drivers/infiniband/ulp/ipoib/ipoib_netlink.c | 3 ++- drivers/net/bonding/bond_netlink.c | 3 ++- drivers/net/caif/caif_hsi.c | 3 ++- drivers/net/can/dev.c | 3 ++- drivers/net/can/vxcan.c | 3 ++- drivers/net/geneve.c | 3 ++- drivers/net/gtp.c | 3 ++- drivers/net/ipvlan/ipvlan.h | 3 ++- drivers/net/ipvlan/ipvlan_main.c | 3 ++- drivers/net/ipvlan/ipvtap.c | 9 ++++----- drivers/net/macsec.c | 3 ++- drivers/net/macvlan.c | 3 ++- drivers/net/macvtap.c | 7 +++---- drivers/net/ppp/ppp_generic.c | 3 ++- drivers/net/team/team.c | 3 ++- drivers/net/veth.c | 3 ++- drivers/net/vrf.c | 3 ++- drivers/net/vxlan.c | 3 ++- 18 files changed, 39 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c index 28884781311b..8b75f80da56c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c @@ -93,7 +93,8 @@ out_err: } static int ipoib_new_child_link(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct net_device *pdev; struct ipoib_dev_priv *ppriv; diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 47a8103610bc..f817fb8005ef 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -438,7 +438,8 @@ static int bond_changelink(struct net_device *bond_dev, } static int bond_newlink(struct net *src_net, struct net_device *bond_dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { int err; diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index 11ba6e3eea22..ed4723a9031f 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c @@ -1399,7 +1399,8 @@ static int caif_hsi_fill_info(struct sk_buff *skb, const struct net_device *dev) } static int caif_hsi_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct cfhsi *cfhsi = NULL; struct cfhsi_ops *(*get_ops)(void); diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index a3011c001080..7f99e8a5dd09 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -1146,7 +1146,8 @@ nla_put_failure: } static int can_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { return -EOPNOTSUPP; } diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index cfe889e8f172..8404e8852a0f 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -163,7 +163,8 @@ static void vxcan_setup(struct net_device *dev) static struct rtnl_link_ops vxcan_link_ops; static int vxcan_newlink(struct net *net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct vxcan_priv *priv; struct net_device *peer; diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index d586ad93aaff..0a72d914e1f9 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1181,7 +1181,8 @@ static void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port) } static int geneve_newlink(struct net *net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { bool use_udp6_rx_checksums = false; struct ip_tunnel_info info; diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 8e333a8a2295..9cfe8a24c1fc 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -636,7 +636,8 @@ static void gtp_hashtable_free(struct gtp_dev *gtp); static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[]); static int gtp_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct gtp_dev *gtp; struct gtp_net *gn; diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index 7919369c0a72..ba8173a0b62e 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h @@ -140,7 +140,8 @@ unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb, void ipvlan_count_rx(const struct ipvl_dev *ipvlan, unsigned int len, bool success, bool mcast); int ipvlan_link_new(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]); + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack); void ipvlan_link_delete(struct net_device *dev, struct list_head *head); void ipvlan_link_setup(struct net_device *dev); int ipvlan_link_register(struct rtnl_link_ops *ops); diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index dc888dd344eb..7bda5f630ac9 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -508,7 +508,8 @@ err: } int ipvlan_link_new(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct ipvl_dev *ipvlan = netdev_priv(dev); struct ipvl_port *port; diff --git a/drivers/net/ipvlan/ipvtap.c b/drivers/net/ipvlan/ipvtap.c index 2b713b63b62c..22f133ea8d7b 100644 --- a/drivers/net/ipvlan/ipvtap.c +++ b/drivers/net/ipvlan/ipvtap.c @@ -73,10 +73,9 @@ static void ipvtap_update_features(struct tap_dev *tap, netdev_update_features(vlan->dev); } -static int ipvtap_newlink(struct net *src_net, - struct net_device *dev, - struct nlattr *tb[], - struct nlattr *data[]) +static int ipvtap_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct ipvtap_dev *vlantap = netdev_priv(dev); int err; @@ -98,7 +97,7 @@ static int ipvtap_newlink(struct net *src_net, /* Don't put anything that may fail after macvlan_common_newlink * because we can't undo what it does. */ - err = ipvlan_link_new(src_net, dev, tb, data); + err = ipvlan_link_new(src_net, dev, tb, data, extack); if (err) { netdev_rx_handler_unregister(dev); return err; diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index e370d7c894cb..60f3e3089ec3 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -3203,7 +3203,8 @@ static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len) } static int macsec_newlink(struct net *net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct macsec_dev *macsec = macsec_priv(dev); struct net_device *real_dev; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 8ca274c6df3d..526d23db3b71 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1390,7 +1390,8 @@ destroy_macvlan_port: EXPORT_SYMBOL_GPL(macvlan_common_newlink); static int macvlan_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { return macvlan_common_newlink(src_net, dev, tb, data); } diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index da85057680d6..91e7b19bbf86 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -77,10 +77,9 @@ static void macvtap_update_features(struct tap_dev *tap, netdev_update_features(vlan->dev); } -static int macvtap_newlink(struct net *src_net, - struct net_device *dev, - struct nlattr *tb[], - struct nlattr *data[]) +static int macvtap_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct macvtap_dev *vlantap = netdev_priv(dev); int err; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index d42091f11eb8..8479c130fe2e 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1075,7 +1075,8 @@ static int ppp_nl_validate(struct nlattr *tb[], struct nlattr *data[]) } static int ppp_nl_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct ppp_config conf = { .unit = -1, diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 629a412dc690..bbe97bb7c9cc 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2101,7 +2101,8 @@ static void team_setup(struct net_device *dev) } static int team_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS] == NULL) eth_hw_addr_random(dev); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 0156fe8cac17..3db907cb7d07 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -347,7 +347,8 @@ static int veth_validate(struct nlattr *tb[], struct nlattr *data[]) static struct rtnl_link_ops veth_link_ops; static int veth_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { int err; struct net_device *peer; diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 997ef25189fd..762f4d033e1b 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1389,7 +1389,8 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) } static int vrf_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct net_vrf *vrf = netdev_priv(dev); bool *add_fib_rules; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 653b2bb32be1..50a208747179 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3333,7 +3333,8 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], } static int vxlan_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct vxlan_config conf; int err; -- cgit v1.2.3 From ad744b223c521b1e01752a826774545c3e3acd8e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 25 Jun 2017 23:56:00 +0200 Subject: net: add netlink_ext_ack argument to rtnl_link_ops.changelink Add support for extended error reporting. Signed-off-by: Matthias Schiffer Acked-by: David Ahern Signed-off-by: David S. Miller --- drivers/infiniband/ulp/ipoib/ipoib_netlink.c | 7 ++++--- drivers/net/bonding/bond_netlink.c | 7 ++++--- drivers/net/caif/caif_hsi.c | 3 ++- drivers/net/can/dev.c | 5 +++-- drivers/net/ipvlan/ipvlan_main.c | 3 ++- drivers/net/macsec.c | 3 ++- drivers/net/macvlan.c | 3 ++- drivers/net/vxlan.c | 3 ++- 8 files changed, 21 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c index 8b75f80da56c..3e44087935ae 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c @@ -64,8 +64,9 @@ nla_put_failure: return -EMSGSIZE; } -static int ipoib_changelink(struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) +static int ipoib_changelink(struct net_device *dev, struct nlattr *tb[], + struct nlattr *data[], + struct netlink_ext_ack *extack) { u16 mode, umcast; int ret = 0; @@ -134,7 +135,7 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev, child_pkey, IPOIB_RTNL_CHILD); if (!err && data) - err = ipoib_changelink(dev, tb, data); + err = ipoib_changelink(dev, tb, data, extack); return err; } diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index f817fb8005ef..cb803c026f1f 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -156,8 +156,9 @@ static int bond_slave_changelink(struct net_device *bond_dev, return 0; } -static int bond_changelink(struct net_device *bond_dev, - struct nlattr *tb[], struct nlattr *data[]) +static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], + struct nlattr *data[], + struct netlink_ext_ack *extack) { struct bonding *bond = netdev_priv(bond_dev); struct bond_opt_value newval; @@ -443,7 +444,7 @@ static int bond_newlink(struct net *src_net, struct net_device *bond_dev, { int err; - err = bond_changelink(bond_dev, tb, data); + err = bond_changelink(bond_dev, tb, data, extack); if (err < 0) return err; diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index ed4723a9031f..438966bf51c2 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c @@ -1352,7 +1352,8 @@ static void cfhsi_netlink_parms(struct nlattr *data[], struct cfhsi *cfhsi) } static int caif_hsi_changelink(struct net_device *dev, struct nlattr *tb[], - struct nlattr *data[]) + struct nlattr *data[], + struct netlink_ext_ack *extack) { cfhsi_netlink_parms(data, netdev_priv(dev)); netdev_state_change(dev); diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 7f99e8a5dd09..6d8191f2ad32 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -880,8 +880,9 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } -static int can_changelink(struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) +static int can_changelink(struct net_device *dev, struct nlattr *tb[], + struct nlattr *data[], + struct netlink_ext_ack *extack) { struct can_priv *priv = netdev_priv(dev); int err; diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 7bda5f630ac9..e7d54072d7b3 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -455,7 +455,8 @@ static const struct ethtool_ops ipvlan_ethtool_ops = { }; static int ipvlan_nl_changelink(struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct ipvl_dev *ipvlan = netdev_priv(dev); struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev); diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 60f3e3089ec3..38ba3d73ac15 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -3056,7 +3056,8 @@ static void macsec_changelink_common(struct net_device *dev, } static int macsec_changelink(struct net_device *dev, struct nlattr *tb[], - struct nlattr *data[]) + struct nlattr *data[], + struct netlink_ext_ack *extack) { if (!data) return 0; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 526d23db3b71..3064416578a9 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1409,7 +1409,8 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head) EXPORT_SYMBOL_GPL(macvlan_dellink); static int macvlan_changelink(struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct macvlan_dev *vlan = netdev_priv(dev); enum macvlan_mode mode; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 50a208747179..60c40349e73e 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3347,7 +3347,8 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, } static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], - struct nlattr *data[]) + struct nlattr *data[], + struct netlink_ext_ack *extack) { struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst *dst = &vxlan->default_dst; -- cgit v1.2.3 From a8b8a889e369de82f295f55455adb4a7c31c458c Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 25 Jun 2017 23:56:01 +0200 Subject: net: add netlink_ext_ack argument to rtnl_link_ops.validate Add support for extended error reporting. Signed-off-by: Matthias Schiffer Acked-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 3 ++- drivers/net/can/dev.c | 3 ++- drivers/net/dummy.c | 3 ++- drivers/net/geneve.c | 3 ++- drivers/net/gtp.c | 3 ++- drivers/net/ifb.c | 3 ++- drivers/net/ipvlan/ipvlan_main.c | 3 ++- drivers/net/macsec.c | 3 ++- drivers/net/macvlan.c | 3 ++- drivers/net/nlmon.c | 3 ++- drivers/net/ppp/ppp_generic.c | 3 ++- drivers/net/team/team.c | 3 ++- drivers/net/tun.c | 3 ++- drivers/net/veth.c | 5 +++-- drivers/net/vrf.c | 3 ++- drivers/net/vxlan.c | 3 ++- 16 files changed, 33 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index cb803c026f1f..0a9d78de6138 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -118,7 +118,8 @@ static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { [IFLA_BOND_SLAVE_QUEUE_ID] = { .type = NLA_U16 }, }; -static int bond_validate(struct nlattr *tb[], struct nlattr *data[]) +static int bond_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 6d8191f2ad32..365a8cc62405 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -848,7 +848,8 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { = { .len = sizeof(struct can_bittiming_const) }, }; -static int can_validate(struct nlattr *tb[], struct nlattr *data[]) +static int can_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { bool is_can_fd = false; diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 9905b52fe293..d0c165d2086e 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -356,7 +356,8 @@ static void dummy_setup(struct net_device *dev) dev->max_mtu = ETH_MAX_MTU; } -static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) +static int dummy_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 0a72d914e1f9..eb77201cb718 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1058,7 +1058,8 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 }, }; -static int geneve_validate(struct nlattr *tb[], struct nlattr *data[]) +static int geneve_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 9cfe8a24c1fc..1542e837fdfa 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -698,7 +698,8 @@ static const struct nla_policy gtp_policy[IFLA_GTP_MAX + 1] = { [IFLA_GTP_ROLE] = { .type = NLA_U32 }, }; -static int gtp_validate(struct nlattr *tb[], struct nlattr *data[]) +static int gtp_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (!data) return -EINVAL; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 144ea5ae8ab4..8870bd2a2e8a 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -273,7 +273,8 @@ static int ifb_open(struct net_device *dev) return 0; } -static int ifb_validate(struct nlattr *tb[], struct nlattr *data[]) +static int ifb_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index e7d54072d7b3..f37e3c1fd4e7 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -477,7 +477,8 @@ static size_t ipvlan_nl_getsize(const struct net_device *dev) ); } -static int ipvlan_nl_validate(struct nlattr *tb[], struct nlattr *data[]) +static int ipvlan_nl_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (data && data[IFLA_IPVLAN_MODE]) { u16 mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 38ba3d73ac15..5e1ab1160856 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -3287,7 +3287,8 @@ unregister: return err; } -static int macsec_validate_attr(struct nlattr *tb[], struct nlattr *data[]) +static int macsec_validate_attr(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { u64 csid = MACSEC_DEFAULT_CIPHER_ID; u8 icv_len = DEFAULT_ICV_LEN; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 3064416578a9..9ffff0362a11 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1162,7 +1162,8 @@ static void macvlan_port_destroy(struct net_device *dev) kfree(port); } -static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) +static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c index c4b3362da4a2..4b22955de191 100644 --- a/drivers/net/nlmon.c +++ b/drivers/net/nlmon.c @@ -127,7 +127,8 @@ static void nlmon_setup(struct net_device *dev) dev->min_mtu = sizeof(struct nlmsghdr); } -static int nlmon_validate(struct nlattr *tb[], struct nlattr *data[]) +static int nlmon_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) return -EINVAL; diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 8479c130fe2e..13028833bee3 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1061,7 +1061,8 @@ static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = { [IFLA_PPP_DEV_FD] = { .type = NLA_S32 }, }; -static int ppp_nl_validate(struct nlattr *tb[], struct nlattr *data[]) +static int ppp_nl_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (!data) return -EINVAL; diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index bbe97bb7c9cc..464570409796 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2110,7 +2110,8 @@ static int team_newlink(struct net *src_net, struct net_device *dev, return register_netdevice(dev); } -static int team_validate(struct nlattr *tb[], struct nlattr *data[]) +static int team_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ae49f4b99b67..3d4c24572ecd 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1580,7 +1580,8 @@ static void tun_setup(struct net_device *dev) /* Trivial set of netlink ops to allow deleting tun or tap * device with netlink. */ -static int tun_validate(struct nlattr *tb[], struct nlattr *data[]) +static int tun_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { return -EINVAL; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 3db907cb7d07..b33553b1e19c 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -329,7 +329,8 @@ static void veth_setup(struct net_device *dev) * netlink interface */ -static int veth_validate(struct nlattr *tb[], struct nlattr *data[]) +static int veth_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) @@ -374,7 +375,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (err < 0) return err; - err = veth_validate(peer_tb, NULL); + err = veth_validate(peer_tb, NULL, extack); if (err < 0) return err; diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 762f4d033e1b..f4d0054981c6 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1372,7 +1372,8 @@ static void vrf_setup(struct net_device *dev) dev->priv_flags |= IFF_NO_QUEUE; } -static int vrf_validate(struct nlattr *tb[], struct nlattr *data[]) +static int vrf_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 60c40349e73e..0dafd8e6c665 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2711,7 +2711,8 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG }, }; -static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) +static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) { -- cgit v1.2.3 From 17dd0ec470f97518893a5ed7160a842a35482fb4 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 25 Jun 2017 23:56:02 +0200 Subject: net: add netlink_ext_ack argument to rtnl_link_ops.slave_changelink Add support for extended error reporting. Signed-off-by: Matthias Schiffer Acked-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 0a9d78de6138..a1b33aa6054a 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -132,7 +132,8 @@ static int bond_validate(struct nlattr *tb[], struct nlattr *data[], static int bond_slave_changelink(struct net_device *bond_dev, struct net_device *slave_dev, - struct nlattr *tb[], struct nlattr *data[]) + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) { struct bonding *bond = netdev_priv(bond_dev); struct bond_opt_value newval; -- cgit v1.2.3 From 593814d1beae8ad91be6c90f95764e09fc7ca236 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 26 Jun 2017 13:53:46 +0100 Subject: net/mlx4: fix spelling mistake: "coalesing" -> "coalescing" Trivial fix to spelling mistake in en_dbg debug message Signed-off-by: Colin Ian King Acked-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 18252a79a074..9da76e3be2fc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1352,7 +1352,7 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) priv->rx_usecs = MLX4_EN_RX_COAL_TIME; priv->tx_frames = MLX4_EN_TX_COAL_PKTS; priv->tx_usecs = MLX4_EN_TX_COAL_TIME; - en_dbg(INTR, priv, "Default coalesing params for mtu:%d - rx_frames:%d rx_usecs:%d\n", + en_dbg(INTR, priv, "Default coalescing params for mtu:%d - rx_frames:%d rx_usecs:%d\n", priv->dev->mtu, priv->rx_frames, priv->rx_usecs); /* Setup cq moderation params */ -- cgit v1.2.3 From 8ce59b16b4b6eacedaec1f7b652b4781cdbfe15f Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 19 Jun 2017 18:25:59 +0300 Subject: net/mlx5: Fix driver load error flow when firmware is stuck When wait for firmware init fails, previous code would mistakenly return success and cause inconsistency in the driver state. Fixes: 6c780a0267b8 ("net/mlx5: Wait for FW readiness before initializing command interface") Signed-off-by: Gal Pressman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 13be264587f1..fd47b5134841 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1020,7 +1020,7 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, if (err) { dev_err(&dev->pdev->dev, "Firmware over %d MS in pre-initializing state, aborting\n", FW_PRE_INIT_TIMEOUT_MILI); - goto out; + goto out_err; } err = mlx5_cmd_init(dev); -- cgit v1.2.3 From 2a0165a034ac024b60cca49c61e46f4afa2e4d98 Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Thu, 30 Mar 2017 17:09:00 +0300 Subject: net/mlx5: Cancel delayed recovery work when unloading the driver Draining the health workqueue will ignore future health works including the one that report hardware failure and thus we can't enter error state Instead cancel the recovery flow and make sure only recovery flow won't be scheduled. Fixes: 5e44fca50470 ('net/mlx5: Only cancel recovery work when cleaning up device') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/health.c | 15 ++++++++++++++- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index f27f84ffbc85..8a8b5f0e497c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -67,6 +67,7 @@ enum { enum { MLX5_DROP_NEW_HEALTH_WORK, + MLX5_DROP_NEW_RECOVERY_WORK, }; static u8 get_nic_state(struct mlx5_core_dev *dev) @@ -193,7 +194,7 @@ static void health_care(struct work_struct *work) mlx5_handle_bad_state(dev); spin_lock(&health->wq_lock); - if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) + if (!test_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags)) schedule_delayed_work(&health->recover_work, recover_delay); else dev_err(&dev->pdev->dev, @@ -313,6 +314,7 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev) init_timer(&health->timer); health->sick = 0; clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); + clear_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags); health->health = &dev->iseg->health; health->health_counter = &dev->iseg->health_counter; @@ -335,11 +337,22 @@ void mlx5_drain_health_wq(struct mlx5_core_dev *dev) spin_lock(&health->wq_lock); set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); + set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags); spin_unlock(&health->wq_lock); cancel_delayed_work_sync(&health->recover_work); cancel_work_sync(&health->work); } +void mlx5_drain_health_recovery(struct mlx5_core_dev *dev) +{ + struct mlx5_core_health *health = &dev->priv.health; + + spin_lock(&health->wq_lock); + set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags); + spin_unlock(&health->wq_lock); + cancel_delayed_work_sync(&dev->priv.health.recover_work); +} + void mlx5_health_cleanup(struct mlx5_core_dev *dev) { struct mlx5_core_health *health = &dev->priv.health; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index fd47b5134841..524c16f72e83 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1228,7 +1228,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, int err = 0; if (cleanup) - mlx5_drain_health_wq(dev); + mlx5_drain_health_recovery(dev); mutex_lock(&dev->intf_state_mutex); if (test_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state)) { -- cgit v1.2.3 From 8ff93de7668bd81bc8efa819d1184ebd48fae72d Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Sun, 25 Jun 2017 16:46:25 +0300 Subject: net/mlx5e: Fix TX carrier errors report in get stats ndo Symbol error during carrier counter from PPCNT was mistakenly reported as TX carrier errors in get_stats ndo, although it's an RX counter. Fixes: 269e6b3af3bf ("net/mlx5e: Report additional error statistics in get stats ndo") Signed-off-by: Gal Pressman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 277f4de30375..7819fe9ede22 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -3053,8 +3053,6 @@ mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) PPORT_802_3_GET(pstats, a_frame_check_sequence_errors); stats->rx_frame_errors = PPORT_802_3_GET(pstats, a_alignment_errors); stats->tx_aborted_errors = PPORT_2863_GET(pstats, if_out_discards); - stats->tx_carrier_errors = - PPORT_802_3_GET(pstats, a_symbol_error_during_carrier); stats->rx_errors = stats->rx_length_errors + stats->rx_crc_errors + stats->rx_frame_errors; stats->tx_errors = stats->tx_aborted_errors + stats->tx_carrier_errors; -- cgit v1.2.3 From 9ade8c7c3c6feb2c477bc20b3458b5edbcf4a87e Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Thu, 25 May 2017 08:42:07 +0300 Subject: net/mlx5: Set interface flags before cleanup in unload_one In load_one, the interface flags are changed from down to up, only after initializing the interfaces. In unload_one, the flags are changed from up to down before the interface cleanup. Change the cleanup order to be opposite to initialization order. This fixes flag consistency between init and cleanup. Signed-off-by: Ilan Tayari Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index c7f75e12c13b..9a5a475d9e00 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1254,6 +1254,9 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, goto out; } + clear_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state); + set_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state); + if (mlx5_device_registered(dev)) mlx5_detach_device(dev); @@ -1282,8 +1285,6 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, mlx5_cmd_cleanup(dev); out: - clear_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state); - set_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state); mutex_unlock(&dev->intf_state_mutex); return err; } -- cgit v1.2.3 From 52ec462eca9b87b8036209483efe1c6cf9c49d9a Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Sun, 26 Mar 2017 17:01:57 +0300 Subject: net/mlx5: Add reserved-gids support Reserved GIDs are entries in the GID table in use by the mlx5_core and its submodules (e.g. FPGA, SRIOV, E-Swtich, netdev). The entries are reserved at the high indexes of the GID table. A mlx5 submodule may reserve a certain amount of GIDs for its own use during the load sequence by calling mlx5_core_reserve_gids, and must also take care to un-reserve these GIDs when it closes. Reservation is only allowed during the load sequence and before any interfaces (e.g. mlx5_ib or mlx5_en) are up. After reservation, a submodule may call mlx5_core_reserved_gid_alloc/ free to allocate entries from the reserved GIDs pool. Reserve a GID table entry for every supported FPGA QP. A later patch in the patchset will remove them from being reported to IB core. Another such patch will make use of these for FPGA QPs in Innova NIC. Added lib/mlx5.h to serve as a library for mlx5 submodlues, and to expose only public mlx5 API, more mlx5 library files will be added in future submissions. Signed-off-by: Ilan Tayari Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 +- .../net/ethernet/mellanox/mlx5/core/fpga/core.c | 31 ++++- .../net/ethernet/mellanox/mlx5/core/fpga/core.h | 5 + drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c | 154 +++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h | 43 ++++++ drivers/net/ethernet/mellanox/mlx5/core/main.c | 11 +- 6 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 5ad093a21a6e..738867bab21f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -4,7 +4,7 @@ subdir-ccflags-y += -I$(src) mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \ mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ - fs_counters.o rl.o lag.o dev.o + fs_counters.o rl.o lag.o dev.o lib/gid.o mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c index d88b332e9669..92d8b1b6e598 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c @@ -35,6 +35,7 @@ #include #include "mlx5_core.h" +#include "lib/mlx5.h" #include "fpga/core.h" static const char *const mlx5_fpga_error_strings[] = { @@ -104,6 +105,7 @@ int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) { struct mlx5_fpga_device *fdev = mdev->fpga; unsigned long flags; + unsigned int max_num_qps; int err; if (!fdev) @@ -123,6 +125,9 @@ int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) mlx5_fpga_image_name(fdev->last_oper_image), MLX5_CAP_FPGA(fdev->mdev, image_version)); + max_num_qps = MLX5_CAP_FPGA(mdev, shell_caps.max_num_qps); + err = mlx5_core_reserve_gids(mdev, max_num_qps); + out: spin_lock_irqsave(&fdev->state_lock, flags); fdev->state = err ? MLX5_FPGA_STATUS_FAILURE : MLX5_FPGA_STATUS_SUCCESS; @@ -151,9 +156,33 @@ int mlx5_fpga_device_init(struct mlx5_core_dev *mdev) return 0; } +void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev) +{ + struct mlx5_fpga_device *fdev = mdev->fpga; + unsigned int max_num_qps; + unsigned long flags; + + if (!fdev) + return; + + spin_lock_irqsave(&fdev->state_lock, flags); + if (fdev->state != MLX5_FPGA_STATUS_SUCCESS) { + spin_unlock_irqrestore(&fdev->state_lock, flags); + return; + } + fdev->state = MLX5_FPGA_STATUS_NONE; + spin_unlock_irqrestore(&fdev->state_lock, flags); + + max_num_qps = MLX5_CAP_FPGA(mdev, shell_caps.max_num_qps); + mlx5_core_unreserve_gids(mdev, max_num_qps); +} + void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev) { - kfree(mdev->fpga); + struct mlx5_fpga_device *fdev = mdev->fpga; + + mlx5_fpga_device_stop(mdev); + kfree(fdev); mdev->fpga = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h index c55044d66778..557d83973ade 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h @@ -71,6 +71,7 @@ struct mlx5_fpga_device { int mlx5_fpga_device_init(struct mlx5_core_dev *mdev); void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev); int mlx5_fpga_device_start(struct mlx5_core_dev *mdev); +void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev); void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data); #else @@ -89,6 +90,10 @@ static inline int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) return 0; } +static inline void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev) +{ +} + static inline void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c new file mode 100644 index 000000000000..4d0db481f6c4 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "mlx5_core.h" + +void mlx5_init_reserved_gids(struct mlx5_core_dev *dev) +{ + unsigned int tblsz = MLX5_CAP_ROCE(dev, roce_address_table_size); + + ida_init(&dev->roce.reserved_gids.ida); + dev->roce.reserved_gids.start = tblsz; + dev->roce.reserved_gids.count = 0; +} + +void mlx5_cleanup_reserved_gids(struct mlx5_core_dev *dev) +{ + WARN_ON(!ida_is_empty(&dev->roce.reserved_gids.ida)); + dev->roce.reserved_gids.start = 0; + dev->roce.reserved_gids.count = 0; + ida_destroy(&dev->roce.reserved_gids.ida); +} + +int mlx5_core_reserve_gids(struct mlx5_core_dev *dev, unsigned int count) +{ + if (test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state)) { + mlx5_core_err(dev, "Cannot reserve GIDs when interfaces are up\n"); + return -EPERM; + } + if (dev->roce.reserved_gids.start < count) { + mlx5_core_warn(dev, "GID table exhausted attempting to reserve %d more GIDs\n", + count); + return -ENOMEM; + } + if (dev->roce.reserved_gids.count + count > MLX5_MAX_RESERVED_GIDS) { + mlx5_core_warn(dev, "Unable to reserve %d more GIDs\n", count); + return -ENOMEM; + } + + dev->roce.reserved_gids.start -= count; + dev->roce.reserved_gids.count += count; + mlx5_core_dbg(dev, "Reserved %u GIDs starting at %u\n", + dev->roce.reserved_gids.count, + dev->roce.reserved_gids.start); + return 0; +} + +void mlx5_core_unreserve_gids(struct mlx5_core_dev *dev, unsigned int count) +{ + WARN(test_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state), "Unreserving GIDs when interfaces are up"); + WARN(count > dev->roce.reserved_gids.count, "Unreserving %u GIDs when only %u reserved", + count, dev->roce.reserved_gids.count); + + dev->roce.reserved_gids.start += count; + dev->roce.reserved_gids.count -= count; + mlx5_core_dbg(dev, "%u GIDs starting at %u left reserved\n", + dev->roce.reserved_gids.count, + dev->roce.reserved_gids.start); +} + +int mlx5_core_reserved_gid_alloc(struct mlx5_core_dev *dev, int *gid_index) +{ + int end = dev->roce.reserved_gids.start + + dev->roce.reserved_gids.count; + int index = 0; + + index = ida_simple_get(&dev->roce.reserved_gids.ida, + dev->roce.reserved_gids.start, end, + GFP_KERNEL); + if (index < 0) + return index; + + mlx5_core_dbg(dev, "Allodating reserved GID %u\n", index); + *gid_index = index; + return 0; +} + +void mlx5_core_reserved_gid_free(struct mlx5_core_dev *dev, int gid_index) +{ + mlx5_core_dbg(dev, "Freeing reserved GID %u\n", gid_index); + ida_simple_remove(&dev->roce.reserved_gids.ida, gid_index); +} + +unsigned int mlx5_core_reserved_gids_count(struct mlx5_core_dev *dev) +{ + return dev->roce.reserved_gids.count; +} +EXPORT_SYMBOL_GPL(mlx5_core_reserved_gids_count); + +int mlx5_core_roce_gid_set(struct mlx5_core_dev *dev, unsigned int index, + u8 roce_version, u8 roce_l3_type, const u8 *gid, + const u8 *mac, bool vlan, u16 vlan_id) +{ +#define MLX5_SET_RA(p, f, v) MLX5_SET(roce_addr_layout, p, f, v) + u32 in[MLX5_ST_SZ_DW(set_roce_address_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(set_roce_address_out)] = {0}; + void *in_addr = MLX5_ADDR_OF(set_roce_address_in, in, roce_address); + char *addr_l3_addr = MLX5_ADDR_OF(roce_addr_layout, in_addr, + source_l3_address); + void *addr_mac = MLX5_ADDR_OF(roce_addr_layout, in_addr, + source_mac_47_32); + int gidsz = MLX5_FLD_SZ_BYTES(roce_addr_layout, source_l3_address); + + if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) + return -EINVAL; + + if (gid) { + if (vlan) { + MLX5_SET_RA(in_addr, vlan_valid, 1); + MLX5_SET_RA(in_addr, vlan_id, vlan_id); + } + + ether_addr_copy(addr_mac, mac); + MLX5_SET_RA(in_addr, roce_version, roce_version); + MLX5_SET_RA(in_addr, roce_l3_type, roce_l3_type); + memcpy(addr_l3_addr, gid, gidsz); + } + + MLX5_SET(set_roce_address_in, in, roce_address_index, index); + MLX5_SET(set_roce_address_in, in, opcode, MLX5_CMD_OP_SET_ROCE_ADDRESS); + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} +EXPORT_SYMBOL(mlx5_core_roce_gid_set); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h new file mode 100644 index 000000000000..7550b1cc8c6a --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __LIB_MLX5_H__ +#define __LIB_MLX5_H__ + +void mlx5_init_reserved_gids(struct mlx5_core_dev *dev); +void mlx5_cleanup_reserved_gids(struct mlx5_core_dev *dev); +int mlx5_core_reserve_gids(struct mlx5_core_dev *dev, unsigned int count); +void mlx5_core_unreserve_gids(struct mlx5_core_dev *dev, unsigned int count); +int mlx5_core_reserved_gid_alloc(struct mlx5_core_dev *dev, int *gid_index); +void mlx5_core_reserved_gid_free(struct mlx5_core_dev *dev, int gid_index); + +#endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 9a5a475d9e00..55f9fccfc394 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -56,6 +56,7 @@ #ifdef CONFIG_MLX5_CORE_EN #include "eswitch.h" #endif +#include "lib/mlx5.h" #include "fpga/core.h" MODULE_AUTHOR("Eli Cohen "); @@ -936,6 +937,8 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv) mlx5_init_mkey_table(dev); + mlx5_init_reserved_gids(dev); + err = mlx5_init_rl_table(dev); if (err) { dev_err(&pdev->dev, "Failed to init rate limiting\n"); @@ -986,6 +989,7 @@ static void mlx5_cleanup_once(struct mlx5_core_dev *dev) mlx5_eswitch_cleanup(dev->priv.eswitch); #endif mlx5_cleanup_rl_table(dev); + mlx5_cleanup_reserved_gids(dev); mlx5_cleanup_mkey_table(dev); mlx5_cleanup_srq_table(dev); mlx5_cleanup_qp_table(dev); @@ -1160,7 +1164,7 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, err = mlx5_fpga_device_start(dev); if (err) { dev_err(&pdev->dev, "fpga device start failed %d\n", err); - goto err_reg_dev; + goto err_fpga_start; } if (mlx5_device_registered(dev)) { @@ -1181,6 +1185,9 @@ out: return 0; err_reg_dev: + mlx5_fpga_device_stop(dev); + +err_fpga_start: mlx5_sriov_detach(dev); err_sriov: @@ -1260,6 +1267,8 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, if (mlx5_device_registered(dev)) mlx5_detach_device(dev); + mlx5_fpga_device_stop(dev); + mlx5_sriov_detach(dev); #ifdef CONFIG_MLX5_CORE_EN mlx5_eswitch_detach(dev->priv.eswitch); -- cgit v1.2.3 From a6f7d2aff623bb7572d4bca1caf5820e0cd5a586 Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Sun, 26 Mar 2017 17:23:42 +0300 Subject: net/mlx5: Add support for multiple RoCE enable Previously, only mlx5_ib enabled RoCE on the port, but FPGA needs it as well. Add support for counting number of enables, so that FPGA and IB can work in parallel and independently. Program the HW to enable RoCE on the first enable call, and program to disable RoCE on the last disable call. Signed-off-by: Ilan Tayari Reviewed-by: Boris Pismenny Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 06019d00ab7b..5abfec1c3399 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -926,12 +926,16 @@ static int mlx5_nic_vport_update_roce_state(struct mlx5_core_dev *mdev, int mlx5_nic_vport_enable_roce(struct mlx5_core_dev *mdev) { + if (atomic_inc_return(&mdev->roce.roce_en) != 1) + return 0; return mlx5_nic_vport_update_roce_state(mdev, MLX5_VPORT_ROCE_ENABLED); } EXPORT_SYMBOL_GPL(mlx5_nic_vport_enable_roce); int mlx5_nic_vport_disable_roce(struct mlx5_core_dev *mdev) { + if (atomic_dec_return(&mdev->roce.roce_en) != 0) + return 0; return mlx5_nic_vport_update_roce_state(mdev, MLX5_VPORT_ROCE_DISABLED); } EXPORT_SYMBOL_GPL(mlx5_nic_vport_disable_roce); -- cgit v1.2.3 From 095b0927f0ce74f7211b9046f8493dbba26ca930 Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Sun, 14 May 2017 16:04:30 +0300 Subject: IB/mlx5: Respect mlx5_core reserved GIDs Reserved gids are taken by the mlx5_core, report smaller GID table size to IB core. Set mlx5_query_roce_port's return value back to int. In case of error, return an indication. This rolls back some of the change in commit 50f22fd8ecf9 ("IB/mlx5: Set mlx5_query_roce_port's return value to void") Change set_roce_addr to use gid_set function, instead of directly sending the command. Signed-off-by: Ilan Tayari Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- drivers/infiniband/hw/mlx5/main.c | 119 +++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 9f7e18612322..dc2f59e33971 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -223,8 +223,8 @@ static int translate_eth_proto_oper(u32 eth_proto_oper, u8 *active_speed, return 0; } -static void mlx5_query_port_roce(struct ib_device *device, u8 port_num, - struct ib_port_attr *props) +static int mlx5_query_port_roce(struct ib_device *device, u8 port_num, + struct ib_port_attr *props) { struct mlx5_ib_dev *dev = to_mdev(device); struct mlx5_core_dev *mdev = dev->mdev; @@ -232,12 +232,14 @@ static void mlx5_query_port_roce(struct ib_device *device, u8 port_num, enum ib_mtu ndev_ib_mtu; u16 qkey_viol_cntr; u32 eth_prot_oper; + int err; /* Possible bad flows are checked before filling out props so in case * of an error it will still be zeroed out. */ - if (mlx5_query_port_eth_proto_oper(mdev, ð_prot_oper, port_num)) - return; + err = mlx5_query_port_eth_proto_oper(mdev, ð_prot_oper, port_num); + if (err) + return err; translate_eth_proto_oper(eth_prot_oper, &props->active_speed, &props->active_width); @@ -258,7 +260,7 @@ static void mlx5_query_port_roce(struct ib_device *device, u8 port_num, ndev = mlx5_ib_get_netdev(device, port_num); if (!ndev) - return; + return 0; if (mlx5_lag_is_active(dev->mdev)) { rcu_read_lock(); @@ -281,75 +283,49 @@ static void mlx5_query_port_roce(struct ib_device *device, u8 port_num, dev_put(ndev); props->active_mtu = min(props->max_mtu, ndev_ib_mtu); + return 0; } -static void ib_gid_to_mlx5_roce_addr(const union ib_gid *gid, - const struct ib_gid_attr *attr, - void *mlx5_addr) +static int set_roce_addr(struct mlx5_ib_dev *dev, u8 port_num, + unsigned int index, const union ib_gid *gid, + const struct ib_gid_attr *attr) { -#define MLX5_SET_RA(p, f, v) MLX5_SET(roce_addr_layout, p, f, v) - char *mlx5_addr_l3_addr = MLX5_ADDR_OF(roce_addr_layout, mlx5_addr, - source_l3_address); - void *mlx5_addr_mac = MLX5_ADDR_OF(roce_addr_layout, mlx5_addr, - source_mac_47_32); - - if (!gid) - return; + enum ib_gid_type gid_type = IB_GID_TYPE_IB; + u8 roce_version = 0; + u8 roce_l3_type = 0; + bool vlan = false; + u8 mac[ETH_ALEN]; + u16 vlan_id = 0; - ether_addr_copy(mlx5_addr_mac, attr->ndev->dev_addr); + if (gid) { + gid_type = attr->gid_type; + ether_addr_copy(mac, attr->ndev->dev_addr); - if (is_vlan_dev(attr->ndev)) { - MLX5_SET_RA(mlx5_addr, vlan_valid, 1); - MLX5_SET_RA(mlx5_addr, vlan_id, vlan_dev_vlan_id(attr->ndev)); + if (is_vlan_dev(attr->ndev)) { + vlan = true; + vlan_id = vlan_dev_vlan_id(attr->ndev); + } } - switch (attr->gid_type) { + switch (gid_type) { case IB_GID_TYPE_IB: - MLX5_SET_RA(mlx5_addr, roce_version, MLX5_ROCE_VERSION_1); + roce_version = MLX5_ROCE_VERSION_1; break; case IB_GID_TYPE_ROCE_UDP_ENCAP: - MLX5_SET_RA(mlx5_addr, roce_version, MLX5_ROCE_VERSION_2); + roce_version = MLX5_ROCE_VERSION_2; + if (ipv6_addr_v4mapped((void *)gid)) + roce_l3_type = MLX5_ROCE_L3_TYPE_IPV4; + else + roce_l3_type = MLX5_ROCE_L3_TYPE_IPV6; break; default: - WARN_ON(true); + mlx5_ib_warn(dev, "Unexpected GID type %u\n", gid_type); } - if (attr->gid_type != IB_GID_TYPE_IB) { - if (ipv6_addr_v4mapped((void *)gid)) - MLX5_SET_RA(mlx5_addr, roce_l3_type, - MLX5_ROCE_L3_TYPE_IPV4); - else - MLX5_SET_RA(mlx5_addr, roce_l3_type, - MLX5_ROCE_L3_TYPE_IPV6); - } - - if ((attr->gid_type == IB_GID_TYPE_IB) || - !ipv6_addr_v4mapped((void *)gid)) - memcpy(mlx5_addr_l3_addr, gid, sizeof(*gid)); - else - memcpy(&mlx5_addr_l3_addr[12], &gid->raw[12], 4); -} - -static int set_roce_addr(struct ib_device *device, u8 port_num, - unsigned int index, - const union ib_gid *gid, - const struct ib_gid_attr *attr) -{ - struct mlx5_ib_dev *dev = to_mdev(device); - u32 in[MLX5_ST_SZ_DW(set_roce_address_in)] = {0}; - u32 out[MLX5_ST_SZ_DW(set_roce_address_out)] = {0}; - void *in_addr = MLX5_ADDR_OF(set_roce_address_in, in, roce_address); - enum rdma_link_layer ll = mlx5_ib_port_link_layer(device, port_num); - - if (ll != IB_LINK_LAYER_ETHERNET) - return -EINVAL; - - ib_gid_to_mlx5_roce_addr(gid, attr, in_addr); - - MLX5_SET(set_roce_address_in, in, roce_address_index, index); - MLX5_SET(set_roce_address_in, in, opcode, MLX5_CMD_OP_SET_ROCE_ADDRESS); - return mlx5_cmd_exec(dev->mdev, in, sizeof(in), out, sizeof(out)); + return mlx5_core_roce_gid_set(dev->mdev, index, roce_version, + roce_l3_type, gid->raw, mac, vlan, + vlan_id); } static int mlx5_ib_add_gid(struct ib_device *device, u8 port_num, @@ -357,13 +333,13 @@ static int mlx5_ib_add_gid(struct ib_device *device, u8 port_num, const struct ib_gid_attr *attr, __always_unused void **context) { - return set_roce_addr(device, port_num, index, gid, attr); + return set_roce_addr(to_mdev(device), port_num, index, gid, attr); } static int mlx5_ib_del_gid(struct ib_device *device, u8 port_num, unsigned int index, __always_unused void **context) { - return set_roce_addr(device, port_num, index, NULL, NULL); + return set_roce_addr(to_mdev(device), port_num, index, NULL, NULL); } __be16 mlx5_get_roce_udp_sport(struct mlx5_ib_dev *dev, u8 port_num, @@ -978,20 +954,31 @@ out: int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props) { + unsigned int count; + int ret; + switch (mlx5_get_vport_access_method(ibdev)) { case MLX5_VPORT_ACCESS_METHOD_MAD: - return mlx5_query_mad_ifc_port(ibdev, port, props); + ret = mlx5_query_mad_ifc_port(ibdev, port, props); + break; case MLX5_VPORT_ACCESS_METHOD_HCA: - return mlx5_query_hca_port(ibdev, port, props); + ret = mlx5_query_hca_port(ibdev, port, props); + break; case MLX5_VPORT_ACCESS_METHOD_NIC: - mlx5_query_port_roce(ibdev, port, props); - return 0; + ret = mlx5_query_port_roce(ibdev, port, props); + break; default: - return -EINVAL; + ret = -EINVAL; + } + + if (!ret && props) { + count = mlx5_core_reserved_gids_count(to_mdev(ibdev)->mdev); + props->gid_tbl_len -= count; } + return ret; } static int mlx5_ib_query_gid(struct ib_device *ibdev, u8 port, int index, -- cgit v1.2.3 From 4b67379376b3674c069477aa48fe8923f735247e Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Mon, 19 Jun 2017 12:53:25 +0300 Subject: net/mlx5: Make get_cqe routine not ethernet-specific Move mlx5e_get_cqe routine to wq.h and rename it to mlx5_cqwq_get_cqe. This allows it to be used by other CQ users outside of the ethernet driver code. A later patch in this patchset will make use of it from FPGA code for the FPGA high-speed connection. Signed-off-by: Ilan Tayari Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 - drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c | 19 +------------------ drivers/net/ethernet/mellanox/mlx5/core/wq.h | 17 +++++++++++++++++ 5 files changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index eef0a50e2388..f93f44d1d1cf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -833,7 +833,6 @@ void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix); void mlx5e_dealloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix); void mlx5e_post_rx_mpwqe(struct mlx5e_rq *rq); void mlx5e_free_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi); -struct mlx5_cqe64 *mlx5e_get_cqe(struct mlx5e_cq *cq); void mlx5e_rx_am(struct mlx5e_rq *rq); void mlx5e_rx_am_work(struct work_struct *work); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 5f3c138c948d..574a96279340 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -996,7 +996,7 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget) work_done += mlx5e_decompress_cqes_cont(rq, cq, 0, budget); for (; work_done < budget; work_done++) { - struct mlx5_cqe64 *cqe = mlx5e_get_cqe(cq); + struct mlx5_cqe64 *cqe = mlx5_cqwq_get_cqe(&cq->wq); if (!cqe) break; @@ -1050,7 +1050,7 @@ bool mlx5e_poll_xdpsq_cq(struct mlx5e_cq *cq) u16 wqe_counter; bool last_wqe; - cqe = mlx5e_get_cqe(cq); + cqe = mlx5_cqwq_get_cqe(&cq->wq); if (!cqe) break; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 0433d69429f3..ccec3b00e17c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -409,7 +409,7 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) u16 wqe_counter; bool last_wqe; - cqe = mlx5e_get_cqe(cq); + cqe = mlx5_cqwq_get_cqe(&cq->wq); if (!cqe) break; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c index 5ca6714e3e02..92db28a9ed43 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c @@ -32,23 +32,6 @@ #include "en.h" -struct mlx5_cqe64 *mlx5e_get_cqe(struct mlx5e_cq *cq) -{ - struct mlx5_cqwq *wq = &cq->wq; - u32 ci = mlx5_cqwq_get_ci(wq); - struct mlx5_cqe64 *cqe = mlx5_cqwq_get_wqe(wq, ci); - u8 cqe_ownership_bit = cqe->op_own & MLX5_CQE_OWNER_MASK; - u8 sw_ownership_val = mlx5_cqwq_get_wrap_cnt(wq) & 1; - - if (cqe_ownership_bit != sw_ownership_val) - return NULL; - - /* ensure cqe content is read after cqe ownership bit */ - dma_rmb(); - - return cqe; -} - static inline void mlx5e_poll_ico_single_cqe(struct mlx5e_cq *cq, struct mlx5e_icosq *sq, struct mlx5_cqe64 *cqe, @@ -89,7 +72,7 @@ static void mlx5e_poll_ico_cq(struct mlx5e_cq *cq) if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state))) return; - cqe = mlx5e_get_cqe(cq); + cqe = mlx5_cqwq_get_cqe(&cq->wq); if (likely(!cqe)) return; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h index d8afed898c31..9ded5d40ce6b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h @@ -34,6 +34,7 @@ #define __MLX5_WQ_H__ #include +#include struct mlx5_wq_param { int linear; @@ -146,6 +147,22 @@ static inline void mlx5_cqwq_update_db_record(struct mlx5_cqwq *wq) *wq->db = cpu_to_be32(wq->cc & 0xffffff); } +static inline struct mlx5_cqe64 *mlx5_cqwq_get_cqe(struct mlx5_cqwq *wq) +{ + u32 ci = mlx5_cqwq_get_ci(wq); + struct mlx5_cqe64 *cqe = mlx5_cqwq_get_wqe(wq, ci); + u8 cqe_ownership_bit = cqe->op_own & MLX5_CQE_OWNER_MASK; + u8 sw_ownership_val = mlx5_cqwq_get_wrap_cnt(wq) & 1; + + if (cqe_ownership_bit != sw_ownership_val) + return NULL; + + /* ensure cqe content is read after cqe ownership bit */ + dma_rmb(); + + return cqe; +} + static inline int mlx5_wq_ll_is_full(struct mlx5_wq_ll *wq) { return wq->cur_sz == wq->sz_m1; -- cgit v1.2.3 From 3f2b7edd7cf59c1ec886bd478b88cfb5d809040b Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Sun, 26 Mar 2017 17:46:03 +0300 Subject: net/mlx5: Add QP WQ support A QP in ConnectX is a concatenation of RQ and SQ which share a QP-number and work together. Add support for allocating and managing the work-queue buffer for a QP, in a similar way to how SQs and RQs are already supported. Signed-off-by: Ilan Tayari Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/wq.c | 46 ++++++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/wq.h | 10 ++++++ 2 files changed, 56 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.c b/drivers/net/ethernet/mellanox/mlx5/core/wq.c index 921673c42bc9..6bcfc25350f5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.c @@ -54,6 +54,12 @@ static u32 mlx5_wq_cyc_get_byte_size(struct mlx5_wq_cyc *wq) return mlx5_wq_cyc_get_size(wq) << wq->log_stride; } +static u32 mlx5_wq_qp_get_byte_size(struct mlx5_wq_qp *wq) +{ + return mlx5_wq_cyc_get_byte_size(&wq->rq) + + mlx5_wq_cyc_get_byte_size(&wq->sq); +} + static u32 mlx5_cqwq_get_byte_size(struct mlx5_cqwq *wq) { return mlx5_cqwq_get_size(wq) << wq->log_stride; @@ -99,6 +105,46 @@ err_db_free: return err; } +int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, + void *qpc, struct mlx5_wq_qp *wq, + struct mlx5_wq_ctrl *wq_ctrl) +{ + int err; + + wq->rq.log_stride = MLX5_GET(qpc, qpc, log_rq_stride) + 4; + wq->rq.sz_m1 = (1 << MLX5_GET(qpc, qpc, log_rq_size)) - 1; + + wq->sq.log_stride = ilog2(MLX5_SEND_WQE_BB); + wq->sq.sz_m1 = (1 << MLX5_GET(qpc, qpc, log_sq_size)) - 1; + + err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node); + if (err) { + mlx5_core_warn(mdev, "mlx5_db_alloc_node() failed, %d\n", err); + return err; + } + + err = mlx5_buf_alloc_node(mdev, mlx5_wq_qp_get_byte_size(wq), + &wq_ctrl->buf, param->buf_numa_node); + if (err) { + mlx5_core_warn(mdev, "mlx5_buf_alloc_node() failed, %d\n", err); + goto err_db_free; + } + + wq->rq.buf = wq_ctrl->buf.direct.buf; + wq->sq.buf = wq->rq.buf + mlx5_wq_cyc_get_byte_size(&wq->rq); + wq->rq.db = &wq_ctrl->db.db[MLX5_RCV_DBR]; + wq->sq.db = &wq_ctrl->db.db[MLX5_SND_DBR]; + + wq_ctrl->mdev = mdev; + + return 0; + +err_db_free: + mlx5_db_free(mdev, &wq_ctrl->db); + + return err; +} + int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *cqc, struct mlx5_cqwq *wq, struct mlx5_frag_wq_ctrl *wq_ctrl) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h index 9ded5d40ce6b..718589d0cec2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h @@ -35,6 +35,7 @@ #include #include +#include struct mlx5_wq_param { int linear; @@ -61,6 +62,11 @@ struct mlx5_wq_cyc { u8 log_stride; }; +struct mlx5_wq_qp { + struct mlx5_wq_cyc rq; + struct mlx5_wq_cyc sq; +}; + struct mlx5_cqwq { struct mlx5_frag_buf frag_buf; __be32 *db; @@ -88,6 +94,10 @@ int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, struct mlx5_wq_ctrl *wq_ctrl); u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq); +int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, + void *qpc, struct mlx5_wq_qp *wq, + struct mlx5_wq_ctrl *wq_ctrl); + int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *cqc, struct mlx5_cqwq *wq, struct mlx5_frag_wq_ctrl *wq_ctrl); -- cgit v1.2.3 From 9410733c44d768b085af3877ccf63efa298168e9 Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Wed, 14 Jun 2017 10:19:54 +0300 Subject: net/mlx5: FPGA, Move FPGA init/cleanup to init_once The FPGA init and cleanup routines should be called just once per device. Move them to the init_once and cleanup_once routines. Signed-off-by: Ilan Tayari Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h | 8 ++++---- drivers/net/ethernet/mellanox/mlx5/core/main.c | 21 ++++++++++----------- 3 files changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c index 92d8b1b6e598..c3bb4b865f01 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c @@ -135,7 +135,7 @@ out: return err; } -int mlx5_fpga_device_init(struct mlx5_core_dev *mdev) +int mlx5_fpga_init(struct mlx5_core_dev *mdev) { struct mlx5_fpga_device *fdev = NULL; @@ -177,7 +177,7 @@ void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev) mlx5_core_unreserve_gids(mdev, max_num_qps); } -void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev) +void mlx5_fpga_cleanup(struct mlx5_core_dev *mdev) { struct mlx5_fpga_device *fdev = mdev->fpga; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h index 557d83973ade..db1d22c356e0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h @@ -68,20 +68,20 @@ struct mlx5_fpga_device { #define mlx5_fpga_info(__adev, format, ...) \ dev_info(&(__adev)->mdev->pdev->dev, "FPGA: " format, ##__VA_ARGS__) -int mlx5_fpga_device_init(struct mlx5_core_dev *mdev); -void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev); +int mlx5_fpga_init(struct mlx5_core_dev *mdev); +void mlx5_fpga_cleanup(struct mlx5_core_dev *mdev); int mlx5_fpga_device_start(struct mlx5_core_dev *mdev); void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev); void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data); #else -static inline int mlx5_fpga_device_init(struct mlx5_core_dev *mdev) +static inline int mlx5_fpga_init(struct mlx5_core_dev *mdev) { return 0; } -static inline void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev) +static inline void mlx5_fpga_cleanup(struct mlx5_core_dev *mdev) { } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 55f9fccfc394..684612778677 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -959,8 +959,16 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv) goto err_eswitch_cleanup; } + err = mlx5_fpga_init(dev); + if (err) { + dev_err(&pdev->dev, "Failed to init fpga device %d\n", err); + goto err_sriov_cleanup; + } + return 0; +err_sriov_cleanup: + mlx5_sriov_cleanup(dev); err_eswitch_cleanup: #ifdef CONFIG_MLX5_CORE_EN mlx5_eswitch_cleanup(dev->priv.eswitch); @@ -984,6 +992,7 @@ out: static void mlx5_cleanup_once(struct mlx5_core_dev *dev) { + mlx5_fpga_cleanup(dev); mlx5_sriov_cleanup(dev); #ifdef CONFIG_MLX5_CORE_EN mlx5_eswitch_cleanup(dev->priv.eswitch); @@ -1121,16 +1130,10 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, goto err_disable_msix; } - err = mlx5_fpga_device_init(dev); - if (err) { - dev_err(&pdev->dev, "fpga device init failed %d\n", err); - goto err_put_uars; - } - err = mlx5_start_eqs(dev); if (err) { dev_err(&pdev->dev, "Failed to start pages and async EQs\n"); - goto err_fpga_init; + goto err_put_uars; } err = alloc_comp_eqs(dev); @@ -1205,9 +1208,6 @@ err_affinity_hints: err_stop_eqs: mlx5_stop_eqs(dev); -err_fpga_init: - mlx5_fpga_device_cleanup(dev); - err_put_uars: mlx5_put_uars_page(dev, priv->uar); @@ -1277,7 +1277,6 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, mlx5_irq_clear_affinity_hints(dev); free_comp_eqs(dev); mlx5_stop_eqs(dev); - mlx5_fpga_device_cleanup(dev); mlx5_put_uars_page(dev, priv->uar); mlx5_disable_msix(dev); if (cleanup) -- cgit v1.2.3 From 6062118d5cd2b90369278cdf831aeffb84ae3943 Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Mon, 27 Mar 2017 14:52:09 +0300 Subject: net/mlx5: FPGA, Add FW commands for FPGA QPs The FPGA QP is a high-bandwidth communication channel between the host CPU and the FPGA device. It allows performing DMA operations between host memory and the FPGA logic via the ConnectX chip. Add ConnectX FW commands which create and manipulate FPGA QPs. Signed-off-by: Ilan Tayari Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 10 +++ drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c | 98 ++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h | 21 +++++ 3 files changed, 129 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 4d5bd01f1ebb..f5a2c605749f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -307,6 +307,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_SET_FLOW_TABLE_ROOT: case MLX5_CMD_OP_DEALLOC_ENCAP_HEADER: case MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT: + case MLX5_CMD_OP_FPGA_DESTROY_QP: return MLX5_CMD_STAT_OK; case MLX5_CMD_OP_QUERY_HCA_CAP: @@ -419,6 +420,10 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_QUERY_FLOW_COUNTER: case MLX5_CMD_OP_ALLOC_ENCAP_HEADER: case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT: + case MLX5_CMD_OP_FPGA_CREATE_QP: + case MLX5_CMD_OP_FPGA_MODIFY_QP: + case MLX5_CMD_OP_FPGA_QUERY_QP: + case MLX5_CMD_OP_FPGA_QUERY_QP_COUNTERS: *status = MLX5_DRIVER_STATUS_ABORTED; *synd = MLX5_DRIVER_SYND; return -EIO; @@ -585,6 +590,11 @@ const char *mlx5_command_str(int command) MLX5_COMMAND_STR_CASE(DEALLOC_ENCAP_HEADER); MLX5_COMMAND_STR_CASE(ALLOC_MODIFY_HEADER_CONTEXT); MLX5_COMMAND_STR_CASE(DEALLOC_MODIFY_HEADER_CONTEXT); + MLX5_COMMAND_STR_CASE(FPGA_CREATE_QP); + MLX5_COMMAND_STR_CASE(FPGA_MODIFY_QP); + MLX5_COMMAND_STR_CASE(FPGA_QUERY_QP); + MLX5_COMMAND_STR_CASE(FPGA_QUERY_QP_COUNTERS); + MLX5_COMMAND_STR_CASE(FPGA_DESTROY_QP); default: return "unknown command opcode"; } } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c index 99cba644b4fc..8308ccbad85a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "mlx5_core.h" #include "fpga/cmd.h" @@ -62,3 +63,100 @@ int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query) query->oper_image = MLX5_GET(fpga_ctrl, out, flash_select_oper); return 0; } + +int mlx5_fpga_create_qp(struct mlx5_core_dev *dev, void *fpga_qpc, + u32 *fpga_qpn) +{ + u32 in[MLX5_ST_SZ_DW(fpga_create_qp_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(fpga_create_qp_out)]; + int ret; + + MLX5_SET(fpga_create_qp_in, in, opcode, MLX5_CMD_OP_FPGA_CREATE_QP); + memcpy(MLX5_ADDR_OF(fpga_create_qp_in, in, fpga_qpc), fpga_qpc, + MLX5_FLD_SZ_BYTES(fpga_create_qp_in, fpga_qpc)); + + ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); + if (ret) + return ret; + + memcpy(fpga_qpc, MLX5_ADDR_OF(fpga_create_qp_out, out, fpga_qpc), + MLX5_FLD_SZ_BYTES(fpga_create_qp_out, fpga_qpc)); + *fpga_qpn = MLX5_GET(fpga_create_qp_out, out, fpga_qpn); + return ret; +} + +int mlx5_fpga_modify_qp(struct mlx5_core_dev *dev, u32 fpga_qpn, + enum mlx5_fpga_qpc_field_select fields, + void *fpga_qpc) +{ + u32 in[MLX5_ST_SZ_DW(fpga_modify_qp_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(fpga_modify_qp_out)]; + + MLX5_SET(fpga_modify_qp_in, in, opcode, MLX5_CMD_OP_FPGA_MODIFY_QP); + MLX5_SET(fpga_modify_qp_in, in, field_select, fields); + MLX5_SET(fpga_modify_qp_in, in, fpga_qpn, fpga_qpn); + memcpy(MLX5_ADDR_OF(fpga_modify_qp_in, in, fpga_qpc), fpga_qpc, + MLX5_FLD_SZ_BYTES(fpga_modify_qp_in, fpga_qpc)); + + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + +int mlx5_fpga_query_qp(struct mlx5_core_dev *dev, + u32 fpga_qpn, void *fpga_qpc) +{ + u32 in[MLX5_ST_SZ_DW(fpga_query_qp_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(fpga_query_qp_out)]; + int ret; + + MLX5_SET(fpga_query_qp_in, in, opcode, MLX5_CMD_OP_FPGA_QUERY_QP); + MLX5_SET(fpga_query_qp_in, in, fpga_qpn, fpga_qpn); + + ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); + if (ret) + return ret; + + memcpy(fpga_qpc, MLX5_ADDR_OF(fpga_query_qp_out, in, fpga_qpc), + MLX5_FLD_SZ_BYTES(fpga_query_qp_out, fpga_qpc)); + return ret; +} + +int mlx5_fpga_destroy_qp(struct mlx5_core_dev *dev, u32 fpga_qpn) +{ + u32 in[MLX5_ST_SZ_DW(fpga_destroy_qp_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(fpga_destroy_qp_out)]; + + MLX5_SET(fpga_destroy_qp_in, in, opcode, MLX5_CMD_OP_FPGA_DESTROY_QP); + MLX5_SET(fpga_destroy_qp_in, in, fpga_qpn, fpga_qpn); + + return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + +int mlx5_fpga_query_qp_counters(struct mlx5_core_dev *dev, u32 fpga_qpn, + bool clear, struct mlx5_fpga_qp_counters *data) +{ + u32 in[MLX5_ST_SZ_DW(fpga_query_qp_counters_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(fpga_query_qp_counters_out)]; + int ret; + + MLX5_SET(fpga_query_qp_counters_in, in, opcode, + MLX5_CMD_OP_FPGA_QUERY_QP_COUNTERS); + MLX5_SET(fpga_query_qp_counters_in, in, clear, clear); + MLX5_SET(fpga_query_qp_counters_in, in, fpga_qpn, fpga_qpn); + + ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); + if (ret) + return ret; + + data->rx_ack_packets = MLX5_GET64(fpga_query_qp_counters_out, out, + rx_ack_packets); + data->rx_send_packets = MLX5_GET64(fpga_query_qp_counters_out, out, + rx_send_packets); + data->tx_ack_packets = MLX5_GET64(fpga_query_qp_counters_out, out, + tx_ack_packets); + data->tx_send_packets = MLX5_GET64(fpga_query_qp_counters_out, out, + tx_send_packets); + data->rx_total_drop = MLX5_GET64(fpga_query_qp_counters_out, out, + rx_total_drop); + + return ret; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h index a74396a61bc3..b851580d846f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h @@ -53,7 +53,28 @@ struct mlx5_fpga_query { enum mlx5_fpga_status status; }; +enum mlx5_fpga_qpc_field_select { + MLX5_FPGA_QPC_STATE = BIT(0), +}; + +struct mlx5_fpga_qp_counters { + u64 rx_ack_packets; + u64 rx_send_packets; + u64 tx_ack_packets; + u64 tx_send_packets; + u64 rx_total_drop; +}; + int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps); int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query); +int mlx5_fpga_create_qp(struct mlx5_core_dev *dev, void *fpga_qpc, + u32 *fpga_qpn); +int mlx5_fpga_modify_qp(struct mlx5_core_dev *dev, u32 fpga_qpn, + enum mlx5_fpga_qpc_field_select fields, void *fpga_qpc); +int mlx5_fpga_query_qp(struct mlx5_core_dev *dev, u32 fpga_qpn, void *fpga_qpc); +int mlx5_fpga_query_qp_counters(struct mlx5_core_dev *dev, u32 fpga_qpn, + bool clear, struct mlx5_fpga_qp_counters *data); +int mlx5_fpga_destroy_qp(struct mlx5_core_dev *dev, u32 fpga_qpn); + #endif /* __MLX5_FPGA_H__ */ -- cgit v1.2.3 From 537a50574175a2b68b0612ffb48cb044a394c7b4 Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Mon, 27 Mar 2017 14:48:38 +0300 Subject: net/mlx5: FPGA, Add high-speed connection routines An FPGA high-speed connection has two endpoints, an FPGA QP and a ConnectX QP. Add library routines to create and connect the endpoints of an FPGA high-speed connection. These routines allow creating and interacting with both types of connections: Shell and Sandbox Unit (SBU). Shell connection provides an interface to the FPGA's address space, which includes the configuration space and the DDR. Use of the shell connection will be introduced in a later patchset. SBU connection provides a command and/or data interface to the application-specific logic within the FPGA. Use of the SBU connection will be introduced in a later patch in this patchset. Some struct definitions are added to a new header file sdk.h, which will be extended in later patches in the patchset. This header file will contain the in-kernel FPGA client driver API. Signed-off-by: Ilan Tayari Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 +- .../net/ethernet/mellanox/mlx5/core/fpga/conn.c | 1042 ++++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/fpga/conn.h | 96 ++ .../net/ethernet/mellanox/mlx5/core/fpga/core.c | 12 + .../net/ethernet/mellanox/mlx5/core/fpga/core.h | 7 + drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h | 106 ++ 6 files changed, 1264 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.h create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 738867bab21f..5221b1235c47 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -6,7 +6,7 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ fs_counters.o rl.o lag.o dev.o lib/gid.o -mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o +mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c new file mode 100644 index 000000000000..c4392f741c5f --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c @@ -0,0 +1,1042 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include + +#include "mlx5_core.h" +#include "lib/mlx5.h" +#include "fpga/conn.h" + +#define MLX5_FPGA_PKEY 0xFFFF +#define MLX5_FPGA_PKEY_INDEX 0 /* RoCE PKEY 0xFFFF is always at index 0 */ +#define MLX5_FPGA_RECV_SIZE 2048 +#define MLX5_FPGA_PORT_NUM 1 +#define MLX5_FPGA_CQ_BUDGET 64 + +static int mlx5_fpga_conn_map_buf(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_dma_buf *buf) +{ + struct device *dma_device; + int err = 0; + + if (unlikely(!buf->sg[0].data)) + goto out; + + dma_device = &conn->fdev->mdev->pdev->dev; + buf->sg[0].dma_addr = dma_map_single(dma_device, buf->sg[0].data, + buf->sg[0].size, buf->dma_dir); + err = dma_mapping_error(dma_device, buf->sg[0].dma_addr); + if (unlikely(err)) { + mlx5_fpga_warn(conn->fdev, "DMA error on sg 0: %d\n", err); + err = -ENOMEM; + goto out; + } + + if (!buf->sg[1].data) + goto out; + + buf->sg[1].dma_addr = dma_map_single(dma_device, buf->sg[1].data, + buf->sg[1].size, buf->dma_dir); + err = dma_mapping_error(dma_device, buf->sg[1].dma_addr); + if (unlikely(err)) { + mlx5_fpga_warn(conn->fdev, "DMA error on sg 1: %d\n", err); + dma_unmap_single(dma_device, buf->sg[0].dma_addr, + buf->sg[0].size, buf->dma_dir); + err = -ENOMEM; + } + +out: + return err; +} + +static void mlx5_fpga_conn_unmap_buf(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_dma_buf *buf) +{ + struct device *dma_device; + + dma_device = &conn->fdev->mdev->pdev->dev; + if (buf->sg[1].data) + dma_unmap_single(dma_device, buf->sg[1].dma_addr, + buf->sg[1].size, buf->dma_dir); + + if (likely(buf->sg[0].data)) + dma_unmap_single(dma_device, buf->sg[0].dma_addr, + buf->sg[0].size, buf->dma_dir); +} + +static int mlx5_fpga_conn_post_recv(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_dma_buf *buf) +{ + struct mlx5_wqe_data_seg *data; + unsigned int ix; + int err = 0; + + err = mlx5_fpga_conn_map_buf(conn, buf); + if (unlikely(err)) + goto out; + + if (unlikely(conn->qp.rq.pc - conn->qp.rq.cc >= conn->qp.rq.size)) { + mlx5_fpga_conn_unmap_buf(conn, buf); + return -EBUSY; + } + + ix = conn->qp.rq.pc & (conn->qp.rq.size - 1); + data = mlx5_wq_cyc_get_wqe(&conn->qp.wq.rq, ix); + data->byte_count = cpu_to_be32(buf->sg[0].size); + data->lkey = cpu_to_be32(conn->fdev->conn_res.mkey.key); + data->addr = cpu_to_be64(buf->sg[0].dma_addr); + + conn->qp.rq.pc++; + conn->qp.rq.bufs[ix] = buf; + + /* Make sure that descriptors are written before doorbell record. */ + dma_wmb(); + *conn->qp.wq.rq.db = cpu_to_be32(conn->qp.rq.pc & 0xffff); +out: + return err; +} + +static void mlx5_fpga_conn_notify_hw(struct mlx5_fpga_conn *conn, void *wqe) +{ + /* ensure wqe is visible to device before updating doorbell record */ + dma_wmb(); + *conn->qp.wq.sq.db = cpu_to_be32(conn->qp.sq.pc); + /* Make sure that doorbell record is visible before ringing */ + wmb(); + mlx5_write64(wqe, conn->fdev->conn_res.uar->map + MLX5_BF_OFFSET, NULL); +} + +static void mlx5_fpga_conn_post_send(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_dma_buf *buf) +{ + struct mlx5_wqe_ctrl_seg *ctrl; + struct mlx5_wqe_data_seg *data; + unsigned int ix, sgi; + int size = 1; + + ix = conn->qp.sq.pc & (conn->qp.sq.size - 1); + + ctrl = mlx5_wq_cyc_get_wqe(&conn->qp.wq.sq, ix); + data = (void *)(ctrl + 1); + + for (sgi = 0; sgi < ARRAY_SIZE(buf->sg); sgi++) { + if (!buf->sg[sgi].data) + break; + data->byte_count = cpu_to_be32(buf->sg[sgi].size); + data->lkey = cpu_to_be32(conn->fdev->conn_res.mkey.key); + data->addr = cpu_to_be64(buf->sg[sgi].dma_addr); + data++; + size++; + } + + ctrl->imm = 0; + ctrl->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE; + ctrl->opmod_idx_opcode = cpu_to_be32(((conn->qp.sq.pc & 0xffff) << 8) | + MLX5_OPCODE_SEND); + ctrl->qpn_ds = cpu_to_be32(size | (conn->qp.mqp.qpn << 8)); + + conn->qp.sq.pc++; + conn->qp.sq.bufs[ix] = buf; + mlx5_fpga_conn_notify_hw(conn, ctrl); +} + +int mlx5_fpga_conn_send(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_dma_buf *buf) +{ + unsigned long flags; + int err; + + if (!conn->qp.active) + return -ENOTCONN; + + err = mlx5_fpga_conn_map_buf(conn, buf); + if (err) + return err; + + spin_lock_irqsave(&conn->qp.sq.lock, flags); + + if (conn->qp.sq.pc - conn->qp.sq.cc >= conn->qp.sq.size) { + list_add_tail(&buf->list, &conn->qp.sq.backlog); + goto out_unlock; + } + + mlx5_fpga_conn_post_send(conn, buf); + +out_unlock: + spin_unlock_irqrestore(&conn->qp.sq.lock, flags); + return err; +} + +static int mlx5_fpga_conn_post_recv_buf(struct mlx5_fpga_conn *conn) +{ + struct mlx5_fpga_dma_buf *buf; + int err; + + buf = kzalloc(sizeof(*buf) + MLX5_FPGA_RECV_SIZE, 0); + if (!buf) + return -ENOMEM; + + buf->sg[0].data = (void *)(buf + 1); + buf->sg[0].size = MLX5_FPGA_RECV_SIZE; + buf->dma_dir = DMA_FROM_DEVICE; + + err = mlx5_fpga_conn_post_recv(conn, buf); + if (err) + kfree(buf); + + return err; +} + +static int mlx5_fpga_conn_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, + struct mlx5_core_mkey *mkey) +{ + int inlen = MLX5_ST_SZ_BYTES(create_mkey_in); + void *mkc; + u32 *in; + int err; + + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry); + MLX5_SET(mkc, mkc, access_mode, MLX5_MKC_ACCESS_MODE_PA); + MLX5_SET(mkc, mkc, lw, 1); + MLX5_SET(mkc, mkc, lr, 1); + + MLX5_SET(mkc, mkc, pd, pdn); + MLX5_SET(mkc, mkc, length64, 1); + MLX5_SET(mkc, mkc, qpn, 0xffffff); + + err = mlx5_core_create_mkey(mdev, mkey, in, inlen); + + kvfree(in); + return err; +} + +static void mlx5_fpga_conn_rq_cqe(struct mlx5_fpga_conn *conn, + struct mlx5_cqe64 *cqe, u8 status) +{ + struct mlx5_fpga_dma_buf *buf; + int ix, err; + + ix = be16_to_cpu(cqe->wqe_counter) & (conn->qp.rq.size - 1); + buf = conn->qp.rq.bufs[ix]; + conn->qp.rq.bufs[ix] = NULL; + if (!status) + buf->sg[0].size = be32_to_cpu(cqe->byte_cnt); + conn->qp.rq.cc++; + + if (unlikely(status && (status != MLX5_CQE_SYNDROME_WR_FLUSH_ERR))) + mlx5_fpga_warn(conn->fdev, "RQ buf %p on FPGA QP %u completion status %d\n", + buf, conn->fpga_qpn, status); + else + mlx5_fpga_dbg(conn->fdev, "RQ buf %p on FPGA QP %u completion status %d\n", + buf, conn->fpga_qpn, status); + + mlx5_fpga_conn_unmap_buf(conn, buf); + + if (unlikely(status || !conn->qp.active)) { + conn->qp.active = false; + kfree(buf); + return; + } + + mlx5_fpga_dbg(conn->fdev, "Message with %u bytes received successfully\n", + buf->sg[0].size); + conn->recv_cb(conn->cb_arg, buf); + + buf->sg[0].size = MLX5_FPGA_RECV_SIZE; + err = mlx5_fpga_conn_post_recv(conn, buf); + if (unlikely(err)) { + mlx5_fpga_warn(conn->fdev, + "Failed to re-post recv buf: %d\n", err); + kfree(buf); + } +} + +static void mlx5_fpga_conn_sq_cqe(struct mlx5_fpga_conn *conn, + struct mlx5_cqe64 *cqe, u8 status) +{ + struct mlx5_fpga_dma_buf *buf, *nextbuf; + unsigned long flags; + int ix; + + spin_lock_irqsave(&conn->qp.sq.lock, flags); + + ix = be16_to_cpu(cqe->wqe_counter) & (conn->qp.sq.size - 1); + buf = conn->qp.sq.bufs[ix]; + conn->qp.sq.bufs[ix] = NULL; + conn->qp.sq.cc++; + + /* Handle backlog still under the spinlock to ensure message post order */ + if (unlikely(!list_empty(&conn->qp.sq.backlog))) { + if (likely(conn->qp.active)) { + nextbuf = list_first_entry(&conn->qp.sq.backlog, + struct mlx5_fpga_dma_buf, list); + list_del(&nextbuf->list); + mlx5_fpga_conn_post_send(conn, nextbuf); + } + } + + spin_unlock_irqrestore(&conn->qp.sq.lock, flags); + + if (unlikely(status && (status != MLX5_CQE_SYNDROME_WR_FLUSH_ERR))) + mlx5_fpga_warn(conn->fdev, "SQ buf %p on FPGA QP %u completion status %d\n", + buf, conn->fpga_qpn, status); + else + mlx5_fpga_dbg(conn->fdev, "SQ buf %p on FPGA QP %u completion status %d\n", + buf, conn->fpga_qpn, status); + + mlx5_fpga_conn_unmap_buf(conn, buf); + + if (likely(buf->complete)) + buf->complete(conn, conn->fdev, buf, status); + + if (unlikely(status)) + conn->qp.active = false; +} + +static void mlx5_fpga_conn_handle_cqe(struct mlx5_fpga_conn *conn, + struct mlx5_cqe64 *cqe) +{ + u8 opcode, status = 0; + + opcode = cqe->op_own >> 4; + + switch (opcode) { + case MLX5_CQE_REQ_ERR: + status = ((struct mlx5_err_cqe *)cqe)->syndrome; + /* Fall through */ + case MLX5_CQE_REQ: + mlx5_fpga_conn_sq_cqe(conn, cqe, status); + break; + + case MLX5_CQE_RESP_ERR: + status = ((struct mlx5_err_cqe *)cqe)->syndrome; + /* Fall through */ + case MLX5_CQE_RESP_SEND: + mlx5_fpga_conn_rq_cqe(conn, cqe, status); + break; + default: + mlx5_fpga_warn(conn->fdev, "Unexpected cqe opcode %u\n", + opcode); + } +} + +static void mlx5_fpga_conn_arm_cq(struct mlx5_fpga_conn *conn) +{ + mlx5_cq_arm(&conn->cq.mcq, MLX5_CQ_DB_REQ_NOT, + conn->fdev->conn_res.uar->map, conn->cq.wq.cc); +} + +static void mlx5_fpga_conn_cq_event(struct mlx5_core_cq *mcq, + enum mlx5_event event) +{ + struct mlx5_fpga_conn *conn; + + conn = container_of(mcq, struct mlx5_fpga_conn, cq.mcq); + mlx5_fpga_warn(conn->fdev, "CQ event %u on CQ #%u\n", event, mcq->cqn); +} + +static void mlx5_fpga_conn_event(struct mlx5_core_qp *mqp, int event) +{ + struct mlx5_fpga_conn *conn; + + conn = container_of(mqp, struct mlx5_fpga_conn, qp.mqp); + mlx5_fpga_warn(conn->fdev, "QP event %u on QP #%u\n", event, mqp->qpn); +} + +static inline void mlx5_fpga_conn_cqes(struct mlx5_fpga_conn *conn, + unsigned int budget) +{ + struct mlx5_cqe64 *cqe; + + while (budget) { + cqe = mlx5_cqwq_get_cqe(&conn->cq.wq); + if (!cqe) + break; + + budget--; + mlx5_cqwq_pop(&conn->cq.wq); + mlx5_fpga_conn_handle_cqe(conn, cqe); + mlx5_cqwq_update_db_record(&conn->cq.wq); + } + if (!budget) { + tasklet_schedule(&conn->cq.tasklet); + return; + } + + mlx5_fpga_dbg(conn->fdev, "Re-arming CQ with cc# %u\n", conn->cq.wq.cc); + /* ensure cq space is freed before enabling more cqes */ + wmb(); + mlx5_fpga_conn_arm_cq(conn); +} + +static void mlx5_fpga_conn_cq_tasklet(unsigned long data) +{ + struct mlx5_fpga_conn *conn = (void *)data; + + if (unlikely(!conn->qp.active)) + return; + mlx5_fpga_conn_cqes(conn, MLX5_FPGA_CQ_BUDGET); +} + +static void mlx5_fpga_conn_cq_complete(struct mlx5_core_cq *mcq) +{ + struct mlx5_fpga_conn *conn; + + conn = container_of(mcq, struct mlx5_fpga_conn, cq.mcq); + if (unlikely(!conn->qp.active)) + return; + mlx5_fpga_conn_cqes(conn, MLX5_FPGA_CQ_BUDGET); +} + +static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size) +{ + struct mlx5_fpga_device *fdev = conn->fdev; + struct mlx5_core_dev *mdev = fdev->mdev; + u32 temp_cqc[MLX5_ST_SZ_DW(cqc)] = {0}; + struct mlx5_wq_param wqp; + struct mlx5_cqe64 *cqe; + int inlen, err, eqn; + unsigned int irqn; + void *cqc, *in; + __be64 *pas; + u32 i; + + cq_size = roundup_pow_of_two(cq_size); + MLX5_SET(cqc, temp_cqc, log_cq_size, ilog2(cq_size)); + + wqp.buf_numa_node = mdev->priv.numa_node; + wqp.db_numa_node = mdev->priv.numa_node; + + err = mlx5_cqwq_create(mdev, &wqp, temp_cqc, &conn->cq.wq, + &conn->cq.wq_ctrl); + if (err) + return err; + + for (i = 0; i < mlx5_cqwq_get_size(&conn->cq.wq); i++) { + cqe = mlx5_cqwq_get_wqe(&conn->cq.wq, i); + cqe->op_own = MLX5_CQE_INVALID << 4 | MLX5_CQE_OWNER_MASK; + } + + inlen = MLX5_ST_SZ_BYTES(create_cq_in) + + sizeof(u64) * conn->cq.wq_ctrl.frag_buf.npages; + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) { + err = -ENOMEM; + goto err_cqwq; + } + + err = mlx5_vector2eqn(mdev, smp_processor_id(), &eqn, &irqn); + if (err) + goto err_cqwq; + + cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); + MLX5_SET(cqc, cqc, log_cq_size, ilog2(cq_size)); + MLX5_SET(cqc, cqc, c_eqn, eqn); + MLX5_SET(cqc, cqc, uar_page, fdev->conn_res.uar->index); + MLX5_SET(cqc, cqc, log_page_size, conn->cq.wq_ctrl.frag_buf.page_shift - + MLX5_ADAPTER_PAGE_SHIFT); + MLX5_SET64(cqc, cqc, dbr_addr, conn->cq.wq_ctrl.db.dma); + + pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas); + mlx5_fill_page_frag_array(&conn->cq.wq_ctrl.frag_buf, pas); + + err = mlx5_core_create_cq(mdev, &conn->cq.mcq, in, inlen); + kvfree(in); + + if (err) + goto err_cqwq; + + conn->cq.mcq.cqe_sz = 64; + conn->cq.mcq.set_ci_db = conn->cq.wq_ctrl.db.db; + conn->cq.mcq.arm_db = conn->cq.wq_ctrl.db.db + 1; + *conn->cq.mcq.set_ci_db = 0; + *conn->cq.mcq.arm_db = 0; + conn->cq.mcq.vector = 0; + conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete; + conn->cq.mcq.event = mlx5_fpga_conn_cq_event; + conn->cq.mcq.irqn = irqn; + conn->cq.mcq.uar = fdev->conn_res.uar; + tasklet_init(&conn->cq.tasklet, mlx5_fpga_conn_cq_tasklet, + (unsigned long)conn); + + mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn); + + goto out; + +err_cqwq: + mlx5_cqwq_destroy(&conn->cq.wq_ctrl); +out: + return err; +} + +static void mlx5_fpga_conn_destroy_cq(struct mlx5_fpga_conn *conn) +{ + tasklet_disable(&conn->cq.tasklet); + tasklet_kill(&conn->cq.tasklet); + mlx5_core_destroy_cq(conn->fdev->mdev, &conn->cq.mcq); + mlx5_cqwq_destroy(&conn->cq.wq_ctrl); +} + +static int mlx5_fpga_conn_create_wq(struct mlx5_fpga_conn *conn, void *qpc) +{ + struct mlx5_fpga_device *fdev = conn->fdev; + struct mlx5_core_dev *mdev = fdev->mdev; + struct mlx5_wq_param wqp; + + wqp.buf_numa_node = mdev->priv.numa_node; + wqp.db_numa_node = mdev->priv.numa_node; + + return mlx5_wq_qp_create(mdev, &wqp, qpc, &conn->qp.wq, + &conn->qp.wq_ctrl); +} + +static int mlx5_fpga_conn_create_qp(struct mlx5_fpga_conn *conn, + unsigned int tx_size, unsigned int rx_size) +{ + struct mlx5_fpga_device *fdev = conn->fdev; + struct mlx5_core_dev *mdev = fdev->mdev; + u32 temp_qpc[MLX5_ST_SZ_DW(qpc)] = {0}; + void *in = NULL, *qpc; + int err, inlen; + + conn->qp.rq.pc = 0; + conn->qp.rq.cc = 0; + conn->qp.rq.size = roundup_pow_of_two(rx_size); + conn->qp.sq.pc = 0; + conn->qp.sq.cc = 0; + conn->qp.sq.size = roundup_pow_of_two(tx_size); + + MLX5_SET(qpc, temp_qpc, log_rq_stride, ilog2(MLX5_SEND_WQE_DS) - 4); + MLX5_SET(qpc, temp_qpc, log_rq_size, ilog2(conn->qp.rq.size)); + MLX5_SET(qpc, temp_qpc, log_sq_size, ilog2(conn->qp.sq.size)); + err = mlx5_fpga_conn_create_wq(conn, temp_qpc); + if (err) + goto out; + + conn->qp.rq.bufs = kvzalloc(sizeof(conn->qp.rq.bufs[0]) * + conn->qp.rq.size, GFP_KERNEL); + if (!conn->qp.rq.bufs) { + err = -ENOMEM; + goto err_wq; + } + + conn->qp.sq.bufs = kvzalloc(sizeof(conn->qp.sq.bufs[0]) * + conn->qp.sq.size, GFP_KERNEL); + if (!conn->qp.sq.bufs) { + err = -ENOMEM; + goto err_rq_bufs; + } + + inlen = MLX5_ST_SZ_BYTES(create_qp_in) + + MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * + conn->qp.wq_ctrl.buf.npages; + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) { + err = -ENOMEM; + goto err_sq_bufs; + } + + qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); + MLX5_SET(qpc, qpc, uar_page, fdev->conn_res.uar->index); + MLX5_SET(qpc, qpc, log_page_size, + conn->qp.wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); + MLX5_SET(qpc, qpc, fre, 1); + MLX5_SET(qpc, qpc, rlky, 1); + MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); + MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); + MLX5_SET(qpc, qpc, pd, fdev->conn_res.pdn); + MLX5_SET(qpc, qpc, log_rq_stride, ilog2(MLX5_SEND_WQE_DS) - 4); + MLX5_SET(qpc, qpc, log_rq_size, ilog2(conn->qp.rq.size)); + MLX5_SET(qpc, qpc, rq_type, MLX5_NON_ZERO_RQ); + MLX5_SET(qpc, qpc, log_sq_size, ilog2(conn->qp.sq.size)); + MLX5_SET(qpc, qpc, cqn_snd, conn->cq.mcq.cqn); + MLX5_SET(qpc, qpc, cqn_rcv, conn->cq.mcq.cqn); + MLX5_SET64(qpc, qpc, dbr_addr, conn->qp.wq_ctrl.db.dma); + if (MLX5_CAP_GEN(mdev, cqe_version) == 1) + MLX5_SET(qpc, qpc, user_index, 0xFFFFFF); + + mlx5_fill_page_array(&conn->qp.wq_ctrl.buf, + (__be64 *)MLX5_ADDR_OF(create_qp_in, in, pas)); + + err = mlx5_core_create_qp(mdev, &conn->qp.mqp, in, inlen); + if (err) + goto err_sq_bufs; + + conn->qp.mqp.event = mlx5_fpga_conn_event; + mlx5_fpga_dbg(fdev, "Created QP #0x%x\n", conn->qp.mqp.qpn); + + goto out; + +err_sq_bufs: + kvfree(conn->qp.sq.bufs); +err_rq_bufs: + kvfree(conn->qp.rq.bufs); +err_wq: + mlx5_wq_destroy(&conn->qp.wq_ctrl); +out: + kvfree(in); + return err; +} + +static void mlx5_fpga_conn_free_recv_bufs(struct mlx5_fpga_conn *conn) +{ + int ix; + + for (ix = 0; ix < conn->qp.rq.size; ix++) { + if (!conn->qp.rq.bufs[ix]) + continue; + mlx5_fpga_conn_unmap_buf(conn, conn->qp.rq.bufs[ix]); + kfree(conn->qp.rq.bufs[ix]); + conn->qp.rq.bufs[ix] = NULL; + } +} + +static void mlx5_fpga_conn_flush_send_bufs(struct mlx5_fpga_conn *conn) +{ + struct mlx5_fpga_dma_buf *buf, *temp; + int ix; + + for (ix = 0; ix < conn->qp.sq.size; ix++) { + buf = conn->qp.sq.bufs[ix]; + if (!buf) + continue; + conn->qp.sq.bufs[ix] = NULL; + mlx5_fpga_conn_unmap_buf(conn, buf); + if (!buf->complete) + continue; + buf->complete(conn, conn->fdev, buf, MLX5_CQE_SYNDROME_WR_FLUSH_ERR); + } + list_for_each_entry_safe(buf, temp, &conn->qp.sq.backlog, list) { + mlx5_fpga_conn_unmap_buf(conn, buf); + if (!buf->complete) + continue; + buf->complete(conn, conn->fdev, buf, MLX5_CQE_SYNDROME_WR_FLUSH_ERR); + } +} + +static void mlx5_fpga_conn_destroy_qp(struct mlx5_fpga_conn *conn) +{ + mlx5_core_destroy_qp(conn->fdev->mdev, &conn->qp.mqp); + mlx5_fpga_conn_free_recv_bufs(conn); + mlx5_fpga_conn_flush_send_bufs(conn); + kvfree(conn->qp.sq.bufs); + kvfree(conn->qp.rq.bufs); + mlx5_wq_destroy(&conn->qp.wq_ctrl); +} + +static inline int mlx5_fpga_conn_reset_qp(struct mlx5_fpga_conn *conn) +{ + struct mlx5_core_dev *mdev = conn->fdev->mdev; + + mlx5_fpga_dbg(conn->fdev, "Modifying QP %u to RST\n", conn->qp.mqp.qpn); + + return mlx5_core_qp_modify(mdev, MLX5_CMD_OP_2RST_QP, 0, NULL, + &conn->qp.mqp); +} + +static inline int mlx5_fpga_conn_init_qp(struct mlx5_fpga_conn *conn) +{ + struct mlx5_fpga_device *fdev = conn->fdev; + struct mlx5_core_dev *mdev = fdev->mdev; + u32 *qpc = NULL; + int err; + + mlx5_fpga_dbg(conn->fdev, "Modifying QP %u to INIT\n", conn->qp.mqp.qpn); + + qpc = kzalloc(MLX5_ST_SZ_BYTES(qpc), GFP_KERNEL); + if (!qpc) { + err = -ENOMEM; + goto out; + } + + MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); + MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); + MLX5_SET(qpc, qpc, primary_address_path.pkey_index, MLX5_FPGA_PKEY_INDEX); + MLX5_SET(qpc, qpc, primary_address_path.port, MLX5_FPGA_PORT_NUM); + MLX5_SET(qpc, qpc, pd, conn->fdev->conn_res.pdn); + MLX5_SET(qpc, qpc, cqn_snd, conn->cq.mcq.cqn); + MLX5_SET(qpc, qpc, cqn_rcv, conn->cq.mcq.cqn); + MLX5_SET64(qpc, qpc, dbr_addr, conn->qp.wq_ctrl.db.dma); + + err = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_RST2INIT_QP, 0, qpc, + &conn->qp.mqp); + if (err) { + mlx5_fpga_warn(fdev, "qp_modify RST2INIT failed: %d\n", err); + goto out; + } + +out: + kfree(qpc); + return err; +} + +static inline int mlx5_fpga_conn_rtr_qp(struct mlx5_fpga_conn *conn) +{ + struct mlx5_fpga_device *fdev = conn->fdev; + struct mlx5_core_dev *mdev = fdev->mdev; + u32 *qpc = NULL; + int err; + + mlx5_fpga_dbg(conn->fdev, "QP RTR\n"); + + qpc = kzalloc(MLX5_ST_SZ_BYTES(qpc), GFP_KERNEL); + if (!qpc) { + err = -ENOMEM; + goto out; + } + + MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_1K_BYTES); + MLX5_SET(qpc, qpc, log_msg_max, (u8)MLX5_CAP_GEN(mdev, log_max_msg)); + MLX5_SET(qpc, qpc, remote_qpn, conn->fpga_qpn); + MLX5_SET(qpc, qpc, next_rcv_psn, + MLX5_GET(fpga_qpc, conn->fpga_qpc, next_send_psn)); + MLX5_SET(qpc, qpc, primary_address_path.pkey_index, MLX5_FPGA_PKEY_INDEX); + MLX5_SET(qpc, qpc, primary_address_path.port, MLX5_FPGA_PORT_NUM); + ether_addr_copy(MLX5_ADDR_OF(qpc, qpc, primary_address_path.rmac_47_32), + MLX5_ADDR_OF(fpga_qpc, conn->fpga_qpc, fpga_mac_47_32)); + MLX5_SET(qpc, qpc, primary_address_path.udp_sport, + MLX5_CAP_ROCE(mdev, r_roce_min_src_udp_port)); + MLX5_SET(qpc, qpc, primary_address_path.src_addr_index, + conn->qp.sgid_index); + MLX5_SET(qpc, qpc, primary_address_path.hop_limit, 0); + memcpy(MLX5_ADDR_OF(qpc, qpc, primary_address_path.rgid_rip), + MLX5_ADDR_OF(fpga_qpc, conn->fpga_qpc, fpga_ip), + MLX5_FLD_SZ_BYTES(qpc, primary_address_path.rgid_rip)); + + err = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_INIT2RTR_QP, 0, qpc, + &conn->qp.mqp); + if (err) { + mlx5_fpga_warn(fdev, "qp_modify RST2INIT failed: %d\n", err); + goto out; + } + +out: + kfree(qpc); + return err; +} + +static inline int mlx5_fpga_conn_rts_qp(struct mlx5_fpga_conn *conn) +{ + struct mlx5_fpga_device *fdev = conn->fdev; + struct mlx5_core_dev *mdev = fdev->mdev; + u32 *qpc = NULL; + u32 opt_mask; + int err; + + mlx5_fpga_dbg(conn->fdev, "QP RTS\n"); + + qpc = kzalloc(MLX5_ST_SZ_BYTES(qpc), GFP_KERNEL); + if (!qpc) { + err = -ENOMEM; + goto out; + } + + MLX5_SET(qpc, qpc, log_ack_req_freq, 8); + MLX5_SET(qpc, qpc, min_rnr_nak, 0x12); + MLX5_SET(qpc, qpc, primary_address_path.ack_timeout, 0x12); /* ~1.07s */ + MLX5_SET(qpc, qpc, next_send_psn, + MLX5_GET(fpga_qpc, conn->fpga_qpc, next_rcv_psn)); + MLX5_SET(qpc, qpc, retry_count, 7); + MLX5_SET(qpc, qpc, rnr_retry, 7); /* Infinite retry if RNR NACK */ + + opt_mask = MLX5_QP_OPTPAR_RNR_TIMEOUT; + err = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_RTR2RTS_QP, opt_mask, qpc, + &conn->qp.mqp); + if (err) { + mlx5_fpga_warn(fdev, "qp_modify RST2INIT failed: %d\n", err); + goto out; + } + +out: + kfree(qpc); + return err; +} + +static int mlx5_fpga_conn_connect(struct mlx5_fpga_conn *conn) +{ + struct mlx5_fpga_device *fdev = conn->fdev; + int err; + + MLX5_SET(fpga_qpc, conn->fpga_qpc, state, MLX5_FPGA_QPC_STATE_ACTIVE); + err = mlx5_fpga_modify_qp(conn->fdev->mdev, conn->fpga_qpn, + MLX5_FPGA_QPC_STATE, &conn->fpga_qpc); + if (err) { + mlx5_fpga_err(fdev, "Failed to activate FPGA RC QP: %d\n", err); + goto out; + } + + err = mlx5_fpga_conn_reset_qp(conn); + if (err) { + mlx5_fpga_err(fdev, "Failed to change QP state to reset\n"); + goto err_fpga_qp; + } + + err = mlx5_fpga_conn_init_qp(conn); + if (err) { + mlx5_fpga_err(fdev, "Failed to modify QP from RESET to INIT\n"); + goto err_fpga_qp; + } + conn->qp.active = true; + + while (!mlx5_fpga_conn_post_recv_buf(conn)) + ; + + err = mlx5_fpga_conn_rtr_qp(conn); + if (err) { + mlx5_fpga_err(fdev, "Failed to change QP state from INIT to RTR\n"); + goto err_recv_bufs; + } + + err = mlx5_fpga_conn_rts_qp(conn); + if (err) { + mlx5_fpga_err(fdev, "Failed to change QP state from RTR to RTS\n"); + goto err_recv_bufs; + } + goto out; + +err_recv_bufs: + mlx5_fpga_conn_free_recv_bufs(conn); +err_fpga_qp: + MLX5_SET(fpga_qpc, conn->fpga_qpc, state, MLX5_FPGA_QPC_STATE_INIT); + if (mlx5_fpga_modify_qp(conn->fdev->mdev, conn->fpga_qpn, + MLX5_FPGA_QPC_STATE, &conn->fpga_qpc)) + mlx5_fpga_err(fdev, "Failed to revert FPGA QP to INIT\n"); +out: + return err; +} + +struct mlx5_fpga_conn *mlx5_fpga_conn_create(struct mlx5_fpga_device *fdev, + struct mlx5_fpga_conn_attr *attr, + enum mlx5_ifc_fpga_qp_type qp_type) +{ + struct mlx5_fpga_conn *ret, *conn; + u8 *remote_mac, *remote_ip; + int err; + + if (!attr->recv_cb) + return ERR_PTR(-EINVAL); + + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + return ERR_PTR(-ENOMEM); + + conn->fdev = fdev; + INIT_LIST_HEAD(&conn->qp.sq.backlog); + + spin_lock_init(&conn->qp.sq.lock); + + conn->recv_cb = attr->recv_cb; + conn->cb_arg = attr->cb_arg; + + remote_mac = MLX5_ADDR_OF(fpga_qpc, conn->fpga_qpc, remote_mac_47_32); + err = mlx5_query_nic_vport_mac_address(fdev->mdev, 0, remote_mac); + if (err) { + mlx5_fpga_err(fdev, "Failed to query local MAC: %d\n", err); + ret = ERR_PTR(err); + goto err; + } + + /* Build Modified EUI-64 IPv6 address from the MAC address */ + remote_ip = MLX5_ADDR_OF(fpga_qpc, conn->fpga_qpc, remote_ip); + remote_ip[0] = 0xfe; + remote_ip[1] = 0x80; + addrconf_addr_eui48(&remote_ip[8], remote_mac); + + err = mlx5_core_reserved_gid_alloc(fdev->mdev, &conn->qp.sgid_index); + if (err) { + mlx5_fpga_err(fdev, "Failed to allocate SGID: %d\n", err); + ret = ERR_PTR(err); + goto err; + } + + err = mlx5_core_roce_gid_set(fdev->mdev, conn->qp.sgid_index, + MLX5_ROCE_VERSION_2, + MLX5_ROCE_L3_TYPE_IPV6, + remote_ip, remote_mac, true, 0); + if (err) { + mlx5_fpga_err(fdev, "Failed to set SGID: %d\n", err); + ret = ERR_PTR(err); + goto err_rsvd_gid; + } + mlx5_fpga_dbg(fdev, "Reserved SGID index %u\n", conn->qp.sgid_index); + + /* Allow for one cqe per rx/tx wqe, plus one cqe for the next wqe, + * created during processing of the cqe + */ + err = mlx5_fpga_conn_create_cq(conn, + (attr->tx_size + attr->rx_size) * 2); + if (err) { + mlx5_fpga_err(fdev, "Failed to create CQ: %d\n", err); + ret = ERR_PTR(err); + goto err_gid; + } + + mlx5_fpga_conn_arm_cq(conn); + + err = mlx5_fpga_conn_create_qp(conn, attr->tx_size, attr->rx_size); + if (err) { + mlx5_fpga_err(fdev, "Failed to create QP: %d\n", err); + ret = ERR_PTR(err); + goto err_cq; + } + + MLX5_SET(fpga_qpc, conn->fpga_qpc, state, MLX5_FPGA_QPC_STATE_INIT); + MLX5_SET(fpga_qpc, conn->fpga_qpc, qp_type, qp_type); + MLX5_SET(fpga_qpc, conn->fpga_qpc, st, MLX5_FPGA_QPC_ST_RC); + MLX5_SET(fpga_qpc, conn->fpga_qpc, ether_type, ETH_P_8021Q); + MLX5_SET(fpga_qpc, conn->fpga_qpc, vid, 0); + MLX5_SET(fpga_qpc, conn->fpga_qpc, next_rcv_psn, 1); + MLX5_SET(fpga_qpc, conn->fpga_qpc, next_send_psn, 0); + MLX5_SET(fpga_qpc, conn->fpga_qpc, pkey, MLX5_FPGA_PKEY); + MLX5_SET(fpga_qpc, conn->fpga_qpc, remote_qpn, conn->qp.mqp.qpn); + MLX5_SET(fpga_qpc, conn->fpga_qpc, rnr_retry, 7); + MLX5_SET(fpga_qpc, conn->fpga_qpc, retry_count, 7); + + err = mlx5_fpga_create_qp(fdev->mdev, &conn->fpga_qpc, + &conn->fpga_qpn); + if (err) { + mlx5_fpga_err(fdev, "Failed to create FPGA RC QP: %d\n", err); + ret = ERR_PTR(err); + goto err_qp; + } + + err = mlx5_fpga_conn_connect(conn); + if (err) { + ret = ERR_PTR(err); + goto err_conn; + } + + mlx5_fpga_dbg(fdev, "FPGA QPN is %u\n", conn->fpga_qpn); + ret = conn; + goto out; + +err_conn: + mlx5_fpga_destroy_qp(conn->fdev->mdev, conn->fpga_qpn); +err_qp: + mlx5_fpga_conn_destroy_qp(conn); +err_cq: + mlx5_fpga_conn_destroy_cq(conn); +err_gid: + mlx5_core_roce_gid_set(fdev->mdev, conn->qp.sgid_index, 0, 0, NULL, + NULL, false, 0); +err_rsvd_gid: + mlx5_core_reserved_gid_free(fdev->mdev, conn->qp.sgid_index); +err: + kfree(conn); +out: + return ret; +} + +void mlx5_fpga_conn_destroy(struct mlx5_fpga_conn *conn) +{ + struct mlx5_fpga_device *fdev = conn->fdev; + struct mlx5_core_dev *mdev = fdev->mdev; + int err = 0; + + conn->qp.active = false; + tasklet_disable(&conn->cq.tasklet); + synchronize_irq(conn->cq.mcq.irqn); + + mlx5_fpga_destroy_qp(conn->fdev->mdev, conn->fpga_qpn); + err = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_2ERR_QP, 0, NULL, + &conn->qp.mqp); + if (err) + mlx5_fpga_warn(fdev, "qp_modify 2ERR failed: %d\n", err); + mlx5_fpga_conn_destroy_qp(conn); + mlx5_fpga_conn_destroy_cq(conn); + + mlx5_core_roce_gid_set(conn->fdev->mdev, conn->qp.sgid_index, 0, 0, + NULL, NULL, false, 0); + mlx5_core_reserved_gid_free(conn->fdev->mdev, conn->qp.sgid_index); + kfree(conn); +} + +int mlx5_fpga_conn_device_init(struct mlx5_fpga_device *fdev) +{ + int err; + + err = mlx5_nic_vport_enable_roce(fdev->mdev); + if (err) { + mlx5_fpga_err(fdev, "Failed to enable RoCE: %d\n", err); + goto out; + } + + fdev->conn_res.uar = mlx5_get_uars_page(fdev->mdev); + if (IS_ERR(fdev->conn_res.uar)) { + err = PTR_ERR(fdev->conn_res.uar); + mlx5_fpga_err(fdev, "get_uars_page failed, %d\n", err); + goto err_roce; + } + mlx5_fpga_dbg(fdev, "Allocated UAR index %u\n", + fdev->conn_res.uar->index); + + err = mlx5_core_alloc_pd(fdev->mdev, &fdev->conn_res.pdn); + if (err) { + mlx5_fpga_err(fdev, "alloc pd failed, %d\n", err); + goto err_uar; + } + mlx5_fpga_dbg(fdev, "Allocated PD %u\n", fdev->conn_res.pdn); + + err = mlx5_fpga_conn_create_mkey(fdev->mdev, fdev->conn_res.pdn, + &fdev->conn_res.mkey); + if (err) { + mlx5_fpga_err(fdev, "create mkey failed, %d\n", err); + goto err_dealloc_pd; + } + mlx5_fpga_dbg(fdev, "Created mkey 0x%x\n", fdev->conn_res.mkey.key); + + return 0; + +err_dealloc_pd: + mlx5_core_dealloc_pd(fdev->mdev, fdev->conn_res.pdn); +err_uar: + mlx5_put_uars_page(fdev->mdev, fdev->conn_res.uar); +err_roce: + mlx5_nic_vport_disable_roce(fdev->mdev); +out: + return err; +} + +void mlx5_fpga_conn_device_cleanup(struct mlx5_fpga_device *fdev) +{ + mlx5_core_destroy_mkey(fdev->mdev, &fdev->conn_res.mkey); + mlx5_core_dealloc_pd(fdev->mdev, fdev->conn_res.pdn); + mlx5_put_uars_page(fdev->mdev, fdev->conn_res.uar); + mlx5_nic_vport_disable_roce(fdev->mdev); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.h new file mode 100644 index 000000000000..44bd9eccc711 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef __MLX5_FPGA_CONN_H__ +#define __MLX5_FPGA_CONN_H__ + +#include +#include + +#include "fpga/core.h" +#include "fpga/sdk.h" +#include "wq.h" + +struct mlx5_fpga_conn { + struct mlx5_fpga_device *fdev; + + void (*recv_cb)(void *cb_arg, struct mlx5_fpga_dma_buf *buf); + void *cb_arg; + + /* FPGA QP */ + u32 fpga_qpc[MLX5_ST_SZ_DW(fpga_qpc)]; + u32 fpga_qpn; + + /* CQ */ + struct { + struct mlx5_cqwq wq; + struct mlx5_frag_wq_ctrl wq_ctrl; + struct mlx5_core_cq mcq; + struct tasklet_struct tasklet; + } cq; + + /* QP */ + struct { + bool active; + int sgid_index; + struct mlx5_wq_qp wq; + struct mlx5_wq_ctrl wq_ctrl; + struct mlx5_core_qp mqp; + struct { + spinlock_t lock; /* Protects all SQ state */ + unsigned int pc; + unsigned int cc; + unsigned int size; + struct mlx5_fpga_dma_buf **bufs; + struct list_head backlog; + } sq; + struct { + unsigned int pc; + unsigned int cc; + unsigned int size; + struct mlx5_fpga_dma_buf **bufs; + } rq; + } qp; +}; + +int mlx5_fpga_conn_device_init(struct mlx5_fpga_device *fdev); +void mlx5_fpga_conn_device_cleanup(struct mlx5_fpga_device *fdev); +struct mlx5_fpga_conn * +mlx5_fpga_conn_create(struct mlx5_fpga_device *fdev, + struct mlx5_fpga_conn_attr *attr, + enum mlx5_ifc_fpga_qp_type qp_type); +void mlx5_fpga_conn_destroy(struct mlx5_fpga_conn *conn); +int mlx5_fpga_conn_send(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_dma_buf *buf); + +#endif /* __MLX5_FPGA_CONN_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c index c3bb4b865f01..7f859a3ad5d2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c @@ -37,6 +37,7 @@ #include "mlx5_core.h" #include "lib/mlx5.h" #include "fpga/core.h" +#include "fpga/conn.h" static const char *const mlx5_fpga_error_strings[] = { "Null Syndrome", @@ -127,7 +128,17 @@ int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) max_num_qps = MLX5_CAP_FPGA(mdev, shell_caps.max_num_qps); err = mlx5_core_reserve_gids(mdev, max_num_qps); + if (err) + goto out; + + err = mlx5_fpga_conn_device_init(fdev); + if (err) + goto err_rsvd_gid; + + goto out; +err_rsvd_gid: + mlx5_core_unreserve_gids(mdev, max_num_qps); out: spin_lock_irqsave(&fdev->state_lock, flags); fdev->state = err ? MLX5_FPGA_STATUS_FAILURE : MLX5_FPGA_STATUS_SUCCESS; @@ -173,6 +184,7 @@ void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev) fdev->state = MLX5_FPGA_STATUS_NONE; spin_unlock_irqrestore(&fdev->state_lock, flags); + mlx5_fpga_conn_device_cleanup(fdev); max_num_qps = MLX5_CAP_FPGA(mdev, shell_caps.max_num_qps); mlx5_core_unreserve_gids(mdev, max_num_qps); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h index db1d22c356e0..f64fa1cdc195 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h @@ -44,6 +44,13 @@ struct mlx5_fpga_device { enum mlx5_fpga_status state; enum mlx5_fpga_image last_admin_image; enum mlx5_fpga_image last_oper_image; + + /* QP Connection resources */ + struct { + u32 pdn; + struct mlx5_core_mkey mkey; + struct mlx5_uars_page *uar; + } conn_res; }; #define mlx5_fpga_dbg(__adev, format, ...) \ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h new file mode 100644 index 000000000000..331798d99a37 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef MLX5_FPGA_SDK_H +#define MLX5_FPGA_SDK_H + +#include +#include + +/** + * DOC: Innova SDK + * This header defines the in-kernel API for Innova FPGA client drivers. + */ + +struct mlx5_fpga_conn; +struct mlx5_fpga_device; + +/** + * struct mlx5_fpga_dma_entry - A scatter-gather DMA entry + */ +struct mlx5_fpga_dma_entry { + /** @data: Virtual address pointer to the data */ + void *data; + /** @size: Size in bytes of the data */ + unsigned int size; + /** @dma_addr: Private member. Physical DMA-mapped address of the data */ + dma_addr_t dma_addr; +}; + +/** + * struct mlx5_fpga_dma_buf - A packet buffer + * May contain up to 2 scatter-gather data entries + */ +struct mlx5_fpga_dma_buf { + /** @dma_dir: DMA direction */ + enum dma_data_direction dma_dir; + /** @sg: Scatter-gather entries pointing to the data in memory */ + struct mlx5_fpga_dma_entry sg[2]; + /** @list: Item in SQ backlog, for TX packets */ + struct list_head list; + /** + * @complete: Completion routine, for TX packets + * @conn: FPGA Connection this packet was sent to + * @fdev: FPGA device this packet was sent to + * @buf: The packet buffer + * @status: 0 if successful, or an error code otherwise + */ + void (*complete)(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_device *fdev, + struct mlx5_fpga_dma_buf *buf, u8 status); +}; + +/** + * struct mlx5_fpga_conn_attr - FPGA connection attributes + * Describes the attributes of a connection + */ +struct mlx5_fpga_conn_attr { + /** @tx_size: Size of connection TX queue, in packets */ + unsigned int tx_size; + /** @rx_size: Size of connection RX queue, in packets */ + unsigned int rx_size; + /** + * @recv_cb: Callback function which is called for received packets + * @cb_arg: The value provided in mlx5_fpga_conn_attr.cb_arg + * @buf: A buffer containing a received packet + * + * buf is guaranteed to only contain a single scatter-gather entry. + * The size of the actual packet received is specified in buf.sg[0].size + * When this callback returns, the packet buffer may be re-used for + * subsequent receives. + */ + void (*recv_cb)(void *cb_arg, struct mlx5_fpga_dma_buf *buf); + void *cb_arg; +}; + +#endif /* MLX5_FPGA_SDK_H */ -- cgit v1.2.3 From c43051d72a8dc4a00d49db27292a76d26e8df7af Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Tue, 18 Apr 2017 12:54:27 +0300 Subject: net/mlx5: FPGA, Add SBU bypass and reset flows The Innova FPGA includes shell hardware and Sandbox-Unit (SBU) hardware. The shell hardware is handled by mlx5_core itself, while the SBU is handled by a client driver. Reset the SBU to a well-known initial state when initializing a new device, and set the FPGA to bypass mode when uninitializing a device. This allows the client driver to assume that its device has been reset when a new device is detected. During SBU reset, the FPGA is put into SBU-bypass mode. In this mode packets do not pass through the SBU, so it cannot affect the network data stream at all. A factory-image does not have an SBU, so skip these flows. Signed-off-by: Ilan Tayari Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c | 11 ++++++ drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h | 1 + .../net/ethernet/mellanox/mlx5/core/fpga/core.c | 40 ++++++++++++++++++++++ 3 files changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c index 8308ccbad85a..a5fdb4cf0b9c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c @@ -47,6 +47,17 @@ int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps) MLX5_REG_FPGA_CAP, 0, 0); } +int mlx5_fpga_ctrl_op(struct mlx5_core_dev *dev, u8 op) +{ + u32 in[MLX5_ST_SZ_DW(fpga_ctrl)] = {0}; + u32 out[MLX5_ST_SZ_DW(fpga_ctrl)]; + + MLX5_SET(fpga_ctrl, in, operation, op); + + return mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), + MLX5_REG_FPGA_CTRL, 0, true); +} + int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query) { u32 in[MLX5_ST_SZ_DW(fpga_ctrl)] = {0}; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h index b851580d846f..8943056163f3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h @@ -67,6 +67,7 @@ struct mlx5_fpga_qp_counters { int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps); int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query); +int mlx5_fpga_ctrl_op(struct mlx5_core_dev *dev, u8 op); int mlx5_fpga_create_qp(struct mlx5_core_dev *dev, void *fpga_qpc, u32 *fpga_qpn); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c index 7f859a3ad5d2..31e5a2627eb8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c @@ -102,6 +102,29 @@ static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev) return 0; } +int mlx5_fpga_device_brb(struct mlx5_fpga_device *fdev) +{ + int err; + struct mlx5_core_dev *mdev = fdev->mdev; + + err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_SANDBOX_BYPASS_ON); + if (err) { + mlx5_fpga_err(fdev, "Failed to set bypass on: %d\n", err); + return err; + } + err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_RESET_SANDBOX); + if (err) { + mlx5_fpga_err(fdev, "Failed to reset SBU: %d\n", err); + return err; + } + err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_SANDBOX_BYPASS_OFF); + if (err) { + mlx5_fpga_err(fdev, "Failed to set bypass off: %d\n", err); + return err; + } + return 0; +} + int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) { struct mlx5_fpga_device *fdev = mdev->fpga; @@ -135,8 +158,17 @@ int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) if (err) goto err_rsvd_gid; + if (fdev->last_oper_image == MLX5_FPGA_IMAGE_USER) { + err = mlx5_fpga_device_brb(fdev); + if (err) + goto err_conn_init; + } + goto out; +err_conn_init: + mlx5_fpga_conn_device_cleanup(fdev); + err_rsvd_gid: mlx5_core_unreserve_gids(mdev, max_num_qps); out: @@ -172,6 +204,7 @@ void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev) struct mlx5_fpga_device *fdev = mdev->fpga; unsigned int max_num_qps; unsigned long flags; + int err; if (!fdev) return; @@ -184,6 +217,13 @@ void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev) fdev->state = MLX5_FPGA_STATUS_NONE; spin_unlock_irqrestore(&fdev->state_lock, flags); + if (fdev->last_oper_image == MLX5_FPGA_IMAGE_USER) { + err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_SANDBOX_BYPASS_ON); + if (err) + mlx5_fpga_err(fdev, "Failed to re-set SBU bypass on: %d\n", + err); + } + mlx5_fpga_conn_device_cleanup(fdev); max_num_qps = MLX5_CAP_FPGA(mdev, shell_caps.max_num_qps); mlx5_core_unreserve_gids(mdev, max_num_qps); -- cgit v1.2.3 From a9956d35d199beb406727a4496bc5d7f09c82976 Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Tue, 18 Apr 2017 13:10:41 +0300 Subject: net/mlx5: FPGA, Add SBU infrastructure Add interface to initialize and interact with Innova FPGA SBU connections. A client driver may use these functions to set up a high-speed DMA connection with its SBU hardware logic, and send/receive messages over this connection. A later patch in this patchset will make use of these functions for Innova IPSec offload in mlx5 Ethernet driver. Add commands to retrieve Innova FPGA SBU capabilities, and to read/write Innova FPGA configuration space registers and memory, over internal I2C. At high level, the FPGA configuration space is divided such: 0x00000000 - 0x007fffff is reserved for the SBU 0x00800000 - 0xffffffff is reserved for the Shell 0x400000000 - ... is DDR memory A later patchset will add support for accessing FPGA CrSpace and memory over a high-speed connection. This is the reason for the ACCESS_TYPE enumeration, which currently only supports I2C. Signed-off-by: Ilan Tayari Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 +- drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c | 65 ++++++++ drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h | 3 + drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.c | 164 +++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h | 98 ++++++++++++ 5 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.c (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 5221b1235c47..676388fde239 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -6,7 +6,7 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ fs_counters.o rl.o lag.o dev.o lib/gid.o -mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o +mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c index a5fdb4cf0b9c..5cb855fd618f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c @@ -38,6 +38,39 @@ #include "mlx5_core.h" #include "fpga/cmd.h" +#define MLX5_FPGA_ACCESS_REG_SZ (MLX5_ST_SZ_DW(fpga_access_reg) + \ + MLX5_FPGA_ACCESS_REG_SIZE_MAX) + +int mlx5_fpga_access_reg(struct mlx5_core_dev *dev, u8 size, u64 addr, + void *buf, bool write) +{ + u32 in[MLX5_FPGA_ACCESS_REG_SZ] = {0}; + u32 out[MLX5_FPGA_ACCESS_REG_SZ]; + int err; + + if (size & 3) + return -EINVAL; + if (addr & 3) + return -EINVAL; + if (size > MLX5_FPGA_ACCESS_REG_SIZE_MAX) + return -EINVAL; + + MLX5_SET(fpga_access_reg, in, size, size); + MLX5_SET64(fpga_access_reg, in, address, addr); + if (write) + memcpy(MLX5_ADDR_OF(fpga_access_reg, in, data), buf, size); + + err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), + MLX5_REG_FPGA_ACCESS_REG, 0, write); + if (err) + return err; + + if (!write) + memcpy(buf, MLX5_ADDR_OF(fpga_access_reg, out, data), size); + + return 0; +} + int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps) { u32 in[MLX5_ST_SZ_DW(fpga_cap)] = {0}; @@ -58,6 +91,38 @@ int mlx5_fpga_ctrl_op(struct mlx5_core_dev *dev, u8 op) MLX5_REG_FPGA_CTRL, 0, true); } +int mlx5_fpga_sbu_caps(struct mlx5_core_dev *dev, void *caps, int size) +{ + unsigned int cap_size = MLX5_CAP_FPGA(dev, sandbox_extended_caps_len); + u64 addr = MLX5_CAP64_FPGA(dev, sandbox_extended_caps_addr); + unsigned int read; + int ret = 0; + + if (cap_size > size) { + mlx5_core_warn(dev, "Not enough buffer %u for FPGA SBU caps %u", + size, cap_size); + return -EINVAL; + } + + while (cap_size > 0) { + read = min_t(unsigned int, cap_size, + MLX5_FPGA_ACCESS_REG_SIZE_MAX); + + ret = mlx5_fpga_access_reg(dev, read, addr, caps, false); + if (ret) { + mlx5_core_warn(dev, "Error reading FPGA SBU caps %u bytes at address 0x%llx: %d", + read, addr, ret); + return ret; + } + + cap_size -= read; + addr += read; + caps += read; + } + + return ret; +} + int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query) { u32 in[MLX5_ST_SZ_DW(fpga_ctrl)] = {0}; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h index 8943056163f3..94bdfd47c3f0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h @@ -68,6 +68,9 @@ struct mlx5_fpga_qp_counters { int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps); int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query); int mlx5_fpga_ctrl_op(struct mlx5_core_dev *dev, u8 op); +int mlx5_fpga_access_reg(struct mlx5_core_dev *dev, u8 size, u64 addr, + void *buf, bool write); +int mlx5_fpga_sbu_caps(struct mlx5_core_dev *dev, void *caps, int size); int mlx5_fpga_create_qp(struct mlx5_core_dev *dev, void *fpga_qpc, u32 *fpga_qpn); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.c new file mode 100644 index 000000000000..3c11d6e2160a --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include + +#include "fpga/core.h" +#include "fpga/conn.h" +#include "fpga/sdk.h" + +struct mlx5_fpga_conn * +mlx5_fpga_sbu_conn_create(struct mlx5_fpga_device *fdev, + struct mlx5_fpga_conn_attr *attr) +{ + return mlx5_fpga_conn_create(fdev, attr, MLX5_FPGA_QPC_QP_TYPE_SANDBOX_QP); +} +EXPORT_SYMBOL(mlx5_fpga_sbu_conn_create); + +void mlx5_fpga_sbu_conn_destroy(struct mlx5_fpga_conn *conn) +{ + mlx5_fpga_conn_destroy(conn); +} +EXPORT_SYMBOL(mlx5_fpga_sbu_conn_destroy); + +int mlx5_fpga_sbu_conn_sendmsg(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_dma_buf *buf) +{ + return mlx5_fpga_conn_send(conn, buf); +} +EXPORT_SYMBOL(mlx5_fpga_sbu_conn_sendmsg); + +static int mlx5_fpga_mem_read_i2c(struct mlx5_fpga_device *fdev, size_t size, + u64 addr, u8 *buf) +{ + size_t max_size = MLX5_FPGA_ACCESS_REG_SIZE_MAX; + size_t bytes_done = 0; + u8 actual_size; + int err; + + if (!fdev->mdev) + return -ENOTCONN; + + while (bytes_done < size) { + actual_size = min(max_size, (size - bytes_done)); + + err = mlx5_fpga_access_reg(fdev->mdev, actual_size, + addr + bytes_done, + buf + bytes_done, false); + if (err) { + mlx5_fpga_err(fdev, "Failed to read over I2C: %d\n", + err); + break; + } + + bytes_done += actual_size; + } + + return err; +} + +static int mlx5_fpga_mem_write_i2c(struct mlx5_fpga_device *fdev, size_t size, + u64 addr, u8 *buf) +{ + size_t max_size = MLX5_FPGA_ACCESS_REG_SIZE_MAX; + size_t bytes_done = 0; + u8 actual_size; + int err; + + if (!fdev->mdev) + return -ENOTCONN; + + while (bytes_done < size) { + actual_size = min(max_size, (size - bytes_done)); + + err = mlx5_fpga_access_reg(fdev->mdev, actual_size, + addr + bytes_done, + buf + bytes_done, true); + if (err) { + mlx5_fpga_err(fdev, "Failed to write FPGA crspace\n"); + break; + } + + bytes_done += actual_size; + } + + return err; +} + +int mlx5_fpga_mem_read(struct mlx5_fpga_device *fdev, size_t size, u64 addr, + void *buf, enum mlx5_fpga_access_type access_type) +{ + int ret; + + switch (access_type) { + case MLX5_FPGA_ACCESS_TYPE_I2C: + ret = mlx5_fpga_mem_read_i2c(fdev, size, addr, buf); + if (ret) + return ret; + break; + default: + mlx5_fpga_warn(fdev, "Unexpected read access_type %u\n", + access_type); + return -EACCES; + } + + return size; +} +EXPORT_SYMBOL(mlx5_fpga_mem_read); + +int mlx5_fpga_mem_write(struct mlx5_fpga_device *fdev, size_t size, u64 addr, + void *buf, enum mlx5_fpga_access_type access_type) +{ + int ret; + + switch (access_type) { + case MLX5_FPGA_ACCESS_TYPE_I2C: + ret = mlx5_fpga_mem_write_i2c(fdev, size, addr, buf); + if (ret) + return ret; + break; + default: + mlx5_fpga_warn(fdev, "Unexpected write access_type %u\n", + access_type); + return -EACCES; + } + + return size; +} +EXPORT_SYMBOL(mlx5_fpga_mem_write); + +int mlx5_fpga_get_sbu_caps(struct mlx5_fpga_device *fdev, int size, void *buf) +{ + return mlx5_fpga_sbu_caps(fdev->mdev, buf, size); +} +EXPORT_SYMBOL(mlx5_fpga_get_sbu_caps); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h index 331798d99a37..baa537e54a49 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/sdk.h @@ -42,6 +42,11 @@ * This header defines the in-kernel API for Innova FPGA client drivers. */ +enum mlx5_fpga_access_type { + MLX5_FPGA_ACCESS_TYPE_I2C = 0x0, + MLX5_FPGA_ACCESS_TYPE_DONTCARE = 0x0, +}; + struct mlx5_fpga_conn; struct mlx5_fpga_device; @@ -103,4 +108,97 @@ struct mlx5_fpga_conn_attr { void *cb_arg; }; +/** + * mlx5_fpga_sbu_conn_create() - Initialize a new FPGA SBU connection + * @fdev: The FPGA device + * @attr: Attributes of the new connection + * + * Sets up a new FPGA SBU connection with the specified attributes. + * The receive callback function may be called for incoming messages even + * before this function returns. + * + * The caller must eventually destroy the connection by calling + * mlx5_fpga_sbu_conn_destroy. + * + * Return: A new connection, or ERR_PTR() error value otherwise. + */ +struct mlx5_fpga_conn * +mlx5_fpga_sbu_conn_create(struct mlx5_fpga_device *fdev, + struct mlx5_fpga_conn_attr *attr); + +/** + * mlx5_fpga_sbu_conn_destroy() - Destroy an FPGA SBU connection + * @conn: The FPGA SBU connection to destroy + * + * Cleans up an FPGA SBU connection which was previously created with + * mlx5_fpga_sbu_conn_create. + */ +void mlx5_fpga_sbu_conn_destroy(struct mlx5_fpga_conn *conn); + +/** + * mlx5_fpga_sbu_conn_sendmsg() - Queue the transmission of a packet + * @fdev: An FPGA SBU connection + * @buf: The packet buffer + * + * Queues a packet for transmission over an FPGA SBU connection. + * The buffer should not be modified or freed until completion. + * Upon completion, the buf's complete() callback is invoked, indicating the + * success or error status of the transmission. + * + * Return: 0 if successful, or an error value otherwise. + */ +int mlx5_fpga_sbu_conn_sendmsg(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_dma_buf *buf); + +/** + * mlx5_fpga_mem_read() - Read from FPGA memory address space + * @fdev: The FPGA device + * @size: Size of chunk to read, in bytes + * @addr: Starting address to read from, in FPGA address space + * @buf: Buffer to read into + * @access_type: Method for reading + * + * Reads from the specified address into the specified buffer. + * The address may point to configuration space or to DDR. + * Large reads may be performed internally as several non-atomic operations. + * This function may sleep, so should not be called from atomic contexts. + * + * Return: 0 if successful, or an error value otherwise. + */ +int mlx5_fpga_mem_read(struct mlx5_fpga_device *fdev, size_t size, u64 addr, + void *buf, enum mlx5_fpga_access_type access_type); + +/** + * mlx5_fpga_mem_write() - Write to FPGA memory address space + * @fdev: The FPGA device + * @size: Size of chunk to write, in bytes + * @addr: Starting address to write to, in FPGA address space + * @buf: Buffer which contains data to write + * @access_type: Method for writing + * + * Writes the specified buffer data to FPGA memory at the specified address. + * The address may point to configuration space or to DDR. + * Large writes may be performed internally as several non-atomic operations. + * This function may sleep, so should not be called from atomic contexts. + * + * Return: 0 if successful, or an error value otherwise. + */ +int mlx5_fpga_mem_write(struct mlx5_fpga_device *fdev, size_t size, u64 addr, + void *buf, enum mlx5_fpga_access_type access_type); + +/** + * mlx5_fpga_get_sbu_caps() - Read the SBU capabilities + * @fdev: The FPGA device + * @size: Size of the buffer to read into + * @buf: Buffer to read the capabilities into + * + * Reads the FPGA SBU capabilities into the specified buffer. + * The format of the capabilities buffer is SBU-dependent. + * + * Return: 0 if successful + * -EINVAL if the buffer is not large enough to contain SBU caps + * or any other error value otherwise. + */ +int mlx5_fpga_get_sbu_caps(struct mlx5_fpga_device *fdev, int size, void *buf); + #endif /* MLX5_FPGA_SDK_H */ -- cgit v1.2.3 From bebb23e6cb02d2fc752905e39d09ff6152852c6c Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Tue, 25 Apr 2017 22:42:31 +0300 Subject: net/mlx5: Accel, Add IPSec acceleration interface Add routines for manipulating the hardware IPSec SA database (SADB). In Innova IPSec, a Security Association (SA) is added or deleted via a command message over the SBU connection. The HW then sends a response message over the same connection. Add implementation for Innova IPSec (FPGA-based) hardware. These routines will be used by the IPSec offload support in a later patch However they may also be used by others such as RDMA and RoCE IPSec. mlx5/accel is a middle acceleration layer to allow mlx5e and other ULPs to work directly with mlx5_core rather than Innova FPGA or other mlx5 acceleration providers. In this patchset we add Innova IPSec support and mlx5/accel delegates IPSec offloads to Innova routines. In the future, when IPSec/TLS or any other acceleration gets integrated into ConnectX chip, mlx5/accel layer will provide the integrated acceleration, rather than the Innova one. Signed-off-by: Ilan Tayari Signed-off-by: Boris Pismenny Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Kconfig | 4 + drivers/net/ethernet/mellanox/mlx5/core/Makefile | 5 +- .../net/ethernet/mellanox/mlx5/core/accel/ipsec.c | 78 +++++ .../net/ethernet/mellanox/mlx5/core/accel/ipsec.h | 138 ++++++++ .../net/ethernet/mellanox/mlx5/core/fpga/core.h | 2 + .../net/ethernet/mellanox/mlx5/core/fpga/ipsec.c | 376 +++++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/fpga/ipsec.h | 94 ++++++ drivers/net/ethernet/mellanox/mlx5/core/main.c | 9 + 8 files changed, 705 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig index cf1ef48bfd8d..d6c6cea8ebab 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig @@ -11,9 +11,13 @@ config MLX5_CORE Core driver for low level functionality of the ConnectX-4 and Connect-IB cards by Mellanox Technologies. +config MLX5_ACCEL + bool + config MLX5_FPGA bool "Mellanox Technologies Innova support" depends on MLX5_CORE + select MLX5_ACCEL ---help--- Build support for the Innova family of network cards by Mellanox Technologies. Innova network cards are comprised of a ConnectX chip diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 676388fde239..33557526f597 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -6,7 +6,10 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ fs_counters.o rl.o lag.o dev.o lib/gid.o -mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o +mlx5_core-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o + +mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \ + fpga/ipsec.o mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c new file mode 100644 index 000000000000..53e69edaedde --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include + +#include "accel/ipsec.h" +#include "mlx5_core.h" +#include "fpga/ipsec.h" + +void *mlx5_accel_ipsec_sa_cmd_exec(struct mlx5_core_dev *mdev, + struct mlx5_accel_ipsec_sa *cmd) +{ + if (!MLX5_IPSEC_DEV(mdev)) + return ERR_PTR(-EOPNOTSUPP); + + return mlx5_fpga_ipsec_sa_cmd_exec(mdev, cmd); +} + +int mlx5_accel_ipsec_sa_cmd_wait(void *ctx) +{ + return mlx5_fpga_ipsec_sa_cmd_wait(ctx); +} + +u32 mlx5_accel_ipsec_device_caps(struct mlx5_core_dev *mdev) +{ + return mlx5_fpga_ipsec_device_caps(mdev); +} + +unsigned int mlx5_accel_ipsec_counters_count(struct mlx5_core_dev *mdev) +{ + return mlx5_fpga_ipsec_counters_count(mdev); +} + +int mlx5_accel_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, + unsigned int count) +{ + return mlx5_fpga_ipsec_counters_read(mdev, counters, count); +} + +int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev) +{ + return mlx5_fpga_ipsec_init(mdev); +} + +void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev) +{ + mlx5_fpga_ipsec_cleanup(mdev); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h new file mode 100644 index 000000000000..d6e20fea9554 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/ipsec.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef __MLX5_ACCEL_IPSEC_H__ +#define __MLX5_ACCEL_IPSEC_H__ + +#ifdef CONFIG_MLX5_ACCEL + +#include + +enum { + MLX5_ACCEL_IPSEC_DEVICE = BIT(1), + MLX5_ACCEL_IPSEC_IPV6 = BIT(2), + MLX5_ACCEL_IPSEC_ESP = BIT(3), + MLX5_ACCEL_IPSEC_LSO = BIT(4), +}; + +#define MLX5_IPSEC_SADB_IP_AH BIT(7) +#define MLX5_IPSEC_SADB_IP_ESP BIT(6) +#define MLX5_IPSEC_SADB_SA_VALID BIT(5) +#define MLX5_IPSEC_SADB_SPI_EN BIT(4) +#define MLX5_IPSEC_SADB_DIR_SX BIT(3) +#define MLX5_IPSEC_SADB_IPV6 BIT(2) + +enum { + MLX5_IPSEC_CMD_ADD_SA = 0, + MLX5_IPSEC_CMD_DEL_SA = 1, +}; + +enum mlx5_accel_ipsec_enc_mode { + MLX5_IPSEC_SADB_MODE_NONE = 0, + MLX5_IPSEC_SADB_MODE_AES_GCM_128_AUTH_128 = 1, + MLX5_IPSEC_SADB_MODE_AES_GCM_256_AUTH_128 = 3, +}; + +#define MLX5_IPSEC_DEV(mdev) (mlx5_accel_ipsec_device_caps(mdev) & \ + MLX5_ACCEL_IPSEC_DEVICE) + +struct mlx5_accel_ipsec_sa { + __be32 cmd; + u8 key_enc[32]; + u8 key_auth[32]; + __be32 sip[4]; + __be32 dip[4]; + union { + struct { + __be32 reserved; + u8 salt_iv[8]; + __be32 salt; + } __packed gcm; + struct { + u8 salt[16]; + } __packed cbc; + }; + __be32 spi; + __be32 sw_sa_handle; + __be16 tfclen; + u8 enc_mode; + u8 sip_masklen; + u8 dip_masklen; + u8 flags; + u8 reserved[2]; +} __packed; + +/** + * mlx5_accel_ipsec_sa_cmd_exec - Execute an IPSec SADB command + * @mdev: mlx5 device + * @cmd: command to execute + * May be called from atomic context. Returns context pointer, or error + * Caller must eventually call mlx5_accel_ipsec_sa_cmd_wait from non-atomic + * context, to cleanup the context pointer + */ +void *mlx5_accel_ipsec_sa_cmd_exec(struct mlx5_core_dev *mdev, + struct mlx5_accel_ipsec_sa *cmd); + +/** + * mlx5_accel_ipsec_sa_cmd_wait - Wait for command execution completion + * @context: Context pointer returned from call to mlx5_accel_ipsec_sa_cmd_exec + * Sleeps (killable) until command execution is complete. + * Returns the command result, or -EINTR if killed + */ +int mlx5_accel_ipsec_sa_cmd_wait(void *context); + +u32 mlx5_accel_ipsec_device_caps(struct mlx5_core_dev *mdev); + +unsigned int mlx5_accel_ipsec_counters_count(struct mlx5_core_dev *mdev); +int mlx5_accel_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, + unsigned int count); + +int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev); +void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev); + +#else + +#define MLX5_IPSEC_DEV(mdev) false + +static inline int mlx5_accel_ipsec_init(struct mlx5_core_dev *mdev) +{ + return 0; +} + +static inline void mlx5_accel_ipsec_cleanup(struct mlx5_core_dev *mdev) +{ +} + +#endif + +#endif /* __MLX5_ACCEL_IPSEC_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h index f64fa1cdc195..82405ed84725 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h @@ -51,6 +51,8 @@ struct mlx5_fpga_device { struct mlx5_core_mkey mkey; struct mlx5_uars_page *uar; } conn_res; + + struct mlx5_fpga_ipsec *ipsec; }; #define mlx5_fpga_dbg(__adev, format, ...) \ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c new file mode 100644 index 000000000000..42970e2a05ff --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include + +#include "mlx5_core.h" +#include "fpga/ipsec.h" +#include "fpga/sdk.h" +#include "fpga/core.h" + +#define SBU_QP_QUEUE_SIZE 8 + +enum mlx5_ipsec_response_syndrome { + MLX5_IPSEC_RESPONSE_SUCCESS = 0, + MLX5_IPSEC_RESPONSE_ILLEGAL_REQUEST = 1, + MLX5_IPSEC_RESPONSE_SADB_ISSUE = 2, + MLX5_IPSEC_RESPONSE_WRITE_RESPONSE_ISSUE = 3, +}; + +enum mlx5_fpga_ipsec_sacmd_status { + MLX5_FPGA_IPSEC_SACMD_PENDING, + MLX5_FPGA_IPSEC_SACMD_SEND_FAIL, + MLX5_FPGA_IPSEC_SACMD_COMPLETE, +}; + +struct mlx5_ipsec_command_context { + struct mlx5_fpga_dma_buf buf; + struct mlx5_accel_ipsec_sa sa; + enum mlx5_fpga_ipsec_sacmd_status status; + int status_code; + struct completion complete; + struct mlx5_fpga_device *dev; + struct list_head list; /* Item in pending_cmds */ +}; + +struct mlx5_ipsec_sadb_resp { + __be32 syndrome; + __be32 sw_sa_handle; + u8 reserved[24]; +} __packed; + +struct mlx5_fpga_ipsec { + struct list_head pending_cmds; + spinlock_t pending_cmds_lock; /* Protects pending_cmds */ + u32 caps[MLX5_ST_SZ_DW(ipsec_extended_cap)]; + struct mlx5_fpga_conn *conn; +}; + +static bool mlx5_fpga_is_ipsec_device(struct mlx5_core_dev *mdev) +{ + if (!mdev->fpga || !MLX5_CAP_GEN(mdev, fpga)) + return false; + + if (MLX5_CAP_FPGA(mdev, ieee_vendor_id) != + MLX5_FPGA_CAP_SANDBOX_VENDOR_ID_MLNX) + return false; + + if (MLX5_CAP_FPGA(mdev, sandbox_product_id) != + MLX5_FPGA_CAP_SANDBOX_PRODUCT_ID_IPSEC) + return false; + + return true; +} + +static void mlx5_fpga_ipsec_send_complete(struct mlx5_fpga_conn *conn, + struct mlx5_fpga_device *fdev, + struct mlx5_fpga_dma_buf *buf, + u8 status) +{ + struct mlx5_ipsec_command_context *context; + + if (status) { + context = container_of(buf, struct mlx5_ipsec_command_context, + buf); + mlx5_fpga_warn(fdev, "IPSec command send failed with status %u\n", + status); + context->status = MLX5_FPGA_IPSEC_SACMD_SEND_FAIL; + complete(&context->complete); + } +} + +static inline int syndrome_to_errno(enum mlx5_ipsec_response_syndrome syndrome) +{ + switch (syndrome) { + case MLX5_IPSEC_RESPONSE_SUCCESS: + return 0; + case MLX5_IPSEC_RESPONSE_SADB_ISSUE: + return -EEXIST; + case MLX5_IPSEC_RESPONSE_ILLEGAL_REQUEST: + return -EINVAL; + case MLX5_IPSEC_RESPONSE_WRITE_RESPONSE_ISSUE: + return -EIO; + } + return -EIO; +} + +static void mlx5_fpga_ipsec_recv(void *cb_arg, struct mlx5_fpga_dma_buf *buf) +{ + struct mlx5_ipsec_sadb_resp *resp = buf->sg[0].data; + struct mlx5_ipsec_command_context *context; + enum mlx5_ipsec_response_syndrome syndrome; + struct mlx5_fpga_device *fdev = cb_arg; + unsigned long flags; + + if (buf->sg[0].size < sizeof(*resp)) { + mlx5_fpga_warn(fdev, "Short receive from FPGA IPSec: %u < %zu bytes\n", + buf->sg[0].size, sizeof(*resp)); + return; + } + + mlx5_fpga_dbg(fdev, "mlx5_ipsec recv_cb syndrome %08x sa_id %x\n", + ntohl(resp->syndrome), ntohl(resp->sw_sa_handle)); + + spin_lock_irqsave(&fdev->ipsec->pending_cmds_lock, flags); + context = list_first_entry_or_null(&fdev->ipsec->pending_cmds, + struct mlx5_ipsec_command_context, + list); + if (context) + list_del(&context->list); + spin_unlock_irqrestore(&fdev->ipsec->pending_cmds_lock, flags); + + if (!context) { + mlx5_fpga_warn(fdev, "Received IPSec offload response without pending command request\n"); + return; + } + mlx5_fpga_dbg(fdev, "Handling response for %p\n", context); + + if (context->sa.sw_sa_handle != resp->sw_sa_handle) { + mlx5_fpga_err(fdev, "mismatch SA handle. cmd 0x%08x vs resp 0x%08x\n", + ntohl(context->sa.sw_sa_handle), + ntohl(resp->sw_sa_handle)); + return; + } + + syndrome = ntohl(resp->syndrome); + context->status_code = syndrome_to_errno(syndrome); + context->status = MLX5_FPGA_IPSEC_SACMD_COMPLETE; + + if (context->status_code) + mlx5_fpga_warn(fdev, "IPSec SADB command failed with syndrome %08x\n", + syndrome); + complete(&context->complete); +} + +void *mlx5_fpga_ipsec_sa_cmd_exec(struct mlx5_core_dev *mdev, + struct mlx5_accel_ipsec_sa *cmd) +{ + struct mlx5_ipsec_command_context *context; + struct mlx5_fpga_device *fdev = mdev->fpga; + unsigned long flags; + int res = 0; + + BUILD_BUG_ON((sizeof(struct mlx5_accel_ipsec_sa) & 3) != 0); + if (!fdev || !fdev->ipsec) + return ERR_PTR(-EOPNOTSUPP); + + context = kzalloc(sizeof(*context), GFP_ATOMIC); + if (!context) + return ERR_PTR(-ENOMEM); + + memcpy(&context->sa, cmd, sizeof(*cmd)); + context->buf.complete = mlx5_fpga_ipsec_send_complete; + context->buf.sg[0].size = sizeof(context->sa); + context->buf.sg[0].data = &context->sa; + init_completion(&context->complete); + context->dev = fdev; + spin_lock_irqsave(&fdev->ipsec->pending_cmds_lock, flags); + list_add_tail(&context->list, &fdev->ipsec->pending_cmds); + spin_unlock_irqrestore(&fdev->ipsec->pending_cmds_lock, flags); + + context->status = MLX5_FPGA_IPSEC_SACMD_PENDING; + + res = mlx5_fpga_sbu_conn_sendmsg(fdev->ipsec->conn, &context->buf); + if (res) { + mlx5_fpga_warn(fdev, "Failure sending IPSec command: %d\n", + res); + spin_lock_irqsave(&fdev->ipsec->pending_cmds_lock, flags); + list_del(&context->list); + spin_unlock_irqrestore(&fdev->ipsec->pending_cmds_lock, flags); + kfree(context); + return ERR_PTR(res); + } + /* Context will be freed by wait func after completion */ + return context; +} + +int mlx5_fpga_ipsec_sa_cmd_wait(void *ctx) +{ + struct mlx5_ipsec_command_context *context = ctx; + int res; + + res = wait_for_completion_killable(&context->complete); + if (res) { + mlx5_fpga_warn(context->dev, "Failure waiting for IPSec command response\n"); + return -EINTR; + } + + if (context->status == MLX5_FPGA_IPSEC_SACMD_COMPLETE) + res = context->status_code; + else + res = -EIO; + + kfree(context); + return res; +} + +u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev) +{ + struct mlx5_fpga_device *fdev = mdev->fpga; + u32 ret = 0; + + if (mlx5_fpga_is_ipsec_device(mdev)) + ret |= MLX5_ACCEL_IPSEC_DEVICE; + else + return ret; + + if (!fdev->ipsec) + return ret; + + if (MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, esp)) + ret |= MLX5_ACCEL_IPSEC_ESP; + + if (MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, ipv6)) + ret |= MLX5_ACCEL_IPSEC_IPV6; + + if (MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, lso)) + ret |= MLX5_ACCEL_IPSEC_LSO; + + return ret; +} + +unsigned int mlx5_fpga_ipsec_counters_count(struct mlx5_core_dev *mdev) +{ + struct mlx5_fpga_device *fdev = mdev->fpga; + + if (!fdev || !fdev->ipsec) + return 0; + + return MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, + number_of_ipsec_counters); +} + +int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, + unsigned int counters_count) +{ + struct mlx5_fpga_device *fdev = mdev->fpga; + unsigned int i; + u32 *data; + u32 count; + u64 addr; + int ret; + + if (!fdev || !fdev->ipsec) + return 0; + + addr = (u64)MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, + ipsec_counters_addr_low) + + ((u64)MLX5_GET(ipsec_extended_cap, fdev->ipsec->caps, + ipsec_counters_addr_high) << 32); + + count = mlx5_fpga_ipsec_counters_count(mdev); + + data = kzalloc(sizeof(u32) * count * 2, GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto out; + } + + ret = mlx5_fpga_mem_read(fdev, count * sizeof(u64), addr, data, + MLX5_FPGA_ACCESS_TYPE_DONTCARE); + if (ret < 0) { + mlx5_fpga_err(fdev, "Failed to read IPSec counters from HW: %d\n", + ret); + goto out; + } + ret = 0; + + if (count > counters_count) + count = counters_count; + + /* Each counter is low word, then high. But each word is big-endian */ + for (i = 0; i < count; i++) + counters[i] = (u64)ntohl(data[i * 2]) | + ((u64)ntohl(data[i * 2 + 1]) << 32); + +out: + kfree(data); + return ret; +} + +int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev) +{ + struct mlx5_fpga_conn_attr init_attr = {0}; + struct mlx5_fpga_device *fdev = mdev->fpga; + struct mlx5_fpga_conn *conn; + int err; + + if (!mlx5_fpga_is_ipsec_device(mdev)) + return 0; + + fdev->ipsec = kzalloc(sizeof(*fdev->ipsec), GFP_KERNEL); + if (!fdev->ipsec) + return -ENOMEM; + + err = mlx5_fpga_get_sbu_caps(fdev, sizeof(fdev->ipsec->caps), + fdev->ipsec->caps); + if (err) { + mlx5_fpga_err(fdev, "Failed to retrieve IPSec extended capabilities: %d\n", + err); + goto error; + } + + INIT_LIST_HEAD(&fdev->ipsec->pending_cmds); + spin_lock_init(&fdev->ipsec->pending_cmds_lock); + + init_attr.rx_size = SBU_QP_QUEUE_SIZE; + init_attr.tx_size = SBU_QP_QUEUE_SIZE; + init_attr.recv_cb = mlx5_fpga_ipsec_recv; + init_attr.cb_arg = fdev; + conn = mlx5_fpga_sbu_conn_create(fdev, &init_attr); + if (IS_ERR(conn)) { + err = PTR_ERR(conn); + mlx5_fpga_err(fdev, "Error creating IPSec command connection %d\n", + err); + goto error; + } + fdev->ipsec->conn = conn; + return 0; + +error: + kfree(fdev->ipsec); + fdev->ipsec = NULL; + return err; +} + +void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev) +{ + struct mlx5_fpga_device *fdev = mdev->fpga; + + if (!mlx5_fpga_is_ipsec_device(mdev)) + return; + + mlx5_fpga_sbu_conn_destroy(fdev->ipsec->conn); + kfree(fdev->ipsec); + fdev->ipsec = NULL; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h new file mode 100644 index 000000000000..26a3e4b56972 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef __MLX5_FPGA_IPSEC_H__ +#define __MLX5_FPGA_IPSEC_H__ + +#include "accel/ipsec.h" + +#ifdef CONFIG_MLX5_FPGA + +void *mlx5_fpga_ipsec_sa_cmd_exec(struct mlx5_core_dev *mdev, + struct mlx5_accel_ipsec_sa *cmd); +int mlx5_fpga_ipsec_sa_cmd_wait(void *context); + +u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev); +unsigned int mlx5_fpga_ipsec_counters_count(struct mlx5_core_dev *mdev); +int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, + unsigned int counters_count); + +int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev); +void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev); + +#else + +static inline void *mlx5_fpga_ipsec_sa_cmd_exec(struct mlx5_core_dev *mdev, + struct mlx5_accel_ipsec_sa *cmd) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline int mlx5_fpga_ipsec_sa_cmd_wait(void *context) +{ + return -EOPNOTSUPP; +} + +static inline u32 mlx5_fpga_ipsec_device_caps(struct mlx5_core_dev *mdev) +{ + return 0; +} + +static inline unsigned int +mlx5_fpga_ipsec_counters_count(struct mlx5_core_dev *mdev) +{ + return 0; +} + +static inline int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev, + u64 *counters) +{ + return 0; +} + +static inline int mlx5_fpga_ipsec_init(struct mlx5_core_dev *mdev) +{ + return 0; +} + +static inline void mlx5_fpga_ipsec_cleanup(struct mlx5_core_dev *mdev) +{ +} + +#endif /* CONFIG_MLX5_FPGA */ + +#endif /* __MLX5_FPGA_SADB_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 684612778677..719f8e974482 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -58,6 +58,7 @@ #endif #include "lib/mlx5.h" #include "fpga/core.h" +#include "accel/ipsec.h" MODULE_AUTHOR("Eli Cohen "); MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver"); @@ -1169,6 +1170,11 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, dev_err(&pdev->dev, "fpga device start failed %d\n", err); goto err_fpga_start; } + err = mlx5_accel_ipsec_init(dev); + if (err) { + dev_err(&pdev->dev, "IPSec device start failed %d\n", err); + goto err_ipsec_start; + } if (mlx5_device_registered(dev)) { mlx5_attach_device(dev); @@ -1188,6 +1194,8 @@ out: return 0; err_reg_dev: + mlx5_accel_ipsec_cleanup(dev); +err_ipsec_start: mlx5_fpga_device_stop(dev); err_fpga_start: @@ -1267,6 +1275,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, if (mlx5_device_registered(dev)) mlx5_detach_device(dev); + mlx5_accel_ipsec_cleanup(dev); mlx5_fpga_device_stop(dev); mlx5_sriov_detach(dev); -- cgit v1.2.3 From 547eede070eb981f1442e494f08f4567dcf1d1c7 Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Tue, 18 Apr 2017 16:04:28 +0300 Subject: net/mlx5e: IPSec, Innova IPSec offload infrastructure Add Innova IPSec ESP crypto offload configuration paths. Detect Innova IPSec device and set the NETIF_F_HW_ESP flag. Configure Security Associations using the API introduced in a previous patch. Add Software-parser hardware descriptor layout Software-Parser (swp) is a hardware feature in ConnectX which allows the host software to specify protocol header offsets in the TX path, thus overriding the hardware parser. This is useful for protocols that the ASIC may not be able to parse on its own. Note that due to inline metadata, XDP is not supported in Innova IPSec. Signed-off-by: Ilan Tayari Signed-off-by: Yossi Kuperman Signed-off-by: Yevgeny Kliteynik Signed-off-by: Boris Pismenny Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Kconfig | 12 + drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 + drivers/net/ethernet/mellanox/mlx5/core/en.h | 3 + .../ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 415 +++++++++++++++++++++ .../ethernet/mellanox/mlx5/core/en_accel/ipsec.h | 78 ++++ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 14 + 6 files changed, 524 insertions(+) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig index d6c6cea8ebab..5aee05992f27 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig @@ -52,3 +52,15 @@ config MLX5_CORE_IPOIB default n ---help--- MLX5 IPoIB offloads & acceleration support. + +config MLX5_EN_IPSEC + bool "IPSec XFRM cryptography-offload accelaration" + depends on MLX5_ACCEL + depends on MLX5_CORE_EN + depends on XFRM_OFFLOAD + depends on INET_ESP_OFFLOAD || INET6_ESP_OFFLOAD + default n + ---help--- + Build support for IPsec cryptography-offload accelaration in the NIC. + Note: Support for hardware with this capability needs to be selected + for this option to become available. diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 33557526f597..7e81084a75ea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -19,3 +19,5 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o + +mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index f93f44d1d1cf..535ffd78a34e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -784,6 +784,9 @@ struct mlx5e_priv { const struct mlx5e_profile *profile; void *ppriv; +#ifdef CONFIG_MLX5_EN_IPSEC + struct mlx5e_ipsec *ipsec; +#endif }; struct mlx5e_profile { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c new file mode 100644 index 000000000000..06d9d6ad93ad --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include +#include +#include + +#include "en.h" +#include "accel/ipsec.h" +#include "en_accel/ipsec.h" + +struct mlx5e_ipsec_sa_entry { + struct hlist_node hlist; /* Item in SADB_RX hashtable */ + unsigned int handle; /* Handle in SADB_RX */ + struct xfrm_state *x; + struct mlx5e_ipsec *ipsec; + void *context; +}; + +static int mlx5e_ipsec_sadb_rx_add(struct mlx5e_ipsec_sa_entry *sa_entry) +{ + struct mlx5e_ipsec *ipsec = sa_entry->ipsec; + unsigned long flags; + int ret; + + spin_lock_irqsave(&ipsec->sadb_rx_lock, flags); + ret = ida_simple_get(&ipsec->halloc, 1, 0, GFP_KERNEL); + if (ret < 0) + goto out; + + sa_entry->handle = ret; + hash_add_rcu(ipsec->sadb_rx, &sa_entry->hlist, sa_entry->handle); + ret = 0; + +out: + spin_unlock_irqrestore(&ipsec->sadb_rx_lock, flags); + return ret; +} + +static void mlx5e_ipsec_sadb_rx_del(struct mlx5e_ipsec_sa_entry *sa_entry) +{ + struct mlx5e_ipsec *ipsec = sa_entry->ipsec; + unsigned long flags; + + spin_lock_irqsave(&ipsec->sadb_rx_lock, flags); + hash_del_rcu(&sa_entry->hlist); + spin_unlock_irqrestore(&ipsec->sadb_rx_lock, flags); +} + +static void mlx5e_ipsec_sadb_rx_free(struct mlx5e_ipsec_sa_entry *sa_entry) +{ + struct mlx5e_ipsec *ipsec = sa_entry->ipsec; + unsigned long flags; + + /* Wait for the hash_del_rcu call in sadb_rx_del to affect data path */ + synchronize_rcu(); + spin_lock_irqsave(&ipsec->sadb_rx_lock, flags); + ida_simple_remove(&ipsec->halloc, sa_entry->handle); + spin_unlock_irqrestore(&ipsec->sadb_rx_lock, flags); +} + +static enum mlx5_accel_ipsec_enc_mode mlx5e_ipsec_enc_mode(struct xfrm_state *x) +{ + unsigned int key_len = (x->aead->alg_key_len + 7) / 8 - 4; + + switch (key_len) { + case 16: + return MLX5_IPSEC_SADB_MODE_AES_GCM_128_AUTH_128; + case 32: + return MLX5_IPSEC_SADB_MODE_AES_GCM_256_AUTH_128; + default: + netdev_warn(x->xso.dev, "Bad key len: %d for alg %s\n", + key_len, x->aead->alg_name); + return -1; + } +} + +static void mlx5e_ipsec_build_hw_sa(u32 op, struct mlx5e_ipsec_sa_entry *sa_entry, + struct mlx5_accel_ipsec_sa *hw_sa) +{ + struct xfrm_state *x = sa_entry->x; + struct aead_geniv_ctx *geniv_ctx; + unsigned int crypto_data_len; + struct crypto_aead *aead; + unsigned int key_len; + int ivsize; + + memset(hw_sa, 0, sizeof(*hw_sa)); + + if (op == MLX5_IPSEC_CMD_ADD_SA) { + crypto_data_len = (x->aead->alg_key_len + 7) / 8; + key_len = crypto_data_len - 4; /* 4 bytes salt at end */ + aead = x->data; + geniv_ctx = crypto_aead_ctx(aead); + ivsize = crypto_aead_ivsize(aead); + + memcpy(&hw_sa->key_enc, x->aead->alg_key, key_len); + /* Duplicate 128 bit key twice according to HW layout */ + if (key_len == 16) + memcpy(&hw_sa->key_enc[16], x->aead->alg_key, key_len); + memcpy(&hw_sa->gcm.salt_iv, geniv_ctx->salt, ivsize); + hw_sa->gcm.salt = *((__be32 *)(x->aead->alg_key + key_len)); + } + + hw_sa->cmd = htonl(op); + hw_sa->flags |= MLX5_IPSEC_SADB_SA_VALID | MLX5_IPSEC_SADB_SPI_EN; + if (x->props.family == AF_INET) { + hw_sa->sip[3] = x->props.saddr.a4; + hw_sa->dip[3] = x->id.daddr.a4; + hw_sa->sip_masklen = 32; + hw_sa->dip_masklen = 32; + } else { + memcpy(hw_sa->sip, x->props.saddr.a6, sizeof(hw_sa->sip)); + memcpy(hw_sa->dip, x->id.daddr.a6, sizeof(hw_sa->dip)); + hw_sa->sip_masklen = 128; + hw_sa->dip_masklen = 128; + hw_sa->flags |= MLX5_IPSEC_SADB_IPV6; + } + hw_sa->spi = x->id.spi; + hw_sa->sw_sa_handle = htonl(sa_entry->handle); + switch (x->id.proto) { + case IPPROTO_ESP: + hw_sa->flags |= MLX5_IPSEC_SADB_IP_ESP; + break; + case IPPROTO_AH: + hw_sa->flags |= MLX5_IPSEC_SADB_IP_AH; + break; + default: + break; + } + hw_sa->enc_mode = mlx5e_ipsec_enc_mode(x); + if (!(x->xso.flags & XFRM_OFFLOAD_INBOUND)) + hw_sa->flags |= MLX5_IPSEC_SADB_DIR_SX; +} + +static inline int mlx5e_xfrm_validate_state(struct xfrm_state *x) +{ + struct net_device *netdev = x->xso.dev; + struct mlx5e_priv *priv; + + priv = netdev_priv(netdev); + + if (x->props.aalgo != SADB_AALG_NONE) { + netdev_info(netdev, "Cannot offload authenticated xfrm states\n"); + return -EINVAL; + } + if (x->props.ealgo != SADB_X_EALG_AES_GCM_ICV16) { + netdev_info(netdev, "Only AES-GCM-ICV16 xfrm state may be offloaded\n"); + return -EINVAL; + } + if (x->props.calgo != SADB_X_CALG_NONE) { + netdev_info(netdev, "Cannot offload compressed xfrm states\n"); + return -EINVAL; + } + if (x->props.flags & XFRM_STATE_ESN) { + netdev_info(netdev, "Cannot offload ESN xfrm states\n"); + return -EINVAL; + } + if (x->props.family != AF_INET && + x->props.family != AF_INET6) { + netdev_info(netdev, "Only IPv4/6 xfrm states may be offloaded\n"); + return -EINVAL; + } + if (x->props.mode != XFRM_MODE_TRANSPORT && + x->props.mode != XFRM_MODE_TUNNEL) { + dev_info(&netdev->dev, "Only transport and tunnel xfrm states may be offloaded\n"); + return -EINVAL; + } + if (x->id.proto != IPPROTO_ESP) { + netdev_info(netdev, "Only ESP xfrm state may be offloaded\n"); + return -EINVAL; + } + if (x->encap) { + netdev_info(netdev, "Encapsulated xfrm state may not be offloaded\n"); + return -EINVAL; + } + if (!x->aead) { + netdev_info(netdev, "Cannot offload xfrm states without aead\n"); + return -EINVAL; + } + if (x->aead->alg_icv_len != 128) { + netdev_info(netdev, "Cannot offload xfrm states with AEAD ICV length other than 128bit\n"); + return -EINVAL; + } + if ((x->aead->alg_key_len != 128 + 32) && + (x->aead->alg_key_len != 256 + 32)) { + netdev_info(netdev, "Cannot offload xfrm states with AEAD key length other than 128/256 bit\n"); + return -EINVAL; + } + if (x->tfcpad) { + netdev_info(netdev, "Cannot offload xfrm states with tfc padding\n"); + return -EINVAL; + } + if (!x->geniv) { + netdev_info(netdev, "Cannot offload xfrm states without geniv\n"); + return -EINVAL; + } + if (strcmp(x->geniv, "seqiv")) { + netdev_info(netdev, "Cannot offload xfrm states with geniv other than seqiv\n"); + return -EINVAL; + } + if (x->props.family == AF_INET6 && + !(mlx5_accel_ipsec_device_caps(priv->mdev) & MLX5_ACCEL_IPSEC_IPV6)) { + netdev_info(netdev, "IPv6 xfrm state offload is not supported by this device\n"); + return -EINVAL; + } + return 0; +} + +static int mlx5e_xfrm_add_state(struct xfrm_state *x) +{ + struct mlx5e_ipsec_sa_entry *sa_entry = NULL; + struct net_device *netdev = x->xso.dev; + struct mlx5_accel_ipsec_sa hw_sa; + struct mlx5e_priv *priv; + void *context; + int err; + + priv = netdev_priv(netdev); + + err = mlx5e_xfrm_validate_state(x); + if (err) + return err; + + sa_entry = kzalloc(sizeof(*sa_entry), GFP_KERNEL); + if (!sa_entry) { + err = -ENOMEM; + goto out; + } + + sa_entry->x = x; + sa_entry->ipsec = priv->ipsec; + + /* Add the SA to handle processed incoming packets before the add SA + * completion was received + */ + if (x->xso.flags & XFRM_OFFLOAD_INBOUND) { + err = mlx5e_ipsec_sadb_rx_add(sa_entry); + if (err) { + netdev_info(netdev, "Failed adding to SADB_RX: %d\n", err); + goto err_entry; + } + } + + mlx5e_ipsec_build_hw_sa(MLX5_IPSEC_CMD_ADD_SA, sa_entry, &hw_sa); + context = mlx5_accel_ipsec_sa_cmd_exec(sa_entry->ipsec->en_priv->mdev, &hw_sa); + if (IS_ERR(context)) { + err = PTR_ERR(context); + goto err_sadb_rx; + } + + err = mlx5_accel_ipsec_sa_cmd_wait(context); + if (err) + goto err_sadb_rx; + + x->xso.offload_handle = (unsigned long)sa_entry; + goto out; + +err_sadb_rx: + if (x->xso.flags & XFRM_OFFLOAD_INBOUND) { + mlx5e_ipsec_sadb_rx_del(sa_entry); + mlx5e_ipsec_sadb_rx_free(sa_entry); + } +err_entry: + kfree(sa_entry); +out: + return err; +} + +static void mlx5e_xfrm_del_state(struct xfrm_state *x) +{ + struct mlx5e_ipsec_sa_entry *sa_entry; + struct mlx5_accel_ipsec_sa hw_sa; + void *context; + + if (!x->xso.offload_handle) + return; + + sa_entry = (struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle; + WARN_ON(sa_entry->x != x); + + if (x->xso.flags & XFRM_OFFLOAD_INBOUND) + mlx5e_ipsec_sadb_rx_del(sa_entry); + + mlx5e_ipsec_build_hw_sa(MLX5_IPSEC_CMD_DEL_SA, sa_entry, &hw_sa); + context = mlx5_accel_ipsec_sa_cmd_exec(sa_entry->ipsec->en_priv->mdev, &hw_sa); + if (IS_ERR(context)) + return; + + sa_entry->context = context; +} + +static void mlx5e_xfrm_free_state(struct xfrm_state *x) +{ + struct mlx5e_ipsec_sa_entry *sa_entry; + int res; + + if (!x->xso.offload_handle) + return; + + sa_entry = (struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle; + WARN_ON(sa_entry->x != x); + + res = mlx5_accel_ipsec_sa_cmd_wait(sa_entry->context); + sa_entry->context = NULL; + if (res) { + /* Leftover object will leak */ + return; + } + + if (x->xso.flags & XFRM_OFFLOAD_INBOUND) + mlx5e_ipsec_sadb_rx_free(sa_entry); + + kfree(sa_entry); +} + +int mlx5e_ipsec_init(struct mlx5e_priv *priv) +{ + struct mlx5e_ipsec *ipsec = NULL; + + if (!MLX5_IPSEC_DEV(priv->mdev)) { + netdev_dbg(priv->netdev, "Not an IPSec offload device\n"); + return 0; + } + + ipsec = kzalloc(sizeof(*ipsec), GFP_KERNEL); + if (!ipsec) + return -ENOMEM; + + hash_init(ipsec->sadb_rx); + spin_lock_init(&ipsec->sadb_rx_lock); + ida_init(&ipsec->halloc); + ipsec->en_priv = priv; + ipsec->en_priv->ipsec = ipsec; + netdev_dbg(priv->netdev, "IPSec attached to netdevice\n"); + return 0; +} + +void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv) +{ + struct mlx5e_ipsec *ipsec = priv->ipsec; + + if (!ipsec) + return; + + ida_destroy(&ipsec->halloc); + kfree(ipsec); + priv->ipsec = NULL; +} + +static const struct xfrmdev_ops mlx5e_ipsec_xfrmdev_ops = { + .xdo_dev_state_add = mlx5e_xfrm_add_state, + .xdo_dev_state_delete = mlx5e_xfrm_del_state, + .xdo_dev_state_free = mlx5e_xfrm_free_state, +}; + +void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv) +{ + struct mlx5_core_dev *mdev = priv->mdev; + struct net_device *netdev = priv->netdev; + + if (!priv->ipsec) + return; + + if (!(mlx5_accel_ipsec_device_caps(mdev) & MLX5_ACCEL_IPSEC_ESP) || + !MLX5_CAP_ETH(mdev, swp)) { + mlx5_core_dbg(mdev, "mlx5e: ESP and SWP offload not supported\n"); + return; + } + + mlx5_core_info(mdev, "mlx5e: IPSec ESP acceleration enabled\n"); + netdev->xfrmdev_ops = &mlx5e_ipsec_xfrmdev_ops; + netdev->features |= NETIF_F_HW_ESP; + netdev->hw_enc_features |= NETIF_F_HW_ESP; + + if (!MLX5_CAP_ETH(mdev, swp_csum)) { + mlx5_core_dbg(mdev, "mlx5e: SWP checksum not supported\n"); + return; + } + + netdev->features |= NETIF_F_HW_ESP_TX_CSUM; + netdev->hw_enc_features |= NETIF_F_HW_ESP_TX_CSUM; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h new file mode 100644 index 000000000000..b9423a2873e2 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef __MLX5E_IPSEC_H__ +#define __MLX5E_IPSEC_H__ + +#ifdef CONFIG_MLX5_EN_IPSEC + +#include +#include +#include + +#define MLX5E_IPSEC_SADB_RX_BITS 10 + +struct mlx5e_priv; + +struct mlx5e_ipsec { + struct mlx5e_priv *en_priv; + DECLARE_HASHTABLE(sadb_rx, MLX5E_IPSEC_SADB_RX_BITS); + spinlock_t sadb_rx_lock; /* Protects sadb_rx and halloc */ + struct ida halloc; +}; + +int mlx5e_ipsec_init(struct mlx5e_priv *priv); +void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv); +void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv); + +struct xfrm_state *mlx5e_ipsec_sadb_rx_lookup(struct mlx5e_ipsec *dev, + unsigned int handle); + +#else + +static inline int mlx5e_ipsec_init(struct mlx5e_priv *priv) +{ + return 0; +} + +static inline void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv) +{ +} + +static inline void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv) +{ +} + +#endif + +#endif /* __MLX5E_IPSEC_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 9f99f624004f..aa5a7aa59ff3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -39,6 +39,7 @@ #include "en.h" #include "en_tc.h" #include "en_rep.h" +#include "en_accel/ipsec.h" #include "vxlan.h" struct mlx5e_rq_param { @@ -3555,6 +3556,12 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog) goto unlock; } + if ((netdev->features & NETIF_F_HW_ESP) && prog) { + netdev_warn(netdev, "can't set XDP with IPSec offload\n"); + err = -EINVAL; + goto unlock; + } + was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); /* no need for full reset when exchanging programs */ reset = (!priv->channels.params.xdp_prog || !prog); @@ -4046,6 +4053,8 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev) if (MLX5_CAP_GEN(mdev, vport_group_manager)) netdev->switchdev_ops = &mlx5e_switchdev_ops; #endif + + mlx5e_ipsec_build_netdev(priv); } static void mlx5e_create_q_counter(struct mlx5e_priv *priv) @@ -4074,14 +4083,19 @@ static void mlx5e_nic_init(struct mlx5_core_dev *mdev, void *ppriv) { struct mlx5e_priv *priv = netdev_priv(netdev); + int err; mlx5e_build_nic_netdev_priv(mdev, netdev, profile, ppriv); + err = mlx5e_ipsec_init(priv); + if (err) + mlx5_core_err(mdev, "IPSec initialization failed, %d\n", err); mlx5e_build_nic_netdev(netdev); mlx5e_vxlan_init(priv); } static void mlx5e_nic_cleanup(struct mlx5e_priv *priv) { + mlx5e_ipsec_cleanup(priv); mlx5e_vxlan_cleanup(priv); if (priv->channels.params.xdp_prog) -- cgit v1.2.3 From 899a59d301bc0ccd312dd23d58899cfbbc94bead Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Mon, 19 Jun 2017 14:04:36 +0300 Subject: net/mlx5e: IPSec, Add Innova IPSec offload RX data path In RX data path, the hardware prepends a special metadata ethertype which indicates that the packet underwent decryption, and the result of the authentication check. Communicate this to the stack in skb->sp. Make wqe_size large enough to account for the injected metadata. Support only Linked-list RQ type. IPSec offload RX packets may have useful CHECKSUM_COMPLETE information, which the stack may not be able to use yet. Signed-off-by: Ilan Tayari Signed-off-by: Yossi Kuperman Signed-off-by: Yevgeny Kliteynik Signed-off-by: Boris Pismenny Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 +- .../ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 19 +++ .../ethernet/mellanox/mlx5/core/en_accel/ipsec.h | 9 ++ .../mellanox/mlx5/core/en_accel/ipsec_rxtx.c | 135 +++++++++++++++++++++ .../mellanox/mlx5/core/en_accel/ipsec_rxtx.h | 44 +++++++ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 22 +++- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 41 +++++++ 7 files changed, 269 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 7e81084a75ea..23cb8ba91e6f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -20,4 +20,4 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o -mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o +mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index 06d9d6ad93ad..bb69660893ee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -40,6 +40,7 @@ #include "en.h" #include "accel/ipsec.h" #include "en_accel/ipsec.h" +#include "en_accel/ipsec_rxtx.h" struct mlx5e_ipsec_sa_entry { struct hlist_node hlist; /* Item in SADB_RX hashtable */ @@ -49,6 +50,24 @@ struct mlx5e_ipsec_sa_entry { void *context; }; +struct xfrm_state *mlx5e_ipsec_sadb_rx_lookup(struct mlx5e_ipsec *ipsec, + unsigned int handle) +{ + struct mlx5e_ipsec_sa_entry *sa_entry; + struct xfrm_state *ret = NULL; + + rcu_read_lock(); + hash_for_each_possible_rcu(ipsec->sadb_rx, sa_entry, hlist, handle) + if (sa_entry->handle == handle) { + ret = sa_entry->x; + xfrm_state_hold(ret); + break; + } + rcu_read_unlock(); + + return ret; +} + static int mlx5e_ipsec_sadb_rx_add(struct mlx5e_ipsec_sa_entry *sa_entry) { struct mlx5e_ipsec *ipsec = sa_entry->ipsec; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h index b9423a2873e2..4d745d3dd4b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h @@ -41,14 +41,23 @@ #include #define MLX5E_IPSEC_SADB_RX_BITS 10 +#define MLX5E_METADATA_ETHER_TYPE (0x8CE4) +#define MLX5E_METADATA_ETHER_LEN 8 struct mlx5e_priv; +struct mlx5e_ipsec_sw_stats { + atomic64_t ipsec_rx_drop_sp_alloc; + atomic64_t ipsec_rx_drop_sadb_miss; + atomic64_t ipsec_rx_drop_syndrome; +}; + struct mlx5e_ipsec { struct mlx5e_priv *en_priv; DECLARE_HASHTABLE(sadb_rx, MLX5E_IPSEC_SADB_RX_BITS); spinlock_t sadb_rx_lock; /* Protects sadb_rx and halloc */ struct ida halloc; + struct mlx5e_ipsec_sw_stats sw_stats; }; int mlx5e_ipsec_init(struct mlx5e_priv *priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c new file mode 100644 index 000000000000..56ab2e80553e --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include + +#include "en_accel/ipsec_rxtx.h" +#include "en_accel/ipsec.h" +#include "en.h" + +enum { + MLX5E_IPSEC_RX_SYNDROME_DECRYPTED = 0x11, + MLX5E_IPSEC_RX_SYNDROME_AUTH_FAILED = 0x12, +}; + +struct mlx5e_ipsec_rx_metadata { + unsigned char reserved; + __be32 sa_handle; +} __packed; + +struct mlx5e_ipsec_metadata { + unsigned char syndrome; + union { + unsigned char raw[5]; + /* from FPGA to host, on successful decrypt */ + struct mlx5e_ipsec_rx_metadata rx; + } __packed content; + /* packet type ID field */ + __be16 ethertype; +} __packed; + +static inline struct xfrm_state * +mlx5e_ipsec_build_sp(struct net_device *netdev, struct sk_buff *skb, + struct mlx5e_ipsec_metadata *mdata) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct xfrm_offload *xo; + struct xfrm_state *xs; + u32 sa_handle; + + skb->sp = secpath_dup(skb->sp); + if (unlikely(!skb->sp)) { + atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_sp_alloc); + return NULL; + } + + sa_handle = be32_to_cpu(mdata->content.rx.sa_handle); + xs = mlx5e_ipsec_sadb_rx_lookup(priv->ipsec, sa_handle); + if (unlikely(!xs)) { + atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_sadb_miss); + return NULL; + } + + skb->sp->xvec[skb->sp->len++] = xs; + skb->sp->olen++; + + xo = xfrm_offload(skb); + xo->flags = CRYPTO_DONE; + switch (mdata->syndrome) { + case MLX5E_IPSEC_RX_SYNDROME_DECRYPTED: + xo->status = CRYPTO_SUCCESS; + break; + case MLX5E_IPSEC_RX_SYNDROME_AUTH_FAILED: + xo->status = CRYPTO_TUNNEL_ESP_AUTH_FAILED; + break; + default: + atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_syndrome); + return NULL; + } + return xs; +} + +struct sk_buff *mlx5e_ipsec_handle_rx_skb(struct net_device *netdev, + struct sk_buff *skb) +{ + struct mlx5e_ipsec_metadata *mdata; + struct ethhdr *old_eth; + struct ethhdr *new_eth; + struct xfrm_state *xs; + __be16 *ethtype; + + /* Detect inline metadata */ + if (skb->len < ETH_HLEN + MLX5E_METADATA_ETHER_LEN) + return skb; + ethtype = (__be16 *)(skb->data + ETH_ALEN * 2); + if (*ethtype != cpu_to_be16(MLX5E_METADATA_ETHER_TYPE)) + return skb; + + /* Use the metadata */ + mdata = (struct mlx5e_ipsec_metadata *)(skb->data + ETH_HLEN); + xs = mlx5e_ipsec_build_sp(netdev, skb, mdata); + if (unlikely(!xs)) { + kfree_skb(skb); + return NULL; + } + + /* Remove the metadata from the buffer */ + old_eth = (struct ethhdr *)skb->data; + new_eth = (struct ethhdr *)(skb->data + MLX5E_METADATA_ETHER_LEN); + memmove(new_eth, old_eth, 2 * ETH_ALEN); + /* Ethertype is already in its new place */ + skb_pull_inline(skb, MLX5E_METADATA_ETHER_LEN); + + return skb; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h new file mode 100644 index 000000000000..4e2fab8c5d74 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef __MLX5E_IPSEC_RXTX_H__ +#define __MLX5E_IPSEC_RXTX_H__ + +#include +#include "en.h" + +struct sk_buff *mlx5e_ipsec_handle_rx_skb(struct net_device *netdev, + struct sk_buff *skb); +void mlx5e_ipsec_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); + +#endif /* __MLX5E_IPSEC_RXTX_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index aa5a7aa59ff3..170a9378d1f7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -40,6 +40,8 @@ #include "en_tc.h" #include "en_rep.h" #include "en_accel/ipsec.h" +#include "en_accel/ipsec_rxtx.h" +#include "accel/ipsec.h" #include "vxlan.h" struct mlx5e_rq_param { @@ -116,7 +118,7 @@ void mlx5e_set_rq_type_params(struct mlx5_core_dev *mdev, static void mlx5e_set_rq_params(struct mlx5_core_dev *mdev, struct mlx5e_params *params) { u8 rq_type = mlx5e_check_fragmented_striding_rq_cap(mdev) && - !params->xdp_prog ? + !params->xdp_prog && !MLX5_IPSEC_DEV(mdev) ? MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ : MLX5_WQ_TYPE_LINKED_LIST; mlx5e_set_rq_type_params(mdev, params, rq_type); @@ -593,6 +595,13 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, rq->dealloc_wqe = mlx5e_dealloc_rx_mpwqe; rq->handle_rx_cqe = c->priv->profile->rx_handlers.handle_rx_cqe_mpwqe; +#ifdef CONFIG_MLX5_EN_IPSEC + if (MLX5_IPSEC_DEV(mdev)) { + err = -EINVAL; + netdev_err(c->netdev, "MPWQE RQ with IPSec offload not supported\n"); + goto err_rq_wq_destroy; + } +#endif if (!rq->handle_rx_cqe) { err = -EINVAL; netdev_err(c->netdev, "RX handler of MPWQE RQ is not set, err %d\n", err); @@ -625,7 +634,12 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, rq->alloc_wqe = mlx5e_alloc_rx_wqe; rq->dealloc_wqe = mlx5e_dealloc_rx_wqe; - rq->handle_rx_cqe = c->priv->profile->rx_handlers.handle_rx_cqe; +#ifdef CONFIG_MLX5_EN_IPSEC + if (c->priv->ipsec) + rq->handle_rx_cqe = mlx5e_ipsec_handle_rx_cqe; + else +#endif + rq->handle_rx_cqe = c->priv->profile->rx_handlers.handle_rx_cqe; if (!rq->handle_rx_cqe) { kfree(rq->wqe.frag_info); err = -EINVAL; @@ -636,6 +650,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, rq->buff.wqe_sz = params->lro_en ? params->lro_wqe_sz : MLX5E_SW2HW_MTU(c->priv, c->netdev->mtu); +#ifdef CONFIG_MLX5_EN_IPSEC + if (MLX5_IPSEC_DEV(mdev)) + rq->buff.wqe_sz += MLX5E_METADATA_ETHER_LEN; +#endif rq->wqe.page_reuse = !params->xdp_prog && !params->lro_en; byte_count = rq->buff.wqe_sz; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 574a96279340..325b2c8c1c6d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -41,6 +41,7 @@ #include "eswitch.h" #include "en_rep.h" #include "ipoib/ipoib.h" +#include "en_accel/ipsec_rxtx.h" static inline bool mlx5e_rx_hw_stamp(struct mlx5e_tstamp *tstamp) { @@ -1183,3 +1184,43 @@ wq_free_wqe: } #endif /* CONFIG_MLX5_CORE_IPOIB */ + +#ifdef CONFIG_MLX5_EN_IPSEC + +void mlx5e_ipsec_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) +{ + struct mlx5e_wqe_frag_info *wi; + struct mlx5e_rx_wqe *wqe; + __be16 wqe_counter_be; + struct sk_buff *skb; + u16 wqe_counter; + u32 cqe_bcnt; + + wqe_counter_be = cqe->wqe_counter; + wqe_counter = be16_to_cpu(wqe_counter_be); + wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter); + wi = &rq->wqe.frag_info[wqe_counter]; + cqe_bcnt = be32_to_cpu(cqe->byte_cnt); + + skb = skb_from_cqe(rq, cqe, wi, cqe_bcnt); + if (unlikely(!skb)) { + /* a DROP, save the page-reuse checks */ + mlx5e_free_rx_wqe(rq, wi); + goto wq_ll_pop; + } + skb = mlx5e_ipsec_handle_rx_skb(rq->netdev, skb); + if (unlikely(!skb)) { + mlx5e_free_rx_wqe(rq, wi); + goto wq_ll_pop; + } + + mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb); + napi_gro_receive(rq->cq.napi, skb); + + mlx5e_free_rx_wqe_reuse(rq, wi); +wq_ll_pop: + mlx5_wq_ll_pop(&rq->wq, wqe_counter_be, + &wqe->next.next_wqe_index); +} + +#endif /* CONFIG_MLX5_EN_IPSEC */ -- cgit v1.2.3 From 2ac9cfe78223bb88be8cff3b59e0e13551b4e29c Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Tue, 18 Apr 2017 16:08:23 +0300 Subject: net/mlx5e: IPSec, Add Innova IPSec offload TX data path In the TX data path, prepend a special metadata ethertype which instructs the hardware to perform cryptography. In addition, fill Software-Parser segment in TX descriptor so that the hardware may parse the ESP protocol, and perform TX checksum offload on the inner payload. Support GSO, by providing the inverse of gso_size in the metadata. This allows the FPGA to update the ESP header (seqno and seqiv) on the resulting packets, by calculating the packet number within the GSO back from the TCP sequence number. Note that for GSO SKBs, the stack does not include an ESP trailer, unlike the non-GSO case. Signed-off-by: Ilan Tayari Signed-off-by: Yossi Kuperman Signed-off-by: Yevgeny Kliteynik Signed-off-by: Boris Pismenny Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 + .../ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 27 +++ .../ethernet/mellanox/mlx5/core/en_accel/ipsec.h | 10 + .../mellanox/mlx5/core/en_accel/ipsec_rxtx.c | 243 +++++++++++++++++++++ .../mellanox/mlx5/core/en_accel/ipsec_rxtx.h | 13 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 9 + drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 25 ++- 7 files changed, 319 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 535ffd78a34e..e1b7ddfecd01 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -328,6 +328,7 @@ struct mlx5e_sq_dma { enum { MLX5E_SQ_STATE_ENABLED, + MLX5E_SQ_STATE_IPSEC, }; struct mlx5e_sq_wqe_info { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index bb69660893ee..bac5103efad3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -399,10 +399,26 @@ void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv) priv->ipsec = NULL; } +static bool mlx5e_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *x) +{ + if (x->props.family == AF_INET) { + /* Offload with IPv4 options is not supported yet */ + if (ip_hdr(skb)->ihl > 5) + return false; + } else { + /* Offload with IPv6 extension headers is not support yet */ + if (ipv6_ext_hdr(ipv6_hdr(skb)->nexthdr)) + return false; + } + + return true; +} + static const struct xfrmdev_ops mlx5e_ipsec_xfrmdev_ops = { .xdo_dev_state_add = mlx5e_xfrm_add_state, .xdo_dev_state_delete = mlx5e_xfrm_del_state, .xdo_dev_state_free = mlx5e_xfrm_free_state, + .xdo_dev_offload_ok = mlx5e_ipsec_offload_ok, }; void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv) @@ -431,4 +447,15 @@ void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv) netdev->features |= NETIF_F_HW_ESP_TX_CSUM; netdev->hw_enc_features |= NETIF_F_HW_ESP_TX_CSUM; + + if (!(mlx5_accel_ipsec_device_caps(mdev) & MLX5_ACCEL_IPSEC_LSO) || + !MLX5_CAP_ETH(mdev, swp_lso)) { + mlx5_core_dbg(mdev, "mlx5e: ESP LSO not supported\n"); + return; + } + + mlx5_core_dbg(mdev, "mlx5e: ESP GSO capability turned on\n"); + netdev->features |= NETIF_F_GSO_ESP; + netdev->hw_features |= NETIF_F_GSO_ESP; + netdev->hw_enc_features |= NETIF_F_GSO_ESP; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h index 4d745d3dd4b1..ffc90b3c6ac7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h @@ -50,6 +50,11 @@ struct mlx5e_ipsec_sw_stats { atomic64_t ipsec_rx_drop_sp_alloc; atomic64_t ipsec_rx_drop_sadb_miss; atomic64_t ipsec_rx_drop_syndrome; + atomic64_t ipsec_tx_drop_bundle; + atomic64_t ipsec_tx_drop_no_state; + atomic64_t ipsec_tx_drop_not_ip; + atomic64_t ipsec_tx_drop_trailer; + atomic64_t ipsec_tx_drop_metadata; }; struct mlx5e_ipsec { @@ -60,6 +65,7 @@ struct mlx5e_ipsec { struct mlx5e_ipsec_sw_stats sw_stats; }; +void mlx5e_ipsec_build_inverse_table(void); int mlx5e_ipsec_init(struct mlx5e_priv *priv); void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv); void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv); @@ -69,6 +75,10 @@ struct xfrm_state *mlx5e_ipsec_sadb_rx_lookup(struct mlx5e_ipsec *dev, #else +static inline void mlx5e_ipsec_build_inverse_table(void) +{ +} + static inline int mlx5e_ipsec_init(struct mlx5e_priv *priv) { return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c index 56ab2e80553e..4a78aefdf157 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c @@ -33,6 +33,7 @@ #include #include +#include #include "en_accel/ipsec_rxtx.h" #include "en_accel/ipsec.h" @@ -48,17 +49,228 @@ struct mlx5e_ipsec_rx_metadata { __be32 sa_handle; } __packed; +enum { + MLX5E_IPSEC_TX_SYNDROME_OFFLOAD = 0x8, + MLX5E_IPSEC_TX_SYNDROME_OFFLOAD_WITH_LSO_TCP = 0x9, +}; + +struct mlx5e_ipsec_tx_metadata { + __be16 mss_inv; /* 1/MSS in 16bit fixed point, only for LSO */ + __be16 seq; /* LSBs of the first TCP seq, only for LSO */ + u8 esp_next_proto; /* Next protocol of ESP */ +} __packed; + struct mlx5e_ipsec_metadata { unsigned char syndrome; union { unsigned char raw[5]; /* from FPGA to host, on successful decrypt */ struct mlx5e_ipsec_rx_metadata rx; + /* from host to FPGA */ + struct mlx5e_ipsec_tx_metadata tx; } __packed content; /* packet type ID field */ __be16 ethertype; } __packed; +#define MAX_LSO_MSS 2048 + +/* Pre-calculated (Q0.16) fixed-point inverse 1/x function */ +static __be16 mlx5e_ipsec_inverse_table[MAX_LSO_MSS]; + +static inline __be16 mlx5e_ipsec_mss_inv(struct sk_buff *skb) +{ + return mlx5e_ipsec_inverse_table[skb_shinfo(skb)->gso_size]; +} + +static struct mlx5e_ipsec_metadata *mlx5e_ipsec_add_metadata(struct sk_buff *skb) +{ + struct mlx5e_ipsec_metadata *mdata; + struct ethhdr *eth; + + if (unlikely(skb_cow_head(skb, sizeof(*mdata)))) + return ERR_PTR(-ENOMEM); + + eth = (struct ethhdr *)skb_push(skb, sizeof(*mdata)); + skb->mac_header -= sizeof(*mdata); + mdata = (struct mlx5e_ipsec_metadata *)(eth + 1); + + memmove(skb->data, skb->data + sizeof(*mdata), + 2 * ETH_ALEN); + + eth->h_proto = cpu_to_be16(MLX5E_METADATA_ETHER_TYPE); + + memset(mdata->content.raw, 0, sizeof(mdata->content.raw)); + return mdata; +} + +static int mlx5e_ipsec_remove_trailer(struct sk_buff *skb, struct xfrm_state *x) +{ + unsigned int alen = crypto_aead_authsize(x->data); + struct ipv6hdr *ipv6hdr = ipv6_hdr(skb); + struct iphdr *ipv4hdr = ip_hdr(skb); + unsigned int trailer_len; + u8 plen; + int ret; + + ret = skb_copy_bits(skb, skb->len - alen - 2, &plen, 1); + if (unlikely(ret)) + return ret; + + trailer_len = alen + plen + 2; + + pskb_trim(skb, skb->len - trailer_len); + if (skb->protocol == htons(ETH_P_IP)) { + ipv4hdr->tot_len = htons(ntohs(ipv4hdr->tot_len) - trailer_len); + ip_send_check(ipv4hdr); + } else { + ipv6hdr->payload_len = htons(ntohs(ipv6hdr->payload_len) - + trailer_len); + } + return 0; +} + +static void mlx5e_ipsec_set_swp(struct sk_buff *skb, + struct mlx5_wqe_eth_seg *eseg, u8 mode, + struct xfrm_offload *xo) +{ + u8 proto; + + /* Tunnel Mode: + * SWP: OutL3 InL3 InL4 + * Pkt: MAC IP ESP IP L4 + * + * Transport Mode: + * SWP: OutL3 InL4 + * InL3 + * Pkt: MAC IP ESP L4 + * + * Offsets are in 2-byte words, counting from start of frame + */ + eseg->swp_outer_l3_offset = skb_network_offset(skb) / 2; + if (skb->protocol == htons(ETH_P_IPV6)) + eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L3_IPV6; + + if (mode == XFRM_MODE_TUNNEL) { + eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2; + if (xo->proto == IPPROTO_IPV6) { + eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6; + proto = inner_ipv6_hdr(skb)->nexthdr; + } else { + proto = inner_ip_hdr(skb)->protocol; + } + } else { + eseg->swp_inner_l3_offset = skb_network_offset(skb) / 2; + if (skb->protocol == htons(ETH_P_IPV6)) + eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6; + proto = xo->proto; + } + switch (proto) { + case IPPROTO_UDP: + eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP; + /* Fall through */ + case IPPROTO_TCP: + eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2; + break; + } +} + +static void mlx5e_ipsec_set_iv(struct sk_buff *skb, struct xfrm_offload *xo) +{ + int iv_offset; + __be64 seqno; + + /* Place the SN in the IV field */ + seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32)); + iv_offset = skb_transport_offset(skb) + sizeof(struct ip_esp_hdr); + skb_store_bits(skb, iv_offset, &seqno, 8); +} + +static void mlx5e_ipsec_set_metadata(struct sk_buff *skb, + struct mlx5e_ipsec_metadata *mdata, + struct xfrm_offload *xo) +{ + struct ip_esp_hdr *esph; + struct tcphdr *tcph; + + if (skb_is_gso(skb)) { + /* Add LSO metadata indication */ + esph = ip_esp_hdr(skb); + tcph = inner_tcp_hdr(skb); + netdev_dbg(skb->dev, " Offloading GSO packet outer L3 %u; L4 %u; Inner L3 %u; L4 %u\n", + skb->network_header, + skb->transport_header, + skb->inner_network_header, + skb->inner_transport_header); + netdev_dbg(skb->dev, " Offloading GSO packet of len %u; mss %u; TCP sp %u dp %u seq 0x%x ESP seq 0x%x\n", + skb->len, skb_shinfo(skb)->gso_size, + ntohs(tcph->source), ntohs(tcph->dest), + ntohl(tcph->seq), ntohl(esph->seq_no)); + mdata->syndrome = MLX5E_IPSEC_TX_SYNDROME_OFFLOAD_WITH_LSO_TCP; + mdata->content.tx.mss_inv = mlx5e_ipsec_mss_inv(skb); + mdata->content.tx.seq = htons(ntohl(tcph->seq) & 0xFFFF); + } else { + mdata->syndrome = MLX5E_IPSEC_TX_SYNDROME_OFFLOAD; + } + mdata->content.tx.esp_next_proto = xo->proto; + + netdev_dbg(skb->dev, " TX metadata syndrome %u proto %u mss_inv %04x seq %04x\n", + mdata->syndrome, mdata->content.tx.esp_next_proto, + ntohs(mdata->content.tx.mss_inv), + ntohs(mdata->content.tx.seq)); +} + +struct sk_buff *mlx5e_ipsec_handle_tx_skb(struct net_device *netdev, + struct mlx5e_tx_wqe *wqe, + struct sk_buff *skb) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct xfrm_offload *xo = xfrm_offload(skb); + struct mlx5e_ipsec_metadata *mdata; + struct xfrm_state *x; + + if (!xo) + return skb; + + if (unlikely(skb->sp->len != 1)) { + atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_bundle); + goto drop; + } + + x = xfrm_input_state(skb); + if (unlikely(!x)) { + atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_no_state); + goto drop; + } + + if (unlikely(!x->xso.offload_handle || + (skb->protocol != htons(ETH_P_IP) && + skb->protocol != htons(ETH_P_IPV6)))) { + atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_not_ip); + goto drop; + } + + if (!skb_is_gso(skb)) + if (unlikely(mlx5e_ipsec_remove_trailer(skb, x))) { + atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_trailer); + goto drop; + } + mdata = mlx5e_ipsec_add_metadata(skb); + if (unlikely(IS_ERR(mdata))) { + atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_metadata); + goto drop; + } + mlx5e_ipsec_set_swp(skb, &wqe->eth, x->props.mode, xo); + mlx5e_ipsec_set_iv(skb, xo); + mlx5e_ipsec_set_metadata(skb, mdata, xo); + + return skb; + +drop: + kfree_skb(skb); + return NULL; +} + static inline struct xfrm_state * mlx5e_ipsec_build_sp(struct net_device *netdev, struct sk_buff *skb, struct mlx5e_ipsec_metadata *mdata) @@ -133,3 +345,34 @@ struct sk_buff *mlx5e_ipsec_handle_rx_skb(struct net_device *netdev, return skb; } + +bool mlx5e_ipsec_feature_check(struct sk_buff *skb, struct net_device *netdev, + netdev_features_t features) +{ + struct xfrm_state *x; + + if (skb->sp && skb->sp->len) { + x = skb->sp->xvec[0]; + if (x && x->xso.offload_handle) + return true; + } + return false; +} + +void mlx5e_ipsec_build_inverse_table(void) +{ + u16 mss_inv; + u32 mss; + + /* Calculate 1/x inverse table for use in GSO data path. + * Using this table, we provide the IPSec accelerator with the value of + * 1/gso_size so that it can infer the position of each segment inside + * the GSO, and increment the ESP sequence number, and generate the IV. + * The HW needs this value in Q0.16 fixed-point number format + */ + mlx5e_ipsec_inverse_table[1] = htons(0xFFFF); + for (mss = 2; mss < MAX_LSO_MSS; mss++) { + mss_inv = ((1ULL << 32) / mss) >> 16; + mlx5e_ipsec_inverse_table[mss] = htons(mss_inv); + } +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h index 4e2fab8c5d74..e37ae2598dbb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h @@ -34,6 +34,8 @@ #ifndef __MLX5E_IPSEC_RXTX_H__ #define __MLX5E_IPSEC_RXTX_H__ +#ifdef CONFIG_MLX5_EN_IPSEC + #include #include "en.h" @@ -41,4 +43,13 @@ struct sk_buff *mlx5e_ipsec_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb); void mlx5e_ipsec_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); -#endif /* __MLX5E_IPSEC_RXTX_H__ */ +void mlx5e_ipsec_inverse_table_init(void); +bool mlx5e_ipsec_feature_check(struct sk_buff *skb, struct net_device *netdev, + netdev_features_t features); +struct sk_buff *mlx5e_ipsec_handle_tx_skb(struct net_device *netdev, + struct mlx5e_tx_wqe *wqe, + struct sk_buff *skb); + +#endif /* CONFIG_MLX5_EN_IPSEC */ + +#endif /* __MLX5E_IPSEC_RXTX_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 170a9378d1f7..a037bd7edb46 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1114,6 +1114,8 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c, sq->uar_map = mdev->mlx5e_res.bfreg.map; sq->max_inline = params->tx_max_inline; sq->min_inline_mode = params->tx_min_inline_mode; + if (MLX5_IPSEC_DEV(c->priv->mdev)) + set_bit(MLX5E_SQ_STATE_IPSEC, &sq->state); param->wq.db_numa_node = cpu_to_node(c->cpu); err = mlx5_wq_cyc_create(mdev, ¶m->wq, sqc_wq, &sq->wq, &sq->wq_ctrl); @@ -1933,6 +1935,7 @@ static void mlx5e_build_sq_param(struct mlx5e_priv *priv, mlx5e_build_sq_param_common(priv, param); MLX5_SET(wq, wq, log_wq_sz, params->log_sq_size); + MLX5_SET(sqc, sqc, allow_swp, !!MLX5_IPSEC_DEV(priv->mdev)); } static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv, @@ -3527,6 +3530,11 @@ static netdev_features_t mlx5e_features_check(struct sk_buff *skb, features = vlan_features_check(skb, features); features = vxlan_features_check(skb, features); +#ifdef CONFIG_MLX5_EN_IPSEC + if (mlx5e_ipsec_feature_check(skb, netdev, features)) + return features; +#endif + /* Validate if the tunneled packet is being offloaded by HW */ if (skb->encapsulation && (features & NETIF_F_CSUM_MASK || features & NETIF_F_GSO_MASK)) @@ -4505,6 +4513,7 @@ static struct mlx5_interface mlx5e_interface = { void mlx5e_init(void) { + mlx5e_ipsec_build_inverse_table(); mlx5e_build_ptys2ethtool_map(); mlx5_register_interface(&mlx5e_interface); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index ccec3b00e17c..aaa0f4ebba9a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -34,6 +34,7 @@ #include #include "en.h" #include "ipoib/ipoib.h" +#include "en_accel/ipsec_rxtx.h" #define MLX5E_SQ_NOPS_ROOM MLX5_SEND_WQE_MAX_WQEBBS #define MLX5E_SQ_STOP_ROOM (MLX5_SEND_WQE_MAX_WQEBBS +\ @@ -299,12 +300,9 @@ mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb, } } -static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb) +static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb, + struct mlx5e_tx_wqe *wqe, u16 pi) { - struct mlx5_wq_cyc *wq = &sq->wq; - - u16 pi = sq->pc & wq->sz_m1; - struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi); struct mlx5e_tx_wqe_info *wi = &sq->db.wqe_info[pi]; struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl; @@ -319,8 +317,6 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb) u16 ds_cnt; u16 ihs; - memset(wqe, 0, sizeof(*wqe)); - mlx5e_txwqe_build_eseg_csum(sq, skb, eseg); if (skb_is_gso(skb)) { @@ -375,8 +371,21 @@ netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev) { struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5e_txqsq *sq = priv->txq2sq[skb_get_queue_mapping(skb)]; + struct mlx5_wq_cyc *wq = &sq->wq; + u16 pi = sq->pc & wq->sz_m1; + struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi); + + memset(wqe, 0, sizeof(*wqe)); + +#ifdef CONFIG_MLX5_EN_IPSEC + if (sq->state & BIT(MLX5E_SQ_STATE_IPSEC)) { + skb = mlx5e_ipsec_handle_tx_skb(dev, wqe, skb); + if (unlikely(!skb)) + return NETDEV_TX_OK; + } +#endif - return mlx5e_sq_xmit(sq, skb); + return mlx5e_sq_xmit(sq, skb, wqe, pi); } bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) -- cgit v1.2.3 From 164f16f7021406795729916e100c7edd53ae954f Mon Sep 17 00:00:00 2001 From: Ilan Tayari Date: Thu, 22 Jun 2017 12:01:17 +0300 Subject: net/mlx5e: IPSec, Add IPSec ethtool stats Add Innova IPSec SBU counters to the ethtool -S stats. Add IPSec offload error counters to the ethtool -S stats. Signed-off-by: Ilan Tayari Reviewed-by: Boris Pismenny Reviewed-by: Gal Pressman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 3 +- .../ethernet/mellanox/mlx5/core/en_accel/ipsec.h | 43 +++++++ .../mellanox/mlx5/core/en_accel/ipsec_stats.c | 133 +++++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 10 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 +- 5 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_stats.c (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 23cb8ba91e6f..ca367445f864 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -20,4 +20,5 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o -mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o +mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \ + en_accel/ipsec_stats.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h index ffc90b3c6ac7..56e00baf16cc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h @@ -57,12 +57,30 @@ struct mlx5e_ipsec_sw_stats { atomic64_t ipsec_tx_drop_metadata; }; +struct mlx5e_ipsec_stats { + u64 ipsec_dec_in_packets; + u64 ipsec_dec_out_packets; + u64 ipsec_dec_bypass_packets; + u64 ipsec_enc_in_packets; + u64 ipsec_enc_out_packets; + u64 ipsec_enc_bypass_packets; + u64 ipsec_dec_drop_packets; + u64 ipsec_dec_auth_fail_packets; + u64 ipsec_enc_drop_packets; + u64 ipsec_add_sa_success; + u64 ipsec_add_sa_fail; + u64 ipsec_del_sa_success; + u64 ipsec_del_sa_fail; + u64 ipsec_cmd_drop; +}; + struct mlx5e_ipsec { struct mlx5e_priv *en_priv; DECLARE_HASHTABLE(sadb_rx, MLX5E_IPSEC_SADB_RX_BITS); spinlock_t sadb_rx_lock; /* Protects sadb_rx and halloc */ struct ida halloc; struct mlx5e_ipsec_sw_stats sw_stats; + struct mlx5e_ipsec_stats stats; }; void mlx5e_ipsec_build_inverse_table(void); @@ -70,6 +88,11 @@ int mlx5e_ipsec_init(struct mlx5e_priv *priv); void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv); void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv); +int mlx5e_ipsec_get_count(struct mlx5e_priv *priv); +int mlx5e_ipsec_get_strings(struct mlx5e_priv *priv, uint8_t *data); +void mlx5e_ipsec_update_stats(struct mlx5e_priv *priv); +int mlx5e_ipsec_get_stats(struct mlx5e_priv *priv, u64 *data); + struct xfrm_state *mlx5e_ipsec_sadb_rx_lookup(struct mlx5e_ipsec *dev, unsigned int handle); @@ -92,6 +115,26 @@ static inline void mlx5e_ipsec_build_netdev(struct mlx5e_priv *priv) { } +static inline int mlx5e_ipsec_get_count(struct mlx5e_priv *priv) +{ + return 0; +} + +static inline int mlx5e_ipsec_get_strings(struct mlx5e_priv *priv, + uint8_t *data) +{ + return 0; +} + +static inline void mlx5e_ipsec_update_stats(struct mlx5e_priv *priv) +{ +} + +static inline int mlx5e_ipsec_get_stats(struct mlx5e_priv *priv, u64 *data) +{ + return 0; +} + #endif #endif /* __MLX5E_IPSEC_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_stats.c new file mode 100644 index 000000000000..6fea59223dc4 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_stats.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include + +#include "en.h" +#include "accel/ipsec.h" +#include "fpga/sdk.h" +#include "en_accel/ipsec.h" + +static const struct counter_desc mlx5e_ipsec_hw_stats_desc[] = { + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_dec_in_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_dec_out_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_dec_bypass_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_enc_in_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_enc_out_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_enc_bypass_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_dec_drop_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_dec_auth_fail_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_enc_drop_packets) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_add_sa_success) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_add_sa_fail) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_del_sa_success) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_del_sa_fail) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_stats, ipsec_cmd_drop) }, +}; + +static const struct counter_desc mlx5e_ipsec_sw_stats_desc[] = { + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_rx_drop_sp_alloc) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_rx_drop_sadb_miss) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_rx_drop_syndrome) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_tx_drop_bundle) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_tx_drop_no_state) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_tx_drop_not_ip) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_tx_drop_trailer) }, + { MLX5E_DECLARE_STAT(struct mlx5e_ipsec_sw_stats, ipsec_tx_drop_metadata) }, +}; + +#define MLX5E_READ_CTR_ATOMIC64(ptr, dsc, i) \ + atomic64_read((atomic64_t *)((char *)(ptr) + (dsc)[i].offset)) + +#define NUM_IPSEC_HW_COUNTERS ARRAY_SIZE(mlx5e_ipsec_hw_stats_desc) +#define NUM_IPSEC_SW_COUNTERS ARRAY_SIZE(mlx5e_ipsec_sw_stats_desc) + +#define NUM_IPSEC_COUNTERS (NUM_IPSEC_HW_COUNTERS + NUM_IPSEC_SW_COUNTERS) + +int mlx5e_ipsec_get_count(struct mlx5e_priv *priv) +{ + if (!priv->ipsec) + return 0; + + return NUM_IPSEC_COUNTERS; +} + +int mlx5e_ipsec_get_strings(struct mlx5e_priv *priv, uint8_t *data) +{ + unsigned int i, idx = 0; + + if (!priv->ipsec) + return 0; + + for (i = 0; i < NUM_IPSEC_HW_COUNTERS; i++) + strcpy(data + (idx++) * ETH_GSTRING_LEN, + mlx5e_ipsec_hw_stats_desc[i].format); + + for (i = 0; i < NUM_IPSEC_SW_COUNTERS; i++) + strcpy(data + (idx++) * ETH_GSTRING_LEN, + mlx5e_ipsec_sw_stats_desc[i].format); + + return NUM_IPSEC_COUNTERS; +} + +void mlx5e_ipsec_update_stats(struct mlx5e_priv *priv) +{ + int ret; + + if (!priv->ipsec) + return; + + ret = mlx5_accel_ipsec_counters_read(priv->mdev, (u64 *)&priv->ipsec->stats, + NUM_IPSEC_HW_COUNTERS); + if (ret) + memset(&priv->ipsec->stats, 0, sizeof(priv->ipsec->stats)); +} + +int mlx5e_ipsec_get_stats(struct mlx5e_priv *priv, u64 *data) +{ + int i, idx = 0; + + if (!priv->ipsec) + return 0; + + for (i = 0; i < NUM_IPSEC_HW_COUNTERS; i++) + data[idx++] = MLX5E_READ_CTR64_CPU(&priv->ipsec->stats, + mlx5e_ipsec_hw_stats_desc, i); + + for (i = 0; i < NUM_IPSEC_SW_COUNTERS; i++) + data[idx++] = MLX5E_READ_CTR_ATOMIC64(&priv->ipsec->sw_stats, + mlx5e_ipsec_sw_stats_desc, i); + + return NUM_IPSEC_COUNTERS; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 16b1e96a7050..917fade5f5d5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -31,6 +31,7 @@ */ #include "en.h" +#include "en_accel/ipsec.h" void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv, struct ethtool_drvinfo *drvinfo) @@ -186,7 +187,8 @@ int mlx5e_ethtool_get_sset_count(struct mlx5e_priv *priv, int sset) MLX5E_NUM_SQ_STATS(priv) + MLX5E_NUM_PFC_COUNTERS(priv) + ARRAY_SIZE(mlx5e_pme_status_desc) + - ARRAY_SIZE(mlx5e_pme_error_desc); + ARRAY_SIZE(mlx5e_pme_error_desc) + + mlx5e_ipsec_get_count(priv); case ETH_SS_PRIV_FLAGS: return ARRAY_SIZE(mlx5e_priv_flags); @@ -275,6 +277,9 @@ static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, uint8_t *data) for (i = 0; i < ARRAY_SIZE(mlx5e_pme_error_desc); i++) strcpy(data + (idx++) * ETH_GSTRING_LEN, mlx5e_pme_error_desc[i].format); + /* IPSec counters */ + idx += mlx5e_ipsec_get_strings(priv, data + idx * ETH_GSTRING_LEN); + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) return; @@ -403,6 +408,9 @@ void mlx5e_ethtool_get_ethtool_stats(struct mlx5e_priv *priv, data[idx++] = MLX5E_READ_CTR64_CPU(mlx5_priv->pme_stats.error_counters, mlx5e_pme_error_desc, i); + /* IPSec counters */ + idx += mlx5e_ipsec_get_stats(priv, data + idx); + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) return; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index a037bd7edb46..a09b11f467a4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -331,8 +331,10 @@ static void mlx5e_update_pcie_counters(struct mlx5e_priv *priv) void mlx5e_update_stats(struct mlx5e_priv *priv, bool full) { - if (full) + if (full) { mlx5e_update_pcie_counters(priv); + mlx5e_ipsec_update_stats(priv); + } mlx5e_update_pport_counters(priv, full); mlx5e_update_vport_counters(priv); mlx5e_update_q_counter(priv); -- cgit v1.2.3 From dca2307ed6250e7be6993e165570fa4097903a58 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Sat, 24 Jun 2017 22:08:27 +0100 Subject: brcmfmac: fix double free upon register_netdevice() failure The function brcmf_net_attach() can only fail when register_netdevice() fails. When this happens register_netdevice() calls priv_destructor, ie. brcmf_cfg80211_free_netdev() freeing the vif instance. Also upon this failure brcmf_net_attach() calls free_netdev(). However, callers are also doing cleanup resulting in double free. In some places they need netdev private space as it holds parameters to communicate with the device. So we want to do the cleanup only in callers of brcmf_net_attach() by making the following changes: - set priv_destructor after register_netdevice() succeeds. - remove call to free_netdev() in brcmf_net_attach(). - call free_netdev() in brcmf_net_detach() for unregistered netdev. - add free_netdev() if brcmf_net_attach() fails for a created interface. Fixes: cf124db566e6 ("net: Fix inconsistent teardown and release of private netdev state.") Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 1 + drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 5 ++--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 2443c71a202f..63e7683a80dd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -625,6 +625,7 @@ struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name, err = brcmf_net_attach(ifp, true); if (err) { brcmf_err("Registering netdevice failed\n"); + free_netdev(ifp->ndev); goto fail; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index c60b897e479a..b4c86434ad80 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -485,13 +485,13 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) goto fail; } + ndev->priv_destructor = brcmf_cfg80211_free_netdev; brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); return 0; fail: drvr->iflist[ifp->bsscfgidx] = NULL; ndev->netdev_ops = NULL; - free_netdev(ndev); return -EBADE; } @@ -504,6 +504,7 @@ static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked) unregister_netdev(ndev); } else { brcmf_cfg80211_free_netdev(ndev); + free_netdev(ndev); } } @@ -580,7 +581,6 @@ static int brcmf_net_p2p_attach(struct brcmf_if *ifp) fail: ifp->drvr->iflist[ifp->bsscfgidx] = NULL; ndev->netdev_ops = NULL; - free_netdev(ndev); return -EBADE; } @@ -626,7 +626,6 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, return ERR_PTR(-ENOMEM); ndev->needs_free_netdev = true; - ndev->priv_destructor = brcmf_cfg80211_free_netdev; ifp = netdev_priv(ndev); ifp->ndev = ndev; /* store mapping ifidx to bsscfgidx */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index aa299c47bfa2..2ce675ab40ef 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2208,6 +2208,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, err = brcmf_net_attach(ifp, true); if (err) { brcmf_err("Registering netdevice failed\n"); + free_netdev(ifp->ndev); goto fail; } -- cgit v1.2.3 From 57c00f2fac512837f8de73474ec1f54020015bae Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Wed, 21 Jun 2017 07:45:53 +0200 Subject: brcmfmac: Fix a memory leak in error handling path in 'brcmf_cfg80211_attach' If 'wiphy_new()' fails, we leak 'ops'. Add a new label in the error handling path to free it in such a case. Cc: stable@vger.kernel.org Fixes: 5c22fb85102a7 ("brcmfmac: add wowl gtk rekeying offload support") Signed-off-by: Christophe JAILLET Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 63e7683a80dd..898c7b024c15 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6862,7 +6862,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info)); if (!wiphy) { brcmf_err("Could not allocate wiphy device\n"); - return NULL; + goto ops_out; } memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN); set_wiphy_dev(wiphy, busdev); @@ -7013,6 +7013,7 @@ priv_out: ifp->vif = NULL; wiphy_out: brcmf_free_wiphy(wiphy); +ops_out: kfree(ops); return NULL; } -- cgit v1.2.3 From cdd24a200a8fa39e383890bbf862c0aa83ba83f5 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 27 Jun 2017 19:15:07 +0200 Subject: Bluetooth: hci_bcm: Fix unwanted error reporting if no bcm dev The hci_bcm proto is able to operate without bcm platform device linked to its uart port. In that case, firmware can be applied, but there is no power operation (no gpio/irq resources mgmt). However, the current implementation breaks this use case because of reporting a ENODEV error in the bcm setup procedure if bcm_request_irq fails (which is the case if no bcm device linked). Fix this by removing bcm_request_irq error forwarding. Signed-off-by: Loic Poulain Reported-by: Ian Molton Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_bcm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index d2e9e2d1b014..192ad2781733 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -419,8 +419,7 @@ finalize: if (err) return err; - err = bcm_request_irq(bcm); - if (!err) + if (!bcm_request_irq(bcm)) err = bcm_setup_sleep(hu); return err; -- cgit v1.2.3 From 019b13ae85260cfab9d7ccb6ca58f094d18a24fd Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 27 Jun 2017 14:42:43 +0200 Subject: vxlan: fix incorrect nlattr access in MTU check The access to the wrong variable could lead to a NULL dereference and possibly other invalid memory reads in vxlan newlink/changelink requests with a IFLA_MTU attribute. Fixes: a985343ba906 "vxlan: refactor verification and application of configuration" Signed-off-by: Matthias Schiffer Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 0dafd8e6c665..fd0ff97e3d81 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2727,7 +2727,7 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[], } if (tb[IFLA_MTU]) { - u32 mtu = nla_get_u32(data[IFLA_MTU]); + u32 mtu = nla_get_u32(tb[IFLA_MTU]); if (mtu < ETH_MIN_MTU || mtu > ETH_MAX_MTU) return -EINVAL; -- cgit v1.2.3 From d557ee6bdc6dc4df2ab8e00c2127120b4acbdfca Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:15 -0700 Subject: nfp: explicitly check if application FW is loaded We support application FW being either loaded automatically at boot from flash or (more commonly) by the driver from disk. If FW is not found on disk and nothing is preloaded users are faced with this unintuitive error: nfp 0000:04:00.0: nfp: Failed to find PF symbol _pf0_net_bar0 We can do better. Since we rely on symbol table being present - check early if it could be correctly read out of from the device and if not print a more informative message. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index cfcbc3b9a9aa..3169400dd474 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -589,10 +589,7 @@ static int nfp_net_pci_map_mem(struct nfp_pf *pf) ctrl_bar_sz, &pf->data_vnic_bar); if (IS_ERR(mem)) { nfp_err(pf->cpp, "Failed to find data vNIC memory symbol\n"); - err = PTR_ERR(mem); - if (!pf->fw_loaded && err == -ENOENT) - err = -EPROBE_DEFER; - return err; + return PTR_ERR(mem); } pf->mac_stats_mem = nfp_net_pf_map_rtsym(pf, "net.macstats", @@ -786,6 +783,12 @@ int nfp_net_pci_probe(struct nfp_pf *pf) return -EINVAL; } + if (!pf->rtbl) { + nfp_err(pf->cpp, "No %s, giving up.\n", + pf->fw_loaded ? "symbol table" : "firmware found"); + return -EPROBE_DEFER; + } + mutex_lock(&pf->lock); pf->max_data_vnics = nfp_net_pf_get_num_ports(pf); if ((int)pf->max_data_vnics < 0) { -- cgit v1.2.3 From 064dc3196ebd2587ad9a4ca2d26629a20f819352 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:16 -0700 Subject: nfp: move area mapping helper into nfpcore nfp_net_map_area() is a helper for mapping areas of NFP memory defined in nfp_net_main.c. Move it to nfpcore to allow reuse and rename accordingly. Create an additional helper - nfp_cpp_area_alloc_acquire() the opposite of already existing nfp_cpp_area_release_free(). Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 56 +--------------------- .../net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 7 +++ .../ethernet/netronome/nfp/nfpcore/nfp_cppcore.c | 35 ++++++++++++++ .../ethernet/netronome/nfp/nfpcore/nfp_cpplib.c | 40 ++++++++++++++++ 4 files changed, 84 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 3169400dd474..16ee904db0cd 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -80,58 +80,6 @@ static int nfp_is_ready(struct nfp_pf *pf) return state == 15; } -/** - * nfp_net_map_area() - Help function to map an area - * @cpp: NFP CPP handler - * @name: Name for the area - * @target: CPP target - * @addr: CPP address - * @size: Size of the area - * @area: Area handle (returned). - * - * This function is primarily to simplify the code in the main probe - * function. To undo the effect of this functions call - * @nfp_cpp_area_release_free(*area); - * - * Return: Pointer to memory mapped area or ERR_PTR - */ -static u8 __iomem *nfp_net_map_area(struct nfp_cpp *cpp, - const char *name, int isl, int target, - unsigned long long addr, unsigned long size, - struct nfp_cpp_area **area) -{ - u8 __iomem *res; - u32 dest; - int err; - - dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, isl); - - *area = nfp_cpp_area_alloc_with_name(cpp, dest, name, addr, size); - if (!*area) { - err = -EIO; - goto err_area; - } - - err = nfp_cpp_area_acquire(*area); - if (err < 0) - goto err_acquire; - - res = nfp_cpp_area_iomem(*area); - if (!res) { - err = -EIO; - goto err_map; - } - - return res; - -err_map: - nfp_cpp_area_release(*area); -err_acquire: - nfp_cpp_area_free(*area); -err_area: - return (u8 __iomem *)ERR_PTR(err); -} - /** * nfp_net_get_mac_addr() - Get the MAC address. * @pf: NFP PF handle @@ -242,7 +190,7 @@ nfp_net_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt, return (u8 __iomem *)ERR_PTR(-EINVAL); } - mem = nfp_net_map_area(pf->cpp, name, sym->domain, sym->target, + mem = nfp_cpp_map_area(pf->cpp, name, sym->domain, sym->target, sym->addr, sym->size, area); if (IS_ERR(mem)) { nfp_err(pf->cpp, "Failed to map PF symbol %s: %ld\n", @@ -617,7 +565,7 @@ static int nfp_net_pci_map_mem(struct nfp_pf *pf) pf->vf_cfg_mem = NULL; } - mem = nfp_net_map_area(pf->cpp, "net.qc", 0, 0, + mem = nfp_cpp_map_area(pf->cpp, "net.qc", 0, 0, NFP_PCIE_QUEUE(0), NFP_QCP_QUEUE_AREA_SZ, &pf->qc_area); if (IS_ERR(mem)) { diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index 25a967158ce9..235dd023d9b9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -230,6 +230,9 @@ struct nfp_cpp_area *nfp_cpp_area_alloc_with_name(struct nfp_cpp *cpp, struct nfp_cpp_area *nfp_cpp_area_alloc(struct nfp_cpp *cpp, u32 cpp_id, unsigned long long address, unsigned long size); +struct nfp_cpp_area * +nfp_cpp_area_alloc_acquire(struct nfp_cpp *cpp, const char *name, u32 cpp_id, + unsigned long long address, unsigned long size); void nfp_cpp_area_free(struct nfp_cpp_area *area); int nfp_cpp_area_acquire(struct nfp_cpp_area *area); int nfp_cpp_area_acquire_nonblocking(struct nfp_cpp_area *area); @@ -278,6 +281,10 @@ int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id, int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id, unsigned long long address, u64 value); +u8 __iomem * +nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target, + u64 addr, unsigned long size, struct nfp_cpp_area **area); + struct nfp_cpp_mutex; int nfp_cpp_mutex_init(struct nfp_cpp *cpp, int target, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c index 9b69dcf87be9..7d5d7293efed 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c @@ -360,6 +360,41 @@ nfp_cpp_area_alloc(struct nfp_cpp *cpp, u32 dest, return nfp_cpp_area_alloc_with_name(cpp, dest, NULL, address, size); } +/** + * nfp_cpp_area_alloc_acquire() - allocate a new CPP area and lock it down + * @cpp: CPP handle + * @name: Name of region + * @dest: CPP id + * @address: Start address on CPP target + * @size: Size of area + * + * Allocate and initialize a CPP area structure, and lock it down so + * that it can be accessed directly. + * + * NOTE: @address and @size must be 32-bit aligned values. + * + * NOTE: The area must also be 'released' when the structure is freed. + * + * Return: NFP CPP Area handle, or NULL + */ +struct nfp_cpp_area * +nfp_cpp_area_alloc_acquire(struct nfp_cpp *cpp, const char *name, u32 dest, + unsigned long long address, unsigned long size) +{ + struct nfp_cpp_area *area; + + area = nfp_cpp_area_alloc_with_name(cpp, dest, name, address, size); + if (!area) + return NULL; + + if (nfp_cpp_area_acquire(area)) { + nfp_cpp_area_free(area); + return NULL; + } + + return area; +} + /** * nfp_cpp_area_free() - free up the CPP area * @area: CPP area handle diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c index 0ba0379b8f75..ab86bceb93f2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c @@ -279,3 +279,43 @@ exit_release: return err; } + +/** + * nfp_cpp_map_area() - Helper function to map an area + * @cpp: NFP CPP handler + * @name: Name for the area + * @domain: CPP domain + * @target: CPP target + * @addr: CPP address + * @size: Size of the area + * @area: Area handle (output) + * + * Map an area of IOMEM access. To undo the effect of this function call + * @nfp_cpp_area_release_free(*area). + * + * Return: Pointer to memory mapped area or ERR_PTR + */ +u8 __iomem * +nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target, + u64 addr, unsigned long size, struct nfp_cpp_area **area) +{ + u8 __iomem *res; + u32 dest; + + dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, domain); + + *area = nfp_cpp_area_alloc_acquire(cpp, name, dest, addr, size); + if (!*area) + goto err_eio; + + res = nfp_cpp_area_iomem(*area); + if (!res) + goto err_release_free; + + return res; + +err_release_free: + nfp_cpp_area_release_free(*area); +err_eio: + return (u8 __iomem *)ERR_PTR(-EIO); +} -- cgit v1.2.3 From f84730240735b15f725ce59d66a663de82650b46 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:17 -0700 Subject: nfp: add helper for mapping runtime symbols Move most of the helper for mapping RTsyms from nfp_net_main.c to nfpcore. Use the new helper directly for mapping MAC statistics, since they don't need to include the PCIe interface ID in the symbol name. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 36 +++++----------------- .../net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h | 4 +++ .../net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c | 27 ++++++++++++++++ 3 files changed, 39 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 16ee904db0cd..93d6ea183956 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -174,31 +174,12 @@ static u8 __iomem * nfp_net_pf_map_rtsym(struct nfp_pf *pf, const char *name, const char *sym_fmt, unsigned int min_size, struct nfp_cpp_area **area) { - const struct nfp_rtsym *sym; char pf_symbol[256]; - u8 __iomem *mem; snprintf(pf_symbol, sizeof(pf_symbol), sym_fmt, nfp_cppcore_pcie_unit(pf->cpp)); - sym = nfp_rtsym_lookup(pf->rtbl, pf_symbol); - if (!sym) - return (u8 __iomem *)ERR_PTR(-ENOENT); - - if (sym->size < min_size) { - nfp_err(pf->cpp, "PF symbol %s too small\n", pf_symbol); - return (u8 __iomem *)ERR_PTR(-EINVAL); - } - - mem = nfp_cpp_map_area(pf->cpp, name, sym->domain, sym->target, - sym->addr, sym->size, area); - if (IS_ERR(mem)) { - nfp_err(pf->cpp, "Failed to map PF symbol %s: %ld\n", - pf_symbol, PTR_ERR(mem)); - return mem; - } - - return mem; + return nfp_rtsym_map(pf->rtbl, pf_symbol, name, min_size, area); } static void nfp_net_pf_free_vnic(struct nfp_pf *pf, struct nfp_net *nn) @@ -528,23 +509,22 @@ static void nfp_net_pci_unmap_mem(struct nfp_pf *pf) static int nfp_net_pci_map_mem(struct nfp_pf *pf) { - u32 ctrl_bar_sz; u8 __iomem *mem; + u32 min_size; int err; - ctrl_bar_sz = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE; + min_size = pf->max_data_vnics * NFP_PF_CSR_SLICE_SIZE; mem = nfp_net_pf_map_rtsym(pf, "net.ctrl", "_pf%d_net_bar0", - ctrl_bar_sz, &pf->data_vnic_bar); + min_size, &pf->data_vnic_bar); if (IS_ERR(mem)) { nfp_err(pf->cpp, "Failed to find data vNIC memory symbol\n"); return PTR_ERR(mem); } - pf->mac_stats_mem = nfp_net_pf_map_rtsym(pf, "net.macstats", - "_mac_stats", - NFP_MAC_STATS_SIZE * - (pf->eth_tbl->max_index + 1), - &pf->mac_stats_bar); + min_size = NFP_MAC_STATS_SIZE * (pf->eth_tbl->max_index + 1); + pf->mac_stats_mem = nfp_rtsym_map(pf->rtbl, "_mac_stats", + "net.macstats", min_size, + &pf->mac_stats_bar); if (IS_ERR(pf->mac_stats_mem)) { if (PTR_ERR(pf->mac_stats_mem) != -ENOENT) { err = PTR_ERR(pf->mac_stats_mem); diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h index d27d29782a12..c9724fb7ea4b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.h @@ -97,7 +97,11 @@ int nfp_rtsym_count(struct nfp_rtsym_table *rtbl); const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx); const struct nfp_rtsym * nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name); + u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, int *error); +u8 __iomem * +nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id, + unsigned int min_size, struct nfp_cpp_area **area); #endif /* NFP_NFFW_H */ diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c index 203f9cbae0fb..ecda474ac7c3 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c @@ -289,3 +289,30 @@ exit: return ~0ULL; return val; } + +u8 __iomem * +nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id, + unsigned int min_size, struct nfp_cpp_area **area) +{ + const struct nfp_rtsym *sym; + u8 __iomem *mem; + + sym = nfp_rtsym_lookup(rtbl, name); + if (!sym) + return (u8 __iomem *)ERR_PTR(-ENOENT); + + if (sym->size < min_size) { + nfp_err(rtbl->cpp, "Symbol %s too small\n", name); + return (u8 __iomem *)ERR_PTR(-EINVAL); + } + + mem = nfp_cpp_map_area(rtbl->cpp, id, sym->domain, sym->target, + sym->addr, sym->size, area); + if (IS_ERR(mem)) { + nfp_err(rtbl->cpp, "Failed to map symbol %s: %ld\n", + name, PTR_ERR(mem)); + return mem; + } + + return mem; +} -- cgit v1.2.3 From 8a119cef9a84c396c7de49da2fb4b8af09e96d2b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:18 -0700 Subject: nfp: remove unused nfp_cpp_area_check_range() Remove unused nfp_cpp_area_check_range() function. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h | 2 -- .../ethernet/netronome/nfp/nfpcore/nfp_cppcore.c | 21 --------------------- 2 files changed, 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index 235dd023d9b9..5798adc57cbc 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -242,8 +242,6 @@ int nfp_cpp_area_read(struct nfp_cpp_area *area, unsigned long offset, void *buffer, size_t length); int nfp_cpp_area_write(struct nfp_cpp_area *area, unsigned long offset, const void *buffer, size_t length); -int nfp_cpp_area_check_range(struct nfp_cpp_area *area, - unsigned long long offset, unsigned long size); const char *nfp_cpp_area_name(struct nfp_cpp_area *cpp_area); void *nfp_cpp_area_priv(struct nfp_cpp_area *cpp_area); struct nfp_cpp *nfp_cpp_area_cpp(struct nfp_cpp_area *cpp_area); diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c index 7d5d7293efed..04dd5758ecf5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c @@ -570,27 +570,6 @@ int nfp_cpp_area_write(struct nfp_cpp_area *area, return area->cpp->op->area_write(area, kernel_vaddr, offset, length); } -/** - * nfp_cpp_area_check_range() - check if address range fits in CPP area - * @area: CPP area handle - * @offset: offset into CPP target - * @length: size of address range in bytes - * - * Check if address range fits within CPP area. Return 0 if area - * fits or -EFAULT on error. - * - * Return: 0, or -ERRNO - */ -int nfp_cpp_area_check_range(struct nfp_cpp_area *area, - unsigned long long offset, unsigned long length) -{ - if (offset < area->offset || - offset + length > area->offset + area->size) - return -EFAULT; - - return 0; -} - /** * nfp_cpp_area_name() - return name of a CPP area * @cpp_area: CPP area handle -- cgit v1.2.3 From 9ce6bbbb0503e58e8629ae0185e916b271237bc3 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:19 -0700 Subject: nfp: add nfp_app cleanup callback and make flower use it Add a cleanup callback for undoing what app init callback did. Make flower allocate its private structure on init and free it from the new callback. While at it remember to set the app pointer to NULL on the error path to avoid any races while probe path unwinds. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.c | 24 +++++++++++------------ drivers/net/ethernet/netronome/nfp/nfp_app.h | 10 +++++++++- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 6 +++++- 3 files changed, 26 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 8e5ca6b4bb33..54d42a7f0d75 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -296,26 +296,16 @@ static int nfp_flower_start(struct nfp_app *app) NFP_REPR_TYPE_PF, 1); } -static void nfp_flower_vnic_clean(struct nfp_app *app, struct nfp_net *nn) -{ - kfree(app->priv); - app->priv = NULL; -} - static int nfp_flower_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) { - struct nfp_flower_priv *priv; + struct nfp_flower_priv *priv = app->priv; if (id > 0) { nfp_warn(app->cpp, "FlowerNIC doesn't support more than one data vNIC\n"); goto err_invalid_port; } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - app->priv = priv; priv->nn = nn; eth_hw_addr_random(nn->dp.netdev); @@ -347,9 +337,19 @@ static int nfp_flower_init(struct nfp_app *app) return -EINVAL; } + app->priv = kzalloc(sizeof(struct nfp_flower_priv), GFP_KERNEL); + if (!app->priv) + return -ENOMEM; + return 0; } +static void nfp_flower_clean(struct nfp_app *app) +{ + kfree(app->priv); + app->priv = NULL; +} + const struct nfp_app_type app_flower = { .id = NFP_APP_FLOWER_NIC, .name = "flower", @@ -358,9 +358,9 @@ const struct nfp_app_type app_flower = { .extra_cap = nfp_flower_extra_cap, .init = nfp_flower_init, + .clean = nfp_flower_clean, .vnic_init = nfp_flower_vnic_init, - .vnic_clean = nfp_flower_vnic_clean, .start = nfp_flower_start, .stop = nfp_flower_stop, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index ae2d02753d1a..2fb503a817d2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -66,7 +66,8 @@ extern const struct nfp_app_type app_flower; * @ctrl_has_meta: control messages have prepend of type:5/port:CTRL * * Callbacks - * @init: perform basic app checks + * @init: perform basic app checks and init + * @clean: clean app state * @extra_cap: extra capabilities string * @vnic_init: init vNICs (assign port types, etc.) * @vnic_clean: clean up app's vNIC state @@ -88,6 +89,7 @@ struct nfp_app_type { bool ctrl_has_meta; int (*init)(struct nfp_app *app); + void (*clean)(struct nfp_app *app); const char *(*extra_cap)(struct nfp_app *app, struct nfp_net *nn); @@ -144,6 +146,12 @@ static inline int nfp_app_init(struct nfp_app *app) return app->type->init(app); } +static inline void nfp_app_clean(struct nfp_app *app) +{ + if (app->type->clean) + app->type->clean(app); +} + static inline int nfp_app_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 93d6ea183956..49c4910fbcc6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -414,7 +414,7 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride) if (IS_ERR(ctrl_bar)) { nfp_err(pf->cpp, "Failed to find data vNIC memory symbol\n"); err = PTR_ERR(ctrl_bar); - goto err_free; + goto err_app_clean; } pf->ctrl_vnic = nfp_net_pf_alloc_vnic(pf, false, ctrl_bar, qc_bar, @@ -428,8 +428,11 @@ nfp_net_pf_app_init(struct nfp_pf *pf, u8 __iomem *qc_bar, unsigned int stride) err_unmap: nfp_cpp_area_release_free(pf->ctrl_vnic_bar); +err_app_clean: + nfp_app_clean(pf->app); err_free: nfp_app_free(pf->app); + pf->app = NULL; return err; } @@ -439,6 +442,7 @@ static void nfp_net_pf_app_clean(struct nfp_pf *pf) nfp_net_pf_free_vnic(pf, pf->ctrl_vnic); nfp_cpp_area_release_free(pf->ctrl_vnic_bar); } + nfp_app_clean(pf->app); nfp_app_free(pf->app); pf->app = NULL; } -- cgit v1.2.3 From 38edbf6f5da4f87741e73b74dc323706827e83e0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:20 -0700 Subject: nfp: spawn nfp_ports for PF and VF ports nfp_port is an abstraction which is supposed to allow us sharing code between different netdev types (vNIC vs repr). Spawn ports for PFs and VFs to enable this sharing. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.c | 19 +++++++++++++++++-- drivers/net/ethernet/netronome/nfp/nfp_port.h | 20 ++++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 54d42a7f0d75..757bc3d78ea4 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -162,14 +162,19 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app, u8 nfp_pcie = nfp_cppcore_pcie_unit(app->pf->cpp); struct nfp_flower_priv *priv = app->priv; struct nfp_reprs *reprs, *old_reprs; + enum nfp_port_type port_type; const u8 queue = 0; int i, err; + port_type = repr_type == NFP_REPR_TYPE_PF ? NFP_PORT_PF_PORT : + NFP_PORT_VF_PORT; + reprs = nfp_reprs_alloc(cnt); if (!reprs) return -ENOMEM; for (i = 0; i < cnt; i++) { + struct nfp_port *port; u32 port_id; reprs->reprs[i] = nfp_repr_alloc(app); @@ -178,15 +183,25 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app, goto err_reprs_clean; } + port = nfp_port_alloc(app, port_type, reprs->reprs[i]); + if (repr_type == NFP_REPR_TYPE_PF) { + port->pf_id = i; + } else { + port->pf_id = 0; /* For now we only support 1 PF */ + port->vf_id = i; + } + eth_hw_addr_random(reprs->reprs[i]); port_id = nfp_flower_cmsg_pcie_port(nfp_pcie, vnic_type, i, queue); err = nfp_repr_init(app, reprs->reprs[i], &nfp_flower_repr_netdev_ops, - port_id, NULL, priv->nn->dp.netdev); - if (err) + port_id, port, priv->nn->dp.netdev); + if (err) { + nfp_port_free(port); goto err_reprs_clean; + } nfp_info(app->cpp, "%s%d Representor(%s) created\n", repr_type == NFP_REPR_TYPE_PF ? "PF" : "VF", i, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index f472bea4ec2b..57d852a4ca59 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -47,10 +47,14 @@ struct nfp_port; * state when port disappears because of FW fault or config * change * @NFP_PORT_PHYS_PORT: external NIC port + * @NFP_PORT_PF_PORT: logical port of PCI PF + * @NFP_PORT_VF_PORT: logical port of PCI VF */ enum nfp_port_type { NFP_PORT_INVALID, NFP_PORT_PHYS_PORT, + NFP_PORT_PF_PORT, + NFP_PORT_VF_PORT, }; /** @@ -72,6 +76,8 @@ enum nfp_port_flags { * @dl_port: devlink port structure * @eth_id: for %NFP_PORT_PHYS_PORT port ID in NFP enumeration scheme * @eth_port: for %NFP_PORT_PHYS_PORT translated ETH Table port entry + * @pf_id: for %NFP_PORT_PF_PORT, %NFP_PORT_VF_PORT ID of the PCI PF (0-3) + * @vf_id: for %NFP_PORT_VF_PORT ID of the PCI VF within @pf_id * @port_list: entry on pf's list of ports */ struct nfp_port { @@ -84,8 +90,18 @@ struct nfp_port { struct devlink_port dl_port; - unsigned int eth_id; - struct nfp_eth_table_port *eth_port; + union { + /* NFP_PORT_PHYS_PORT */ + struct { + unsigned int eth_id; + struct nfp_eth_table_port *eth_port; + }; + /* NFP_PORT_PF_PORT, NFP_PORT_VF_PORT */ + struct { + unsigned int pf_id; + unsigned int vf_id; + }; + }; struct list_head port_list; }; -- cgit v1.2.3 From 3238b250b7624a20756667032648263eb3dc1521 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:21 -0700 Subject: nfp: make the representor get stats app-independent Thanks to the fact that all representors will now have an nfp_port, we can depend on information there to provide a app-independent .ndo_get_stats64(). Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.c | 16 +------------ drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 28 +++++++++++++++-------- drivers/net/ethernet/netronome/nfp/nfp_net_repr.h | 4 ++-- 3 files changed, 22 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 757bc3d78ea4..2e66d51ec104 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -104,20 +104,6 @@ nfp_flower_repr_get(struct nfp_app *app, u32 port_id) return reprs->reprs[port]; } -static void -nfp_flower_repr_netdev_get_stats64(struct net_device *netdev, - struct rtnl_link_stats64 *stats) -{ - struct nfp_repr *repr = netdev_priv(netdev); - enum nfp_repr_type type; - u32 port_id; - u8 port = 0; - - port_id = repr->dst->u.port_info.port_id; - type = nfp_flower_repr_get_type_and_port(repr->app, port_id, &port); - nfp_repr_get_stats64(repr->app, type, port, stats); -} - static int nfp_flower_repr_netdev_open(struct net_device *netdev) { int err; @@ -144,7 +130,7 @@ static const struct net_device_ops nfp_flower_repr_netdev_ops = { .ndo_open = nfp_flower_repr_netdev_open, .ndo_stop = nfp_flower_repr_netdev_stop, .ndo_start_xmit = nfp_repr_xmit, - .ndo_get_stats64 = nfp_flower_repr_netdev_get_stats64, + .ndo_get_stats64 = nfp_repr_get_stats64, .ndo_has_offload_stats = nfp_repr_has_offload_stats, .ndo_get_offload_stats = nfp_repr_get_offload_stats, }; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 44adcc5df11e..6f1548c6840c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -37,6 +37,7 @@ #include #include "nfpcore/nfp_cpp.h" +#include "nfpcore/nfp_nsp.h" #include "nfp_app.h" #include "nfp_main.h" #include "nfp_net_ctrl.h" @@ -136,18 +137,27 @@ nfp_repr_pf_get_stats64(const struct nfp_app *app, u8 pf, } void -nfp_repr_get_stats64(const struct nfp_app *app, enum nfp_repr_type type, - u8 port, struct rtnl_link_stats64 *stats) +nfp_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) { - switch (type) { - case NFP_REPR_TYPE_PHYS_PORT: - nfp_repr_phy_port_get_stats64(app, port, stats); + struct nfp_repr *repr = netdev_priv(netdev); + struct nfp_eth_table_port *eth_port; + struct nfp_app *app = repr->app; + + if (WARN_ON(!repr->port)) + return; + + switch (repr->port->type) { + case NFP_PORT_PHYS_PORT: + eth_port = __nfp_port_get_eth_port(repr->port); + if (!eth_port) + break; + nfp_repr_phy_port_get_stats64(app, eth_port->index, stats); break; - case NFP_REPR_TYPE_PF: - nfp_repr_pf_get_stats64(app, port, stats); + case NFP_PORT_PF_PORT: + nfp_repr_pf_get_stats64(app, repr->port->pf_id, stats); break; - case NFP_REPR_TYPE_VF: - nfp_repr_vf_get_stats64(app, port, stats); + case NFP_PORT_VF_PORT: + nfp_repr_vf_get_stats64(app, repr->port->vf_id, stats); default: break; } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h index c5ed6611f708..e970661ecd42 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h @@ -99,8 +99,8 @@ enum nfp_repr_type { void nfp_repr_inc_rx_stats(struct net_device *netdev, unsigned int len); void -nfp_repr_get_stats64(const struct nfp_app *app, enum nfp_repr_type type, - u8 port, struct rtnl_link_stats64 *stats); +nfp_repr_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats); bool nfp_repr_has_offload_stats(const struct net_device *dev, int attr_id); int nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev, void *stats); -- cgit v1.2.3 From 5d7c64a70fa15aef903469b05ca664f7cd17d769 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:22 -0700 Subject: nfp: move representors' struct net_device_ops to shared code Apps shouldn't declare their own struct net_device_ops for representors, this makes sharing code harder. Add necessary nfp_app callbacks and move the definition of representors' struct net_device_ops to common code. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 5 ++- drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 2 +- drivers/net/ethernet/netronome/nfp/flower/main.c | 32 ++++++++---------- drivers/net/ethernet/netronome/nfp/nfp_app.h | 20 ++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 40 ++++++++++++++++++----- drivers/net/ethernet/netronome/nfp/nfp_net_repr.h | 8 ----- 6 files changed, 68 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c index 7761be436726..916a6196d2ba 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c @@ -79,9 +79,8 @@ nfp_flower_cmsg_alloc(struct nfp_app *app, unsigned int size, return skb; } -int nfp_flower_cmsg_portmod(struct net_device *netdev, bool carrier_ok) +int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok) { - struct nfp_repr *repr = netdev_priv(netdev); struct nfp_flower_cmsg_portmod *msg; struct sk_buff *skb; @@ -94,7 +93,7 @@ int nfp_flower_cmsg_portmod(struct net_device *netdev, bool carrier_ok) msg->portnum = cpu_to_be32(repr->dst->u.port_info.port_id); msg->reserved = 0; msg->info = carrier_ok; - msg->mtu = cpu_to_be16(netdev->mtu); + msg->mtu = cpu_to_be16(repr->netdev->mtu); nfp_ctrl_tx(repr->app->ctrl, skb); diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index 2eeddada7f4d..c10ae7631941 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -110,7 +110,7 @@ nfp_flower_cmsg_pcie_port(u8 nfp_pcie, enum nfp_flower_cmsg_port_vnic_type type, NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT); } -int nfp_flower_cmsg_portmod(struct net_device *netdev, bool carrier_ok); +int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok); void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb); #endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 2e66d51ec104..ab68a8f58862 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -104,37 +104,30 @@ nfp_flower_repr_get(struct nfp_app *app, u32 port_id) return reprs->reprs[port]; } -static int nfp_flower_repr_netdev_open(struct net_device *netdev) +static int +nfp_flower_repr_netdev_open(struct nfp_app *app, struct nfp_repr *repr) { int err; - err = nfp_flower_cmsg_portmod(netdev, true); + err = nfp_flower_cmsg_portmod(repr, true); if (err) return err; - netif_carrier_on(netdev); - netif_tx_wake_all_queues(netdev); + netif_carrier_on(repr->netdev); + netif_tx_wake_all_queues(repr->netdev); return 0; } -static int nfp_flower_repr_netdev_stop(struct net_device *netdev) +static int +nfp_flower_repr_netdev_stop(struct nfp_app *app, struct nfp_repr *repr) { - netif_carrier_off(netdev); - netif_tx_disable(netdev); + netif_carrier_off(repr->netdev); + netif_tx_disable(repr->netdev); - return nfp_flower_cmsg_portmod(netdev, false); + return nfp_flower_cmsg_portmod(repr, false); } -static const struct net_device_ops nfp_flower_repr_netdev_ops = { - .ndo_open = nfp_flower_repr_netdev_open, - .ndo_stop = nfp_flower_repr_netdev_stop, - .ndo_start_xmit = nfp_repr_xmit, - .ndo_get_stats64 = nfp_repr_get_stats64, - .ndo_has_offload_stats = nfp_repr_has_offload_stats, - .ndo_get_offload_stats = nfp_repr_get_offload_stats, -}; - static void nfp_flower_sriov_disable(struct nfp_app *app) { nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_VF); @@ -182,7 +175,6 @@ nfp_flower_spawn_vnic_reprs(struct nfp_app *app, port_id = nfp_flower_cmsg_pcie_port(nfp_pcie, vnic_type, i, queue); err = nfp_repr_init(app, reprs->reprs[i], - &nfp_flower_repr_netdev_ops, port_id, port, priv->nn->dp.netdev); if (err) { nfp_port_free(port); @@ -261,7 +253,6 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv) cmsg_port_id = nfp_flower_cmsg_phys_port(phys_port); err = nfp_repr_init(app, reprs->reprs[phys_port], - &nfp_flower_repr_netdev_ops, cmsg_port_id, port, priv->nn->dp.netdev); if (err) { nfp_port_free(port); @@ -363,6 +354,9 @@ const struct nfp_app_type app_flower = { .vnic_init = nfp_flower_vnic_init, + .repr_open = nfp_flower_repr_netdev_open, + .repr_stop = nfp_flower_repr_netdev_stop, + .start = nfp_flower_start, .stop = nfp_flower_stop, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index 2fb503a817d2..5d714e10d9a9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h @@ -47,6 +47,7 @@ struct sk_buff; struct nfp_app; struct nfp_cpp; struct nfp_pf; +struct nfp_repr; struct nfp_net; enum nfp_app_id { @@ -71,6 +72,8 @@ extern const struct nfp_app_type app_flower; * @extra_cap: extra capabilities string * @vnic_init: init vNICs (assign port types, etc.) * @vnic_clean: clean up app's vNIC state + * @repr_open: representor netdev open callback + * @repr_stop: representor netdev stop callback * @start: start application logic * @stop: stop application logic * @ctrl_msg_rx: control message handler @@ -97,6 +100,9 @@ struct nfp_app_type { unsigned int id); void (*vnic_clean)(struct nfp_app *app, struct nfp_net *nn); + int (*repr_open)(struct nfp_app *app, struct nfp_repr *repr); + int (*repr_stop)(struct nfp_app *app, struct nfp_repr *repr); + int (*start)(struct nfp_app *app); void (*stop)(struct nfp_app *app); @@ -164,6 +170,20 @@ static inline void nfp_app_vnic_clean(struct nfp_app *app, struct nfp_net *nn) app->type->vnic_clean(app, nn); } +static inline int nfp_app_repr_open(struct nfp_app *app, struct nfp_repr *repr) +{ + if (!app->type->repr_open) + return -EINVAL; + return app->type->repr_open(app, repr); +} + +static inline int nfp_app_repr_stop(struct nfp_app *app, struct nfp_repr *repr) +{ + if (!app->type->repr_stop) + return -EINVAL; + return app->type->repr_stop(app, repr); +} + static inline int nfp_app_start(struct nfp_app *app, struct nfp_net *ctrl) { app->ctrl = ctrl; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 6f1548c6840c..44416f679fdb 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -136,7 +136,7 @@ nfp_repr_pf_get_stats64(const struct nfp_app *app, u8 pf, stats->rx_dropped = readq(mem + NFP_NET_CFG_STATS_TX_DISCARDS); } -void +static void nfp_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) { struct nfp_repr *repr = netdev_priv(netdev); @@ -163,7 +163,7 @@ nfp_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) } } -bool +static bool nfp_repr_has_offload_stats(const struct net_device *dev, int attr_id) { switch (attr_id) { @@ -206,8 +206,9 @@ nfp_repr_get_host_stats64(const struct net_device *netdev, return 0; } -int nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev, - void *stats) +static int +nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev, + void *stats) { switch (attr_id) { case IFLA_OFFLOAD_XSTATS_CPU_HIT: @@ -217,7 +218,7 @@ int nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev, return -EINVAL; } -netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev) +static netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev) { struct nfp_repr *repr = netdev_priv(netdev); unsigned int len = skb->len; @@ -234,6 +235,29 @@ netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev) return ret; } +static int nfp_repr_stop(struct net_device *netdev) +{ + struct nfp_repr *repr = netdev_priv(netdev); + + return nfp_app_repr_stop(repr->app, repr); +} + +static int nfp_repr_open(struct net_device *netdev) +{ + struct nfp_repr *repr = netdev_priv(netdev); + + return nfp_app_repr_open(repr->app, repr); +} + +static const struct net_device_ops nfp_repr_netdev_ops = { + .ndo_open = nfp_repr_open, + .ndo_stop = nfp_repr_stop, + .ndo_start_xmit = nfp_repr_xmit, + .ndo_get_stats64 = nfp_repr_get_stats64, + .ndo_has_offload_stats = nfp_repr_has_offload_stats, + .ndo_get_offload_stats = nfp_repr_get_offload_stats, +}; + static void nfp_repr_clean(struct nfp_repr *repr) { unregister_netdev(repr->netdev); @@ -258,8 +282,8 @@ static void nfp_repr_set_lockdep_class(struct net_device *dev) } int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, - const struct net_device_ops *netdev_ops, u32 cmsg_port_id, - struct nfp_port *port, struct net_device *pf_netdev) + u32 cmsg_port_id, struct nfp_port *port, + struct net_device *pf_netdev) { struct nfp_repr *repr = netdev_priv(netdev); int err; @@ -273,7 +297,7 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, repr->dst->u.port_info.port_id = cmsg_port_id; repr->dst->u.port_info.lower_dev = pf_netdev; - netdev->netdev_ops = netdev_ops; + netdev->netdev_ops = &nfp_repr_netdev_ops; err = register_netdev(netdev); if (err) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h index e970661ecd42..8f126362d5ed 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h @@ -98,15 +98,7 @@ enum nfp_repr_type { #define NFP_REPR_TYPE_MAX (__NFP_REPR_TYPE_MAX - 1) void nfp_repr_inc_rx_stats(struct net_device *netdev, unsigned int len); -void -nfp_repr_get_stats64(struct net_device *netdev, - struct rtnl_link_stats64 *stats); -bool nfp_repr_has_offload_stats(const struct net_device *dev, int attr_id); -int nfp_repr_get_offload_stats(int attr_id, const struct net_device *dev, - void *stats); -netdev_tx_t nfp_repr_xmit(struct sk_buff *skb, struct net_device *netdev); int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, - const struct net_device_ops *netdev_ops, u32 cmsg_port_id, struct nfp_port *port, struct net_device *pf_netdev); struct net_device *nfp_repr_alloc(struct nfp_app *app); -- cgit v1.2.3 From 39ae7eb69db3a3daa3aa2f6c66e37dba1975ef00 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:23 -0700 Subject: nfp: allow converting representor's netdev into nfp_port Based on struct net_device_ops figure out if netdev is a nfp_repr. Use this knowledge to convert netdev directly to nfp_port. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 2 +- drivers/net/ethernet/netronome/nfp/nfp_net_repr.h | 7 +++++++ drivers/net/ethernet/netronome/nfp/nfp_port.c | 18 +++++++++++++----- 3 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 44416f679fdb..7bfdef2af1a9 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -249,7 +249,7 @@ static int nfp_repr_open(struct net_device *netdev) return nfp_app_repr_open(repr->app, repr); } -static const struct net_device_ops nfp_repr_netdev_ops = { +const struct net_device_ops nfp_repr_netdev_ops = { .ndo_open = nfp_repr_open, .ndo_stop = nfp_repr_stop, .ndo_start_xmit = nfp_repr_xmit, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h index 8f126362d5ed..6a6727816010 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h @@ -97,6 +97,13 @@ enum nfp_repr_type { }; #define NFP_REPR_TYPE_MAX (__NFP_REPR_TYPE_MAX - 1) +extern const struct net_device_ops nfp_repr_netdev_ops; + +static inline bool nfp_netdev_is_nfp_repr(struct net_device *netdev) +{ + return netdev->netdev_ops == &nfp_repr_netdev_ops; +} + void nfp_repr_inc_rx_stats(struct net_device *netdev, unsigned int len); int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, u32 cmsg_port_id, struct nfp_port *port, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 19bceeb82225..0be6c7e0b1c1 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -42,13 +42,21 @@ struct nfp_port *nfp_port_from_netdev(struct net_device *netdev) { - struct nfp_net *nn; + if (nfp_netdev_is_nfp_net(netdev)) { + struct nfp_net *nn = netdev_priv(netdev); - if (WARN_ON(!nfp_netdev_is_nfp_net(netdev))) - return NULL; - nn = netdev_priv(netdev); + return nn->port; + } - return nn->port; + if (nfp_netdev_is_nfp_repr(netdev)) { + struct nfp_repr *repr = netdev_priv(netdev); + + return repr->port; + } + + WARN(1, "Unknown netdev type for nfp_port\n"); + + return NULL; } struct nfp_port * -- cgit v1.2.3 From 168c478e107e790456cd6ebb308529756c21de3f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:24 -0700 Subject: nfp: wire get_phys_port_name on representors Make nfp_port_get_phys_port_name() support new port types and wire it up to representors' struct net_device_ops. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 1 + drivers/net/ethernet/netronome/nfp/nfp_port.c | 30 +++++++++++++++++------ 2 files changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 7bfdef2af1a9..046b89eb4cf2 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -256,6 +256,7 @@ const struct net_device_ops nfp_repr_netdev_ops = { .ndo_get_stats64 = nfp_repr_get_stats64, .ndo_has_offload_stats = nfp_repr_has_offload_stats, .ndo_get_offload_stats = nfp_repr_get_offload_stats, + .ndo_get_phys_port_name = nfp_port_get_phys_port_name, }; static void nfp_repr_clean(struct nfp_repr *repr) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 0be6c7e0b1c1..0b44952945d8 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -106,15 +106,31 @@ nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len) int n; port = nfp_port_from_netdev(netdev); - eth_port = __nfp_port_get_eth_port(port); - if (!eth_port) + if (!port) + return -EOPNOTSUPP; + + switch (port->type) { + case NFP_PORT_PHYS_PORT: + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) + return -EOPNOTSUPP; + + if (!eth_port->is_split) + n = snprintf(name, len, "p%d", eth_port->label_port); + else + n = snprintf(name, len, "p%ds%d", eth_port->label_port, + eth_port->label_subport); + break; + case NFP_PORT_PF_PORT: + n = snprintf(name, len, "pf%d", port->pf_id); + break; + case NFP_PORT_VF_PORT: + n = snprintf(name, len, "pf%dvf%d", port->pf_id, port->vf_id); + break; + default: return -EOPNOTSUPP; + } - if (!eth_port->is_split) - n = snprintf(name, len, "p%d", eth_port->label_port); - else - n = snprintf(name, len, "p%ds%d", eth_port->label_port, - eth_port->label_subport); if (n >= len) return -EINVAL; -- cgit v1.2.3 From 0dc78621918693face1700d1379c2b9f740282f5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:25 -0700 Subject: nfp: handle SR-IOV already enabled when driver is probing We assumed that when we probe number of enabled VFs will be at 0. This doesn't have to be the case for example if previous driver left SR-IOV enabled due to some VFs being assigned. Read the number of VFs enabled. Fail probe if it's above current FWs limit. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 748e54cc885e..d47adb4c86d6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -414,6 +414,14 @@ static int nfp_pci_probe(struct pci_dev *pdev, if (err) goto err_fw_unload; + pf->num_vfs = pci_num_vf(pdev); + if (pf->num_vfs > pf->limit_vfs) { + dev_err(&pdev->dev, + "Error: %d VFs already enabled, but loaded FW can only support %d\n", + pf->num_vfs, pf->limit_vfs); + goto err_fw_unload; + } + err = nfp_net_pci_probe(pf); if (err) goto err_sriov_unlimit; -- cgit v1.2.3 From e3f28473b8ed348f7c052fa1bf79edfde5efba48 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:26 -0700 Subject: nfp: reorder SR-IOV config and nfp_app SR-IOV callbacks We previously assumed that app callback can be guaranteed to be executed before SR-IOV is actually enabled. Given that we can't guarantee that SR-IOV will be disabled during probe or that we will be able to disable it on remove, we should reorder the callbacks. We should also call the app's sriov_enable if SR-IOV was enabled during probe. Application FW must be able to disable VFs internally and not depend on them being removed at PCIe level. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 40 ++++++++++------------- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 10 ++++++ 2 files changed, 27 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index d47adb4c86d6..a0f3df8572d6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -107,17 +107,18 @@ static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs) goto err_unlock; } - err = nfp_app_sriov_enable(pf->app, num_vfs); + err = pci_enable_sriov(pdev, num_vfs); if (err) { - dev_warn(&pdev->dev, "App specific PCI sriov configuration failed: %d\n", - err); + dev_warn(&pdev->dev, "Failed to enable PCI SR-IOV: %d\n", err); goto err_unlock; } - err = pci_enable_sriov(pdev, num_vfs); + err = nfp_app_sriov_enable(pf->app, num_vfs); if (err) { - dev_warn(&pdev->dev, "Failed to enable PCI sriov: %d\n", err); - goto err_app_sriov_disable; + dev_warn(&pdev->dev, + "App specific PCI SR-IOV configuration failed: %d\n", + err); + goto err_sriov_disable; } pf->num_vfs = num_vfs; @@ -127,8 +128,8 @@ static int nfp_pcie_sriov_enable(struct pci_dev *pdev, int num_vfs) mutex_unlock(&pf->lock); return num_vfs; -err_app_sriov_disable: - nfp_app_sriov_disable(pf->app); +err_sriov_disable: + pci_disable_sriov(pdev); err_unlock: mutex_unlock(&pf->lock); return err; @@ -136,17 +137,20 @@ err_unlock: return 0; } -static int __nfp_pcie_sriov_disable(struct pci_dev *pdev) +static int nfp_pcie_sriov_disable(struct pci_dev *pdev) { #ifdef CONFIG_PCI_IOV struct nfp_pf *pf = pci_get_drvdata(pdev); + mutex_lock(&pf->lock); + /* If the VFs are assigned we cannot shut down SR-IOV without * causing issues, so just leave the hardware available but * disabled */ if (pci_vfs_assigned(pdev)) { dev_warn(&pdev->dev, "Disabling while VFs assigned - VFs will not be deallocated\n"); + mutex_unlock(&pf->lock); return -EPERM; } @@ -156,20 +160,10 @@ static int __nfp_pcie_sriov_disable(struct pci_dev *pdev) pci_disable_sriov(pdev); dev_dbg(&pdev->dev, "Removed VFs.\n"); -#endif - return 0; -} -static int nfp_pcie_sriov_disable(struct pci_dev *pdev) -{ - struct nfp_pf *pf = pci_get_drvdata(pdev); - int err; - - mutex_lock(&pf->lock); - err = __nfp_pcie_sriov_disable(pdev); mutex_unlock(&pf->lock); - - return err; +#endif + return 0; } static int nfp_pcie_sriov_configure(struct pci_dev *pdev, int num_vfs) @@ -471,11 +465,11 @@ static void nfp_pci_remove(struct pci_dev *pdev) devlink = priv_to_devlink(pf); + nfp_net_pci_remove(pf); + nfp_pcie_sriov_disable(pdev); pci_sriov_set_totalvfs(pf->pdev, 0); - nfp_net_pci_remove(pf); - devlink_unregister(devlink); kfree(pf->rtbl); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 49c4910fbcc6..4d22e1cc013e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -488,8 +488,16 @@ static int nfp_net_pf_app_start(struct nfp_pf *pf) if (err) goto err_ctrl_stop; + if (pf->num_vfs) { + err = nfp_app_sriov_enable(pf->app, pf->num_vfs); + if (err) + goto err_app_stop; + } + return 0; +err_app_stop: + nfp_app_stop(pf->app); err_ctrl_stop: nfp_net_pf_app_stop_ctrl(pf); return err; @@ -497,6 +505,8 @@ err_ctrl_stop: static void nfp_net_pf_app_stop(struct nfp_pf *pf) { + if (pf->num_vfs) + nfp_app_sriov_disable(pf->app); nfp_app_stop(pf->app); nfp_net_pf_app_stop_ctrl(pf); } -- cgit v1.2.3 From 6d48ceb27af1420882f092495fc796cfcbf92a14 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:27 -0700 Subject: nfp: allocate a private workqueue for driver work Since we grab pf->lock around pci_enable_sriov() we can no longer safely queue work which may also grab that lock onto system workqueue. pci_enable_sriov() will flush system workqueue as part to wait for VF probing. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 9 +++++++++ drivers/net/ethernet/netronome/nfp/nfp_main.h | 4 ++++ drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index a0f3df8572d6..d67969d3e484 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -376,6 +376,12 @@ static int nfp_pci_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, pf); pf->pdev = pdev; + pf->wq = alloc_workqueue("nfp-%s", 0, 2, pci_name(pdev)); + if (!pf->wq) { + err = -ENOMEM; + goto err_pci_priv_unset; + } + pf->cpp = nfp_cpp_from_nfp6000_pcie(pdev); if (IS_ERR_OR_NULL(pf->cpp)) { err = PTR_ERR(pf->cpp); @@ -445,6 +451,8 @@ err_hwinfo_free: kfree(pf->hwinfo); nfp_cpp_free(pf->cpp); err_disable_msix: + destroy_workqueue(pf->wq); +err_pci_priv_unset: pci_set_drvdata(pdev, NULL); mutex_destroy(&pf->lock); devlink_free(devlink); @@ -477,6 +485,7 @@ static void nfp_pci_remove(struct pci_dev *pdev) if (pf->fw_loaded) nfp_fw_unload(pf); + destroy_workqueue(pf->wq); pci_set_drvdata(pdev, NULL); kfree(pf->hwinfo); nfp_cpp_free(pf->cpp); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index edc14dc78674..a08cfba7e68e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -89,6 +89,7 @@ struct nfp_rtsym_table; * @num_vnics: Number of vNICs spawned * @vnics: Linked list of vNIC structures (struct nfp_net) * @ports: Linked list of port structures (struct nfp_port) + * @wq: Workqueue for running works which need to grab @lock * @port_refresh_work: Work entry for taking netdevs out * @lock: Protects all fields which may change after probe */ @@ -131,7 +132,10 @@ struct nfp_pf { struct list_head vnics; struct list_head ports; + + struct workqueue_struct *wq; struct work_struct port_refresh_work; + struct mutex lock; }; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index 4d22e1cc013e..c85a2f18c4df 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -682,7 +682,7 @@ void nfp_net_refresh_port_table(struct nfp_port *port) set_bit(NFP_PORT_CHANGED, &port->flags); - schedule_work(&pf->port_refresh_work); + queue_work(pf->wq, &pf->port_refresh_work); } int nfp_net_refresh_eth_port(struct nfp_port *port) -- cgit v1.2.3 From 57ae676ee63ec810c64aea67fc451ae0900a05f9 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 27 Jun 2017 00:50:28 -0700 Subject: nfp: flower: add Kconfig for flower app Give users an option not to build the flower-offload related code. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/Kconfig | 10 ++++++++++ drivers/net/ethernet/netronome/nfp/Makefile | 8 ++++++-- drivers/net/ethernet/netronome/nfp/nfp_app.c | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/Kconfig b/drivers/net/ethernet/netronome/Kconfig index 0d5a7b9203a4..0e331e2f685a 100644 --- a/drivers/net/ethernet/netronome/Kconfig +++ b/drivers/net/ethernet/netronome/Kconfig @@ -25,6 +25,16 @@ config NFP cards working as a advanced Ethernet NIC. It works with both SR-IOV physical and virtual functions. +config NFP_APP_FLOWER + bool "NFP4000/NFP6000 TC Flower offload support" + depends on NFP + depends on NET_SWITCHDEV + ---help--- + Enable driver support for TC Flower offload on NFP4000 and NFP6000. + Say Y, if you are planning to make use of TC Flower offload + either directly, with Open vSwitch, or any other way. Note that + TC Flower offload requires specific FW to work. + config NFP_DEBUG bool "Debug support for Netronome(R) NFP4000/NFP6000 NIC drivers" depends on NFP diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 10b556b2c59d..43bdbc228969 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -27,10 +27,14 @@ nfp-objs := \ nfp_port.o \ bpf/main.o \ bpf/offload.o \ - flower/cmsg.o \ - flower/main.o \ nic/main.o +ifeq ($(CONFIG_NFP_APP_FLOWER),y) +nfp-objs += \ + flower/cmsg.o \ + flower/main.o +endif + ifeq ($(CONFIG_BPF_SYSCALL),y) nfp-objs += \ bpf/verifier.o \ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index 5620de05c996..c704c022574f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -43,7 +43,9 @@ static const struct nfp_app_type *apps[] = { &app_nic, &app_bpf, +#ifdef CONFIG_NFP_APP_FLOWER &app_flower, +#endif }; const char *nfp_app_mip_name(struct nfp_app *app) -- cgit v1.2.3 From bd751808f9ff5e1822c627f6c4283009e66b2e53 Mon Sep 17 00:00:00 2001 From: Geoff Lansberry Date: Thu, 27 Apr 2017 17:28:46 -0400 Subject: NFC: trf7970a: Correct register settings for 27MHz clock In prior commits the selected clock frequency does not propagate correctly to what is written to the TRF7970A_MODULATOR_SYS_CLK_CTRL register. Signed-off-by: Geoff Lansberry Acked-by: Mark Greer Signed-off-by: Samuel Ortiz --- drivers/nfc/trf7970a.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 6ee7b038823d..eee5cc1a9220 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -2049,6 +2049,13 @@ static int trf7970a_probe(struct spi_device *spi) return -EINVAL; } + if (clk_freq == TRF7970A_27MHZ_CLOCK_FREQUENCY) { + trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_27MHZ; + dev_dbg(trf->dev, "trf7970a configured for 27MHz crystal\n"); + } else { + trf->modulator_sys_clk_ctrl = 0; + } + ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL, trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, -- cgit v1.2.3 From cf8ce1ea61b75712a154c93e40f2a5af2e4dd997 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Tue, 27 Jun 2017 17:31:49 +0300 Subject: ath9k: fix tx99 use after free One scenario that could lead to UAF is two threads writing simultaneously to the "tx99" debug file. One of them would set the "start" value to true and follow to ath9k_tx99_init(). Inside the function it would set the sc->tx99_state to true after allocating sc->tx99skb. Then, the other thread would execute write_file_tx99() and call ath9k_tx99_deinit(). sc->tx99_state would be freed. After that, the first thread would continue inside ath9k_tx99_init() and call r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl); that would make use of the freed sc->tx99_skb memory. Cc: Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/tx99.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index a866cbda0799..49ed1afb913c 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -189,22 +189,27 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, if (strtobool(buf, &start)) return -EINVAL; + mutex_lock(&sc->mutex); + if (start == sc->tx99_state) { if (!start) - return count; + goto out; ath_dbg(common, XMIT, "Resetting TX99\n"); ath9k_tx99_deinit(sc); } if (!start) { ath9k_tx99_deinit(sc); - return count; + goto out; } r = ath9k_tx99_init(sc); - if (r) + if (r) { + mutex_unlock(&sc->mutex); return r; - + } +out: + mutex_unlock(&sc->mutex); return count; } -- cgit v1.2.3 From bde717ab473668377fc65872398a102d40cb2d58 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Tue, 27 Jun 2017 17:31:51 +0300 Subject: ath9k: fix tx99 bus error The hard coded register 0x9864 and 0x9924 are invalid for ar9300 chips. Cc: Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index ae3043559b6d..fe5102ca5010 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1821,8 +1821,6 @@ static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah) static void ar9003_hw_tx99_start(struct ath_hw *ah, u32 qnum) { REG_SET_BIT(ah, AR_PHY_TEST, PHY_AGC_CLR); - REG_SET_BIT(ah, 0x9864, 0x7f000); - REG_SET_BIT(ah, 0x9924, 0x7f00fe); REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); REG_WRITE(ah, AR_CR, AR_CR_RXD); REG_WRITE(ah, AR_DLCL_IFS(qnum), 0); -- cgit v1.2.3 From 1cdb6c9fd43366413f928531a03fc07a8c14429a Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 27 Jun 2017 17:31:52 +0300 Subject: ath10k: add const to thermal_cooling_device_ops structure Declare thermal_cooling_device_ops structure as const as it is only passed as an argument to the function thermal_cooling_device_register and this argument is of type const. So, declare the structure as const. Signed-off-by: Bhumika Goyal Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index 87948aff1bd5..ef717b631ff8 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -63,7 +63,7 @@ ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, return 0; } -static struct thermal_cooling_device_ops ath10k_thermal_ops = { +static const struct thermal_cooling_device_ops ath10k_thermal_ops = { .get_max_state = ath10k_thermal_get_max_throttle_state, .get_cur_state = ath10k_thermal_get_cur_throttle_state, .set_cur_state = ath10k_thermal_set_cur_throttle_state, -- cgit v1.2.3 From 07246c115801c27652700e3679bb58661ef7ed65 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Tue, 27 Jun 2017 17:31:53 +0300 Subject: ath9k: fix an invalid pointer dereference in ath9k_rng_stop() The bug was triggered when do suspend/resuming continuously on Dell XPS L322X/0PJHXN version 9333 (2013) with kernel 4.12.0-041200rc4-generic. But can't reproduce on DELL E5440 + AR9300 PCIE chips. The warning is caused by accessing invalid pointer sc->rng_task. sc->rng_task is not be cleared after kthread_stop(sc->rng_task) be called in ath9k_rng_stop(). Because the kthread is stopped before ath9k_rng_kthread() be scheduled. So set sc->rng_task to null after kthread_stop(sc->rng_task) to resolve this issue. WARNING: CPU: 0 PID: 984 at linux/kernel/kthread.c:71 kthread_stop+0xf1/0x100 CPU: 0 PID: 984 Comm: NetworkManager Not tainted 4.12.0-041200rc4-generic #201706042031 Hardware name: Dell Inc. Dell System XPS L322X/0PJHXN, BIOS A09 05/15/2013 task: ffff950170fdda00 task.stack: ffffa22c01538000 RIP: 0010:kthread_stop+0xf1/0x100 RSP: 0018:ffffa22c0153b5b0 EFLAGS: 00010246 RAX: ffffffffa6257800 RBX: ffff950171b79560 RCX: 0000000000000000 RDX: 0000000080000000 RSI: 000000007fffffff RDI: ffff9500ac9a9680 RBP: ffffa22c0153b5c8 R08: 0000000000000000 R09: 0000000000000000 R10: ffffa22c0153b648 R11: ffff9501768004b8 R12: ffff9500ac9a9680 R13: ffff950171b79f70 R14: ffff950171b78780 R15: ffff9501749dc018 FS: 00007f0d6bfd5540(0000) GS:ffff95017f200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fc190161a08 CR3: 0000000232906000 CR4: 00000000001406f0 Call Trace: ath9k_rng_stop+0x1a/0x20 [ath9k] ath9k_stop+0x3b/0x1d0 [ath9k] drv_stop+0x33/0xf0 [mac80211] ieee80211_stop_device+0x43/0x50 [mac80211] ieee80211_do_stop+0x4f2/0x810 [mac80211] Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196043 Reported-by: Giulio Genovese Tested-by: Giulio Genovese Cc: Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/rng.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c index 568b1c6c2b2b..73f46fb3e83a 100644 --- a/drivers/net/wireless/ath/ath9k/rng.c +++ b/drivers/net/wireless/ath/ath9k/rng.c @@ -120,6 +120,8 @@ void ath9k_rng_start(struct ath_softc *sc) void ath9k_rng_stop(struct ath_softc *sc) { - if (sc->rng_task) + if (sc->rng_task) { kthread_stop(sc->rng_task); + sc->rng_task = NULL; + } } -- cgit v1.2.3 From 473becac4b310dd720a0f5e07ce149a09467f1a4 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Tue, 27 Jun 2017 17:31:54 +0300 Subject: ath9k: avoid potential freezing during random generator read In the worst case, ath9k_rng_stop() may take 10s to stop rng kthread. The time is too long for users, use wait_event_interruptible_timeout() instead of msleep_interruptible(), wakup immediately once kthread_should_stop() is true. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/rng.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c index 73f46fb3e83a..f9d3d6eedd3c 100644 --- a/drivers/net/wireless/ath/ath9k/rng.c +++ b/drivers/net/wireless/ath/ath9k/rng.c @@ -24,6 +24,8 @@ #define ATH9K_RNG_BUF_SIZE 320 #define ATH9K_RNG_ENTROPY(x) (((x) * 8 * 10) >> 5) /* quality: 10/32 */ +static DECLARE_WAIT_QUEUE_HEAD(rng_queue); + static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size) { int i, j; @@ -85,7 +87,9 @@ static int ath9k_rng_kthread(void *data) ATH9K_RNG_BUF_SIZE); if (unlikely(!bytes_read)) { delay = ath9k_rng_delay_get(++fail_stats); - msleep_interruptible(delay); + wait_event_interruptible_timeout(rng_queue, + kthread_should_stop(), + msecs_to_jiffies(delay)); continue; } -- cgit v1.2.3 From f23cdfb3fe8f6e3502b8aebb819edf5669c1d802 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Tue, 27 Jun 2017 17:31:55 +0300 Subject: ath9k: Use mutex_lock to avoid potential race in start/stop rng Move ath9k_rng_stop/ath9k_rng_start pair into critical section, use mutex_lock to void potential race accessing. Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9e65d14e7b1e..8b4ac7f0a09b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -731,12 +731,12 @@ static int ath9k_start(struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_rng_start(sc); + mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); - ath9k_rng_start(sc); - return 0; } @@ -826,10 +826,10 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_deinit_channel_context(sc); - ath9k_rng_stop(sc); - mutex_lock(&sc->mutex); + ath9k_rng_stop(sc); + ath_cancel_work(sc); if (test_bit(ATH_OP_INVALID, &common->op_flags)) { -- cgit v1.2.3 From 23de57975f1467ec1987a716a27b20c1bc665309 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 25 Jun 2017 22:29:32 +0100 Subject: ath10k: fix a bunch of spelling mistakes in messages Fix the following spelling mistakes in messages: syncronise -> synchronize unusally -> unusually addrress -> address inverval -> interval Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath10k/pci.c | 2 +- drivers/net/wireless/ath/ath10k/sdio.c | 4 ++-- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4a71815490ae..55c808f03a84 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1392,7 +1392,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n", + ath10k_warn(ar, "failed to synchronize setup for vdev %i: %d\n", arvif->vdev_id, ret); return ret; } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 4f3f513dac4f..7ebfc409018d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -469,7 +469,7 @@ static int ath10k_pci_wake_wait(struct ath10k *ar) while (tot_delay < PCIE_WAKE_TIMEOUT) { if (ath10k_pci_is_awake(ar)) { if (tot_delay > PCIE_WAKE_LATE_US) - ath10k_warn(ar, "device wakeup took %d ms which is unusally long, otherwise it works normally.\n", + ath10k_warn(ar, "device wakeup took %d ms which is unusually long, otherwise it works normally.\n", tot_delay / 1000); return 0; } diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 9e78fbae8413..859ed870bd97 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -1553,7 +1553,7 @@ static int ath10k_sdio_hif_diag_read(struct ath10k *ar, u32 address, void *buf, /* read the data */ ret = ath10k_sdio_read(ar, MBOX_WINDOW_DATA_ADDRESS, buf, buf_len); if (ret) { - ath10k_warn(ar, "failed to read from mbox window data addrress: %d\n", + ath10k_warn(ar, "failed to read from mbox window data address: %d\n", ret); return ret; } @@ -1592,7 +1592,7 @@ static int ath10k_sdio_hif_diag_write_mem(struct ath10k *ar, u32 address, ret = ath10k_sdio_write(ar, MBOX_WINDOW_DATA_ADDRESS, data, nbytes); if (ret) { ath10k_warn(ar, - "failed to write 0x%p to mbox window data addrress: %d\n", + "failed to write 0x%p to mbox window data address: %d\n", data, ret); return ret; } diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index f9188027a6f6..7616c1c4bbd3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -2022,7 +2022,7 @@ ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar, arp->dest_ip4_addr = arg->dest_ip4_addr; ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr); - ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d inverval %d\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d interval %d\n", arg->vdev_id, arg->enabled, arg->method, arg->interval); return skb; } -- cgit v1.2.3 From 6788a3832c706c541d8a8227076eddde47446c8a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 26 Jun 2017 18:26:58 -0500 Subject: ath9k: remove useless variable assignment in ath_mci_intr() Value assigned to variable offset at line 551 is overwritten at line 562, before it can be used. This makes such variable assignment useless. Addresses-Coverity-ID: 1226941 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/mci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 66596b95273f..cf23fd815211 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -548,7 +548,7 @@ void ath_mci_intr(struct ath_softc *sc) if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO; - offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET); + ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) { -- cgit v1.2.3 From 3e3d8aa611076efc945687df30a3abf181989d1d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 21 Jun 2017 14:25:30 +0100 Subject: qtnfmac: fix uninitialized return code in ret The return value ret is unitialized and garbage is being returned for the three different error conditions when setting up the PCIe BARs. Fix this by initializing ret to -ENOMEM to indicate that the BARs failed to be setup correctly. Detected by CoverityScan, CID#1437563 ("Unitialized scalar variable") Signed-off-by: Colin Ian King Reviewed-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c index f93b27f3a236..7fc4f0d6a9ad 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -247,7 +247,7 @@ static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) { - int ret; + int ret = -ENOMEM; priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR); if (IS_ERR_OR_NULL(priv->sysctl_bar)) { -- cgit v1.2.3 From 135f4fbd75d74ac2c945e3f2aef779ef0d5a29ac Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 21 Jun 2017 12:15:31 -0500 Subject: rtlwifi: Fix a2dp choppy while BT RSSI stays on threshold. In this case, BTC asks to enter/leave PS mode frequently to cause A2DP choppy. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/ps.c | 14 ++++++++------ drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c | 10 ++++++++-- drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c | 8 ++++++-- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c | 10 ++++++++-- 4 files changed, 30 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index 0d152877d969..07ee3096f50e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -356,7 +356,7 @@ void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) if (mac->link_state != MAC80211_LINKED) return; - if (ppsc->dot11_psmode == rt_psmode) + if (ppsc->dot11_psmode == rt_psmode && rt_psmode == EACTIVE) return; /* Update power save mode configured. */ @@ -438,11 +438,13 @@ static void rtl_lps_enter_core(struct ieee80211_hw *hw) spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - if (ppsc->dot11_psmode == EACTIVE) { - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, - "Enter 802.11 power save mode...\n"); - rtl_lps_set_psmode(hw, EAUTOPS); - } + /* Don't need to check (ppsc->dot11_psmode == EACTIVE), because + * bt_ccoexist may ask to enter lps. + * In normal case, this constraint move to rtl_lps_set_psmode(). + */ + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + "Enter 802.11 power save mode...\n"); + rtl_lps_set_psmode(hw, EAUTOPS); spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index 379dbc158dfc..f5d4df985c37 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -427,6 +427,11 @@ void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); + bool bt_lps_on = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_lps_on(rtlpriv) : false); + + if (bt_ctrl_lps) + mode = (bt_lps_on ? FW_PS_MIN_MODE : FW_PS_ACTIVE_MODE); RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", mode, bt_ctrl_lps); @@ -482,8 +487,9 @@ void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, - (rtlpriv->mac80211.p2p) ? - ppsc->smart_ps : 1); + bt_ctrl_lps ? 0 : + ((rtlpriv->mac80211.p2p) ? + ppsc->smart_ps : 1)); SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, awake_intvl); SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c index eb440a850643..dd6f95cfaec9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c @@ -245,6 +245,11 @@ void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); + bool bt_lps_on = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_lps_on(rtlpriv) : false); + + if (bt_ctrl_lps) + mode = (bt_lps_on ? FW_PS_MIN_MODE : FW_PS_ACTIVE_MODE); RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", mode, bt_ctrl_lps); @@ -300,8 +305,7 @@ void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, - (rtlpriv->mac80211.p2p) ? - ppsc->smart_ps : 1); + bt_ctrl_lps ? 0 : ppsc->smart_ps); SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, awake_intvl); SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index 87818d2ccc4e..03259aa150fd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -494,6 +494,11 @@ void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ? btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false); + bool bt_lps_on = (rtlpriv->cfg->ops->get_btc_status() ? + btc_ops->btc_is_bt_lps_on(rtlpriv) : false); + + if (bt_ctrl_lps) + mode = (bt_lps_on ? FW_PS_MIN_MODE : FW_PS_ACTIVE_MODE); RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n", mode, bt_ctrl_lps); @@ -549,8 +554,9 @@ void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0)); SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm); SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, - (rtlpriv->mac80211.p2p) ? - ppsc->smart_ps : 1); + bt_ctrl_lps ? 0 : + ((rtlpriv->mac80211.p2p) ? + ppsc->smart_ps : 1)); SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode, awake_intvl); SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0); -- cgit v1.2.3 From a70883920ea1070942255e1c32ef196707a12471 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 21 Jun 2017 12:15:32 -0500 Subject: rtlwifi: Do IQK only once to reduce wifi occupy antenna Modify 8723be and 8192e only. 8812/8821 do IQK in DM, so we may do it later. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c | 3 ++- drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c | 7 +++++-- drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index 11d97fa0e921..d84ac7adfd82 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -1670,7 +1670,8 @@ void rtl92ee_card_disable(struct ieee80211_hw *hw) _rtl92ee_poweroff_adapter(hw); /* after power off we should do iqk again */ - rtlpriv->phy.iqk_initialized = false; + if (!rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->phy.iqk_initialized = false; } void rtl92ee_interrupt_recognized(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index 0ce2900722f4..2a7ad5ffe997 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -1443,7 +1443,9 @@ int rtl8723be_hw_init(struct ieee80211_hw *hw) */ if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2 || !rtlpriv->cfg->ops->get_btc_status()) { - rtl8723be_phy_iq_calibrate(hw, false); + rtl8723be_phy_iq_calibrate(hw, + (rtlphy->iqk_initialized ? + true : false)); rtlphy->iqk_initialized = true; } rtl8723be_dm_check_txpower_tracking(hw); @@ -1677,7 +1679,8 @@ void rtl8723be_card_disable(struct ieee80211_hw *hw) _rtl8723be_poweroff_adapter(hw); /* after power off we should do iqk again */ - rtlpriv->phy.iqk_initialized = false; + if (!rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->phy.iqk_initialized = false; } void rtl8723be_interrupt_recognized(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c index ab0f39e46e1b..9752175cc466 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c @@ -2352,7 +2352,7 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) if (b_recovery) { rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9); - return; + goto label_done; } /* Save RF Path */ path_sel_bb = rtl_get_bbreg(hw, 0x948, MASKDWORD); @@ -2460,6 +2460,7 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) rtl_set_bbreg(hw, 0x948, MASKDWORD, path_sel_bb); /* rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, 0xfffff, path_sel_rf); */ +label_done: spin_lock(&rtlpriv->locks.iqk_lock); rtlphy->lck_inprogress = false; spin_unlock(&rtlpriv->locks.iqk_lock); -- cgit v1.2.3 From 1024b31629bd8e296b71b97d7583f1d7a214ef84 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 21 Jun 2017 12:15:33 -0500 Subject: rtlwifi: Modify power mode parameters of 8723be and 8821ae. Change the parameters suggested by FW. awake int: 2 smart_ps: 2 or 0 ps_mode: 2 (MAX -- every DTIM) Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 8c0ac96b5430..f9d10f1e7cf8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -155,8 +155,8 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); - rtlpriv->psc.reg_fwctrl_lps = 3; - rtlpriv->psc.reg_max_lps_awakeintvl = 5; + rtlpriv->psc.reg_fwctrl_lps = 2; + rtlpriv->psc.reg_max_lps_awakeintvl = 2; /* for ASPM, you can close aspm through * set const_support_pciaspm = 0 */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index abaf34cb1433..d71d2776ca03 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -172,8 +172,8 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); - rtlpriv->psc.reg_fwctrl_lps = 3; - rtlpriv->psc.reg_max_lps_awakeintvl = 5; + rtlpriv->psc.reg_fwctrl_lps = 2; + rtlpriv->psc.reg_max_lps_awakeintvl = 2; /* for ASPM, you can close aspm through * set const_support_pciaspm = 0 -- cgit v1.2.3 From 838dd0d3ffe644451f7492bc1f746d609c0baead Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 21 Jun 2017 12:15:34 -0500 Subject: rtlwifi: Update some cases in btc_get function -- roam, 5G, AP mode, and return value. Return value may be false in some situations. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 24 +++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index eaa916a0727b..d8fb2442f795 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -381,6 +381,7 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) u32 *u32_tmp = (u32 *)out_buf; u8 *u8_tmp = (u8 *)out_buf; bool tmp = false; + bool ret = true; if (!halbtc_is_bt_coexist_available(btcoexist)) return false; @@ -388,9 +389,11 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) switch (get_type) { case BTC_GET_BL_HS_OPERATION: *bool_tmp = false; + ret = false; break; case BTC_GET_BL_HS_CONNECTING: *bool_tmp = false; + ret = false; break; case BTC_GET_BL_WIFI_CONNECTED: if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION && @@ -429,11 +432,16 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *bool_tmp = false; break; case BTC_GET_BL_WIFI_UNDER_5G: - /* TODO */ - *bool_tmp = false; + if (rtlhal->current_bandtype == BAND_ON_5G) + *bool_tmp = true; + else + *bool_tmp = false; break; case BTC_GET_BL_WIFI_AP_MODE_ENABLE: - *bool_tmp = false; + if (mac->opmode == NL80211_IFTYPE_AP) + *bool_tmp = true; + else + *bool_tmp = false; break; case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION: if (NO_ENCRYPTION == rtlpriv->sec.pairwise_enc_algorithm) @@ -460,8 +468,8 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); break; case BTC_GET_S4_HS_RSSI: - /* TODO */ - *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); + *s32_tmp = 0; + ret = false; break; case BTC_GET_U4_WIFI_BW: *u32_tmp = halbtc_get_wifi_bw(btcoexist); @@ -491,7 +499,8 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *u8_tmp = halbtc_get_wifi_central_chnl(btcoexist); break; case BTC_GET_U1_WIFI_HS_CHNL: - *u8_tmp = 1; + *u8_tmp = 0; + ret = false; break; case BTC_GET_U1_AP_NUM: /* driver do not know AP num, @@ -512,10 +521,11 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) break; default: + ret = false; break; } - return true; + return ret; } static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) -- cgit v1.2.3 From 8488e211d665c8574ef78bf49adc35918b3b7d7d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 21 Jun 2017 12:15:35 -0500 Subject: rtlwifi: Add return value to btc_set. We will use return value to handle error case. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index d8fb2442f795..ffa7a517b665 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -534,6 +534,7 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) bool *bool_tmp = (bool *)in_buf; u8 *u8_tmp = (u8 *)in_buf; u32 *u32_tmp = (u32 *)in_buf; + bool ret = true; if (!halbtc_is_bt_coexist_available(btcoexist)) return false; @@ -577,6 +578,7 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) /* the following are some action which will be triggered */ case BTC_SET_ACT_GET_BT_RSSI: + ret = false; break; case BTC_SET_ACT_AGGREGATE_CTRL: halbtc_aggregation_check(btcoexist); @@ -622,7 +624,7 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) break; } - return true; + return ret; } /************************************************************ -- cgit v1.2.3 From f1cb27eda3a69099c4e2c9feb0d6c7e5d6ddf668 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 21 Jun 2017 12:15:36 -0500 Subject: rtlwifi: Add ap_num field for btcoexist If there are many AP (dirty environment), we use another strategy set to resolve coex issue. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 5 +---- drivers/net/wireless/realtek/rtlwifi/pci.c | 1 + drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 ++ 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index ffa7a517b665..9dbb35f190d1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -503,10 +503,7 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) ret = false; break; case BTC_GET_U1_AP_NUM: - /* driver do not know AP num, - * so the return value here is not right - */ - *u8_tmp = 1; + *u8_tmp = rtlpriv->btcoexist.btc_info.ap_num; break; case BTC_GET_U1_ANT_TYPE: *u8_tmp = (u8)BTC_ANT_TYPE_0; diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index df5f6795f650..a3997da72ed3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -1824,6 +1824,7 @@ static int rtl_pci_start(struct ieee80211_hw *hw) rtlpci->driver_is_goingto_unload = false; if (rtlpriv->cfg->ops->get_btc_status && rtlpriv->cfg->ops->get_btc_status()) { + rtlpriv->btcoexist.btc_info.ap_num = 36; rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv); rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv); } diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 49c0d2229274..2fb83a7061dd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2481,6 +2481,8 @@ struct rtl_btc_info { u8 btcoexist; u8 ant_num; u8 single_ant_path; + + u8 ap_num; }; struct bt_coexist_info { -- cgit v1.2.3 From c76ab8e754426729199448ae1749e88fbbf04dd1 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 21 Jun 2017 12:15:37 -0500 Subject: rtlwifi: Fill ap_num field by driver Check beacon and probe_resp frames to know ap_num Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/base.c | 102 ++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtlwifi/base.h | 2 + drivers/net/wireless/realtek/rtlwifi/core.c | 3 + drivers/net/wireless/realtek/rtlwifi/pci.c | 3 + drivers/net/wireless/realtek/rtlwifi/wifi.h | 13 ++++ 5 files changed, 123 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index d34ad94c327b..e36ee592c660 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -564,6 +564,7 @@ int rtl_init_core(struct ieee80211_hw *hw) spin_lock_init(&rtlpriv->locks.waitq_lock); spin_lock_init(&rtlpriv->locks.entry_list_lock); spin_lock_init(&rtlpriv->locks.c2hcmd_lock); + spin_lock_init(&rtlpriv->locks.scan_list_lock); spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); spin_lock_init(&rtlpriv->locks.check_sendpkt_lock); spin_lock_init(&rtlpriv->locks.fw_ps_lock); @@ -572,6 +573,7 @@ int rtl_init_core(struct ieee80211_hw *hw) /* <5> init list */ INIT_LIST_HEAD(&rtlpriv->entry_list); INIT_LIST_HEAD(&rtlpriv->c2hcmd_list); + INIT_LIST_HEAD(&rtlpriv->scan_list.list); rtlmac->link_state = MAC80211_NOLINK; @@ -582,9 +584,12 @@ int rtl_init_core(struct ieee80211_hw *hw) } EXPORT_SYMBOL_GPL(rtl_init_core); +static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw); + void rtl_deinit_core(struct ieee80211_hw *hw) { rtl_c2hcmd_launcher(hw, 0); + rtl_free_entries_from_scan_list(hw); } EXPORT_SYMBOL_GPL(rtl_deinit_core); @@ -1704,6 +1709,100 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(rtl_beacon_statistic); +static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_bssid_entry *entry, *next; + + list_for_each_entry_safe(entry, next, &rtlpriv->scan_list.list, list) { + list_del(&entry->list); + kfree(entry); + rtlpriv->scan_list.num--; + } +} + +void rtl_scan_list_expire(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_bssid_entry *entry, *next; + unsigned long flags; + + spin_lock_irqsave(&rtlpriv->locks.scan_list_lock, flags); + + list_for_each_entry_safe(entry, next, &rtlpriv->scan_list.list, list) { + /* 180 seconds */ + if (jiffies_to_msecs(jiffies - entry->age) < 180000) + continue; + + list_del(&entry->list); + kfree(entry); + rtlpriv->scan_list.num--; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "BSSID=%pM is expire in scan list (total=%d)\n", + entry->bssid, rtlpriv->scan_list.num); + } + + spin_unlock_irqrestore(&rtlpriv->locks.scan_list_lock, flags); + + rtlpriv->btcoexist.btc_info.ap_num = rtlpriv->scan_list.num; +} + +void rtl_collect_scan_list(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + unsigned long flags; + + struct rtl_bssid_entry *entry; + bool entry_found = false; + + /* check if it is scanning */ + if (!mac->act_scanning) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control) && + !ieee80211_is_probe_resp(hdr->frame_control)) + return; + + spin_lock_irqsave(&rtlpriv->locks.scan_list_lock, flags); + + list_for_each_entry(entry, &rtlpriv->scan_list.list, list) { + if (memcmp(entry->bssid, hdr->addr3, ETH_ALEN) == 0) { + list_del_init(&entry->list); + entry_found = true; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "Update BSSID=%pM to scan list (total=%d)\n", + hdr->addr3, rtlpriv->scan_list.num); + break; + } + } + + if (!entry_found) { + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + + if (!entry) + goto label_err; + + memcpy(entry->bssid, hdr->addr3, ETH_ALEN); + rtlpriv->scan_list.num++; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, + "Add BSSID=%pM to scan list (total=%d)\n", + hdr->addr3, rtlpriv->scan_list.num); + } + + entry->age = jiffies; + + list_add_tail(&entry->list, &rtlpriv->scan_list.list); + +label_err: + spin_unlock_irqrestore(&rtlpriv->locks.scan_list_lock, flags); +} +EXPORT_SYMBOL(rtl_collect_scan_list); + void rtl_watchdog_wq_callback(void *data) { struct rtl_works *rtlworks = container_of_dwork_rtl(data, @@ -1861,6 +1960,9 @@ label_lps_done: rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv); rtlpriv->link_info.bcn_rx_inperiod = 0; + + /* <6> scan list */ + rtl_scan_list_expire(hw); } void rtl_watch_dog_timer_callback(unsigned long data) diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index 21fa4562f631..ab7d81904d25 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -137,6 +137,8 @@ bool rtl_check_tx_report_acked(struct ieee80211_hw *hw); void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms); void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_collect_scan_list(struct ieee80211_hw *hw, struct sk_buff *skb); +void rtl_scan_list_expire(struct ieee80211_hw *hw); int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 1a53a95d373b..b0ad061048c5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1464,6 +1464,9 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n"); mac->act_scanning = false; mac->skip_scan = false; + + rtlpriv->btcoexist.btc_info.ap_num = rtlpriv->scan_list.num; + if (rtlpriv->link_info.higher_busytraffic) return; diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index a3997da72ed3..032b6317690d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -879,6 +879,9 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) if (unicast) rtlpriv->link_info.num_rx_inperiod++; } + + rtl_collect_scan_list(hw, skb); + /* static bcn for roaming */ rtl_beacon_statistic(hw, skb); rtl_p2p_info(hw, (void *)skb->data, skb->len); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 2fb83a7061dd..98183dc707aa 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2333,6 +2333,7 @@ struct rtl_locks { spinlock_t entry_list_lock; spinlock_t usb_lock; spinlock_t c2hcmd_lock; + spinlock_t scan_list_lock; /* lock for the scan list */ /*FW clock change */ spinlock_t fw_ps_lock; @@ -2587,6 +2588,17 @@ struct rtl_c2hcmd { u8 *val; }; +struct rtl_bssid_entry { + struct list_head list; + u8 bssid[ETH_ALEN]; + u32 age; +}; + +struct rtl_scan_list { + int num; + struct list_head list; /* sort by age */ +}; + struct rtl_priv { struct ieee80211_hw *hw; struct completion firmware_loading_complete; @@ -2608,6 +2620,7 @@ struct rtl_priv { struct rtl_efuse efuse; struct rtl_led_ctl ledctl; struct rtl_tx_report tx_report; + struct rtl_scan_list scan_list; struct rtl_ps_ctl psc; struct rate_adaptive ra; -- cgit v1.2.3 From 76f146b6645b79bb21a7bfdc0a903282f1160245 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 21 Jun 2017 12:15:38 -0500 Subject: rtlwifi: Add in_4way field for btcoexist If wifi is in 4way, btcoex give wifi higher priority to use antenna. Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c | 3 +-- drivers/net/wireless/realtek/rtlwifi/wifi.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 9dbb35f190d1..e6024b013ca5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -428,8 +428,7 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) *bool_tmp = false; break; case BTC_GET_BL_WIFI_4_WAY_PROGRESS: - /* TODO */ - *bool_tmp = false; + *bool_tmp = rtlpriv->btcoexist.btc_info.in_4way; break; case BTC_GET_BL_WIFI_UNDER_5G: if (rtlhal->current_bandtype == BAND_ON_5G) diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 98183dc707aa..fb1ebb01133f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2484,6 +2484,7 @@ struct rtl_btc_info { u8 single_ant_path; u8 ap_num; + bool in_4way; }; struct bt_coexist_info { -- cgit v1.2.3 From 4d7ab36f0c47c9ed5fa2391e77f3b3cb0e23c9dd Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Thu, 22 Jun 2017 12:32:52 +0530 Subject: mwifiex: Do not change bss_type in change_virtual_intf When user adds a virtual interface driver will set the bss_type to the iface_type given by the user. When supplicant is started on the same interface, a call to change_virtual_intf will be triggered if if_type is not NL80211_IFTYPE_STATION. Here driver should not update it's bss_type, because bss_type is intended to indicate the original iface_type and changing the same will defeat the purpose of creating this interface. Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index a850ec0054e2..062f3369f831 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -892,24 +892,20 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, priv->bss_num = mwifiex_get_unused_bss_num(adapter, MWIFIEX_BSS_TYPE_STA); priv->bss_role = MWIFIEX_BSS_ROLE_STA; - priv->bss_type = MWIFIEX_BSS_TYPE_STA; break; case NL80211_IFTYPE_P2P_CLIENT: priv->bss_num = mwifiex_get_unused_bss_num(adapter, MWIFIEX_BSS_TYPE_P2P); priv->bss_role = MWIFIEX_BSS_ROLE_STA; - priv->bss_type = MWIFIEX_BSS_TYPE_P2P; break; case NL80211_IFTYPE_P2P_GO: priv->bss_num = mwifiex_get_unused_bss_num(adapter, MWIFIEX_BSS_TYPE_P2P); priv->bss_role = MWIFIEX_BSS_ROLE_UAP; - priv->bss_type = MWIFIEX_BSS_TYPE_P2P; break; case NL80211_IFTYPE_AP: priv->bss_num = mwifiex_get_unused_bss_num(adapter, MWIFIEX_BSS_TYPE_UAP); - priv->bss_type = MWIFIEX_BSS_TYPE_UAP; priv->bss_role = MWIFIEX_BSS_ROLE_UAP; break; default: -- cgit v1.2.3 From ca2e99b2cae99570cade884e800153f5a2928335 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 22 Jun 2017 11:01:01 +0100 Subject: brcmfmac: cleanup kerneldoc for struct brcmf_bus A couple of old fields were still described and one field was not described. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index b55c3293c4b4..e2c895bc1e68 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -122,9 +122,8 @@ struct brcmf_bus_msgbuf { * @state: operational state of the bus interface. * @maxctl: maximum size for rxctl request message. * @tx_realloc: number of tx packets realloced for headroom. - * @dstats: dongle-based statistical data. - * @dcmd_list: bus/device specific dongle initialization commands. * @chip: device identifier of the dongle chip. + * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive. * @wowl_supported: is wowl supported by bus driver. * @chiprev: revision of the dongle chip. */ -- cgit v1.2.3 From a833f3d4de53921263f6a060dbff08d5af926ba7 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 22 Jun 2017 11:01:02 +0100 Subject: brcmfmac: use atomic_t for statistic counter in struct brcmf_bus The statistic counter is used in common layer and in the bus layer in different thread contexts so change to use atomic operations. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 2 +- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index e2c895bc1e68..e1a4d9e0eb10 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -138,7 +138,7 @@ struct brcmf_bus { struct brcmf_pub *drvr; enum brcmf_bus_state state; uint maxctl; - unsigned long tx_realloc; + atomic_t tx_realloc; u32 chip; u32 chiprev; bool always_use_fws_queue; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index fd7b5addc54f..eb67d7d5be9d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -2046,7 +2046,7 @@ static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt) head_pad = ((unsigned long)dat_buf % bus->head_align); if (head_pad) { if (skb_headroom(pkt) < head_pad) { - bus->sdiodev->bus_if->tx_realloc++; + atomic_inc(&bus->sdiodev->bus_if->tx_realloc); head_pad = 0; if (skb_cow(pkt, head_pad)) return -ENOMEM; -- cgit v1.2.3 From 270a6c1f65fe68a28a5d39cd405592c550b496c7 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 22 Jun 2017 11:01:03 +0100 Subject: brcmfmac: rework headroom check in .start_xmit() Since commit 9cc4b7cb86cb ("brcmfmac: Make skb header writable before use") the headroom usage has been fixed. However, the driver was keeping statistics that got lost. So reworking the code so we get those driver statistics back for debugging. Cc: James Hughes Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h | 15 ++++++++++++-- .../wireless/broadcom/brcm80211/brcmfmac/core.c | 23 +++++++++++++++------- .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 13 +++++++----- 3 files changed, 37 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index e1a4d9e0eb10..163ddc49f951 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -112,6 +112,17 @@ struct brcmf_bus_msgbuf { }; +/** + * struct brcmf_bus_stats - bus statistic counters. + * + * @pktcowed: packets cowed for extra headroom/unorphan. + * @pktcow_failed: packets dropped due to failed cow-ing. + */ +struct brcmf_bus_stats { + atomic_t pktcowed; + atomic_t pktcow_failed; +}; + /** * struct brcmf_bus - interface structure between common and bus layer * @@ -120,8 +131,8 @@ struct brcmf_bus_msgbuf { * @dev: device pointer of bus device. * @drvr: public driver information. * @state: operational state of the bus interface. + * @stats: statistics shared between common and bus layer. * @maxctl: maximum size for rxctl request message. - * @tx_realloc: number of tx packets realloced for headroom. * @chip: device identifier of the dongle chip. * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive. * @wowl_supported: is wowl supported by bus driver. @@ -137,8 +148,8 @@ struct brcmf_bus { struct device *dev; struct brcmf_pub *drvr; enum brcmf_bus_state state; + struct brcmf_bus_stats stats; uint maxctl; - atomic_t tx_realloc; u32 chip; u32 chiprev; bool always_use_fws_queue; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index b4c86434ad80..2153e8062b4c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -199,6 +199,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; struct ethhdr *eh; + int head_delta; brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx); @@ -211,13 +212,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, goto done; } - /* Make sure there's enough writable headroom*/ - ret = skb_cow_head(skb, drvr->hdrlen); - if (ret < 0) { - brcmf_err("%s: skb_cow_head failed\n", - brcmf_ifname(ifp)); - dev_kfree_skb(skb); - goto done; + /* Make sure there's enough writeable headroom */ + if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) { + head_delta = drvr->hdrlen - skb_headroom(skb); + + brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n", + brcmf_ifname(ifp), head_delta); + atomic_inc(&drvr->bus_if->stats.pktcowed); + ret = pskb_expand_head(skb, ALIGN(head_delta, NET_SKB_PAD), 0, + GFP_ATOMIC); + if (ret < 0) { + brcmf_err("%s: failed to expand headroom\n", + brcmf_ifname(ifp)); + atomic_inc(&drvr->bus_if->stats.pktcow_failed); + goto done; + } } /* validate length for ether packet */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index eb67d7d5be9d..fbcbb4325936 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -2037,6 +2037,7 @@ brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus) static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt) { + struct brcmf_bus_stats *stats; u16 head_pad; u8 *dat_buf; @@ -2046,16 +2047,18 @@ static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt) head_pad = ((unsigned long)dat_buf % bus->head_align); if (head_pad) { if (skb_headroom(pkt) < head_pad) { - atomic_inc(&bus->sdiodev->bus_if->tx_realloc); - head_pad = 0; - if (skb_cow(pkt, head_pad)) + stats = &bus->sdiodev->bus_if->stats; + atomic_inc(&stats->pktcowed); + if (skb_cow_head(pkt, head_pad)) { + atomic_inc(&stats->pktcow_failed); return -ENOMEM; + } } skb_push(pkt, head_pad); dat_buf = (u8 *)(pkt->data); - memset(dat_buf, 0, head_pad + bus->tx_hdrlen); } - return head_pad; + memset(dat_buf, 0, head_pad + bus->tx_hdrlen); + return 0; } /** -- cgit v1.2.3 From 58828680af495bc4863af3a006f2018c71714665 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 22 Jun 2017 17:58:04 +0100 Subject: rsi: add in missing RSI_FSM_STATES into array fsm_state Two recent commits added new RSI_FSM_STATES (namely FSM_FW_NOT_LOADED and FSM_COMMON_DEV_PARAMS_SENT) and the corresponding table fsm_state was not updated to match. This can lead to an array overrun when accessing the latter two states in fsm_state. Fix this by adding in the missing states. Detected by CoverityScan, CID#1398379 ("Illegal address computation") Fixes: 9920322ccd8e ("rsi: add tx frame for common device configuration") Fixes: 015e367494c1 ("rsi: Register interrupt handler before firmware load") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_debugfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c index 828a042f903f..4c0a493bd44e 100644 --- a/drivers/net/wireless/rsi/rsi_91x_debugfs.c +++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c @@ -125,7 +125,9 @@ static int rsi_stats_read(struct seq_file *seq, void *data) struct rsi_common *common = seq->private; unsigned char fsm_state[][32] = { + "FSM_FW_NOT_LOADED", "FSM_CARD_NOT_READY", + "FSM_COMMON_DEV_PARAMS_SENT", "FSM_BOOT_PARAMS_SENT", "FSM_EEPROM_READ_MAC_ADDR", "FSM_RESET_MAC_SENT", -- cgit v1.2.3 From 3ac27dd37b40ae9a1a2690c91f27ab339b275142 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Fri, 23 Jun 2017 17:13:19 +0530 Subject: cw1200: add const to hwbus_ops structures Declare hwbus_ops structures as const as they are only passed as an argument to the function cw1200_core_probe. This argument is of type const. So, make these structures const. Signed-off-by: Bhumika Goyal Signed-off-by: Kalle Valo --- drivers/net/wireless/st/cw1200/cw1200_sdio.c | 2 +- drivers/net/wireless/st/cw1200/cw1200_spi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/st/cw1200/cw1200_sdio.c b/drivers/net/wireless/st/cw1200/cw1200_sdio.c index 709f56e5ad87..1037ec62659d 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_sdio.c +++ b/drivers/net/wireless/st/cw1200/cw1200_sdio.c @@ -266,7 +266,7 @@ static int cw1200_sdio_pm(struct hwbus_priv *self, bool suspend) return ret; } -static struct hwbus_ops cw1200_sdio_hwbus_ops = { +static const struct hwbus_ops cw1200_sdio_hwbus_ops = { .hwbus_memcpy_fromio = cw1200_sdio_memcpy_fromio, .hwbus_memcpy_toio = cw1200_sdio_memcpy_toio, .lock = cw1200_sdio_lock, diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index 63f95e9c2992..412fb6e49aed 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -352,7 +352,7 @@ static int cw1200_spi_pm(struct hwbus_priv *self, bool suspend) return irq_set_irq_wake(self->func->irq, suspend); } -static struct hwbus_ops cw1200_spi_hwbus_ops = { +static const struct hwbus_ops cw1200_spi_hwbus_ops = { .hwbus_memcpy_fromio = cw1200_spi_memcpy_fromio, .hwbus_memcpy_toio = cw1200_spi_memcpy_toio, .lock = cw1200_spi_lock, -- cgit v1.2.3 From 69551f5f370cc20342fab17ca54716b6ec7e332d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 23 Jun 2017 18:17:38 +0300 Subject: libertas: Fix lbs_prb_rsp_limit_set() The kstrtoul() test was reversed so this always returned -ENOTSUPP. Fixes: 27d7f47756f4 ("net: wireless: replace strict_strtoul() with kstrtoul()") Signed-off-by: Dan Carpenter Reviewed-by: James Cameron Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/mesh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c index eeeb892219aa..37ace5cb309d 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.c +++ b/drivers/net/wireless/marvell/libertas/mesh.c @@ -233,8 +233,9 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev, memset(&mesh_access, 0, sizeof(mesh_access)); mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET); - if (!kstrtoul(buf, 10, &retry_limit)) - return -ENOTSUPP; + ret = kstrtoul(buf, 10, &retry_limit); + if (ret) + return ret; if (retry_limit > 15) return -ENOTSUPP; -- cgit v1.2.3 From 059c98599b1ab1e2e479e1f4617948d4c2a32b84 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 26 Jun 2017 18:06:19 -0500 Subject: wl18xx: add checks on wl18xx_top_reg_write() return value Check return value from call to wl18xx_top_reg_write(), so in case of error jump to goto label out and return. Also, remove unnecessary value check before goto label out. Addresses-Coverity-ID: 1226938 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index d1aa3eee0e81..0cf3b4013dd6 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -793,9 +793,13 @@ static int wl18xx_set_clk(struct wl1271 *wl) ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2, (wl18xx_clk_table[clk_freq].p >> 16) & PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK); + if (ret < 0) + goto out; } else { ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN, PLLSH_WCS_PLL_SWALLOW_EN_VAL2); + if (ret < 0) + goto out; } /* choose WCS PLL */ @@ -819,8 +823,6 @@ static int wl18xx_set_clk(struct wl1271 *wl) /* reset the swallowing logic */ ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN, PLLSH_COEX_PLL_SWALLOW_EN_VAL2); - if (ret < 0) - goto out; out: return ret; -- cgit v1.2.3 From 3334c28ec56cfaa7c25931711eb2bda4a92d0712 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 28 Jun 2017 16:50:54 +0100 Subject: mwifiex: fix spelling mistake: "secuirty" -> "security" Trivial fix to spelling mistake in mwifiex_dbg message Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 062f3369f831..06ad2d50f9b0 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1977,7 +1977,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, if (mwifiex_set_secure_params(priv, bss_cfg, params)) { mwifiex_dbg(priv->adapter, ERROR, - "Failed to parse secuirty parameters!\n"); + "Failed to parse security parameters!\n"); goto out; } -- cgit v1.2.3 From 7fe90e0e3d603844657e8361aa4686c6ee4a8c9d Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Thu, 30 Mar 2017 11:16:17 +0300 Subject: iwlwifi: mvm: refactor geo init We are going to add debugfs entry to retrieve the current geographic profile being used in the FW. Currently the driver reads those tables from the BIOS and passes them to the FW. To prepare for this retrieving we want to store those tables in the driver. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/fw-api-power.h | 9 +++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 64 ++++++++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 12 +++- 3 files changed, 67 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h index 9d87fddd29b6..7da57ef2454e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h @@ -363,6 +363,7 @@ struct iwl_dev_tx_power_cmd { } __packed; /* TX_REDUCED_POWER_API_S_VER_4 */ #define IWL_NUM_GEO_PROFILES 3 +#define IWL_GEO_PER_CHAIN_SIZE 3 /** * enum iwl_geo_per_chain_offset_operation - type of operation @@ -401,6 +402,14 @@ struct iwl_geo_tx_power_profiles_cmd { struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES]; } __packed; /* GEO_TX_POWER_LIMIT */ +/** + * struct iwl_geo_tx_power_profiles_resp - response to GEO_TX_POWER_LIMIT cmd + * @profile_idx: current geo profile in use + */ +struct iwl_geo_tx_power_profiles_resp { + __le32 profile_idx; +} __packed; /* GEO_TX_POWER_LIMIT_RESP */ + /** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 24cc406d87ef..273e19460016 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1243,15 +1243,15 @@ out_free: return ret; } -static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm, - struct iwl_mvm_geo_table *geo_table) +static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm) { union acpi_object *wifi_pkg; acpi_handle root_handle; acpi_handle handle; struct acpi_buffer wgds = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_status status; - int i, ret; + int i, j, ret; + int idx = 1; root_handle = ACPI_HANDLE(mvm->dev); if (!root_handle) { @@ -1282,15 +1282,17 @@ static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm, goto out_free; } - for (i = 0; i < ACPI_WGDS_WIFI_DATA_SIZE; i++) { - union acpi_object *entry; + for (i = 0; i < IWL_NUM_GEO_PROFILES; i++) { + for (j = 0; j < IWL_MVM_GEO_TABLE_SIZE; j++) { + union acpi_object *entry; - entry = &wifi_pkg->package.elements[i + 1]; - if ((entry->type != ACPI_TYPE_INTEGER) || - (entry->integer.value > U8_MAX)) - return -EINVAL; + entry = &wifi_pkg->package.elements[idx++]; + if ((entry->type != ACPI_TYPE_INTEGER) || + (entry->integer.value > U8_MAX)) + return -EINVAL; - geo_table->values[i] = entry->integer.value; + mvm->geo_profiles[i].values[j] = entry->integer.value; + } } ret = 0; out_free: @@ -1351,16 +1353,47 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } +int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) +{ + struct iwl_geo_tx_power_profiles_resp *resp; + int ret; + + struct iwl_geo_tx_power_profiles_cmd geo_cmd = { + .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE), + }; + struct iwl_host_cmd cmd = { + .id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT), + .len = { sizeof(geo_cmd), }, + .flags = CMD_WANT_SKB, + .data = { &geo_cmd }, + }; + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) { + IWL_ERR(mvm, "Failed to get geographic profile info %d\n", ret); + return ret; + } + + resp = (void *)cmd.resp_pkt->data; + ret = le32_to_cpu(resp->profile_idx); + if (WARN_ON(ret > IWL_NUM_GEO_PROFILES)) { + ret = -EIO; + IWL_WARN(mvm, "Invalid geographic profile idx (%d)\n", ret); + } + + iwl_free_resp(&cmd); + return ret; +} + static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) { - struct iwl_mvm_geo_table geo_table; struct iwl_geo_tx_power_profiles_cmd cmd = { .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES), }; - int ret, i, j, idx; + int ret, i, j; u16 cmd_wide_id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT); - ret = iwl_mvm_sar_get_wgds_table(mvm, &geo_table); + ret = iwl_mvm_sar_get_wgds_table(mvm); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "Geo SAR BIOS table invalid or unavailable. (%d)\n", @@ -1381,9 +1414,8 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) for (j = 0; j < ACPI_WGDS_NUM_BANDS; j++) { u8 *value; - idx = i * ACPI_WGDS_NUM_BANDS * ACPI_WGDS_TABLE_SIZE + - j * ACPI_WGDS_TABLE_SIZE; - value = &geo_table.values[idx]; + value = &mvm->geo_profiles[i].values[j * + IWL_GEO_PER_CHAIN_SIZE]; chain[j].max_tx_power = cpu_to_le16(value[0]); chain[j].chain_a = value[1]; chain[j].chain_b = value[2]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 3b1f15873034..9b777b847e22 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -724,14 +724,14 @@ enum iwl_mvm_queue_status { #ifdef CONFIG_ACPI #define IWL_MVM_SAR_TABLE_SIZE 10 #define IWL_MVM_SAR_PROFILE_NUM 4 -#define IWL_MVM_GEO_TABLE_SIZE 18 +#define IWL_MVM_GEO_TABLE_SIZE 6 struct iwl_mvm_sar_profile { bool enabled; u8 table[IWL_MVM_SAR_TABLE_SIZE]; }; -struct iwl_mvm_geo_table { +struct iwl_mvm_geo_profile { u8 values[IWL_MVM_GEO_TABLE_SIZE]; }; #endif @@ -1071,6 +1071,7 @@ struct iwl_mvm { struct delayed_work cs_tx_unblock_dwork; #ifdef CONFIG_ACPI struct iwl_mvm_sar_profile sar_profiles[IWL_MVM_SAR_PROFILE_NUM]; + struct iwl_mvm_geo_profile geo_profiles[IWL_NUM_GEO_PROFILES]; #endif }; @@ -1889,12 +1890,19 @@ bool iwl_mvm_lqm_active(struct iwl_mvm *mvm); #ifdef CONFIG_ACPI int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); +int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); #else static inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { return -ENOENT; } + +static inline +int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) +{ + return -ENOENT; +} #endif /* CONFIG_ACPI */ #endif /* __IWL_MVM_H__ */ -- cgit v1.2.3 From e6ee06575bb71ae96d936b2279fc827b82f98353 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Mon, 15 May 2017 14:27:21 +0300 Subject: iwlwifi: mvm: Add debugfs entry to retrieve SAR geographic profile Add a debugfs entry to get a verbose description of the power settings used in each band with the currently selected SAR geographic profile. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index c2a1aeef74ec..c3ab13ee4097 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -336,6 +336,49 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +#ifdef CONFIG_ACPI +static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + char buf[256]; + int pos = 0; + int bufsz = sizeof(buf); + int tbl_idx; + u8 *value; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + + mutex_lock(&mvm->mutex); + tbl_idx = iwl_mvm_get_sar_geo_profile(mvm); + if (tbl_idx < 0) { + mutex_unlock(&mvm->mutex); + return tbl_idx; + } + + if (!tbl_idx) { + pos = scnprintf(buf, bufsz, + "SAR geographic profile disabled\n"); + } else { + value = &mvm->geo_profiles[tbl_idx - 1].values[0]; + + pos += scnprintf(buf + pos, bufsz - pos, + "Use geographic profile %d\n", tbl_idx); + pos += scnprintf(buf + pos, bufsz - pos, + "2.4GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n", + value[1], value[2], value[0]); + pos += scnprintf(buf + pos, bufsz - pos, + "5.2GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n", + value[4], value[5], value[3]); + } + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} +#endif + static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1572,6 +1615,9 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); #endif +#ifdef CONFIG_ACPI +MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile); +#endif static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -1744,6 +1790,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, S_IWUSR); +#ifdef CONFIG_ACPI + MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, S_IRUSR); +#endif + if (!debugfs_create_bool("enable_scan_iteration_notif", S_IRUSR | S_IWUSR, mvm->debugfs_dir, -- cgit v1.2.3 From 1644be9189c962cfd064d6b21af16f26f219a146 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 May 2017 13:21:52 +0200 Subject: iwlwifi: mvm: remove some CamelCase from firmware API Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h index edde49202786..3463d1c577e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h @@ -164,7 +164,7 @@ struct iwl_proto_offload_cmd_v2 { u8 solicited_node_ipv6_addr[16]; u8 target_ipv6_addr[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2][16]; u8 ndp_mac_addr[ETH_ALEN]; - u8 numValidIPv6Addresses; + u8 num_valid_ipv6_addrs; u8 reserved2[3]; } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index b84e8ddbbbc9..7588b93f835a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -1748,8 +1748,8 @@ enum iwl_mvm_marker_id { * @metadata: additional meta data that will be written to the unsiffer log */ struct iwl_mvm_marker { - u8 dwLen; - u8 markerId; + u8 dw_len; + u8 marker_id; __le16 reserved; __le64 timestamp; __le32 metadata[0]; -- cgit v1.2.3 From 83b0319abc5c8bfb16c5fe3063a04de1402f9b21 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 May 2017 13:28:53 +0200 Subject: iwlwifi: mvm: fix various "Excess ... description" kernel-doc warnings Fix various "Excess struct/union/enum/typedef member '...' description in '...'" warnings from kernel-doc, mostly caused by typos. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h | 3 +-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h | 8 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 1 - drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 5 ++--- 6 files changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h index 3463d1c577e8..2bfe4de6ac5a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h @@ -183,7 +183,7 @@ struct iwl_targ_addr { /** * struct iwl_proto_offload_cmd_v3_small - ARP/NS offload configuration * @common: common/IPv4 configuration - * @target_ipv6_addr: target IPv6 addresses + * @targ_addrs: target IPv6 addresses * @ns_config: NS offload configurations */ struct iwl_proto_offload_cmd_v3_small { @@ -196,7 +196,7 @@ struct iwl_proto_offload_cmd_v3_small { /** * struct iwl_proto_offload_cmd_v3_large - ARP/NS offload configuration * @common: common/IPv4 configuration - * @target_ipv6_addr: target IPv6 addresses + * @targ_addrs: target IPv6 addresses * @ns_config: NS offload configurations */ struct iwl_proto_offload_cmd_v3_large { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h index 1d970bf0d735..932adaf575eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h @@ -331,7 +331,7 @@ struct iwl_ac_qos { * @id_and_color: ID and color of the MAC * @action: action to perform, one of FW_CTXT_ACTION_* * @mac_type: one of &enum iwl_mac_types - * @tsd_id: TSF HW timer, one of &enum iwl_tsf_id + * @tsf_id: TSF HW timer, one of &enum iwl_tsf_id * @node_addr: MAC address * @bssid_addr: BSSID * @cck_rates: basic rates available for CCK @@ -342,7 +342,6 @@ struct iwl_ac_qos { * @filter_flags: combination of &enum iwl_mac_filter_flags * @qos_flags: from &enum iwl_mac_qos_flags * @ac: one iwl_mac_qos configuration for each AC - * @mac_specific: one of struct iwl_mac_data_*, according to mac_type */ struct iwl_mac_ctx_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index ad7ab6dd86cb..02c321738e1e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -96,7 +96,7 @@ enum iwl_mac_context_info { * @beacon_time_stamp: beacon at on-air rise * @phy_flags: general phy flags: band, modulation, ... * @channel: channel number - * @non_cfg_phy_buf: for various implementations of non_cfg_phy + * @non_cfg_phy: for various implementations of non_cfg_phy * @rate_n_flags: RATE_MCS_* * @byte_count: frame's byte-count * @frame_time: frame's time on the air, based on byte count and frame rate diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h index f8e92026bdc6..e752359841b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h @@ -137,7 +137,7 @@ enum iwl_scan_offload_band_selection { * struct iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S * @ssid_index: index to ssid list in fixed part * @unicast_cipher: encryption algorithm to match - bitmap - * @aut_alg: authentication algorithm to match - bitmap + * @auth_alg: authentication algorithm to match - bitmap * @network_type: enum iwl_scan_offload_network_type * @band_selection: enum iwl_scan_offload_band_selection * @client_bitmap: clients waiting for match - enum scan_framework_client @@ -221,7 +221,7 @@ enum iwl_scan_channel_flags_lmac { * struct iwl_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2 * @flags: bits 1-20: directed scan to i'th ssid * other bits &enum iwl_scan_channel_flags_lmac - * @channel_number: channel number 1-13 etc + * @channel_num: channel number 1-13 etc * @iter_count: scan iteration on this channel * @iter_interval: interval in seconds between iterations on one channel */ @@ -320,13 +320,13 @@ enum iwl_scan_priority_ext { /** * struct iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1 * @reserved1: for alignment and future use - * @channel_num: num of channels to scan + * @n_channels: num of channels to scan * @active-dwell: dwell time for active channels * @passive-dwell: dwell time for passive channels * @fragmented-dwell: dwell time for fragmented passive scan * @extended_dwell: dwell time for channels 1, 6 and 11 (in certain cases) * @reserved2: for alignment and future use - * @rx_chain_selct: PHY_RX_CHAIN_* flags + * @rx_chain_select: PHY_RX_CHAIN_* flags * @scan_flags: &enum iwl_mvm_lmac_scan_flags * @max_out_time: max time (in TU) to be out of associated channel * @suspend_time: pause scan this long (TUs) when returning to service channel diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index a37c584b0b48..4a6b919f13de 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -537,7 +537,6 @@ struct agg_tx_status { * @tlc_info: TLC rate info * @ra_tid: bits [3:0] = ra, bits [7:4] = tid * @frame_ctrl: frame control - * @tx_queue: TX queue for this response * @status: for non-agg: frame status TX_STATUS_* * for agg: status of 1st frame, AGG_TX_STATE_*; other frame status fields * follow this one, up to frame_count. Length in @frame_count. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 7588b93f835a..612546334545 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -2184,7 +2184,7 @@ enum iwl_tdls_channel_switch_type { * 200TU and the TDLS peer is to be given 25% of the time, the value * given will be 50TU, or 50 * 1024 if translated into microseconds. * @switch_time: switch time the peer sent in its channel switch timing IE - * @switch_timout: switch timeout the peer sent in its channel switch timing IE + * @switch_timeout: switch timeout the peer sent in its channel switch timing IE */ struct iwl_tdls_channel_switch_timing { __le32 frame_timestamp; /* GP2 time of peer packet Rx */ @@ -2456,7 +2456,7 @@ enum iwl_lqm_status { /** * struct iwl_link_qual_msrmnt_cmd - Link Quality Measurement command - * @cmd_operatrion: command operation to be performed (start or stop) + * @cmd_operation: command operation to be performed (start or stop) * as defined above. * @mac_id: MAC ID the measurement applies to. * @measurement_time: time of the total measurement to be performed, in uSec. @@ -2633,7 +2633,6 @@ struct iwl_nvm_get_info_phy { * struct iwl_nvm_get_info_regulatory - regulatory information * @lar_enabled: is LAR enabled * @channel_profile: regulatory data of this channel - * @regulatory: regulatory data, see &enum iwl_nvm_channel_flags for data */ struct iwl_nvm_get_info_regulatory { __le32 lar_enabled; -- cgit v1.2.3 From 40e07545d1bb9be2c37140a4d40df1339a4ed51d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 May 2017 14:33:41 +0200 Subject: iwlwifi: mvm: remove various unused command IDs/structs Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 28 ------------------------- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 11 ---------- 2 files changed, 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 612546334545..60f86997f8cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -295,7 +295,6 @@ enum iwl_legacy_cmds { HOT_SPOT_CMD = 0x53, SCAN_OFFLOAD_COMPLETE = 0x6D, SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, - SCAN_OFFLOAD_CONFIG_CMD = 0x6f, MATCH_FOUND_NOTIFICATION = 0xd9, SCAN_ITERATION_COMPLETE = 0xe7, @@ -329,8 +328,6 @@ enum iwl_legacy_cmds { */ NVM_ACCESS_CMD = 0x88, - SET_CALIB_DEFAULT_CMD = 0x8e, - BEACON_NOTIFICATION = 0x90, /** * @BEACON_TEMPLATE_CMD: @@ -364,8 +361,6 @@ enum iwl_legacy_cmds { */ REDUCE_TX_POWER_CMD = 0x9f, - /* RF-KILL commands and notifications */ - CARD_STATE_CMD = 0xa0, CARD_STATE_NOTIFICATION = 0xa1, MISSED_BEACONS_NOTIFICATION = 0xa2, @@ -411,9 +406,6 @@ enum iwl_legacy_cmds { MARKER_CMD = 0xcb, - /* BT Coex */ - BT_COEX_PRIO_TABLE = 0xcc, - BT_COEX_PROT_ENV = 0xcd, /** * @BT_PROFILE_NOTIFICATION: &struct iwl_bt_coex_profile_notif */ @@ -422,7 +414,6 @@ enum iwl_legacy_cmds { * @BT_CONFIG: &struct iwl_bt_coex_cmd */ BT_CONFIG = 0x9b, - BT_COEX_UPDATE_SW_BOOST = 0x5a, BT_COEX_UPDATE_CORUN_LUT = 0x5b, BT_COEX_UPDATE_REDUCED_TXP = 0x5c, /** @@ -439,11 +430,8 @@ enum iwl_legacy_cmds { */ REPLY_BEACON_FILTERING_CMD = 0xd2, - /* DTS measurements */ - CMD_DTS_MEASUREMENT_TRIGGER = 0xdc, DTS_MEASUREMENT_NOTIFICATION = 0xdd, - REPLY_DEBUG_CMD = 0xf0, LDBG_CONFIG_CMD = 0xf6, DEBUG_LOG_MSG = 0xf7, @@ -484,12 +472,9 @@ enum iwl_legacy_cmds { * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status */ WOWLAN_GET_STATUSES = 0xe5, - WOWLAN_TX_POWER_PER_DB = 0xe6, /* and for NetDetect */ SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, - SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD = 0x58, - SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD = 0x59, }; /* Please keep this enum *SORTED* by hex value. @@ -1580,19 +1565,6 @@ struct iwl_mfu_assert_dump_notif { __le32 data[0]; } __packed; /*MFU_DUMP_ASSERT_API_S_VER_1*/ -/** - * struct iwl_set_calib_default_cmd - set default value for calibration. - * ( SET_CALIB_DEFAULT_CMD = 0x8e ) - * @calib_index: the calibration to set value for - * @length: of data - * @data: the value to set for the calibration result - */ -struct iwl_set_calib_default_cmd { - __le16 calib_index; - __le16 length; - u8 data[0]; -} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ - #define MAX_PORT_ID_NUM 2 #define MAX_MCAST_FILTERING_ADDRESSES 256 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 2e4bfe9f07ec..695d1aead89f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -357,9 +357,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(SCAN_OFFLOAD_ABORT_CMD), HCMD_NAME(HOT_SPOT_CMD), HCMD_NAME(SCAN_OFFLOAD_PROFILES_QUERY_CMD), - HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD), - HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD), - HCMD_NAME(BT_COEX_UPDATE_SW_BOOST), HCMD_NAME(BT_COEX_UPDATE_CORUN_LUT), HCMD_NAME(BT_COEX_UPDATE_REDUCED_TXP), HCMD_NAME(BT_COEX_CI), @@ -368,13 +365,11 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(PHY_DB_CMD), HCMD_NAME(SCAN_OFFLOAD_COMPLETE), HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), - HCMD_NAME(SCAN_OFFLOAD_CONFIG_CMD), HCMD_NAME(POWER_TABLE_CMD), HCMD_NAME(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), HCMD_NAME(REPLY_THERMAL_MNG_BACKOFF), HCMD_NAME(DC2DC_CONFIG_CMD), HCMD_NAME(NVM_ACCESS_CMD), - HCMD_NAME(SET_CALIB_DEFAULT_CMD), HCMD_NAME(BEACON_NOTIFICATION), HCMD_NAME(BEACON_TEMPLATE_CMD), HCMD_NAME(TX_ANT_CONFIGURATION_CMD), @@ -383,7 +378,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(STATISTICS_NOTIFICATION), HCMD_NAME(EOSP_NOTIFICATION), HCMD_NAME(REDUCE_TX_POWER_CMD), - HCMD_NAME(CARD_STATE_CMD), HCMD_NAME(CARD_STATE_NOTIFICATION), HCMD_NAME(MISSED_BEACONS_NOTIFICATION), HCMD_NAME(TDLS_CONFIG_CMD), @@ -398,8 +392,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(MCC_UPDATE_CMD), HCMD_NAME(MCC_CHUB_UPDATE_CMD), HCMD_NAME(MARKER_CMD), - HCMD_NAME(BT_COEX_PRIO_TABLE), - HCMD_NAME(BT_COEX_PROT_ENV), HCMD_NAME(BT_PROFILE_NOTIFICATION), HCMD_NAME(BCAST_FILTER_CMD), HCMD_NAME(MCAST_FILTER_CMD), @@ -410,7 +402,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(OFFLOADS_QUERY_CMD), HCMD_NAME(REMOTE_WAKE_CONFIG_CMD), HCMD_NAME(MATCH_FOUND_NOTIFICATION), - HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER), HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION), HCMD_NAME(WOWLAN_PATTERNS), HCMD_NAME(WOWLAN_CONFIGURATION), @@ -418,11 +409,9 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(WOWLAN_TKIP_PARAM), HCMD_NAME(WOWLAN_KEK_KCK_MATERIAL), HCMD_NAME(WOWLAN_GET_STATUSES), - HCMD_NAME(WOWLAN_TX_POWER_PER_DB), HCMD_NAME(SCAN_ITERATION_COMPLETE), HCMD_NAME(D0I3_END_CMD), HCMD_NAME(LTR_CONFIG), - HCMD_NAME(REPLY_DEBUG_CMD), }; /* Please keep this array *SORTED* by hex value. -- cgit v1.2.3 From cecb43c7b5e68924a57e09bba9290907defc2308 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 May 2017 15:12:14 +0200 Subject: iwlwifi: mvm: use __le16 even for reserved fields Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index 02c321738e1e..39b6f592a004 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -569,7 +569,7 @@ struct iwl_mvm_pm_state_notification { u8 sta_id; u8 type; /* private: */ - u16 reserved; + __le16 reserved; } __packed; /* PEER_PM_NTFY_API_S_VER_1 */ #endif /* __fw_api_rx_h__ */ -- cgit v1.2.3 From 358631bf444547d476476cb90c8fc78962a81884 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 May 2017 15:14:19 +0200 Subject: iwlwifi: mvm: add documentation for all command IDs Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h | 24 ++ drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c | 18 -- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 276 ++++++++++++++++++++- 4 files changed, 292 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h index a004409fa984..0e107f916ce3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h @@ -202,4 +202,28 @@ struct iwl_tx_queue_cfg_rsp { __le16 reserved; } __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ +/** + * struct iwl_calib_res_notif_phy_db - Receive phy db chunk after calibrations + * @type: type of the result - mostly ignored + * @length: length of the data + * @data: data, length in @length + */ +struct iwl_calib_res_notif_phy_db { + __le16 type; + __le16 length; + u8 data[]; +} __packed; + +/** + * struct iwl_phy_db_cmd - configure operational ucode + * @type: type of the data + * @length: length of the data + * @data: data, length in @length + */ +struct iwl_phy_db_cmd { + __le16 type; + __le16 length; + u8 data[]; +} __packed; + #endif /* __iwl_fw_api_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c index 2893826d7d2b..b7cd813ba70f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c @@ -112,30 +112,12 @@ enum iwl_phy_db_section_type { #define PHY_DB_CMD 0x6c -/* - * phy db - configure operational ucode - */ -struct iwl_phy_db_cmd { - __le16 type; - __le16 length; - u8 data[]; -} __packed; - /* for parsing of tx power channel group data that comes from the firmware*/ struct iwl_phy_db_chg_txp { __le32 space; __le16 max_channel_idx; } __packed; -/* - * phy db - Receive phy db chunk after calibrations - */ -struct iwl_calib_res_notif_phy_db { - __le16 type; - __le16 length; - u8 data[]; -} __packed; - struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans) { struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 4a6b919f13de..9d2a991221cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -595,6 +595,7 @@ struct iwl_mvm_tx_resp_v3 { * @ra_tid: bits [3:0] = ra, bits [7:4] = tid * @frame_ctrl: frame control * @tx_queue: TX queue for this response + * @reserved2: reserved for padding/alignment * @status: for non-agg: frame status TX_STATUS_* * For version 6 TX response isn't received for aggregation at all. * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 60f86997f8cf..89e5ba3f4e42 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -185,7 +185,15 @@ enum iwl_legacy_cmds { * uses &struct iwl_scan_config_v1 or &struct iwl_scan_config */ SCAN_CFG_CMD = 0xc, + + /** + * @SCAN_REQ_UMAC: uses &struct iwl_scan_req_umac + */ SCAN_REQ_UMAC = 0xd, + + /** + * @SCAN_ABORT_UMAC: uses &struct iwl_umac_scan_abort + */ SCAN_ABORT_UMAC = 0xe, /** @@ -193,6 +201,10 @@ enum iwl_legacy_cmds { */ SCAN_COMPLETE_UMAC = 0xf, + /** + * @BA_WINDOW_STATUS_NOTIFICATION_ID: + * uses &struct iwl_ba_window_status_notif + */ BA_WINDOW_STATUS_NOTIFICATION_ID = 0x13, /** @@ -207,12 +219,15 @@ enum iwl_legacy_cmds { * &struct iwl_mvm_add_sta_cmd or &struct iwl_mvm_add_sta_cmd_v7. */ ADD_STA = 0x18, + /** * @REMOVE_STA: &struct iwl_mvm_rm_sta_cmd */ REMOVE_STA = 0x19, - /* paging get item */ + /** + * @FW_GET_ITEM_CMD: uses &struct iwl_fw_get_item_cmd + */ FW_GET_ITEM_CMD = 0x1a, /** @@ -242,15 +257,33 @@ enum iwl_legacy_cmds { */ SCD_QUEUE_CFG = 0x1d, - /* global key */ + /** + * @WEP_KEY: uses &struct iwl_mvm_wep_key_cmd + */ WEP_KEY = 0x20, - /* Memory */ + /** + * @SHARED_MEM_CFG: + * retrieve shared memory configuration - response in + * &struct iwl_shared_mem_cfg + */ SHARED_MEM_CFG = 0x25, - /* TDLS */ + /** + * @TDLS_CHANNEL_SWITCH_CMD: uses &struct iwl_tdls_channel_switch_cmd + */ TDLS_CHANNEL_SWITCH_CMD = 0x27, + + /** + * @TDLS_CHANNEL_SWITCH_NOTIFICATION: + * uses &struct iwl_tdls_channel_switch_notif + */ TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa, + + /** + * @TDLS_CONFIG_CMD: + * &struct iwl_tdls_config_cmd, response in &struct iwl_tdls_config_res + */ TDLS_CONFIG_CMD = 0xa7, /** @@ -263,19 +296,27 @@ enum iwl_legacy_cmds { * &struct iwl_time_event_cmd, response in &struct iwl_time_event_resp */ TIME_EVENT_CMD = 0x29, /* both CMD and response */ + /** * @TIME_EVENT_NOTIFICATION: &struct iwl_time_event_notif */ TIME_EVENT_NOTIFICATION = 0x2a, + /** * @BINDING_CONTEXT_CMD: * &struct iwl_binding_cmd or &struct iwl_binding_cmd_v1 */ BINDING_CONTEXT_CMD = 0x2b, + /** * @TIME_QUOTA_CMD: &struct iwl_time_quota_cmd */ TIME_QUOTA_CMD = 0x2c, + + /** + * @NON_QOS_TX_COUNTER_CMD: + * command is &struct iwl_nonqos_seq_query_cmd + */ NON_QOS_TX_COUNTER_CMD = 0x2d, /** @@ -289,13 +330,42 @@ enum iwl_legacy_cmds { */ FW_PAGING_BLOCK_CMD = 0x4f, - /* Scan offload */ + /** + * @SCAN_OFFLOAD_REQUEST_CMD: uses &struct iwl_scan_req_lmac + */ SCAN_OFFLOAD_REQUEST_CMD = 0x51, + + /** + * @SCAN_OFFLOAD_ABORT_CMD: abort the scan - no further contents + */ SCAN_OFFLOAD_ABORT_CMD = 0x52, + + /** + * @HOT_SPOT_CMD: uses &struct iwl_hs20_roc_req + */ HOT_SPOT_CMD = 0x53, + + /** + * @SCAN_OFFLOAD_COMPLETE: + * notification, &struct iwl_periodic_scan_complete + */ SCAN_OFFLOAD_COMPLETE = 0x6D, + + /** + * @SCAN_OFFLOAD_UPDATE_PROFILES_CMD: + * update scan offload (scheduled scan) profiles/blacklist/etc. + */ SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, + + /** + * @MATCH_FOUND_NOTIFICATION: scan match found + */ MATCH_FOUND_NOTIFICATION = 0xd9, + + /** + * @SCAN_ITERATION_COMPLETE: + * uses &struct iwl_lmac_scan_complete_notif + */ SCAN_ITERATION_COMPLETE = 0xe7, /* Phy */ @@ -303,24 +373,55 @@ enum iwl_legacy_cmds { * @PHY_CONFIGURATION_CMD: &struct iwl_phy_cfg_cmd */ PHY_CONFIGURATION_CMD = 0x6a, + + /** + * @CALIB_RES_NOTIF_PHY_DB: &struct iwl_calib_res_notif_phy_db + */ CALIB_RES_NOTIF_PHY_DB = 0x6b, + + /** + * @PHY_DB_CMD: &struct iwl_phy_db_cmd + */ PHY_DB_CMD = 0x6c, - /* ToF - 802.11mc FTM */ + /** + * @TOF_CMD: &struct iwl_tof_config_cmd + */ TOF_CMD = 0x10, + + /** + * @TOF_NOTIFICATION: &struct iwl_tof_gen_resp_cmd + */ TOF_NOTIFICATION = 0x11, /** * @POWER_TABLE_CMD: &struct iwl_device_power_cmd */ POWER_TABLE_CMD = 0x77, + + /** + * @PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION: + * &struct iwl_uapsd_misbehaving_ap_notif + */ PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, + + /** + * @LTR_CONFIG: &struct iwl_ltr_config_cmd + */ LTR_CONFIG = 0xee, - /* Thermal Throttling*/ + /** + * @REPLY_THERMAL_MNG_BACKOFF: + * Thermal throttling command + */ REPLY_THERMAL_MNG_BACKOFF = 0x7e, - /* Set/Get DC2DC frequency tune */ + /** + * @DC2DC_CONFIG_CMD: + * Set/Get DC2DC frequency tune + * Command is &struct iwl_dc2dc_config_cmd, + * response is &struct iwl_dc2dc_config_resp + */ DC2DC_CONFIG_CMD = 0x83, /** @@ -328,7 +429,11 @@ enum iwl_legacy_cmds { */ NVM_ACCESS_CMD = 0x88, + /** + * @BEACON_NOTIFICATION: &struct iwl_extended_beacon_notif + */ BEACON_NOTIFICATION = 0x90, + /** * @BEACON_TEMPLATE_CMD: * Uses one of &struct iwl_mac_beacon_cmd_v6, @@ -353,6 +458,12 @@ enum iwl_legacy_cmds { * &struct iwl_notif_statistics_cdb */ STATISTICS_NOTIFICATION = 0x9d, + + /** + * @EOSP_NOTIFICATION: + * Notify that a service period ended, + * &struct iwl_mvm_eosp_notification + */ EOSP_NOTIFICATION = 0x9e, /** @@ -361,8 +472,16 @@ enum iwl_legacy_cmds { */ REDUCE_TX_POWER_CMD = 0x9f, + /** + * @CARD_STATE_NOTIFICATION: + * Card state (RF/CT kill) notification, + * uses &struct iwl_card_state_notif + */ CARD_STATE_NOTIFICATION = 0xa1, + /** + * @MISSED_BEACONS_NOTIFICATION: &struct iwl_missed_beacons_notif + */ MISSED_BEACONS_NOTIFICATION = 0xa2, /** @@ -390,7 +509,19 @@ enum iwl_legacy_cmds { * &struct iwl_rx_mpdu_res_start or &struct iwl_rx_mpdu_desc */ REPLY_RX_MPDU_CMD = 0xc1, + + /** + * @FRAME_RELEASE: + * Frame release (reorder helper) notification, uses + * &struct iwl_frame_release + */ FRAME_RELEASE = 0xc3, + + /** + * @BA_NOTIF: + * BlockAck notification, uses &struct iwl_mvm_compressed_ba_notif + * or &struct iwl_mvm_ba_notif depending on the HW + */ BA_NOTIF = 0xc5, /* Location Aware Regulatory */ @@ -404,18 +535,33 @@ enum iwl_legacy_cmds { */ MCC_CHUB_UPDATE_CMD = 0xc9, + /** + * @MARKER_CMD: trace marker command, uses &struct iwl_mvm_marker + */ MARKER_CMD = 0xcb, /** * @BT_PROFILE_NOTIFICATION: &struct iwl_bt_coex_profile_notif */ BT_PROFILE_NOTIFICATION = 0xce, + /** * @BT_CONFIG: &struct iwl_bt_coex_cmd */ BT_CONFIG = 0x9b, + + /** + * @BT_COEX_UPDATE_CORUN_LUT: + * &struct iwl_bt_coex_corun_lut_update_cmd + */ BT_COEX_UPDATE_CORUN_LUT = 0x5b, + + /** + * @BT_COEX_UPDATE_REDUCED_TXP: + * &struct iwl_bt_coex_reduced_txp_update_cmd + */ BT_COEX_UPDATE_REDUCED_TXP = 0x5c, + /** * @BT_COEX_CI: &struct iwl_bt_coex_ci_cmd */ @@ -430,21 +576,60 @@ enum iwl_legacy_cmds { */ REPLY_BEACON_FILTERING_CMD = 0xd2, + /** + * @DTS_MEASUREMENT_NOTIFICATION: + * &struct iwl_dts_measurement_notif_v1 or + * &struct iwl_dts_measurement_notif_v2 + */ DTS_MEASUREMENT_NOTIFICATION = 0xdd, + /** + * @LDBG_CONFIG_CMD: configure continuous trace recording + */ LDBG_CONFIG_CMD = 0xf6, + + /** + * @DEBUG_LOG_MSG: Debugging log data from firmware + */ DEBUG_LOG_MSG = 0xf7, + /** + * @BCAST_FILTER_CMD: &struct iwl_bcast_filter_cmd + */ BCAST_FILTER_CMD = 0xcf, + + /** + * @MCAST_FILTER_CMD: &struct iwl_mcast_filter_cmd + */ MCAST_FILTER_CMD = 0xd0, /** * @D3_CONFIG_CMD: &struct iwl_d3_manager_config */ D3_CONFIG_CMD = 0xd3, + + /** + * @PROT_OFFLOAD_CONFIG_CMD: Depending on firmware, uses one of + * &struct iwl_proto_offload_cmd_v1, &struct iwl_proto_offload_cmd_v2, + * &struct iwl_proto_offload_cmd_v3_small, + * &struct iwl_proto_offload_cmd_v3_large + */ PROT_OFFLOAD_CONFIG_CMD = 0xd4, + + /** + * @OFFLOADS_QUERY_CMD: + * No data in command, response in &struct iwl_wowlan_status + */ OFFLOADS_QUERY_CMD = 0xd5, + + /** + * @REMOTE_WAKE_CONFIG_CMD: &struct iwl_wowlan_remote_wake_config + */ REMOTE_WAKE_CONFIG_CMD = 0xd6, + + /** + * @D0I3_END_CMD: End D0i3/D3 state, no command data + */ D0I3_END_CMD = 0xed, /** @@ -456,24 +641,31 @@ enum iwl_legacy_cmds { * @WOWLAN_CONFIGURATION: &struct iwl_wowlan_config_cmd */ WOWLAN_CONFIGURATION = 0xe1, + /** * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd */ WOWLAN_TSC_RSC_PARAM = 0xe2, + /** * @WOWLAN_TKIP_PARAM: &struct iwl_wowlan_tkip_params_cmd */ WOWLAN_TKIP_PARAM = 0xe3, + /** * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd */ WOWLAN_KEK_KCK_MATERIAL = 0xe4, + /** * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status */ WOWLAN_GET_STATUSES = 0xe5, - /* and for NetDetect */ + /** + * @SCAN_OFFLOAD_PROFILES_QUERY_CMD: + * No command data, response is &struct iwl_scan_offload_profiles_query + */ SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, }; @@ -490,15 +682,38 @@ enum iwl_mac_conf_subcmd_ids { * enum iwl_phy_ops_subcmd_ids - PHY group commands */ enum iwl_phy_ops_subcmd_ids { + /** + * @CMD_DTS_MEASUREMENT_TRIGGER_WIDE: + * Uses either &struct iwl_dts_measurement_cmd or + * &struct iwl_ext_dts_measurement_cmd + */ CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, + + /** + * @CTDP_CONFIG_CMD: &struct iwl_mvm_ctdp_cmd + */ CTDP_CONFIG_CMD = 0x03, /** * @TEMP_REPORTING_THRESHOLDS_CMD: &struct temp_report_ths_cmd */ TEMP_REPORTING_THRESHOLDS_CMD = 0x04, + + /** + * @GEO_TX_POWER_LIMIT: &struct iwl_geo_tx_power_profiles_cmd + */ GEO_TX_POWER_LIMIT = 0x05, + + /** + * @CT_KILL_NOTIFICATION: &struct ct_kill_notif + */ CT_KILL_NOTIFICATION = 0xFE, + + /** + * @DTS_MEASUREMENT_NOTIF_WIDE: + * &struct iwl_dts_measurement_notif_v1 or + * &struct iwl_dts_measurement_notif_v2 + */ DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, }; @@ -512,6 +727,10 @@ enum iwl_system_subcmd_ids { * &struct iwl_shared_mem_cfg_v1 */ SHARED_MEM_CFG_CMD = 0x0, + + /** + * @INIT_EXTENDED_CFG_CMD: &struct iwl_init_extended_cfg_cmd + */ INIT_EXTENDED_CFG_CMD = 0x03, }; @@ -523,19 +742,57 @@ enum iwl_data_path_subcmd_ids { * @DQA_ENABLE_CMD: &struct iwl_dqa_enable_cmd */ DQA_ENABLE_CMD = 0x0, + + /** + * @UPDATE_MU_GROUPS_CMD: &struct iwl_mu_group_mgmt_cmd + */ UPDATE_MU_GROUPS_CMD = 0x1, + + /** + * @TRIGGER_RX_QUEUES_NOTIF_CMD: &struct iwl_rxq_sync_cmd + */ TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2, + + /** + * @STA_PM_NOTIF: &struct iwl_mvm_pm_state_notification + */ STA_PM_NOTIF = 0xFD, + + /** + * @MU_GROUP_MGMT_NOTIF: &struct iwl_mu_group_mgmt_notif + */ MU_GROUP_MGMT_NOTIF = 0xFE, + + /** + * @RX_QUEUES_NOTIFICATION: &struct iwl_rxq_sync_notification + */ RX_QUEUES_NOTIFICATION = 0xFF, }; +/** + * enum iwl_prot_offload_subcmd_ids - protocol offload commands + */ enum iwl_prot_offload_subcmd_ids { + /** + * @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif + */ STORED_BEACON_NTF = 0xFF, }; +/** + * enum iwl_regulatory_and_nvm_subcmd_ids - regulatory/NVM commands + */ enum iwl_regulatory_and_nvm_subcmd_ids { + /** + * @NVM_ACCESS_COMPLETE: &struct iwl_nvm_access_complete_cmd + */ NVM_ACCESS_COMPLETE = 0x0, + + /** + * @NVM_GET_INFO: + * Command is &struct iwl_nvm_get_info, + * response is &struct iwl_nvm_get_info_rsp + */ NVM_GET_INFO = 0x2, }; @@ -2605,6 +2862,7 @@ struct iwl_nvm_get_info_phy { * struct iwl_nvm_get_info_regulatory - regulatory information * @lar_enabled: is LAR enabled * @channel_profile: regulatory data of this channel + * @reserved: reserved */ struct iwl_nvm_get_info_regulatory { __le32 lar_enabled; -- cgit v1.2.3 From acf91dda3f64bedb4abc46d87b35d41c36a4a28d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 May 2017 16:15:42 +0200 Subject: iwlwifi: mvm: fix a bunch of kernel-doc warnings Fix the kernel-doc, and remove some fields even the firmware doesn't use in ToF, RX, scan, station and generic FW APIS. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/fw-api-coex.h | 11 ++-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h | 5 ++ .../net/wireless/intel/iwlwifi/mvm/fw-api-mac.h | 2 + drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h | 3 ++ drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h | 33 ++++++------ .../net/wireless/intel/iwlwifi/mvm/fw-api-scan.h | 28 ++++++---- .../net/wireless/intel/iwlwifi/mvm/fw-api-sta.h | 63 ++++++++++++++++------ .../net/wireless/intel/iwlwifi/mvm/fw-api-tof.h | 14 +++-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 26 ++++++--- 9 files changed, 127 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h index c432fdb98630..8cd06aaa1f54 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h @@ -7,6 +7,7 @@ * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -132,10 +134,10 @@ struct iwl_bt_coex_reduced_txp_update_cmd { /** * struct iwl_bt_coex_ci_cmd - bt coex channel inhibition command - * @bt_primary_ci: - * @primary_ch_phy_id: - * @bt_secondary_ci: - * @secondary_ch_phy_id: + * @bt_primary_ci: primary channel inhibition bitmap + * @primary_ch_phy_id: primary channel PHY ID + * @bt_secondary_ci: secondary channel inhibition bitmap + * @secondary_ch_phy_id: secondary channel PHY ID * * Used for BT_COEX_CI command */ @@ -238,6 +240,7 @@ enum iwl_bt_ci_compliance { * @secondary_ch_lut: LUT used for secondary channel &enum iwl_bt_coex_lut_type * @bt_activity_grading: the activity of BT &enum iwl_bt_activity_grading * @ttc_rrc_status: is TTC or RRC enabled - one bit per PHY + * @reserved: reserved */ struct iwl_bt_coex_profile_notif { __le32 mbox_msg[4]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h index 2bfe4de6ac5a..d4a4c28b7192 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h @@ -139,6 +139,7 @@ struct iwl_proto_offload_cmd_common { * for each target address * @target_ipv6_addr: our target addresses * @ndp_mac_addr: neighbor solicitation response MAC address + * @reserved2: reserved */ struct iwl_proto_offload_cmd_v1 { struct iwl_proto_offload_cmd_common common; @@ -157,6 +158,8 @@ struct iwl_proto_offload_cmd_v1 { * for each target address * @target_ipv6_addr: our target addresses * @ndp_mac_addr: neighbor solicitation response MAC address + * @num_valid_ipv6_addrs: number of valid IPv6 addresses + * @reserved2: reserved */ struct iwl_proto_offload_cmd_v2 { struct iwl_proto_offload_cmd_common common; @@ -183,6 +186,7 @@ struct iwl_targ_addr { /** * struct iwl_proto_offload_cmd_v3_small - ARP/NS offload configuration * @common: common/IPv4 configuration + * @num_valid_ipv6_addrs: number of valid IPv6 addresses * @targ_addrs: target IPv6 addresses * @ns_config: NS offload configurations */ @@ -196,6 +200,7 @@ struct iwl_proto_offload_cmd_v3_small { /** * struct iwl_proto_offload_cmd_v3_large - ARP/NS offload configuration * @common: common/IPv4 configuration + * @num_valid_ipv6_addrs: number of valid IPv6 addresses * @targ_addrs: target IPv6 addresses * @ns_config: NS offload configurations */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h index 932adaf575eb..0c3350ad2f2f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h @@ -333,7 +333,9 @@ struct iwl_ac_qos { * @mac_type: one of &enum iwl_mac_types * @tsf_id: TSF HW timer, one of &enum iwl_tsf_id * @node_addr: MAC address + * @reserved_for_node_addr: reserved * @bssid_addr: BSSID + * @reserved_for_bssid_addr: reserved * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM * @protection_flags: combination of &enum iwl_mac_protection_flags diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h index 1e34e41f52bc..bdf1228d050b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h @@ -368,6 +368,7 @@ enum { /** * struct iwl_lq_cmd - link quality command * @sta_id: station to update + * @reduced_tpc: reduced transmit power control value * @control: not used * @flags: combination of LQ_FLAG_* * @mimo_delim: the first SISO index in rs_table, which separates MIMO @@ -385,6 +386,7 @@ enum { * 0: no limit * 1: no aggregation (one frame per aggregation) * 2 - 0x3f: maximal number of frames (up to 3f == 63) + * @reserved2: reserved * @rs_table: array of rates for each TX try, each is rate_n_flags, * meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP * @ss_params: single stream features. declare whether STBC or BFER are allowed. @@ -407,4 +409,5 @@ struct iwl_lq_cmd { __le32 rs_table[LQ_MAX_RETRY_NUM]; __le32 ss_params; }; /* LINK_QUALITY_CMD_API_S_VER_1 */ + #endif /* __fw_api_rs_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h index 39b6f592a004..59038ade08d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h @@ -90,7 +90,7 @@ enum iwl_mac_context_info { * @non_cfg_phy_cnt: non configurable DSP phy data byte count * @cfg_phy_cnt: configurable DSP phy data byte count * @stat_id: configurable DSP phy data set ID - * @reserved1: + * @reserved1: reserved * @system_timestamp: GP2 at on air rise * @timestamp: TSF at on air rise * @beacon_time_stamp: beacon at on-air rise @@ -158,10 +158,11 @@ struct iwl_rx_mpdu_res_start { /** * enum iwl_rx_phy_flags - to parse %iwl_rx_phy_info phy_flags * @RX_RES_PHY_FLAGS_BAND_24: true if the packet was received on 2.4 band - * @RX_RES_PHY_FLAGS_MOD_CCK: + * @RX_RES_PHY_FLAGS_MOD_CCK: modulation is CCK * @RX_RES_PHY_FLAGS_SHORT_PREAMBLE: true if packet's preamble was short - * @RX_RES_PHY_FLAGS_NARROW_BAND: + * @RX_RES_PHY_FLAGS_NARROW_BAND: narrow band (<20 MHz) receive * @RX_RES_PHY_FLAGS_ANTENNA: antenna on which the packet was received + * @RX_RES_PHY_FLAGS_ANTENNA_POS: antenna bit position * @RX_RES_PHY_FLAGS_AGG: set if the packet was part of an A-MPDU * @RX_RES_PHY_FLAGS_OFDM_HT: The frame was an HT frame * @RX_RES_PHY_FLAGS_OFDM_GF: The frame used GF preamble @@ -184,9 +185,9 @@ enum iwl_rx_phy_flags { * enum iwl_mvm_rx_status - written by fw for each Rx packet * @RX_MPDU_RES_STATUS_CRC_OK: CRC is fine * @RX_MPDU_RES_STATUS_OVERRUN_OK: there was no RXE overflow - * @RX_MPDU_RES_STATUS_SRC_STA_FOUND: - * @RX_MPDU_RES_STATUS_KEY_VALID: - * @RX_MPDU_RES_STATUS_KEY_PARAM_OK: + * @RX_MPDU_RES_STATUS_SRC_STA_FOUND: station was found + * @RX_MPDU_RES_STATUS_KEY_VALID: key was valid + * @RX_MPDU_RES_STATUS_KEY_PARAM_OK: key parameters were usable * @RX_MPDU_RES_STATUS_ICV_OK: ICV is fine, if not, the packet is destroyed * @RX_MPDU_RES_STATUS_MIC_OK: used for CCM alg only. TKIP MIC is checked * in the driver. @@ -198,21 +199,21 @@ enum iwl_rx_phy_flags { * @RX_MPDU_RES_STATUS_SEC_WEP_ENC: this frame is encrypted using WEP * @RX_MPDU_RES_STATUS_SEC_CCM_ENC: this frame is encrypted using CCM * @RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP + * @RX_MPDU_RES_STATUS_SEC_EXT_ENC: this frame is encrypted using extension + * algorithm * @RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC * @RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted * @RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm * @RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted - * @RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP: - * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: - * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: + * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: extended IV (set with TKIP) + * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: key ID comparison done * @RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame * @RX_MPDU_RES_STATUS_CSUM_DONE: checksum was done by the hw * @RX_MPDU_RES_STATUS_CSUM_OK: checksum found no errors - * @RX_MPDU_RES_STATUS_HASH_INDEX_MSK: - * @RX_MPDU_RES_STATUS_STA_ID_MSK: - * @RX_MPDU_RES_STATUS_RRF_KILL: - * @RX_MPDU_RES_STATUS_FILTERING_MSK: - * @RX_MPDU_RES_STATUS2_FILTERING_MSK: + * @RX_MPDU_RES_STATUS_STA_ID_MSK: station ID mask + * @RX_MDPU_RES_STATUS_STA_ID_SHIFT: station ID bit shift + * @RX_MPDU_RES_STATUS_FILTERING_MSK: filter status + * @RX_MPDU_RES_STATUS2_FILTERING_MSK: filter status 2 */ enum iwl_mvm_rx_status { RX_MPDU_RES_STATUS_CRC_OK = BIT(0), @@ -233,16 +234,13 @@ enum iwl_mvm_rx_status { RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8), RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8), RX_MPDU_RES_STATUS_DEC_DONE = BIT(11), - RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP = BIT(12), RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP = BIT(13), RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT = BIT(14), RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME = BIT(15), RX_MPDU_RES_STATUS_CSUM_DONE = BIT(16), RX_MPDU_RES_STATUS_CSUM_OK = BIT(17), - RX_MPDU_RES_STATUS_HASH_INDEX_MSK = (0x3F0000), RX_MDPU_RES_STATUS_STA_ID_SHIFT = 24, RX_MPDU_RES_STATUS_STA_ID_MSK = 0x1f << RX_MDPU_RES_STATUS_STA_ID_SHIFT, - RX_MPDU_RES_STATUS_RRF_KILL = BIT(29), RX_MPDU_RES_STATUS_FILTERING_MSK = (0xc00000), RX_MPDU_RES_STATUS2_FILTERING_MSK = (0xc0000000), }; @@ -476,6 +474,7 @@ enum iwl_rss_hash_func_en { * * @flags: 1 - enable, 0 - disable * @hash_mask: Type of RSS to use. Values are from %iwl_rss_hash_func_en + * @reserved: reserved * @secret_key: 320 bit input of random key configuration from driver * @indirection_table: indirection table */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h index e752359841b8..1cd7cc087936 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h @@ -80,6 +80,10 @@ * selected by "type" bit field in struct iwl_scan_channel; * each channel may select different ssids from among the 20 entries. * SSID IEs get transmitted in reverse order of entry. + * + * @id: element ID + * @len: element length + * @ssid: element (SSID) data */ struct iwl_ssid_ie { u8 id; @@ -141,6 +145,7 @@ enum iwl_scan_offload_band_selection { * @network_type: enum iwl_scan_offload_network_type * @band_selection: enum iwl_scan_offload_band_selection * @client_bitmap: clients waiting for match - enum scan_framework_client + * @reserved: reserved */ struct iwl_scan_offload_profile { u8 ssid_index; @@ -161,6 +166,7 @@ struct iwl_scan_offload_profile { * @pass_match: clients waiting for the results * @active_clients: active clients bitmap - enum scan_framework_client * @any_beacon_notify: clients waiting for match notification without match + * @reserved: reserved */ struct iwl_scan_offload_profile_cfg { struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES]; @@ -280,7 +286,7 @@ struct iwl_scan_channel_opt { * @IWL_MVM_LMAC_SCAN_FLAG_PASSIVE: force passive scan on all channels * @IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION: single channel scan * @IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification - * @IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching + * @IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS: multiple SSID matching * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented * @IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report * and DS parameter set IEs into probe requests. @@ -321,9 +327,9 @@ enum iwl_scan_priority_ext { * struct iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1 * @reserved1: for alignment and future use * @n_channels: num of channels to scan - * @active-dwell: dwell time for active channels - * @passive-dwell: dwell time for passive channels - * @fragmented-dwell: dwell time for fragmented passive scan + * @active_dwell: dwell time for active channels + * @passive_dwell: dwell time for passive channels + * @fragmented_dwell: dwell time for fragmented passive scan * @extended_dwell: dwell time for channels 1, 6 and 11 (in certain cases) * @reserved2: for alignment and future use * @rx_chain_select: PHY_RX_CHAIN_* flags @@ -411,9 +417,10 @@ struct iwl_lmac_scan_complete_notif { * struct iwl_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 * @last_schedule_line: last schedule line executed (fast or regular) * @last_schedule_iteration: last scan iteration executed before scan abort - * @status: enum iwl_scan_offload_complete_status + * @status: &enum iwl_scan_offload_complete_status * @ebs_status: EBS success status &enum iwl_scan_ebs_status - * @time_after_last_iter; time in seconds elapsed after last iteration + * @time_after_last_iter: time in seconds elapsed after last iteration + * @reserved: reserved */ struct iwl_periodic_scan_complete { u8 last_schedule_line; @@ -699,8 +706,8 @@ struct iwl_umac_scan_abort { * struct iwl_umac_scan_complete * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @last_schedule: last scheduling line - * @last_iter: last scan iteration number - * @scan status: &enum iwl_scan_offload_complete_status + * @last_iter: last scan iteration number + * @status: &enum iwl_scan_offload_complete_status * @ebs_status: &enum iwl_scan_ebs_status * @time_from_last_iter: time elapsed from last iteration * @reserved: for future use @@ -719,9 +726,10 @@ struct iwl_umac_scan_complete { /** * struct iwl_scan_offload_profile_match - match information * @bssid: matched bssid + * @reserved: reserved * @channel: channel where the match occurred - * @energy: - * @matching_feature: + * @energy: energy + * @matching_feature: feature matches * @matching_channels: bitmap of channels that matched, referencing * the channels passed in tue scan offload request */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index c14ebd7ff77d..81f0a3463bac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -69,8 +69,8 @@ /** * enum iwl_sta_flags - flags for the ADD_STA host command - * @STA_FLG_REDUCED_TX_PWR_CTRL: - * @STA_FLG_REDUCED_TX_PWR_DATA: + * @STA_FLG_REDUCED_TX_PWR_CTRL: reduced TX power (control frames) + * @STA_FLG_REDUCED_TX_PWR_DATA: reduced TX power (data frames) * @STA_FLG_DISABLE_TX: set if TX should be disabled * @STA_FLG_PS: set if STA is in Power Save * @STA_FLG_INVALID: set if STA is invalid @@ -78,18 +78,40 @@ * @STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs * @STA_FLG_DRAIN_FLOW: drain flow * @STA_FLG_PAN: STA is for PAN interface - * @STA_FLG_CLASS_AUTH: - * @STA_FLG_CLASS_ASSOC: - * @STA_FLG_CLASS_MIMO_PROT: - * @STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU + * @STA_FLG_CLASS_AUTH: station is authenticated + * @STA_FLG_CLASS_ASSOC: station is associated + * @STA_FLG_RTS_MIMO_PROT: station requires RTS MIMO protection (dynamic SMPS) + * @STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU (mask) + * @STA_FLG_MAX_AGG_SIZE_SHIFT: maximal size for A-MPDU (bit shift) + * @STA_FLG_MAX_AGG_SIZE_8K: maximal size for A-MPDU (8k supported) + * @STA_FLG_MAX_AGG_SIZE_16K: maximal size for A-MPDU (16k supported) + * @STA_FLG_MAX_AGG_SIZE_32K: maximal size for A-MPDU (32k supported) + * @STA_FLG_MAX_AGG_SIZE_64K: maximal size for A-MPDU (64k supported) + * @STA_FLG_MAX_AGG_SIZE_128K: maximal size for A-MPDU (128k supported) + * @STA_FLG_MAX_AGG_SIZE_256K: maximal size for A-MPDU (256k supported) + * @STA_FLG_MAX_AGG_SIZE_512K: maximal size for A-MPDU (512k supported) + * @STA_FLG_MAX_AGG_SIZE_1024K: maximal size for A-MPDU (1024k supported) * @STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation * @STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is * initialised by driver and can be updated by fw upon reception of * action frames that can change the channel width. When cleared the fw * will send all the frames in 20MHz even when FAT channel is requested. + * @STA_FLG_FAT_EN_20MHZ: no wide channels are supported, only 20 MHz + * @STA_FLG_FAT_EN_40MHZ: wide channels up to 40 MHz supported + * @STA_FLG_FAT_EN_80MHZ: wide channels up to 80 MHz supported + * @STA_FLG_FAT_EN_160MHZ: wide channels up to 160 MHz supported * @STA_FLG_MIMO_EN_MSK: support for MIMO. This flag is initialised by the * driver and can be updated by fw upon reception of action frames. + * @STA_FLG_MIMO_EN_SISO: no support for MIMO + * @STA_FLG_MIMO_EN_MIMO2: 2 streams supported + * @STA_FLG_MIMO_EN_MIMO3: 3 streams supported * @STA_FLG_MFP_EN: Management Frame Protection + * @STA_FLG_AGG_MPDU_DENS_MSK: A-MPDU density (mask) + * @STA_FLG_AGG_MPDU_DENS_SHIFT: A-MPDU density (bit shift) + * @STA_FLG_AGG_MPDU_DENS_2US: A-MPDU density (2 usec gap) + * @STA_FLG_AGG_MPDU_DENS_4US: A-MPDU density (4 usec gap) + * @STA_FLG_AGG_MPDU_DENS_8US: A-MPDU density (8 usec gap) + * @STA_FLG_AGG_MPDU_DENS_16US: A-MPDU density (16 usec gap) */ enum iwl_sta_flags { STA_FLG_REDUCED_TX_PWR_CTRL = BIT(3), @@ -148,9 +170,10 @@ enum iwl_sta_flags { * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from * station info array (1 - n 1X mode) * @STA_KEY_FLG_KEYID_MSK: the index of the key + * @STA_KEY_FLG_KEYID_POS: key index bit position * @STA_KEY_NOT_VALID: key is invalid * @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key - * @STA_KEY_FLG_KEY_32BYTES for non-wep key set for 32 bytes key + * @STA_KEY_FLG_KEY_32BYTES: for non-wep key set for 32 bytes key * @STA_KEY_MULTICAST: set for multical key * @STA_KEY_MFP: key is used for Management Frame Protection */ @@ -183,7 +206,7 @@ enum iwl_sta_key_flag { * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count - * @STA_MODIFY_PROT_TH: + * @STA_MODIFY_PROT_TH: modify RTS threshold * @STA_MODIFY_QUEUES: modify the queues used by this station */ enum iwl_sta_modify_flag { @@ -209,9 +232,9 @@ enum iwl_sta_mode { /** * enum iwl_sta_sleep_flag - type of sleep of the station - * @STA_SLEEP_STATE_AWAKE: - * @STA_SLEEP_STATE_PS_POLL: - * @STA_SLEEP_STATE_UAPSD: + * @STA_SLEEP_STATE_AWAKE: station is awake + * @STA_SLEEP_STATE_PS_POLL: station is PS-polling + * @STA_SLEEP_STATE_UAPSD: station uses U-APSD * @STA_SLEEP_STATE_MOREDATA: set more-data bit on * (last) released frame */ @@ -233,8 +256,10 @@ enum iwl_sta_sleep_flag { * struct iwl_mvm_keyinfo - key information * @key_flags: type &enum iwl_sta_key_flag * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection + * @reserved1: reserved * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx * @key_offset: key offset in the fw's key table + * @reserved2: reserved * @key: 16-byte unicast decryption key * @tx_secur_seq_cnt: initial RSC / PN needed for replay check * @hw_tkip_mic_rx_key: byte: MIC Rx Key - used for TKIP only @@ -262,15 +287,17 @@ struct iwl_mvm_keyinfo { * struct iwl_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) * @add_modify: see &enum iwl_sta_mode - * @awake_acs: + * @awake_acs: ACs to transmit data on while station is sleeping (for U-APSD) * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to, * see &enum iwl_mvm_id_and_color * @addr: station's MAC address + * @reserved2: reserved * @sta_id: index of station in uCode's station table * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. + * @reserved3: reserved * @station_flags: look at &enum iwl_sta_flags * @station_flags_msk: what of %station_flags have changed, * also &enum iwl_sta_flags @@ -341,15 +368,17 @@ enum iwl_sta_type { * struct iwl_mvm_add_sta_cmd - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) * @add_modify: see &enum iwl_sta_mode - * @awake_acs: + * @awake_acs: ACs to transmit data on while station is sleeping (for U-APSD) * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to, * see &enum iwl_mvm_id_and_color * @addr: station's MAC address + * @reserved2: reserved * @sta_id: index of station in uCode's station table * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. + * @reserved3: reserved * @station_flags: look at &enum iwl_sta_flags * @station_flags_msk: what of %station_flags have changed, * also &enum iwl_sta_flags @@ -429,6 +458,7 @@ struct iwl_mvm_add_sta_key_common { * struct iwl_mvm_add_sta_key_cmd_v1 - add/modify sta key * @common: see &struct iwl_mvm_add_sta_key_common * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection + * @reserved: reserved * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx */ struct iwl_mvm_add_sta_key_cmd_v1 { @@ -471,6 +501,7 @@ enum iwl_mvm_add_sta_rsp_status { * struct iwl_mvm_rm_sta_cmd - Add / modify a station in the fw's station table * ( REMOVE_STA = 0x19 ) * @sta_id: the station id of the station to be removed + * @reserved: reserved */ struct iwl_mvm_rm_sta_cmd { u8 sta_id; @@ -481,11 +512,11 @@ struct iwl_mvm_rm_sta_cmd { * struct iwl_mvm_mgmt_mcast_key_cmd_v1 * ( MGMT_MCAST_KEY = 0x1f ) * @ctrl_flags: &enum iwl_sta_key_flag - * @igtk: + * @igtk: IGTK key material * @k1: unused * @k2: unused * @sta_id: station ID that support IGTK - * @key_id: + * @key_id: key ID * @receive_seq_cnt: initial RSC/PN needed for replay check */ struct iwl_mvm_mgmt_mcast_key_cmd_v1 { @@ -504,7 +535,7 @@ struct iwl_mvm_mgmt_mcast_key_cmd_v1 { * @ctrl_flags: &enum iwl_sta_key_flag * @igtk: IGTK master key * @sta_id: station ID that support IGTK - * @key_id: + * @key_id: key ID * @receive_seq_cnt: initial RSC/PN needed for replay check */ struct iwl_mvm_mgmt_mcast_key_cmd { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h index e2acf39f784d..8658a983c463 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -163,6 +163,7 @@ struct iwl_tof_responder_config_cmd { /** * struct iwl_tof_range_request_ext_cmd - extended range req for WLS * @tsf_timer_offset_msec: the recommended time offset (mSec) from the AP's TSF + * @reserved: reserved * @min_delta_ftm: Minimal time between two consecutive measurements, * in units of 100us. 0 means no preference by station * @ftm_format_and_bw20M: FTM Channel Spacing/Format for 20MHz: recommended @@ -272,6 +273,7 @@ enum iwl_tof_response_mode { * '1' Use MAC Address randomization according to the below * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. * Bits set to 1 shall be randomized by the UMAC + * @ap: per-AP request data */ struct iwl_tof_range_req_cmd { __le32 sub_grp_cmd_id; @@ -298,7 +300,9 @@ struct iwl_tof_gen_resp_cmd { /** * struct iwl_tof_range_rsp_ap_entry_ntfy - AP parameters (response) - * @measure_status: current APs measurement status + * @bssid: BSSID of the AP + * @measure_status: current APs measurement status, one of + * &enum iwl_tof_entry_status. * @measure_bw: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz * @rtt: The Round Trip Time that took for the last measurement for * current AP [nSec] @@ -308,6 +312,7 @@ struct iwl_tof_gen_resp_cmd { * @rssi: RSSI as uploaded in the Channel Estimation notification * @rssi_spread: The Difference between the maximum and the minimum RSSI values * measured for current AP in the current session + * @reserved: reserved * @range: Measured range [cm] * @range_variance: Measured range variance [cm] * @timestamp: The GP2 Clock [usec] where Channel Estimation notification was @@ -334,6 +339,7 @@ struct iwl_tof_range_rsp_ap_entry_ntfy { * @request_status: status of current measurement session * @last_in_batch: reprot policy (when not all responses are uploaded at once) * @num_of_aps: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @ap: per-AP data */ struct iwl_tof_range_rsp_ntfy { u8 request_id; @@ -348,6 +354,7 @@ struct iwl_tof_range_rsp_ntfy { * struct iwl_tof_mcsi_notif - used for debug * @token: token ID for the current session * @role: '0' - initiator, '1' - responder + * @reserved: reserved * @initiator_bssid: initiator machine * @responder_bssid: responder machine * @mcsi_buffer: debug data @@ -380,6 +387,7 @@ struct iwl_tof_neighbor_report { /** * struct iwl_tof_range_abort_cmd * @request_id: corresponds to a range request + * @reserved: reserved */ struct iwl_tof_range_abort_cmd { __le32 sub_grp_cmd_id; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 89e5ba3f4e42..17475e269ef5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -1187,6 +1187,7 @@ enum { * ( REPLY_ERROR = 0x2 ) * @error_type: one of FW_ERR_* * @cmd_id: the command ID for which the error occured + * @reserved1: reserved * @bad_cmd_seq_num: sequence number of the erroneous command * @error_service: which service created the error, applicable only if * error_type = 2, otherwise 0 @@ -1649,7 +1650,7 @@ struct iwl_fw_channel_info { * @apply_time: 0 means immediate apply and context switch. * other value means apply new params after X usecs * @tx_param_color: ??? - * @channel_info: + * @ci: channel info * @txchain_info: ??? * @rxchain_info: ??? * @acquisition_data: ??? @@ -1738,9 +1739,9 @@ struct iwl_hs20_roc_res { /** * struct iwl_radio_version_notif - information on the radio version * ( RADIO_VERSION_NOTIFICATION = 0x68 ) - * @radio_flavor: - * @radio_step: - * @radio_dash: + * @radio_flavor: radio flavor + * @radio_step: radio version step + * @radio_dash: radio version dash */ struct iwl_radio_version_notif { __le32 radio_flavor; @@ -1774,8 +1775,8 @@ struct iwl_card_state_notif { * @consec_missed_beacons_since_last_rx: number of consecutive missed * beacons since last RX. * @consec_missed_beacons: number of consecutive missed beacons - * @num_expected_beacons: - * @num_recvd_beacons: + * @num_expected_beacons: number of expected beacons + * @num_recvd_beacons: number of received beacons */ struct iwl_missed_beacons_notif { __le32 mac_id; @@ -1835,6 +1836,7 @@ struct iwl_mfu_assert_dump_notif { * @count: Number of MAC addresses in the array * @pass_all: Set 1 to pass all multicast packets. * @bssid: current association BSSID. + * @reserved: reserved * @addr_list: Place holder for array of MAC addresses. * IMPORTANT: add padding if necessary to ensure DWORD alignment. */ @@ -1866,7 +1868,8 @@ enum iwl_mvm_bcast_filter_attr_offset { * struct iwl_fw_bcast_filter_attr - broadcast filter attribute * @offset_type: &enum iwl_mvm_bcast_filter_attr_offset. * @offset: starting offset of this pattern. - * @val: value to match - big endian (MSB is the first + * @reserved1: reserved + * @val: value to match - big endian (MSB is the first * byte to match from offset pos). * @mask: mask to match (big endian). */ @@ -1892,6 +1895,7 @@ enum iwl_mvm_bcast_filter_frame_type { * struct iwl_fw_bcast_filter - broadcast filter * @discard: discard frame (1) or let it pass (0). * @frame_type: &enum iwl_mvm_bcast_filter_frame_type. + * @reserved1: reserved * @num_attrs: number of valid attributes in this filter. * @attrs: attributes of this filter. a filter is considered matched * only when all its attributes are matched (i.e. AND relationship) @@ -1927,6 +1931,7 @@ struct iwl_ba_window_status_notif { /** * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration. * @default_discard: default action for this mac (discard (1) / pass (0)). + * @reserved1: reserved * @attached_filters: bitmap of relevant filters for this mac. */ struct iwl_fw_bcast_mac { @@ -1940,6 +1945,7 @@ struct iwl_fw_bcast_mac { * @disable: enable (0) / disable (1) * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS) * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER) + * @reserved1: reserved * @filters: broadcast filters * @macs: broadcast filtering configuration per-mac */ @@ -2282,7 +2288,7 @@ enum iwl_dts_control_measurement_mode { * @DTS_USE_CHAIN_A: chain A * @DTS_USE_CHAIN_B: chain B * @DTS_USE_CHAIN_C: chain C -* @XTAL_TEMPERATURE - read temperature from xtal +* @XTAL_TEMPERATURE: read temperature from xtal */ enum iwl_dts_used { DTS_USE_TOP = 0, @@ -2624,6 +2630,7 @@ struct iwl_shared_mem_cfg { /** * struct iwl_mu_group_mgmt_cmd - VHT MU-MIMO group configuration * + * @reserved: reserved * @membership_status: a bitmap of MU groups * @user_position:the position of station in a group. If the station is in the * group then bits (group * 2) is the position -1 @@ -2658,6 +2665,7 @@ struct iwl_mu_group_mgmt_notif { * @channel: channel this beacon was received on * @rates: rate in ucode internal format * @byte_count: frame's byte count + * @data: beacon data, length in @byte_count */ struct iwl_stored_beacon_notif { __le32 system_time; @@ -2781,6 +2789,7 @@ struct iwl_dbg_mem_access_rsp { /** * struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed + * @reserved: reserved */ struct iwl_nvm_access_complete_cmd { __le32 reserved; @@ -2820,6 +2829,7 @@ struct iwl_nvm_get_info { * @flags: 1 - empty, 0 - valid * @nvm_version: nvm version * @board_type: board type + * @reserved: reserved */ struct iwl_nvm_get_info_general { __le32 flags; -- cgit v1.2.3 From 779e0513c76e21b62e2ef907f8cfc48f9f41f734 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 May 2017 13:45:29 +0200 Subject: iwlwifi: dvm: use macros for format strings Some static checkers (e.g. smatch) complain if a non-constant format string is used, even if that's a static const variable. Since there's no impact on code generation, just change those format strings to be macros. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c index 376c79337a0e..937be04c6c71 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c @@ -681,11 +681,10 @@ DEBUGFS_READ_FILE_OPS(temperature); DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); DEBUGFS_READ_FILE_OPS(current_sleep_command); -static const char *fmt_value = " %-30s %10u\n"; -static const char *fmt_hex = " %-30s 0x%02X\n"; -static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; -static const char *fmt_header = - "%-32s current cumulative delta max\n"; +#define fmt_value " %-30s %10u\n" +#define fmt_hex " %-30s 0x%02X\n" +#define fmt_table " %-30s %10u %10u %10u %10u\n" +#define fmt_header "%-32s current cumulative delta max\n" static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) { -- cgit v1.2.3 From 565291c60a3592bd1b6683d2c848dd165a6a3e76 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 May 2017 11:31:06 +0200 Subject: iwlwifi: pcie: only apply retention workaround on 9000-series A-step Due to a hardware issue, certain power saving had to be disabled. However, this issue was fixed in B-step, so the workaround only needs to apply to A-step. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index a5c0f69423d2..cd109740632d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -761,6 +761,15 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable) { + if (trans->cfg->device_family != IWL_DEVICE_FAMILY_9000) + return; + + if (CSR_HW_REV_STEP(trans->hw_rev) != SILICON_A_STEP) + return; + + if (!trans->cfg->integrated) + return; + /* * Turn on the chicken-bits that cause MAC wakeup for RX-related * values. @@ -768,12 +777,10 @@ void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable) * bug where shadow registers are not in the retention list and their * value is lost when NIC powers down */ - if (trans->cfg->integrated) { - iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, - CSR_MAC_SHADOW_REG_CTRL_RX_WAKE); - iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTL2, - CSR_MAC_SHADOW_REG_CTL2_RX_WAKE); - } + iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, + CSR_MAC_SHADOW_REG_CTRL_RX_WAKE); + iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTL2, + CSR_MAC_SHADOW_REG_CTL2_RX_WAKE); } static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) -- cgit v1.2.3 From ae5bb2a62d96e52b138628e0cda4ebb377cbc456 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 18 May 2017 17:02:05 +0200 Subject: iwlwifi: pcie: fix 9000-series RF-kill interrupt propagation A hardware issue on 9000 series devices sometimes causes RF-kill interrupts to not be propagated to the host properly if ASPM is enabled. Work around this by setting the right hardware bit to allow it to interrupt the host for this reason (rfkill). Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index e239b1d92cf9..c6c1876c1ad4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -312,7 +312,7 @@ #define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) #define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) -#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) +#define CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN (0x04000000) #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 1f4bc933f0f2..7ec2d96ccceb 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -674,6 +674,16 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) iwl_enable_hw_int_msk_msix(trans, MSIX_HW_INT_CAUSES_REG_RF_KILL); } + + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_9000) { + /* + * On 9000-series devices this bit isn't enabled by default, so + * when we power down the device we need set the bit to allow it + * to wake up the PCI-E bus for RF-kill interrupts. + */ + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); + } } void iwl_pcie_handle_rfkill_irq(struct iwl_trans *trans); -- cgit v1.2.3 From 806911da64404a6a6348c4840a47218c3bb64a3c Mon Sep 17 00:00:00 2001 From: Sharon Dvir Date: Sun, 21 May 2017 12:09:49 +0300 Subject: iwlwifi: mvm: change sta_id to u8 The sta_id variable is used as an index in an array, should be unsigned. Found by Klocwork. Fixes: 9f9af3d7d303 ("iwlwifi: mvm: re-aggregate shared queue after unsharing") Signed-off-by: Sharon Dvir Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 02f35a929606..9ec427966533 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -398,7 +398,7 @@ static int iwl_mvm_get_queue_agg_tids(struct iwl_mvm *mvm, int queue) struct iwl_mvm_sta *mvmsta; unsigned long tid_bitmap; unsigned long agg_tids = 0; - s8 sta_id; + u8 sta_id; int tid; lockdep_assert_held(&mvm->mutex); @@ -989,7 +989,7 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) { struct ieee80211_sta *sta; struct iwl_mvm_sta *mvmsta; - s8 sta_id; + u8 sta_id; int tid = -1; unsigned long tid_bitmap; unsigned int wdg_timeout; -- cgit v1.2.3 From 4c324a51b62079a43a4aa5024785ba542ff83ce3 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 19 May 2017 15:06:29 +0300 Subject: iwlwifi: mvm: simplify CHECK_MLME_TRIGGER macro There's no reason to pass mvm and trig as parameters to the macro, since it will be expanded inside the function itself. Also remove the bogus buf parameter which doesn't exist and is not used. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 24 +++++++++-------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index d04a88c6c593..b98978d6cb21 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4151,11 +4151,11 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const struct ieee80211_event *event) { -#define CHECK_MLME_TRIGGER(_mvm, _trig, _buf, _cnt, _fmt...) \ +#define CHECK_MLME_TRIGGER(_cnt, _fmt...) \ do { \ - if ((_cnt) && --(_cnt)) \ + if ((trig_mlme->_cnt) && --(trig_mlme->_cnt)) \ break; \ - iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt);\ + iwl_mvm_fw_dbg_collect_trig(mvm, trig, _fmt); \ } while (0) struct iwl_fw_dbg_trigger_tlv *trig; @@ -4171,31 +4171,25 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm, if (event->u.mlme.data == ASSOC_EVENT) { if (event->u.mlme.status == MLME_DENIED) - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_assoc_denied, + CHECK_MLME_TRIGGER(stop_assoc_denied, "DENIED ASSOC: reason %d", event->u.mlme.reason); else if (event->u.mlme.status == MLME_TIMEOUT) - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_assoc_timeout, + CHECK_MLME_TRIGGER(stop_assoc_timeout, "ASSOC TIMEOUT"); } else if (event->u.mlme.data == AUTH_EVENT) { if (event->u.mlme.status == MLME_DENIED) - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_auth_denied, + CHECK_MLME_TRIGGER(stop_auth_denied, "DENIED AUTH: reason %d", event->u.mlme.reason); else if (event->u.mlme.status == MLME_TIMEOUT) - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_auth_timeout, + CHECK_MLME_TRIGGER(stop_auth_timeout, "AUTH TIMEOUT"); } else if (event->u.mlme.data == DEAUTH_RX_EVENT) { - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_rx_deauth, + CHECK_MLME_TRIGGER(stop_rx_deauth, "DEAUTH RX %d", event->u.mlme.reason); } else if (event->u.mlme.data == DEAUTH_TX_EVENT) { - CHECK_MLME_TRIGGER(mvm, trig, buf, - trig_mlme->stop_tx_deauth, + CHECK_MLME_TRIGGER(stop_tx_deauth, "DEAUTH TX %d", event->u.mlme.reason); } #undef CHECK_MLME_TRIGGER -- cgit v1.2.3 From 175b87c692532ece6c4622628c8c9df726773236 Mon Sep 17 00:00:00 2001 From: Tzipi Peres Date: Mon, 22 May 2017 12:36:28 +0300 Subject: iwlwifi: add the new a000_2ax series Add a new config struct for the new a000 2ax series and add the five PCI ID for it. Signed-off-by: Tzipi Peres Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 10 ++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 5 +++++ 3 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index 4634c46d1eb4..2940c0a6c3d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -158,5 +158,15 @@ const struct iwl_cfg iwla000_2ac_cfg_jf = { .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; +const struct iwl_cfg iwla000_2ax_cfg_hr = { + .name = "Intel(R) Dual Band Wireless AX a000", + .fw_name_pre = IWL_A000_HR_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + MODULE_FIRMWARE(IWL_A000_HR_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_A000_JF_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 127017efdd87..c52623cb7c2a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -462,6 +462,7 @@ extern const struct iwl_cfg iwl9560_2ac_cfg; extern const struct iwl_cfg iwla000_2ac_cfg_hr; extern const struct iwl_cfg iwla000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwla000_2ac_cfg_jf; +extern const struct iwl_cfg iwla000_2ax_cfg_hr; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index a8fb77483313..e995b055be4e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -539,6 +539,11 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* a000 Series */ {IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg_hr_cdb)}, {IWL_PCI_DEVICE(0x34F0, 0x0310, iwla000_2ac_cfg_jf)}, + {IWL_PCI_DEVICE(0x2720, 0x0000, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x0070, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0078, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0070, iwla000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x1080, iwla000_2ax_cfg_hr)}, #endif /* CONFIG_IWLMVM */ {0} -- cgit v1.2.3 From 4e37b063ad9f902052903c579b6f291ba329104e Mon Sep 17 00:00:00 2001 From: Tzipi Peres Date: Mon, 22 May 2017 16:16:52 +0300 Subject: iwlwifi: add twelve new 9560 series PCI IDs Add twelve new PCI IDs for the 9560 series. Signed-off-by: Tzipi Peres Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index e995b055be4e..7bf765ba5235 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -7,7 +7,7 @@ * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016-2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -35,6 +35,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. + * Copyright(c) 2017 Intel Deutschland GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -535,6 +536,18 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x1030, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0034, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x0034, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0034, iwl9560_2ac_cfg)}, /* a000 Series */ {IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg_hr_cdb)}, -- cgit v1.2.3 From 91109f42d0ad0c0c282d1fa1257a1548977aa895 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 26 May 2017 13:11:44 +0200 Subject: iwlwifi: mvm: use proper CDB check in PHY context modify When the firmware supports CDB, PHY contexts cannot be modified to change their band, but need to be added/remove instead. Instead of relying on iwl_mvm_has_new_tx_api(), check the right FW capa flag IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT and remove the comment. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index d59efe804356..fb9eaf003ea5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -255,8 +255,8 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, lockdep_assert_held(&mvm->mutex); - /* In CDB mode we cannot modify PHY context between bands so... */ - if (iwl_mvm_has_new_tx_api(mvm) && + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && ctxt->channel->band != chandef->chan->band) { int ret; -- cgit v1.2.3 From a395058eb61c888ac5624cccb40eaedf77c01472 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 26 May 2017 11:16:39 +0200 Subject: iwlwifi: pcie: improve "invalid queue" warning Print out both queue IDs to be able to see what went wrong. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index cd109740632d..6544facc2e0c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1129,8 +1129,12 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) break; - WARN_ON((le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >> - FH_RSCSR_RXQ_POS != rxq->id); + WARN((le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >> + FH_RSCSR_RXQ_POS != rxq->id, + "frame on invalid queue - is on %d and indicates %d\n", + rxq->id, + (le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >> + FH_RSCSR_RXQ_POS); IWL_DEBUG_RX(trans, "cmd at offset %d: %s (%.2x.%2x, seq 0x%x)\n", -- cgit v1.2.3 From a58bb46855a019a204858cefd3e7d56f87f842f4 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 28 May 2017 14:20:04 +0300 Subject: iwlwifi: mvm: support aggs of 64 frames in A000 family A SCD bug was fixed in the A000 family, allowing to support aggregations of 64 frames (rather than 63). Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 6 +++++- drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 11 +++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index a02dda8d9ea3..65beca3a457a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -3233,7 +3233,11 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm, if (num_of_ant(ant) == 1) lq_cmd->single_stream_ant_msk = ant; - lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + if (!mvm->trans->cfg->gen2) + lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + else + lq_cmd->agg_frame_cnt_limit = + LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF; } #endif /* CONFIG_MAC80211_DEBUGFS */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 3abde1cb0303..32b4d66debea 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -145,6 +145,8 @@ enum { #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) +#define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF (64) +#define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_MAX (64) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) #define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 9ec427966533..ee7c978fe5ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1354,7 +1354,10 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, mvm_sta->mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); mvm_sta->vif = vif; - mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + if (!mvm->trans->cfg->gen2) + mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + else + mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF; mvm_sta->tx_protection = 0; mvm_sta->tt_tx_protection = false; mvm_sta->sta_type = sta->tdls ? IWL_STA_TDLS_LINK : IWL_STA_LINK; @@ -2677,7 +2680,11 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, BUILD_BUG_ON((sizeof(mvmsta->agg_tids) * BITS_PER_BYTE) != IWL_MAX_TID_COUNT); - buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); + if (!mvm->trans->cfg->gen2) + buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); + else + buf_size = min_t(int, buf_size, + LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF); spin_lock_bh(&mvmsta->lock); ssn = tid_data->ssn; -- cgit v1.2.3 From 3bfdee768c09bac3ee3e4b3a6d3b75cdc19e489c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 May 2017 12:15:45 +0200 Subject: iwlwifi: pcie: improve debug in iwl_pcie_rx_handle_rb() Print the queue for the existing debug message and add a new debug message indicating where the RB ended. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 6544facc2e0c..1618a59a8a2f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1126,8 +1126,12 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, pkt = rxb_addr(&rxcb); - if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) + if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) { + IWL_DEBUG_RX(trans, + "Q %d: RB end marker at offset %d\n", + rxq->id, offset); break; + } WARN((le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >> FH_RSCSR_RXQ_POS != rxq->id, @@ -1137,8 +1141,8 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, FH_RSCSR_RXQ_POS); IWL_DEBUG_RX(trans, - "cmd at offset %d: %s (%.2x.%2x, seq 0x%x)\n", - rxcb._offset, + "Q %d: cmd at offset %d: %s (%.2x.%2x, seq 0x%x)\n", + rxq->id, offset, iwl_get_cmd_string(trans, iwl_cmd_id(pkt->hdr.cmd, pkt->hdr.group_id, -- cgit v1.2.3 From b3de3ef48aa3fe066150243f07d1cc4e6fac2c80 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 29 May 2017 14:01:06 +0300 Subject: iwlwifi: mvm: change when the BT_COEX is sent The BT_COEX command should not be sent to the INIT firmware image starting from 8000 family. The firmware team also requested to send the BT_COEX command after the PHY_DB_CMD and the PHY_CFG_CMD. While at it: s/iwl_send_bt_init_conf/iwl_mvm_send_bt_init_conf/ Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 16 +++++++++------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index fe7f1e424f55..34dd5c40ce77 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -406,7 +406,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) return ret; } -int iwl_send_bt_init_conf(struct iwl_mvm *mvm) +int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm) { struct iwl_bt_coex_cmd bt_cmd = {}; u32 mode; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index c3ab13ee4097..f87a43dad086 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -644,7 +644,7 @@ iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf, modes_str[mvm->bt_force_ant_mode]); if (iwl_mvm_firmware_running(mvm)) - ret = iwl_send_bt_init_conf(mvm); + ret = iwl_mvm_send_bt_init_conf(mvm); else ret = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 273e19460016..07308912486a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -836,9 +836,11 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) goto error; } - ret = iwl_send_bt_init_conf(mvm); - if (ret) - goto error; + if (mvm->cfg->device_family < IWL_DEVICE_FAMILY_8000) { + ret = iwl_mvm_send_bt_init_conf(mvm); + if (ret) + goto error; + } /* Read the NVM only at driver load time, no need to do this twice */ if (read_nvm) { @@ -1545,10 +1547,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; - ret = iwl_send_bt_init_conf(mvm); - if (ret) - goto error; - /* Send phy db control command and then phy db calibration*/ if (!iwl_mvm_has_new_tx_api(mvm)) { ret = iwl_send_phy_db_data(mvm->phy_db); @@ -1560,6 +1558,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } + ret = iwl_mvm_send_bt_init_conf(mvm); + if (ret) + goto error; + /* Init RSS configuration */ /* TODO - remove a000 disablement when we have RXQ config API */ if (iwl_mvm_has_new_rx_api(mvm) && !iwl_mvm_has_new_tx_api(mvm)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 9b777b847e22..f2f1e04f471d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1680,7 +1680,7 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode); int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); /* BT Coex */ -int iwl_send_bt_init_conf(struct iwl_mvm *mvm); +int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm); void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, -- cgit v1.2.3 From cba46988c0813cd9e74d6625af32f7043780dac3 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Thu, 13 Apr 2017 17:10:33 +0300 Subject: iwlwifi: mvm: support multi tid ba notif When receiving a BA_NOTIF on new TX API, it can contain BAs for several TIDs. Go over them and reclaim TX for every TID. Note that although the small API change, the API version still isn't bumped forward, as this NIC isn't still officially released. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 4 +++- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 28 ++++++++++------------ 2 files changed, 15 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 9d2a991221cf..97d7eed32622 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -668,13 +668,15 @@ struct iwl_mvm_ba_notif { * @q_num: TFD queue number * @tfd_index: Index of first un-acked frame in the TFD queue * @scd_queue: For debug only - the physical queue the TFD queue is bound to + * @tid: TID of the queue (0-7) * @reserved: reserved for alignment */ struct iwl_mvm_compressed_ba_tfd { __le16 q_num; __le16 tfd_index; u8 scd_queue; - u8 reserved[3]; + u8 tid; + u8 reserved[2]; } __packed; /* COMPRESSED_BA_TFD_API_S_VER_1 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index c89bb453c496..627befb0d8d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1813,6 +1813,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) if (iwl_mvm_has_new_tx_api(mvm)) { struct iwl_mvm_compressed_ba_notif *ba_res = (void *)pkt->data; + int i; sta_id = ba_res->sta_id; ba_info.status.ampdu_ack_len = (u8)le16_to_cpu(ba_res->done); @@ -1825,22 +1826,17 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) if (!le16_to_cpu(ba_res->tfd_cnt)) goto out; - /* - * TODO: - * When supporting multi TID aggregations - we need to move - * next_reclaimed to be per TXQ and not per TID or handle it - * in a different way. - * This will go together with SN and AddBA offload and cannot - * be handled properly for now. - */ - WARN_ON(le16_to_cpu(ba_res->ra_tid_cnt) != 1); - tid = ba_res->ra_tid[0].tid; - if (tid == IWL_MGMT_TID) - tid = IWL_MAX_TID_COUNT; - iwl_mvm_tx_reclaim(mvm, sta_id, tid, - (int)(le16_to_cpu(ba_res->tfd[0].q_num)), - le16_to_cpu(ba_res->tfd[0].tfd_index), - &ba_info, le32_to_cpu(ba_res->tx_rate)); + /* Free per TID */ + for (i = 0; i < le16_to_cpu(ba_res->tfd_cnt); i++) { + struct iwl_mvm_compressed_ba_tfd *ba_tfd = + &ba_res->tfd[i]; + + iwl_mvm_tx_reclaim(mvm, sta_id, ba_tfd->tid, + (int)(le16_to_cpu(ba_tfd->q_num)), + le16_to_cpu(ba_tfd->tfd_index), + &ba_info, + le32_to_cpu(ba_res->tx_rate)); + } out: IWL_DEBUG_TX_REPLY(mvm, -- cgit v1.2.3 From 3b37f4c99c93abf2cdde751a536190bde5a1283a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 30 May 2017 16:45:31 +0200 Subject: iwlwifi: unify external & internal modparam names Where possible (all except for "11n_disable", which isn't valid in C) rename the internal names for module parameters to be the same as the externally visible names, to aid finding their use etc. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c | 6 +++--- drivers/net/wireless/intel/iwlwifi/dvm/lib.c | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c | 8 ++++---- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/dvm/rx.c | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/rxon.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 12 ++++++------ drivers/net/wireless/intel/iwlwifi/iwl-modparams.h | 16 ++++++++-------- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 8 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 +- 15 files changed, 43 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c index 937be04c6c71..482ac8fdc67b 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c @@ -2308,10 +2308,10 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - bool restart_fw = iwlwifi_mod_params.restart_fw; + bool fw_restart = iwlwifi_mod_params.fw_restart; int __maybe_unused ret; - iwlwifi_mod_params.restart_fw = true; + iwlwifi_mod_params.fw_restart = true; mutex_lock(&priv->mutex); @@ -2320,7 +2320,7 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, mutex_unlock(&priv->mutex); - iwlwifi_mod_params.restart_fw = restart_fw; + iwlwifi_mod_params.fw_restart = fw_restart; return count; } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index 74e52f7c5aa1..2b6ffbc46fa5 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -1157,7 +1157,7 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) if (ret) goto out; - if (!iwlwifi_mod_params.sw_crypto) { + if (!iwlwifi_mod_params.swcrypto) { /* mark all keys clear */ priv->ucode_key_table = 0; ctx->key_mapping_keys = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 444c74371929..82caae02dd09 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -138,7 +138,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, * packets, so enabling it with software crypto isn't safe) */ if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP && - !iwlwifi_mod_params.sw_crypto) + !iwlwifi_mod_params.swcrypto) ieee80211_hw_set(hw, MFP_CAPABLE); hw->sta_data_size = sizeof(struct iwl_station_priv); @@ -171,7 +171,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_EAP_IDENTITY_REQ | WIPHY_WOWLAN_RFKILL_RELEASE; - if (!iwlwifi_mod_params.sw_crypto) + if (!iwlwifi_mod_params.swcrypto) priv->wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_GTK_REKEY_FAILURE; @@ -348,7 +348,7 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - if (iwlwifi_mod_params.sw_crypto) + if (iwlwifi_mod_params.swcrypto) return; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -624,7 +624,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (iwlwifi_mod_params.sw_crypto) { + if (iwlwifi_mod_params.swcrypto) { IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 4c8f9f1a5532..2acd94da9efe 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1371,7 +1371,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, /* is antenna coupling more than 35dB ? */ priv->bt_ant_couple_ok = - (iwlwifi_mod_params.ant_coupling > + (iwlwifi_mod_params.antenna_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ? true : false; @@ -1958,7 +1958,7 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) } if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - if (iwlwifi_mod_params.restart_fw) { + if (iwlwifi_mod_params.fw_restart) { IWL_DEBUG_FW_ERRORS(priv, "Restarting adapter due to uCode error.\n"); queue_work(priv->workqueue, &priv->restart); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index eaad7389b67c..c942830af2b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -639,7 +639,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, } /* In case of HW accelerated crypto and bad decryption, drop */ - if (!iwlwifi_mod_params.sw_crypto && + if (!iwlwifi_mod_params.swcrypto && iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 087e579854ab..8f3e5586eda9 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -1120,7 +1120,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } - iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.swcrypto); IWL_DEBUG_INFO(priv, "Going to commit RXON\n" diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index c8d451474b64..b5ebd0fcfbf6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1615,11 +1615,11 @@ void iwl_drv_stop(struct iwl_drv *drv) /* shared module parameters */ struct iwl_mod_params iwlwifi_mod_params = { - .restart_fw = true, + .fw_restart = true, .bt_coex_active = true, .power_level = IWL_POWER_INDEX_1, .d0i3_disable = true, - .d0i3_entry_delay = 1000, + .d0i3_timeout = 1000, .uapsd_disable = IWL_DISABLE_UAPSD_BSS | IWL_DISABLE_UAPSD_P2P_CLIENT, /* the rest are 0 by default */ }; @@ -1711,7 +1711,7 @@ module_param_named(debug, iwlwifi_mod_params.debug_level, uint, MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(swcrypto, iwlwifi_mod_params.sw_crypto, int, S_IRUGO); +module_param_named(swcrypto, iwlwifi_mod_params.swcrypto, int, S_IRUGO); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO); MODULE_PARM_DESC(11n_disable, @@ -1720,10 +1720,10 @@ module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size, int, S_IRUGO); MODULE_PARM_DESC(amsdu_size, "amsdu size 0: 12K for multi Rx queue devices, 4K for other devices 1:4K 2:8K 3:12K (default 0)"); -module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, bool, S_IRUGO); +module_param_named(fw_restart, iwlwifi_mod_params.fw_restart, bool, S_IRUGO); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)"); -module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, +module_param_named(antenna_coupling, iwlwifi_mod_params.antenna_coupling, int, S_IRUGO); MODULE_PARM_DESC(antenna_coupling, "specify antenna coupling in dB (default: 0 dB)"); @@ -1782,7 +1782,7 @@ module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, S_IRUGO); MODULE_PARM_DESC(fw_monitor, "firmware monitor - to debug FW (default: false - needs lots of memory)"); -module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_entry_delay, +module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_timeout, uint, S_IRUGO); MODULE_PARM_DESC(d0i3_timeout, "Timeout to D0i3 entry when idle (ms)"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index 0bd85e58cc2c..a41c46e63eb1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -102,32 +102,32 @@ enum iwl_uapsd_disable { * * Holds the module parameters * - * @sw_crypto: using hardware encryption, default = 0 + * @swcrypto: using hardware encryption, default = 0 * @disable_11n: disable 11n capabilities, default = 0, * use IWL_[DIS,EN]ABLE_HT_* constants * @amsdu_size: See &enum iwl_amsdu_size. - * @restart_fw: restart firmware, default = 1 + * @fw_restart: restart firmware, default = 1 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 * @power_save: enable power save, default = false * @power_level: power level, default = 1 * @debug_level: levels are IWL_DL_* - * @ant_coupling: antenna coupling in dB, default = 0 + * @antenna_coupling: antenna coupling in dB, default = 0 * @nvm_file: specifies a external NVM file * @uapsd_disable: disable U-APSD, see &enum iwl_uapsd_disable, default = * IWL_DISABLE_UAPSD_BSS | IWL_DISABLE_UAPSD_P2P_CLIENT * @d0i3_disable: disable d0i3, default = 1, - * @d0i3_entry_delay: time to wait after no refs are taken before + * @d0i3_timeout: time to wait after no refs are taken before * entering D0i3 (in msecs) * @lar_disable: disable LAR (regulatory), default = 0 * @fw_monitor: allow to use firmware monitor * @disable_11ac: disable VHT capabilities, default = false. */ struct iwl_mod_params { - int sw_crypto; + int swcrypto; unsigned int disable_11n; int amsdu_size; - bool restart_fw; + bool fw_restart; bool bt_coex_active; int led_mode; bool power_save; @@ -135,11 +135,11 @@ struct iwl_mod_params { #ifdef CONFIG_IWLWIFI_DEBUG u32 debug_level; #endif - int ant_coupling; + int antenna_coupling; char *nvm_file; u32 uapsd_disable; bool d0i3_disable; - unsigned int d0i3_entry_delay; + unsigned int d0i3_timeout; bool lar_disable; bool fw_monitor; bool disable_11ac; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index ca2d11f4984e..5de19ea10575 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -83,7 +83,7 @@ void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (iwlwifi_mod_params.sw_crypto) + if (iwlwifi_mod_params.swcrypto) return; mutex_lock(&mvm->mutex); @@ -1054,7 +1054,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, return ret; } - if (!iwlwifi_mod_params.sw_crypto) { + if (!iwlwifi_mod_params.swcrypto) { /* * This needs to be unlocked due to lock ordering * constraints. Since we're in the suspend path @@ -1280,8 +1280,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (!unified_image) { iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); - if (mvm->restart_fw > 0) { - mvm->restart_fw--; + if (mvm->fw_restart > 0) { + mvm->fw_restart--; ieee80211_restart_hw(mvm->hw); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index f87a43dad086..78dde0a8d358 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -869,8 +869,8 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, mutex_lock(&mvm->mutex); /* allow one more restart that we're provoking here */ - if (mvm->restart_fw >= 0) - mvm->restart_fw++; + if (mvm->fw_restart >= 0) + mvm->fw_restart++; /* take the return value to make compiler happy - it will fail anyway */ ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b98978d6cb21..1cfb4c72199a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -493,7 +493,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) * firmware will interpret some mgmt packets, so enabling it * with software crypto isn't safe). */ - if (!iwlwifi_mod_params.sw_crypto) { + if (!iwlwifi_mod_params.swcrypto) { ieee80211_hw_set(hw, MFP_CAPABLE); mvm->ciphers[hw->wiphy->n_cipher_suites] = WLAN_CIPHER_SUITE_AES_CMAC; @@ -687,7 +687,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) WIPHY_WOWLAN_EAP_IDENTITY_REQ | WIPHY_WOWLAN_RFKILL_RELEASE | WIPHY_WOWLAN_NET_DETECT; - if (!iwlwifi_mod_params.sw_crypto) + if (!iwlwifi_mod_params.swcrypto) mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_GTK_REKEY_FAILURE | WIPHY_WOWLAN_4WAY_HANDSHAKE; @@ -2888,7 +2888,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, int ret; u8 key_offset; - if (iwlwifi_mod_params.sw_crypto) { + if (iwlwifi_mod_params.swcrypto) { IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index f2f1e04f471d..e1f7d273d0bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -921,7 +921,7 @@ struct iwl_mvm { u8 vif_count; /* -1 for always, 0 for never, >0 for that many times */ - s8 restart_fw; + s8 fw_restart; u8 fw_dbg_conf; struct delayed_work fw_dump_wk; const struct iwl_mvm_dump_desc *fw_dump_desc; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 695d1aead89f..a0907762b0bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -594,7 +594,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, goto out_free; } - mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; + mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0; if (!iwl_mvm_is_dqa_supported(mvm)) { mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1; @@ -1225,7 +1225,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * If WoWLAN fw asserted, don't restart either, mac80211 * can't recover this since we're already half suspended. */ - if (!mvm->restart_fw && fw_error) { + if (!mvm->fw_restart && fw_error) { iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, NULL); } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, @@ -1258,8 +1258,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) /* don't let the transport/FW power down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); - if (fw_error && mvm->restart_fw > 0) - mvm->restart_fw--; + if (fw_error && mvm->fw_restart > 0) + mvm->fw_restart--; ieee80211_restart_hw(mvm->hw); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index d48c2ecc0893..35e813bdfbe5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1695,7 +1695,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) mvm->scan_uid_status[uid] = 0; } uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED); - if (uid >= 0 && !mvm->restart_fw) { + if (uid >= 0 && !mvm->fw_restart) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; mvm->scan_uid_status[uid] = 0; @@ -1725,7 +1725,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) * restarted. */ if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && - !mvm->restart_fw) { + !mvm->fw_restart) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 7bf765ba5235..3ca0f374c081 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -723,7 +723,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, - iwlwifi_mod_params.d0i3_entry_delay); + iwlwifi_mod_params.d0i3_timeout); pm_runtime_use_autosuspend(&pdev->dev); /* We are not supposed to call pm_runtime_allow() by -- cgit v1.2.3 From 87fc030231b11a190f16d7162a141e2f162eae36 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 May 2017 13:15:18 +0200 Subject: iwlwifi: pcie: make ctxt-info free idempotent By setting the pointers to NULL at the end, these functions are made idempotent. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index b1f43397bb59..00d1a5f048b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -103,6 +103,7 @@ static void iwl_pcie_ctxt_info_free_fw_img(struct iwl_trans *trans) kfree(dram->fw); dram->fw_cnt = 0; + dram->fw = NULL; } void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans) @@ -124,6 +125,7 @@ void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans) kfree(dram->paging); dram->paging_cnt = 0; + dram->paging = NULL; } static int iwl_pcie_ctxt_info_init_fw_sec(struct iwl_trans *trans, -- cgit v1.2.3 From f0fea2b728af737ec45d96a0279087a558ad9774 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 May 2017 13:19:10 +0200 Subject: iwlwifi: pcie: warn if paging is already initialized during init This appears to happen in some cases, like when iwlmvm is unloaded and loaded again without also unloading iwlwifi. Warn in this case and free the paging data to be able to continue without causing corruption and kernel crashes due to it (otherwise, paging data is overwritten, but dram->paging_cnt gets to be twice as big as it should be, and then an eventual free will crash.) Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 00d1a5f048b3..eddaca76d514 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -137,6 +137,11 @@ static int iwl_pcie_ctxt_info_init_fw_sec(struct iwl_trans *trans, struct iwl_context_info_dram *ctxt_dram = &ctxt_info->dram; int i, ret, lmac_cnt, umac_cnt, paging_cnt; + if (WARN(dram->paging, + "paging shouldn't already be initialized (%d pages)\n", + dram->paging_cnt)) + iwl_pcie_ctxt_info_free_paging(trans); + lmac_cnt = iwl_pcie_get_num_sections(fw, 0); /* add 1 due to separator */ umac_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + 1); -- cgit v1.2.3 From b092c9f25d45972cf401ad8bcfee2429bf189e2b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 May 2017 14:14:51 +0200 Subject: iwlwifi: mvm: unconditionally stop device after init In commit b93b1fe3b532 ("iwlwifi: mvm: fix init_dbg flow to work as expected"), the code was changed to make the stop conditional on not having failed (and on not having init_dbg), which doesn't make sense - we should stop the device regardless of failures. Failure to do so is leading to the device being enabled when it shouldn't be, and - if it gets re-enabled later - the new context info code gets confused as paging data wasn't freed. Remove the invalid error condition again. Fixes: b93b1fe3b532 ("iwlwifi: mvm: fix init_dbg flow to work as expected") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index a0907762b0bf..c1ce92f5306d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -741,7 +741,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mutex_lock(&mvm->mutex); iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE); err = iwl_run_init_mvm_ucode(mvm, true); - if (!err || !iwlmvm_mod_params.init_dbg) + if (!iwlmvm_mod_params.init_dbg) iwl_mvm_stop_device(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE); mutex_unlock(&mvm->mutex); -- cgit v1.2.3 From 92c4dca6f5fd3d29d8c1daf02e210dd48dc756ac Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 7 Jun 2017 10:35:54 +0200 Subject: iwlwifi: mvm: fix deduplication start logic If the first frame on a given TID is received with seqno 0 and needed to be retransmitted, we erroneously drop it because the deduplication data is initialized to zero, and then comparing if (unlikely(ieee80211_has_retry(hdr->frame_control) && dup_data->last_seq[tid] == hdr->seq_ctrl && dup_data->last_sub_frame[tid] >= sub_frame_idx)) return true; will return in iwl_mvm_is_dup() since last_sub_frame is also set to zero, and sub_frame_idx is usually zero since this only covers the relatively rare case of A-MSDU. Fix this by initializing the last_seq array to 0xffff, which is an impossible value for hdr->seq_ctrl to have here because the lower four bits are the fragment number, and fragments aren't handled in this code but go to mac80211 instead. Fixes: a571f5f635ef ("iwlwifi: mvm: add duplicate packet detection per rx queue") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index ee7c978fe5ab..4df5f13fcdae 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1402,11 +1402,24 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, if (iwl_mvm_has_new_rx_api(mvm) && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + int q; + dup_data = kcalloc(mvm->trans->num_rx_queues, - sizeof(*dup_data), - GFP_KERNEL); + sizeof(*dup_data), GFP_KERNEL); if (!dup_data) return -ENOMEM; + /* + * Initialize all the last_seq values to 0xffff which can never + * compare equal to the frame's seq_ctrl in the check in + * iwl_mvm_is_dup() since the lower 4 bits are the fragment + * number and fragmented packets don't reach that function. + * + * This thus allows receiving a packet with seqno 0 and the + * retry bit set as the very first packet on a new TID. + */ + for (q = 0; q < mvm->trans->num_rx_queues; q++) + memset(dup_data[q].last_seq, 0xff, + sizeof(dup_data[q].last_seq)); mvm_sta->dup_data = dup_data; } -- cgit v1.2.3 From b4f489857aba0e066847dfd01b980578bbf921c9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2017 09:06:11 +0200 Subject: iwlwifi: mvm: rename iwl_shared_mem_cfg_v1 to the correct _v2 This structure represents V2, V1 has the three last fields missing. Rename it to be more accurate. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 6 +++--- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 17475e269ef5..f3ca61ff9f58 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -724,7 +724,7 @@ enum iwl_system_subcmd_ids { /** * @SHARED_MEM_CFG_CMD: * response in &struct iwl_shared_mem_cfg or - * &struct iwl_shared_mem_cfg_v1 + * &struct iwl_shared_mem_cfg_v2 */ SHARED_MEM_CFG_CMD = 0x0, @@ -2546,7 +2546,7 @@ struct iwl_tdls_config_res { #define TX_FIFO_INTERNAL_MAX_NUM 6 /** - * struct iwl_shared_mem_cfg_v1 - Shared memory configuration information + * struct iwl_shared_mem_cfg_v2 - Shared memory configuration information * * @shared_mem_addr: shared memory addr (pre 8000 HW set to 0x0 as MARBH is not * accessible) @@ -2568,7 +2568,7 @@ struct iwl_tdls_config_res { * NOTE: on firmware that don't have IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG * set, the last 3 members don't exist. */ -struct iwl_shared_mem_cfg_v1 { +struct iwl_shared_mem_cfg_v2 { __le32 shared_mem_addr; __le32 shared_mem_size; __le32 sample_buff_addr; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 07308912486a..c5445be36701 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -955,7 +955,7 @@ static void iwl_mvm_parse_shared_mem_a000(struct iwl_mvm *mvm, static void iwl_mvm_parse_shared_mem(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { - struct iwl_shared_mem_cfg_v1 *mem_cfg = (void *)pkt->data; + struct iwl_shared_mem_cfg_v2 *mem_cfg = (void *)pkt->data; int i; mvm->smem_cfg.num_lmacs = 1; -- cgit v1.2.3 From d962f9b1013b3209813b7b8038c2b9123a9626c4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2017 10:22:09 +0200 Subject: iwlwifi: create new subdirectory for FW interaction There's a lot of mvm code that really should be more generic and part of the iwlwifi module. Start by making a place to keep such code - in the new "fw" subdirectory - and already move the firmware related header files there. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/dev.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/api.h | 229 ++++++ drivers/net/wireless/intel/iwlwifi/fw/error-dump.h | 335 ++++++++ drivers/net/wireless/intel/iwlwifi/fw/file.h | 870 +++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/img.h | 342 ++++++++ drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h | 229 ------ .../net/wireless/intel/iwlwifi/iwl-fw-error-dump.h | 335 -------- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 870 --------------------- drivers/net/wireless/intel/iwlwifi/iwl-fw.h | 342 -------- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- 18 files changed, 1788 insertions(+), 1788 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/api.h create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/error-dump.h create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/file.h create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/img.h delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-fw.h (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h index 8148df61a916..025db135b63c 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h @@ -38,7 +38,7 @@ #include #include -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-eeprom-parse.h" #include "iwl-csr.h" #include "iwl-debug.h" diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api.h b/drivers/net/wireless/intel/iwlwifi/fw/api.h new file mode 100644 index 000000000000..0e107f916ce3 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api.h @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_fw_api_h__ +#define __iwl_fw_api_h__ + +/** + * DOC: Host command section + * + * A host command is a command issued by the upper layer to the fw. There are + * several versions of fw that have several APIs. The transport layer is + * completely agnostic to these differences. + * The transport does provide helper functionality (i.e. SYNC / ASYNC mode), + */ +#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) +#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) +#define SEQ_TO_INDEX(s) ((s) & 0xff) +#define INDEX_TO_SEQ(i) ((i) & 0xff) +#define SEQ_RX_FRAME cpu_to_le16(0x8000) + +/* + * those functions retrieve specific information from + * the id field in the iwl_host_cmd struct which contains + * the command id, the group id and the version of the command + * and vice versa +*/ +static inline u8 iwl_cmd_opcode(u32 cmdid) +{ + return cmdid & 0xFF; +} + +static inline u8 iwl_cmd_groupid(u32 cmdid) +{ + return ((cmdid & 0xFF00) >> 8); +} + +static inline u8 iwl_cmd_version(u32 cmdid) +{ + return ((cmdid & 0xFF0000) >> 16); +} + +static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) +{ + return opcode + (groupid << 8) + (version << 16); +} + +/* make u16 wide id out of u8 group and opcode */ +#define WIDE_ID(grp, opcode) (((grp) << 8) | (opcode)) +#define DEF_ID(opcode) ((1 << 8) | (opcode)) + +/* due to the conversion, this group is special; new groups + * should be defined in the appropriate fw-api header files + */ +#define IWL_ALWAYS_LONG_GROUP 1 + +/** + * struct iwl_cmd_header + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + */ +struct iwl_cmd_header { + u8 cmd; /* Command ID: REPLY_RXON, etc. */ + u8 group_id; + /* + * The driver sets up the sequence number to values of its choosing. + * uCode does not use this value, but passes it back to the driver + * when sending the response to each driver-originated command, so + * the driver can match the response to the command. Since the values + * don't get used by uCode, the driver may set up an arbitrary format. + * + * There is one exception: uCode sets bit 15 when it originates + * the response/notification, i.e. when the response/notification + * is not a direct response to a command sent by the driver. For + * example, uCode issues REPLY_RX when it sends a received frame + * to the driver; it is not a direct response to any driver command. + * + * The Linux driver uses the following format: + * + * 0:7 tfd index - position within TX queue + * 8:12 TX queue id + * 13:14 reserved + * 15 unsolicited RX or uCode-originated notification + */ + __le16 sequence; +} __packed; + +/** + * struct iwl_cmd_header_wide + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + * this is the wide version that contains more information about the command + * like length, version and command type + */ +struct iwl_cmd_header_wide { + u8 cmd; + u8 group_id; + __le16 sequence; + __le16 length; + u8 reserved; + u8 version; +} __packed; + +/** + * iwl_tx_queue_cfg_actions - TXQ config options + * @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue + * @TX_QUEUE_CFG_TFD_SHORT_FORMAT: use short TFD format + */ +enum iwl_tx_queue_cfg_actions { + TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0), + TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), +}; + +/** + * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command + * @sta_id: station id + * @tid: tid of the queue + * @flags: see &enum iwl_tx_queue_cfg_actions + * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. + * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) + * @byte_cnt_addr: address of byte count table + * @tfdq_addr: address of TFD circular buffer + */ +struct iwl_tx_queue_cfg_cmd { + u8 sta_id; + u8 tid; + __le16 flags; + __le32 cb_size; + __le64 byte_cnt_addr; + __le64 tfdq_addr; +} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ + +/** + * struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config + * @queue_number: queue number assigned to this RA -TID + * @flags: set on failure + * @write_pointer: initial value for write pointer + */ +struct iwl_tx_queue_cfg_rsp { + __le16 queue_number; + __le16 flags; + __le16 write_pointer; + __le16 reserved; +} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ + +/** + * struct iwl_calib_res_notif_phy_db - Receive phy db chunk after calibrations + * @type: type of the result - mostly ignored + * @length: length of the data + * @data: data, length in @length + */ +struct iwl_calib_res_notif_phy_db { + __le16 type; + __le16 length; + u8 data[]; +} __packed; + +/** + * struct iwl_phy_db_cmd - configure operational ucode + * @type: type of the data + * @length: length of the data + * @data: data, length in @length + */ +struct iwl_phy_db_cmd { + __le16 type; + __le16 length; + u8 data[]; +} __packed; + +#endif /* __iwl_fw_api_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h new file mode 100644 index 000000000000..cfebde68a391 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -0,0 +1,335 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __fw_error_dump_h__ +#define __fw_error_dump_h__ + +#include + +#define IWL_FW_ERROR_DUMP_BARKER 0x14789632 + +/** + * enum iwl_fw_error_dump_type - types of data in the dump file + * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0 + * @IWL_FW_ERROR_DUMP_RXF: + * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as + * &struct iwl_fw_error_dump_txcmd packets + * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info + * info on the device / firmware. + * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor + * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several + * sections like this in a single file. + * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers + * @IWL_FW_ERROR_DUMP_MEM: chunk of memory + * @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump. + * Structured as &struct iwl_fw_error_dump_trigger_desc. + * @IWL_FW_ERROR_DUMP_RB: the content of an RB structured as + * &struct iwl_fw_error_dump_rb + * @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were + * paged to the DRAM. + * @IWL_FW_ERROR_DUMP_RADIO_REG: Dump the radio registers. + * @IWL_FW_ERROR_DUMP_EXTERNAL: used only by external code utilities, and + * for that reason is not in use in any other place in the Linux Wi-Fi + * stack. + */ +enum iwl_fw_error_dump_type { + /* 0 is deprecated */ + IWL_FW_ERROR_DUMP_CSR = 1, + IWL_FW_ERROR_DUMP_RXF = 2, + IWL_FW_ERROR_DUMP_TXCMD = 3, + IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, + IWL_FW_ERROR_DUMP_FW_MONITOR = 5, + IWL_FW_ERROR_DUMP_PRPH = 6, + IWL_FW_ERROR_DUMP_TXF = 7, + IWL_FW_ERROR_DUMP_FH_REGS = 8, + IWL_FW_ERROR_DUMP_MEM = 9, + IWL_FW_ERROR_DUMP_ERROR_INFO = 10, + IWL_FW_ERROR_DUMP_RB = 11, + IWL_FW_ERROR_DUMP_PAGING = 12, + IWL_FW_ERROR_DUMP_RADIO_REG = 13, + IWL_FW_ERROR_DUMP_INTERNAL_TXF = 14, + IWL_FW_ERROR_DUMP_EXTERNAL = 15, /* Do not move */ + + IWL_FW_ERROR_DUMP_MAX, +}; + +/** + * struct iwl_fw_error_dump_data - data for one type + * @type: &enum iwl_fw_error_dump_type + * @len: the length starting from %data + * @data: the data itself + */ +struct iwl_fw_error_dump_data { + __le32 type; + __le32 len; + __u8 data[]; +} __packed; + +/** + * struct iwl_fw_error_dump_file - the layout of the header of the file + * @barker: must be %IWL_FW_ERROR_DUMP_BARKER + * @file_len: the length of all the file starting from %barker + * @data: array of &struct iwl_fw_error_dump_data + */ +struct iwl_fw_error_dump_file { + __le32 barker; + __le32 file_len; + u8 data[0]; +} __packed; + +/** + * struct iwl_fw_error_dump_txcmd - TX command data + * @cmdlen: original length of command + * @caplen: captured length of command (may be less) + * @data: captured command data, @caplen bytes + */ +struct iwl_fw_error_dump_txcmd { + __le32 cmdlen; + __le32 caplen; + u8 data[]; +} __packed; + +/** + * struct iwl_fw_error_dump_fifo - RX/TX FIFO data + * @fifo_num: number of FIFO (starting from 0) + * @available_bytes: num of bytes available in FIFO (may be less than FIFO size) + * @wr_ptr: position of write pointer + * @rd_ptr: position of read pointer + * @fence_ptr: position of fence pointer + * @fence_mode: the current mode of the fence (before locking) - + * 0=follow RD pointer ; 1 = freeze + * @data: all of the FIFO's data + */ +struct iwl_fw_error_dump_fifo { + __le32 fifo_num; + __le32 available_bytes; + __le32 wr_ptr; + __le32 rd_ptr; + __le32 fence_ptr; + __le32 fence_mode; + u8 data[]; +} __packed; + +enum iwl_fw_error_dump_family { + IWL_FW_ERROR_DUMP_FAMILY_7 = 7, + IWL_FW_ERROR_DUMP_FAMILY_8 = 8, +}; + +/** + * struct iwl_fw_error_dump_info - info on the device / firmware + * @device_family: the family of the device (7 / 8) + * @hw_step: the step of the device + * @fw_human_readable: human readable FW version + * @dev_human_readable: name of the device + * @bus_human_readable: name of the bus used + */ +struct iwl_fw_error_dump_info { + __le32 device_family; + __le32 hw_step; + u8 fw_human_readable[FW_VER_HUMAN_READABLE_SZ]; + u8 dev_human_readable[64]; + u8 bus_human_readable[8]; +} __packed; + +/** + * struct iwl_fw_error_dump_fw_mon - FW monitor data + * @fw_mon_wr_ptr: the position of the write pointer in the cyclic buffer + * @fw_mon_base_ptr: base pointer of the data + * @fw_mon_cycle_cnt: number of wraparounds + * @reserved: for future use + * @data: captured data + */ +struct iwl_fw_error_dump_fw_mon { + __le32 fw_mon_wr_ptr; + __le32 fw_mon_base_ptr; + __le32 fw_mon_cycle_cnt; + __le32 reserved[3]; + u8 data[]; +} __packed; + +/** + * struct iwl_fw_error_dump_prph - periphery registers data + * @prph_start: address of the first register in this chunk + * @data: the content of the registers + */ +struct iwl_fw_error_dump_prph { + __le32 prph_start; + __le32 data[]; +}; + +enum iwl_fw_error_dump_mem_type { + IWL_FW_ERROR_DUMP_MEM_SRAM, + IWL_FW_ERROR_DUMP_MEM_SMEM, +}; + +/** + * struct iwl_fw_error_dump_mem - chunk of memory + * @type: &enum iwl_fw_error_dump_mem_type + * @offset: the offset from which the memory was read + * @data: the content of the memory + */ +struct iwl_fw_error_dump_mem { + __le32 type; + __le32 offset; + u8 data[]; +}; + +/** + * struct iwl_fw_error_dump_rb - content of an Receive Buffer + * @index: the index of the Receive Buffer in the Rx queue + * @rxq: the RB's Rx queue + * @reserved: + * @data: the content of the Receive Buffer + */ +struct iwl_fw_error_dump_rb { + __le32 index; + __le32 rxq; + __le32 reserved; + u8 data[]; +}; + +/** + * struct iwl_fw_error_dump_paging - content of the UMAC's image page + * block on DRAM + * @index: the index of the page block + * @reserved: + * @data: the content of the page block + */ +struct iwl_fw_error_dump_paging { + __le32 index; + __le32 reserved; + u8 data[]; +}; + +/** + * iwl_fw_error_next_data - advance fw error dump data pointer + * @data: previous data block + * Returns: next data block + */ +static inline struct iwl_fw_error_dump_data * +iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) +{ + return (void *)(data->data + le32_to_cpu(data->len)); +} + +/** + * enum iwl_fw_dbg_trigger - triggers available + * + * @FW_DBG_TRIGGER_USER: trigger log collection by user + * This should not be defined as a trigger to the driver, but a value the + * driver should set to indicate that the trigger was initiated by the + * user. + * @FW_DBG_TRIGGER_FW_ASSERT: trigger log collection when the firmware asserts + * @FW_DBG_TRIGGER_MISSED_BEACONS: trigger log collection when beacons are + * missed. + * @FW_DBG_TRIGGER_CHANNEL_SWITCH: trigger log collection upon channel switch. + * @FW_DBG_TRIGGER_FW_NOTIF: trigger log collection when the firmware sends a + * command response or a notification. + * @FW_DBG_TRIGGER_MLME: trigger log collection upon MLME event. + * @FW_DBG_TRIGGER_STATS: trigger log collection upon statistics threshold. + * @FW_DBG_TRIGGER_RSSI: trigger log collection when the rssi of the beacon + * goes below a threshold. + * @FW_DBG_TRIGGER_TXQ_TIMERS: configures the timers for the Tx queue hang + * detection. + * @FW_DBG_TRIGGER_TIME_EVENT: trigger log collection upon time events related + * events. + * @FW_DBG_TRIGGER_BA: trigger log collection upon BlockAck related events. + * @FW_DBG_TX_LATENCY: trigger log collection when the tx latency goes above a + * threshold. + * @FW_DBG_TDLS: trigger log collection upon TDLS related events. + * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when + * the firmware sends a tx reply. + */ +enum iwl_fw_dbg_trigger { + FW_DBG_TRIGGER_INVALID = 0, + FW_DBG_TRIGGER_USER, + FW_DBG_TRIGGER_FW_ASSERT, + FW_DBG_TRIGGER_MISSED_BEACONS, + FW_DBG_TRIGGER_CHANNEL_SWITCH, + FW_DBG_TRIGGER_FW_NOTIF, + FW_DBG_TRIGGER_MLME, + FW_DBG_TRIGGER_STATS, + FW_DBG_TRIGGER_RSSI, + FW_DBG_TRIGGER_TXQ_TIMERS, + FW_DBG_TRIGGER_TIME_EVENT, + FW_DBG_TRIGGER_BA, + FW_DBG_TRIGGER_TX_LATENCY, + FW_DBG_TRIGGER_TDLS, + FW_DBG_TRIGGER_TX_STATUS, + + /* must be last */ + FW_DBG_TRIGGER_MAX, +}; + +/** + * struct iwl_fw_error_dump_trigger_desc - describes the trigger condition + * @type: &enum iwl_fw_dbg_trigger + * @data: raw data about what happened + */ +struct iwl_fw_error_dump_trigger_desc { + __le32 type; + u8 data[]; +}; + +#endif /* __fw_error_dump_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h new file mode 100644 index 000000000000..a216657b3c60 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -0,0 +1,870 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwl_fw_file_h__ +#define __iwl_fw_file_h__ + +#include +#include + +/* v1/v2 uCode file layout */ +struct iwl_ucode_header { + __le32 ver; /* major/minor/API/serial */ + union { + struct { + __le32 inst_size; /* bytes of runtime code */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of init code */ + __le32 init_data_size; /* bytes of init data */ + __le32 boot_size; /* bytes of bootstrap code */ + u8 data[0]; /* in same order as sizes */ + } v1; + struct { + __le32 build; /* build number */ + __le32 inst_size; /* bytes of runtime code */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of init code */ + __le32 init_data_size; /* bytes of init data */ + __le32 boot_size; /* bytes of bootstrap code */ + u8 data[0]; /* in same order as sizes */ + } v2; + } u; +}; + +/* + * new TLV uCode file layout + * + * The new TLV file format contains TLVs, that each specify + * some piece of data. + */ + +enum iwl_ucode_tlv_type { + IWL_UCODE_TLV_INVALID = 0, /* unused */ + IWL_UCODE_TLV_INST = 1, + IWL_UCODE_TLV_DATA = 2, + IWL_UCODE_TLV_INIT = 3, + IWL_UCODE_TLV_INIT_DATA = 4, + IWL_UCODE_TLV_BOOT = 5, + IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */ + IWL_UCODE_TLV_PAN = 7, + IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8, + IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9, + IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10, + IWL_UCODE_TLV_INIT_EVTLOG_PTR = 11, + IWL_UCODE_TLV_INIT_EVTLOG_SIZE = 12, + IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, + IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, + IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, + IWL_UCODE_TLV_WOWLAN_INST = 16, + IWL_UCODE_TLV_WOWLAN_DATA = 17, + IWL_UCODE_TLV_FLAGS = 18, + IWL_UCODE_TLV_SEC_RT = 19, + IWL_UCODE_TLV_SEC_INIT = 20, + IWL_UCODE_TLV_SEC_WOWLAN = 21, + IWL_UCODE_TLV_DEF_CALIB = 22, + IWL_UCODE_TLV_PHY_SKU = 23, + IWL_UCODE_TLV_SECURE_SEC_RT = 24, + IWL_UCODE_TLV_SECURE_SEC_INIT = 25, + IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26, + IWL_UCODE_TLV_NUM_OF_CPU = 27, + IWL_UCODE_TLV_CSCHEME = 28, + IWL_UCODE_TLV_API_CHANGES_SET = 29, + IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, + IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, + IWL_UCODE_TLV_PAGING = 32, + IWL_UCODE_TLV_SEC_RT_USNIFFER = 34, + IWL_UCODE_TLV_SDIO_ADMA_ADDR = 35, + IWL_UCODE_TLV_FW_VERSION = 36, + IWL_UCODE_TLV_FW_DBG_DEST = 38, + IWL_UCODE_TLV_FW_DBG_CONF = 39, + IWL_UCODE_TLV_FW_DBG_TRIGGER = 40, + IWL_UCODE_TLV_FW_GSCAN_CAPA = 50, + IWL_UCODE_TLV_FW_MEM_SEG = 51, +}; + +struct iwl_ucode_tlv { + __le32 type; /* see above */ + __le32 length; /* not including type/length fields */ + u8 data[0]; +}; + +#define IWL_TLV_UCODE_MAGIC 0x0a4c5749 +#define FW_VER_HUMAN_READABLE_SZ 64 + +struct iwl_tlv_ucode_header { + /* + * The TLV style ucode header is distinguished from + * the v1/v2 style header by first four bytes being + * zero, as such is an invalid combination of + * major/minor/API/serial versions. + */ + __le32 zero; + __le32 magic; + u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; + /* major/minor/API/serial or major in new format */ + __le32 ver; + __le32 build; + __le64 ignore; + /* + * The data contained herein has a TLV layout, + * see above for the TLV header and types. + * Note that each TLV is padded to a length + * that is a multiple of 4 for alignment. + */ + u8 data[0]; +}; + +/* + * ucode TLVs + * + * ability to get extension for: flags & capabilities from ucode binaries files + */ +struct iwl_ucode_api { + __le32 api_index; + __le32 api_flags; +} __packed; + +struct iwl_ucode_capa { + __le32 api_index; + __le32 api_capa; +} __packed; + +/** + * enum iwl_ucode_tlv_flag - ucode API flags + * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously + * was a separate TLV but moved here to save space. + * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behavior on hidden SSID, + * treats good CRC threshold as a boolean + * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). + * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: This uCode image supports uAPSD + * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan + * offload profile config command. + * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six + * (rather than two) IPv6 addresses + * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element + * from the probe request template. + * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) + * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) + * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD + * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save + * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. + * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. + */ +enum iwl_ucode_tlv_flag { + IWL_UCODE_TLV_FLAGS_PAN = BIT(0), + IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), + IWL_UCODE_TLV_FLAGS_MFP = BIT(2), + IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7), + IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), + IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), + IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), + IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), + IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), + IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25), + IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), + IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), +}; + +typedef unsigned int __bitwise iwl_ucode_tlv_api_t; + +/** + * enum iwl_ucode_tlv_api - ucode api + * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time + * longer than the passive one, which is essential for fragmented scan. + * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. + * @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params + * @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format + * @IWL_UCODE_TLV_API_SCAN_TSF_REPORT: Scan start time reported in scan + * iteration complete notification, and the timestamp reported for RX + * received during scan, are reported in TSF of the mac specified in the + * scan request. + * @IWL_UCODE_TLV_API_TKIP_MIC_KEYS: This ucode supports version 2 of + * ADD_MODIFY_STA_KEY_API_S_VER_2. + * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. + * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 + * + * @NUM_IWL_UCODE_TLV_API: number of bits used + */ +enum iwl_ucode_tlv_api { + IWL_UCODE_TLV_API_FRAGMENTED_SCAN = (__force iwl_ucode_tlv_api_t)8, + IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9, + IWL_UCODE_TLV_API_LQ_SS_PARAMS = (__force iwl_ucode_tlv_api_t)18, + IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20, + IWL_UCODE_TLV_API_SCAN_TSF_REPORT = (__force iwl_ucode_tlv_api_t)28, + IWL_UCODE_TLV_API_TKIP_MIC_KEYS = (__force iwl_ucode_tlv_api_t)29, + IWL_UCODE_TLV_API_STA_TYPE = (__force iwl_ucode_tlv_api_t)30, + IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31, + + NUM_IWL_UCODE_TLV_API +#ifdef __CHECKER__ + /* sparse says it cannot increment the previous enum member */ + = 128 +#endif +}; + +typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; + +/** + * enum iwl_ucode_tlv_capa - ucode capabilities + * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 + * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory + * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. + * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer + * @IWL_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM) + * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality + * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current + * tx power value into TPC Report action frame and Link Measurement Report + * action frame + * @IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports updating current + * channel in DS parameter set element in probe requests. + * @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in + * probe requests. + * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests + * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), + * which also implies support for the scheduler configuration command + * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching + * @IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG: Consolidated D3-D0 image + * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command + * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command + * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload + * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics + * @IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD: supports U-APSD on p2p interface when it + * is standalone or with a BSS station interface in the same binding. + * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running + * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different + * sources for the MCC. This TLV bit is a future replacement to + * IWL_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR + * is supported. + * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC + * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan + * @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification + * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement + * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts + * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT + * @IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD: the firmware supports CSA + * countdown offloading. Beacon notifications are not sent to the host. + * The fw also offloads TBTT alignment. + * @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what + * antenna the beacon should be transmitted + * @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon + * from AP and will send it upon d0i3 exit. + * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2 + * @IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill + * @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature + * thresholds reporting + * @IWL_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command + * @IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in + * regular image. + * @IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared + * memory addresses from the firmware. + * @IWL_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement + * @IWL_UCODE_TLV_CAPA_TX_POWER_ACK: reduced TX power API has larger + * command size (command version 4) that supports toggling ACK TX + * power reduction. + * + * @NUM_IWL_UCODE_TLV_CAPA: number of bits used + */ +enum iwl_ucode_tlv_capa { + IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = (__force iwl_ucode_tlv_capa_t)0, + IWL_UCODE_TLV_CAPA_LAR_SUPPORT = (__force iwl_ucode_tlv_capa_t)1, + IWL_UCODE_TLV_CAPA_UMAC_SCAN = (__force iwl_ucode_tlv_capa_t)2, + IWL_UCODE_TLV_CAPA_BEAMFORMER = (__force iwl_ucode_tlv_capa_t)3, + IWL_UCODE_TLV_CAPA_TOF_SUPPORT = (__force iwl_ucode_tlv_capa_t)5, + IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = (__force iwl_ucode_tlv_capa_t)6, + IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = (__force iwl_ucode_tlv_capa_t)8, + IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)9, + IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)10, + IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = (__force iwl_ucode_tlv_capa_t)11, + IWL_UCODE_TLV_CAPA_DQA_SUPPORT = (__force iwl_ucode_tlv_capa_t)12, + IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = (__force iwl_ucode_tlv_capa_t)13, + IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG = (__force iwl_ucode_tlv_capa_t)17, + IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = (__force iwl_ucode_tlv_capa_t)18, + IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19, + IWL_UCODE_TLV_CAPA_CSUM_SUPPORT = (__force iwl_ucode_tlv_capa_t)21, + IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = (__force iwl_ucode_tlv_capa_t)22, + IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD = (__force iwl_ucode_tlv_capa_t)26, + IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28, + IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, + IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30, + IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31, + IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38, + IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39, + IWL_UCODE_TLV_CAPA_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)40, + IWL_UCODE_TLV_CAPA_D0I3_END_FIRST = (__force iwl_ucode_tlv_capa_t)41, + IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, + IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, + IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, + IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT = (__force iwl_ucode_tlv_capa_t)68, + IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD = (__force iwl_ucode_tlv_capa_t)70, + IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71, + IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72, + IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73, + IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW = (__force iwl_ucode_tlv_capa_t)74, + IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75, + IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76, + IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED = (__force iwl_ucode_tlv_capa_t)77, + IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80, + IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81, + IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84, + + NUM_IWL_UCODE_TLV_CAPA +#ifdef __CHECKER__ + /* sparse says it cannot increment the previous enum member */ + = 128 +#endif +}; + +/* The default calibrate table size if not specified by firmware file */ +#define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 +#define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 +#define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 + +/* The default max probe length if not specified by the firmware file */ +#define IWL_DEFAULT_MAX_PROBE_LENGTH 200 + +/* + * For 16.0 uCode and above, there is no differentiation between sections, + * just an offset to the HW address. + */ +#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC +#define PAGING_SEPARATOR_SECTION 0xAAAABBBB + +/* uCode version contains 4 values: Major/Minor/API/Serial */ +#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) +#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) +#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) +#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) + +/** + * struct iwl_tlv_calib_ctrl - Calibration control struct. + * Sent as part of the phy configuration command. + * @flow_trigger: bitmap for which calibrations to perform according to + * flow triggers. + * @event_trigger: bitmap for which calibrations to perform according to + * event triggers. + */ +struct iwl_tlv_calib_ctrl { + __le32 flow_trigger; + __le32 event_trigger; +} __packed; + +enum iwl_fw_phy_cfg { + FW_PHY_CFG_RADIO_TYPE_POS = 0, + FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS, + FW_PHY_CFG_RADIO_STEP_POS = 2, + FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS, + FW_PHY_CFG_RADIO_DASH_POS = 4, + FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS, + FW_PHY_CFG_TX_CHAIN_POS = 16, + FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, + FW_PHY_CFG_RX_CHAIN_POS = 20, + FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, +}; + +#define IWL_UCODE_MAX_CS 1 + +/** + * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW. + * @cipher: a cipher suite selector + * @flags: cipher scheme flags (currently reserved for a future use) + * @hdr_len: a size of MPDU security header + * @pn_len: a size of PN + * @pn_off: an offset of pn from the beginning of the security header + * @key_idx_off: an offset of key index byte in the security header + * @key_idx_mask: a bit mask of key_idx bits + * @key_idx_shift: bit shift needed to get key_idx + * @mic_len: mic length in bytes + * @hw_cipher: a HW cipher index used in host commands + */ +struct iwl_fw_cipher_scheme { + __le32 cipher; + u8 flags; + u8 hdr_len; + u8 pn_len; + u8 pn_off; + u8 key_idx_off; + u8 key_idx_mask; + u8 key_idx_shift; + u8 mic_len; + u8 hw_cipher; +} __packed; + +enum iwl_fw_dbg_reg_operator { + CSR_ASSIGN, + CSR_SETBIT, + CSR_CLEARBIT, + + PRPH_ASSIGN, + PRPH_SETBIT, + PRPH_CLEARBIT, + + INDIRECT_ASSIGN, + INDIRECT_SETBIT, + INDIRECT_CLEARBIT, + + PRPH_BLOCKBIT, +}; + +/** + * struct iwl_fw_dbg_reg_op - an operation on a register + * + * @op: &enum iwl_fw_dbg_reg_operator + * @addr: offset of the register + * @val: value + */ +struct iwl_fw_dbg_reg_op { + u8 op; + u8 reserved[3]; + __le32 addr; + __le32 val; +} __packed; + +/** + * enum iwl_fw_dbg_monitor_mode - available monitor recording modes + * + * @SMEM_MODE: monitor stores the data in SMEM + * @EXTERNAL_MODE: monitor stores the data in allocated DRAM + * @MARBH_MODE: monitor stores the data in MARBH buffer + * @MIPI_MODE: monitor outputs the data through the MIPI interface + */ +enum iwl_fw_dbg_monitor_mode { + SMEM_MODE = 0, + EXTERNAL_MODE = 1, + MARBH_MODE = 2, + MIPI_MODE = 3, +}; + +/** + * enum iwl_fw_mem_seg_type - memory segment type + * @FW_DBG_MEM_TYPE_MASK: mask for the type indication + * @FW_DBG_MEM_TYPE_REGULAR: regular memory + * @FW_DBG_MEM_TYPE_PRPH: periphery memory (requires special reading) + */ +enum iwl_fw_mem_seg_type { + FW_DBG_MEM_TYPE_MASK = 0xff000000, + FW_DBG_MEM_TYPE_REGULAR = 0x00000000, + FW_DBG_MEM_TYPE_PRPH = 0x01000000, +}; + +/** + * struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments + * + * @data_type: the memory segment type to record, see &enum iwl_fw_mem_seg_type + * for what we care about + * @ofs: the memory segment offset + * @len: the memory segment length, in bytes + * + * This parses IWL_UCODE_TLV_FW_MEM_SEG + */ +struct iwl_fw_dbg_mem_seg_tlv { + __le32 data_type; + __le32 ofs; + __le32 len; +} __packed; + +/** + * struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data + * + * @version: version of the TLV - currently 0 + * @monitor_mode: &enum iwl_fw_dbg_monitor_mode + * @size_power: buffer size will be 2^(size_power + 11) + * @base_reg: addr of the base addr register (PRPH) + * @end_reg: addr of the end addr register (PRPH) + * @write_ptr_reg: the addr of the reg of the write pointer + * @wrap_count: the addr of the reg of the wrap_count + * @base_shift: shift right of the base addr reg + * @end_shift: shift right of the end addr reg + * @reg_ops: array of registers operations + * + * This parses IWL_UCODE_TLV_FW_DBG_DEST + */ +struct iwl_fw_dbg_dest_tlv { + u8 version; + u8 monitor_mode; + u8 size_power; + u8 reserved; + __le32 base_reg; + __le32 end_reg; + __le32 write_ptr_reg; + __le32 wrap_count; + u8 base_shift; + u8 end_shift; + struct iwl_fw_dbg_reg_op reg_ops[0]; +} __packed; + +struct iwl_fw_dbg_conf_hcmd { + u8 id; + u8 reserved; + __le16 len; + u8 data[0]; +} __packed; + +/** + * enum iwl_fw_dbg_trigger_mode - triggers functionalities + * + * @IWL_FW_DBG_TRIGGER_START: when trigger occurs re-conf the dbg mechanism + * @IWL_FW_DBG_TRIGGER_STOP: when trigger occurs pull the dbg data + * @IWL_FW_DBG_TRIGGER_MONITOR_ONLY: when trigger occurs trigger is set to + * collect only monitor data + */ +enum iwl_fw_dbg_trigger_mode { + IWL_FW_DBG_TRIGGER_START = BIT(0), + IWL_FW_DBG_TRIGGER_STOP = BIT(1), + IWL_FW_DBG_TRIGGER_MONITOR_ONLY = BIT(2), +}; + +/** + * enum iwl_fw_dbg_trigger_vif_type - define the VIF type for a trigger + * @IWL_FW_DBG_CONF_VIF_ANY: any vif type + * @IWL_FW_DBG_CONF_VIF_IBSS: IBSS mode + * @IWL_FW_DBG_CONF_VIF_STATION: BSS mode + * @IWL_FW_DBG_CONF_VIF_AP: AP mode + * @IWL_FW_DBG_CONF_VIF_P2P_CLIENT: P2P Client mode + * @IWL_FW_DBG_CONF_VIF_P2P_GO: P2P GO mode + * @IWL_FW_DBG_CONF_VIF_P2P_DEVICE: P2P device + */ +enum iwl_fw_dbg_trigger_vif_type { + IWL_FW_DBG_CONF_VIF_ANY = NL80211_IFTYPE_UNSPECIFIED, + IWL_FW_DBG_CONF_VIF_IBSS = NL80211_IFTYPE_ADHOC, + IWL_FW_DBG_CONF_VIF_STATION = NL80211_IFTYPE_STATION, + IWL_FW_DBG_CONF_VIF_AP = NL80211_IFTYPE_AP, + IWL_FW_DBG_CONF_VIF_P2P_CLIENT = NL80211_IFTYPE_P2P_CLIENT, + IWL_FW_DBG_CONF_VIF_P2P_GO = NL80211_IFTYPE_P2P_GO, + IWL_FW_DBG_CONF_VIF_P2P_DEVICE = NL80211_IFTYPE_P2P_DEVICE, +}; + +/** + * struct iwl_fw_dbg_trigger_tlv - a TLV that describes the trigger + * @id: &enum iwl_fw_dbg_trigger + * @vif_type: &enum iwl_fw_dbg_trigger_vif_type + * @stop_conf_ids: bitmap of configurations this trigger relates to. + * if the mode is %IWL_FW_DBG_TRIGGER_STOP, then if the bit corresponding + * to the currently running configuration is set, the data should be + * collected. + * @stop_delay: how many milliseconds to wait before collecting the data + * after the STOP trigger fires. + * @mode: &enum iwl_fw_dbg_trigger_mode - can be stop / start of both + * @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what + * configuration should be applied when the triggers kicks in. + * @occurrences: number of occurrences. 0 means the trigger will never fire. + * @trig_dis_ms: the time, in milliseconds, after an occurrence of this + * trigger in which another occurrence should be ignored. + */ +struct iwl_fw_dbg_trigger_tlv { + __le32 id; + __le32 vif_type; + __le32 stop_conf_ids; + __le32 stop_delay; + u8 mode; + u8 start_conf_id; + __le16 occurrences; + __le16 trig_dis_ms; + __le16 reserved[3]; + + u8 data[0]; +} __packed; + +#define FW_DBG_START_FROM_ALIVE 0 +#define FW_DBG_CONF_MAX 32 +#define FW_DBG_INVALID 0xff + +/** + * struct iwl_fw_dbg_trigger_missed_bcon - configures trigger for missed beacons + * @stop_consec_missed_bcon: stop recording if threshold is crossed. + * @stop_consec_missed_bcon_since_rx: stop recording if threshold is crossed. + * @start_consec_missed_bcon: start recording if threshold is crossed. + * @start_consec_missed_bcon_since_rx: start recording if threshold is crossed. + * @reserved1: reserved + * @reserved2: reserved + */ +struct iwl_fw_dbg_trigger_missed_bcon { + __le32 stop_consec_missed_bcon; + __le32 stop_consec_missed_bcon_since_rx; + __le32 reserved2[2]; + __le32 start_consec_missed_bcon; + __le32 start_consec_missed_bcon_since_rx; + __le32 reserved1[2]; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_cmd - configures trigger for messages from FW. + * cmds: the list of commands to trigger the collection on + */ +struct iwl_fw_dbg_trigger_cmd { + struct cmd { + u8 cmd_id; + u8 group_id; + } __packed cmds[16]; +} __packed; + +/** + * iwl_fw_dbg_trigger_stats - configures trigger for statistics + * @stop_offset: the offset of the value to be monitored + * @stop_threshold: the threshold above which to collect + * @start_offset: the offset of the value to be monitored + * @start_threshold: the threshold above which to start recording + */ +struct iwl_fw_dbg_trigger_stats { + __le32 stop_offset; + __le32 stop_threshold; + __le32 start_offset; + __le32 start_threshold; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_low_rssi - trigger for low beacon RSSI + * @rssi: RSSI value to trigger at + */ +struct iwl_fw_dbg_trigger_low_rssi { + __le32 rssi; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_mlme - configures trigger for mlme events + * @stop_auth_denied: number of denied authentication to collect + * @stop_auth_timeout: number of authentication timeout to collect + * @stop_rx_deauth: number of Rx deauth before to collect + * @stop_tx_deauth: number of Tx deauth before to collect + * @stop_assoc_denied: number of denied association to collect + * @stop_assoc_timeout: number of association timeout to collect + * @stop_connection_loss: number of connection loss to collect + * @start_auth_denied: number of denied authentication to start recording + * @start_auth_timeout: number of authentication timeout to start recording + * @start_rx_deauth: number of Rx deauth to start recording + * @start_tx_deauth: number of Tx deauth to start recording + * @start_assoc_denied: number of denied association to start recording + * @start_assoc_timeout: number of association timeout to start recording + * @start_connection_loss: number of connection loss to start recording + */ +struct iwl_fw_dbg_trigger_mlme { + u8 stop_auth_denied; + u8 stop_auth_timeout; + u8 stop_rx_deauth; + u8 stop_tx_deauth; + + u8 stop_assoc_denied; + u8 stop_assoc_timeout; + u8 stop_connection_loss; + u8 reserved; + + u8 start_auth_denied; + u8 start_auth_timeout; + u8 start_rx_deauth; + u8 start_tx_deauth; + + u8 start_assoc_denied; + u8 start_assoc_timeout; + u8 start_connection_loss; + u8 reserved2; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_txq_timer - configures the Tx queue's timer + * @command_queue: timeout for the command queue in ms + * @bss: timeout for the queues of a BSS (except for TDLS queues) in ms + * @softap: timeout for the queues of a softAP in ms + * @p2p_go: timeout for the queues of a P2P GO in ms + * @p2p_client: timeout for the queues of a P2P client in ms + * @p2p_device: timeout for the queues of a P2P device in ms + * @ibss: timeout for the queues of an IBSS in ms + * @tdls: timeout for the queues of a TDLS station in ms + */ +struct iwl_fw_dbg_trigger_txq_timer { + __le32 command_queue; + __le32 bss; + __le32 softap; + __le32 p2p_go; + __le32 p2p_client; + __le32 p2p_device; + __le32 ibss; + __le32 tdls; + __le32 reserved[4]; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_time_event - configures a time event trigger + * time_Events: a list of tuples . The driver will issue a + * trigger each time a time event notification that relates to time event + * id with one of the actions in the bitmap is received and + * BIT(notif->status) is set in status_bitmap. + * + */ +struct iwl_fw_dbg_trigger_time_event { + struct { + __le32 id; + __le32 action_bitmap; + __le32 status_bitmap; + } __packed time_events[16]; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_ba - configures BlockAck related trigger + * rx_ba_start: tid bitmap to configure on what tid the trigger should occur + * when an Rx BlockAck session is started. + * rx_ba_stop: tid bitmap to configure on what tid the trigger should occur + * when an Rx BlockAck session is stopped. + * tx_ba_start: tid bitmap to configure on what tid the trigger should occur + * when a Tx BlockAck session is started. + * tx_ba_stop: tid bitmap to configure on what tid the trigger should occur + * when a Tx BlockAck session is stopped. + * rx_bar: tid bitmap to configure on what tid the trigger should occur + * when a BAR is received (for a Tx BlockAck session). + * tx_bar: tid bitmap to configure on what tid the trigger should occur + * when a BAR is send (for an Rx BlocAck session). + * frame_timeout: tid bitmap to configure on what tid the trigger should occur + * when a frame times out in the reodering buffer. + */ +struct iwl_fw_dbg_trigger_ba { + __le16 rx_ba_start; + __le16 rx_ba_stop; + __le16 tx_ba_start; + __le16 tx_ba_stop; + __le16 rx_bar; + __le16 tx_bar; + __le16 frame_timeout; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_tdls - configures trigger for TDLS events. + * @action_bitmap: the TDLS action to trigger the collection upon + * @peer_mode: trigger on specific peer or all + * @peer: the TDLS peer to trigger the collection on + */ +struct iwl_fw_dbg_trigger_tdls { + u8 action_bitmap; + u8 peer_mode; + u8 peer[ETH_ALEN]; + u8 reserved[4]; +} __packed; + +/** + * struct iwl_fw_dbg_trigger_tx_status - configures trigger for tx response + * status. + * @statuses: the list of statuses to trigger the collection on + */ +struct iwl_fw_dbg_trigger_tx_status { + struct tx_status { + u8 status; + u8 reserved[3]; + } __packed statuses[16]; + __le32 reserved[2]; +} __packed; + +/** + * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration. + * @id: conf id + * @usniffer: should the uSniffer image be used + * @num_of_hcmds: how many HCMDs to send are present here + * @hcmd: a variable length host command to be sent to apply the configuration. + * If there is more than one HCMD to send, they will appear one after the + * other and be sent in the order that they appear in. + * This parses IWL_UCODE_TLV_FW_DBG_CONF. The user can add up-to + * %FW_DBG_CONF_MAX configuration per run. + */ +struct iwl_fw_dbg_conf_tlv { + u8 id; + u8 usniffer; + u8 reserved; + u8 num_of_hcmds; + struct iwl_fw_dbg_conf_hcmd hcmd; +} __packed; + +/** + * struct iwl_fw_gscan_capabilities - gscan capabilities supported by FW + * @max_scan_cache_size: total space allocated for scan results (in bytes). + * @max_scan_buckets: maximum number of channel buckets. + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. + * @max_scan_reporting_threshold: max possible report threshold. in percentage. + * @max_hotlist_aps: maximum number of entries for hotlist APs. + * @max_significant_change_aps: maximum number of entries for significant + * change APs. + * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can + * hold. + * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs. + * @max_number_epno_networks: max number of epno entries. + * @max_number_epno_networks_by_ssid: max number of epno entries if ssid is + * specified. + * @max_number_of_white_listed_ssid: max number of white listed SSIDs. + * @max_number_of_black_listed_ssid: max number of black listed SSIDs. + */ +struct iwl_fw_gscan_capabilities { + __le32 max_scan_cache_size; + __le32 max_scan_buckets; + __le32 max_ap_cache_per_scan; + __le32 max_rssi_sample_size; + __le32 max_scan_reporting_threshold; + __le32 max_hotlist_aps; + __le32 max_significant_change_aps; + __le32 max_bssid_history_entries; + __le32 max_hotlist_ssids; + __le32 max_number_epno_networks; + __le32 max_number_epno_networks_by_ssid; + __le32 max_number_of_white_listed_ssid; + __le32 max_number_of_black_listed_ssid; +} __packed; + +#endif /* __iwl_fw_file_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h new file mode 100644 index 000000000000..e6bc9cb60700 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -0,0 +1,342 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwl_fw_img_h__ +#define __iwl_fw_img_h__ +#include + +#include "file.h" +#include "error-dump.h" + +/** + * enum iwl_ucode_type + * + * The type of ucode. + * + * @IWL_UCODE_REGULAR: Normal runtime ucode + * @IWL_UCODE_INIT: Initial ucode + * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode + * @IWL_UCODE_REGULAR_USNIFFER: Normal runtime ucode when using usniffer image + */ +enum iwl_ucode_type { + IWL_UCODE_REGULAR, + IWL_UCODE_INIT, + IWL_UCODE_WOWLAN, + IWL_UCODE_REGULAR_USNIFFER, + IWL_UCODE_TYPE_MAX, +}; + +/* + * enumeration of ucode section. + * This enumeration is used directly for older firmware (before 16.0). + * For new firmware, there can be up to 4 sections (see below) but the + * first one packaged into the firmware file is the DATA section and + * some debugging code accesses that. + */ +enum iwl_ucode_sec { + IWL_UCODE_SECTION_DATA, + IWL_UCODE_SECTION_INST, +}; + +struct iwl_ucode_capabilities { + u32 max_probe_length; + u32 n_scan_channels; + u32 standard_phy_calibration_size; + u32 flags; + unsigned long _api[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_API)]; + unsigned long _capa[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_CAPA)]; +}; + +static inline bool +fw_has_api(const struct iwl_ucode_capabilities *capabilities, + iwl_ucode_tlv_api_t api) +{ + return test_bit((__force long)api, capabilities->_api); +} + +static inline bool +fw_has_capa(const struct iwl_ucode_capabilities *capabilities, + iwl_ucode_tlv_capa_t capa) +{ + return test_bit((__force long)capa, capabilities->_capa); +} + +/* one for each uCode image (inst/data, init/runtime/wowlan) */ +struct fw_desc { + const void *data; /* vmalloc'ed data */ + u32 len; /* size in bytes */ + u32 offset; /* offset in the device */ +}; + +struct fw_img { + struct fw_desc *sec; + int num_sec; + bool is_dual_cpus; + u32 paging_mem_size; +}; + +struct iwl_sf_region { + u32 addr; + u32 size; +}; + +/* + * Block paging calculations + */ +#define PAGE_2_EXP_SIZE 12 /* 4K == 2^12 */ +#define FW_PAGING_SIZE BIT(PAGE_2_EXP_SIZE) /* page size is 4KB */ +#define PAGE_PER_GROUP_2_EXP_SIZE 3 +/* 8 pages per group */ +#define NUM_OF_PAGE_PER_GROUP BIT(PAGE_PER_GROUP_2_EXP_SIZE) +/* don't change, support only 32KB size */ +#define PAGING_BLOCK_SIZE (NUM_OF_PAGE_PER_GROUP * FW_PAGING_SIZE) +/* 32K == 2^15 */ +#define BLOCK_2_EXP_SIZE (PAGE_2_EXP_SIZE + PAGE_PER_GROUP_2_EXP_SIZE) + +/* + * Image paging calculations + */ +#define BLOCK_PER_IMAGE_2_EXP_SIZE 5 +/* 2^5 == 32 blocks per image */ +#define NUM_OF_BLOCK_PER_IMAGE BIT(BLOCK_PER_IMAGE_2_EXP_SIZE) +/* maximum image size 1024KB */ +#define MAX_PAGING_IMAGE_SIZE (NUM_OF_BLOCK_PER_IMAGE * PAGING_BLOCK_SIZE) + +/* Virtual address signature */ +#define PAGING_ADDR_SIG 0xAA000000 + +#define PAGING_CMD_IS_SECURED BIT(9) +#define PAGING_CMD_IS_ENABLED BIT(8) +#define PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS 0 +#define PAGING_TLV_SECURE_MASK 1 + +/** + * struct iwl_fw_paging + * @fw_paging_phys: page phy pointer + * @fw_paging_block: pointer to the allocated block + * @fw_paging_size: page size + */ +struct iwl_fw_paging { + dma_addr_t fw_paging_phys; + struct page *fw_paging_block; + u32 fw_paging_size; +}; + +/** + * struct iwl_fw_cscheme_list - a cipher scheme list + * @size: a number of entries + * @cs: cipher scheme entries + */ +struct iwl_fw_cscheme_list { + u8 size; + struct iwl_fw_cipher_scheme cs[]; +} __packed; + +/** + * struct iwl_gscan_capabilities - gscan capabilities supported by FW + * @max_scan_cache_size: total space allocated for scan results (in bytes). + * @max_scan_buckets: maximum number of channel buckets. + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. + * @max_scan_reporting_threshold: max possible report threshold. in percentage. + * @max_hotlist_aps: maximum number of entries for hotlist APs. + * @max_significant_change_aps: maximum number of entries for significant + * change APs. + * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can + * hold. + * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs. + * @max_number_epno_networks: max number of epno entries. + * @max_number_epno_networks_by_ssid: max number of epno entries if ssid is + * specified. + * @max_number_of_white_listed_ssid: max number of white listed SSIDs. + * @max_number_of_black_listed_ssid: max number of black listed SSIDs. + */ +struct iwl_gscan_capabilities { + u32 max_scan_cache_size; + u32 max_scan_buckets; + u32 max_ap_cache_per_scan; + u32 max_rssi_sample_size; + u32 max_scan_reporting_threshold; + u32 max_hotlist_aps; + u32 max_significant_change_aps; + u32 max_bssid_history_entries; + u32 max_hotlist_ssids; + u32 max_number_epno_networks; + u32 max_number_epno_networks_by_ssid; + u32 max_number_of_white_listed_ssid; + u32 max_number_of_black_listed_ssid; +}; + +/** + * enum iwl_fw_type - iwlwifi firmware type + * @IWL_FW_DVM: DVM firmware + * @IWL_FW_MVM: MVM firmware + */ +enum iwl_fw_type { + IWL_FW_DVM, + IWL_FW_MVM, +}; + +/** + * struct iwl_fw - variables associated with the firmware + * + * @ucode_ver: ucode version from the ucode file + * @fw_version: firmware version string + * @img: ucode image like ucode_rt, ucode_init, ucode_wowlan. + * @ucode_capa: capabilities parsed from the ucode file. + * @enhance_sensitivity_table: device can do enhanced sensitivity. + * @init_evtlog_ptr: event log offset for init ucode. + * @init_evtlog_size: event log size for init ucode. + * @init_errlog_ptr: error log offfset for init ucode. + * @inst_evtlog_ptr: event log offset for runtime ucode. + * @inst_evtlog_size: event log size for runtime ucode. + * @inst_errlog_ptr: error log offfset for runtime ucode. + * @type: firmware type (&enum iwl_fw_type) + * @cipher_scheme: optional external cipher scheme. + * @human_readable: human readable version + * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until + * we get the ALIVE from the uCode + * @dbg_dest_tlv: points to the destination TLV for debug + * @dbg_conf_tlv: array of pointers to configuration TLVs for debug + * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries + * @dbg_trigger_tlv: array of pointers to triggers TLVs + * @dbg_trigger_tlv_len: lengths of the @dbg_trigger_tlv entries + * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv + */ +struct iwl_fw { + u32 ucode_ver; + + char fw_version[ETHTOOL_FWVERS_LEN]; + + /* ucode images */ + struct fw_img img[IWL_UCODE_TYPE_MAX]; + + struct iwl_ucode_capabilities ucode_capa; + bool enhance_sensitivity_table; + + u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; + u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; + + struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX]; + u32 phy_config; + u8 valid_tx_ant; + u8 valid_rx_ant; + + enum iwl_fw_type type; + + struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS]; + u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; + + u32 sdio_adma_addr; + + struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; + struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX]; + size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX]; + struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX]; + struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv; + size_t n_dbg_mem_tlv; + size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX]; + u8 dbg_dest_reg_num; + struct iwl_gscan_capabilities gscan_capa; +}; + +static inline const char *get_fw_dbg_mode_string(int mode) +{ + switch (mode) { + case SMEM_MODE: + return "SMEM"; + case EXTERNAL_MODE: + return "EXTERNAL_DRAM"; + case MARBH_MODE: + return "MARBH"; + case MIPI_MODE: + return "MIPI"; + default: + return "UNKNOWN"; + } +} + +static inline bool +iwl_fw_dbg_conf_usniffer(const struct iwl_fw *fw, u8 id) +{ + const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id]; + + if (!conf_tlv) + return false; + + return conf_tlv->usniffer; +} + +static inline const struct fw_img * +iwl_get_ucode_image(const struct iwl_fw *fw, enum iwl_ucode_type ucode_type) +{ + if (ucode_type >= IWL_UCODE_TYPE_MAX) + return NULL; + + return &fw->img[ucode_type]; +} + +#endif /* __iwl_fw_img_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index b5ebd0fcfbf6..6fdb5921e17f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -76,7 +76,7 @@ #include "iwl-trans.h" #include "iwl-op-mode.h" #include "iwl-agn-hw.h" -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-config.h" #include "iwl-modparams.h" diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h deleted file mode 100644 index 0e107f916ce3..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-api.h +++ /dev/null @@ -1,229 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -#ifndef __iwl_fw_api_h__ -#define __iwl_fw_api_h__ - -/** - * DOC: Host command section - * - * A host command is a command issued by the upper layer to the fw. There are - * several versions of fw that have several APIs. The transport layer is - * completely agnostic to these differences. - * The transport does provide helper functionality (i.e. SYNC / ASYNC mode), - */ -#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) -#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) -#define SEQ_TO_INDEX(s) ((s) & 0xff) -#define INDEX_TO_SEQ(i) ((i) & 0xff) -#define SEQ_RX_FRAME cpu_to_le16(0x8000) - -/* - * those functions retrieve specific information from - * the id field in the iwl_host_cmd struct which contains - * the command id, the group id and the version of the command - * and vice versa -*/ -static inline u8 iwl_cmd_opcode(u32 cmdid) -{ - return cmdid & 0xFF; -} - -static inline u8 iwl_cmd_groupid(u32 cmdid) -{ - return ((cmdid & 0xFF00) >> 8); -} - -static inline u8 iwl_cmd_version(u32 cmdid) -{ - return ((cmdid & 0xFF0000) >> 16); -} - -static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) -{ - return opcode + (groupid << 8) + (version << 16); -} - -/* make u16 wide id out of u8 group and opcode */ -#define WIDE_ID(grp, opcode) (((grp) << 8) | (opcode)) -#define DEF_ID(opcode) ((1 << 8) | (opcode)) - -/* due to the conversion, this group is special; new groups - * should be defined in the appropriate fw-api header files - */ -#define IWL_ALWAYS_LONG_GROUP 1 - -/** - * struct iwl_cmd_header - * - * This header format appears in the beginning of each command sent from the - * driver, and each response/notification received from uCode. - */ -struct iwl_cmd_header { - u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 group_id; - /* - * The driver sets up the sequence number to values of its choosing. - * uCode does not use this value, but passes it back to the driver - * when sending the response to each driver-originated command, so - * the driver can match the response to the command. Since the values - * don't get used by uCode, the driver may set up an arbitrary format. - * - * There is one exception: uCode sets bit 15 when it originates - * the response/notification, i.e. when the response/notification - * is not a direct response to a command sent by the driver. For - * example, uCode issues REPLY_RX when it sends a received frame - * to the driver; it is not a direct response to any driver command. - * - * The Linux driver uses the following format: - * - * 0:7 tfd index - position within TX queue - * 8:12 TX queue id - * 13:14 reserved - * 15 unsolicited RX or uCode-originated notification - */ - __le16 sequence; -} __packed; - -/** - * struct iwl_cmd_header_wide - * - * This header format appears in the beginning of each command sent from the - * driver, and each response/notification received from uCode. - * this is the wide version that contains more information about the command - * like length, version and command type - */ -struct iwl_cmd_header_wide { - u8 cmd; - u8 group_id; - __le16 sequence; - __le16 length; - u8 reserved; - u8 version; -} __packed; - -/** - * iwl_tx_queue_cfg_actions - TXQ config options - * @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue - * @TX_QUEUE_CFG_TFD_SHORT_FORMAT: use short TFD format - */ -enum iwl_tx_queue_cfg_actions { - TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0), - TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), -}; - -/** - * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command - * @sta_id: station id - * @tid: tid of the queue - * @flags: see &enum iwl_tx_queue_cfg_actions - * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. - * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) - * @byte_cnt_addr: address of byte count table - * @tfdq_addr: address of TFD circular buffer - */ -struct iwl_tx_queue_cfg_cmd { - u8 sta_id; - u8 tid; - __le16 flags; - __le32 cb_size; - __le64 byte_cnt_addr; - __le64 tfdq_addr; -} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ - -/** - * struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config - * @queue_number: queue number assigned to this RA -TID - * @flags: set on failure - * @write_pointer: initial value for write pointer - */ -struct iwl_tx_queue_cfg_rsp { - __le16 queue_number; - __le16 flags; - __le16 write_pointer; - __le16 reserved; -} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ - -/** - * struct iwl_calib_res_notif_phy_db - Receive phy db chunk after calibrations - * @type: type of the result - mostly ignored - * @length: length of the data - * @data: data, length in @length - */ -struct iwl_calib_res_notif_phy_db { - __le16 type; - __le16 length; - u8 data[]; -} __packed; - -/** - * struct iwl_phy_db_cmd - configure operational ucode - * @type: type of the data - * @length: length of the data - * @data: data, length in @length - */ -struct iwl_phy_db_cmd { - __le16 type; - __le16 length; - u8 data[]; -} __packed; - -#endif /* __iwl_fw_api_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h deleted file mode 100644 index cfebde68a391..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h +++ /dev/null @@ -1,335 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifndef __fw_error_dump_h__ -#define __fw_error_dump_h__ - -#include - -#define IWL_FW_ERROR_DUMP_BARKER 0x14789632 - -/** - * enum iwl_fw_error_dump_type - types of data in the dump file - * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0 - * @IWL_FW_ERROR_DUMP_RXF: - * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as - * &struct iwl_fw_error_dump_txcmd packets - * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info - * info on the device / firmware. - * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor - * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several - * sections like this in a single file. - * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers - * @IWL_FW_ERROR_DUMP_MEM: chunk of memory - * @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump. - * Structured as &struct iwl_fw_error_dump_trigger_desc. - * @IWL_FW_ERROR_DUMP_RB: the content of an RB structured as - * &struct iwl_fw_error_dump_rb - * @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were - * paged to the DRAM. - * @IWL_FW_ERROR_DUMP_RADIO_REG: Dump the radio registers. - * @IWL_FW_ERROR_DUMP_EXTERNAL: used only by external code utilities, and - * for that reason is not in use in any other place in the Linux Wi-Fi - * stack. - */ -enum iwl_fw_error_dump_type { - /* 0 is deprecated */ - IWL_FW_ERROR_DUMP_CSR = 1, - IWL_FW_ERROR_DUMP_RXF = 2, - IWL_FW_ERROR_DUMP_TXCMD = 3, - IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, - IWL_FW_ERROR_DUMP_FW_MONITOR = 5, - IWL_FW_ERROR_DUMP_PRPH = 6, - IWL_FW_ERROR_DUMP_TXF = 7, - IWL_FW_ERROR_DUMP_FH_REGS = 8, - IWL_FW_ERROR_DUMP_MEM = 9, - IWL_FW_ERROR_DUMP_ERROR_INFO = 10, - IWL_FW_ERROR_DUMP_RB = 11, - IWL_FW_ERROR_DUMP_PAGING = 12, - IWL_FW_ERROR_DUMP_RADIO_REG = 13, - IWL_FW_ERROR_DUMP_INTERNAL_TXF = 14, - IWL_FW_ERROR_DUMP_EXTERNAL = 15, /* Do not move */ - - IWL_FW_ERROR_DUMP_MAX, -}; - -/** - * struct iwl_fw_error_dump_data - data for one type - * @type: &enum iwl_fw_error_dump_type - * @len: the length starting from %data - * @data: the data itself - */ -struct iwl_fw_error_dump_data { - __le32 type; - __le32 len; - __u8 data[]; -} __packed; - -/** - * struct iwl_fw_error_dump_file - the layout of the header of the file - * @barker: must be %IWL_FW_ERROR_DUMP_BARKER - * @file_len: the length of all the file starting from %barker - * @data: array of &struct iwl_fw_error_dump_data - */ -struct iwl_fw_error_dump_file { - __le32 barker; - __le32 file_len; - u8 data[0]; -} __packed; - -/** - * struct iwl_fw_error_dump_txcmd - TX command data - * @cmdlen: original length of command - * @caplen: captured length of command (may be less) - * @data: captured command data, @caplen bytes - */ -struct iwl_fw_error_dump_txcmd { - __le32 cmdlen; - __le32 caplen; - u8 data[]; -} __packed; - -/** - * struct iwl_fw_error_dump_fifo - RX/TX FIFO data - * @fifo_num: number of FIFO (starting from 0) - * @available_bytes: num of bytes available in FIFO (may be less than FIFO size) - * @wr_ptr: position of write pointer - * @rd_ptr: position of read pointer - * @fence_ptr: position of fence pointer - * @fence_mode: the current mode of the fence (before locking) - - * 0=follow RD pointer ; 1 = freeze - * @data: all of the FIFO's data - */ -struct iwl_fw_error_dump_fifo { - __le32 fifo_num; - __le32 available_bytes; - __le32 wr_ptr; - __le32 rd_ptr; - __le32 fence_ptr; - __le32 fence_mode; - u8 data[]; -} __packed; - -enum iwl_fw_error_dump_family { - IWL_FW_ERROR_DUMP_FAMILY_7 = 7, - IWL_FW_ERROR_DUMP_FAMILY_8 = 8, -}; - -/** - * struct iwl_fw_error_dump_info - info on the device / firmware - * @device_family: the family of the device (7 / 8) - * @hw_step: the step of the device - * @fw_human_readable: human readable FW version - * @dev_human_readable: name of the device - * @bus_human_readable: name of the bus used - */ -struct iwl_fw_error_dump_info { - __le32 device_family; - __le32 hw_step; - u8 fw_human_readable[FW_VER_HUMAN_READABLE_SZ]; - u8 dev_human_readable[64]; - u8 bus_human_readable[8]; -} __packed; - -/** - * struct iwl_fw_error_dump_fw_mon - FW monitor data - * @fw_mon_wr_ptr: the position of the write pointer in the cyclic buffer - * @fw_mon_base_ptr: base pointer of the data - * @fw_mon_cycle_cnt: number of wraparounds - * @reserved: for future use - * @data: captured data - */ -struct iwl_fw_error_dump_fw_mon { - __le32 fw_mon_wr_ptr; - __le32 fw_mon_base_ptr; - __le32 fw_mon_cycle_cnt; - __le32 reserved[3]; - u8 data[]; -} __packed; - -/** - * struct iwl_fw_error_dump_prph - periphery registers data - * @prph_start: address of the first register in this chunk - * @data: the content of the registers - */ -struct iwl_fw_error_dump_prph { - __le32 prph_start; - __le32 data[]; -}; - -enum iwl_fw_error_dump_mem_type { - IWL_FW_ERROR_DUMP_MEM_SRAM, - IWL_FW_ERROR_DUMP_MEM_SMEM, -}; - -/** - * struct iwl_fw_error_dump_mem - chunk of memory - * @type: &enum iwl_fw_error_dump_mem_type - * @offset: the offset from which the memory was read - * @data: the content of the memory - */ -struct iwl_fw_error_dump_mem { - __le32 type; - __le32 offset; - u8 data[]; -}; - -/** - * struct iwl_fw_error_dump_rb - content of an Receive Buffer - * @index: the index of the Receive Buffer in the Rx queue - * @rxq: the RB's Rx queue - * @reserved: - * @data: the content of the Receive Buffer - */ -struct iwl_fw_error_dump_rb { - __le32 index; - __le32 rxq; - __le32 reserved; - u8 data[]; -}; - -/** - * struct iwl_fw_error_dump_paging - content of the UMAC's image page - * block on DRAM - * @index: the index of the page block - * @reserved: - * @data: the content of the page block - */ -struct iwl_fw_error_dump_paging { - __le32 index; - __le32 reserved; - u8 data[]; -}; - -/** - * iwl_fw_error_next_data - advance fw error dump data pointer - * @data: previous data block - * Returns: next data block - */ -static inline struct iwl_fw_error_dump_data * -iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) -{ - return (void *)(data->data + le32_to_cpu(data->len)); -} - -/** - * enum iwl_fw_dbg_trigger - triggers available - * - * @FW_DBG_TRIGGER_USER: trigger log collection by user - * This should not be defined as a trigger to the driver, but a value the - * driver should set to indicate that the trigger was initiated by the - * user. - * @FW_DBG_TRIGGER_FW_ASSERT: trigger log collection when the firmware asserts - * @FW_DBG_TRIGGER_MISSED_BEACONS: trigger log collection when beacons are - * missed. - * @FW_DBG_TRIGGER_CHANNEL_SWITCH: trigger log collection upon channel switch. - * @FW_DBG_TRIGGER_FW_NOTIF: trigger log collection when the firmware sends a - * command response or a notification. - * @FW_DBG_TRIGGER_MLME: trigger log collection upon MLME event. - * @FW_DBG_TRIGGER_STATS: trigger log collection upon statistics threshold. - * @FW_DBG_TRIGGER_RSSI: trigger log collection when the rssi of the beacon - * goes below a threshold. - * @FW_DBG_TRIGGER_TXQ_TIMERS: configures the timers for the Tx queue hang - * detection. - * @FW_DBG_TRIGGER_TIME_EVENT: trigger log collection upon time events related - * events. - * @FW_DBG_TRIGGER_BA: trigger log collection upon BlockAck related events. - * @FW_DBG_TX_LATENCY: trigger log collection when the tx latency goes above a - * threshold. - * @FW_DBG_TDLS: trigger log collection upon TDLS related events. - * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when - * the firmware sends a tx reply. - */ -enum iwl_fw_dbg_trigger { - FW_DBG_TRIGGER_INVALID = 0, - FW_DBG_TRIGGER_USER, - FW_DBG_TRIGGER_FW_ASSERT, - FW_DBG_TRIGGER_MISSED_BEACONS, - FW_DBG_TRIGGER_CHANNEL_SWITCH, - FW_DBG_TRIGGER_FW_NOTIF, - FW_DBG_TRIGGER_MLME, - FW_DBG_TRIGGER_STATS, - FW_DBG_TRIGGER_RSSI, - FW_DBG_TRIGGER_TXQ_TIMERS, - FW_DBG_TRIGGER_TIME_EVENT, - FW_DBG_TRIGGER_BA, - FW_DBG_TRIGGER_TX_LATENCY, - FW_DBG_TRIGGER_TDLS, - FW_DBG_TRIGGER_TX_STATUS, - - /* must be last */ - FW_DBG_TRIGGER_MAX, -}; - -/** - * struct iwl_fw_error_dump_trigger_desc - describes the trigger condition - * @type: &enum iwl_fw_dbg_trigger - * @data: raw data about what happened - */ -struct iwl_fw_error_dump_trigger_desc { - __le32 type; - u8 data[]; -}; - -#endif /* __fw_error_dump_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h deleted file mode 100644 index a216657b3c60..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ /dev/null @@ -1,870 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifndef __iwl_fw_file_h__ -#define __iwl_fw_file_h__ - -#include -#include - -/* v1/v2 uCode file layout */ -struct iwl_ucode_header { - __le32 ver; /* major/minor/API/serial */ - union { - struct { - __le32 inst_size; /* bytes of runtime code */ - __le32 data_size; /* bytes of runtime data */ - __le32 init_size; /* bytes of init code */ - __le32 init_data_size; /* bytes of init data */ - __le32 boot_size; /* bytes of bootstrap code */ - u8 data[0]; /* in same order as sizes */ - } v1; - struct { - __le32 build; /* build number */ - __le32 inst_size; /* bytes of runtime code */ - __le32 data_size; /* bytes of runtime data */ - __le32 init_size; /* bytes of init code */ - __le32 init_data_size; /* bytes of init data */ - __le32 boot_size; /* bytes of bootstrap code */ - u8 data[0]; /* in same order as sizes */ - } v2; - } u; -}; - -/* - * new TLV uCode file layout - * - * The new TLV file format contains TLVs, that each specify - * some piece of data. - */ - -enum iwl_ucode_tlv_type { - IWL_UCODE_TLV_INVALID = 0, /* unused */ - IWL_UCODE_TLV_INST = 1, - IWL_UCODE_TLV_DATA = 2, - IWL_UCODE_TLV_INIT = 3, - IWL_UCODE_TLV_INIT_DATA = 4, - IWL_UCODE_TLV_BOOT = 5, - IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */ - IWL_UCODE_TLV_PAN = 7, - IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8, - IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9, - IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10, - IWL_UCODE_TLV_INIT_EVTLOG_PTR = 11, - IWL_UCODE_TLV_INIT_EVTLOG_SIZE = 12, - IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, - IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, - IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, - IWL_UCODE_TLV_WOWLAN_INST = 16, - IWL_UCODE_TLV_WOWLAN_DATA = 17, - IWL_UCODE_TLV_FLAGS = 18, - IWL_UCODE_TLV_SEC_RT = 19, - IWL_UCODE_TLV_SEC_INIT = 20, - IWL_UCODE_TLV_SEC_WOWLAN = 21, - IWL_UCODE_TLV_DEF_CALIB = 22, - IWL_UCODE_TLV_PHY_SKU = 23, - IWL_UCODE_TLV_SECURE_SEC_RT = 24, - IWL_UCODE_TLV_SECURE_SEC_INIT = 25, - IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26, - IWL_UCODE_TLV_NUM_OF_CPU = 27, - IWL_UCODE_TLV_CSCHEME = 28, - IWL_UCODE_TLV_API_CHANGES_SET = 29, - IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, - IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, - IWL_UCODE_TLV_PAGING = 32, - IWL_UCODE_TLV_SEC_RT_USNIFFER = 34, - IWL_UCODE_TLV_SDIO_ADMA_ADDR = 35, - IWL_UCODE_TLV_FW_VERSION = 36, - IWL_UCODE_TLV_FW_DBG_DEST = 38, - IWL_UCODE_TLV_FW_DBG_CONF = 39, - IWL_UCODE_TLV_FW_DBG_TRIGGER = 40, - IWL_UCODE_TLV_FW_GSCAN_CAPA = 50, - IWL_UCODE_TLV_FW_MEM_SEG = 51, -}; - -struct iwl_ucode_tlv { - __le32 type; /* see above */ - __le32 length; /* not including type/length fields */ - u8 data[0]; -}; - -#define IWL_TLV_UCODE_MAGIC 0x0a4c5749 -#define FW_VER_HUMAN_READABLE_SZ 64 - -struct iwl_tlv_ucode_header { - /* - * The TLV style ucode header is distinguished from - * the v1/v2 style header by first four bytes being - * zero, as such is an invalid combination of - * major/minor/API/serial versions. - */ - __le32 zero; - __le32 magic; - u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; - /* major/minor/API/serial or major in new format */ - __le32 ver; - __le32 build; - __le64 ignore; - /* - * The data contained herein has a TLV layout, - * see above for the TLV header and types. - * Note that each TLV is padded to a length - * that is a multiple of 4 for alignment. - */ - u8 data[0]; -}; - -/* - * ucode TLVs - * - * ability to get extension for: flags & capabilities from ucode binaries files - */ -struct iwl_ucode_api { - __le32 api_index; - __le32 api_flags; -} __packed; - -struct iwl_ucode_capa { - __le32 api_index; - __le32 api_capa; -} __packed; - -/** - * enum iwl_ucode_tlv_flag - ucode API flags - * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously - * was a separate TLV but moved here to save space. - * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behavior on hidden SSID, - * treats good CRC threshold as a boolean - * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). - * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: This uCode image supports uAPSD - * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan - * offload profile config command. - * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six - * (rather than two) IPv6 addresses - * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element - * from the probe request template. - * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) - * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) - * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD - * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save - * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. - * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. - */ -enum iwl_ucode_tlv_flag { - IWL_UCODE_TLV_FLAGS_PAN = BIT(0), - IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), - IWL_UCODE_TLV_FLAGS_MFP = BIT(2), - IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7), - IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), - IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), - IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15), - IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16), - IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24), - IWL_UCODE_TLV_FLAGS_EBS_SUPPORT = BIT(25), - IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26), - IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), -}; - -typedef unsigned int __bitwise iwl_ucode_tlv_api_t; - -/** - * enum iwl_ucode_tlv_api - ucode api - * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time - * longer than the passive one, which is essential for fragmented scan. - * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. - * @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params - * @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format - * @IWL_UCODE_TLV_API_SCAN_TSF_REPORT: Scan start time reported in scan - * iteration complete notification, and the timestamp reported for RX - * received during scan, are reported in TSF of the mac specified in the - * scan request. - * @IWL_UCODE_TLV_API_TKIP_MIC_KEYS: This ucode supports version 2 of - * ADD_MODIFY_STA_KEY_API_S_VER_2. - * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. - * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 - * - * @NUM_IWL_UCODE_TLV_API: number of bits used - */ -enum iwl_ucode_tlv_api { - IWL_UCODE_TLV_API_FRAGMENTED_SCAN = (__force iwl_ucode_tlv_api_t)8, - IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9, - IWL_UCODE_TLV_API_LQ_SS_PARAMS = (__force iwl_ucode_tlv_api_t)18, - IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20, - IWL_UCODE_TLV_API_SCAN_TSF_REPORT = (__force iwl_ucode_tlv_api_t)28, - IWL_UCODE_TLV_API_TKIP_MIC_KEYS = (__force iwl_ucode_tlv_api_t)29, - IWL_UCODE_TLV_API_STA_TYPE = (__force iwl_ucode_tlv_api_t)30, - IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31, - - NUM_IWL_UCODE_TLV_API -#ifdef __CHECKER__ - /* sparse says it cannot increment the previous enum member */ - = 128 -#endif -}; - -typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; - -/** - * enum iwl_ucode_tlv_capa - ucode capabilities - * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 - * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory - * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. - * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer - * @IWL_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM) - * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality - * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current - * tx power value into TPC Report action frame and Link Measurement Report - * action frame - * @IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports updating current - * channel in DS parameter set element in probe requests. - * @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in - * probe requests. - * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests - * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), - * which also implies support for the scheduler configuration command - * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching - * @IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG: Consolidated D3-D0 image - * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command - * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command - * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload - * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics - * @IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD: supports U-APSD on p2p interface when it - * is standalone or with a BSS station interface in the same binding. - * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running - * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different - * sources for the MCC. This TLV bit is a future replacement to - * IWL_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR - * is supported. - * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC - * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan - * @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification - * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement - * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts - * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT - * @IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD: the firmware supports CSA - * countdown offloading. Beacon notifications are not sent to the host. - * The fw also offloads TBTT alignment. - * @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what - * antenna the beacon should be transmitted - * @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon - * from AP and will send it upon d0i3 exit. - * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2 - * @IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill - * @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature - * thresholds reporting - * @IWL_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command - * @IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in - * regular image. - * @IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared - * memory addresses from the firmware. - * @IWL_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement - * @IWL_UCODE_TLV_CAPA_TX_POWER_ACK: reduced TX power API has larger - * command size (command version 4) that supports toggling ACK TX - * power reduction. - * - * @NUM_IWL_UCODE_TLV_CAPA: number of bits used - */ -enum iwl_ucode_tlv_capa { - IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = (__force iwl_ucode_tlv_capa_t)0, - IWL_UCODE_TLV_CAPA_LAR_SUPPORT = (__force iwl_ucode_tlv_capa_t)1, - IWL_UCODE_TLV_CAPA_UMAC_SCAN = (__force iwl_ucode_tlv_capa_t)2, - IWL_UCODE_TLV_CAPA_BEAMFORMER = (__force iwl_ucode_tlv_capa_t)3, - IWL_UCODE_TLV_CAPA_TOF_SUPPORT = (__force iwl_ucode_tlv_capa_t)5, - IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = (__force iwl_ucode_tlv_capa_t)6, - IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = (__force iwl_ucode_tlv_capa_t)8, - IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)9, - IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)10, - IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = (__force iwl_ucode_tlv_capa_t)11, - IWL_UCODE_TLV_CAPA_DQA_SUPPORT = (__force iwl_ucode_tlv_capa_t)12, - IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = (__force iwl_ucode_tlv_capa_t)13, - IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG = (__force iwl_ucode_tlv_capa_t)17, - IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = (__force iwl_ucode_tlv_capa_t)18, - IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19, - IWL_UCODE_TLV_CAPA_CSUM_SUPPORT = (__force iwl_ucode_tlv_capa_t)21, - IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = (__force iwl_ucode_tlv_capa_t)22, - IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD = (__force iwl_ucode_tlv_capa_t)26, - IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28, - IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, - IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30, - IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31, - IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38, - IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39, - IWL_UCODE_TLV_CAPA_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)40, - IWL_UCODE_TLV_CAPA_D0I3_END_FIRST = (__force iwl_ucode_tlv_capa_t)41, - IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, - IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, - IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, - IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT = (__force iwl_ucode_tlv_capa_t)68, - IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD = (__force iwl_ucode_tlv_capa_t)70, - IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71, - IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72, - IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73, - IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW = (__force iwl_ucode_tlv_capa_t)74, - IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75, - IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76, - IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED = (__force iwl_ucode_tlv_capa_t)77, - IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80, - IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81, - IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84, - - NUM_IWL_UCODE_TLV_CAPA -#ifdef __CHECKER__ - /* sparse says it cannot increment the previous enum member */ - = 128 -#endif -}; - -/* The default calibrate table size if not specified by firmware file */ -#define IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 -#define IWL_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 -#define IWL_MAX_PHY_CALIBRATE_TBL_SIZE 253 - -/* The default max probe length if not specified by the firmware file */ -#define IWL_DEFAULT_MAX_PROBE_LENGTH 200 - -/* - * For 16.0 uCode and above, there is no differentiation between sections, - * just an offset to the HW address. - */ -#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC -#define PAGING_SEPARATOR_SECTION 0xAAAABBBB - -/* uCode version contains 4 values: Major/Minor/API/Serial */ -#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) -#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) -#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) -#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) - -/** - * struct iwl_tlv_calib_ctrl - Calibration control struct. - * Sent as part of the phy configuration command. - * @flow_trigger: bitmap for which calibrations to perform according to - * flow triggers. - * @event_trigger: bitmap for which calibrations to perform according to - * event triggers. - */ -struct iwl_tlv_calib_ctrl { - __le32 flow_trigger; - __le32 event_trigger; -} __packed; - -enum iwl_fw_phy_cfg { - FW_PHY_CFG_RADIO_TYPE_POS = 0, - FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS, - FW_PHY_CFG_RADIO_STEP_POS = 2, - FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS, - FW_PHY_CFG_RADIO_DASH_POS = 4, - FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS, - FW_PHY_CFG_TX_CHAIN_POS = 16, - FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, - FW_PHY_CFG_RX_CHAIN_POS = 20, - FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, -}; - -#define IWL_UCODE_MAX_CS 1 - -/** - * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW. - * @cipher: a cipher suite selector - * @flags: cipher scheme flags (currently reserved for a future use) - * @hdr_len: a size of MPDU security header - * @pn_len: a size of PN - * @pn_off: an offset of pn from the beginning of the security header - * @key_idx_off: an offset of key index byte in the security header - * @key_idx_mask: a bit mask of key_idx bits - * @key_idx_shift: bit shift needed to get key_idx - * @mic_len: mic length in bytes - * @hw_cipher: a HW cipher index used in host commands - */ -struct iwl_fw_cipher_scheme { - __le32 cipher; - u8 flags; - u8 hdr_len; - u8 pn_len; - u8 pn_off; - u8 key_idx_off; - u8 key_idx_mask; - u8 key_idx_shift; - u8 mic_len; - u8 hw_cipher; -} __packed; - -enum iwl_fw_dbg_reg_operator { - CSR_ASSIGN, - CSR_SETBIT, - CSR_CLEARBIT, - - PRPH_ASSIGN, - PRPH_SETBIT, - PRPH_CLEARBIT, - - INDIRECT_ASSIGN, - INDIRECT_SETBIT, - INDIRECT_CLEARBIT, - - PRPH_BLOCKBIT, -}; - -/** - * struct iwl_fw_dbg_reg_op - an operation on a register - * - * @op: &enum iwl_fw_dbg_reg_operator - * @addr: offset of the register - * @val: value - */ -struct iwl_fw_dbg_reg_op { - u8 op; - u8 reserved[3]; - __le32 addr; - __le32 val; -} __packed; - -/** - * enum iwl_fw_dbg_monitor_mode - available monitor recording modes - * - * @SMEM_MODE: monitor stores the data in SMEM - * @EXTERNAL_MODE: monitor stores the data in allocated DRAM - * @MARBH_MODE: monitor stores the data in MARBH buffer - * @MIPI_MODE: monitor outputs the data through the MIPI interface - */ -enum iwl_fw_dbg_monitor_mode { - SMEM_MODE = 0, - EXTERNAL_MODE = 1, - MARBH_MODE = 2, - MIPI_MODE = 3, -}; - -/** - * enum iwl_fw_mem_seg_type - memory segment type - * @FW_DBG_MEM_TYPE_MASK: mask for the type indication - * @FW_DBG_MEM_TYPE_REGULAR: regular memory - * @FW_DBG_MEM_TYPE_PRPH: periphery memory (requires special reading) - */ -enum iwl_fw_mem_seg_type { - FW_DBG_MEM_TYPE_MASK = 0xff000000, - FW_DBG_MEM_TYPE_REGULAR = 0x00000000, - FW_DBG_MEM_TYPE_PRPH = 0x01000000, -}; - -/** - * struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments - * - * @data_type: the memory segment type to record, see &enum iwl_fw_mem_seg_type - * for what we care about - * @ofs: the memory segment offset - * @len: the memory segment length, in bytes - * - * This parses IWL_UCODE_TLV_FW_MEM_SEG - */ -struct iwl_fw_dbg_mem_seg_tlv { - __le32 data_type; - __le32 ofs; - __le32 len; -} __packed; - -/** - * struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data - * - * @version: version of the TLV - currently 0 - * @monitor_mode: &enum iwl_fw_dbg_monitor_mode - * @size_power: buffer size will be 2^(size_power + 11) - * @base_reg: addr of the base addr register (PRPH) - * @end_reg: addr of the end addr register (PRPH) - * @write_ptr_reg: the addr of the reg of the write pointer - * @wrap_count: the addr of the reg of the wrap_count - * @base_shift: shift right of the base addr reg - * @end_shift: shift right of the end addr reg - * @reg_ops: array of registers operations - * - * This parses IWL_UCODE_TLV_FW_DBG_DEST - */ -struct iwl_fw_dbg_dest_tlv { - u8 version; - u8 monitor_mode; - u8 size_power; - u8 reserved; - __le32 base_reg; - __le32 end_reg; - __le32 write_ptr_reg; - __le32 wrap_count; - u8 base_shift; - u8 end_shift; - struct iwl_fw_dbg_reg_op reg_ops[0]; -} __packed; - -struct iwl_fw_dbg_conf_hcmd { - u8 id; - u8 reserved; - __le16 len; - u8 data[0]; -} __packed; - -/** - * enum iwl_fw_dbg_trigger_mode - triggers functionalities - * - * @IWL_FW_DBG_TRIGGER_START: when trigger occurs re-conf the dbg mechanism - * @IWL_FW_DBG_TRIGGER_STOP: when trigger occurs pull the dbg data - * @IWL_FW_DBG_TRIGGER_MONITOR_ONLY: when trigger occurs trigger is set to - * collect only monitor data - */ -enum iwl_fw_dbg_trigger_mode { - IWL_FW_DBG_TRIGGER_START = BIT(0), - IWL_FW_DBG_TRIGGER_STOP = BIT(1), - IWL_FW_DBG_TRIGGER_MONITOR_ONLY = BIT(2), -}; - -/** - * enum iwl_fw_dbg_trigger_vif_type - define the VIF type for a trigger - * @IWL_FW_DBG_CONF_VIF_ANY: any vif type - * @IWL_FW_DBG_CONF_VIF_IBSS: IBSS mode - * @IWL_FW_DBG_CONF_VIF_STATION: BSS mode - * @IWL_FW_DBG_CONF_VIF_AP: AP mode - * @IWL_FW_DBG_CONF_VIF_P2P_CLIENT: P2P Client mode - * @IWL_FW_DBG_CONF_VIF_P2P_GO: P2P GO mode - * @IWL_FW_DBG_CONF_VIF_P2P_DEVICE: P2P device - */ -enum iwl_fw_dbg_trigger_vif_type { - IWL_FW_DBG_CONF_VIF_ANY = NL80211_IFTYPE_UNSPECIFIED, - IWL_FW_DBG_CONF_VIF_IBSS = NL80211_IFTYPE_ADHOC, - IWL_FW_DBG_CONF_VIF_STATION = NL80211_IFTYPE_STATION, - IWL_FW_DBG_CONF_VIF_AP = NL80211_IFTYPE_AP, - IWL_FW_DBG_CONF_VIF_P2P_CLIENT = NL80211_IFTYPE_P2P_CLIENT, - IWL_FW_DBG_CONF_VIF_P2P_GO = NL80211_IFTYPE_P2P_GO, - IWL_FW_DBG_CONF_VIF_P2P_DEVICE = NL80211_IFTYPE_P2P_DEVICE, -}; - -/** - * struct iwl_fw_dbg_trigger_tlv - a TLV that describes the trigger - * @id: &enum iwl_fw_dbg_trigger - * @vif_type: &enum iwl_fw_dbg_trigger_vif_type - * @stop_conf_ids: bitmap of configurations this trigger relates to. - * if the mode is %IWL_FW_DBG_TRIGGER_STOP, then if the bit corresponding - * to the currently running configuration is set, the data should be - * collected. - * @stop_delay: how many milliseconds to wait before collecting the data - * after the STOP trigger fires. - * @mode: &enum iwl_fw_dbg_trigger_mode - can be stop / start of both - * @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what - * configuration should be applied when the triggers kicks in. - * @occurrences: number of occurrences. 0 means the trigger will never fire. - * @trig_dis_ms: the time, in milliseconds, after an occurrence of this - * trigger in which another occurrence should be ignored. - */ -struct iwl_fw_dbg_trigger_tlv { - __le32 id; - __le32 vif_type; - __le32 stop_conf_ids; - __le32 stop_delay; - u8 mode; - u8 start_conf_id; - __le16 occurrences; - __le16 trig_dis_ms; - __le16 reserved[3]; - - u8 data[0]; -} __packed; - -#define FW_DBG_START_FROM_ALIVE 0 -#define FW_DBG_CONF_MAX 32 -#define FW_DBG_INVALID 0xff - -/** - * struct iwl_fw_dbg_trigger_missed_bcon - configures trigger for missed beacons - * @stop_consec_missed_bcon: stop recording if threshold is crossed. - * @stop_consec_missed_bcon_since_rx: stop recording if threshold is crossed. - * @start_consec_missed_bcon: start recording if threshold is crossed. - * @start_consec_missed_bcon_since_rx: start recording if threshold is crossed. - * @reserved1: reserved - * @reserved2: reserved - */ -struct iwl_fw_dbg_trigger_missed_bcon { - __le32 stop_consec_missed_bcon; - __le32 stop_consec_missed_bcon_since_rx; - __le32 reserved2[2]; - __le32 start_consec_missed_bcon; - __le32 start_consec_missed_bcon_since_rx; - __le32 reserved1[2]; -} __packed; - -/** - * struct iwl_fw_dbg_trigger_cmd - configures trigger for messages from FW. - * cmds: the list of commands to trigger the collection on - */ -struct iwl_fw_dbg_trigger_cmd { - struct cmd { - u8 cmd_id; - u8 group_id; - } __packed cmds[16]; -} __packed; - -/** - * iwl_fw_dbg_trigger_stats - configures trigger for statistics - * @stop_offset: the offset of the value to be monitored - * @stop_threshold: the threshold above which to collect - * @start_offset: the offset of the value to be monitored - * @start_threshold: the threshold above which to start recording - */ -struct iwl_fw_dbg_trigger_stats { - __le32 stop_offset; - __le32 stop_threshold; - __le32 start_offset; - __le32 start_threshold; -} __packed; - -/** - * struct iwl_fw_dbg_trigger_low_rssi - trigger for low beacon RSSI - * @rssi: RSSI value to trigger at - */ -struct iwl_fw_dbg_trigger_low_rssi { - __le32 rssi; -} __packed; - -/** - * struct iwl_fw_dbg_trigger_mlme - configures trigger for mlme events - * @stop_auth_denied: number of denied authentication to collect - * @stop_auth_timeout: number of authentication timeout to collect - * @stop_rx_deauth: number of Rx deauth before to collect - * @stop_tx_deauth: number of Tx deauth before to collect - * @stop_assoc_denied: number of denied association to collect - * @stop_assoc_timeout: number of association timeout to collect - * @stop_connection_loss: number of connection loss to collect - * @start_auth_denied: number of denied authentication to start recording - * @start_auth_timeout: number of authentication timeout to start recording - * @start_rx_deauth: number of Rx deauth to start recording - * @start_tx_deauth: number of Tx deauth to start recording - * @start_assoc_denied: number of denied association to start recording - * @start_assoc_timeout: number of association timeout to start recording - * @start_connection_loss: number of connection loss to start recording - */ -struct iwl_fw_dbg_trigger_mlme { - u8 stop_auth_denied; - u8 stop_auth_timeout; - u8 stop_rx_deauth; - u8 stop_tx_deauth; - - u8 stop_assoc_denied; - u8 stop_assoc_timeout; - u8 stop_connection_loss; - u8 reserved; - - u8 start_auth_denied; - u8 start_auth_timeout; - u8 start_rx_deauth; - u8 start_tx_deauth; - - u8 start_assoc_denied; - u8 start_assoc_timeout; - u8 start_connection_loss; - u8 reserved2; -} __packed; - -/** - * struct iwl_fw_dbg_trigger_txq_timer - configures the Tx queue's timer - * @command_queue: timeout for the command queue in ms - * @bss: timeout for the queues of a BSS (except for TDLS queues) in ms - * @softap: timeout for the queues of a softAP in ms - * @p2p_go: timeout for the queues of a P2P GO in ms - * @p2p_client: timeout for the queues of a P2P client in ms - * @p2p_device: timeout for the queues of a P2P device in ms - * @ibss: timeout for the queues of an IBSS in ms - * @tdls: timeout for the queues of a TDLS station in ms - */ -struct iwl_fw_dbg_trigger_txq_timer { - __le32 command_queue; - __le32 bss; - __le32 softap; - __le32 p2p_go; - __le32 p2p_client; - __le32 p2p_device; - __le32 ibss; - __le32 tdls; - __le32 reserved[4]; -} __packed; - -/** - * struct iwl_fw_dbg_trigger_time_event - configures a time event trigger - * time_Events: a list of tuples . The driver will issue a - * trigger each time a time event notification that relates to time event - * id with one of the actions in the bitmap is received and - * BIT(notif->status) is set in status_bitmap. - * - */ -struct iwl_fw_dbg_trigger_time_event { - struct { - __le32 id; - __le32 action_bitmap; - __le32 status_bitmap; - } __packed time_events[16]; -} __packed; - -/** - * struct iwl_fw_dbg_trigger_ba - configures BlockAck related trigger - * rx_ba_start: tid bitmap to configure on what tid the trigger should occur - * when an Rx BlockAck session is started. - * rx_ba_stop: tid bitmap to configure on what tid the trigger should occur - * when an Rx BlockAck session is stopped. - * tx_ba_start: tid bitmap to configure on what tid the trigger should occur - * when a Tx BlockAck session is started. - * tx_ba_stop: tid bitmap to configure on what tid the trigger should occur - * when a Tx BlockAck session is stopped. - * rx_bar: tid bitmap to configure on what tid the trigger should occur - * when a BAR is received (for a Tx BlockAck session). - * tx_bar: tid bitmap to configure on what tid the trigger should occur - * when a BAR is send (for an Rx BlocAck session). - * frame_timeout: tid bitmap to configure on what tid the trigger should occur - * when a frame times out in the reodering buffer. - */ -struct iwl_fw_dbg_trigger_ba { - __le16 rx_ba_start; - __le16 rx_ba_stop; - __le16 tx_ba_start; - __le16 tx_ba_stop; - __le16 rx_bar; - __le16 tx_bar; - __le16 frame_timeout; -} __packed; - -/** - * struct iwl_fw_dbg_trigger_tdls - configures trigger for TDLS events. - * @action_bitmap: the TDLS action to trigger the collection upon - * @peer_mode: trigger on specific peer or all - * @peer: the TDLS peer to trigger the collection on - */ -struct iwl_fw_dbg_trigger_tdls { - u8 action_bitmap; - u8 peer_mode; - u8 peer[ETH_ALEN]; - u8 reserved[4]; -} __packed; - -/** - * struct iwl_fw_dbg_trigger_tx_status - configures trigger for tx response - * status. - * @statuses: the list of statuses to trigger the collection on - */ -struct iwl_fw_dbg_trigger_tx_status { - struct tx_status { - u8 status; - u8 reserved[3]; - } __packed statuses[16]; - __le32 reserved[2]; -} __packed; - -/** - * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration. - * @id: conf id - * @usniffer: should the uSniffer image be used - * @num_of_hcmds: how many HCMDs to send are present here - * @hcmd: a variable length host command to be sent to apply the configuration. - * If there is more than one HCMD to send, they will appear one after the - * other and be sent in the order that they appear in. - * This parses IWL_UCODE_TLV_FW_DBG_CONF. The user can add up-to - * %FW_DBG_CONF_MAX configuration per run. - */ -struct iwl_fw_dbg_conf_tlv { - u8 id; - u8 usniffer; - u8 reserved; - u8 num_of_hcmds; - struct iwl_fw_dbg_conf_hcmd hcmd; -} __packed; - -/** - * struct iwl_fw_gscan_capabilities - gscan capabilities supported by FW - * @max_scan_cache_size: total space allocated for scan results (in bytes). - * @max_scan_buckets: maximum number of channel buckets. - * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. - * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. - * @max_scan_reporting_threshold: max possible report threshold. in percentage. - * @max_hotlist_aps: maximum number of entries for hotlist APs. - * @max_significant_change_aps: maximum number of entries for significant - * change APs. - * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can - * hold. - * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs. - * @max_number_epno_networks: max number of epno entries. - * @max_number_epno_networks_by_ssid: max number of epno entries if ssid is - * specified. - * @max_number_of_white_listed_ssid: max number of white listed SSIDs. - * @max_number_of_black_listed_ssid: max number of black listed SSIDs. - */ -struct iwl_fw_gscan_capabilities { - __le32 max_scan_cache_size; - __le32 max_scan_buckets; - __le32 max_ap_cache_per_scan; - __le32 max_rssi_sample_size; - __le32 max_scan_reporting_threshold; - __le32 max_hotlist_aps; - __le32 max_significant_change_aps; - __le32 max_bssid_history_entries; - __le32 max_hotlist_ssids; - __le32 max_number_epno_networks; - __le32 max_number_epno_networks_by_ssid; - __le32 max_number_of_white_listed_ssid; - __le32 max_number_of_black_listed_ssid; -} __packed; - -#endif /* __iwl_fw_file_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw.h deleted file mode 100644 index d323b70b510a..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw.h +++ /dev/null @@ -1,342 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifndef __iwl_fw_h__ -#define __iwl_fw_h__ -#include - -#include "iwl-fw-file.h" -#include "iwl-fw-error-dump.h" - -/** - * enum iwl_ucode_type - * - * The type of ucode. - * - * @IWL_UCODE_REGULAR: Normal runtime ucode - * @IWL_UCODE_INIT: Initial ucode - * @IWL_UCODE_WOWLAN: Wake on Wireless enabled ucode - * @IWL_UCODE_REGULAR_USNIFFER: Normal runtime ucode when using usniffer image - */ -enum iwl_ucode_type { - IWL_UCODE_REGULAR, - IWL_UCODE_INIT, - IWL_UCODE_WOWLAN, - IWL_UCODE_REGULAR_USNIFFER, - IWL_UCODE_TYPE_MAX, -}; - -/* - * enumeration of ucode section. - * This enumeration is used directly for older firmware (before 16.0). - * For new firmware, there can be up to 4 sections (see below) but the - * first one packaged into the firmware file is the DATA section and - * some debugging code accesses that. - */ -enum iwl_ucode_sec { - IWL_UCODE_SECTION_DATA, - IWL_UCODE_SECTION_INST, -}; - -struct iwl_ucode_capabilities { - u32 max_probe_length; - u32 n_scan_channels; - u32 standard_phy_calibration_size; - u32 flags; - unsigned long _api[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_API)]; - unsigned long _capa[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_CAPA)]; -}; - -static inline bool -fw_has_api(const struct iwl_ucode_capabilities *capabilities, - iwl_ucode_tlv_api_t api) -{ - return test_bit((__force long)api, capabilities->_api); -} - -static inline bool -fw_has_capa(const struct iwl_ucode_capabilities *capabilities, - iwl_ucode_tlv_capa_t capa) -{ - return test_bit((__force long)capa, capabilities->_capa); -} - -/* one for each uCode image (inst/data, init/runtime/wowlan) */ -struct fw_desc { - const void *data; /* vmalloc'ed data */ - u32 len; /* size in bytes */ - u32 offset; /* offset in the device */ -}; - -struct fw_img { - struct fw_desc *sec; - int num_sec; - bool is_dual_cpus; - u32 paging_mem_size; -}; - -struct iwl_sf_region { - u32 addr; - u32 size; -}; - -/* - * Block paging calculations - */ -#define PAGE_2_EXP_SIZE 12 /* 4K == 2^12 */ -#define FW_PAGING_SIZE BIT(PAGE_2_EXP_SIZE) /* page size is 4KB */ -#define PAGE_PER_GROUP_2_EXP_SIZE 3 -/* 8 pages per group */ -#define NUM_OF_PAGE_PER_GROUP BIT(PAGE_PER_GROUP_2_EXP_SIZE) -/* don't change, support only 32KB size */ -#define PAGING_BLOCK_SIZE (NUM_OF_PAGE_PER_GROUP * FW_PAGING_SIZE) -/* 32K == 2^15 */ -#define BLOCK_2_EXP_SIZE (PAGE_2_EXP_SIZE + PAGE_PER_GROUP_2_EXP_SIZE) - -/* - * Image paging calculations - */ -#define BLOCK_PER_IMAGE_2_EXP_SIZE 5 -/* 2^5 == 32 blocks per image */ -#define NUM_OF_BLOCK_PER_IMAGE BIT(BLOCK_PER_IMAGE_2_EXP_SIZE) -/* maximum image size 1024KB */ -#define MAX_PAGING_IMAGE_SIZE (NUM_OF_BLOCK_PER_IMAGE * PAGING_BLOCK_SIZE) - -/* Virtual address signature */ -#define PAGING_ADDR_SIG 0xAA000000 - -#define PAGING_CMD_IS_SECURED BIT(9) -#define PAGING_CMD_IS_ENABLED BIT(8) -#define PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS 0 -#define PAGING_TLV_SECURE_MASK 1 - -/** - * struct iwl_fw_paging - * @fw_paging_phys: page phy pointer - * @fw_paging_block: pointer to the allocated block - * @fw_paging_size: page size - */ -struct iwl_fw_paging { - dma_addr_t fw_paging_phys; - struct page *fw_paging_block; - u32 fw_paging_size; -}; - -/** - * struct iwl_fw_cscheme_list - a cipher scheme list - * @size: a number of entries - * @cs: cipher scheme entries - */ -struct iwl_fw_cscheme_list { - u8 size; - struct iwl_fw_cipher_scheme cs[]; -} __packed; - -/** - * struct iwl_gscan_capabilities - gscan capabilities supported by FW - * @max_scan_cache_size: total space allocated for scan results (in bytes). - * @max_scan_buckets: maximum number of channel buckets. - * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. - * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. - * @max_scan_reporting_threshold: max possible report threshold. in percentage. - * @max_hotlist_aps: maximum number of entries for hotlist APs. - * @max_significant_change_aps: maximum number of entries for significant - * change APs. - * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can - * hold. - * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs. - * @max_number_epno_networks: max number of epno entries. - * @max_number_epno_networks_by_ssid: max number of epno entries if ssid is - * specified. - * @max_number_of_white_listed_ssid: max number of white listed SSIDs. - * @max_number_of_black_listed_ssid: max number of black listed SSIDs. - */ -struct iwl_gscan_capabilities { - u32 max_scan_cache_size; - u32 max_scan_buckets; - u32 max_ap_cache_per_scan; - u32 max_rssi_sample_size; - u32 max_scan_reporting_threshold; - u32 max_hotlist_aps; - u32 max_significant_change_aps; - u32 max_bssid_history_entries; - u32 max_hotlist_ssids; - u32 max_number_epno_networks; - u32 max_number_epno_networks_by_ssid; - u32 max_number_of_white_listed_ssid; - u32 max_number_of_black_listed_ssid; -}; - -/** - * enum iwl_fw_type - iwlwifi firmware type - * @IWL_FW_DVM: DVM firmware - * @IWL_FW_MVM: MVM firmware - */ -enum iwl_fw_type { - IWL_FW_DVM, - IWL_FW_MVM, -}; - -/** - * struct iwl_fw - variables associated with the firmware - * - * @ucode_ver: ucode version from the ucode file - * @fw_version: firmware version string - * @img: ucode image like ucode_rt, ucode_init, ucode_wowlan. - * @ucode_capa: capabilities parsed from the ucode file. - * @enhance_sensitivity_table: device can do enhanced sensitivity. - * @init_evtlog_ptr: event log offset for init ucode. - * @init_evtlog_size: event log size for init ucode. - * @init_errlog_ptr: error log offfset for init ucode. - * @inst_evtlog_ptr: event log offset for runtime ucode. - * @inst_evtlog_size: event log size for runtime ucode. - * @inst_errlog_ptr: error log offfset for runtime ucode. - * @type: firmware type (&enum iwl_fw_type) - * @cipher_scheme: optional external cipher scheme. - * @human_readable: human readable version - * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until - * we get the ALIVE from the uCode - * @dbg_dest_tlv: points to the destination TLV for debug - * @dbg_conf_tlv: array of pointers to configuration TLVs for debug - * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries - * @dbg_trigger_tlv: array of pointers to triggers TLVs - * @dbg_trigger_tlv_len: lengths of the @dbg_trigger_tlv entries - * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv - */ -struct iwl_fw { - u32 ucode_ver; - - char fw_version[ETHTOOL_FWVERS_LEN]; - - /* ucode images */ - struct fw_img img[IWL_UCODE_TYPE_MAX]; - - struct iwl_ucode_capabilities ucode_capa; - bool enhance_sensitivity_table; - - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; - u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; - - struct iwl_tlv_calib_ctrl default_calib[IWL_UCODE_TYPE_MAX]; - u32 phy_config; - u8 valid_tx_ant; - u8 valid_rx_ant; - - enum iwl_fw_type type; - - struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS]; - u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; - - u32 sdio_adma_addr; - - struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; - struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX]; - size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX]; - struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX]; - struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv; - size_t n_dbg_mem_tlv; - size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX]; - u8 dbg_dest_reg_num; - struct iwl_gscan_capabilities gscan_capa; -}; - -static inline const char *get_fw_dbg_mode_string(int mode) -{ - switch (mode) { - case SMEM_MODE: - return "SMEM"; - case EXTERNAL_MODE: - return "EXTERNAL_DRAM"; - case MARBH_MODE: - return "MARBH"; - case MIPI_MODE: - return "MIPI"; - default: - return "UNKNOWN"; - } -} - -static inline bool -iwl_fw_dbg_conf_usniffer(const struct iwl_fw *fw, u8 id) -{ - const struct iwl_fw_dbg_conf_tlv *conf_tlv = fw->dbg_conf_tlv[id]; - - if (!conf_tlv) - return false; - - return conf_tlv->usniffer; -} - -static inline const struct fw_img * -iwl_get_ucode_image(const struct iwl_fw *fw, enum iwl_ucode_type ucode_type) -{ - if (ucode_type >= IWL_UCODE_TYPE_MAX) - return NULL; - - return &fw->img[ucode_type]; -} - -#endif /* __iwl_fw_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 57db6250a329..eb6842abb4c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -74,9 +74,9 @@ #include "iwl-debug.h" #include "iwl-config.h" -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-op-mode.h" -#include "iwl-fw-api.h" +#include "fw/api.h" /** * DOC: Transport layer - what is it ? diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 78dde0a8d358..61a5e34140db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -73,7 +73,7 @@ #include "sta.h" #include "iwl-io.h" #include "debugfs.h" -#include "iwl-fw-error-dump.h" +#include "fw/error-dump.h" static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, char __user *user_buf, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h index e9f1be9da7d4..4a5287a0c617 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h @@ -65,8 +65,8 @@ #ifndef __mvm_fw_dbg_h__ #define __mvm_fw_dbg_h__ -#include "iwl-fw-file.h" -#include "iwl-fw-error-dump.h" +#include "fw/file.h" +#include "fw/error-dump.h" #include "mvm.h" void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index c5445be36701..80c42ef981c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -70,7 +70,7 @@ #include "iwl-trans.h" #include "iwl-op-mode.h" -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-debug.h" #include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */ #include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 1cfb4c72199a..bcde1ba0f1c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -84,7 +84,7 @@ #include "iwl-eeprom-parse.h" #include "iwl-phy-db.h" #include "testmode.h" -#include "iwl-fw-error-dump.h" +#include "fw/error-dump.h" #include "iwl-prph.h" #include "iwl-nvm-parse.h" #include "fw-dbg.h" diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index e1f7d273d0bd..33979b48ac0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -81,7 +81,7 @@ #include "iwl-trans.h" #include "iwl-notif-wait.h" #include "iwl-eeprom-parse.h" -#include "iwl-fw-file.h" +#include "fw/file.h" #include "iwl-config.h" #include "sta.h" #include "fw-api.h" diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index c1ce92f5306d..d93f1fcdf879 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -71,7 +71,7 @@ #include "iwl-notif-wait.h" #include "iwl-trans.h" #include "iwl-op-mode.h" -#include "iwl-fw.h" +#include "fw/img.h" #include "iwl-debug.h" #include "iwl-drv.h" #include "iwl-modparams.h" diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 5778ba2278d1..a7d0b5c5e4a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -80,7 +80,7 @@ #include "iwl-prph.h" #include "iwl-scd.h" #include "iwl-agn-hw.h" -#include "iwl-fw-error-dump.h" +#include "fw/error-dump.h" #include "internal.h" #include "iwl-fh.h" -- cgit v1.2.3 From 9fca9d5c9745a18f65a380dfc61cd07ee874c7e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2017 10:32:17 +0200 Subject: iwlwifi: move notification wait into fw/ Move the notification wait code into the new fw interaction directory. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Makefile | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/dev.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c | 195 +++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h | 154 ++++++++++++++++ .../net/wireless/intel/iwlwifi/iwl-notif-wait.c | 195 --------------------- .../net/wireless/intel/iwlwifi/iwl-notif-wait.h | 154 ---------------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 2 +- 9 files changed, 354 insertions(+), 354 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 411cb91c102f..7733fc41ce98 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -3,7 +3,6 @@ obj-$(CONFIG_IWLWIFI) += iwlwifi.o iwlwifi-objs += iwl-io.o iwlwifi-objs += iwl-drv.o iwlwifi-objs += iwl-debug.o -iwlwifi-objs += iwl-notif-wait.o iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o @@ -11,6 +10,7 @@ iwlwifi-objs += pcie/ctxt-info.o pcie/trans-gen2.o pcie/tx-gen2.o iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o iwl-a000.o iwlwifi-objs += iwl-trans.o +iwlwifi-objs += fw/notif-wait.o iwlwifi-objs += $(iwlwifi-m) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h index 025db135b63c..cceb4cd8e501 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h @@ -44,7 +44,7 @@ #include "iwl-debug.h" #include "iwl-agn-hw.h" #include "iwl-op-mode.h" -#include "iwl-notif-wait.h" +#include "fw/notif-wait.h" #include "iwl-trans.h" #include "led.h" diff --git a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c new file mode 100644 index 000000000000..29bb92e3df59 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c @@ -0,0 +1,195 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include +#include + +#include "iwl-drv.h" +#include "notif-wait.h" + + +void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait) +{ + spin_lock_init(¬if_wait->notif_wait_lock); + INIT_LIST_HEAD(¬if_wait->notif_waits); + init_waitqueue_head(¬if_wait->notif_waitq); +} +IWL_EXPORT_SYMBOL(iwl_notification_wait_init); + +bool iwl_notification_wait(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt) +{ + bool triggered = false; + + if (!list_empty(¬if_wait->notif_waits)) { + struct iwl_notification_wait *w; + + spin_lock(¬if_wait->notif_wait_lock); + list_for_each_entry(w, ¬if_wait->notif_waits, list) { + int i; + bool found = false; + + /* + * If it already finished (triggered) or has been + * aborted then don't evaluate it again to avoid races, + * Otherwise the function could be called again even + * though it returned true before + */ + if (w->triggered || w->aborted) + continue; + + for (i = 0; i < w->n_cmds; i++) { + u16 rec_id = WIDE_ID(pkt->hdr.group_id, + pkt->hdr.cmd); + + if (w->cmds[i] == rec_id || + (!iwl_cmd_groupid(w->cmds[i]) && + DEF_ID(w->cmds[i]) == rec_id)) { + found = true; + break; + } + } + if (!found) + continue; + + if (!w->fn || w->fn(notif_wait, pkt, w->fn_data)) { + w->triggered = true; + triggered = true; + } + } + spin_unlock(¬if_wait->notif_wait_lock); + } + + return triggered; +} +IWL_EXPORT_SYMBOL(iwl_notification_wait); + +void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait) +{ + struct iwl_notification_wait *wait_entry; + + spin_lock(¬if_wait->notif_wait_lock); + list_for_each_entry(wait_entry, ¬if_wait->notif_waits, list) + wait_entry->aborted = true; + spin_unlock(¬if_wait->notif_wait_lock); + + wake_up_all(¬if_wait->notif_waitq); +} +IWL_EXPORT_SYMBOL(iwl_abort_notification_waits); + +void +iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait, + struct iwl_notification_wait *wait_entry, + const u16 *cmds, int n_cmds, + bool (*fn)(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data), + void *fn_data) +{ + if (WARN_ON(n_cmds > MAX_NOTIF_CMDS)) + n_cmds = MAX_NOTIF_CMDS; + + wait_entry->fn = fn; + wait_entry->fn_data = fn_data; + wait_entry->n_cmds = n_cmds; + memcpy(wait_entry->cmds, cmds, n_cmds * sizeof(u16)); + wait_entry->triggered = false; + wait_entry->aborted = false; + + spin_lock_bh(¬if_wait->notif_wait_lock); + list_add(&wait_entry->list, ¬if_wait->notif_waits); + spin_unlock_bh(¬if_wait->notif_wait_lock); +} +IWL_EXPORT_SYMBOL(iwl_init_notification_wait); + +int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait, + struct iwl_notification_wait *wait_entry, + unsigned long timeout) +{ + int ret; + + ret = wait_event_timeout(notif_wait->notif_waitq, + wait_entry->triggered || wait_entry->aborted, + timeout); + + spin_lock_bh(¬if_wait->notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(¬if_wait->notif_wait_lock); + + if (wait_entry->aborted) + return -EIO; + + /* return value is always >= 0 */ + if (ret <= 0) + return -ETIMEDOUT; + return 0; +} +IWL_EXPORT_SYMBOL(iwl_wait_notification); + +void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait, + struct iwl_notification_wait *wait_entry) +{ + spin_lock_bh(¬if_wait->notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(¬if_wait->notif_wait_lock); +} +IWL_EXPORT_SYMBOL(iwl_remove_notification); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h new file mode 100644 index 000000000000..368884be4e7c --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.h @@ -0,0 +1,154 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_notif_wait_h__ +#define __iwl_notif_wait_h__ + +#include + +#include "iwl-trans.h" + +struct iwl_notif_wait_data { + struct list_head notif_waits; + spinlock_t notif_wait_lock; + wait_queue_head_t notif_waitq; +}; + +#define MAX_NOTIF_CMDS 5 + +/** + * struct iwl_notification_wait - notification wait entry + * @list: list head for global list + * @fn: Function called with the notification. If the function + * returns true, the wait is over, if it returns false then + * the waiter stays blocked. If no function is given, any + * of the listed commands will unblock the waiter. + * @cmds: command IDs + * @n_cmds: number of command IDs + * @triggered: waiter should be woken up + * @aborted: wait was aborted + * + * This structure is not used directly, to wait for a + * notification declare it on the stack, and call + * iwl_init_notification_wait() with appropriate + * parameters. Then do whatever will cause the ucode + * to notify the driver, and to wait for that then + * call iwl_wait_notification(). + * + * Each notification is one-shot. If at some point we + * need to support multi-shot notifications (which + * can't be allocated on the stack) we need to modify + * the code for them. + */ +struct iwl_notification_wait { + struct list_head list; + + bool (*fn)(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt, void *data); + void *fn_data; + + u16 cmds[MAX_NOTIF_CMDS]; + u8 n_cmds; + bool triggered, aborted; +}; + + +/* caller functions */ +void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_data); +bool iwl_notification_wait(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt); +void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data); + +static inline void +iwl_notification_notify(struct iwl_notif_wait_data *notif_data) +{ + wake_up_all(¬if_data->notif_waitq); +} + +static inline void +iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt) +{ + if (iwl_notification_wait(notif_data, pkt)) + iwl_notification_notify(notif_data); +} + +/* user functions */ +void __acquires(wait_entry) +iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data, + struct iwl_notification_wait *wait_entry, + const u16 *cmds, int n_cmds, + bool (*fn)(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt, void *data), + void *fn_data); + +int __must_check __releases(wait_entry) +iwl_wait_notification(struct iwl_notif_wait_data *notif_data, + struct iwl_notification_wait *wait_entry, + unsigned long timeout); + +void __releases(wait_entry) +iwl_remove_notification(struct iwl_notif_wait_data *notif_data, + struct iwl_notification_wait *wait_entry); + +#endif /* __iwl_notif_wait_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c deleted file mode 100644 index 68412ff2112e..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c +++ /dev/null @@ -1,195 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -#include -#include - -#include "iwl-drv.h" -#include "iwl-notif-wait.h" - - -void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait) -{ - spin_lock_init(¬if_wait->notif_wait_lock); - INIT_LIST_HEAD(¬if_wait->notif_waits); - init_waitqueue_head(¬if_wait->notif_waitq); -} -IWL_EXPORT_SYMBOL(iwl_notification_wait_init); - -bool iwl_notification_wait(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt) -{ - bool triggered = false; - - if (!list_empty(¬if_wait->notif_waits)) { - struct iwl_notification_wait *w; - - spin_lock(¬if_wait->notif_wait_lock); - list_for_each_entry(w, ¬if_wait->notif_waits, list) { - int i; - bool found = false; - - /* - * If it already finished (triggered) or has been - * aborted then don't evaluate it again to avoid races, - * Otherwise the function could be called again even - * though it returned true before - */ - if (w->triggered || w->aborted) - continue; - - for (i = 0; i < w->n_cmds; i++) { - u16 rec_id = WIDE_ID(pkt->hdr.group_id, - pkt->hdr.cmd); - - if (w->cmds[i] == rec_id || - (!iwl_cmd_groupid(w->cmds[i]) && - DEF_ID(w->cmds[i]) == rec_id)) { - found = true; - break; - } - } - if (!found) - continue; - - if (!w->fn || w->fn(notif_wait, pkt, w->fn_data)) { - w->triggered = true; - triggered = true; - } - } - spin_unlock(¬if_wait->notif_wait_lock); - } - - return triggered; -} -IWL_EXPORT_SYMBOL(iwl_notification_wait); - -void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait) -{ - struct iwl_notification_wait *wait_entry; - - spin_lock(¬if_wait->notif_wait_lock); - list_for_each_entry(wait_entry, ¬if_wait->notif_waits, list) - wait_entry->aborted = true; - spin_unlock(¬if_wait->notif_wait_lock); - - wake_up_all(¬if_wait->notif_waitq); -} -IWL_EXPORT_SYMBOL(iwl_abort_notification_waits); - -void -iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait, - struct iwl_notification_wait *wait_entry, - const u16 *cmds, int n_cmds, - bool (*fn)(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt, void *data), - void *fn_data) -{ - if (WARN_ON(n_cmds > MAX_NOTIF_CMDS)) - n_cmds = MAX_NOTIF_CMDS; - - wait_entry->fn = fn; - wait_entry->fn_data = fn_data; - wait_entry->n_cmds = n_cmds; - memcpy(wait_entry->cmds, cmds, n_cmds * sizeof(u16)); - wait_entry->triggered = false; - wait_entry->aborted = false; - - spin_lock_bh(¬if_wait->notif_wait_lock); - list_add(&wait_entry->list, ¬if_wait->notif_waits); - spin_unlock_bh(¬if_wait->notif_wait_lock); -} -IWL_EXPORT_SYMBOL(iwl_init_notification_wait); - -int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait, - struct iwl_notification_wait *wait_entry, - unsigned long timeout) -{ - int ret; - - ret = wait_event_timeout(notif_wait->notif_waitq, - wait_entry->triggered || wait_entry->aborted, - timeout); - - spin_lock_bh(¬if_wait->notif_wait_lock); - list_del(&wait_entry->list); - spin_unlock_bh(¬if_wait->notif_wait_lock); - - if (wait_entry->aborted) - return -EIO; - - /* return value is always >= 0 */ - if (ret <= 0) - return -ETIMEDOUT; - return 0; -} -IWL_EXPORT_SYMBOL(iwl_wait_notification); - -void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait, - struct iwl_notification_wait *wait_entry) -{ - spin_lock_bh(¬if_wait->notif_wait_lock); - list_del(&wait_entry->list); - spin_unlock_bh(¬if_wait->notif_wait_lock); -} -IWL_EXPORT_SYMBOL(iwl_remove_notification); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h deleted file mode 100644 index 368884be4e7c..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h +++ /dev/null @@ -1,154 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -#ifndef __iwl_notif_wait_h__ -#define __iwl_notif_wait_h__ - -#include - -#include "iwl-trans.h" - -struct iwl_notif_wait_data { - struct list_head notif_waits; - spinlock_t notif_wait_lock; - wait_queue_head_t notif_waitq; -}; - -#define MAX_NOTIF_CMDS 5 - -/** - * struct iwl_notification_wait - notification wait entry - * @list: list head for global list - * @fn: Function called with the notification. If the function - * returns true, the wait is over, if it returns false then - * the waiter stays blocked. If no function is given, any - * of the listed commands will unblock the waiter. - * @cmds: command IDs - * @n_cmds: number of command IDs - * @triggered: waiter should be woken up - * @aborted: wait was aborted - * - * This structure is not used directly, to wait for a - * notification declare it on the stack, and call - * iwl_init_notification_wait() with appropriate - * parameters. Then do whatever will cause the ucode - * to notify the driver, and to wait for that then - * call iwl_wait_notification(). - * - * Each notification is one-shot. If at some point we - * need to support multi-shot notifications (which - * can't be allocated on the stack) we need to modify - * the code for them. - */ -struct iwl_notification_wait { - struct list_head list; - - bool (*fn)(struct iwl_notif_wait_data *notif_data, - struct iwl_rx_packet *pkt, void *data); - void *fn_data; - - u16 cmds[MAX_NOTIF_CMDS]; - u8 n_cmds; - bool triggered, aborted; -}; - - -/* caller functions */ -void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_data); -bool iwl_notification_wait(struct iwl_notif_wait_data *notif_data, - struct iwl_rx_packet *pkt); -void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data); - -static inline void -iwl_notification_notify(struct iwl_notif_wait_data *notif_data) -{ - wake_up_all(¬if_data->notif_waitq); -} - -static inline void -iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_data, - struct iwl_rx_packet *pkt) -{ - if (iwl_notification_wait(notif_data, pkt)) - iwl_notification_notify(notif_data); -} - -/* user functions */ -void __acquires(wait_entry) -iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data, - struct iwl_notification_wait *wait_entry, - const u16 *cmds, int n_cmds, - bool (*fn)(struct iwl_notif_wait_data *notif_data, - struct iwl_rx_packet *pkt, void *data), - void *fn_data); - -int __must_check __releases(wait_entry) -iwl_wait_notification(struct iwl_notif_wait_data *notif_data, - struct iwl_notification_wait *wait_entry, - unsigned long timeout); - -void __releases(wait_entry) -iwl_remove_notification(struct iwl_notif_wait_data *notif_data, - struct iwl_notification_wait *wait_entry); - -#endif /* __iwl_notif_wait_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 33979b48ac0a..0f0cd6c9ce8b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -79,7 +79,7 @@ #include "iwl-op-mode.h" #include "iwl-trans.h" -#include "iwl-notif-wait.h" +#include "fw/notif-wait.h" #include "iwl-eeprom-parse.h" #include "fw/file.h" #include "iwl-config.h" diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index d93f1fcdf879..32233cba6786 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -68,7 +68,7 @@ #include #include -#include "iwl-notif-wait.h" +#include "fw/notif-wait.h" #include "iwl-trans.h" #include "iwl-op-mode.h" #include "fw/img.h" diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 3e4fa853b44d..5a682722adce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -66,7 +66,7 @@ #include #include -#include "iwl-notif-wait.h" +#include "fw/notif-wait.h" #include "iwl-trans.h" #include "fw-api.h" #include "time-event.h" -- cgit v1.2.3 From 650aaed3b30158f74c1f051a653da4f6eb3db205 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2017 10:38:04 +0200 Subject: iwlwifi: move configuration into sub-directory Since we now support 8 device families, move their configuration files into a new subdirectory "cfg". Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Makefile | 4 +- drivers/net/wireless/intel/iwlwifi/cfg/1000.c | 134 +++++++++ drivers/net/wireless/intel/iwlwifi/cfg/2000.c | 204 ++++++++++++++ drivers/net/wireless/intel/iwlwifi/cfg/5000.c | 171 ++++++++++++ drivers/net/wireless/intel/iwlwifi/cfg/6000.c | 374 +++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/cfg/7000.c | 384 ++++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/cfg/8000.c | 280 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 214 ++++++++++++++ drivers/net/wireless/intel/iwlwifi/cfg/a000.c | 172 ++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-1000.c | 134 --------- drivers/net/wireless/intel/iwlwifi/iwl-2000.c | 204 -------------- drivers/net/wireless/intel/iwlwifi/iwl-5000.c | 171 ------------ drivers/net/wireless/intel/iwlwifi/iwl-6000.c | 374 ------------------------- drivers/net/wireless/intel/iwlwifi/iwl-7000.c | 384 -------------------------- drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 280 ------------------- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 214 -------------- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 172 ------------ 17 files changed, 1935 insertions(+), 1935 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/1000.c create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/2000.c create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/5000.c create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/6000.c create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/7000.c create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/8000.c create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/9000.c create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/a000.c delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-1000.c delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-2000.c delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-5000.c delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-6000.c delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-7000.c delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-8000.c delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-9000.c delete mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-a000.c (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 7733fc41ce98..20bd261223af 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -7,8 +7,8 @@ iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o iwlwifi-objs += pcie/ctxt-info.o pcie/trans-gen2.o pcie/tx-gen2.o -iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o -iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o iwl-a000.o +iwlwifi-$(CONFIG_IWLDVM) += cfg/1000.o cfg/2000.o cfg/5000.o cfg/6000.o +iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/a000.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += fw/notif-wait.o diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c new file mode 100644 index 000000000000..b2573b1d1506 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c @@ -0,0 +1,134 @@ +/****************************************************************************** + * + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include "iwl-config.h" +#include "iwl-csr.h" +#include "iwl-agn-hw.h" + +/* Highest firmware API version supported */ +#define IWL1000_UCODE_API_MAX 5 +#define IWL100_UCODE_API_MAX 5 + +/* Lowest firmware API version supported */ +#define IWL1000_UCODE_API_MIN 1 +#define IWL100_UCODE_API_MIN 5 + +/* EEPROM version */ +#define EEPROM_1000_TX_POWER_VERSION (4) +#define EEPROM_1000_EEPROM_VERSION (0x15C) + +#define IWL1000_FW_PRE "iwlwifi-1000-" +#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode" + +#define IWL100_FW_PRE "iwlwifi-100-" +#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode" + + +static const struct iwl_base_params iwl1000_base_params = { + .num_of_queues = IWLAGN_NUM_QUEUES, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .pll_cfg = true, + .max_ll_items = OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, + .led_compensation = 51, + .wd_timeout = IWL_WATCHDOG_DISABLED, + .max_event_log_size = 128, + .scd_chain_ext_wa = true, +}; + +static const struct iwl_ht_params iwl1000_ht_params = { + .ht_greenfield_support = true, + .use_rts_for_aggregation = true, /* use rts/cts protection */ + .ht40_bands = BIT(NL80211_BAND_2GHZ), +}; + +static const struct iwl_eeprom_params iwl1000_eeprom_params = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_REG_BAND_24_HT40_CHANNELS, + EEPROM_REGULATORY_BAND_NO_HT40, + } +}; + +#define IWL_DEVICE_1000 \ + .fw_name_pre = IWL1000_FW_PRE, \ + .ucode_api_max = IWL1000_UCODE_API_MAX, \ + .ucode_api_min = IWL1000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_1000, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_1000_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ + .base_params = &iwl1000_base_params, \ + .eeprom_params = &iwl1000_eeprom_params, \ + .led_mode = IWL_LED_BLINK, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl1000_bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN", + IWL_DEVICE_1000, + .ht_params = &iwl1000_ht_params, +}; + +const struct iwl_cfg iwl1000_bg_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 1000 BG", + IWL_DEVICE_1000, +}; + +#define IWL_DEVICE_100 \ + .fw_name_pre = IWL100_FW_PRE, \ + .ucode_api_max = IWL100_UCODE_API_MAX, \ + .ucode_api_min = IWL100_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_100, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_1000_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ + .base_params = &iwl1000_base_params, \ + .eeprom_params = &iwl1000_eeprom_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .rx_with_siso_diversity = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl100_bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 100 BGN", + IWL_DEVICE_100, + .ht_params = &iwl1000_ht_params, +}; + +const struct iwl_cfg iwl100_bg_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 100 BG", + IWL_DEVICE_100, +}; + +MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c new file mode 100644 index 000000000000..1b32ad413b9e --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c @@ -0,0 +1,204 @@ +/****************************************************************************** + * + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include "iwl-config.h" +#include "iwl-agn-hw.h" +#include "dvm/commands.h" /* needed for BT for now */ + +/* Highest firmware API version supported */ +#define IWL2030_UCODE_API_MAX 6 +#define IWL2000_UCODE_API_MAX 6 +#define IWL105_UCODE_API_MAX 6 +#define IWL135_UCODE_API_MAX 6 + +/* Lowest firmware API version supported */ +#define IWL2030_UCODE_API_MIN 5 +#define IWL2000_UCODE_API_MIN 5 +#define IWL105_UCODE_API_MIN 5 +#define IWL135_UCODE_API_MIN 5 + +/* EEPROM version */ +#define EEPROM_2000_TX_POWER_VERSION (6) +#define EEPROM_2000_EEPROM_VERSION (0x805) + + +#define IWL2030_FW_PRE "iwlwifi-2030-" +#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode" + +#define IWL2000_FW_PRE "iwlwifi-2000-" +#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode" + +#define IWL105_FW_PRE "iwlwifi-105-" +#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode" + +#define IWL135_FW_PRE "iwlwifi-135-" +#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode" + +static const struct iwl_base_params iwl2000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .max_ll_items = OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .led_compensation = 51, + .wd_timeout = IWL_DEF_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, +}; + + +static const struct iwl_base_params iwl2030_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .max_ll_items = OTP_MAX_LL_ITEMS_2x00, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, +}; + +static const struct iwl_ht_params iwl2000_ht_params = { + .ht_greenfield_support = true, + .use_rts_for_aggregation = true, /* use rts/cts protection */ + .ht40_bands = BIT(NL80211_BAND_2GHZ), +}; + +static const struct iwl_eeprom_params iwl20x0_eeprom_params = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REGULATORY_BAND_NO_HT40, + }, + .enhanced_txpower = true, +}; + +#define IWL_DEVICE_2000 \ + .fw_name_pre = IWL2000_FW_PRE, \ + .ucode_api_max = IWL2000_UCODE_API_MAX, \ + .ucode_api_min = IWL2000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_2000, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .base_params = &iwl2000_base_params, \ + .eeprom_params = &iwl20x0_eeprom_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + + +const struct iwl_cfg iwl2000_2bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN", + IWL_DEVICE_2000, + .ht_params = &iwl2000_ht_params, +}; + +const struct iwl_cfg iwl2000_2bgn_d_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 2200D BGN", + IWL_DEVICE_2000, + .ht_params = &iwl2000_ht_params, +}; + +#define IWL_DEVICE_2030 \ + .fw_name_pre = IWL2030_FW_PRE, \ + .ucode_api_max = IWL2030_UCODE_API_MAX, \ + .ucode_api_min = IWL2030_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_2030, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .base_params = &iwl2030_base_params, \ + .eeprom_params = &iwl20x0_eeprom_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl2030_2bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", + IWL_DEVICE_2030, + .ht_params = &iwl2000_ht_params, +}; + +#define IWL_DEVICE_105 \ + .fw_name_pre = IWL105_FW_PRE, \ + .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_min = IWL105_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_105, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .base_params = &iwl2000_base_params, \ + .eeprom_params = &iwl20x0_eeprom_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .rx_with_siso_diversity = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl105_bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 105 BGN", + IWL_DEVICE_105, + .ht_params = &iwl2000_ht_params, +}; + +const struct iwl_cfg iwl105_bgn_d_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 105D BGN", + IWL_DEVICE_105, + .ht_params = &iwl2000_ht_params, +}; + +#define IWL_DEVICE_135 \ + .fw_name_pre = IWL135_FW_PRE, \ + .ucode_api_max = IWL135_UCODE_API_MAX, \ + .ucode_api_min = IWL135_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_135, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ + .base_params = &iwl2030_base_params, \ + .eeprom_params = &iwl20x0_eeprom_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .rx_with_siso_diversity = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl135_bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 135 BGN", + IWL_DEVICE_135, + .ht_params = &iwl2000_ht_params, +}; + +MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c new file mode 100644 index 000000000000..4aa8f0a05c8a --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include "iwl-config.h" +#include "iwl-agn-hw.h" +#include "iwl-csr.h" + +/* Highest firmware API version supported */ +#define IWL5000_UCODE_API_MAX 5 +#define IWL5150_UCODE_API_MAX 2 + +/* Lowest firmware API version supported */ +#define IWL5000_UCODE_API_MIN 1 +#define IWL5150_UCODE_API_MIN 1 + +/* EEPROM versions */ +#define EEPROM_5000_TX_POWER_VERSION (4) +#define EEPROM_5000_EEPROM_VERSION (0x11A) +#define EEPROM_5050_TX_POWER_VERSION (4) +#define EEPROM_5050_EEPROM_VERSION (0x21E) + +#define IWL5000_FW_PRE "iwlwifi-5000-" +#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode" + +#define IWL5150_FW_PRE "iwlwifi-5150-" +#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode" + +static const struct iwl_base_params iwl5000_base_params = { + .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .pll_cfg = true, + .led_compensation = 51, + .wd_timeout = IWL_WATCHDOG_DISABLED, + .max_event_log_size = 512, + .scd_chain_ext_wa = true, +}; + +static const struct iwl_ht_params iwl5000_ht_params = { + .ht_greenfield_support = true, + .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), +}; + +static const struct iwl_eeprom_params iwl5000_eeprom_params = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, +}; + +#define IWL_DEVICE_5000 \ + .fw_name_pre = IWL5000_FW_PRE, \ + .ucode_api_max = IWL5000_UCODE_API_MAX, \ + .ucode_api_min = IWL5000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_5000, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_5000_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ + .base_params = &iwl5000_base_params, \ + .eeprom_params = &iwl5000_eeprom_params, \ + .led_mode = IWL_LED_BLINK, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl5300_agn_cfg = { + .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", + IWL_DEVICE_5000, + /* at least EEPROM 0x11A has wrong info */ + .valid_tx_ant = ANT_ABC, /* .cfg overwrite */ + .valid_rx_ant = ANT_ABC, /* .cfg overwrite */ + .ht_params = &iwl5000_ht_params, +}; + +const struct iwl_cfg iwl5100_bgn_cfg = { + .name = "Intel(R) WiFi Link 5100 BGN", + IWL_DEVICE_5000, + .valid_tx_ant = ANT_B, /* .cfg overwrite */ + .valid_rx_ant = ANT_AB, /* .cfg overwrite */ + .ht_params = &iwl5000_ht_params, +}; + +const struct iwl_cfg iwl5100_abg_cfg = { + .name = "Intel(R) WiFi Link 5100 ABG", + IWL_DEVICE_5000, + .valid_tx_ant = ANT_B, /* .cfg overwrite */ + .valid_rx_ant = ANT_AB, /* .cfg overwrite */ +}; + +const struct iwl_cfg iwl5100_agn_cfg = { + .name = "Intel(R) WiFi Link 5100 AGN", + IWL_DEVICE_5000, + .valid_tx_ant = ANT_B, /* .cfg overwrite */ + .valid_rx_ant = ANT_AB, /* .cfg overwrite */ + .ht_params = &iwl5000_ht_params, +}; + +const struct iwl_cfg iwl5350_agn_cfg = { + .name = "Intel(R) WiMAX/WiFi Link 5350 AGN", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, + .device_family = IWL_DEVICE_FAMILY_5000, + .max_inst_size = IWLAGN_RTC_INST_SIZE, + .max_data_size = IWLAGN_RTC_DATA_SIZE, + .nvm_ver = EEPROM_5050_EEPROM_VERSION, + .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .base_params = &iwl5000_base_params, + .eeprom_params = &iwl5000_eeprom_params, + .ht_params = &iwl5000_ht_params, + .led_mode = IWL_LED_BLINK, + .internal_wimax_coex = true, +}; + +#define IWL_DEVICE_5150 \ + .fw_name_pre = IWL5150_FW_PRE, \ + .ucode_api_max = IWL5150_UCODE_API_MAX, \ + .ucode_api_min = IWL5150_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_5150, \ + .max_inst_size = IWLAGN_RTC_INST_SIZE, \ + .max_data_size = IWLAGN_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_5050_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ + .base_params = &iwl5000_base_params, \ + .eeprom_params = &iwl5000_eeprom_params, \ + .led_mode = IWL_LED_BLINK, \ + .internal_wimax_coex = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl5150_agn_cfg = { + .name = "Intel(R) WiMAX/WiFi Link 5150 AGN", + IWL_DEVICE_5150, + .ht_params = &iwl5000_ht_params, + +}; + +const struct iwl_cfg iwl5150_abg_cfg = { + .name = "Intel(R) WiMAX/WiFi Link 5150 ABG", + IWL_DEVICE_5150, +}; + +MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c new file mode 100644 index 000000000000..39335b7b0c16 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c @@ -0,0 +1,374 @@ +/****************************************************************************** + * + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include "iwl-config.h" +#include "iwl-agn-hw.h" +#include "dvm/commands.h" /* needed for BT for now */ + +/* Highest firmware API version supported */ +#define IWL6000_UCODE_API_MAX 6 +#define IWL6050_UCODE_API_MAX 5 +#define IWL6000G2_UCODE_API_MAX 6 +#define IWL6035_UCODE_API_MAX 6 + +/* Lowest firmware API version supported */ +#define IWL6000_UCODE_API_MIN 4 +#define IWL6050_UCODE_API_MIN 4 +#define IWL6000G2_UCODE_API_MIN 5 +#define IWL6035_UCODE_API_MIN 6 + +/* EEPROM versions */ +#define EEPROM_6000_TX_POWER_VERSION (4) +#define EEPROM_6000_EEPROM_VERSION (0x423) +#define EEPROM_6050_TX_POWER_VERSION (4) +#define EEPROM_6050_EEPROM_VERSION (0x532) +#define EEPROM_6150_TX_POWER_VERSION (6) +#define EEPROM_6150_EEPROM_VERSION (0x553) +#define EEPROM_6005_TX_POWER_VERSION (6) +#define EEPROM_6005_EEPROM_VERSION (0x709) +#define EEPROM_6030_TX_POWER_VERSION (6) +#define EEPROM_6030_EEPROM_VERSION (0x709) +#define EEPROM_6035_TX_POWER_VERSION (6) +#define EEPROM_6035_EEPROM_VERSION (0x753) + +#define IWL6000_FW_PRE "iwlwifi-6000-" +#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode" + +#define IWL6050_FW_PRE "iwlwifi-6050-" +#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode" + +#define IWL6005_FW_PRE "iwlwifi-6000g2a-" +#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode" + +#define IWL6030_FW_PRE "iwlwifi-6000g2b-" +#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode" + +static const struct iwl_base_params iwl6000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .led_compensation = 51, + .wd_timeout = IWL_DEF_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, +}; + +static const struct iwl_base_params iwl6050_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .max_ll_items = OTP_MAX_LL_ITEMS_6x50, + .shadow_ram_support = true, + .led_compensation = 51, + .wd_timeout = IWL_DEF_WD_TIMEOUT, + .max_event_log_size = 1024, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, +}; + +static const struct iwl_base_params iwl6000_g2_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .num_of_queues = IWLAGN_NUM_QUEUES, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .scd_chain_ext_wa = true, +}; + +static const struct iwl_ht_params iwl6000_ht_params = { + .ht_greenfield_support = true, + .use_rts_for_aggregation = true, /* use rts/cts protection */ + .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), +}; + +static const struct iwl_eeprom_params iwl6000_eeprom_params = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, + .enhanced_txpower = true, +}; + +#define IWL_DEVICE_6005 \ + .fw_name_pre = IWL6005_FW_PRE, \ + .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ + .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6005, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_6005_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ + .base_params = &iwl6000_g2_base_params, \ + .eeprom_params = &iwl6000_eeprom_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl6005_2agn_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6005_2abg_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6205 ABG", + IWL_DEVICE_6005, +}; + +const struct iwl_cfg iwl6005_2bg_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6205 BG", + IWL_DEVICE_6005, +}; + +const struct iwl_cfg iwl6005_2agn_sff_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6205S AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6005_2agn_d_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6205D AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6005_2agn_mow1_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6206 AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6005_2agn_mow2_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6207 AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; + +#define IWL_DEVICE_6030 \ + .fw_name_pre = IWL6030_FW_PRE, \ + .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ + .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6030, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_6030_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ + .base_params = &iwl6000_g2_base_params, \ + .eeprom_params = &iwl6000_eeprom_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl6030_2agn_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN", + IWL_DEVICE_6030, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6030_2abg_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6230 ABG", + IWL_DEVICE_6030, +}; + +const struct iwl_cfg iwl6030_2bgn_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6230 BGN", + IWL_DEVICE_6030, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6030_2bg_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6230 BG", + IWL_DEVICE_6030, +}; + +#define IWL_DEVICE_6035 \ + .fw_name_pre = IWL6030_FW_PRE, \ + .ucode_api_max = IWL6035_UCODE_API_MAX, \ + .ucode_api_min = IWL6035_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6030, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_6030_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ + .base_params = &iwl6000_g2_base_params, \ + .eeprom_params = &iwl6000_eeprom_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl6035_2agn_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", + IWL_DEVICE_6035, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6035_2agn_sff_cfg = { + .name = "Intel(R) Centrino(R) Ultimate-N 6235 AGN", + IWL_DEVICE_6035, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl1030_bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", + IWL_DEVICE_6030, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl1030_bg_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 1030 BG", + IWL_DEVICE_6030, +}; + +const struct iwl_cfg iwl130_bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 130 BGN", + IWL_DEVICE_6030, + .ht_params = &iwl6000_ht_params, + .rx_with_siso_diversity = true, +}; + +const struct iwl_cfg iwl130_bg_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N 130 BG", + IWL_DEVICE_6030, + .rx_with_siso_diversity = true, +}; + +/* + * "i": Internal configuration, use internal Power Amplifier + */ +#define IWL_DEVICE_6000i \ + .fw_name_pre = IWL6000_FW_PRE, \ + .ucode_api_max = IWL6000_UCODE_API_MAX, \ + .ucode_api_min = IWL6000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6000i, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .valid_tx_ant = ANT_BC, /* .cfg overwrite */ \ + .valid_rx_ant = ANT_BC, /* .cfg overwrite */ \ + .nvm_ver = EEPROM_6000_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ + .base_params = &iwl6000_base_params, \ + .eeprom_params = &iwl6000_eeprom_params, \ + .led_mode = IWL_LED_BLINK, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl6000i_2agn_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN", + IWL_DEVICE_6000i, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6000i_2abg_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6200 ABG", + IWL_DEVICE_6000i, +}; + +const struct iwl_cfg iwl6000i_2bg_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6200 BG", + IWL_DEVICE_6000i, +}; + +#define IWL_DEVICE_6050 \ + .fw_name_pre = IWL6050_FW_PRE, \ + .ucode_api_max = IWL6050_UCODE_API_MAX, \ + .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6050, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .valid_tx_ant = ANT_AB, /* .cfg overwrite */ \ + .valid_rx_ant = ANT_AB, /* .cfg overwrite */ \ + .nvm_ver = EEPROM_6050_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ + .base_params = &iwl6050_base_params, \ + .eeprom_params = &iwl6000_eeprom_params, \ + .led_mode = IWL_LED_BLINK, \ + .internal_wimax_coex = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl6050_2agn_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN", + IWL_DEVICE_6050, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6050_2abg_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG", + IWL_DEVICE_6050, +}; + +#define IWL_DEVICE_6150 \ + .fw_name_pre = IWL6050_FW_PRE, \ + .ucode_api_max = IWL6050_UCODE_API_MAX, \ + .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6150, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .nvm_ver = EEPROM_6150_EEPROM_VERSION, \ + .nvm_calib_ver = EEPROM_6150_TX_POWER_VERSION, \ + .base_params = &iwl6050_base_params, \ + .eeprom_params = &iwl6000_eeprom_params, \ + .led_mode = IWL_LED_BLINK, \ + .internal_wimax_coex = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + +const struct iwl_cfg iwl6150_bgn_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN", + IWL_DEVICE_6150, + .ht_params = &iwl6000_ht_params, +}; + +const struct iwl_cfg iwl6150_bg_cfg = { + .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG", + IWL_DEVICE_6150, +}; + +const struct iwl_cfg iwl6000_3agn_cfg = { + .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .device_family = IWL_DEVICE_FAMILY_6000, + .max_inst_size = IWL60_RTC_INST_SIZE, + .max_data_size = IWL60_RTC_DATA_SIZE, + .nvm_ver = EEPROM_6000_EEPROM_VERSION, + .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION, + .base_params = &iwl6000_base_params, + .eeprom_params = &iwl6000_eeprom_params, + .ht_params = &iwl6000_ht_params, + .led_mode = IWL_LED_BLINK, +}; + +MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c new file mode 100644 index 000000000000..45e2efc70d19 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c @@ -0,0 +1,384 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +#include +#include "iwl-config.h" +#include "iwl-agn-hw.h" + +/* Highest firmware API version supported */ +#define IWL7260_UCODE_API_MAX 17 +#define IWL7265_UCODE_API_MAX 17 +#define IWL7265D_UCODE_API_MAX 29 +#define IWL3168_UCODE_API_MAX 29 + +/* Lowest firmware API version supported */ +#define IWL7260_UCODE_API_MIN 17 +#define IWL7265_UCODE_API_MIN 17 +#define IWL7265D_UCODE_API_MIN 22 +#define IWL3168_UCODE_API_MIN 22 + +/* NVM versions */ +#define IWL7260_NVM_VERSION 0x0a1d +#define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */ +#define IWL3160_NVM_VERSION 0x709 +#define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */ +#define IWL3165_NVM_VERSION 0x709 +#define IWL3165_TX_POWER_VERSION 0xffff /* meaningless */ +#define IWL3168_NVM_VERSION 0xd01 +#define IWL3168_TX_POWER_VERSION 0xffff /* meaningless */ +#define IWL7265_NVM_VERSION 0x0a1d +#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ +#define IWL7265D_NVM_VERSION 0x0c11 +#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ + +/* DCCM offsets and lengths */ +#define IWL7000_DCCM_OFFSET 0x800000 +#define IWL7260_DCCM_LEN 0x14000 +#define IWL3160_DCCM_LEN 0x10000 +#define IWL7265_DCCM_LEN 0x17A00 + +#define IWL7260_FW_PRE "iwlwifi-7260-" +#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" + +#define IWL3160_FW_PRE "iwlwifi-3160-" +#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode" + +#define IWL3168_FW_PRE "iwlwifi-3168-" +#define IWL3168_MODULE_FIRMWARE(api) IWL3168_FW_PRE __stringify(api) ".ucode" + +#define IWL7265_FW_PRE "iwlwifi-7265-" +#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" + +#define IWL7265D_FW_PRE "iwlwifi-7265D-" +#define IWL7265D_MODULE_FIRMWARE(api) IWL7265D_FW_PRE __stringify(api) ".ucode" + +#define NVM_HW_SECTION_NUM_FAMILY_7000 0 + +static const struct iwl_base_params iwl7000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_7000, + .num_of_queues = 31, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, + .pcie_l1_allowed = true, + .apmg_wake_up_wa = true, +}; + +static const struct iwl_tt_params iwl7000_high_temp_tt_params = { + .ct_kill_entry = 118, + .ct_kill_exit = 96, + .ct_kill_duration = 5, + .dynamic_smps_entry = 114, + .dynamic_smps_exit = 110, + .tx_protection_entry = 114, + .tx_protection_exit = 108, + .tx_backoff = { + {.temperature = 112, .backoff = 300}, + {.temperature = 113, .backoff = 800}, + {.temperature = 114, .backoff = 1500}, + {.temperature = 115, .backoff = 3000}, + {.temperature = 116, .backoff = 5000}, + {.temperature = 117, .backoff = 10000}, + }, + .support_ct_kill = true, + .support_dynamic_smps = true, + .support_tx_protection = true, + .support_tx_backoff = true, +}; + +static const struct iwl_ht_params iwl7000_ht_params = { + .stbc = true, + .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), +}; + +#define IWL_DEVICE_7000_COMMON \ + .device_family = IWL_DEVICE_FAMILY_7000, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .base_params = &iwl7000_base_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ + .non_shared_ant = ANT_A, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .dccm_offset = IWL7000_DCCM_OFFSET + +#define IWL_DEVICE_7000 \ + IWL_DEVICE_7000_COMMON, \ + .ucode_api_max = IWL7260_UCODE_API_MAX, \ + .ucode_api_min = IWL7260_UCODE_API_MIN + +#define IWL_DEVICE_7005 \ + IWL_DEVICE_7000_COMMON, \ + .ucode_api_max = IWL7265_UCODE_API_MAX, \ + .ucode_api_min = IWL7265_UCODE_API_MIN + +#define IWL_DEVICE_3008 \ + IWL_DEVICE_7000_COMMON, \ + .ucode_api_max = IWL3168_UCODE_API_MAX, \ + .ucode_api_min = IWL3168_UCODE_API_MIN + +#define IWL_DEVICE_7005D \ + IWL_DEVICE_7000_COMMON, \ + .ucode_api_max = IWL7265D_UCODE_API_MAX, \ + .ucode_api_min = IWL7265D_UCODE_API_MIN + +const struct iwl_cfg iwl7260_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 7260", + .fw_name_pre = IWL7260_FW_PRE, + IWL_DEVICE_7000, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL7260_NVM_VERSION, + .nvm_calib_ver = IWL7260_TX_POWER_VERSION, + .host_interrupt_operation_mode = true, + .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, +}; + +const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { + .name = "Intel(R) Dual Band Wireless AC 7260", + .fw_name_pre = IWL7260_FW_PRE, + IWL_DEVICE_7000, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL7260_NVM_VERSION, + .nvm_calib_ver = IWL7260_TX_POWER_VERSION, + .high_temp = true, + .host_interrupt_operation_mode = true, + .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, + .thermal_params = &iwl7000_high_temp_tt_params, +}; + +const struct iwl_cfg iwl7260_2n_cfg = { + .name = "Intel(R) Dual Band Wireless N 7260", + .fw_name_pre = IWL7260_FW_PRE, + IWL_DEVICE_7000, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL7260_NVM_VERSION, + .nvm_calib_ver = IWL7260_TX_POWER_VERSION, + .host_interrupt_operation_mode = true, + .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, +}; + +const struct iwl_cfg iwl7260_n_cfg = { + .name = "Intel(R) Wireless N 7260", + .fw_name_pre = IWL7260_FW_PRE, + IWL_DEVICE_7000, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL7260_NVM_VERSION, + .nvm_calib_ver = IWL7260_TX_POWER_VERSION, + .host_interrupt_operation_mode = true, + .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, +}; + +const struct iwl_cfg iwl3160_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 3160", + .fw_name_pre = IWL3160_FW_PRE, + IWL_DEVICE_7000, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL3160_NVM_VERSION, + .nvm_calib_ver = IWL3160_TX_POWER_VERSION, + .host_interrupt_operation_mode = true, + .dccm_len = IWL3160_DCCM_LEN, +}; + +const struct iwl_cfg iwl3160_2n_cfg = { + .name = "Intel(R) Dual Band Wireless N 3160", + .fw_name_pre = IWL3160_FW_PRE, + IWL_DEVICE_7000, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL3160_NVM_VERSION, + .nvm_calib_ver = IWL3160_TX_POWER_VERSION, + .host_interrupt_operation_mode = true, + .dccm_len = IWL3160_DCCM_LEN, +}; + +const struct iwl_cfg iwl3160_n_cfg = { + .name = "Intel(R) Wireless N 3160", + .fw_name_pre = IWL3160_FW_PRE, + IWL_DEVICE_7000, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL3160_NVM_VERSION, + .nvm_calib_ver = IWL3160_TX_POWER_VERSION, + .host_interrupt_operation_mode = true, + .dccm_len = IWL3160_DCCM_LEN, +}; + +static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { + {.pwr = 1600, .backoff = 0}, + {.pwr = 1300, .backoff = 467}, + {.pwr = 900, .backoff = 1900}, + {.pwr = 800, .backoff = 2630}, + {.pwr = 700, .backoff = 3720}, + {.pwr = 600, .backoff = 5550}, + {.pwr = 500, .backoff = 9350}, + {0}, +}; + +static const struct iwl_ht_params iwl7265_ht_params = { + .stbc = true, + .ldpc = true, + .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), +}; + +const struct iwl_cfg iwl3165_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 3165", + .fw_name_pre = IWL7265D_FW_PRE, + IWL_DEVICE_7005D, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL3165_NVM_VERSION, + .nvm_calib_ver = IWL3165_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, +}; + +const struct iwl_cfg iwl3168_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 3168", + .fw_name_pre = IWL3168_FW_PRE, + IWL_DEVICE_3008, + .ht_params = &iwl7000_ht_params, + .nvm_ver = IWL3168_NVM_VERSION, + .nvm_calib_ver = IWL3168_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, +}; + +const struct iwl_cfg iwl7265_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 7265", + .fw_name_pre = IWL7265_FW_PRE, + IWL_DEVICE_7005, + .ht_params = &iwl7265_ht_params, + .nvm_ver = IWL7265_NVM_VERSION, + .nvm_calib_ver = IWL7265_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, +}; + +const struct iwl_cfg iwl7265_2n_cfg = { + .name = "Intel(R) Dual Band Wireless N 7265", + .fw_name_pre = IWL7265_FW_PRE, + IWL_DEVICE_7005, + .ht_params = &iwl7265_ht_params, + .nvm_ver = IWL7265_NVM_VERSION, + .nvm_calib_ver = IWL7265_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, +}; + +const struct iwl_cfg iwl7265_n_cfg = { + .name = "Intel(R) Wireless N 7265", + .fw_name_pre = IWL7265_FW_PRE, + IWL_DEVICE_7005, + .ht_params = &iwl7265_ht_params, + .nvm_ver = IWL7265_NVM_VERSION, + .nvm_calib_ver = IWL7265_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, +}; + +const struct iwl_cfg iwl7265d_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 7265", + .fw_name_pre = IWL7265D_FW_PRE, + IWL_DEVICE_7005D, + .ht_params = &iwl7265_ht_params, + .nvm_ver = IWL7265D_NVM_VERSION, + .nvm_calib_ver = IWL7265_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, +}; + +const struct iwl_cfg iwl7265d_2n_cfg = { + .name = "Intel(R) Dual Band Wireless N 7265", + .fw_name_pre = IWL7265D_FW_PRE, + IWL_DEVICE_7005D, + .ht_params = &iwl7265_ht_params, + .nvm_ver = IWL7265D_NVM_VERSION, + .nvm_calib_ver = IWL7265_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, +}; + +const struct iwl_cfg iwl7265d_n_cfg = { + .name = "Intel(R) Wireless N 7265", + .fw_name_pre = IWL7265D_FW_PRE, + IWL_DEVICE_7005D, + .ht_params = &iwl7265_ht_params, + .nvm_ver = IWL7265D_NVM_VERSION, + .nvm_calib_ver = IWL7265_TX_POWER_VERSION, + .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, +}; + +MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL7260_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL3168_MODULE_FIRMWARE(IWL3168_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7265_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7265D_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c new file mode 100644 index 000000000000..766bb2037b94 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -0,0 +1,280 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +#include +#include "iwl-config.h" +#include "iwl-agn-hw.h" + +/* Highest firmware API version supported */ +#define IWL8000_UCODE_API_MAX 31 +#define IWL8265_UCODE_API_MAX 31 + +/* Lowest firmware API version supported */ +#define IWL8000_UCODE_API_MIN 22 +#define IWL8265_UCODE_API_MIN 22 + +/* NVM versions */ +#define IWL8000_NVM_VERSION 0x0a1d +#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ + +/* Memory offsets and lengths */ +#define IWL8260_DCCM_OFFSET 0x800000 +#define IWL8260_DCCM_LEN 0x18000 +#define IWL8260_DCCM2_OFFSET 0x880000 +#define IWL8260_DCCM2_LEN 0x8000 +#define IWL8260_SMEM_OFFSET 0x400000 +#define IWL8260_SMEM_LEN 0x68000 + +#define IWL8000_FW_PRE "iwlwifi-8000C-" +#define IWL8000_MODULE_FIRMWARE(api) \ + IWL8000_FW_PRE __stringify(api) ".ucode" + +#define IWL8265_FW_PRE "iwlwifi-8265-" +#define IWL8265_MODULE_FIRMWARE(api) \ + IWL8265_FW_PRE __stringify(api) ".ucode" + +#define NVM_HW_SECTION_NUM_FAMILY_8000 10 +#define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C" + +/* Max SDIO RX/TX aggregation sizes of the ADDBA request/response */ +#define MAX_RX_AGG_SIZE_8260_SDIO 21 +#define MAX_TX_AGG_SIZE_8260_SDIO 40 + +/* Max A-MPDU exponent for HT and VHT */ +#define MAX_HT_AMPDU_EXPONENT_8260_SDIO IEEE80211_HT_MAX_AMPDU_32K +#define MAX_VHT_AMPDU_EXPONENT_8260_SDIO IEEE80211_VHT_MAX_AMPDU_32K + +static const struct iwl_base_params iwl8000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, + .num_of_queues = 31, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, + .pcie_l1_allowed = true, +}; + +static const struct iwl_ht_params iwl8000_ht_params = { + .stbc = true, + .ldpc = true, + .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), +}; + +static const struct iwl_tt_params iwl8000_tt_params = { + .ct_kill_entry = 115, + .ct_kill_exit = 93, + .ct_kill_duration = 5, + .dynamic_smps_entry = 111, + .dynamic_smps_exit = 107, + .tx_protection_entry = 112, + .tx_protection_exit = 105, + .tx_backoff = { + {.temperature = 110, .backoff = 200}, + {.temperature = 111, .backoff = 600}, + {.temperature = 112, .backoff = 1200}, + {.temperature = 113, .backoff = 2000}, + {.temperature = 114, .backoff = 4000}, + }, + .support_ct_kill = true, + .support_dynamic_smps = true, + .support_tx_protection = true, + .support_tx_backoff = true, +}; + +#define IWL_DEVICE_8000_COMMON \ + .device_family = IWL_DEVICE_FAMILY_8000, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .base_params = &iwl8000_base_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ + .features = NETIF_F_RXCSUM, \ + .non_shared_ant = ANT_A, \ + .dccm_offset = IWL8260_DCCM_OFFSET, \ + .dccm_len = IWL8260_DCCM_LEN, \ + .dccm2_offset = IWL8260_DCCM2_OFFSET, \ + .dccm2_len = IWL8260_DCCM2_LEN, \ + .smem_offset = IWL8260_SMEM_OFFSET, \ + .smem_len = IWL8260_SMEM_LEN, \ + .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, \ + .thermal_params = &iwl8000_tt_params, \ + .apmg_not_supported = true, \ + .ext_nvm = true, \ + .dbgc_supported = true + +#define IWL_DEVICE_8000 \ + IWL_DEVICE_8000_COMMON, \ + .ucode_api_max = IWL8000_UCODE_API_MAX, \ + .ucode_api_min = IWL8000_UCODE_API_MIN \ + +#define IWL_DEVICE_8260 \ + IWL_DEVICE_8000_COMMON, \ + .ucode_api_max = IWL8000_UCODE_API_MAX, \ + .ucode_api_min = IWL8000_UCODE_API_MIN \ + +#define IWL_DEVICE_8265 \ + IWL_DEVICE_8000_COMMON, \ + .ucode_api_max = IWL8265_UCODE_API_MAX, \ + .ucode_api_min = IWL8265_UCODE_API_MIN \ + +const struct iwl_cfg iwl8260_2n_cfg = { + .name = "Intel(R) Dual Band Wireless N 8260", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8260, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, +}; + +const struct iwl_cfg iwl8260_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 8260", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8260, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwl8265_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 8265", + .fw_name_pre = IWL8265_FW_PRE, + IWL_DEVICE_8265, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .vht_mu_mimo_supported = true, +}; + +const struct iwl_cfg iwl8275_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 8275", + .fw_name_pre = IWL8265_FW_PRE, + IWL_DEVICE_8265, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .vht_mu_mimo_supported = true, +}; + +const struct iwl_cfg iwl4165_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 4165", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8000, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwl8260_2ac_sdio_cfg = { + .name = "Intel(R) Dual Band Wireless-AC 8260", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8260, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, + .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, + .disable_dummy_notification = true, + .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, + .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, +}; + +const struct iwl_cfg iwl8265_2ac_sdio_cfg = { + .name = "Intel(R) Dual Band Wireless-AC 8265", + .fw_name_pre = IWL8265_FW_PRE, + IWL_DEVICE_8265, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, + .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, + .disable_dummy_notification = true, + .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, + .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, +}; + +const struct iwl_cfg iwl4165_2ac_sdio_cfg = { + .name = "Intel(R) Dual Band Wireless-AC 4165", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8000, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, + .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, + .bt_shared_single_ant = true, + .disable_dummy_notification = true, + .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, + .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, +}; + +MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL8265_MODULE_FIRMWARE(IWL8265_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c new file mode 100644 index 000000000000..42daaddfa740 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -0,0 +1,214 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015-2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015-2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +#include +#include "iwl-config.h" +#include "iwl-agn-hw.h" + +/* Highest firmware API version supported */ +#define IWL9000_UCODE_API_MAX 31 + +/* Lowest firmware API version supported */ +#define IWL9000_UCODE_API_MIN 30 + +/* NVM versions */ +#define IWL9000_NVM_VERSION 0x0a1d +#define IWL9000_TX_POWER_VERSION 0xffff /* meaningless */ + +/* Memory offsets and lengths */ +#define IWL9000_DCCM_OFFSET 0x800000 +#define IWL9000_DCCM_LEN 0x18000 +#define IWL9000_DCCM2_OFFSET 0x880000 +#define IWL9000_DCCM2_LEN 0x8000 +#define IWL9000_SMEM_OFFSET 0x400000 +#define IWL9000_SMEM_LEN 0x68000 + +#define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-" +#define IWL9000RFB_FW_PRE "iwlwifi-9000-pu-a0-jf-b0-" +#define IWL9260A_FW_PRE "iwlwifi-9260-th-a0-jf-a0-" +#define IWL9260B_FW_PRE "iwlwifi-9260-th-b0-jf-b0-" +#define IWL9000_MODULE_FIRMWARE(api) \ + IWL9000_FW_PRE "-" __stringify(api) ".ucode" +#define IWL9000RFB_MODULE_FIRMWARE(api) \ + IWL9000RFB_FW_PRE "-" __stringify(api) ".ucode" +#define IWL9260A_MODULE_FIRMWARE(api) \ + IWL9260A_FW_PRE "-" __stringify(api) ".ucode" +#define IWL9260B_MODULE_FIRMWARE(api) \ + IWL9260B_FW_PRE "-" __stringify(api) ".ucode" + +#define NVM_HW_SECTION_NUM_FAMILY_9000 10 + +static const struct iwl_base_params iwl9000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_9000, + .num_of_queues = 31, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, + .pcie_l1_allowed = true, +}; + +static const struct iwl_ht_params iwl9000_ht_params = { + .stbc = true, + .ldpc = true, + .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), +}; + +static const struct iwl_tt_params iwl9000_tt_params = { + .ct_kill_entry = 115, + .ct_kill_exit = 93, + .ct_kill_duration = 5, + .dynamic_smps_entry = 111, + .dynamic_smps_exit = 107, + .tx_protection_entry = 112, + .tx_protection_exit = 105, + .tx_backoff = { + {.temperature = 110, .backoff = 200}, + {.temperature = 111, .backoff = 600}, + {.temperature = 112, .backoff = 1200}, + {.temperature = 113, .backoff = 2000}, + {.temperature = 114, .backoff = 4000}, + }, + .support_ct_kill = true, + .support_dynamic_smps = true, + .support_tx_protection = true, + .support_tx_backoff = true, +}; + +#define IWL_DEVICE_9000 \ + .ucode_api_max = IWL9000_UCODE_API_MAX, \ + .ucode_api_min = IWL9000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_9000, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .base_params = &iwl9000_base_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_9000, \ + .non_shared_ant = ANT_A, \ + .dccm_offset = IWL9000_DCCM_OFFSET, \ + .dccm_len = IWL9000_DCCM_LEN, \ + .dccm2_offset = IWL9000_DCCM2_OFFSET, \ + .dccm2_len = IWL9000_DCCM2_LEN, \ + .smem_offset = IWL9000_SMEM_OFFSET, \ + .smem_len = IWL9000_SMEM_LEN, \ + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .thermal_params = &iwl9000_tt_params, \ + .apmg_not_supported = true, \ + .mq_rx_supported = true, \ + .vht_mu_mimo_supported = true, \ + .mac_addr_from_csr = true, \ + .rf_id = true, \ + .ext_nvm = true, \ + .dbgc_supported = true + +const struct iwl_cfg iwl9160_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 9160", + .fw_name_pre = IWL9260A_FW_PRE, + .fw_name_pre_next_step = IWL9260B_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwl9260_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 9260", + .fw_name_pre = IWL9260A_FW_PRE, + .fw_name_pre_next_step = IWL9260B_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwl9270_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 9270", + .fw_name_pre = IWL9260A_FW_PRE, + .fw_name_pre_next_step = IWL9260B_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwl9460_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 9460", + .fw_name_pre = IWL9000_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, +}; + +const struct iwl_cfg iwl9560_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 9560", + .fw_name_pre = IWL9000_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, +}; + +MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9260A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9260B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/a000.c b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c new file mode 100644 index 000000000000..2940c0a6c3d6 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c @@ -0,0 +1,172 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015-2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015-2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +#include +#include "iwl-config.h" +#include "iwl-agn-hw.h" + +/* Highest firmware API version supported */ +#define IWL_A000_UCODE_API_MAX 31 + +/* Lowest firmware API version supported */ +#define IWL_A000_UCODE_API_MIN 24 + +/* NVM versions */ +#define IWL_A000_NVM_VERSION 0x0a1d +#define IWL_A000_TX_POWER_VERSION 0xffff /* meaningless */ + +/* Memory offsets and lengths */ +#define IWL_A000_DCCM_OFFSET 0x800000 /* LMAC1 */ +#define IWL_A000_DCCM_LEN 0x10000 /* LMAC1 */ +#define IWL_A000_DCCM2_OFFSET 0x880000 +#define IWL_A000_DCCM2_LEN 0x8000 +#define IWL_A000_SMEM_OFFSET 0x400000 +#define IWL_A000_SMEM_LEN 0xD0000 + +#define IWL_A000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-" +#define IWL_A000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" +#define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-" + +#define IWL_A000_HR_MODULE_FIRMWARE(api) \ + IWL_A000_HR_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_A000_JF_MODULE_FIRMWARE(api) \ + IWL_A000_JF_FW_PRE "-" __stringify(api) ".ucode" + +#define NVM_HW_SECTION_NUM_FAMILY_A000 10 + +static const struct iwl_base_params iwl_a000_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_A000, + .num_of_queues = 512, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, + .pcie_l1_allowed = true, +}; + +static const struct iwl_ht_params iwl_a000_ht_params = { + .stbc = true, + .ldpc = true, + .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), +}; + +#define IWL_DEVICE_A000 \ + .ucode_api_max = IWL_A000_UCODE_API_MAX, \ + .ucode_api_min = IWL_A000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_A000, \ + .max_inst_size = IWL60_RTC_INST_SIZE, \ + .max_data_size = IWL60_RTC_DATA_SIZE, \ + .base_params = &iwl_a000_base_params, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_A000, \ + .non_shared_ant = ANT_A, \ + .dccm_offset = IWL_A000_DCCM_OFFSET, \ + .dccm_len = IWL_A000_DCCM_LEN, \ + .dccm2_offset = IWL_A000_DCCM2_OFFSET, \ + .dccm2_len = IWL_A000_DCCM2_LEN, \ + .smem_offset = IWL_A000_SMEM_OFFSET, \ + .smem_len = IWL_A000_SMEM_LEN, \ + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .apmg_not_supported = true, \ + .mq_rx_supported = true, \ + .vht_mu_mimo_supported = true, \ + .mac_addr_from_csr = true, \ + .use_tfh = true, \ + .rf_id = true, \ + .gen2 = true, \ + .ext_nvm = true, \ + .dbgc_supported = true + +const struct iwl_cfg iwla000_2ac_cfg_hr = { + .name = "Intel(R) Dual Band Wireless AC a000", + .fw_name_pre = IWL_A000_HR_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwla000_2ac_cfg_hr_cdb = { + .name = "Intel(R) Dual Band Wireless AC a000", + .fw_name_pre = IWL_A000_HR_CDB_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .cdb = true, +}; + +const struct iwl_cfg iwla000_2ac_cfg_jf = { + .name = "Intel(R) Dual Band Wireless AC a000", + .fw_name_pre = IWL_A000_JF_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwla000_2ax_cfg_hr = { + .name = "Intel(R) Dual Band Wireless AX a000", + .fw_name_pre = IWL_A000_HR_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +MODULE_FIRMWARE(IWL_A000_HR_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_A000_JF_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-1000.c b/drivers/net/wireless/intel/iwlwifi/iwl-1000.c deleted file mode 100644 index b2573b1d1506..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-1000.c +++ /dev/null @@ -1,134 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include -#include -#include "iwl-config.h" -#include "iwl-csr.h" -#include "iwl-agn-hw.h" - -/* Highest firmware API version supported */ -#define IWL1000_UCODE_API_MAX 5 -#define IWL100_UCODE_API_MAX 5 - -/* Lowest firmware API version supported */ -#define IWL1000_UCODE_API_MIN 1 -#define IWL100_UCODE_API_MIN 5 - -/* EEPROM version */ -#define EEPROM_1000_TX_POWER_VERSION (4) -#define EEPROM_1000_EEPROM_VERSION (0x15C) - -#define IWL1000_FW_PRE "iwlwifi-1000-" -#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode" - -#define IWL100_FW_PRE "iwlwifi-100-" -#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode" - - -static const struct iwl_base_params iwl1000_base_params = { - .num_of_queues = IWLAGN_NUM_QUEUES, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .pll_cfg = true, - .max_ll_items = OTP_MAX_LL_ITEMS_1000, - .shadow_ram_support = false, - .led_compensation = 51, - .wd_timeout = IWL_WATCHDOG_DISABLED, - .max_event_log_size = 128, - .scd_chain_ext_wa = true, -}; - -static const struct iwl_ht_params iwl1000_ht_params = { - .ht_greenfield_support = true, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .ht40_bands = BIT(NL80211_BAND_2GHZ), -}; - -static const struct iwl_eeprom_params iwl1000_eeprom_params = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_REG_BAND_24_HT40_CHANNELS, - EEPROM_REGULATORY_BAND_NO_HT40, - } -}; - -#define IWL_DEVICE_1000 \ - .fw_name_pre = IWL1000_FW_PRE, \ - .ucode_api_max = IWL1000_UCODE_API_MAX, \ - .ucode_api_min = IWL1000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_1000, \ - .max_inst_size = IWLAGN_RTC_INST_SIZE, \ - .max_data_size = IWLAGN_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_1000_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ - .base_params = &iwl1000_base_params, \ - .eeprom_params = &iwl1000_eeprom_params, \ - .led_mode = IWL_LED_BLINK, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl1000_bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN", - IWL_DEVICE_1000, - .ht_params = &iwl1000_ht_params, -}; - -const struct iwl_cfg iwl1000_bg_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 1000 BG", - IWL_DEVICE_1000, -}; - -#define IWL_DEVICE_100 \ - .fw_name_pre = IWL100_FW_PRE, \ - .ucode_api_max = IWL100_UCODE_API_MAX, \ - .ucode_api_min = IWL100_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_100, \ - .max_inst_size = IWLAGN_RTC_INST_SIZE, \ - .max_data_size = IWLAGN_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_1000_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ - .base_params = &iwl1000_base_params, \ - .eeprom_params = &iwl1000_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .rx_with_siso_diversity = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl100_bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 100 BGN", - IWL_DEVICE_100, - .ht_params = &iwl1000_ht_params, -}; - -const struct iwl_cfg iwl100_bg_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 100 BG", - IWL_DEVICE_100, -}; - -MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-2000.c b/drivers/net/wireless/intel/iwlwifi/iwl-2000.c deleted file mode 100644 index 1b32ad413b9e..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-2000.c +++ /dev/null @@ -1,204 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include -#include -#include "iwl-config.h" -#include "iwl-agn-hw.h" -#include "dvm/commands.h" /* needed for BT for now */ - -/* Highest firmware API version supported */ -#define IWL2030_UCODE_API_MAX 6 -#define IWL2000_UCODE_API_MAX 6 -#define IWL105_UCODE_API_MAX 6 -#define IWL135_UCODE_API_MAX 6 - -/* Lowest firmware API version supported */ -#define IWL2030_UCODE_API_MIN 5 -#define IWL2000_UCODE_API_MIN 5 -#define IWL105_UCODE_API_MIN 5 -#define IWL135_UCODE_API_MIN 5 - -/* EEPROM version */ -#define EEPROM_2000_TX_POWER_VERSION (6) -#define EEPROM_2000_EEPROM_VERSION (0x805) - - -#define IWL2030_FW_PRE "iwlwifi-2030-" -#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode" - -#define IWL2000_FW_PRE "iwlwifi-2000-" -#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode" - -#define IWL105_FW_PRE "iwlwifi-105-" -#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode" - -#define IWL135_FW_PRE "iwlwifi-135-" -#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode" - -static const struct iwl_base_params iwl2000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .num_of_queues = IWLAGN_NUM_QUEUES, - .max_ll_items = OTP_MAX_LL_ITEMS_2x00, - .shadow_ram_support = true, - .led_compensation = 51, - .wd_timeout = IWL_DEF_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ - .scd_chain_ext_wa = true, -}; - - -static const struct iwl_base_params iwl2030_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .num_of_queues = IWLAGN_NUM_QUEUES, - .max_ll_items = OTP_MAX_LL_ITEMS_2x00, - .shadow_ram_support = true, - .led_compensation = 57, - .wd_timeout = IWL_LONG_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ - .scd_chain_ext_wa = true, -}; - -static const struct iwl_ht_params iwl2000_ht_params = { - .ht_greenfield_support = true, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .ht40_bands = BIT(NL80211_BAND_2GHZ), -}; - -static const struct iwl_eeprom_params iwl20x0_eeprom_params = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_6000_REG_BAND_24_HT40_CHANNELS, - EEPROM_REGULATORY_BAND_NO_HT40, - }, - .enhanced_txpower = true, -}; - -#define IWL_DEVICE_2000 \ - .fw_name_pre = IWL2000_FW_PRE, \ - .ucode_api_max = IWL2000_UCODE_API_MAX, \ - .ucode_api_min = IWL2000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_2000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .base_params = &iwl2000_base_params, \ - .eeprom_params = &iwl20x0_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - - -const struct iwl_cfg iwl2000_2bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN", - IWL_DEVICE_2000, - .ht_params = &iwl2000_ht_params, -}; - -const struct iwl_cfg iwl2000_2bgn_d_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 2200D BGN", - IWL_DEVICE_2000, - .ht_params = &iwl2000_ht_params, -}; - -#define IWL_DEVICE_2030 \ - .fw_name_pre = IWL2030_FW_PRE, \ - .ucode_api_max = IWL2030_UCODE_API_MAX, \ - .ucode_api_min = IWL2030_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_2030, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .base_params = &iwl2030_base_params, \ - .eeprom_params = &iwl20x0_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl2030_2bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", - IWL_DEVICE_2030, - .ht_params = &iwl2000_ht_params, -}; - -#define IWL_DEVICE_105 \ - .fw_name_pre = IWL105_FW_PRE, \ - .ucode_api_max = IWL105_UCODE_API_MAX, \ - .ucode_api_min = IWL105_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_105, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .base_params = &iwl2000_base_params, \ - .eeprom_params = &iwl20x0_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .rx_with_siso_diversity = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl105_bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 105 BGN", - IWL_DEVICE_105, - .ht_params = &iwl2000_ht_params, -}; - -const struct iwl_cfg iwl105_bgn_d_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 105D BGN", - IWL_DEVICE_105, - .ht_params = &iwl2000_ht_params, -}; - -#define IWL_DEVICE_135 \ - .fw_name_pre = IWL135_FW_PRE, \ - .ucode_api_max = IWL135_UCODE_API_MAX, \ - .ucode_api_min = IWL135_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_135, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .base_params = &iwl2030_base_params, \ - .eeprom_params = &iwl20x0_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .rx_with_siso_diversity = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl135_bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 135 BGN", - IWL_DEVICE_135, - .ht_params = &iwl2000_ht_params, -}; - -MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-5000.c b/drivers/net/wireless/intel/iwlwifi/iwl-5000.c deleted file mode 100644 index 4aa8f0a05c8a..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-5000.c +++ /dev/null @@ -1,171 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include -#include -#include "iwl-config.h" -#include "iwl-agn-hw.h" -#include "iwl-csr.h" - -/* Highest firmware API version supported */ -#define IWL5000_UCODE_API_MAX 5 -#define IWL5150_UCODE_API_MAX 2 - -/* Lowest firmware API version supported */ -#define IWL5000_UCODE_API_MIN 1 -#define IWL5150_UCODE_API_MIN 1 - -/* EEPROM versions */ -#define EEPROM_5000_TX_POWER_VERSION (4) -#define EEPROM_5000_EEPROM_VERSION (0x11A) -#define EEPROM_5050_TX_POWER_VERSION (4) -#define EEPROM_5050_EEPROM_VERSION (0x21E) - -#define IWL5000_FW_PRE "iwlwifi-5000-" -#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode" - -#define IWL5150_FW_PRE "iwlwifi-5150-" -#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode" - -static const struct iwl_base_params iwl5000_base_params = { - .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, - .num_of_queues = IWLAGN_NUM_QUEUES, - .pll_cfg = true, - .led_compensation = 51, - .wd_timeout = IWL_WATCHDOG_DISABLED, - .max_event_log_size = 512, - .scd_chain_ext_wa = true, -}; - -static const struct iwl_ht_params iwl5000_ht_params = { - .ht_greenfield_support = true, - .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), -}; - -static const struct iwl_eeprom_params iwl5000_eeprom_params = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS - }, -}; - -#define IWL_DEVICE_5000 \ - .fw_name_pre = IWL5000_FW_PRE, \ - .ucode_api_max = IWL5000_UCODE_API_MAX, \ - .ucode_api_min = IWL5000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_5000, \ - .max_inst_size = IWLAGN_RTC_INST_SIZE, \ - .max_data_size = IWLAGN_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_5000_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ - .base_params = &iwl5000_base_params, \ - .eeprom_params = &iwl5000_eeprom_params, \ - .led_mode = IWL_LED_BLINK, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl5300_agn_cfg = { - .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", - IWL_DEVICE_5000, - /* at least EEPROM 0x11A has wrong info */ - .valid_tx_ant = ANT_ABC, /* .cfg overwrite */ - .valid_rx_ant = ANT_ABC, /* .cfg overwrite */ - .ht_params = &iwl5000_ht_params, -}; - -const struct iwl_cfg iwl5100_bgn_cfg = { - .name = "Intel(R) WiFi Link 5100 BGN", - IWL_DEVICE_5000, - .valid_tx_ant = ANT_B, /* .cfg overwrite */ - .valid_rx_ant = ANT_AB, /* .cfg overwrite */ - .ht_params = &iwl5000_ht_params, -}; - -const struct iwl_cfg iwl5100_abg_cfg = { - .name = "Intel(R) WiFi Link 5100 ABG", - IWL_DEVICE_5000, - .valid_tx_ant = ANT_B, /* .cfg overwrite */ - .valid_rx_ant = ANT_AB, /* .cfg overwrite */ -}; - -const struct iwl_cfg iwl5100_agn_cfg = { - .name = "Intel(R) WiFi Link 5100 AGN", - IWL_DEVICE_5000, - .valid_tx_ant = ANT_B, /* .cfg overwrite */ - .valid_rx_ant = ANT_AB, /* .cfg overwrite */ - .ht_params = &iwl5000_ht_params, -}; - -const struct iwl_cfg iwl5350_agn_cfg = { - .name = "Intel(R) WiMAX/WiFi Link 5350 AGN", - .fw_name_pre = IWL5000_FW_PRE, - .ucode_api_max = IWL5000_UCODE_API_MAX, - .ucode_api_min = IWL5000_UCODE_API_MIN, - .device_family = IWL_DEVICE_FAMILY_5000, - .max_inst_size = IWLAGN_RTC_INST_SIZE, - .max_data_size = IWLAGN_RTC_DATA_SIZE, - .nvm_ver = EEPROM_5050_EEPROM_VERSION, - .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION, - .base_params = &iwl5000_base_params, - .eeprom_params = &iwl5000_eeprom_params, - .ht_params = &iwl5000_ht_params, - .led_mode = IWL_LED_BLINK, - .internal_wimax_coex = true, -}; - -#define IWL_DEVICE_5150 \ - .fw_name_pre = IWL5150_FW_PRE, \ - .ucode_api_max = IWL5150_UCODE_API_MAX, \ - .ucode_api_min = IWL5150_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_5150, \ - .max_inst_size = IWLAGN_RTC_INST_SIZE, \ - .max_data_size = IWLAGN_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_5050_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ - .base_params = &iwl5000_base_params, \ - .eeprom_params = &iwl5000_eeprom_params, \ - .led_mode = IWL_LED_BLINK, \ - .internal_wimax_coex = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl5150_agn_cfg = { - .name = "Intel(R) WiMAX/WiFi Link 5150 AGN", - IWL_DEVICE_5150, - .ht_params = &iwl5000_ht_params, - -}; - -const struct iwl_cfg iwl5150_abg_cfg = { - .name = "Intel(R) WiMAX/WiFi Link 5150 ABG", - IWL_DEVICE_5150, -}; - -MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-6000.c b/drivers/net/wireless/intel/iwlwifi/iwl-6000.c deleted file mode 100644 index 39335b7b0c16..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-6000.c +++ /dev/null @@ -1,374 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include -#include -#include "iwl-config.h" -#include "iwl-agn-hw.h" -#include "dvm/commands.h" /* needed for BT for now */ - -/* Highest firmware API version supported */ -#define IWL6000_UCODE_API_MAX 6 -#define IWL6050_UCODE_API_MAX 5 -#define IWL6000G2_UCODE_API_MAX 6 -#define IWL6035_UCODE_API_MAX 6 - -/* Lowest firmware API version supported */ -#define IWL6000_UCODE_API_MIN 4 -#define IWL6050_UCODE_API_MIN 4 -#define IWL6000G2_UCODE_API_MIN 5 -#define IWL6035_UCODE_API_MIN 6 - -/* EEPROM versions */ -#define EEPROM_6000_TX_POWER_VERSION (4) -#define EEPROM_6000_EEPROM_VERSION (0x423) -#define EEPROM_6050_TX_POWER_VERSION (4) -#define EEPROM_6050_EEPROM_VERSION (0x532) -#define EEPROM_6150_TX_POWER_VERSION (6) -#define EEPROM_6150_EEPROM_VERSION (0x553) -#define EEPROM_6005_TX_POWER_VERSION (6) -#define EEPROM_6005_EEPROM_VERSION (0x709) -#define EEPROM_6030_TX_POWER_VERSION (6) -#define EEPROM_6030_EEPROM_VERSION (0x709) -#define EEPROM_6035_TX_POWER_VERSION (6) -#define EEPROM_6035_EEPROM_VERSION (0x753) - -#define IWL6000_FW_PRE "iwlwifi-6000-" -#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode" - -#define IWL6050_FW_PRE "iwlwifi-6050-" -#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode" - -#define IWL6005_FW_PRE "iwlwifi-6000g2a-" -#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode" - -#define IWL6030_FW_PRE "iwlwifi-6000g2b-" -#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode" - -static const struct iwl_base_params iwl6000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .num_of_queues = IWLAGN_NUM_QUEUES, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .led_compensation = 51, - .wd_timeout = IWL_DEF_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ - .scd_chain_ext_wa = true, -}; - -static const struct iwl_base_params iwl6050_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .num_of_queues = IWLAGN_NUM_QUEUES, - .max_ll_items = OTP_MAX_LL_ITEMS_6x50, - .shadow_ram_support = true, - .led_compensation = 51, - .wd_timeout = IWL_DEF_WD_TIMEOUT, - .max_event_log_size = 1024, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ - .scd_chain_ext_wa = true, -}; - -static const struct iwl_base_params iwl6000_g2_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .num_of_queues = IWLAGN_NUM_QUEUES, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .led_compensation = 57, - .wd_timeout = IWL_LONG_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ - .scd_chain_ext_wa = true, -}; - -static const struct iwl_ht_params iwl6000_ht_params = { - .ht_greenfield_support = true, - .use_rts_for_aggregation = true, /* use rts/cts protection */ - .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), -}; - -static const struct iwl_eeprom_params iwl6000_eeprom_params = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_6000_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS - }, - .enhanced_txpower = true, -}; - -#define IWL_DEVICE_6005 \ - .fw_name_pre = IWL6005_FW_PRE, \ - .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ - .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_6005, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_6005_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ - .base_params = &iwl6000_g2_base_params, \ - .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl6005_2agn_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN", - IWL_DEVICE_6005, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6005_2abg_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6205 ABG", - IWL_DEVICE_6005, -}; - -const struct iwl_cfg iwl6005_2bg_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6205 BG", - IWL_DEVICE_6005, -}; - -const struct iwl_cfg iwl6005_2agn_sff_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6205S AGN", - IWL_DEVICE_6005, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6005_2agn_d_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6205D AGN", - IWL_DEVICE_6005, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6005_2agn_mow1_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6206 AGN", - IWL_DEVICE_6005, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6005_2agn_mow2_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6207 AGN", - IWL_DEVICE_6005, - .ht_params = &iwl6000_ht_params, -}; - -#define IWL_DEVICE_6030 \ - .fw_name_pre = IWL6030_FW_PRE, \ - .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ - .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_6030, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_6030_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ - .base_params = &iwl6000_g2_base_params, \ - .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl6030_2agn_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN", - IWL_DEVICE_6030, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6030_2abg_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6230 ABG", - IWL_DEVICE_6030, -}; - -const struct iwl_cfg iwl6030_2bgn_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6230 BGN", - IWL_DEVICE_6030, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6030_2bg_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6230 BG", - IWL_DEVICE_6030, -}; - -#define IWL_DEVICE_6035 \ - .fw_name_pre = IWL6030_FW_PRE, \ - .ucode_api_max = IWL6035_UCODE_API_MAX, \ - .ucode_api_min = IWL6035_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_6030, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_6030_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ - .base_params = &iwl6000_g2_base_params, \ - .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl6035_2agn_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", - IWL_DEVICE_6035, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6035_2agn_sff_cfg = { - .name = "Intel(R) Centrino(R) Ultimate-N 6235 AGN", - IWL_DEVICE_6035, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl1030_bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", - IWL_DEVICE_6030, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl1030_bg_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 1030 BG", - IWL_DEVICE_6030, -}; - -const struct iwl_cfg iwl130_bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 130 BGN", - IWL_DEVICE_6030, - .ht_params = &iwl6000_ht_params, - .rx_with_siso_diversity = true, -}; - -const struct iwl_cfg iwl130_bg_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N 130 BG", - IWL_DEVICE_6030, - .rx_with_siso_diversity = true, -}; - -/* - * "i": Internal configuration, use internal Power Amplifier - */ -#define IWL_DEVICE_6000i \ - .fw_name_pre = IWL6000_FW_PRE, \ - .ucode_api_max = IWL6000_UCODE_API_MAX, \ - .ucode_api_min = IWL6000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_6000i, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .valid_tx_ant = ANT_BC, /* .cfg overwrite */ \ - .valid_rx_ant = ANT_BC, /* .cfg overwrite */ \ - .nvm_ver = EEPROM_6000_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ - .base_params = &iwl6000_base_params, \ - .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_BLINK, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl6000i_2agn_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN", - IWL_DEVICE_6000i, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6000i_2abg_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6200 ABG", - IWL_DEVICE_6000i, -}; - -const struct iwl_cfg iwl6000i_2bg_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N 6200 BG", - IWL_DEVICE_6000i, -}; - -#define IWL_DEVICE_6050 \ - .fw_name_pre = IWL6050_FW_PRE, \ - .ucode_api_max = IWL6050_UCODE_API_MAX, \ - .ucode_api_min = IWL6050_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_6050, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .valid_tx_ant = ANT_AB, /* .cfg overwrite */ \ - .valid_rx_ant = ANT_AB, /* .cfg overwrite */ \ - .nvm_ver = EEPROM_6050_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ - .base_params = &iwl6050_base_params, \ - .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_BLINK, \ - .internal_wimax_coex = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl6050_2agn_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN", - IWL_DEVICE_6050, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6050_2abg_cfg = { - .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG", - IWL_DEVICE_6050, -}; - -#define IWL_DEVICE_6150 \ - .fw_name_pre = IWL6050_FW_PRE, \ - .ucode_api_max = IWL6050_UCODE_API_MAX, \ - .ucode_api_min = IWL6050_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_6150, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .nvm_ver = EEPROM_6150_EEPROM_VERSION, \ - .nvm_calib_ver = EEPROM_6150_TX_POWER_VERSION, \ - .base_params = &iwl6050_base_params, \ - .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_BLINK, \ - .internal_wimax_coex = true, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K - -const struct iwl_cfg iwl6150_bgn_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN", - IWL_DEVICE_6150, - .ht_params = &iwl6000_ht_params, -}; - -const struct iwl_cfg iwl6150_bg_cfg = { - .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG", - IWL_DEVICE_6150, -}; - -const struct iwl_cfg iwl6000_3agn_cfg = { - .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN", - .fw_name_pre = IWL6000_FW_PRE, - .ucode_api_max = IWL6000_UCODE_API_MAX, - .ucode_api_min = IWL6000_UCODE_API_MIN, - .device_family = IWL_DEVICE_FAMILY_6000, - .max_inst_size = IWL60_RTC_INST_SIZE, - .max_data_size = IWL60_RTC_DATA_SIZE, - .nvm_ver = EEPROM_6000_EEPROM_VERSION, - .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION, - .base_params = &iwl6000_base_params, - .eeprom_params = &iwl6000_eeprom_params, - .ht_params = &iwl6000_ht_params, - .led_mode = IWL_LED_BLINK, -}; - -MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c deleted file mode 100644 index 45e2efc70d19..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c +++ /dev/null @@ -1,384 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ - -#include -#include -#include "iwl-config.h" -#include "iwl-agn-hw.h" - -/* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX 17 -#define IWL7265_UCODE_API_MAX 17 -#define IWL7265D_UCODE_API_MAX 29 -#define IWL3168_UCODE_API_MAX 29 - -/* Lowest firmware API version supported */ -#define IWL7260_UCODE_API_MIN 17 -#define IWL7265_UCODE_API_MIN 17 -#define IWL7265D_UCODE_API_MIN 22 -#define IWL3168_UCODE_API_MIN 22 - -/* NVM versions */ -#define IWL7260_NVM_VERSION 0x0a1d -#define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */ -#define IWL3160_NVM_VERSION 0x709 -#define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */ -#define IWL3165_NVM_VERSION 0x709 -#define IWL3165_TX_POWER_VERSION 0xffff /* meaningless */ -#define IWL3168_NVM_VERSION 0xd01 -#define IWL3168_TX_POWER_VERSION 0xffff /* meaningless */ -#define IWL7265_NVM_VERSION 0x0a1d -#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ -#define IWL7265D_NVM_VERSION 0x0c11 -#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ - -/* DCCM offsets and lengths */ -#define IWL7000_DCCM_OFFSET 0x800000 -#define IWL7260_DCCM_LEN 0x14000 -#define IWL3160_DCCM_LEN 0x10000 -#define IWL7265_DCCM_LEN 0x17A00 - -#define IWL7260_FW_PRE "iwlwifi-7260-" -#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" - -#define IWL3160_FW_PRE "iwlwifi-3160-" -#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode" - -#define IWL3168_FW_PRE "iwlwifi-3168-" -#define IWL3168_MODULE_FIRMWARE(api) IWL3168_FW_PRE __stringify(api) ".ucode" - -#define IWL7265_FW_PRE "iwlwifi-7265-" -#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" - -#define IWL7265D_FW_PRE "iwlwifi-7265D-" -#define IWL7265D_MODULE_FIRMWARE(api) IWL7265D_FW_PRE __stringify(api) ".ucode" - -#define NVM_HW_SECTION_NUM_FAMILY_7000 0 - -static const struct iwl_base_params iwl7000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_7000, - .num_of_queues = 31, - .shadow_ram_support = true, - .led_compensation = 57, - .wd_timeout = IWL_LONG_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = true, - .pcie_l1_allowed = true, - .apmg_wake_up_wa = true, -}; - -static const struct iwl_tt_params iwl7000_high_temp_tt_params = { - .ct_kill_entry = 118, - .ct_kill_exit = 96, - .ct_kill_duration = 5, - .dynamic_smps_entry = 114, - .dynamic_smps_exit = 110, - .tx_protection_entry = 114, - .tx_protection_exit = 108, - .tx_backoff = { - {.temperature = 112, .backoff = 300}, - {.temperature = 113, .backoff = 800}, - {.temperature = 114, .backoff = 1500}, - {.temperature = 115, .backoff = 3000}, - {.temperature = 116, .backoff = 5000}, - {.temperature = 117, .backoff = 10000}, - }, - .support_ct_kill = true, - .support_dynamic_smps = true, - .support_tx_protection = true, - .support_tx_backoff = true, -}; - -static const struct iwl_ht_params iwl7000_ht_params = { - .stbc = true, - .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), -}; - -#define IWL_DEVICE_7000_COMMON \ - .device_family = IWL_DEVICE_FAMILY_7000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .base_params = &iwl7000_base_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ - .non_shared_ant = ANT_A, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ - .dccm_offset = IWL7000_DCCM_OFFSET - -#define IWL_DEVICE_7000 \ - IWL_DEVICE_7000_COMMON, \ - .ucode_api_max = IWL7260_UCODE_API_MAX, \ - .ucode_api_min = IWL7260_UCODE_API_MIN - -#define IWL_DEVICE_7005 \ - IWL_DEVICE_7000_COMMON, \ - .ucode_api_max = IWL7265_UCODE_API_MAX, \ - .ucode_api_min = IWL7265_UCODE_API_MIN - -#define IWL_DEVICE_3008 \ - IWL_DEVICE_7000_COMMON, \ - .ucode_api_max = IWL3168_UCODE_API_MAX, \ - .ucode_api_min = IWL3168_UCODE_API_MIN - -#define IWL_DEVICE_7005D \ - IWL_DEVICE_7000_COMMON, \ - .ucode_api_max = IWL7265D_UCODE_API_MAX, \ - .ucode_api_min = IWL7265D_UCODE_API_MIN - -const struct iwl_cfg iwl7260_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 7260", - .fw_name_pre = IWL7260_FW_PRE, - IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL7260_NVM_VERSION, - .nvm_calib_ver = IWL7260_TX_POWER_VERSION, - .host_interrupt_operation_mode = true, - .lp_xtal_workaround = true, - .dccm_len = IWL7260_DCCM_LEN, -}; - -const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { - .name = "Intel(R) Dual Band Wireless AC 7260", - .fw_name_pre = IWL7260_FW_PRE, - IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL7260_NVM_VERSION, - .nvm_calib_ver = IWL7260_TX_POWER_VERSION, - .high_temp = true, - .host_interrupt_operation_mode = true, - .lp_xtal_workaround = true, - .dccm_len = IWL7260_DCCM_LEN, - .thermal_params = &iwl7000_high_temp_tt_params, -}; - -const struct iwl_cfg iwl7260_2n_cfg = { - .name = "Intel(R) Dual Band Wireless N 7260", - .fw_name_pre = IWL7260_FW_PRE, - IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL7260_NVM_VERSION, - .nvm_calib_ver = IWL7260_TX_POWER_VERSION, - .host_interrupt_operation_mode = true, - .lp_xtal_workaround = true, - .dccm_len = IWL7260_DCCM_LEN, -}; - -const struct iwl_cfg iwl7260_n_cfg = { - .name = "Intel(R) Wireless N 7260", - .fw_name_pre = IWL7260_FW_PRE, - IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL7260_NVM_VERSION, - .nvm_calib_ver = IWL7260_TX_POWER_VERSION, - .host_interrupt_operation_mode = true, - .lp_xtal_workaround = true, - .dccm_len = IWL7260_DCCM_LEN, -}; - -const struct iwl_cfg iwl3160_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 3160", - .fw_name_pre = IWL3160_FW_PRE, - IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL3160_NVM_VERSION, - .nvm_calib_ver = IWL3160_TX_POWER_VERSION, - .host_interrupt_operation_mode = true, - .dccm_len = IWL3160_DCCM_LEN, -}; - -const struct iwl_cfg iwl3160_2n_cfg = { - .name = "Intel(R) Dual Band Wireless N 3160", - .fw_name_pre = IWL3160_FW_PRE, - IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL3160_NVM_VERSION, - .nvm_calib_ver = IWL3160_TX_POWER_VERSION, - .host_interrupt_operation_mode = true, - .dccm_len = IWL3160_DCCM_LEN, -}; - -const struct iwl_cfg iwl3160_n_cfg = { - .name = "Intel(R) Wireless N 3160", - .fw_name_pre = IWL3160_FW_PRE, - IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL3160_NVM_VERSION, - .nvm_calib_ver = IWL3160_TX_POWER_VERSION, - .host_interrupt_operation_mode = true, - .dccm_len = IWL3160_DCCM_LEN, -}; - -static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { - {.pwr = 1600, .backoff = 0}, - {.pwr = 1300, .backoff = 467}, - {.pwr = 900, .backoff = 1900}, - {.pwr = 800, .backoff = 2630}, - {.pwr = 700, .backoff = 3720}, - {.pwr = 600, .backoff = 5550}, - {.pwr = 500, .backoff = 9350}, - {0}, -}; - -static const struct iwl_ht_params iwl7265_ht_params = { - .stbc = true, - .ldpc = true, - .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), -}; - -const struct iwl_cfg iwl3165_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 3165", - .fw_name_pre = IWL7265D_FW_PRE, - IWL_DEVICE_7005D, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL3165_NVM_VERSION, - .nvm_calib_ver = IWL3165_TX_POWER_VERSION, - .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, - .dccm_len = IWL7265_DCCM_LEN, -}; - -const struct iwl_cfg iwl3168_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 3168", - .fw_name_pre = IWL3168_FW_PRE, - IWL_DEVICE_3008, - .ht_params = &iwl7000_ht_params, - .nvm_ver = IWL3168_NVM_VERSION, - .nvm_calib_ver = IWL3168_TX_POWER_VERSION, - .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, - .dccm_len = IWL7265_DCCM_LEN, -}; - -const struct iwl_cfg iwl7265_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 7265", - .fw_name_pre = IWL7265_FW_PRE, - IWL_DEVICE_7005, - .ht_params = &iwl7265_ht_params, - .nvm_ver = IWL7265_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, - .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, - .dccm_len = IWL7265_DCCM_LEN, -}; - -const struct iwl_cfg iwl7265_2n_cfg = { - .name = "Intel(R) Dual Band Wireless N 7265", - .fw_name_pre = IWL7265_FW_PRE, - IWL_DEVICE_7005, - .ht_params = &iwl7265_ht_params, - .nvm_ver = IWL7265_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, - .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, - .dccm_len = IWL7265_DCCM_LEN, -}; - -const struct iwl_cfg iwl7265_n_cfg = { - .name = "Intel(R) Wireless N 7265", - .fw_name_pre = IWL7265_FW_PRE, - IWL_DEVICE_7005, - .ht_params = &iwl7265_ht_params, - .nvm_ver = IWL7265_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, - .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, - .dccm_len = IWL7265_DCCM_LEN, -}; - -const struct iwl_cfg iwl7265d_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 7265", - .fw_name_pre = IWL7265D_FW_PRE, - IWL_DEVICE_7005D, - .ht_params = &iwl7265_ht_params, - .nvm_ver = IWL7265D_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, - .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, - .dccm_len = IWL7265_DCCM_LEN, -}; - -const struct iwl_cfg iwl7265d_2n_cfg = { - .name = "Intel(R) Dual Band Wireless N 7265", - .fw_name_pre = IWL7265D_FW_PRE, - IWL_DEVICE_7005D, - .ht_params = &iwl7265_ht_params, - .nvm_ver = IWL7265D_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, - .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, - .dccm_len = IWL7265_DCCM_LEN, -}; - -const struct iwl_cfg iwl7265d_n_cfg = { - .name = "Intel(R) Wireless N 7265", - .fw_name_pre = IWL7265D_FW_PRE, - IWL_DEVICE_7005D, - .ht_params = &iwl7265_ht_params, - .nvm_ver = IWL7265D_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, - .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, - .dccm_len = IWL7265_DCCM_LEN, -}; - -MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL7260_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL3168_MODULE_FIRMWARE(IWL3168_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7265_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7265D_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c deleted file mode 100644 index 766bb2037b94..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ /dev/null @@ -1,280 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ - -#include -#include -#include "iwl-config.h" -#include "iwl-agn-hw.h" - -/* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 31 -#define IWL8265_UCODE_API_MAX 31 - -/* Lowest firmware API version supported */ -#define IWL8000_UCODE_API_MIN 22 -#define IWL8265_UCODE_API_MIN 22 - -/* NVM versions */ -#define IWL8000_NVM_VERSION 0x0a1d -#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ - -/* Memory offsets and lengths */ -#define IWL8260_DCCM_OFFSET 0x800000 -#define IWL8260_DCCM_LEN 0x18000 -#define IWL8260_DCCM2_OFFSET 0x880000 -#define IWL8260_DCCM2_LEN 0x8000 -#define IWL8260_SMEM_OFFSET 0x400000 -#define IWL8260_SMEM_LEN 0x68000 - -#define IWL8000_FW_PRE "iwlwifi-8000C-" -#define IWL8000_MODULE_FIRMWARE(api) \ - IWL8000_FW_PRE __stringify(api) ".ucode" - -#define IWL8265_FW_PRE "iwlwifi-8265-" -#define IWL8265_MODULE_FIRMWARE(api) \ - IWL8265_FW_PRE __stringify(api) ".ucode" - -#define NVM_HW_SECTION_NUM_FAMILY_8000 10 -#define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C" - -/* Max SDIO RX/TX aggregation sizes of the ADDBA request/response */ -#define MAX_RX_AGG_SIZE_8260_SDIO 21 -#define MAX_TX_AGG_SIZE_8260_SDIO 40 - -/* Max A-MPDU exponent for HT and VHT */ -#define MAX_HT_AMPDU_EXPONENT_8260_SDIO IEEE80211_HT_MAX_AMPDU_32K -#define MAX_VHT_AMPDU_EXPONENT_8260_SDIO IEEE80211_VHT_MAX_AMPDU_32K - -static const struct iwl_base_params iwl8000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, - .num_of_queues = 31, - .shadow_ram_support = true, - .led_compensation = 57, - .wd_timeout = IWL_LONG_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = true, - .pcie_l1_allowed = true, -}; - -static const struct iwl_ht_params iwl8000_ht_params = { - .stbc = true, - .ldpc = true, - .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), -}; - -static const struct iwl_tt_params iwl8000_tt_params = { - .ct_kill_entry = 115, - .ct_kill_exit = 93, - .ct_kill_duration = 5, - .dynamic_smps_entry = 111, - .dynamic_smps_exit = 107, - .tx_protection_entry = 112, - .tx_protection_exit = 105, - .tx_backoff = { - {.temperature = 110, .backoff = 200}, - {.temperature = 111, .backoff = 600}, - {.temperature = 112, .backoff = 1200}, - {.temperature = 113, .backoff = 2000}, - {.temperature = 114, .backoff = 4000}, - }, - .support_ct_kill = true, - .support_dynamic_smps = true, - .support_tx_protection = true, - .support_tx_backoff = true, -}; - -#define IWL_DEVICE_8000_COMMON \ - .device_family = IWL_DEVICE_FAMILY_8000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .base_params = &iwl8000_base_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ - .features = NETIF_F_RXCSUM, \ - .non_shared_ant = ANT_A, \ - .dccm_offset = IWL8260_DCCM_OFFSET, \ - .dccm_len = IWL8260_DCCM_LEN, \ - .dccm2_offset = IWL8260_DCCM2_OFFSET, \ - .dccm2_len = IWL8260_DCCM2_LEN, \ - .smem_offset = IWL8260_SMEM_OFFSET, \ - .smem_len = IWL8260_SMEM_LEN, \ - .default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, \ - .thermal_params = &iwl8000_tt_params, \ - .apmg_not_supported = true, \ - .ext_nvm = true, \ - .dbgc_supported = true - -#define IWL_DEVICE_8000 \ - IWL_DEVICE_8000_COMMON, \ - .ucode_api_max = IWL8000_UCODE_API_MAX, \ - .ucode_api_min = IWL8000_UCODE_API_MIN \ - -#define IWL_DEVICE_8260 \ - IWL_DEVICE_8000_COMMON, \ - .ucode_api_max = IWL8000_UCODE_API_MAX, \ - .ucode_api_min = IWL8000_UCODE_API_MIN \ - -#define IWL_DEVICE_8265 \ - IWL_DEVICE_8000_COMMON, \ - .ucode_api_max = IWL8265_UCODE_API_MAX, \ - .ucode_api_min = IWL8265_UCODE_API_MIN \ - -const struct iwl_cfg iwl8260_2n_cfg = { - .name = "Intel(R) Dual Band Wireless N 8260", - .fw_name_pre = IWL8000_FW_PRE, - IWL_DEVICE_8260, - .ht_params = &iwl8000_ht_params, - .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, -}; - -const struct iwl_cfg iwl8260_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 8260", - .fw_name_pre = IWL8000_FW_PRE, - IWL_DEVICE_8260, - .ht_params = &iwl8000_ht_params, - .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, -}; - -const struct iwl_cfg iwl8265_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 8265", - .fw_name_pre = IWL8265_FW_PRE, - IWL_DEVICE_8265, - .ht_params = &iwl8000_ht_params, - .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, - .vht_mu_mimo_supported = true, -}; - -const struct iwl_cfg iwl8275_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 8275", - .fw_name_pre = IWL8265_FW_PRE, - IWL_DEVICE_8265, - .ht_params = &iwl8000_ht_params, - .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, - .vht_mu_mimo_supported = true, -}; - -const struct iwl_cfg iwl4165_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 4165", - .fw_name_pre = IWL8000_FW_PRE, - IWL_DEVICE_8000, - .ht_params = &iwl8000_ht_params, - .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, -}; - -const struct iwl_cfg iwl8260_2ac_sdio_cfg = { - .name = "Intel(R) Dual Band Wireless-AC 8260", - .fw_name_pre = IWL8000_FW_PRE, - IWL_DEVICE_8260, - .ht_params = &iwl8000_ht_params, - .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, - .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, - .disable_dummy_notification = true, - .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, - .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, -}; - -const struct iwl_cfg iwl8265_2ac_sdio_cfg = { - .name = "Intel(R) Dual Band Wireless-AC 8265", - .fw_name_pre = IWL8265_FW_PRE, - IWL_DEVICE_8265, - .ht_params = &iwl8000_ht_params, - .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, - .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, - .disable_dummy_notification = true, - .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, - .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, -}; - -const struct iwl_cfg iwl4165_2ac_sdio_cfg = { - .name = "Intel(R) Dual Band Wireless-AC 4165", - .fw_name_pre = IWL8000_FW_PRE, - IWL_DEVICE_8000, - .ht_params = &iwl8000_ht_params, - .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, - .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, - .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, - .bt_shared_single_ant = true, - .disable_dummy_notification = true, - .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, - .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, -}; - -MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL8265_MODULE_FIRMWARE(IWL8265_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c deleted file mode 100644 index 42daaddfa740..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ /dev/null @@ -1,214 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2015-2017 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * BSD LICENSE - * - * Copyright(c) 2015-2017 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ - -#include -#include -#include "iwl-config.h" -#include "iwl-agn-hw.h" - -/* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 31 - -/* Lowest firmware API version supported */ -#define IWL9000_UCODE_API_MIN 30 - -/* NVM versions */ -#define IWL9000_NVM_VERSION 0x0a1d -#define IWL9000_TX_POWER_VERSION 0xffff /* meaningless */ - -/* Memory offsets and lengths */ -#define IWL9000_DCCM_OFFSET 0x800000 -#define IWL9000_DCCM_LEN 0x18000 -#define IWL9000_DCCM2_OFFSET 0x880000 -#define IWL9000_DCCM2_LEN 0x8000 -#define IWL9000_SMEM_OFFSET 0x400000 -#define IWL9000_SMEM_LEN 0x68000 - -#define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-" -#define IWL9000RFB_FW_PRE "iwlwifi-9000-pu-a0-jf-b0-" -#define IWL9260A_FW_PRE "iwlwifi-9260-th-a0-jf-a0-" -#define IWL9260B_FW_PRE "iwlwifi-9260-th-b0-jf-b0-" -#define IWL9000_MODULE_FIRMWARE(api) \ - IWL9000_FW_PRE "-" __stringify(api) ".ucode" -#define IWL9000RFB_MODULE_FIRMWARE(api) \ - IWL9000RFB_FW_PRE "-" __stringify(api) ".ucode" -#define IWL9260A_MODULE_FIRMWARE(api) \ - IWL9260A_FW_PRE "-" __stringify(api) ".ucode" -#define IWL9260B_MODULE_FIRMWARE(api) \ - IWL9260B_FW_PRE "-" __stringify(api) ".ucode" - -#define NVM_HW_SECTION_NUM_FAMILY_9000 10 - -static const struct iwl_base_params iwl9000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_9000, - .num_of_queues = 31, - .shadow_ram_support = true, - .led_compensation = 57, - .wd_timeout = IWL_LONG_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = true, - .pcie_l1_allowed = true, -}; - -static const struct iwl_ht_params iwl9000_ht_params = { - .stbc = true, - .ldpc = true, - .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), -}; - -static const struct iwl_tt_params iwl9000_tt_params = { - .ct_kill_entry = 115, - .ct_kill_exit = 93, - .ct_kill_duration = 5, - .dynamic_smps_entry = 111, - .dynamic_smps_exit = 107, - .tx_protection_entry = 112, - .tx_protection_exit = 105, - .tx_backoff = { - {.temperature = 110, .backoff = 200}, - {.temperature = 111, .backoff = 600}, - {.temperature = 112, .backoff = 1200}, - {.temperature = 113, .backoff = 2000}, - {.temperature = 114, .backoff = 4000}, - }, - .support_ct_kill = true, - .support_dynamic_smps = true, - .support_tx_protection = true, - .support_tx_backoff = true, -}; - -#define IWL_DEVICE_9000 \ - .ucode_api_max = IWL9000_UCODE_API_MAX, \ - .ucode_api_min = IWL9000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_9000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .base_params = &iwl9000_base_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_9000, \ - .non_shared_ant = ANT_A, \ - .dccm_offset = IWL9000_DCCM_OFFSET, \ - .dccm_len = IWL9000_DCCM_LEN, \ - .dccm2_offset = IWL9000_DCCM2_OFFSET, \ - .dccm2_len = IWL9000_DCCM2_LEN, \ - .smem_offset = IWL9000_SMEM_OFFSET, \ - .smem_len = IWL9000_SMEM_LEN, \ - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ - .thermal_params = &iwl9000_tt_params, \ - .apmg_not_supported = true, \ - .mq_rx_supported = true, \ - .vht_mu_mimo_supported = true, \ - .mac_addr_from_csr = true, \ - .rf_id = true, \ - .ext_nvm = true, \ - .dbgc_supported = true - -const struct iwl_cfg iwl9160_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 9160", - .fw_name_pre = IWL9260A_FW_PRE, - .fw_name_pre_next_step = IWL9260B_FW_PRE, - IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, -}; - -const struct iwl_cfg iwl9260_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 9260", - .fw_name_pre = IWL9260A_FW_PRE, - .fw_name_pre_next_step = IWL9260B_FW_PRE, - IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, -}; - -const struct iwl_cfg iwl9270_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 9270", - .fw_name_pre = IWL9260A_FW_PRE, - .fw_name_pre_next_step = IWL9260B_FW_PRE, - IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, -}; - -const struct iwl_cfg iwl9460_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 9460", - .fw_name_pre = IWL9000_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, - IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, - .integrated = true, -}; - -const struct iwl_cfg iwl9560_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 9560", - .fw_name_pre = IWL9000_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, - IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, - .integrated = true, -}; - -MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL9260A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL9260B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c deleted file mode 100644 index 2940c0a6c3d6..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ /dev/null @@ -1,172 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2015-2017 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * BSD LICENSE - * - * Copyright(c) 2015-2017 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ - -#include -#include -#include "iwl-config.h" -#include "iwl-agn-hw.h" - -/* Highest firmware API version supported */ -#define IWL_A000_UCODE_API_MAX 31 - -/* Lowest firmware API version supported */ -#define IWL_A000_UCODE_API_MIN 24 - -/* NVM versions */ -#define IWL_A000_NVM_VERSION 0x0a1d -#define IWL_A000_TX_POWER_VERSION 0xffff /* meaningless */ - -/* Memory offsets and lengths */ -#define IWL_A000_DCCM_OFFSET 0x800000 /* LMAC1 */ -#define IWL_A000_DCCM_LEN 0x10000 /* LMAC1 */ -#define IWL_A000_DCCM2_OFFSET 0x880000 -#define IWL_A000_DCCM2_LEN 0x8000 -#define IWL_A000_SMEM_OFFSET 0x400000 -#define IWL_A000_SMEM_LEN 0xD0000 - -#define IWL_A000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-" -#define IWL_A000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" -#define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-" - -#define IWL_A000_HR_MODULE_FIRMWARE(api) \ - IWL_A000_HR_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_A000_JF_MODULE_FIRMWARE(api) \ - IWL_A000_JF_FW_PRE "-" __stringify(api) ".ucode" - -#define NVM_HW_SECTION_NUM_FAMILY_A000 10 - -static const struct iwl_base_params iwl_a000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_A000, - .num_of_queues = 512, - .shadow_ram_support = true, - .led_compensation = 57, - .wd_timeout = IWL_LONG_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = true, - .pcie_l1_allowed = true, -}; - -static const struct iwl_ht_params iwl_a000_ht_params = { - .stbc = true, - .ldpc = true, - .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), -}; - -#define IWL_DEVICE_A000 \ - .ucode_api_max = IWL_A000_UCODE_API_MAX, \ - .ucode_api_min = IWL_A000_UCODE_API_MIN, \ - .device_family = IWL_DEVICE_FAMILY_A000, \ - .max_inst_size = IWL60_RTC_INST_SIZE, \ - .max_data_size = IWL60_RTC_DATA_SIZE, \ - .base_params = &iwl_a000_base_params, \ - .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_A000, \ - .non_shared_ant = ANT_A, \ - .dccm_offset = IWL_A000_DCCM_OFFSET, \ - .dccm_len = IWL_A000_DCCM_LEN, \ - .dccm2_offset = IWL_A000_DCCM2_OFFSET, \ - .dccm2_len = IWL_A000_DCCM2_LEN, \ - .smem_offset = IWL_A000_SMEM_OFFSET, \ - .smem_len = IWL_A000_SMEM_LEN, \ - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ - .apmg_not_supported = true, \ - .mq_rx_supported = true, \ - .vht_mu_mimo_supported = true, \ - .mac_addr_from_csr = true, \ - .use_tfh = true, \ - .rf_id = true, \ - .gen2 = true, \ - .ext_nvm = true, \ - .dbgc_supported = true - -const struct iwl_cfg iwla000_2ac_cfg_hr = { - .name = "Intel(R) Dual Band Wireless AC a000", - .fw_name_pre = IWL_A000_HR_FW_PRE, - IWL_DEVICE_A000, - .ht_params = &iwl_a000_ht_params, - .nvm_ver = IWL_A000_NVM_VERSION, - .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, -}; - -const struct iwl_cfg iwla000_2ac_cfg_hr_cdb = { - .name = "Intel(R) Dual Band Wireless AC a000", - .fw_name_pre = IWL_A000_HR_CDB_FW_PRE, - IWL_DEVICE_A000, - .ht_params = &iwl_a000_ht_params, - .nvm_ver = IWL_A000_NVM_VERSION, - .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, - .cdb = true, -}; - -const struct iwl_cfg iwla000_2ac_cfg_jf = { - .name = "Intel(R) Dual Band Wireless AC a000", - .fw_name_pre = IWL_A000_JF_FW_PRE, - IWL_DEVICE_A000, - .ht_params = &iwl_a000_ht_params, - .nvm_ver = IWL_A000_NVM_VERSION, - .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, -}; - -const struct iwl_cfg iwla000_2ax_cfg_hr = { - .name = "Intel(R) Dual Band Wireless AX a000", - .fw_name_pre = IWL_A000_HR_FW_PRE, - IWL_DEVICE_A000, - .ht_params = &iwl_a000_ht_params, - .nvm_ver = IWL_A000_NVM_VERSION, - .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, -}; - -MODULE_FIRMWARE(IWL_A000_HR_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_A000_JF_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); -- cgit v1.2.3 From 4f2210ee8498faa3499a927f0a40027ff972ec3a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2017 11:37:25 +0200 Subject: iwlwifi: mvm: remove version 2 of paging command Only a000-series devices were going to use this, but actually initialize using the context info, which includes paging, so this code is never invoked; remove it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 25 ++-------------- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 39 ++++++++----------------- 2 files changed, 15 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index f3ca61ff9f58..3e297c95e8ff 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -326,7 +326,7 @@ enum iwl_legacy_cmds { /** * @FW_PAGING_BLOCK_CMD: - * &struct iwl_fw_paging_cmd or &struct iwl_fw_paging_cmd_v1 + * &struct iwl_fw_paging_cmd */ FW_PAGING_BLOCK_CMD = 0x4f, @@ -998,25 +998,6 @@ struct iwl_nvm_access_cmd { #define NUM_OF_FW_PAGING_BLOCKS 33 /* 32 for data and 1 block for CSS */ -/** - * struct iwl_fw_paging_cmd_v1 - paging layout - * - * (FW_PAGING_BLOCK_CMD = 0x4f) - * - * Send to FW the paging layout in the driver. - * - * @flags: various flags for the command - * @block_size: the block size in powers of 2 - * @block_num: number of blocks specified in the command. - * @device_phy_addr: virtual addresses from device side - */ -struct iwl_fw_paging_cmd_v1 { - __le32 flags; - __le32 block_size; - __le32 block_num; - __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; -} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ - /** * struct iwl_fw_paging_cmd - paging layout * @@ -1033,8 +1014,8 @@ struct iwl_fw_paging_cmd { __le32 flags; __le32 block_size; __le32 block_num; - __le64 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; -} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_2 */ + __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; +} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ /* * Fw items ID's diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 80c42ef981c0..79e7a7a285dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -384,44 +384,29 @@ static int iwl_save_fw_paging(struct iwl_mvm *mvm, /* send paging cmd to FW in case CPU2 has paging image */ static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) { - union { - struct iwl_fw_paging_cmd v2; - struct iwl_fw_paging_cmd_v1 v1; - } paging_cmd = { - .v2.flags = - cpu_to_le32(PAGING_CMD_IS_SECURED | - PAGING_CMD_IS_ENABLED | - (mvm->num_of_pages_in_last_blk << - PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), - .v2.block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), - .v2.block_num = cpu_to_le32(mvm->num_of_paging_blk), + struct iwl_fw_paging_cmd paging_cmd = { + .flags = cpu_to_le32(PAGING_CMD_IS_SECURED | + PAGING_CMD_IS_ENABLED | + (mvm->num_of_pages_in_last_blk << + PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), + .block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), + .block_num = cpu_to_le32(mvm->num_of_paging_blk), }; - int blk_idx, size = sizeof(paging_cmd.v2); - - /* A bit hard coded - but this is the old API and will be deprecated */ - if (!iwl_mvm_has_new_tx_api(mvm)) - size = sizeof(paging_cmd.v1); + int blk_idx; /* loop for for all paging blocks + CSS block */ for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { dma_addr_t addr = mvm->fw_paging_db[blk_idx].fw_paging_phys; + __le32 phy_addr; addr = addr >> PAGE_2_EXP_SIZE; - - if (iwl_mvm_has_new_tx_api(mvm)) { - __le64 phy_addr = cpu_to_le64(addr); - - paging_cmd.v2.device_phy_addr[blk_idx] = phy_addr; - } else { - __le32 phy_addr = cpu_to_le32(addr); - - paging_cmd.v1.device_phy_addr[blk_idx] = phy_addr; - } + phy_addr = cpu_to_le32(addr); + paging_cmd.device_phy_addr[blk_idx] = phy_addr; } return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(FW_PAGING_BLOCK_CMD, IWL_ALWAYS_LONG_GROUP, 0), - 0, size, &paging_cmd); + 0, sizeof(paging_cmd), &paging_cmd); } /* -- cgit v1.2.3 From e6835942a7414ef4fd07b59851ad1fca7560dec1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 12 Jun 2017 11:24:06 +0200 Subject: iwlwifi: mvm: quietly accept non-sta assoc response frames When hostapd adds a station, it does so before sending the association response frame, so that it can indicate the correct status code in the response. However, when this then fails, or the association response already is a reject for some other reason, then there's no station entry and thus no per-station management queue to send the response on and it must be sent on the probe response queue. The code should therefore not warn. In theory, we could check and warn if the status code is success, but that seems excessive, so just relax the check to allow any association response frames. Fixes: 3ee0f0e23e4f ("iwlwifi: mvm: fix DQA AP mode station assumption") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 627befb0d8d1..214829e5a860 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -554,12 +554,15 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: /* - * Handle legacy hostapd as well, where station may be added - * only after assoc. Take care of the case where we send a - * deauth to a station that we don't have. + * Handle legacy hostapd as well, where station will be added + * only just before sending the association response. + * Also take care of the case where we send a deauth to a + * station that we don't have, or similarly an association + * response (with non-success status) for a station we can't + * accept. */ if (ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) || - ieee80211_is_deauth(fc)) + ieee80211_is_deauth(fc) || ieee80211_is_assoc_resp(fc)) return mvm->probe_queue; if (info->hw_queue == info->control.vif->cab_queue) return info->hw_queue; -- cgit v1.2.3 From c4c285da1ee18582ace366f07e56e355c20ebc49 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 29 Jun 2017 14:21:32 +0200 Subject: Bluetooth: hci_bcm: Add active_low irq polarity quirk for Asus T100CHI Just like the T100TA the host-wake irq on the Asus T100CHI is active low. Having a quirk for this is actually extra important on the T100CHI as it ships with a bluetooth keyboard dock, which does not work properly without this quirk. Signed-off-by: Hans de Goede Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_bcm.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 192ad2781733..6a662d0161b4 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -656,6 +656,15 @@ static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = { }, .driver_data = &acpi_active_low, }, + { + .ident = "Asus T100CHI", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, + "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100CHI"), + }, + .driver_data = &acpi_active_low, + }, { /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */ .ident = "Lenovo ThinkPad 8", .matches = { -- cgit v1.2.3 From feb16722b5d5f05b7ae1278a43e717c3d35cd512 Mon Sep 17 00:00:00 2001 From: Ian Molton Date: Wed, 28 Jun 2017 20:10:55 +0100 Subject: Bluetooth: btbcm: Add entry for BCM43430 UART bluetooth This patch adds the device ID for the bluetooth chip used in the Broadcom BCM43430 SDIO WiFi / UART BT chip. Successfully tested using Firmware version 0x0182 Signed-off-by: Ian Molton Reported-by: Loic Poulain Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btbcm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 24f8c4e93f4e..9ab6cfbb831d 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -295,6 +295,7 @@ static const struct { { 0x410e, "BCM43341B0" }, /* 002.001.014 */ { 0x4406, "BCM4324B3" }, /* 002.004.006 */ { 0x610c, "BCM4354" }, /* 003.001.012 */ + { 0x2209, "BCM43430A1" }, /* 001.002.009 */ { } }; -- cgit v1.2.3 From eac306b4adb7452c0228f32dd004f791ab08aae8 Mon Sep 17 00:00:00 2001 From: Michael Dilmore Date: Mon, 26 Jun 2017 16:49:46 +0100 Subject: Bonding: Convert multiple netdev_info messages to netdev_dbg The bond_options.c file contains multiple netdev_info statements that clutter kernel output. This patch replaces all netdev_info with netdev_dbg and adds a netdev_dbg statement for the packets per slave parameter. Also fixes misalignment at line 467. Suggested-by: Joe Perches Signed-off-by: Michael J Dilmore Signed-off-by: David S. Miller --- drivers/net/bonding/bond_options.c | 132 +++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 8ca683396fcc..a12d603d41c6 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -464,7 +464,7 @@ const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val) /* Searches for a value in opt's values[] table which matches the flagmask */ static const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt, - u32 flagmask) + u32 flagmask) { int i; @@ -744,14 +744,14 @@ static int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval) { if (!bond_mode_uses_arp(newval->value) && bond->params.arp_interval) { - netdev_info(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n", - newval->string); + netdev_dbg(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n", + newval->string); /* disable arp monitoring */ bond->params.arp_interval = 0; /* set miimon to default value */ bond->params.miimon = BOND_DEFAULT_MIIMON; - netdev_info(bond->dev, "Setting MII monitoring interval to %d\n", - bond->params.miimon); + netdev_dbg(bond->dev, "Setting MII monitoring interval to %d\n", + bond->params.miimon); } /* don't cache arp_validate between modes */ @@ -794,7 +794,7 @@ static int bond_option_active_slave_set(struct bonding *bond, block_netpoll_tx(); /* check to see if we are clearing active */ if (!slave_dev) { - netdev_info(bond->dev, "Clearing current active slave\n"); + netdev_dbg(bond->dev, "Clearing current active slave\n"); RCU_INIT_POINTER(bond->curr_active_slave, NULL); bond_select_active_slave(bond); } else { @@ -805,13 +805,13 @@ static int bond_option_active_slave_set(struct bonding *bond, if (new_active == old_active) { /* do nothing */ - netdev_info(bond->dev, "%s is already the current active slave\n", - new_active->dev->name); + netdev_dbg(bond->dev, "%s is already the current active slave\n", + new_active->dev->name); } else { if (old_active && (new_active->link == BOND_LINK_UP) && bond_slave_is_up(new_active)) { - netdev_info(bond->dev, "Setting %s as active slave\n", - new_active->dev->name); + netdev_dbg(bond->dev, "Setting %s as active slave\n", + new_active->dev->name); bond_change_active_slave(bond, new_active); } else { netdev_err(bond->dev, "Could not set %s as active slave; either %s is down or the link is down\n", @@ -833,17 +833,17 @@ static int bond_option_active_slave_set(struct bonding *bond, static int bond_option_miimon_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting MII monitoring interval to %llu\n", - newval->value); + netdev_dbg(bond->dev, "Setting MII monitoring interval to %llu\n", + newval->value); bond->params.miimon = newval->value; if (bond->params.updelay) - netdev_info(bond->dev, "Note: Updating updelay (to %d) since it is a multiple of the miimon value\n", - bond->params.updelay * bond->params.miimon); + netdev_dbg(bond->dev, "Note: Updating updelay (to %d) since it is a multiple of the miimon value\n", + bond->params.updelay * bond->params.miimon); if (bond->params.downdelay) - netdev_info(bond->dev, "Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n", - bond->params.downdelay * bond->params.miimon); + netdev_dbg(bond->dev, "Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n", + bond->params.downdelay * bond->params.miimon); if (newval->value && bond->params.arp_interval) { - netdev_info(bond->dev, "MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n"); + netdev_dbg(bond->dev, "MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n"); bond->params.arp_interval = 0; if (bond->params.arp_validate) bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; @@ -885,8 +885,8 @@ static int bond_option_updelay_set(struct bonding *bond, bond->params.miimon); } bond->params.updelay = value / bond->params.miimon; - netdev_info(bond->dev, "Setting up delay to %d\n", - bond->params.updelay * bond->params.miimon); + netdev_dbg(bond->dev, "Setting up delay to %d\n", + bond->params.updelay * bond->params.miimon); return 0; } @@ -907,8 +907,8 @@ static int bond_option_downdelay_set(struct bonding *bond, bond->params.miimon); } bond->params.downdelay = value / bond->params.miimon; - netdev_info(bond->dev, "Setting down delay to %d\n", - bond->params.downdelay * bond->params.miimon); + netdev_dbg(bond->dev, "Setting down delay to %d\n", + bond->params.downdelay * bond->params.miimon); return 0; } @@ -916,8 +916,8 @@ static int bond_option_downdelay_set(struct bonding *bond, static int bond_option_use_carrier_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting use_carrier to %llu\n", - newval->value); + netdev_dbg(bond->dev, "Setting use_carrier to %llu\n", + newval->value); bond->params.use_carrier = newval->value; return 0; @@ -930,16 +930,16 @@ static int bond_option_use_carrier_set(struct bonding *bond, static int bond_option_arp_interval_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting ARP monitoring interval to %llu\n", - newval->value); + netdev_dbg(bond->dev, "Setting ARP monitoring interval to %llu\n", + newval->value); bond->params.arp_interval = newval->value; if (newval->value) { if (bond->params.miimon) { - netdev_info(bond->dev, "ARP monitoring cannot be used with MII monitoring. Disabling MII monitoring\n"); + netdev_dbg(bond->dev, "ARP monitoring cannot be used with MII monitoring. Disabling MII monitoring\n"); bond->params.miimon = 0; } if (!bond->params.arp_targets[0]) - netdev_info(bond->dev, "ARP monitoring has been set up, but no ARP targets have been specified\n"); + netdev_dbg(bond->dev, "ARP monitoring has been set up, but no ARP targets have been specified\n"); } if (bond->dev->flags & IFF_UP) { /* If the interface is up, we may need to fire off @@ -1000,7 +1000,7 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) return -EINVAL; } - netdev_info(bond->dev, "Adding ARP target %pI4\n", &target); + netdev_dbg(bond->dev, "Adding ARP target %pI4\n", &target); _bond_options_arp_ip_target_set(bond, ind, target, jiffies); @@ -1036,7 +1036,7 @@ static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) if (ind == 0 && !targets[1] && bond->params.arp_interval) netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n"); - netdev_info(bond->dev, "Removing ARP target %pI4\n", &target); + netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target); bond_for_each_slave(bond, slave, iter) { targets_rx = slave->target_last_arp_rx; @@ -1088,8 +1088,8 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond, static int bond_option_arp_validate_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting arp_validate to %s (%llu)\n", - newval->string, newval->value); + netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n", + newval->string, newval->value); if (bond->dev->flags & IFF_UP) { if (!newval->value) @@ -1105,8 +1105,8 @@ static int bond_option_arp_validate_set(struct bonding *bond, static int bond_option_arp_all_targets_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting arp_all_targets to %s (%llu)\n", - newval->string, newval->value); + netdev_dbg(bond->dev, "Setting arp_all_targets to %s (%llu)\n", + newval->string, newval->value); bond->params.arp_all_targets = newval->value; return 0; @@ -1126,7 +1126,7 @@ static int bond_option_primary_set(struct bonding *bond, *p = '\0'; /* check to see if we are clearing primary */ if (!strlen(primary)) { - netdev_info(bond->dev, "Setting primary slave to None\n"); + netdev_dbg(bond->dev, "Setting primary slave to None\n"); RCU_INIT_POINTER(bond->primary_slave, NULL); memset(bond->params.primary, 0, sizeof(bond->params.primary)); bond_select_active_slave(bond); @@ -1135,8 +1135,8 @@ static int bond_option_primary_set(struct bonding *bond, bond_for_each_slave(bond, slave, iter) { if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) { - netdev_info(bond->dev, "Setting %s as primary slave\n", - slave->dev->name); + netdev_dbg(bond->dev, "Setting %s as primary slave\n", + slave->dev->name); rcu_assign_pointer(bond->primary_slave, slave); strcpy(bond->params.primary, slave->dev->name); bond_select_active_slave(bond); @@ -1145,15 +1145,15 @@ static int bond_option_primary_set(struct bonding *bond, } if (rtnl_dereference(bond->primary_slave)) { - netdev_info(bond->dev, "Setting primary slave to None\n"); + netdev_dbg(bond->dev, "Setting primary slave to None\n"); RCU_INIT_POINTER(bond->primary_slave, NULL); bond_select_active_slave(bond); } strncpy(bond->params.primary, primary, IFNAMSIZ); bond->params.primary[IFNAMSIZ - 1] = 0; - netdev_info(bond->dev, "Recording %s as primary, but it has not been enslaved to %s yet\n", - primary, bond->dev->name); + netdev_dbg(bond->dev, "Recording %s as primary, but it has not been enslaved to %s yet\n", + primary, bond->dev->name); out: unblock_netpoll_tx(); @@ -1164,8 +1164,8 @@ out: static int bond_option_primary_reselect_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting primary_reselect to %s (%llu)\n", - newval->string, newval->value); + netdev_dbg(bond->dev, "Setting primary_reselect to %s (%llu)\n", + newval->string, newval->value); bond->params.primary_reselect = newval->value; block_netpoll_tx(); @@ -1178,8 +1178,8 @@ static int bond_option_primary_reselect_set(struct bonding *bond, static int bond_option_fail_over_mac_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting fail_over_mac to %s (%llu)\n", - newval->string, newval->value); + netdev_dbg(bond->dev, "Setting fail_over_mac to %s (%llu)\n", + newval->string, newval->value); bond->params.fail_over_mac = newval->value; return 0; @@ -1188,8 +1188,8 @@ static int bond_option_fail_over_mac_set(struct bonding *bond, static int bond_option_xmit_hash_policy_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting xmit hash policy to %s (%llu)\n", - newval->string, newval->value); + netdev_dbg(bond->dev, "Setting xmit hash policy to %s (%llu)\n", + newval->string, newval->value); bond->params.xmit_policy = newval->value; return 0; @@ -1198,8 +1198,8 @@ static int bond_option_xmit_hash_policy_set(struct bonding *bond, static int bond_option_resend_igmp_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting resend_igmp to %llu\n", - newval->value); + netdev_dbg(bond->dev, "Setting resend_igmp to %llu\n", + newval->value); bond->params.resend_igmp = newval->value; return 0; @@ -1237,8 +1237,8 @@ static int bond_option_all_slaves_active_set(struct bonding *bond, static int bond_option_min_links_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting min links value to %llu\n", - newval->value); + netdev_dbg(bond->dev, "Setting min links value to %llu\n", + newval->value); bond->params.min_links = newval->value; bond_set_carrier(bond); @@ -1256,6 +1256,8 @@ static int bond_option_lp_interval_set(struct bonding *bond, static int bond_option_pps_set(struct bonding *bond, const struct bond_opt_value *newval) { + netdev_dbg(bond->dev, "Setting packets per slave to %llu\n", + newval->value); bond->params.packets_per_slave = newval->value; if (newval->value > 0) { bond->params.reciprocal_packets_per_slave = @@ -1274,8 +1276,8 @@ static int bond_option_pps_set(struct bonding *bond, static int bond_option_lacp_rate_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting LACP rate to %s (%llu)\n", - newval->string, newval->value); + netdev_dbg(bond->dev, "Setting LACP rate to %s (%llu)\n", + newval->string, newval->value); bond->params.lacp_fast = newval->value; bond_3ad_update_lacp_rate(bond); @@ -1285,8 +1287,8 @@ static int bond_option_lacp_rate_set(struct bonding *bond, static int bond_option_ad_select_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting ad_select to %s (%llu)\n", - newval->string, newval->value); + netdev_dbg(bond->dev, "Setting ad_select to %s (%llu)\n", + newval->string, newval->value); bond->params.ad_select = newval->value; return 0; @@ -1347,7 +1349,7 @@ out: return ret; err_no_cmd: - netdev_info(bond->dev, "invalid input for queue_id set\n"); + netdev_dbg(bond->dev, "invalid input for queue_id set\n"); ret = -EPERM; goto out; @@ -1369,20 +1371,20 @@ static int bond_option_slaves_set(struct bonding *bond, dev = __dev_get_by_name(dev_net(bond->dev), ifname); if (!dev) { - netdev_info(bond->dev, "interface %s does not exist!\n", - ifname); + netdev_dbg(bond->dev, "interface %s does not exist!\n", + ifname); ret = -ENODEV; goto out; } switch (command[0]) { case '+': - netdev_info(bond->dev, "Adding slave %s\n", dev->name); + netdev_dbg(bond->dev, "Adding slave %s\n", dev->name); ret = bond_enslave(bond->dev, dev); break; case '-': - netdev_info(bond->dev, "Removing slave %s\n", dev->name); + netdev_dbg(bond->dev, "Removing slave %s\n", dev->name); ret = bond_release(bond->dev, dev); break; @@ -1402,8 +1404,8 @@ err_no_cmd: static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting dynamic-lb to %s (%llu)\n", - newval->string, newval->value); + netdev_dbg(bond->dev, "Setting dynamic-lb to %s (%llu)\n", + newval->string, newval->value); bond->params.tlb_dynamic_lb = newval->value; return 0; @@ -1412,8 +1414,8 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting ad_actor_sys_prio to %llu\n", - newval->value); + netdev_dbg(bond->dev, "Setting ad_actor_sys_prio to %llu\n", + newval->value); bond->params.ad_actor_sys_prio = newval->value; bond_3ad_update_ad_actor_settings(bond); @@ -1442,7 +1444,7 @@ static int bond_option_ad_actor_system_set(struct bonding *bond, if (!is_valid_ether_addr(mac)) goto err; - netdev_info(bond->dev, "Setting ad_actor_system to %pM\n", mac); + netdev_dbg(bond->dev, "Setting ad_actor_system to %pM\n", mac); ether_addr_copy(bond->params.ad_actor_system, mac); bond_3ad_update_ad_actor_settings(bond); @@ -1456,8 +1458,8 @@ err: static int bond_option_ad_user_port_key_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting ad_user_port_key to %llu\n", - newval->value); + netdev_dbg(bond->dev, "Setting ad_user_port_key to %llu\n", + newval->value); bond->params.ad_user_port_key = newval->value; return 0; -- cgit v1.2.3 From 1c2fa5f846832cbed8b8e6151471436071972e41 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Tue, 27 Jun 2017 11:28:01 +0200 Subject: net: stmmac: support future possible different internal phy mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current way to find if the phy is internal is to compare DT phy-mode and emac_variant/internal_phy. But it will negate a possible future SoC where an external PHY use the same phy mode than the internal one. By using phy-mode = "internal" we permit to have an external PHY with the same mode than the internal one. Reported-by: André Przywara Signed-off-by: Corentin Labbe Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index fffd6d5fc907..6c2d1da05588 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -638,7 +638,7 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) { struct sunxi_priv_data *gmac = priv->plat->bsp_priv; struct device_node *node = priv->device->of_node; - int ret; + int ret, phy_interface; u32 reg, val; regmap_read(gmac->regmap, SYSCON_EMAC_REG, &val); @@ -718,7 +718,11 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) if (gmac->variant->support_rmii) reg &= ~SYSCON_RMII_EN; - switch (priv->plat->interface) { + phy_interface = priv->plat->interface; + /* if PHY is internal, select the mode (xMII) used by the SoC */ + if (gmac->use_internal_phy) + phy_interface = gmac->variant->internal_phy; + switch (phy_interface) { case PHY_INTERFACE_MODE_MII: /* default */ break; @@ -932,7 +936,7 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) } plat_dat->interface = of_get_phy_mode(dev->of_node); - if (plat_dat->interface == gmac->variant->internal_phy) { + if (plat_dat->interface == PHY_INTERFACE_MODE_INTERNAL) { dev_info(&pdev->dev, "Will use internal PHY\n"); gmac->use_internal_phy = true; gmac->ephy_clk = of_clk_get(plat_dat->phy_node, 0); -- cgit v1.2.3 From 62d4fd4733002c17da7c467dd3bd1065ebca9833 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Jun 2017 10:51:22 +0100 Subject: net: atl1c: fix spelling mistake: "droppted" -> "dropped" Trivial fix to spelling mistake in netif_info message Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 7e913d8331c3..8c9986f3fc01 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -2252,7 +2252,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, if (atl1c_tx_map(adapter, skb, tpd, type) < 0) { netif_info(adapter, tx_done, adapter->netdev, - "tx-skb droppted due to dma error\n"); + "tx-skb dropped due to dma error\n"); /* roll back tpd/buffer */ atl1c_tx_rollback(adapter, tpd, type); dev_kfree_skb_any(skb); -- cgit v1.2.3 From 46ccf725bff81693aff8f02b588a2c68566a0b92 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Jun 2017 11:36:49 +0100 Subject: net/mlx4: fix spelling mistake: "enforcment" -> "enforcement" Trivial fix to spelling mistake in mlx4_dbg debug message Signed-off-by: Colin Ian King Acked-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index c1af47e45d3f..674773b28b2e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -3280,7 +3280,7 @@ int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_stat if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port)) mlx4_dbg(dev, - "updating vf %d port %d no link state HW enforcment\n", + "updating vf %d port %d no link state HW enforcement\n", vf, port); return 0; } -- cgit v1.2.3 From bf24e136a32eb513195b6e0148e5a70131a95494 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 27 Jun 2017 03:56:54 -0700 Subject: cavium: thunder: Remove duplicate "netdev->name" logging output Using netdev_(netdev, "%s: ...", netdev->name) duplicates the name in the output. Remove those uses. Miscellanea: o Use the netif_ convenience macros at the same time Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/nicvf_main.c | 33 ++++++++-------------- drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 8 ++---- 2 files changed, 15 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 573755b0a51b..49b80da51ba7 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -227,15 +227,14 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) nic->speed = mbx.link_status.speed; nic->mac_type = mbx.link_status.mac_type; if (nic->link_up) { - netdev_info(nic->netdev, "%s: Link is Up %d Mbps %s\n", - nic->netdev->name, nic->speed, + netdev_info(nic->netdev, "Link is Up %d Mbps %s duplex\n", + nic->speed, nic->duplex == DUPLEX_FULL ? - "Full duplex" : "Half duplex"); + "Full" : "Half"); netif_carrier_on(nic->netdev); netif_tx_start_all_queues(nic->netdev); } else { - netdev_info(nic->netdev, "%s: Link is Down\n", - nic->netdev->name); + netdev_info(nic->netdev, "Link is Down\n"); netif_carrier_off(nic->netdev); netif_tx_stop_all_queues(nic->netdev); } @@ -721,8 +720,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, return; if (netif_msg_pktdata(nic)) { - netdev_info(nic->netdev, "%s: skb 0x%p, len=%d\n", netdev->name, - skb, skb->len); + netdev_info(nic->netdev, "skb 0x%p, len=%d\n", skb, skb->len); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb->len, true); } @@ -854,10 +852,8 @@ done: netif_tx_wake_queue(txq); nic = nic->pnicvf; this_cpu_inc(nic->drv_stats->txq_wake); - if (netif_msg_tx_err(nic)) - netdev_warn(netdev, - "%s: Transmit queue wakeup SQ%d\n", - netdev->name, txq_idx); + netif_warn(nic, tx_err, netdev, + "Transmit queue wakeup SQ%d\n", txq_idx); } } @@ -928,9 +924,8 @@ static void nicvf_handle_qs_err(unsigned long data) static void nicvf_dump_intr_status(struct nicvf *nic) { - if (netif_msg_intr(nic)) - netdev_info(nic->netdev, "%s: interrupt status 0x%llx\n", - nic->netdev->name, nicvf_reg_read(nic, NIC_VF_INT)); + netif_info(nic, intr, nic->netdev, "interrupt status 0x%llx\n", + nicvf_reg_read(nic, NIC_VF_INT)); } static irqreturn_t nicvf_misc_intr_handler(int irq, void *nicvf_irq) @@ -1212,10 +1207,8 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev) netif_tx_wake_queue(txq); } else { this_cpu_inc(nic->drv_stats->txq_stop); - if (netif_msg_tx_err(nic)) - netdev_warn(netdev, - "%s: Transmit ring full, stopping SQ%d\n", - netdev->name, qid); + netif_warn(nic, tx_err, netdev, + "Transmit ring full, stopping SQ%d\n", qid); } return NETDEV_TX_BUSY; } @@ -1600,9 +1593,7 @@ static void nicvf_tx_timeout(struct net_device *dev) { struct nicvf *nic = netdev_priv(dev); - if (netif_msg_tx_err(nic)) - netdev_warn(dev, "%s: Transmit timed out, resetting\n", - dev->name); + netif_warn(nic, tx_err, dev, "Transmit timed out, resetting\n"); this_cpu_inc(nic->drv_stats->tx_timeout); schedule_work(&nic->reset_task); diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index 2b181762ad49..d4496e9afcdf 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -1811,11 +1811,9 @@ void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx) /* Check for errors in the receive cmp.queue entry */ int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx) { - if (netif_msg_rx_err(nic)) - netdev_err(nic->netdev, - "%s: RX error CQE err_level 0x%x err_opcode 0x%x\n", - nic->netdev->name, - cqe_rx->err_level, cqe_rx->err_opcode); + netif_err(nic, rx_err, nic->netdev, + "RX error CQE err_level 0x%x err_opcode 0x%x\n", + cqe_rx->err_level, cqe_rx->err_opcode); switch (cqe_rx->err_opcode) { case CQ_RX_ERROP_RE_PARTIAL: -- cgit v1.2.3 From 98fdd857a3bd6a3bf0003d3f68f07c25c85dcde3 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 27 Jun 2017 16:58:51 +0300 Subject: net: ethernet: ti: cpsw: move skb timestamp to packet_submit Move sw timestamp function close to channel submit function. Signed-off-by: Ivan Khoronzhuk Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index b7a0f5eeab62..422994ea0b49 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1236,6 +1236,7 @@ static inline int cpsw_tx_packet_submit(struct cpsw_priv *priv, { struct cpsw_common *cpsw = priv->cpsw; + skb_tx_timestamp(skb); return cpdma_chan_submit(txch, skb, skb->data, skb->len, priv->emac_port + cpsw->data.dual_emac); } @@ -1611,8 +1612,6 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, cpts_is_tx_enabled(cpsw->cpts)) skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - skb_tx_timestamp(skb); - q_idx = skb_get_queue_mapping(skb); if (q_idx >= cpsw->tx_ch_num) q_idx = q_idx % cpsw->tx_ch_num; -- cgit v1.2.3 From f44f8417baef9dcd8533a706691dadbda219ef82 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 27 Jun 2017 16:58:52 +0300 Subject: net: ethernet: ti: cpsw: fix sw timestamping for non PTP packets The cpts can timestmap only ptp packets at this moment, so driver cannot mark every packet as though it's going to be timestamped, only because h/w timestamping for given skb is enabled with SKBTX_HW_TSTAMP. It doesn't allow to use sw timestamping, as result outgoing packet is not timestamped at all if it's not PTP and h/w timestamping is enabled. So, fix it by setting SKBTX_IN_PROGRESS only for PTP packets. Signed-off-by: Ivan Khoronzhuk Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 3 ++- drivers/net/ethernet/ti/cpts.h | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 422994ea0b49..1850e348f555 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1598,6 +1598,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; + struct cpts *cpts = cpsw->cpts; struct netdev_queue *txq; struct cpdma_chan *txch; int ret, q_idx; @@ -1609,7 +1610,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, } if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && - cpts_is_tx_enabled(cpsw->cpts)) + cpts_is_tx_enabled(cpts) && cpts_can_timestamp(cpts, skb)) skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; q_idx = skb_get_queue_mapping(skb); diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h index c96eca2b1b46..01ea82ba9cdc 100644 --- a/drivers/net/ethernet/ti/cpts.h +++ b/drivers/net/ethernet/ti/cpts.h @@ -30,6 +30,7 @@ #include #include #include +#include #include struct cpsw_cpts { @@ -155,6 +156,16 @@ static inline bool cpts_is_tx_enabled(struct cpts *cpts) return !!cpts->tx_enable; } +static inline bool cpts_can_timestamp(struct cpts *cpts, struct sk_buff *skb) +{ + unsigned int class = ptp_classify_raw(skb); + + if (class == PTP_CLASS_NONE) + return false; + + return true; +} + #else struct cpts; @@ -203,6 +214,11 @@ static inline bool cpts_is_tx_enabled(struct cpts *cpts) { return false; } + +static inline bool cpts_can_timestamp(struct cpts *cpts, struct sk_buff *skb) +{ + return false; +} #endif -- cgit v1.2.3 From 0ccf59ba07377201f3d4347b7c6443f60bd9af93 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 27 Jun 2017 16:58:53 +0300 Subject: net: ethernet: ti: netcp_ethss: use cpts to check if packet needs timestamping There is cpts function to check if packet can be timstamped with cpts. Seems that ptp_classify_raw cover all cases listed with "case". Signed-off-by: Ivan Khoronzhuk Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 0847a8f48cfe..28cb38af1a34 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -2503,24 +2503,8 @@ static bool gbe_need_txtstamp(struct gbe_intf *gbe_intf, const struct netcp_packet *p_info) { struct sk_buff *skb = p_info->skb; - unsigned int class = ptp_classify_raw(skb); - if (class == PTP_CLASS_NONE) - return false; - - switch (class) { - case PTP_CLASS_V1_IPV4: - case PTP_CLASS_V1_IPV6: - case PTP_CLASS_V2_IPV4: - case PTP_CLASS_V2_IPV6: - case PTP_CLASS_V2_L2: - case (PTP_CLASS_V2_VLAN | PTP_CLASS_L2): - case (PTP_CLASS_V2_VLAN | PTP_CLASS_IPV4): - case (PTP_CLASS_V2_VLAN | PTP_CLASS_IPV6): - return true; - } - - return false; + return cpts_can_timestamp(gbe_intf->gbe_dev->cpts, skb); } static int gbe_txtstamp_mark_pkt(struct gbe_intf *gbe_intf, -- cgit v1.2.3 From 77b0d3617738e532bae683bf9d88ea35fff223e5 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 27 Jun 2017 17:16:27 -0500 Subject: net: stmmac: Add additional registers for dwmac1000_dma ethtool Version 3.70a of the Designware has additional DMA registers so add those to the ethtool DMA Register dump. Offset 9 - Receive Interrupt Watchdog Timer Register Offset 10 - AXI Bus Mode Register Offset 11 - AHB or AXI Status Register Offset 22 - HW Feature Register Signed-off-by: Thor Thayer Acked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 4 ++-- drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c index 471a9aa6ac94..22cf6353ba04 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c @@ -205,8 +205,8 @@ static void dwmac1000_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space) { int i; - for (i = 0; i < 22; i++) - if ((i < 9) || (i > 17)) + for (i = 0; i < 23; i++) + if ((i < 12) || (i > 17)) reg_space[DMA_BUS_MODE / 4 + i] = readl(ioaddr + DMA_BUS_MODE + i * 4); } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 743170d57f62..babb39c646ff 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -29,7 +29,7 @@ #include "stmmac.h" #include "dwmac_dma.h" -#define REG_SPACE_SIZE 0x1054 +#define REG_SPACE_SIZE 0x1060 #define MAC100_ETHTOOL_NAME "st_mac100" #define GMAC_ETHTOOL_NAME "st_gmac" -- cgit v1.2.3 From c42ff65da8167fa486bfcb7ea290cbdee8350aa7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Jun 2017 21:19:47 +0200 Subject: iwlwifi: pcie: add MSI-X interrupt tracing We have tracing for both pre-ICT and ICT interrupts, including all the data read there. Extend the tracing to MSI-X interrupts. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/iwl-devtrace-io.h | 26 +++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 4 ++++ 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h index 1dccae6532cf..4164dc1745ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h @@ -1,7 +1,7 @@ /****************************************************************************** * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016-2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -29,6 +29,7 @@ #define __IWLWIFI_DEVICE_TRACE_IO #include +#include #undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi_io @@ -165,6 +166,29 @@ TRACE_EVENT(iwlwifi_dev_irq, TP_printk("%d", 0) ); +TRACE_EVENT(iwlwifi_dev_irq_msix, + TP_PROTO(const struct device *dev, struct msix_entry *msix_entry, + bool defirq, u32 inta_fh, u32 inta_hw), + TP_ARGS(dev, msix_entry, defirq, inta_fh, inta_hw), + TP_STRUCT__entry( + DEV_ENTRY + __field(u32, entry) + __field(u8, defirq) + __field(u32, inta_fh) + __field(u32, inta_hw) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->entry = msix_entry->entry; + __entry->defirq = defirq; + __entry->inta_fh = inta_fh; + __entry->inta_hw = inta_hw; + ), + TP_printk("entry:%d defirq:%d fh:0x%x, hw:0x%x", + __entry->entry, __entry->defirq, + __entry->inta_fh, __entry->inta_hw) +); + TRACE_EVENT(iwlwifi_dev_ict_read, TP_PROTO(const struct device *dev, u32 index, u32 value), TP_ARGS(dev, index, value), diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 1618a59a8a2f..351c4423125a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1391,6 +1391,8 @@ irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id) struct iwl_trans_pcie *trans_pcie = iwl_pcie_get_trans_pcie(entry); struct iwl_trans *trans = trans_pcie->trans; + trace_iwlwifi_dev_irq_msix(trans->dev, entry, false, 0, 0); + if (WARN_ON(entry->entry >= trans->num_rx_queues)) return IRQ_NONE; @@ -1932,6 +1934,8 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) iwl_write32(trans, CSR_MSIX_HW_INT_CAUSES_AD, inta_hw); spin_unlock(&trans_pcie->irq_lock); + trace_iwlwifi_dev_irq_msix(trans->dev, entry, true, inta_fh, inta_hw); + if (unlikely(!(inta_fh | inta_hw))) { IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); lock_map_release(&trans->sync_cmd_lockdep_map); -- cgit v1.2.3 From 275896ab5fbffcbe9d148ec054efe1af3fb4a29d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2017 13:24:49 +0200 Subject: iwlwifi: mvm: properly enable IP header checksumming The code was intended to enable IP header checksumming on AMSDUs, but failed to really do so because the A-MSDU bit was set after all the checksumming bits, and thus checking for A-MSDU could never be true. Fix this by setting the A-MSDU bit before the offload bits. Fixes: 5e6a98dc4863 ("iwlwifi: mvm: enable TCP/UDP checksum support for 9000 family") Reported-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 214829e5a860..419d0351e0ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -105,9 +105,9 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr, static u16 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_hdr *hdr, - struct ieee80211_tx_info *info) + struct ieee80211_tx_info *info, + u16 offload_assist) { - u16 offload_assist = 0; #if IS_ENABLED(CONFIG_INET) u16 mh_len = ieee80211_hdrlen(hdr->frame_control); u8 protocol = 0; @@ -207,6 +207,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, __le16 fc = hdr->frame_control; u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); u32 len = skb->len + FCS_LEN; + u16 offload_assist = 0; u8 ac; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -225,8 +226,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL; if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) - tx_cmd->offload_assist |= - cpu_to_le16(BIT(TX_CMD_OFFLD_AMSDU)); + offload_assist |= BIT(TX_CMD_OFFLD_AMSDU); } else if (ieee80211_is_back_req(fc)) { struct ieee80211_bar *bar = (void *)skb->data; u16 control = le16_to_cpu(bar->control); @@ -291,11 +291,12 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, /* padding is inserted later in transport */ if (ieee80211_hdrlen(fc) % 4 && - !(tx_cmd->offload_assist & cpu_to_le16(BIT(TX_CMD_OFFLD_AMSDU)))) - tx_cmd->offload_assist |= cpu_to_le16(BIT(TX_CMD_OFFLD_PAD)); + !(offload_assist & BIT(TX_CMD_OFFLD_AMSDU))) + offload_assist |= BIT(TX_CMD_OFFLD_PAD); tx_cmd->offload_assist |= - cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, hdr, info)); + cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, hdr, info, + offload_assist)); } static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, @@ -481,7 +482,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, if (iwl_mvm_has_new_tx_api(mvm)) { struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload; - u16 offload_assist = iwl_mvm_tx_csum(mvm, skb, hdr, info); + u16 offload_assist = 0; if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *qc = ieee80211_get_qos_ctl(hdr); @@ -490,6 +491,9 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, offload_assist |= BIT(TX_CMD_OFFLD_AMSDU); } + offload_assist = iwl_mvm_tx_csum(mvm, skb, hdr, info, + offload_assist); + /* padding is inserted later in transport */ if (ieee80211_hdrlen(hdr->frame_control) % 4 && !(offload_assist & BIT(TX_CMD_OFFLD_AMSDU))) -- cgit v1.2.3 From 37e474acc9b6f645d92d8dc35014ff1baed3b1bc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2017 22:31:56 +0200 Subject: iwlwifi: mvm: fix mac80211 queue tracking In the driver, we track which hardware queue is associated with which mac80211 "hw_queue", in order to be able to stop and wake it. When moving these bitmaps out of the queue_info structures, the type of the bitmap was erroneously changed from u32 to u8, presumably in order to save memory. Turns out that u32 isn't needed, because the highest queue we can ever tell mac80211 is always < 16, but a u16 definitely is needed, queues >=8 do happen. While at it, throw a BUILD_BUG_ON() into the place where we set the limit (mvm->first_agg_queue) and a warning when it actually gets put into the bitmap. The consequence of this bug is that full HW queues associated with such a too-high mac80211 number never stop higher layer queues when full, and thus would simply drop all packets that couldn't be enqueued to the hardware queue. Fixes: 34e10860ae8d ("iwlwifi: mvm: remove references to queue_info in new TX path") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 ++++ drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 8 +++++++- 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 0f0cd6c9ce8b..6b8f7817391d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -789,7 +789,7 @@ struct iwl_mvm { u64 on_time_scan; } radio_stats, accu_radio_stats; - u8 hw_queue_to_mac80211[IWL_MAX_TVQM_QUEUES]; + u16 hw_queue_to_mac80211[IWL_MAX_TVQM_QUEUES]; struct { u8 hw_queue_refcount; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 32233cba6786..1799a3d367f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -602,9 +602,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (mvm->cfg->base_params->num_of_queues == 16) { mvm->aux_queue = 11; mvm->first_agg_queue = 12; + BUILD_BUG_ON(BITS_PER_BYTE * + sizeof(mvm->hw_queue_to_mac80211[0]) < 12); } else { mvm->aux_queue = 15; mvm->first_agg_queue = 16; + BUILD_BUG_ON(BITS_PER_BYTE * + sizeof(mvm->hw_queue_to_mac80211[0]) < 16); } } else { mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 0093e78dd571..bd2596fdafda 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -698,7 +698,13 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, if (mvm->queue_info[queue].hw_queue_refcount > 0) enable_queue = false; - mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); + if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) { + WARN(mac80211_queue >= + BITS_PER_BYTE * sizeof(mvm->hw_queue_to_mac80211[0]), + "cannot track mac80211 queue %d (queue %d, sta %d, tid %d)\n", + mac80211_queue, queue, sta_id, tid); + mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); + } mvm->queue_info[queue].hw_queue_refcount++; mvm->queue_info[queue].tid_bitmap |= BIT(tid); -- cgit v1.2.3 From b0129db4f0669eb5d7c79031ac54e746f470e45a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2017 22:48:32 +0200 Subject: iwlwifi: mvm: map cab_queue to real one earlier There may be a difference between the mac80211 vif->cab_queue and mvmvif->cab_queue, particularly with TVQM. Make the code map this earlier, instead of first returning the mac80211 one again from iwl_mvm_get_ctrl_vif_queue(). Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 419d0351e0ef..12a35af66918 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -551,9 +551,13 @@ static void iwl_mvm_skb_prepare_status(struct sk_buff *skb, static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, struct ieee80211_tx_info *info, __le16 fc) { + struct iwl_mvm_vif *mvmvif; + if (!iwl_mvm_is_dqa_supported(mvm)) return info->hw_queue; + mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); + switch (info->control.vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: @@ -569,7 +573,7 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, ieee80211_is_deauth(fc) || ieee80211_is_assoc_resp(fc)) return mvm->probe_queue; if (info->hw_queue == info->control.vif->cab_queue) - return info->hw_queue; + return mvmvif->cab_queue; WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC, "fc=0x%02x", le16_to_cpu(fc)); @@ -578,7 +582,7 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, if (ieee80211_is_mgmt(fc)) return mvm->p2p_dev_queue; if (info->hw_queue == info->control.vif->cab_queue) - return info->hw_queue; + return mvmvif->cab_queue; WARN_ON_ONCE(1); return mvm->p2p_dev_queue; @@ -645,9 +649,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) hdr->frame_control); if (queue < 0) return -1; - - if (queue == info.control.vif->cab_queue) - queue = mvmvif->cab_queue; } else if (info.control.vif->type == NL80211_IFTYPE_STATION && is_multicast_ether_addr(hdr->addr1)) { u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id); -- cgit v1.2.3 From 32026e8f709ff29bd00cce58036da8381eaa7592 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2017 23:26:55 +0200 Subject: iwlwifi: mvm: fix mac80211's hw_queue in DQA mode When in non-DQA mode, mac80211 actually gets a pretty much perfect idea (in vif->hw_queue/cab_queue) of which queues we're using. But in DQA mode, this isn't true - nonetheless, we were adding all the queues, even the ones stations are using, to the queue allocation bitmap. Fix this, we should only add the queues we really are using in DQA mode: * IWL_MVM_OFFCHANNEL_QUEUE, as we use this in both modes * mvm->aux_queue, as we use this in both modes - mac80211 never really knows about it but we use it as a cookie internally, so can't reuse it * possibly the GCAST queue (cab_queue) * all the "queues" we told mac80211 about we were using on each interface (vif->hw_queue), these are entirely virtual in this mode Also add back the failure now when we can't allocate any more of these - now virtual - queues; this was skipped in DQA mode and would lead to having multiple ACs or even interfaces use the same queue number in mac80211 (10, since that's the limit), which would stop far too many queues if stopped. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 32 ++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 71f23ac608eb..dc631b23e189 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -257,7 +257,7 @@ unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, }; if (iwl_mvm_is_dqa_supported(mvm)) - data.used_hw_queues |= BIT(IWL_MVM_DQA_CMD_QUEUE); + data.used_hw_queues |= BIT(IWL_MVM_DQA_GCAST_QUEUE); else data.used_hw_queues |= BIT(IWL_MVM_CMD_QUEUE); @@ -268,6 +268,14 @@ unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, iwl_mvm_iface_hw_queues_iter, &data); + /* + * for DQA, the hw_queue in mac80211 is never really used for + * real traffic (only the few queue IDs covered above), so + * we can reuse the real HW queue IDs the stations use + */ + if (iwl_mvm_is_dqa_supported(mvm)) + return data.used_hw_queues; + /* don't assign the same hw queues as TDLS stations */ ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_mac_sta_hw_queues_iter, @@ -344,7 +352,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, .found_vif = false, }; u32 ac; - int ret, i; + int ret, i, queue_limit; unsigned long used_hw_queues; /* @@ -430,17 +438,29 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, return 0; } + if (iwl_mvm_is_dqa_supported(mvm)) { + /* + * queues in mac80211 almost entirely independent of + * the ones here - no real limit + */ + queue_limit = IEEE80211_MAX_QUEUES; + BUILD_BUG_ON(IEEE80211_MAX_QUEUES > + BITS_PER_BYTE * + sizeof(mvm->hw_queue_to_mac80211[0])); + } else { + /* need to not use too many in this case */ + queue_limit = mvm->first_agg_queue; + } + /* * Find available queues, and allocate them to the ACs. When in * DQA-mode they aren't really used, and this is done only so the * mac80211 ieee80211_check_queues() function won't fail */ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - u8 queue = find_first_zero_bit(&used_hw_queues, - mvm->first_agg_queue); + u8 queue = find_first_zero_bit(&used_hw_queues, queue_limit); - if (!iwl_mvm_is_dqa_supported(mvm) && - queue >= mvm->first_agg_queue) { + if (queue >= queue_limit) { IWL_ERR(mvm, "Failed to allocate queue\n"); ret = -EIO; goto exit_fail; -- cgit v1.2.3 From 4f555e602b42826b3d79081c9ef8b8e8fe29fc49 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 20 Jun 2017 16:05:30 +0300 Subject: iwlwifi: mvm: don't send fetch the TID from a non-QoS packet in TSO Getting the TID of a packet before we know it is a QoS data packet isn't a good idea. Delay the TID retrieval until we know the packet is a QoS data packet. Fixes: bb81bb68f472 ("iwlwifi: mvm: add Tx A-MSDU inside A-MPDU") Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 12a35af66918..172f0aa8d019 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -715,11 +715,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + tcp_hdrlen(skb); - qc = ieee80211_get_qos_ctl(hdr); - tid = *qc & IEEE80211_QOS_CTL_TID_MASK; - if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) - return -EINVAL; - dbg_max_amsdu_len = ACCESS_ONCE(mvm->max_amsdu_len); if (!sta->max_amsdu_len || @@ -730,6 +725,11 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, goto segment; } + qc = ieee80211_get_qos_ctl(hdr); + tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) + return -EINVAL; + /* * Do not build AMSDU for IPv6 with extension headers. * ask stack to segment and checkum the generated MPDUs for us. -- cgit v1.2.3 From 52848a79b9d2d6773160221e7ea1e1500954de84 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2017 12:51:30 +0200 Subject: iwlwifi: pcie: reconfigure MSI-X HW on resume When going into suspend, the HW configuration for MSI-X will likely be lost. As a consequence, after waking up, all IRQ causes will be mapped to interrupt 0, and as a consequence we don't notice the interrupt because in most cases this is an interrupt for a queue, and getting it doesn't read the other cause registers. Fixes: 2e5d4a8f61dc ("iwlwifi: pcie: Add new configuration to enable MSIX") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 3ca0f374c081..f16c1bb9bf94 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -799,6 +799,9 @@ static int iwl_pci_resume(struct device *device) if (!trans->op_mode) return 0; + /* reconfigure the MSI-X mapping to get the correct IRQ for rfkill */ + iwl_pcie_conf_msix_hw(trans_pcie); + /* * Enable rfkill interrupt (in order to keep track of the rfkill * status). Must be locked to avoid processing a possible rfkill -- cgit v1.2.3 From 6344436e9d3f4fb4878c12169477d4beb5b825ea Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 21 Jun 2017 09:40:15 +0300 Subject: iwlwifi: mvm: don't mess the SNAP header in TSO for non-QoS packets When we get large sends on non-QoS association, we had a bug that mangled the SNAP header. Fix that. Fixes: a6d5e32f247c ("iwlwifi: mvm: send large SKBs to the transport") Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 172f0aa8d019..584ddc39d5f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -849,11 +849,13 @@ segment: if (tcp_payload_len > mss) { skb_shinfo(tmp)->gso_size = mss; } else { - qc = ieee80211_get_qos_ctl((void *)tmp->data); + if (ieee80211_is_data_qos(hdr->frame_control)) { + qc = ieee80211_get_qos_ctl((void *)tmp->data); - if (ipv4) - ip_send_check(ip_hdr(tmp)); - *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + if (ipv4) + ip_send_check(ip_hdr(tmp)); + *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + } skb_shinfo(tmp)->gso_size = 0; } -- cgit v1.2.3 From 6e46496302df7e63158fa1476cf9a30d5ee59dee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 22 Jun 2017 13:06:21 +0200 Subject: iwlwifi: mvm: remove DQA non-STA client mode special case When we get a non-STA frame to transmit in client mode, we try to use the IWL_MVM_DQA_BSS_CLIENT_QUEUE queue (queue #4). However, at this point, the queue might not be allocated at all, causing warnings. The scenario on which this happened was a race condition between mac80211 and our queue allocation work: * mac80211 sends auth * we stop mac80211 queues to allocate a hw queue * authentication is aborted * we allocate HW queue and start mac80211 queues * mac80211 removes station * mac80211 hands us the auth frame from the pending queue At this point, since mac80211 has already removed the station, we try to transmit the frame through this special non-station case on queue 4 anyway. In order to really use it properly, we'd have to again go through the hw queue allocation work, and attach it to a station, etc. In this case that isn't possible (there's no station anymore), but if this special case were needed, then we'd have to do it this way. However, the special case is documented to exist for TDLS, but can't trigger there because the TDLS setup frames etc. are normal to-DS frames going to the peer through the AP. Testing also confirms that this code path isn't triggered in TDLS. Therefore, remove the code path to avoid using an unused queue. The erroneous frame described above will still be transmitted on the AUX queue, but arguably that's a mac80211 problem, which will eventually be fixed by moving everything there to TXQs. Fixes: e3118ad74d7e ("iwlwifi: mvm: support tdls in dqa mode") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 584ddc39d5f7..73967790f7e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -631,10 +631,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) * (this is not possible for unicast packets as a TLDS discovery * response are sent without a station entry); otherwise use the * AUX station. - * In DQA mode, if vif is of type STATION and frames are not multicast - * or offchannel, they should be sent from the BSS queue. - * For example, TDLS setup frames should be sent on this queue, - * as they go through the AP. */ sta_id = mvm->aux_sta.sta_id; if (info.control.vif) { @@ -655,10 +651,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) if (ap_sta_id != IWL_MVM_INVALID_STA) sta_id = ap_sta_id; - } else if (iwl_mvm_is_dqa_supported(mvm) && - info.control.vif->type == NL80211_IFTYPE_STATION && - queue != mvm->aux_queue) { - queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE; } else if (iwl_mvm_is_dqa_supported(mvm) && info.control.vif->type == NL80211_IFTYPE_MONITOR) { queue = mvm->aux_queue; -- cgit v1.2.3 From 678d9b6dddea3869e78996a94ade8dc6d1b5fe68 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Thu, 18 May 2017 18:00:49 +0300 Subject: iwlwifi: mvm: update rx statistics cmd api The API has changed - update the code. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 4 + drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 235 +++++++++++++-------- .../net/wireless/intel/iwlwifi/mvm/fw-api-stats.h | 167 +++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 11 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 83 +++++--- 7 files changed, 371 insertions(+), 141 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index a216657b3c60..0fa8c473f1e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -245,10 +245,12 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * ADD_MODIFY_STA_KEY_API_S_VER_2. * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 + * @IWL_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used * * @NUM_IWL_UCODE_TLV_API: number of bits used */ enum iwl_ucode_tlv_api { + /* API Set 0 */ IWL_UCODE_TLV_API_FRAGMENTED_SCAN = (__force iwl_ucode_tlv_api_t)8, IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9, IWL_UCODE_TLV_API_LQ_SS_PARAMS = (__force iwl_ucode_tlv_api_t)18, @@ -257,6 +259,8 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_TKIP_MIC_KEYS = (__force iwl_ucode_tlv_api_t)29, IWL_UCODE_TLV_API_STA_TYPE = (__force iwl_ucode_tlv_api_t)30, IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31, + /* API Set 1 */ + IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35, NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 61a5e34140db..c1c9c489edc9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -668,15 +668,15 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, int pos = 0; char *buf; int ret; - /* 43 is the size of each data line, 33 is the size of each header */ - size_t bufsz = - ((sizeof(struct mvm_statistics_rx) / sizeof(__le32)) * 43) + - (4 * 33) + 1; + size_t bufsz; - struct mvm_statistics_rx_phy *ofdm; - struct mvm_statistics_rx_phy *cck; - struct mvm_statistics_rx_non_phy *general; - struct mvm_statistics_rx_ht_phy *ht; + if (iwl_mvm_has_new_rx_stats_api(mvm)) + bufsz = ((sizeof(struct mvm_statistics_rx) / + sizeof(__le32)) * 43) + (4 * 33) + 1; + else + /* 43 = size of each data line; 33 = size of each header */ + bufsz = ((sizeof(struct mvm_statistics_rx_v3) / + sizeof(__le32)) * 43) + (4 * 33) + 1; buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) @@ -684,96 +684,157 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, mutex_lock(&mvm->mutex); - ofdm = &mvm->rx_stats.ofdm; - cck = &mvm->rx_stats.cck; - general = &mvm->rx_stats.general; - ht = &mvm->rx_stats.ofdm_ht; - pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - OFDM"); - PRINT_STATS_LE32(ofdm, ina_cnt); - PRINT_STATS_LE32(ofdm, fina_cnt); - PRINT_STATS_LE32(ofdm, plcp_err); - PRINT_STATS_LE32(ofdm, crc32_err); - PRINT_STATS_LE32(ofdm, overrun_err); - PRINT_STATS_LE32(ofdm, early_overrun_err); - PRINT_STATS_LE32(ofdm, crc32_good); - PRINT_STATS_LE32(ofdm, false_alarm_cnt); - PRINT_STATS_LE32(ofdm, fina_sync_err_cnt); - PRINT_STATS_LE32(ofdm, sfd_timeout); - PRINT_STATS_LE32(ofdm, fina_timeout); - PRINT_STATS_LE32(ofdm, unresponded_rts); - PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun); - PRINT_STATS_LE32(ofdm, sent_ack_cnt); - PRINT_STATS_LE32(ofdm, sent_cts_cnt); - PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt); - PRINT_STATS_LE32(ofdm, dsp_self_kill); - PRINT_STATS_LE32(ofdm, mh_format_err); - PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum); - PRINT_STATS_LE32(ofdm, reserved); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct mvm_statistics_rx_phy_v2 *ofdm = &mvm->rx_stats_v3.ofdm; + + PRINT_STATS_LE32(ofdm, ina_cnt); + PRINT_STATS_LE32(ofdm, fina_cnt); + PRINT_STATS_LE32(ofdm, plcp_err); + PRINT_STATS_LE32(ofdm, crc32_err); + PRINT_STATS_LE32(ofdm, overrun_err); + PRINT_STATS_LE32(ofdm, early_overrun_err); + PRINT_STATS_LE32(ofdm, crc32_good); + PRINT_STATS_LE32(ofdm, false_alarm_cnt); + PRINT_STATS_LE32(ofdm, fina_sync_err_cnt); + PRINT_STATS_LE32(ofdm, sfd_timeout); + PRINT_STATS_LE32(ofdm, fina_timeout); + PRINT_STATS_LE32(ofdm, unresponded_rts); + PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(ofdm, sent_ack_cnt); + PRINT_STATS_LE32(ofdm, sent_cts_cnt); + PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt); + PRINT_STATS_LE32(ofdm, dsp_self_kill); + PRINT_STATS_LE32(ofdm, mh_format_err); + PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum); + PRINT_STATS_LE32(ofdm, reserved); + } else { + struct mvm_statistics_rx_phy *ofdm = &mvm->rx_stats.ofdm; + + PRINT_STATS_LE32(ofdm, unresponded_rts); + PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt); + PRINT_STATS_LE32(ofdm, dsp_self_kill); + PRINT_STATS_LE32(ofdm, reserved); + } pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - CCK"); - PRINT_STATS_LE32(cck, ina_cnt); - PRINT_STATS_LE32(cck, fina_cnt); - PRINT_STATS_LE32(cck, plcp_err); - PRINT_STATS_LE32(cck, crc32_err); - PRINT_STATS_LE32(cck, overrun_err); - PRINT_STATS_LE32(cck, early_overrun_err); - PRINT_STATS_LE32(cck, crc32_good); - PRINT_STATS_LE32(cck, false_alarm_cnt); - PRINT_STATS_LE32(cck, fina_sync_err_cnt); - PRINT_STATS_LE32(cck, sfd_timeout); - PRINT_STATS_LE32(cck, fina_timeout); - PRINT_STATS_LE32(cck, unresponded_rts); - PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun); - PRINT_STATS_LE32(cck, sent_ack_cnt); - PRINT_STATS_LE32(cck, sent_cts_cnt); - PRINT_STATS_LE32(cck, sent_ba_rsp_cnt); - PRINT_STATS_LE32(cck, dsp_self_kill); - PRINT_STATS_LE32(cck, mh_format_err); - PRINT_STATS_LE32(cck, re_acq_main_rssi_sum); - PRINT_STATS_LE32(cck, reserved); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct mvm_statistics_rx_phy_v2 *cck = &mvm->rx_stats_v3.cck; + + PRINT_STATS_LE32(cck, ina_cnt); + PRINT_STATS_LE32(cck, fina_cnt); + PRINT_STATS_LE32(cck, plcp_err); + PRINT_STATS_LE32(cck, crc32_err); + PRINT_STATS_LE32(cck, overrun_err); + PRINT_STATS_LE32(cck, early_overrun_err); + PRINT_STATS_LE32(cck, crc32_good); + PRINT_STATS_LE32(cck, false_alarm_cnt); + PRINT_STATS_LE32(cck, fina_sync_err_cnt); + PRINT_STATS_LE32(cck, sfd_timeout); + PRINT_STATS_LE32(cck, fina_timeout); + PRINT_STATS_LE32(cck, unresponded_rts); + PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(cck, sent_ack_cnt); + PRINT_STATS_LE32(cck, sent_cts_cnt); + PRINT_STATS_LE32(cck, sent_ba_rsp_cnt); + PRINT_STATS_LE32(cck, dsp_self_kill); + PRINT_STATS_LE32(cck, mh_format_err); + PRINT_STATS_LE32(cck, re_acq_main_rssi_sum); + PRINT_STATS_LE32(cck, reserved); + } else { + struct mvm_statistics_rx_phy *cck = &mvm->rx_stats.cck; + + PRINT_STATS_LE32(cck, unresponded_rts); + PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(cck, sent_ba_rsp_cnt); + PRINT_STATS_LE32(cck, dsp_self_kill); + PRINT_STATS_LE32(cck, reserved); + } pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - GENERAL"); - PRINT_STATS_LE32(general, bogus_cts); - PRINT_STATS_LE32(general, bogus_ack); - PRINT_STATS_LE32(general, non_bssid_frames); - PRINT_STATS_LE32(general, filtered_frames); - PRINT_STATS_LE32(general, non_channel_beacons); - PRINT_STATS_LE32(general, channel_beacons); - PRINT_STATS_LE32(general, num_missed_bcon); - PRINT_STATS_LE32(general, adc_rx_saturation_time); - PRINT_STATS_LE32(general, ina_detection_search_time); - PRINT_STATS_LE32(general, beacon_silence_rssi_a); - PRINT_STATS_LE32(general, beacon_silence_rssi_b); - PRINT_STATS_LE32(general, beacon_silence_rssi_c); - PRINT_STATS_LE32(general, interference_data_flag); - PRINT_STATS_LE32(general, channel_load); - PRINT_STATS_LE32(general, dsp_false_alarms); - PRINT_STATS_LE32(general, beacon_rssi_a); - PRINT_STATS_LE32(general, beacon_rssi_b); - PRINT_STATS_LE32(general, beacon_rssi_c); - PRINT_STATS_LE32(general, beacon_energy_a); - PRINT_STATS_LE32(general, beacon_energy_b); - PRINT_STATS_LE32(general, beacon_energy_c); - PRINT_STATS_LE32(general, num_bt_kills); - PRINT_STATS_LE32(general, mac_id); - PRINT_STATS_LE32(general, directed_data_mpdu); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct mvm_statistics_rx_non_phy_v3 *general = + &mvm->rx_stats_v3.general; + + PRINT_STATS_LE32(general, bogus_cts); + PRINT_STATS_LE32(general, bogus_ack); + PRINT_STATS_LE32(general, non_bssid_frames); + PRINT_STATS_LE32(general, filtered_frames); + PRINT_STATS_LE32(general, non_channel_beacons); + PRINT_STATS_LE32(general, channel_beacons); + PRINT_STATS_LE32(general, num_missed_bcon); + PRINT_STATS_LE32(general, adc_rx_saturation_time); + PRINT_STATS_LE32(general, ina_detection_search_time); + PRINT_STATS_LE32(general, beacon_silence_rssi_a); + PRINT_STATS_LE32(general, beacon_silence_rssi_b); + PRINT_STATS_LE32(general, beacon_silence_rssi_c); + PRINT_STATS_LE32(general, interference_data_flag); + PRINT_STATS_LE32(general, channel_load); + PRINT_STATS_LE32(general, dsp_false_alarms); + PRINT_STATS_LE32(general, beacon_rssi_a); + PRINT_STATS_LE32(general, beacon_rssi_b); + PRINT_STATS_LE32(general, beacon_rssi_c); + PRINT_STATS_LE32(general, beacon_energy_a); + PRINT_STATS_LE32(general, beacon_energy_b); + PRINT_STATS_LE32(general, beacon_energy_c); + PRINT_STATS_LE32(general, num_bt_kills); + PRINT_STATS_LE32(general, mac_id); + PRINT_STATS_LE32(general, directed_data_mpdu); + } else { + struct mvm_statistics_rx_non_phy *general = + &mvm->rx_stats.general; + + PRINT_STATS_LE32(general, bogus_cts); + PRINT_STATS_LE32(general, bogus_ack); + PRINT_STATS_LE32(general, non_channel_beacons); + PRINT_STATS_LE32(general, channel_beacons); + PRINT_STATS_LE32(general, num_missed_bcon); + PRINT_STATS_LE32(general, adc_rx_saturation_time); + PRINT_STATS_LE32(general, ina_detection_search_time); + PRINT_STATS_LE32(general, beacon_silence_rssi_a); + PRINT_STATS_LE32(general, beacon_silence_rssi_b); + PRINT_STATS_LE32(general, beacon_silence_rssi_c); + PRINT_STATS_LE32(general, interference_data_flag); + PRINT_STATS_LE32(general, channel_load); + PRINT_STATS_LE32(general, beacon_rssi_a); + PRINT_STATS_LE32(general, beacon_rssi_b); + PRINT_STATS_LE32(general, beacon_rssi_c); + PRINT_STATS_LE32(general, beacon_energy_a); + PRINT_STATS_LE32(general, beacon_energy_b); + PRINT_STATS_LE32(general, beacon_energy_c); + PRINT_STATS_LE32(general, num_bt_kills); + PRINT_STATS_LE32(general, mac_id); + } pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - HT"); - PRINT_STATS_LE32(ht, plcp_err); - PRINT_STATS_LE32(ht, overrun_err); - PRINT_STATS_LE32(ht, early_overrun_err); - PRINT_STATS_LE32(ht, crc32_good); - PRINT_STATS_LE32(ht, crc32_err); - PRINT_STATS_LE32(ht, mh_format_err); - PRINT_STATS_LE32(ht, agg_crc32_good); - PRINT_STATS_LE32(ht, agg_mpdu_cnt); - PRINT_STATS_LE32(ht, agg_cnt); - PRINT_STATS_LE32(ht, unsupport_mcs); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct mvm_statistics_rx_ht_phy_v1 *ht = + &mvm->rx_stats_v3.ofdm_ht; + + PRINT_STATS_LE32(ht, plcp_err); + PRINT_STATS_LE32(ht, overrun_err); + PRINT_STATS_LE32(ht, early_overrun_err); + PRINT_STATS_LE32(ht, crc32_good); + PRINT_STATS_LE32(ht, crc32_err); + PRINT_STATS_LE32(ht, mh_format_err); + PRINT_STATS_LE32(ht, agg_crc32_good); + PRINT_STATS_LE32(ht, agg_mpdu_cnt); + PRINT_STATS_LE32(ht, agg_cnt); + PRINT_STATS_LE32(ht, unsupport_mcs); + } else { + struct mvm_statistics_rx_ht_phy *ht = + &mvm->rx_stats.ofdm_ht; + + PRINT_STATS_LE32(ht, mh_format_err); + PRINT_STATS_LE32(ht, agg_mpdu_cnt); + PRINT_STATS_LE32(ht, agg_cnt); + PRINT_STATS_LE32(ht, unsupport_mcs); + } mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h index 4286222f54f7..c7531da508fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h @@ -84,7 +84,55 @@ struct mvm_statistics_div { __le32 reserved2; } __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */ +/** + * struct mvm_statistics_rx_non_phy + * @bogus_cts: CTS received when not expecting CTS + * @bogus_ack: ACK received when not expecting ACK + * @non_channel_beacons: beacons with our bss id but not on our serving channel + * @channel_beacons: beacons with our bss id and in our serving channel + * @num_missed_bcon: number of missed beacons + * @adc_rx_saturation_time: count in 0.8us units the time the ADC was in + * saturation + * @ina_detection_search_time: total time (in 0.8us) searched for INA + * @beacon_silence_rssi_a: RSSI silence after beacon frame + * @beacon_silence_rssi_b: RSSI silence after beacon frame + * @beacon_silence_rssi_c: RSSI silence after beacon frame + * @interference_data_flag: flag for interference data availability. 1 when data + * is available. + * @channel_load: counts RX Enable time in uSec + * @beacon_rssi_a: beacon RSSI on anntena A + * @beacon_rssi_b: beacon RSSI on antenna B + * @beacon_rssi_c: beacon RSSI on antenna C + * @beacon_energy_a: beacon energy on antenna A + * @beacon_energy_b: beacon energy on antenna B + * @beacon_energy_c: beacon energy on antenna C + * @num_bt_kills: number of BT "kills" (frame TX aborts) + * @mac_id: mac ID + */ struct mvm_statistics_rx_non_phy { + __le32 bogus_cts; + __le32 bogus_ack; + __le32 non_channel_beacons; + __le32 channel_beacons; + __le32 num_missed_bcon; + __le32 adc_rx_saturation_time; + __le32 ina_detection_search_time; + __le32 beacon_silence_rssi_a; + __le32 beacon_silence_rssi_b; + __le32 beacon_silence_rssi_c; + __le32 interference_data_flag; + __le32 channel_load; + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 beacon_rssi_c; + __le32 beacon_energy_a; + __le32 beacon_energy_b; + __le32 beacon_energy_c; + __le32 num_bt_kills; + __le32 mac_id; +} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_4 */ + +struct mvm_statistics_rx_non_phy_v3 { __le32 bogus_cts; /* CTS received when not expecting CTS */ __le32 bogus_ack; /* ACK received when not expecting ACK */ __le32 non_bssid_frames; /* number of frames with BSSID that @@ -121,6 +169,14 @@ struct mvm_statistics_rx_non_phy { } __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */ struct mvm_statistics_rx_phy { + __le32 unresponded_rts; + __le32 rxe_frame_lmt_overrun; + __le32 sent_ba_rsp_cnt; + __le32 dsp_self_kill; + __le32 reserved; +} __packed; /* STATISTICS_RX_PHY_API_S_VER_3 */ + +struct mvm_statistics_rx_phy_v2 { __le32 ina_cnt; __le32 fina_cnt; __le32 plcp_err; @@ -143,7 +199,7 @@ struct mvm_statistics_rx_phy { __le32 reserved; } __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */ -struct mvm_statistics_rx_ht_phy { +struct mvm_statistics_rx_ht_phy_v1 { __le32 plcp_err; __le32 overrun_err; __le32 early_overrun_err; @@ -156,7 +212,14 @@ struct mvm_statistics_rx_ht_phy { __le32 unsupport_mcs; } __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */ -struct mvm_statistics_tx_non_phy { +struct mvm_statistics_rx_ht_phy { + __le32 mh_format_err; + __le32 agg_mpdu_cnt; + __le32 agg_cnt; + __le32 unsupport_mcs; +} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_2 */ + +struct mvm_statistics_tx_non_phy_v3 { __le32 preamble_cnt; __le32 rx_detected_cnt; __le32 bt_prio_defer_cnt; @@ -173,6 +236,19 @@ struct mvm_statistics_tx_non_phy { __le32 ack_or_ba_timeout_collision; } __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_3 */ +struct mvm_statistics_tx_non_phy { + __le32 bt_prio_defer_cnt; + __le32 bt_prio_kill_cnt; + __le32 few_bytes_cnt; + __le32 cts_timeout; + __le32 ack_timeout; + __le32 dump_msdu_cnt; + __le32 burst_abort_next_frame_mismatch_cnt; + __le32 burst_abort_missing_next_frame_cnt; + __le32 cts_timeout_collision; + __le32 ack_or_ba_timeout_collision; +} __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_4 */ + #define MAX_CHAINS 3 struct mvm_statistics_tx_non_phy_agg { @@ -202,11 +278,17 @@ struct mvm_statistics_tx_channel_width { __le32 fail_per_ch_width[4]; }; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ +struct mvm_statistics_tx_v4 { + struct mvm_statistics_tx_non_phy_v3 general; + struct mvm_statistics_tx_non_phy_agg agg; + struct mvm_statistics_tx_channel_width channel_width; +} __packed; /* STATISTICS_TX_API_S_VER_4 */ + struct mvm_statistics_tx { struct mvm_statistics_tx_non_phy general; struct mvm_statistics_tx_non_phy_agg agg; struct mvm_statistics_tx_channel_width channel_width; -} __packed; /* STATISTICS_TX_API_S_VER_4 */ +} __packed; /* STATISTICS_TX_API_S_VER_5 */ struct mvm_statistics_bt_activity { @@ -220,7 +302,7 @@ struct mvm_statistics_bt_activity { __le32 lo_priority_rx_denied_cnt; } __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ -struct mvm_statistics_general_common { +struct mvm_statistics_general_common_v19 { __le32 radio_temperature; __le32 radio_voltage; struct mvm_statistics_dbg dbg; @@ -250,20 +332,56 @@ struct mvm_statistics_general_common { __le64 tx_time; } __packed; +struct mvm_statistics_general_common { + __le32 radio_temperature; + struct mvm_statistics_dbg dbg; + __le32 sleep_time; + __le32 slots_out; + __le32 slots_idle; + __le32 ttl_timestamp; + struct mvm_statistics_div slow_div; + __le32 rx_enable_counter; + /* + * num_of_sos_states: + * count the number of times we have to re-tune + * in order to get out of bad PHY status + */ + __le32 num_of_sos_states; + __le32 beacon_filtered; + __le32 missed_beacons; + u8 beacon_filter_average_energy; + u8 beacon_filter_reason; + u8 beacon_filter_current_energy; + u8 beacon_filter_reserved; + __le32 beacon_filter_delta_time; + struct mvm_statistics_bt_activity bt_activity; + __le64 rx_time; + __le64 on_time_rf; + __le64 on_time_scan; + __le64 tx_time; +} __packed; /* STATISTICS_GENERAL_API_S_VER_10 */ + struct mvm_statistics_general_v8 { - struct mvm_statistics_general_common common; + struct mvm_statistics_general_common_v19 common; __le32 beacon_counter[NUM_MAC_INDEX]; u8 beacon_average_energy[NUM_MAC_INDEX]; u8 reserved[4 - (NUM_MAC_INDEX % 4)]; } __packed; /* STATISTICS_GENERAL_API_S_VER_8 */ -struct mvm_statistics_general_cdb { - struct mvm_statistics_general_common common; +struct mvm_statistics_general_cdb_v9 { + struct mvm_statistics_general_common_v19 common; __le32 beacon_counter[NUM_MAC_INDEX_CDB]; u8 beacon_average_energy[NUM_MAC_INDEX_CDB]; u8 reserved[4 - (NUM_MAC_INDEX_CDB % 4)]; } __packed; /* STATISTICS_GENERAL_API_S_VER_9 */ +struct mvm_statistics_general_cdb { + struct mvm_statistics_general_common common; + __le32 beacon_counter[MAC_INDEX_AUX]; + u8 beacon_average_energy[MAC_INDEX_AUX]; + u8 reserved[8 - MAC_INDEX_AUX]; +} __packed; /* STATISTICS_GENERAL_API_S_VER_10 */ + /** * struct mvm_statistics_load - RX statistics for multi-queue devices * @air_time: accumulated air time, per mac @@ -272,24 +390,31 @@ struct mvm_statistics_general_cdb { * @avg_energy: average RSSI, per station */ struct mvm_statistics_load { + __le32 air_time[MAC_INDEX_AUX]; + __le32 byte_count[MAC_INDEX_AUX]; + __le32 pkt_count[MAC_INDEX_AUX]; + u8 avg_energy[IWL_MVM_STATION_COUNT]; +} __packed; /* STATISTICS_RX_MAC_STATION_S_VER_3 */ + +struct mvm_statistics_load_v1 { __le32 air_time[NUM_MAC_INDEX]; __le32 byte_count[NUM_MAC_INDEX]; __le32 pkt_count[NUM_MAC_INDEX]; u8 avg_energy[IWL_MVM_STATION_COUNT]; } __packed; /* STATISTICS_RX_MAC_STATION_S_VER_1 */ -struct mvm_statistics_load_cdb { - __le32 air_time[NUM_MAC_INDEX_CDB]; - __le32 byte_count[NUM_MAC_INDEX_CDB]; - __le32 pkt_count[NUM_MAC_INDEX_CDB]; - u8 avg_energy[IWL_MVM_STATION_COUNT]; -} __packed; /* STATISTICS_RX_MAC_STATION_S_VER_2 */ - struct mvm_statistics_rx { struct mvm_statistics_rx_phy ofdm; struct mvm_statistics_rx_phy cck; struct mvm_statistics_rx_non_phy general; struct mvm_statistics_rx_ht_phy ofdm_ht; +} __packed; /* STATISTICS_RX_API_S_VER_4 */ + +struct mvm_statistics_rx_v3 { + struct mvm_statistics_rx_phy_v2 ofdm; + struct mvm_statistics_rx_phy_v2 cck; + struct mvm_statistics_rx_non_phy_v3 general; + struct mvm_statistics_rx_ht_phy_v1 ofdm_ht; } __packed; /* STATISTICS_RX_API_S_VER_3 */ /* @@ -302,17 +427,17 @@ struct mvm_statistics_rx { struct iwl_notif_statistics_v10 { __le32 flag; - struct mvm_statistics_rx rx; - struct mvm_statistics_tx tx; + struct mvm_statistics_rx_v3 rx; + struct mvm_statistics_tx_v4 tx; struct mvm_statistics_general_v8 general; } __packed; /* STATISTICS_NTFY_API_S_VER_10 */ struct iwl_notif_statistics_v11 { __le32 flag; - struct mvm_statistics_rx rx; - struct mvm_statistics_tx tx; + struct mvm_statistics_rx_v3 rx; + struct mvm_statistics_tx_v4 tx; struct mvm_statistics_general_v8 general; - struct mvm_statistics_load load_stats; + struct mvm_statistics_load_v1 load_stats; } __packed; /* STATISTICS_NTFY_API_S_VER_11 */ struct iwl_notif_statistics_cdb { @@ -320,8 +445,8 @@ struct iwl_notif_statistics_cdb { struct mvm_statistics_rx rx; struct mvm_statistics_tx tx; struct mvm_statistics_general_cdb general; - struct mvm_statistics_load_cdb load_stats; -} __packed; /* STATISTICS_NTFY_API_S_VER_12 */ + struct mvm_statistics_load load_stats; +} __packed; /* STATISTICS_NTFY_API_S_VER_13 */ /** * enum iwl_statistics_notif_flags - flags used in statistics notification diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 3e297c95e8ff..aad265dcfaf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -447,7 +447,11 @@ enum iwl_legacy_cmds { TX_ANT_CONFIGURATION_CMD = 0x98, /** - * @STATISTICS_CMD: &struct iwl_statistics_cmd + * @STATISTICS_CMD: + * one of &struct iwl_statistics_cmd, + * &struct iwl_notif_statistics_v11, + * &struct iwl_notif_statistics_v10, + * &struct iwl_notif_statistics_cdb */ STATISTICS_CMD = 0x9c, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 6b8f7817391d..eaacfaf37206 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -780,7 +780,10 @@ struct iwl_mvm { struct iwl_notif_wait_data notif_wait; - struct mvm_statistics_rx rx_stats; + union { + struct mvm_statistics_rx_v3 rx_stats_v3; + struct mvm_statistics_rx rx_stats; + }; struct { u64 rx_time; @@ -1297,6 +1300,12 @@ static inline bool iwl_mvm_is_cdb_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CDB_SUPPORT); } +static inline bool iwl_mvm_has_new_rx_stats_api(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_NEW_RX_STATS); +} + static inline struct agg_tx_status * iwl_mvm_get_agg_status(struct iwl_mvm *mvm, void *tx_resp) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 1799a3d367f9..4d1188b8736a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -776,7 +776,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (err) goto out_unregister; - memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) + memset(&mvm->rx_stats_v3, 0, + sizeof(struct mvm_statistics_rx_v3)); + else + memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); /* The transport always starts with a taken reference, we can * release it now if d0i3 is supported */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 2c07719aa45c..622d543abb70 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -504,14 +504,6 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, iwl_mvm_unref(mvm, IWL_MVM_REF_RX); } -static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, - struct mvm_statistics_rx *rx_stats) -{ - lockdep_assert_held(&mvm->mutex); - - mvm->rx_stats = *rx_stats; -} - struct iwl_mvm_stat_data { struct iwl_mvm *mvm; __le32 mac_id; @@ -555,7 +547,6 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac, mvmvif->beacon_stats.avg_signal = -general->beacon_average_energy[vif_id]; } - } if (mvmvif->id != id) @@ -651,7 +642,6 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { - struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; struct iwl_mvm_stat_data data = { .mvm = mvm, }; @@ -659,13 +649,16 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, int i; u8 *energy; __le32 *bytes, *air_time; + __le32 flags; - if (iwl_mvm_is_cdb_supported(mvm)) - expected_size = sizeof(*stats); - else if (iwl_mvm_has_new_rx_api(mvm)) - expected_size = sizeof(struct iwl_notif_statistics_v11); - else - expected_size = sizeof(struct iwl_notif_statistics_v10); + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + if (iwl_mvm_has_new_rx_api(mvm)) + expected_size = sizeof(struct iwl_notif_statistics_v11); + else + expected_size = sizeof(struct iwl_notif_statistics_v10); + } else { + expected_size = sizeof(struct iwl_notif_statistics_cdb); + } if (iwl_rx_packet_payload_len(pkt) != expected_size) { IWL_ERR(mvm, "received invalid statistics size (%d)!\n", @@ -673,20 +666,49 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, return; } - data.mac_id = stats->rx.general.mac_id; - data.beacon_filter_average_energy = - stats->general.common.beacon_filter_average_energy; + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct iwl_notif_statistics_v11 *stats = (void *)&pkt->data; - iwl_mvm_update_rx_statistics(mvm, &stats->rx); + data.mac_id = stats->rx.general.mac_id; + data.beacon_filter_average_energy = + stats->general.common.beacon_filter_average_energy; - mvm->radio_stats.rx_time = le64_to_cpu(stats->general.common.rx_time); - mvm->radio_stats.tx_time = le64_to_cpu(stats->general.common.tx_time); - mvm->radio_stats.on_time_rf = - le64_to_cpu(stats->general.common.on_time_rf); - mvm->radio_stats.on_time_scan = - le64_to_cpu(stats->general.common.on_time_scan); + mvm->rx_stats_v3 = stats->rx; - data.general = &stats->general; + mvm->radio_stats.rx_time = + le64_to_cpu(stats->general.common.rx_time); + mvm->radio_stats.tx_time = + le64_to_cpu(stats->general.common.tx_time); + mvm->radio_stats.on_time_rf = + le64_to_cpu(stats->general.common.on_time_rf); + mvm->radio_stats.on_time_scan = + le64_to_cpu(stats->general.common.on_time_scan); + + data.general = &stats->general; + + flags = stats->flag; + } else { + struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; + + data.mac_id = stats->rx.general.mac_id; + data.beacon_filter_average_energy = + stats->general.common.beacon_filter_average_energy; + + mvm->rx_stats = stats->rx; + + mvm->radio_stats.rx_time = + le64_to_cpu(stats->general.common.rx_time); + mvm->radio_stats.tx_time = + le64_to_cpu(stats->general.common.tx_time); + mvm->radio_stats.on_time_rf = + le64_to_cpu(stats->general.common.on_time_rf); + mvm->radio_stats.on_time_scan = + le64_to_cpu(stats->general.common.on_time_scan); + + data.general = &stats->general; + + flags = stats->flag; + } iwl_mvm_rx_stats_check_trigger(mvm, pkt); @@ -698,14 +720,15 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, if (!iwl_mvm_has_new_rx_api(mvm)) return; - if (!iwl_mvm_is_cdb_supported(mvm)) { - struct iwl_notif_statistics_v11 *v11 = - (void *)&pkt->data; + if (!iwl_mvm_has_new_rx_stats_api(mvm)) { + struct iwl_notif_statistics_v11 *v11 = (void *)&pkt->data; energy = (void *)&v11->load_stats.avg_energy; bytes = (void *)&v11->load_stats.byte_count; air_time = (void *)&v11->load_stats.air_time; } else { + struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; + energy = (void *)&stats->load_stats.avg_energy; bytes = (void *)&stats->load_stats.byte_count; air_time = (void *)&stats->load_stats.air_time; -- cgit v1.2.3 From 51da3d8b94485a8397ae7af3bfdb65feaf582202 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 12 Jun 2017 11:24:06 +0200 Subject: iwlwifi: mvm: quietly accept non-sta disassoc frames When a station that's not associated sends a data frame (e.g. an NDP) hostapd will respond with a disassoc frame, telling it that it's not associated. The station might also not be authenticated, in which case there will not be a station entry for it, and as a result we need to accept such frames without a station. Fixes: 3ee0f0e23e4f ("iwlwifi: mvm: fix DQA AP mode station assumption") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 73967790f7e4..60360ed73f26 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -568,9 +568,12 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, * station that we don't have, or similarly an association * response (with non-success status) for a station we can't * accept. + * Also, disassociate frames might happen, particular with + * reason 7 ("Class 3 frame received from nonassociated STA"). */ if (ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) || - ieee80211_is_deauth(fc) || ieee80211_is_assoc_resp(fc)) + ieee80211_is_deauth(fc) || ieee80211_is_assoc_resp(fc) || + ieee80211_is_disassoc(fc)) return mvm->probe_queue; if (info->hw_queue == info->control.vif->cab_queue) return mvmvif->cab_queue; -- cgit v1.2.3 From 52b6e168ae579483d71621e4d64d6491e8973e91 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 27 Jun 2017 12:23:56 +0300 Subject: iwlwifi: pcie: propagate iwl_pcie_apm_init's status iwl_pcie_apm_init can fail so make sure that the caller takes the status into account. Also, ensure that the error that iwl_pcie_apm_init can emit will appear in the kernel log by default. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index a7d0b5c5e4a0..cac584cc07b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -236,7 +236,8 @@ void iwl_pcie_apm_config(struct iwl_trans *trans) */ static int iwl_pcie_apm_init(struct iwl_trans *trans) { - int ret = 0; + int ret; + IWL_DEBUG_INFO(trans, "Init card's basic functions\n"); /* @@ -287,8 +288,8 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { - IWL_DEBUG_INFO(trans, "Failed to init the card\n"); - goto out; + IWL_ERR(trans, "Failed to init the card\n"); + return ret; } if (trans->cfg->host_interrupt_operation_mode) { @@ -336,8 +337,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) set_bit(STATUS_DEVICE_ENABLED, &trans->status); -out: - return ret; + return 0; } /* @@ -514,13 +514,16 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) static int iwl_pcie_nic_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; /* nic_init */ spin_lock(&trans_pcie->irq_lock); - iwl_pcie_apm_init(trans); - + ret = iwl_pcie_apm_init(trans); spin_unlock(&trans_pcie->irq_lock); + if (ret) + return ret; + iwl_pcie_set_pwr(trans, false); iwl_op_mode_nic_config(trans->op_mode); @@ -1658,7 +1661,9 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); usleep_range(1000, 2000); - iwl_pcie_apm_init(trans); + err = iwl_pcie_apm_init(trans); + if (err) + return err; iwl_pcie_init_msix(trans_pcie); -- cgit v1.2.3 From 099a628bf6d9bb1d66cc0383f97cea19cfa4aacc Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 27 Jun 2017 12:29:26 +0300 Subject: iwlwifi: pcie: wait longer after device reset The newest devices need a longer time to reset because of their more complex hardware. Wait 5ms after device reset. Consolidate all the places that reset the device in the PCIe transport to avoid future bugs. While at it, unify the flow to use set_bit instead of full write as requested by the hardware designers. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 7 +++++++ .../net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 8 ++------ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 23 +++++----------------- 4 files changed, 15 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index bd2596fdafda..fc5a490880d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -526,7 +526,7 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) /* reset the device */ iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + usleep_range(5000, 6000); /* set INIT_DONE flag */ iwl_set_bit(trans, CSR_GP_CNTRL, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 7ec2d96ccceb..fa315d84e98e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -654,6 +654,13 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans) } } +static inline void iwl_pcie_sw_reset(struct iwl_trans *trans) +{ + /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + usleep_range(5000, 6000); +} + static inline void *iwl_pcie_get_tfd(struct iwl_trans_pcie *trans_pcie, struct iwl_txq *txq, int idx) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index e84c5ff389a8..b84b78293e7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -136,9 +136,7 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) /* Stop device's DMA activity */ iwl_pcie_apm_stop_master(trans); - /* Reset the entire device */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Clear "initialization complete" bit to move adapter from @@ -188,9 +186,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) /* Stop the device, and put it in low power state */ iwl_pcie_gen2_apm_stop(trans, false); - /* stop and reset the on-board processor */ - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Upon stop, the IVAR table gets erased, so msi-x won't diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index cac584cc07b6..92b3a55d0fbc 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -358,9 +358,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_XTAL_ON); - /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Set "initialization complete" bit to move adapter from @@ -401,12 +399,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) apmg_xtal_cfg_reg | SHR_APMG_XTAL_CFG_XTAL_ON_REQ); - /* - * Reset entire device again - do controller reset (results in - * SHRD_HW_RST). Turn MAC off before proceeding. - */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* Enable LP XTAL by indirect access through CSR */ apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG); @@ -499,9 +492,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) return; } - /* Reset the entire device */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Clear "initialization complete" bit to move adapter from @@ -1181,9 +1172,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) /* Stop the device, and put it in low power state */ iwl_pcie_apm_stop(trans, false); - /* stop and reset the on-board processor */ - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); /* * Upon stop, the IVAR table gets erased, so msi-x won't @@ -1657,9 +1646,7 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) return err; } - /* Reset the entire device */ - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(1000, 2000); + iwl_pcie_sw_reset(trans); err = iwl_pcie_apm_init(trans); if (err) -- cgit v1.2.3 From ba320dd61ec91bbe98730f3407a486facc174d63 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 19 May 2017 15:12:07 +0300 Subject: iwlwifi: bump MAX API for 8000/9000/A000 to 33 Bump the maximum API supported by these device families to 33. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/8000.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/a000.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index 766bb2037b94..5081720608af 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -70,8 +70,8 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 31 -#define IWL8265_UCODE_API_MAX 31 +#define IWL8000_UCODE_API_MAX 33 +#define IWL8265_UCODE_API_MAX 33 /* Lowest firmware API version supported */ #define IWL8000_UCODE_API_MIN 22 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 42daaddfa740..b4ecd1fe1374 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 31 +#define IWL9000_UCODE_API_MAX 33 /* Lowest firmware API version supported */ #define IWL9000_UCODE_API_MIN 30 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/a000.c b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c index 2940c0a6c3d6..98f24cd1b44f 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/a000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL_A000_UCODE_API_MAX 31 +#define IWL_A000_UCODE_API_MAX 33 /* Lowest firmware API version supported */ #define IWL_A000_UCODE_API_MIN 24 -- cgit v1.2.3 From 549b32af9f7c4b3a924ddf4feb3b09aae6d8c867 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:41:32 -0500 Subject: amd-xgbe: Simplify mailbox interface rate change code Simplify and centralize the mailbox command rate change interface by having a single function perform the writes to the mailbox registers to issue the request. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 155 ++++++---------------------- 1 file changed, 29 insertions(+), 126 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index e707c49cc55a..04298401c133 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -1694,19 +1694,25 @@ static void xgbe_phy_set_redrv_mode(struct xgbe_prv_data *pdata) xgbe_phy_put_comm_ownership(pdata); } -static void xgbe_phy_start_ratechange(struct xgbe_prv_data *pdata) +static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata, + unsigned int cmd, unsigned int sub_cmd) { - if (!XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) - return; + unsigned int s0 = 0; + unsigned int wait; /* Log if a previous command did not complete */ - netif_dbg(pdata, link, pdata->netdev, - "firmware mailbox not ready for command\n"); -} + if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) + netif_dbg(pdata, link, pdata->netdev, + "firmware mailbox not ready for command\n"); -static void xgbe_phy_complete_ratechange(struct xgbe_prv_data *pdata) -{ - unsigned int wait; + /* Construct the command */ + XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, cmd); + XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, sub_cmd); + + /* Issue the command */ + XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); + XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); + XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); /* Wait for command to complete */ wait = XGBE_RATECHANGE_COUNT; @@ -1723,21 +1729,8 @@ static void xgbe_phy_complete_ratechange(struct xgbe_prv_data *pdata) static void xgbe_phy_rrc(struct xgbe_prv_data *pdata) { - unsigned int s0; - - xgbe_phy_start_ratechange(pdata); - /* Receiver Reset Cycle */ - s0 = 0; - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 5); - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 0); - - /* Call FW to make the change */ - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); - XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); - - xgbe_phy_complete_ratechange(pdata); + xgbe_phy_perform_ratechange(pdata, 5, 0); netif_dbg(pdata, link, pdata->netdev, "receiver reset complete\n"); } @@ -1746,14 +1739,8 @@ static void xgbe_phy_power_off(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - xgbe_phy_start_ratechange(pdata); - - /* Call FW to make the change */ - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, 0); - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); - XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); - - xgbe_phy_complete_ratechange(pdata); + /* Power off */ + xgbe_phy_perform_ratechange(pdata, 0, 0); phy_data->cur_mode = XGBE_MODE_UNKNOWN; @@ -1763,33 +1750,21 @@ static void xgbe_phy_power_off(struct xgbe_prv_data *pdata) static void xgbe_phy_sfi_mode(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - unsigned int s0; xgbe_phy_set_redrv_mode(pdata); - xgbe_phy_start_ratechange(pdata); - /* 10G/SFI */ - s0 = 0; - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 3); if (phy_data->sfp_cable != XGBE_SFP_CABLE_PASSIVE) { - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 0); + xgbe_phy_perform_ratechange(pdata, 3, 0); } else { if (phy_data->sfp_cable_len <= 1) - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 1); + xgbe_phy_perform_ratechange(pdata, 3, 1); else if (phy_data->sfp_cable_len <= 3) - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 2); + xgbe_phy_perform_ratechange(pdata, 3, 2); else - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 3); + xgbe_phy_perform_ratechange(pdata, 3, 3); } - /* Call FW to make the change */ - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); - XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); - - xgbe_phy_complete_ratechange(pdata); - phy_data->cur_mode = XGBE_MODE_SFI; netif_dbg(pdata, link, pdata->netdev, "10GbE SFI mode set\n"); @@ -1798,23 +1773,11 @@ static void xgbe_phy_sfi_mode(struct xgbe_prv_data *pdata) static void xgbe_phy_x_mode(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - unsigned int s0; xgbe_phy_set_redrv_mode(pdata); - xgbe_phy_start_ratechange(pdata); - /* 1G/X */ - s0 = 0; - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 1); - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 3); - - /* Call FW to make the change */ - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); - XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); - - xgbe_phy_complete_ratechange(pdata); + xgbe_phy_perform_ratechange(pdata, 1, 3); phy_data->cur_mode = XGBE_MODE_X; @@ -1824,23 +1787,11 @@ static void xgbe_phy_x_mode(struct xgbe_prv_data *pdata) static void xgbe_phy_sgmii_1000_mode(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - unsigned int s0; xgbe_phy_set_redrv_mode(pdata); - xgbe_phy_start_ratechange(pdata); - /* 1G/SGMII */ - s0 = 0; - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 1); - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 2); - - /* Call FW to make the change */ - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); - XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); - - xgbe_phy_complete_ratechange(pdata); + xgbe_phy_perform_ratechange(pdata, 1, 2); phy_data->cur_mode = XGBE_MODE_SGMII_1000; @@ -1850,23 +1801,11 @@ static void xgbe_phy_sgmii_1000_mode(struct xgbe_prv_data *pdata) static void xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - unsigned int s0; xgbe_phy_set_redrv_mode(pdata); - xgbe_phy_start_ratechange(pdata); - - /* 1G/SGMII */ - s0 = 0; - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 1); - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 1); - - /* Call FW to make the change */ - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); - XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); - - xgbe_phy_complete_ratechange(pdata); + /* 100M/SGMII */ + xgbe_phy_perform_ratechange(pdata, 1, 1); phy_data->cur_mode = XGBE_MODE_SGMII_100; @@ -1876,23 +1815,11 @@ static void xgbe_phy_sgmii_100_mode(struct xgbe_prv_data *pdata) static void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - unsigned int s0; xgbe_phy_set_redrv_mode(pdata); - xgbe_phy_start_ratechange(pdata); - /* 10G/KR */ - s0 = 0; - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 4); - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 0); - - /* Call FW to make the change */ - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); - XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); - - xgbe_phy_complete_ratechange(pdata); + xgbe_phy_perform_ratechange(pdata, 4, 0); phy_data->cur_mode = XGBE_MODE_KR; @@ -1902,23 +1829,11 @@ static void xgbe_phy_kr_mode(struct xgbe_prv_data *pdata) static void xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - unsigned int s0; xgbe_phy_set_redrv_mode(pdata); - xgbe_phy_start_ratechange(pdata); - /* 2.5G/KX */ - s0 = 0; - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 2); - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 0); - - /* Call FW to make the change */ - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); - XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); - - xgbe_phy_complete_ratechange(pdata); + xgbe_phy_perform_ratechange(pdata, 2, 0); phy_data->cur_mode = XGBE_MODE_KX_2500; @@ -1928,23 +1843,11 @@ static void xgbe_phy_kx_2500_mode(struct xgbe_prv_data *pdata) static void xgbe_phy_kx_1000_mode(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - unsigned int s0; xgbe_phy_set_redrv_mode(pdata); - xgbe_phy_start_ratechange(pdata); - /* 1G/KX */ - s0 = 0; - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, 1); - XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, SUB_COMMAND, 3); - - /* Call FW to make the change */ - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_0, s0); - XP_IOWRITE(pdata, XP_DRIVER_SCRATCH_1, 0); - XP_IOWRITE_BITS(pdata, XP_DRIVER_INT_REQ, REQUEST, 1); - - xgbe_phy_complete_ratechange(pdata); + xgbe_phy_perform_ratechange(pdata, 1, 3); phy_data->cur_mode = XGBE_MODE_KX_1000; -- cgit v1.2.3 From 56503d55cc8b843096a5f51355712ca837f3757b Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:41:40 -0500 Subject: amd-xgbe: Fix SFP PHY supported/advertised settings When using SFPs, the supported and advertised settings should be initially based on the SFP that has been detected. The code currently indicates the overall support of the device as opposed to what the SFP is capable of. Update the code to change the supported link modes, auto-negotiation, etc. to be based on the installed SFP. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 69 ++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 04298401c133..756e1165a318 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -711,23 +711,39 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; + if (!phy_data->sfp_mod_absent && !phy_data->sfp_changed) + return; + + pdata->phy.supported &= ~SUPPORTED_Autoneg; + pdata->phy.supported &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause); + pdata->phy.supported &= ~SUPPORTED_TP; + pdata->phy.supported &= ~SUPPORTED_FIBRE; + pdata->phy.supported &= ~SUPPORTED_100baseT_Full; + pdata->phy.supported &= ~SUPPORTED_1000baseT_Full; + pdata->phy.supported &= ~SUPPORTED_10000baseT_Full; + if (phy_data->sfp_mod_absent) { pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.duplex = DUPLEX_UNKNOWN; pdata->phy.autoneg = AUTONEG_ENABLE; + pdata->phy.pause_autoneg = AUTONEG_ENABLE; + + pdata->phy.supported |= SUPPORTED_Autoneg; + pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + pdata->phy.supported |= SUPPORTED_TP; + pdata->phy.supported |= SUPPORTED_FIBRE; + if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) + pdata->phy.supported |= SUPPORTED_100baseT_Full; + if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) + pdata->phy.supported |= SUPPORTED_1000baseT_Full; + if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) + pdata->phy.supported |= SUPPORTED_10000baseT_Full; + pdata->phy.advertising = pdata->phy.supported; return; } - pdata->phy.advertising &= ~ADVERTISED_Autoneg; - pdata->phy.advertising &= ~ADVERTISED_TP; - pdata->phy.advertising &= ~ADVERTISED_FIBRE; - pdata->phy.advertising &= ~ADVERTISED_100baseT_Full; - pdata->phy.advertising &= ~ADVERTISED_1000baseT_Full; - pdata->phy.advertising &= ~ADVERTISED_10000baseT_Full; - pdata->phy.advertising &= ~ADVERTISED_10000baseR_FEC; - switch (phy_data->sfp_base) { case XGBE_SFP_BASE_1000_T: case XGBE_SFP_BASE_1000_SX: @@ -736,17 +752,25 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.duplex = DUPLEX_UNKNOWN; pdata->phy.autoneg = AUTONEG_ENABLE; - pdata->phy.advertising |= ADVERTISED_Autoneg; + pdata->phy.pause_autoneg = AUTONEG_ENABLE; + pdata->phy.supported |= SUPPORTED_Autoneg; + pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; break; case XGBE_SFP_BASE_10000_SR: case XGBE_SFP_BASE_10000_LR: case XGBE_SFP_BASE_10000_LRM: case XGBE_SFP_BASE_10000_ER: case XGBE_SFP_BASE_10000_CR: - default: pdata->phy.speed = SPEED_10000; pdata->phy.duplex = DUPLEX_FULL; pdata->phy.autoneg = AUTONEG_DISABLE; + pdata->phy.pause_autoneg = AUTONEG_DISABLE; + break; + default: + pdata->phy.speed = SPEED_UNKNOWN; + pdata->phy.duplex = DUPLEX_UNKNOWN; + pdata->phy.autoneg = AUTONEG_DISABLE; + pdata->phy.pause_autoneg = AUTONEG_DISABLE; break; } @@ -754,36 +778,38 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) case XGBE_SFP_BASE_1000_T: case XGBE_SFP_BASE_1000_CX: case XGBE_SFP_BASE_10000_CR: - pdata->phy.advertising |= ADVERTISED_TP; + pdata->phy.supported |= SUPPORTED_TP; break; default: - pdata->phy.advertising |= ADVERTISED_FIBRE; + pdata->phy.supported |= SUPPORTED_FIBRE; } switch (phy_data->sfp_speed) { case XGBE_SFP_SPEED_100_1000: if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) - pdata->phy.advertising |= ADVERTISED_100baseT_Full; + pdata->phy.supported |= SUPPORTED_100baseT_Full; if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) - pdata->phy.advertising |= ADVERTISED_1000baseT_Full; + pdata->phy.supported |= SUPPORTED_1000baseT_Full; break; case XGBE_SFP_SPEED_1000: if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) - pdata->phy.advertising |= ADVERTISED_1000baseT_Full; + pdata->phy.supported |= SUPPORTED_1000baseT_Full; break; case XGBE_SFP_SPEED_10000: if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) - pdata->phy.advertising |= ADVERTISED_10000baseT_Full; + pdata->phy.supported |= SUPPORTED_10000baseT_Full; break; default: /* Choose the fastest supported speed */ if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) - pdata->phy.advertising |= ADVERTISED_10000baseT_Full; + pdata->phy.supported |= SUPPORTED_10000baseT_Full; else if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) - pdata->phy.advertising |= ADVERTISED_1000baseT_Full; + pdata->phy.supported |= SUPPORTED_1000baseT_Full; else if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) - pdata->phy.advertising |= ADVERTISED_100baseT_Full; + pdata->phy.supported |= SUPPORTED_100baseT_Full; } + + pdata->phy.advertising = pdata->phy.supported; } static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, @@ -2113,6 +2139,8 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, return xgbe_phy_check_mode(pdata, mode, ADVERTISED_1000baseT_Full); case XGBE_MODE_SFI: + if (phy_data->sfp_mod_absent) + return true; return xgbe_phy_check_mode(pdata, mode, ADVERTISED_10000baseT_Full); default: @@ -2916,9 +2944,6 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { pdata->phy.supported |= SUPPORTED_10000baseT_Full; phy_data->start_mode = XGBE_MODE_SFI; - if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) - pdata->phy.supported |= - SUPPORTED_10000baseR_FEC; } phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; -- cgit v1.2.3 From 3abc7cff671a15f797f2baca9ba6b406508757b8 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:41:49 -0500 Subject: amd-xgbe: Use the proper register during PTP initialization During PTP initialization, the Timestamp Control register should be cleared and not the Tx Configuration register. While this typo causes the wrong register to be cleared, the default value of each register and and the fact that the Tx Configuration register is programmed afterwards doesn't result in a bug, hence only fixing in net-next. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c index a533a6cc2d53..d06d260cf1e2 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c @@ -267,7 +267,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) ktime_to_ns(ktime_get_real())); /* Disable all timestamping to start */ - XGMAC_IOWRITE(pdata, MAC_TCR, 0); + XGMAC_IOWRITE(pdata, MAC_TSCR, 0); pdata->tstamp_config.tx_type = HWTSTAMP_TX_OFF; pdata->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; } -- cgit v1.2.3 From 93845d5f1b3c3878fdeb6275f1928217ec0c9ff2 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:41:58 -0500 Subject: amd-xgbe: Add a check for an skb in the timestamp path Spurious Tx timestamp interrupts can cause an oops in the Tx timestamp processing function if a Tx timestamp skb is NULL. Add a check to insure a Tx timestamp skb is present before attempting to use it. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index a934bd5d0507..20685100ce12 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1212,6 +1212,10 @@ static void xgbe_tx_tstamp(struct work_struct *work) u64 nsec; unsigned long flags; + spin_lock_irqsave(&pdata->tstamp_lock, flags); + if (!pdata->tx_tstamp_skb) + goto unlock; + if (pdata->tx_tstamp) { nsec = timecounter_cyc2time(&pdata->tstamp_tc, pdata->tx_tstamp); @@ -1223,8 +1227,9 @@ static void xgbe_tx_tstamp(struct work_struct *work) dev_kfree_skb_any(pdata->tx_tstamp_skb); - spin_lock_irqsave(&pdata->tstamp_lock, flags); pdata->tx_tstamp_skb = NULL; + +unlock: spin_unlock_irqrestore(&pdata->tstamp_lock, flags); } -- cgit v1.2.3 From 9018ff5331a64aa9e6dd600345bb1d087684fdff Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:42:07 -0500 Subject: amd-xgbe: Prevent looping forever if timestamp update fails Just to be on the safe side, should the update of the timestamp registers not complete, issue a warning rather than looping forever waiting for the update to complete. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 24a687ce4388..3ad4036fb6d9 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1497,26 +1497,37 @@ static void xgbe_rx_desc_init(struct xgbe_channel *channel) static void xgbe_update_tstamp_addend(struct xgbe_prv_data *pdata, unsigned int addend) { + unsigned int count = 10000; + /* Set the addend register value and tell the device */ XGMAC_IOWRITE(pdata, MAC_TSAR, addend); XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSADDREG, 1); /* Wait for addend update to complete */ - while (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSADDREG)) + while (--count && XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSADDREG)) udelay(5); + + if (!count) + netdev_err(pdata->netdev, + "timed out updating timestamp addend register\n"); } static void xgbe_set_tstamp_time(struct xgbe_prv_data *pdata, unsigned int sec, unsigned int nsec) { + unsigned int count = 10000; + /* Set the time values and tell the device */ XGMAC_IOWRITE(pdata, MAC_STSUR, sec); XGMAC_IOWRITE(pdata, MAC_STNUR, nsec); XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSINIT, 1); /* Wait for time update to complete */ - while (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSINIT)) + while (--count && XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSINIT)) udelay(5); + + if (!count) + netdev_err(pdata->netdev, "timed out initializing timestamp\n"); } static u64 xgbe_get_tstamp_time(struct xgbe_prv_data *pdata) -- cgit v1.2.3 From 42d452dc4a3674bbe53fa80f00f31f72385252dd Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:42:16 -0500 Subject: amd-xgbe: Handle return code from software reset function Currently the function that performs a software reset of the hardware provides a return code. During driver probe check this return code and exit with an error if the software reset fails. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 17ac8f9a51a0..982368b560ba 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -277,7 +277,11 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata) pdata->desc_ded_period = jiffies; /* Issue software reset to device */ - pdata->hw_if.exit(pdata); + ret = pdata->hw_if.exit(pdata); + if (ret) { + dev_err(dev, "software reset failed\n"); + return ret; + } /* Set default configuration data */ xgbe_default_config(pdata); -- cgit v1.2.3 From ed3333fa6fc21b4191601367a5ea4f0f198f100d Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:42:25 -0500 Subject: amd-xgbe: Fixes for working with PHYs that support 2.5GbE The driver has some missing functionality when operating in the mode that supports 2.5GbE. Fix the driver to fully recognize and support this speed. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 756e1165a318..b8be62e273c0 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -1966,6 +1966,8 @@ static enum xgbe_mode xgbe_phy_get_baset_mode(struct xgbe_phy_data *phy_data, return XGBE_MODE_SGMII_100; case SPEED_1000: return XGBE_MODE_SGMII_1000; + case SPEED_2500: + return XGBE_MODE_KX_2500; case SPEED_10000: return XGBE_MODE_KR; default: @@ -2109,6 +2111,9 @@ static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata, case XGBE_MODE_SGMII_1000: return xgbe_phy_check_mode(pdata, mode, ADVERTISED_1000baseT_Full); + case XGBE_MODE_KX_2500: + return xgbe_phy_check_mode(pdata, mode, + ADVERTISED_2500baseX_Full); case XGBE_MODE_KR: return xgbe_phy_check_mode(pdata, mode, ADVERTISED_10000baseT_Full); @@ -2218,6 +2223,8 @@ static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_phy_data *phy_data, case SPEED_100: case SPEED_1000: return true; + case SPEED_2500: + return (phy_data->port_mode == XGBE_PORT_MODE_NBASE_T); case SPEED_10000: return (phy_data->port_mode == XGBE_PORT_MODE_10GBASE_T); default: -- cgit v1.2.3 From 45a2005e9354f8bcf2333a8bc8cc4b26a927d042 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:42:35 -0500 Subject: amd-xgbe: Limit the I2C error messages that are output When I2C communication fails, it tends to always fail. Rather than continuously issue an error message (once per second in most cases), change the message to be issued just once. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index b8be62e273c0..04b5c149caca 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -1121,7 +1121,8 @@ static int xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata) ret = xgbe_phy_sfp_get_mux(pdata); if (ret) { - netdev_err(pdata->netdev, "I2C error setting SFP MUX\n"); + dev_err_once(pdata->dev, "%s: I2C error setting SFP MUX\n", + netdev_name(pdata->netdev)); return ret; } @@ -1131,7 +1132,8 @@ static int xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata) &eeprom_addr, sizeof(eeprom_addr), &sfp_eeprom, sizeof(sfp_eeprom)); if (ret) { - netdev_err(pdata->netdev, "I2C error reading SFP EEPROM\n"); + dev_err_once(pdata->dev, "%s: I2C error reading SFP EEPROM\n", + netdev_name(pdata->netdev)); goto put; } @@ -1190,7 +1192,8 @@ static void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata) &gpio_reg, sizeof(gpio_reg), gpio_ports, sizeof(gpio_ports)); if (ret) { - netdev_err(pdata->netdev, "I2C error reading SFP GPIOs\n"); + dev_err_once(pdata->dev, "%s: I2C error reading SFP GPIOs\n", + netdev_name(pdata->netdev)); return; } -- cgit v1.2.3 From 85b85c853401da56e15ef500552c1c2e795122ed Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:42:42 -0500 Subject: amd-xgbe: Re-issue interrupt if interrupt status not cleared Some of the device interrupts should function as level interrupts. For some hardware configurations this requires setting some control bits so that if the interrupt status has not been cleared the interrupt should be reissued. Additionally, when using MSI or MSI-X interrupts, run the interrupt service routine as a tasklet so that the re-issuance of the interrupt is handled properly. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 1 + drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 53 +++++++++++++++++++++++++---- drivers/net/ethernet/amd/xgbe/xgbe-i2c.c | 30 +++++++++++++--- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 33 ++++++++++++++++-- drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 4 +++ drivers/net/ethernet/amd/xgbe/xgbe.h | 11 ++++-- 6 files changed, 115 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 127adbeefb10..e7b68043d627 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -959,6 +959,7 @@ #define XP_DRIVER_INT_RO 0x0064 #define XP_DRIVER_SCRATCH_0 0x0068 #define XP_DRIVER_SCRATCH_1 0x006c +#define XP_INT_REISSUE_EN 0x0074 #define XP_INT_EN 0x0078 #define XP_I2C_MUTEX 0x0080 #define XP_MDIO_MUTEX 0x0084 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 20685100ce12..ff6d20496526 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -382,9 +382,9 @@ static bool xgbe_ecc_ded(struct xgbe_prv_data *pdata, unsigned long *period, return false; } -static irqreturn_t xgbe_ecc_isr(int irq, void *data) +static void xgbe_ecc_isr_task(unsigned long data) { - struct xgbe_prv_data *pdata = data; + struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; unsigned int ecc_isr; bool stop = false; @@ -435,12 +435,26 @@ out: /* Clear all ECC interrupts */ XP_IOWRITE(pdata, XP_ECC_ISR, ecc_isr); - return IRQ_HANDLED; + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 1); } -static irqreturn_t xgbe_isr(int irq, void *data) +static irqreturn_t xgbe_ecc_isr(int irq, void *data) { struct xgbe_prv_data *pdata = data; + + if (pdata->isr_as_tasklet) + tasklet_schedule(&pdata->tasklet_ecc); + else + xgbe_ecc_isr_task((unsigned long)pdata); + + return IRQ_HANDLED; +} + +static void xgbe_isr_task(unsigned long data) +{ + struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_channel *channel; unsigned int dma_isr, dma_ch_isr; @@ -543,15 +557,36 @@ static irqreturn_t xgbe_isr(int irq, void *data) isr_done: /* If there is not a separate AN irq, handle it here */ if (pdata->dev_irq == pdata->an_irq) - pdata->phy_if.an_isr(irq, pdata); + pdata->phy_if.an_isr(pdata); /* If there is not a separate ECC irq, handle it here */ if (pdata->vdata->ecc_support && (pdata->dev_irq == pdata->ecc_irq)) - xgbe_ecc_isr(irq, pdata); + xgbe_ecc_isr_task((unsigned long)pdata); /* If there is not a separate I2C irq, handle it here */ if (pdata->vdata->i2c_support && (pdata->dev_irq == pdata->i2c_irq)) - pdata->i2c_if.i2c_isr(irq, pdata); + pdata->i2c_if.i2c_isr(pdata); + + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) { + unsigned int reissue_mask; + + reissue_mask = 1 << 0; + if (!pdata->per_channel_irq) + reissue_mask |= 0xffff < 4; + + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, reissue_mask); + } +} + +static irqreturn_t xgbe_isr(int irq, void *data) +{ + struct xgbe_prv_data *pdata = data; + + if (pdata->isr_as_tasklet) + tasklet_schedule(&pdata->tasklet_dev); + else + xgbe_isr_task((unsigned long)pdata); return IRQ_HANDLED; } @@ -826,6 +861,10 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata) unsigned int i; int ret; + tasklet_init(&pdata->tasklet_dev, xgbe_isr_task, (unsigned long)pdata); + tasklet_init(&pdata->tasklet_ecc, xgbe_ecc_isr_task, + (unsigned long)pdata); + ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0, netdev->name, pdata); if (ret) { diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c index 417bdb5982a9..4d9062d35930 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c @@ -274,13 +274,16 @@ static void xgbe_i2c_clear_isr_interrupts(struct xgbe_prv_data *pdata, XI2C_IOREAD(pdata, IC_CLR_STOP_DET); } -static irqreturn_t xgbe_i2c_isr(int irq, void *data) +static void xgbe_i2c_isr_task(unsigned long data) { struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; struct xgbe_i2c_op_state *state = &pdata->i2c.op_state; unsigned int isr; isr = XI2C_IOREAD(pdata, IC_RAW_INTR_STAT); + if (!isr) + goto reissue_check; + netif_dbg(pdata, intr, pdata->netdev, "I2C interrupt received: status=%#010x\n", isr); @@ -308,6 +311,21 @@ out: if (state->ret || XI2C_GET_BITS(isr, IC_RAW_INTR_STAT, STOP_DET)) complete(&pdata->i2c_complete); +reissue_check: + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 2); +} + +static irqreturn_t xgbe_i2c_isr(int irq, void *data) +{ + struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; + + if (pdata->isr_as_tasklet) + tasklet_schedule(&pdata->tasklet_i2c); + else + xgbe_i2c_isr_task((unsigned long)pdata); + return IRQ_HANDLED; } @@ -349,12 +367,11 @@ static void xgbe_i2c_set_target(struct xgbe_prv_data *pdata, unsigned int addr) XI2C_IOWRITE(pdata, IC_TAR, addr); } -static irqreturn_t xgbe_i2c_combined_isr(int irq, struct xgbe_prv_data *pdata) +static irqreturn_t xgbe_i2c_combined_isr(struct xgbe_prv_data *pdata) { - if (!XI2C_IOREAD(pdata, IC_RAW_INTR_STAT)) - return IRQ_HANDLED; + xgbe_i2c_isr_task((unsigned long)pdata); - return xgbe_i2c_isr(irq, pdata); + return IRQ_HANDLED; } static int xgbe_i2c_xfer(struct xgbe_prv_data *pdata, struct xgbe_i2c_op *op) @@ -445,6 +462,9 @@ static int xgbe_i2c_start(struct xgbe_prv_data *pdata) /* If we have a separate I2C irq, enable it */ if (pdata->dev_irq != pdata->i2c_irq) { + tasklet_init(&pdata->tasklet_i2c, xgbe_i2c_isr_task, + (unsigned long)pdata); + ret = devm_request_irq(pdata->dev, pdata->i2c_irq, xgbe_i2c_isr, 0, pdata->i2c_name, pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index b672d9249539..80684914dd8a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -665,6 +665,10 @@ static void xgbe_an37_isr(struct xgbe_prv_data *pdata) } else { /* Enable AN interrupts */ xgbe_an37_enable_interrupts(pdata); + + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); } } @@ -684,10 +688,14 @@ static void xgbe_an73_isr(struct xgbe_prv_data *pdata) } else { /* Enable AN interrupts */ xgbe_an73_enable_interrupts(pdata); + + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); } } -static irqreturn_t xgbe_an_isr(int irq, void *data) +static void xgbe_an_isr_task(unsigned long data) { struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; @@ -705,13 +713,25 @@ static irqreturn_t xgbe_an_isr(int irq, void *data) default: break; } +} + +static irqreturn_t xgbe_an_isr(int irq, void *data) +{ + struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; + + if (pdata->isr_as_tasklet) + tasklet_schedule(&pdata->tasklet_an); + else + xgbe_an_isr_task((unsigned long)pdata); return IRQ_HANDLED; } -static irqreturn_t xgbe_an_combined_isr(int irq, struct xgbe_prv_data *pdata) +static irqreturn_t xgbe_an_combined_isr(struct xgbe_prv_data *pdata) { - return xgbe_an_isr(irq, pdata); + xgbe_an_isr_task((unsigned long)pdata); + + return IRQ_HANDLED; } static void xgbe_an_irq_work(struct work_struct *work) @@ -915,6 +935,10 @@ static void xgbe_an_state_machine(struct work_struct *work) break; } + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); + mutex_unlock(&pdata->an_mutex); } @@ -1379,6 +1403,9 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata) /* If we have a separate AN irq, enable it */ if (pdata->dev_irq != pdata->an_irq) { + tasklet_init(&pdata->tasklet_an, xgbe_an_isr_task, + (unsigned long)pdata); + ret = devm_request_irq(pdata->dev, pdata->an_irq, xgbe_an_isr, 0, pdata->an_name, pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index 38392a520725..f0c2e88a5037 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -139,6 +139,7 @@ static int xgbe_config_multi_msi(struct xgbe_prv_data *pdata) return ret; } + pdata->isr_as_tasklet = 1; pdata->irq_count = ret; pdata->dev_irq = pci_irq_vector(pdata->pcidev, 0); @@ -175,6 +176,7 @@ static int xgbe_config_irqs(struct xgbe_prv_data *pdata) return ret; } + pdata->isr_as_tasklet = pdata->pcidev->msi_enabled ? 1 : 0; pdata->irq_count = 1; pdata->channel_irq_count = 1; @@ -445,6 +447,7 @@ static const struct xgbe_version_data xgbe_v2a = { .tx_tstamp_workaround = 1, .ecc_support = 1, .i2c_support = 1, + .irq_reissue_support = 1, }; static const struct xgbe_version_data xgbe_v2b = { @@ -456,6 +459,7 @@ static const struct xgbe_version_data xgbe_v2b = { .tx_tstamp_workaround = 1, .ecc_support = 1, .i2c_support = 1, + .irq_reissue_support = 1, }; static const struct pci_device_id xgbe_pci_table[] = { diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index f9a24639f574..2834961a9c25 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -837,7 +837,7 @@ struct xgbe_phy_if { bool (*phy_valid_speed)(struct xgbe_prv_data *, int); /* For single interrupt support */ - irqreturn_t (*an_isr)(int, struct xgbe_prv_data *); + irqreturn_t (*an_isr)(struct xgbe_prv_data *); /* PHY implementation specific services */ struct xgbe_phy_impl_if phy_impl; @@ -855,7 +855,7 @@ struct xgbe_i2c_if { int (*i2c_xfer)(struct xgbe_prv_data *, struct xgbe_i2c_op *); /* For single interrupt support */ - irqreturn_t (*i2c_isr)(int, struct xgbe_prv_data *); + irqreturn_t (*i2c_isr)(struct xgbe_prv_data *); }; struct xgbe_desc_if { @@ -924,6 +924,7 @@ struct xgbe_version_data { unsigned int tx_tstamp_workaround; unsigned int ecc_support; unsigned int i2c_support; + unsigned int irq_reissue_support; }; struct xgbe_prv_data { @@ -1159,6 +1160,12 @@ struct xgbe_prv_data { unsigned int lpm_ctrl; /* CTRL1 for resume */ + unsigned int isr_as_tasklet; + struct tasklet_struct tasklet_dev; + struct tasklet_struct tasklet_ecc; + struct tasklet_struct tasklet_i2c; + struct tasklet_struct tasklet_an; + #ifdef CONFIG_DEBUG_FS struct dentry *xgbe_debugfs; -- cgit v1.2.3 From 18f9f0ac55629b298b1e975c4ed1c86aa21eafb0 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:42:51 -0500 Subject: amd-xgbe: Add NUMA affinity support for memory allocations Add support to perform memory allocations on the node of the device. The original allocation or the ring structure and Tx/Rx queues allocated all of the memory at once and then carved it up for each channel and queue. To best ensure that we get as much memory from the NUMA node as we can, break the channel and ring allocations into individual allocations. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 94 +++++++++++----- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 135 +++++++++-------------- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 177 ++++++++++++++++-------------- drivers/net/ethernet/amd/xgbe/xgbe.h | 5 +- 4 files changed, 217 insertions(+), 194 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index 0a98c369df20..45d92304068e 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -176,8 +176,8 @@ static void xgbe_free_ring_resources(struct xgbe_prv_data *pdata) DBGPR("-->xgbe_free_ring_resources\n"); - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; xgbe_free_ring(pdata, channel->tx_ring); xgbe_free_ring(pdata, channel->rx_ring); } @@ -185,34 +185,60 @@ static void xgbe_free_ring_resources(struct xgbe_prv_data *pdata) DBGPR("<--xgbe_free_ring_resources\n"); } +static void *xgbe_alloc_node(size_t size, int node) +{ + void *mem; + + mem = kzalloc_node(size, GFP_KERNEL, node); + if (!mem) + mem = kzalloc(size, GFP_KERNEL); + + return mem; +} + +static void *xgbe_dma_alloc_node(struct device *dev, size_t size, + dma_addr_t *dma, int node) +{ + void *mem; + int cur_node = dev_to_node(dev); + + set_dev_node(dev, node); + mem = dma_alloc_coherent(dev, size, dma, GFP_KERNEL); + set_dev_node(dev, cur_node); + + if (!mem) + mem = dma_alloc_coherent(dev, size, dma, GFP_KERNEL); + + return mem; +} + static int xgbe_init_ring(struct xgbe_prv_data *pdata, struct xgbe_ring *ring, unsigned int rdesc_count) { - DBGPR("-->xgbe_init_ring\n"); + size_t size; if (!ring) return 0; /* Descriptors */ + size = rdesc_count * sizeof(struct xgbe_ring_desc); + ring->rdesc_count = rdesc_count; - ring->rdesc = dma_alloc_coherent(pdata->dev, - (sizeof(struct xgbe_ring_desc) * - rdesc_count), &ring->rdesc_dma, - GFP_KERNEL); + ring->rdesc = xgbe_dma_alloc_node(pdata->dev, size, &ring->rdesc_dma, + ring->node); if (!ring->rdesc) return -ENOMEM; /* Descriptor information */ - ring->rdata = kcalloc(rdesc_count, sizeof(struct xgbe_ring_data), - GFP_KERNEL); + size = rdesc_count * sizeof(struct xgbe_ring_data); + + ring->rdata = xgbe_alloc_node(size, ring->node); if (!ring->rdata) return -ENOMEM; netif_dbg(pdata, drv, pdata->netdev, - "rdesc=%p, rdesc_dma=%pad, rdata=%p\n", - ring->rdesc, &ring->rdesc_dma, ring->rdata); - - DBGPR("<--xgbe_init_ring\n"); + "rdesc=%p, rdesc_dma=%pad, rdata=%p, node=%d\n", + ring->rdesc, &ring->rdesc_dma, ring->rdata, ring->node); return 0; } @@ -223,10 +249,8 @@ static int xgbe_alloc_ring_resources(struct xgbe_prv_data *pdata) unsigned int i; int ret; - DBGPR("-->xgbe_alloc_ring_resources\n"); - - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; netif_dbg(pdata, drv, pdata->netdev, "%s - Tx ring:\n", channel->name); @@ -250,8 +274,6 @@ static int xgbe_alloc_ring_resources(struct xgbe_prv_data *pdata) } } - DBGPR("<--xgbe_alloc_ring_resources\n"); - return 0; err_ring: @@ -261,21 +283,33 @@ err_ring: } static int xgbe_alloc_pages(struct xgbe_prv_data *pdata, - struct xgbe_page_alloc *pa, gfp_t gfp, int order) + struct xgbe_page_alloc *pa, int alloc_order, + int node) { struct page *pages = NULL; dma_addr_t pages_dma; - int ret; + gfp_t gfp; + int order, ret; + +again: + order = alloc_order; /* Try to obtain pages, decreasing order if necessary */ - gfp |= __GFP_COLD | __GFP_COMP | __GFP_NOWARN; + gfp = GFP_ATOMIC | __GFP_COLD | __GFP_COMP | __GFP_NOWARN; while (order >= 0) { - pages = alloc_pages(gfp, order); + pages = alloc_pages_node(node, gfp, order); if (pages) break; order--; } + + /* If we couldn't get local pages, try getting from anywhere */ + if (!pages && (node != NUMA_NO_NODE)) { + node = NUMA_NO_NODE; + goto again; + } + if (!pages) return -ENOMEM; @@ -327,14 +361,14 @@ static int xgbe_map_rx_buffer(struct xgbe_prv_data *pdata, int ret; if (!ring->rx_hdr_pa.pages) { - ret = xgbe_alloc_pages(pdata, &ring->rx_hdr_pa, GFP_ATOMIC, 0); + ret = xgbe_alloc_pages(pdata, &ring->rx_hdr_pa, 0, ring->node); if (ret) return ret; } if (!ring->rx_buf_pa.pages) { - ret = xgbe_alloc_pages(pdata, &ring->rx_buf_pa, GFP_ATOMIC, - PAGE_ALLOC_COSTLY_ORDER); + ret = xgbe_alloc_pages(pdata, &ring->rx_buf_pa, + PAGE_ALLOC_COSTLY_ORDER, ring->node); if (ret) return ret; } @@ -362,8 +396,8 @@ static void xgbe_wrapper_tx_descriptor_init(struct xgbe_prv_data *pdata) DBGPR("-->xgbe_wrapper_tx_descriptor_init\n"); - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; ring = channel->tx_ring; if (!ring) break; @@ -403,8 +437,8 @@ static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata) DBGPR("-->xgbe_wrapper_rx_descriptor_init\n"); - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; ring = channel->rx_ring; if (!ring) break; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 3ad4036fb6d9..b05393f0ff0a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -176,12 +176,10 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata, static int xgbe_config_pblx8(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_CR, PBLX8, + for (i = 0; i < pdata->channel_count; i++) + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, PBLX8, pdata->pblx8); return 0; @@ -189,20 +187,18 @@ static int xgbe_config_pblx8(struct xgbe_prv_data *pdata) static int xgbe_get_tx_pbl_val(struct xgbe_prv_data *pdata) { - return XGMAC_DMA_IOREAD_BITS(pdata->channel, DMA_CH_TCR, PBL); + return XGMAC_DMA_IOREAD_BITS(pdata->channel[0], DMA_CH_TCR, PBL); } static int xgbe_config_tx_pbl_val(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->tx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->tx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, PBL, + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, PBL, pdata->tx_pbl); } @@ -211,20 +207,18 @@ static int xgbe_config_tx_pbl_val(struct xgbe_prv_data *pdata) static int xgbe_get_rx_pbl_val(struct xgbe_prv_data *pdata) { - return XGMAC_DMA_IOREAD_BITS(pdata->channel, DMA_CH_RCR, PBL); + return XGMAC_DMA_IOREAD_BITS(pdata->channel[0], DMA_CH_RCR, PBL); } static int xgbe_config_rx_pbl_val(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->rx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->rx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, PBL, + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, PBL, pdata->rx_pbl); } @@ -233,15 +227,13 @@ static int xgbe_config_rx_pbl_val(struct xgbe_prv_data *pdata) static int xgbe_config_osp_mode(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->tx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->tx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, OSP, + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, OSP, pdata->tx_osp_mode); } @@ -292,15 +284,13 @@ static int xgbe_config_tx_threshold(struct xgbe_prv_data *pdata, static int xgbe_config_rx_coalesce(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->rx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->rx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RIWT, RWT, + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RIWT, RWT, pdata->rx_riwt); } @@ -314,44 +304,38 @@ static int xgbe_config_tx_coalesce(struct xgbe_prv_data *pdata) static void xgbe_config_rx_buffer_size(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->rx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->rx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, RBSZ, + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, RBSZ, pdata->rx_buf_size); } } static void xgbe_config_tso_mode(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->tx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->tx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, TSE, 1); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, TSE, 1); } } static void xgbe_config_sph_mode(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->rx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->rx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_CR, SPH, 1); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, SPH, 1); } XGMAC_IOWRITE_BITS(pdata, MAC_RCR, HDSMS, XGBE_SPH_HDSMS_SIZE); @@ -651,8 +635,9 @@ static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata) XGMAC_IOWRITE_BITS(pdata, DMA_MR, INTM, pdata->channel_irq_mode); - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; + /* Clear all the interrupts which are set */ dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); XGMAC_DMA_IOWRITE(channel, DMA_CH_SR, dma_ch_isr); @@ -3213,16 +3198,14 @@ static void xgbe_prepare_tx_stop(struct xgbe_prv_data *pdata, static void xgbe_enable_tx(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; /* Enable each Tx DMA channel */ - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->tx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->tx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, ST, 1); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, ST, 1); } /* Enable each Tx queue */ @@ -3236,7 +3219,6 @@ static void xgbe_enable_tx(struct xgbe_prv_data *pdata) static void xgbe_disable_tx(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; /* Prepare for Tx DMA channel stop */ @@ -3251,12 +3233,11 @@ static void xgbe_disable_tx(struct xgbe_prv_data *pdata) XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN, 0); /* Disable each Tx DMA channel */ - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->tx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->tx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, ST, 0); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, ST, 0); } } @@ -3288,16 +3269,14 @@ static void xgbe_prepare_rx_stop(struct xgbe_prv_data *pdata, static void xgbe_enable_rx(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int reg_val, i; /* Enable each Rx DMA channel */ - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->rx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->rx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, SR, 1); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, SR, 1); } /* Enable each Rx queue */ @@ -3315,7 +3294,6 @@ static void xgbe_enable_rx(struct xgbe_prv_data *pdata) static void xgbe_disable_rx(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; /* Disable MAC Rx */ @@ -3332,27 +3310,24 @@ static void xgbe_disable_rx(struct xgbe_prv_data *pdata) XGMAC_IOWRITE(pdata, MAC_RQC0R, 0); /* Disable each Rx DMA channel */ - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->rx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->rx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, SR, 0); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, SR, 0); } } static void xgbe_powerup_tx(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; /* Enable each Tx DMA channel */ - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->tx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->tx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, ST, 1); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, ST, 1); } /* Enable MAC Tx */ @@ -3361,7 +3336,6 @@ static void xgbe_powerup_tx(struct xgbe_prv_data *pdata) static void xgbe_powerdown_tx(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; /* Prepare for Tx DMA channel stop */ @@ -3372,42 +3346,37 @@ static void xgbe_powerdown_tx(struct xgbe_prv_data *pdata) XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0); /* Disable each Tx DMA channel */ - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->tx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->tx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, ST, 0); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, ST, 0); } } static void xgbe_powerup_rx(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; /* Enable each Rx DMA channel */ - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->rx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->rx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, SR, 1); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, SR, 1); } } static void xgbe_powerdown_rx(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; /* Disable each Rx DMA channel */ - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - if (!channel->rx_ring) + for (i = 0; i < pdata->channel_count; i++) { + if (!pdata->channel[i]->rx_ring) break; - XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, SR, 0); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, SR, 0); } } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index ff6d20496526..43b84ff0b621 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -158,81 +158,100 @@ static int xgbe_one_poll(struct napi_struct *, int); static int xgbe_all_poll(struct napi_struct *, int); static void xgbe_stop(struct xgbe_prv_data *); -static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) +static void *xgbe_alloc_node(size_t size, int node) { - struct xgbe_channel *channel_mem, *channel; - struct xgbe_ring *tx_ring, *rx_ring; - unsigned int count, i; - int ret = -ENOMEM; + void *mem; - count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count); + mem = kzalloc_node(size, GFP_KERNEL, node); + if (!mem) + mem = kzalloc(size, GFP_KERNEL); + + return mem; +} + +static void xgbe_free_channels(struct xgbe_prv_data *pdata) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pdata->channel); i++) { + if (!pdata->channel[i]) + continue; + + kfree(pdata->channel[i]->rx_ring); + kfree(pdata->channel[i]->tx_ring); + kfree(pdata->channel[i]); + + pdata->channel[i] = NULL; + } - channel_mem = kcalloc(count, sizeof(struct xgbe_channel), GFP_KERNEL); - if (!channel_mem) - goto err_channel; + pdata->channel_count = 0; +} + +static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) +{ + struct xgbe_channel *channel; + struct xgbe_ring *ring; + unsigned int count, i; + int node; - tx_ring = kcalloc(pdata->tx_ring_count, sizeof(struct xgbe_ring), - GFP_KERNEL); - if (!tx_ring) - goto err_tx_ring; + node = dev_to_node(pdata->dev); - rx_ring = kcalloc(pdata->rx_ring_count, sizeof(struct xgbe_ring), - GFP_KERNEL); - if (!rx_ring) - goto err_rx_ring; + count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count); + for (i = 0; i < count; i++) { + channel = xgbe_alloc_node(sizeof(*channel), node); + if (!channel) + goto err_mem; + pdata->channel[i] = channel; - for (i = 0, channel = channel_mem; i < count; i++, channel++) { snprintf(channel->name, sizeof(channel->name), "channel-%u", i); channel->pdata = pdata; channel->queue_index = i; channel->dma_regs = pdata->xgmac_regs + DMA_CH_BASE + (DMA_CH_INC * i); + channel->node = node; if (pdata->per_channel_irq) channel->dma_irq = pdata->channel_irq[i]; if (i < pdata->tx_ring_count) { - spin_lock_init(&tx_ring->lock); - channel->tx_ring = tx_ring++; + ring = xgbe_alloc_node(sizeof(*ring), node); + if (!ring) + goto err_mem; + + spin_lock_init(&ring->lock); + ring->node = node; + + channel->tx_ring = ring; } if (i < pdata->rx_ring_count) { - spin_lock_init(&rx_ring->lock); - channel->rx_ring = rx_ring++; + ring = xgbe_alloc_node(sizeof(*ring), node); + if (!ring) + goto err_mem; + + spin_lock_init(&ring->lock); + ring->node = node; + + channel->rx_ring = ring; } + netif_dbg(pdata, drv, pdata->netdev, + "%s: node=%d\n", channel->name, node); + netif_dbg(pdata, drv, pdata->netdev, "%s: dma_regs=%p, dma_irq=%d, tx=%p, rx=%p\n", channel->name, channel->dma_regs, channel->dma_irq, channel->tx_ring, channel->rx_ring); } - pdata->channel = channel_mem; pdata->channel_count = count; return 0; -err_rx_ring: - kfree(tx_ring); - -err_tx_ring: - kfree(channel_mem); - -err_channel: - return ret; -} - -static void xgbe_free_channels(struct xgbe_prv_data *pdata) -{ - if (!pdata->channel) - return; - - kfree(pdata->channel->rx_ring); - kfree(pdata->channel->tx_ring); - kfree(pdata->channel); +err_mem: + xgbe_free_channels(pdata); - pdata->channel = NULL; - pdata->channel_count = 0; + return -ENOMEM; } static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring) @@ -301,12 +320,10 @@ static void xgbe_enable_rx_tx_int(struct xgbe_prv_data *pdata, static void xgbe_enable_rx_tx_ints(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) - xgbe_enable_rx_tx_int(pdata, channel); + for (i = 0; i < pdata->channel_count; i++) + xgbe_enable_rx_tx_int(pdata, pdata->channel[i]); } static void xgbe_disable_rx_tx_int(struct xgbe_prv_data *pdata, @@ -329,12 +346,10 @@ static void xgbe_disable_rx_tx_int(struct xgbe_prv_data *pdata, static void xgbe_disable_rx_tx_ints(struct xgbe_prv_data *pdata) { - struct xgbe_channel *channel; unsigned int i; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) - xgbe_disable_rx_tx_int(pdata, channel); + for (i = 0; i < pdata->channel_count; i++) + xgbe_disable_rx_tx_int(pdata, pdata->channel[i]); } static bool xgbe_ecc_sec(struct xgbe_prv_data *pdata, unsigned long *period, @@ -475,7 +490,7 @@ static void xgbe_isr_task(unsigned long data) if (!(dma_isr & (1 << i))) continue; - channel = pdata->channel + i; + channel = pdata->channel[i]; dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); netif_dbg(pdata, intr, pdata->netdev, "DMA_CH%u_ISR=%#010x\n", @@ -675,8 +690,8 @@ static void xgbe_init_timers(struct xgbe_prv_data *pdata) setup_timer(&pdata->service_timer, xgbe_service_timer, (unsigned long)pdata); - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; if (!channel->tx_ring) break; @@ -697,8 +712,8 @@ static void xgbe_stop_timers(struct xgbe_prv_data *pdata) del_timer_sync(&pdata->service_timer); - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; if (!channel->tx_ring) break; @@ -816,8 +831,8 @@ static void xgbe_napi_enable(struct xgbe_prv_data *pdata, unsigned int add) unsigned int i; if (pdata->per_channel_irq) { - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; if (add) netif_napi_add(pdata->netdev, &channel->napi, xgbe_one_poll, NAPI_POLL_WEIGHT); @@ -839,8 +854,8 @@ static void xgbe_napi_disable(struct xgbe_prv_data *pdata, unsigned int del) unsigned int i; if (pdata->per_channel_irq) { - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; napi_disable(&channel->napi); if (del) @@ -886,8 +901,8 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata) if (!pdata->per_channel_irq) return 0; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; snprintf(channel->dma_irq_name, sizeof(channel->dma_irq_name) - 1, "%s-TxRx-%u", netdev_name(netdev), @@ -907,8 +922,11 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata) err_dma_irq: /* Using an unsigned int, 'i' will go to UINT_MAX and exit */ - for (i--, channel--; i < pdata->channel_count; i--, channel--) + for (i--; i < pdata->channel_count; i--) { + channel = pdata->channel[i]; + devm_free_irq(pdata->dev, channel->dma_irq, channel); + } if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq)) devm_free_irq(pdata->dev, pdata->ecc_irq, pdata); @@ -932,9 +950,10 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata) if (!pdata->per_channel_irq) return; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; devm_free_irq(pdata->dev, channel->dma_irq, channel); + } } void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata) @@ -969,16 +988,14 @@ void xgbe_init_rx_coalesce(struct xgbe_prv_data *pdata) static void xgbe_free_tx_data(struct xgbe_prv_data *pdata) { struct xgbe_desc_if *desc_if = &pdata->desc_if; - struct xgbe_channel *channel; struct xgbe_ring *ring; struct xgbe_ring_data *rdata; unsigned int i, j; DBGPR("-->xgbe_free_tx_data\n"); - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - ring = channel->tx_ring; + for (i = 0; i < pdata->channel_count; i++) { + ring = pdata->channel[i]->tx_ring; if (!ring) break; @@ -994,16 +1011,14 @@ static void xgbe_free_tx_data(struct xgbe_prv_data *pdata) static void xgbe_free_rx_data(struct xgbe_prv_data *pdata) { struct xgbe_desc_if *desc_if = &pdata->desc_if; - struct xgbe_channel *channel; struct xgbe_ring *ring; struct xgbe_ring_data *rdata; unsigned int i, j; DBGPR("-->xgbe_free_rx_data\n"); - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { - ring = channel->rx_ring; + for (i = 0; i < pdata->channel_count; i++) { + ring = pdata->channel[i]->rx_ring; if (!ring) break; @@ -1179,8 +1194,8 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) hw_if->exit(pdata); - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; if (!channel->tx_ring) continue; @@ -1667,7 +1682,7 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len); - channel = pdata->channel + skb->queue_mapping; + channel = pdata->channel[skb->queue_mapping]; txq = netdev_get_tx_queue(netdev, channel->queue_index); ring = channel->tx_ring; packet = &ring->packet_data; @@ -1877,9 +1892,10 @@ static void xgbe_poll_controller(struct net_device *netdev) DBGPR("-->xgbe_poll_controller\n"); if (pdata->per_channel_irq) { - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; xgbe_dma_isr(channel->dma_irq, channel); + } } else { disable_irq(pdata->dev_irq); xgbe_isr(pdata->dev_irq, pdata); @@ -2372,8 +2388,9 @@ static int xgbe_all_poll(struct napi_struct *napi, int budget) do { last_processed = processed; - channel = pdata->channel; - for (i = 0; i < pdata->channel_count; i++, channel++) { + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel[i]; + /* Cleanup Tx ring first */ xgbe_tx_poll(channel); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 2834961a9c25..ac3b5588b845 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -412,6 +412,7 @@ struct xgbe_ring { /* Page allocation for RX buffers */ struct xgbe_page_alloc rx_hdr_pa; struct xgbe_page_alloc rx_buf_pa; + int node; /* Ring index values * cur - Tx: index of descriptor to be used for current transfer @@ -462,6 +463,8 @@ struct xgbe_channel { struct xgbe_ring *tx_ring; struct xgbe_ring *rx_ring; + + int node; } ____cacheline_aligned; enum xgbe_state { @@ -1012,7 +1015,7 @@ struct xgbe_prv_data { struct timer_list service_timer; /* Rings for Tx/Rx on a DMA channel */ - struct xgbe_channel *channel; + struct xgbe_channel *channel[XGBE_MAX_DMA_CHANNELS]; unsigned int tx_max_channel_count; unsigned int rx_max_channel_count; unsigned int channel_count; -- cgit v1.2.3 From f00ba49d8ef9b7a8a9f17be4128fad397e42683b Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:43:00 -0500 Subject: amd-xgbe: Add NUMA affinity support for IRQ hints For IRQ affinity, set the affinity hints for the IRQs to be (initially) on the processors corresponding to the NUMA node of the device. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 18 +++++++++++++++--- drivers/net/ethernet/amd/xgbe/xgbe.h | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 43b84ff0b621..ecef3ee87b17 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -192,12 +192,17 @@ static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) struct xgbe_channel *channel; struct xgbe_ring *ring; unsigned int count, i; + unsigned int cpu; int node; - node = dev_to_node(pdata->dev); - count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count); for (i = 0; i < count; i++) { + /* Attempt to use a CPU on the node the device is on */ + cpu = cpumask_local_spread(i, dev_to_node(pdata->dev)); + + /* Set the allocation node based on the returned CPU */ + node = cpu_to_node(cpu); + channel = xgbe_alloc_node(sizeof(*channel), node); if (!channel) goto err_mem; @@ -209,6 +214,7 @@ static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) channel->dma_regs = pdata->xgmac_regs + DMA_CH_BASE + (DMA_CH_INC * i); channel->node = node; + cpumask_set_cpu(cpu, &channel->affinity_mask); if (pdata->per_channel_irq) channel->dma_irq = pdata->channel_irq[i]; @@ -236,7 +242,7 @@ static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) } netif_dbg(pdata, drv, pdata->netdev, - "%s: node=%d\n", channel->name, node); + "%s: cpu=%u, node=%d\n", channel->name, cpu, node); netif_dbg(pdata, drv, pdata->netdev, "%s: dma_regs=%p, dma_irq=%d, tx=%p, rx=%p\n", @@ -916,6 +922,9 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata) channel->dma_irq); goto err_dma_irq; } + + irq_set_affinity_hint(channel->dma_irq, + &channel->affinity_mask); } return 0; @@ -925,6 +934,7 @@ err_dma_irq: for (i--; i < pdata->channel_count; i--) { channel = pdata->channel[i]; + irq_set_affinity_hint(channel->dma_irq, NULL); devm_free_irq(pdata->dev, channel->dma_irq, channel); } @@ -952,6 +962,8 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata) for (i = 0; i < pdata->channel_count; i++) { channel = pdata->channel[i]; + + irq_set_affinity_hint(channel->dma_irq, NULL); devm_free_irq(pdata->dev, channel->dma_irq, channel); } } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index ac3b5588b845..7b50469c77a0 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -128,6 +128,7 @@ #include #include #include +#include #define XGBE_DRV_NAME "amd-xgbe" #define XGBE_DRV_VERSION "1.0.3" @@ -465,6 +466,7 @@ struct xgbe_channel { struct xgbe_ring *rx_ring; int node; + cpumask_t affinity_mask; } ____cacheline_aligned; enum xgbe_state { -- cgit v1.2.3 From 9916716a1bb677be8371f602f53989bf04a70d7f Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:43:09 -0500 Subject: amd-xgbe: Prepare for more fine grained cache coherency controls In prep for setting fine grained read and write DMA cache coherency controls, allow specific values to be used to set the cache coherency registers. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 28 --------------------------- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 23 ++-------------------- drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 5 ++--- drivers/net/ethernet/amd/xgbe/xgbe-platform.c | 10 ++++------ drivers/net/ethernet/amd/xgbe/xgbe.h | 15 ++++++-------- 5 files changed, 14 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index e7b68043d627..dc098832e0fe 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -127,34 +127,6 @@ #define DMA_DSR1 0x3024 /* DMA register entry bit positions and sizes */ -#define DMA_AXIARCR_DRC_INDEX 0 -#define DMA_AXIARCR_DRC_WIDTH 4 -#define DMA_AXIARCR_DRD_INDEX 4 -#define DMA_AXIARCR_DRD_WIDTH 2 -#define DMA_AXIARCR_TEC_INDEX 8 -#define DMA_AXIARCR_TEC_WIDTH 4 -#define DMA_AXIARCR_TED_INDEX 12 -#define DMA_AXIARCR_TED_WIDTH 2 -#define DMA_AXIARCR_THC_INDEX 16 -#define DMA_AXIARCR_THC_WIDTH 4 -#define DMA_AXIARCR_THD_INDEX 20 -#define DMA_AXIARCR_THD_WIDTH 2 -#define DMA_AXIAWCR_DWC_INDEX 0 -#define DMA_AXIAWCR_DWC_WIDTH 4 -#define DMA_AXIAWCR_DWD_INDEX 4 -#define DMA_AXIAWCR_DWD_WIDTH 2 -#define DMA_AXIAWCR_RPC_INDEX 8 -#define DMA_AXIAWCR_RPC_WIDTH 4 -#define DMA_AXIAWCR_RPD_INDEX 12 -#define DMA_AXIAWCR_RPD_WIDTH 2 -#define DMA_AXIAWCR_RHC_INDEX 16 -#define DMA_AXIAWCR_RHC_WIDTH 4 -#define DMA_AXIAWCR_RHD_INDEX 20 -#define DMA_AXIAWCR_RHD_WIDTH 2 -#define DMA_AXIAWCR_TDC_INDEX 24 -#define DMA_AXIAWCR_TDC_WIDTH 4 -#define DMA_AXIAWCR_TDD_INDEX 28 -#define DMA_AXIAWCR_TDD_WIDTH 2 #define DMA_ISR_MACIS_INDEX 17 #define DMA_ISR_MACIS_WIDTH 1 #define DMA_ISR_MTLIS_INDEX 16 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index b05393f0ff0a..98da24964f1f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -2146,27 +2146,8 @@ static void xgbe_config_dma_bus(struct xgbe_prv_data *pdata) static void xgbe_config_dma_cache(struct xgbe_prv_data *pdata) { - unsigned int arcache, awcache; - - arcache = 0; - XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRC, pdata->arcache); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRD, pdata->axdomain); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, TEC, pdata->arcache); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, TED, pdata->axdomain); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, THC, pdata->arcache); - XGMAC_SET_BITS(arcache, DMA_AXIARCR, THD, pdata->axdomain); - XGMAC_IOWRITE(pdata, DMA_AXIARCR, arcache); - - awcache = 0; - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWC, pdata->awcache); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWD, pdata->axdomain); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPC, pdata->awcache); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPD, pdata->axdomain); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHC, pdata->awcache); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHD, pdata->axdomain); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDC, pdata->awcache); - XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDD, pdata->axdomain); - XGMAC_IOWRITE(pdata, DMA_AXIAWCR, awcache); + XGMAC_IOWRITE(pdata, DMA_AXIARCR, pdata->arcr); + XGMAC_IOWRITE(pdata, DMA_AXIAWCR, pdata->awcr); } static void xgbe_config_mtl_mode(struct xgbe_prv_data *pdata) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index f0c2e88a5037..1e7376887568 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -327,9 +327,8 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Set the DMA coherency values */ pdata->coherent = 1; - pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; - pdata->arcache = XGBE_DMA_OS_ARCACHE; - pdata->awcache = XGBE_DMA_OS_AWCACHE; + pdata->arcr = XGBE_DMA_OS_ARCR; + pdata->awcr = XGBE_DMA_OS_AWCR; /* Set the maximum channels and queues */ reg = XP_IOREAD(pdata, XP_PROP_1); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-platform.c b/drivers/net/ethernet/amd/xgbe/xgbe-platform.c index 84d4c51cab8c..d0f3dfb88202 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-platform.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-platform.c @@ -448,13 +448,11 @@ static int xgbe_platform_probe(struct platform_device *pdev) } pdata->coherent = (attr == DEV_DMA_COHERENT); if (pdata->coherent) { - pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; - pdata->arcache = XGBE_DMA_OS_ARCACHE; - pdata->awcache = XGBE_DMA_OS_AWCACHE; + pdata->arcr = XGBE_DMA_OS_ARCR; + pdata->awcr = XGBE_DMA_OS_AWCR; } else { - pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN; - pdata->arcache = XGBE_DMA_SYS_ARCACHE; - pdata->awcache = XGBE_DMA_SYS_AWCACHE; + pdata->arcr = XGBE_DMA_SYS_ARCR; + pdata->awcr = XGBE_DMA_SYS_AWCR; } /* Set the maximum fifo amounts */ diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 7b50469c77a0..46780aa74301 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -164,14 +164,12 @@ #define XGBE_DMA_STOP_TIMEOUT 1 /* DMA cache settings - Outer sharable, write-back, write-allocate */ -#define XGBE_DMA_OS_AXDOMAIN 0x2 -#define XGBE_DMA_OS_ARCACHE 0xb -#define XGBE_DMA_OS_AWCACHE 0xf +#define XGBE_DMA_OS_ARCR 0x002b2b2b +#define XGBE_DMA_OS_AWCR 0x2f2f2f2f /* DMA cache settings - System, no caches used */ -#define XGBE_DMA_SYS_AXDOMAIN 0x3 -#define XGBE_DMA_SYS_ARCACHE 0x0 -#define XGBE_DMA_SYS_AWCACHE 0x0 +#define XGBE_DMA_SYS_ARCR 0x00303030 +#define XGBE_DMA_SYS_AWCR 0x30303030 /* DMA channel interrupt modes */ #define XGBE_IRQ_MODE_EDGE 0 @@ -1007,9 +1005,8 @@ struct xgbe_prv_data { /* AXI DMA settings */ unsigned int coherent; - unsigned int axdomain; - unsigned int arcache; - unsigned int awcache; + unsigned int arcr; + unsigned int awcr; /* Service routine support */ struct workqueue_struct *dev_workqueue; -- cgit v1.2.3 From 7e1e6b86a5d96ca13834fbc6b6e54a9228f308e1 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:43:18 -0500 Subject: amd-xgbe: Simplify the burst length settings Currently the driver hardcodes the PBLx8 setting. Remove the need for specifying the PBLx8 setting and automatically calculate based on the specified PBL value. Since the PBLx8 setting applies to both Tx and Rx use the same PBL value for both of them. Also, the driver currently uses a bit field to set the AXI master burst len setting. Change to the full bit field range and set the burst length based on the specified value. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 11 ++++- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 67 ++++++++--------------------- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 5 +-- drivers/net/ethernet/amd/xgbe/xgbe.h | 12 +----- 4 files changed, 31 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index dc098832e0fe..6b5c72d27655 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -137,12 +137,19 @@ #define DMA_MR_SWR_WIDTH 1 #define DMA_SBMR_EAME_INDEX 11 #define DMA_SBMR_EAME_WIDTH 1 -#define DMA_SBMR_BLEN_256_INDEX 7 -#define DMA_SBMR_BLEN_256_WIDTH 1 +#define DMA_SBMR_BLEN_INDEX 1 +#define DMA_SBMR_BLEN_WIDTH 7 #define DMA_SBMR_UNDEF_INDEX 0 #define DMA_SBMR_UNDEF_WIDTH 1 /* DMA register values */ +#define DMA_SBMR_BLEN_256 256 +#define DMA_SBMR_BLEN_128 128 +#define DMA_SBMR_BLEN_64 64 +#define DMA_SBMR_BLEN_32 32 +#define DMA_SBMR_BLEN_16 16 +#define DMA_SBMR_BLEN_8 8 +#define DMA_SBMR_BLEN_4 4 #define DMA_DSR_RPS_WIDTH 4 #define DMA_DSR_TPS_WIDTH 4 #define DMA_DSR_Q_WIDTH (DMA_DSR_RPS_WIDTH + DMA_DSR_TPS_WIDTH) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 98da24964f1f..a51ece52905f 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -174,52 +174,30 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata, return ret; } -static int xgbe_config_pblx8(struct xgbe_prv_data *pdata) +static int xgbe_config_pbl_val(struct xgbe_prv_data *pdata) { + unsigned int pblx8, pbl; unsigned int i; - for (i = 0; i < pdata->channel_count; i++) - XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, PBLX8, - pdata->pblx8); - - return 0; -} - -static int xgbe_get_tx_pbl_val(struct xgbe_prv_data *pdata) -{ - return XGMAC_DMA_IOREAD_BITS(pdata->channel[0], DMA_CH_TCR, PBL); -} - -static int xgbe_config_tx_pbl_val(struct xgbe_prv_data *pdata) -{ - unsigned int i; - - for (i = 0; i < pdata->channel_count; i++) { - if (!pdata->channel[i]->tx_ring) - break; + pblx8 = DMA_PBL_X8_DISABLE; + pbl = pdata->pbl; - XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, PBL, - pdata->tx_pbl); + if (pdata->pbl > 32) { + pblx8 = DMA_PBL_X8_ENABLE; + pbl >>= 3; } - return 0; -} - -static int xgbe_get_rx_pbl_val(struct xgbe_prv_data *pdata) -{ - return XGMAC_DMA_IOREAD_BITS(pdata->channel[0], DMA_CH_RCR, PBL); -} - -static int xgbe_config_rx_pbl_val(struct xgbe_prv_data *pdata) -{ - unsigned int i; - for (i = 0; i < pdata->channel_count; i++) { - if (!pdata->channel[i]->rx_ring) - break; + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, PBLX8, + pblx8); + + if (pdata->channel[i]->tx_ring) + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, + PBL, pbl); - XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, PBL, - pdata->rx_pbl); + if (pdata->channel[i]->rx_ring) + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_RCR, + PBL, pbl); } return 0; @@ -2141,7 +2119,7 @@ static void xgbe_config_dma_bus(struct xgbe_prv_data *pdata) /* Set the System Bus mode */ XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, UNDEF, 1); - XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, BLEN_256, 1); + XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, BLEN, pdata->blen >> 2); } static void xgbe_config_dma_cache(struct xgbe_prv_data *pdata) @@ -3381,9 +3359,7 @@ static int xgbe_init(struct xgbe_prv_data *pdata) xgbe_config_dma_bus(pdata); xgbe_config_dma_cache(pdata); xgbe_config_osp_mode(pdata); - xgbe_config_pblx8(pdata); - xgbe_config_tx_pbl_val(pdata); - xgbe_config_rx_pbl_val(pdata); + xgbe_config_pbl_val(pdata); xgbe_config_rx_coalesce(pdata); xgbe_config_tx_coalesce(pdata); xgbe_config_rx_buffer_size(pdata); @@ -3511,13 +3487,6 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) /* For TX DMA Operating on Second Frame config */ hw_if->config_osp_mode = xgbe_config_osp_mode; - /* For RX and TX PBL config */ - hw_if->config_rx_pbl_val = xgbe_config_rx_pbl_val; - hw_if->get_rx_pbl_val = xgbe_get_rx_pbl_val; - hw_if->config_tx_pbl_val = xgbe_config_tx_pbl_val; - hw_if->get_tx_pbl_val = xgbe_get_tx_pbl_val; - hw_if->config_pblx8 = xgbe_config_pblx8; - /* For MMC statistics support */ hw_if->tx_mmc_int = xgbe_tx_mmc_int; hw_if->rx_mmc_int = xgbe_rx_mmc_int; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 982368b560ba..8eec9f5991f5 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -140,14 +140,13 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata) { DBGPR("-->xgbe_default_config\n"); - pdata->pblx8 = DMA_PBL_X8_ENABLE; + pdata->blen = DMA_SBMR_BLEN_256; + pdata->pbl = DMA_PBL_128; pdata->tx_sf_mode = MTL_TSF_ENABLE; pdata->tx_threshold = MTL_TX_THRESHOLD_64; - pdata->tx_pbl = DMA_PBL_16; pdata->tx_osp_mode = DMA_OSP_ENABLE; pdata->rx_sf_mode = MTL_RSF_DISABLE; pdata->rx_threshold = MTL_RX_THRESHOLD_64; - pdata->rx_pbl = DMA_PBL_16; pdata->pause_autoneg = 1; pdata->tx_pause = 1; pdata->rx_pause = 1; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 46780aa74301..4bf82eb23ae6 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -737,13 +737,6 @@ struct xgbe_hw_if { /* For TX DMA Operate on Second Frame config */ int (*config_osp_mode)(struct xgbe_prv_data *); - /* For RX and TX PBL config */ - int (*config_rx_pbl_val)(struct xgbe_prv_data *); - int (*get_rx_pbl_val)(struct xgbe_prv_data *); - int (*config_tx_pbl_val)(struct xgbe_prv_data *); - int (*get_tx_pbl_val)(struct xgbe_prv_data *); - int (*config_pblx8)(struct xgbe_prv_data *); - /* For MMC statistics */ void (*rx_mmc_int)(struct xgbe_prv_data *); void (*tx_mmc_int)(struct xgbe_prv_data *); @@ -1029,19 +1022,18 @@ struct xgbe_prv_data { unsigned int rx_q_count; /* Tx/Rx common settings */ - unsigned int pblx8; + unsigned int blen; + unsigned int pbl; /* Tx settings */ unsigned int tx_sf_mode; unsigned int tx_threshold; - unsigned int tx_pbl; unsigned int tx_osp_mode; unsigned int tx_max_fifo_size; /* Rx settings */ unsigned int rx_sf_mode; unsigned int rx_threshold; - unsigned int rx_pbl; unsigned int rx_max_fifo_size; /* Tx coalescing settings */ -- cgit v1.2.3 From 6f595959c095d8923b19196fea3e983dcb299f22 Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Wed, 28 Jun 2017 13:43:26 -0500 Subject: amd-xgbe: Adjust register settings to improve performance Add support to change some general performance settings and to provide some performance settings based on the device that is probed. This includes: - Setting the maximum read/write outstanding request limit - Reducing the AXI interface burst length size - Selectively setting the Tx and Rx descriptor pre-fetch threshold - Selectively setting additional cache coherency controls Tested and verified on all versions of the hardware. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 13 +++++++++++++ drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 26 +++++++++++++++++++++++--- drivers/net/ethernet/amd/xgbe/xgbe-main.c | 5 ++++- drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 9 +++++++-- drivers/net/ethernet/amd/xgbe/xgbe.h | 11 +++++++++++ 5 files changed, 58 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 6b5c72d27655..9795419aac2d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -123,8 +123,11 @@ #define DMA_ISR 0x3008 #define DMA_AXIARCR 0x3010 #define DMA_AXIAWCR 0x3018 +#define DMA_AXIAWARCR 0x301c #define DMA_DSR0 0x3020 #define DMA_DSR1 0x3024 +#define DMA_TXEDMACR 0x3040 +#define DMA_RXEDMACR 0x3044 /* DMA register entry bit positions and sizes */ #define DMA_ISR_MACIS_INDEX 17 @@ -135,12 +138,22 @@ #define DMA_MR_INTM_WIDTH 2 #define DMA_MR_SWR_INDEX 0 #define DMA_MR_SWR_WIDTH 1 +#define DMA_RXEDMACR_RDPS_INDEX 0 +#define DMA_RXEDMACR_RDPS_WIDTH 3 +#define DMA_SBMR_AAL_INDEX 12 +#define DMA_SBMR_AAL_WIDTH 1 #define DMA_SBMR_EAME_INDEX 11 #define DMA_SBMR_EAME_WIDTH 1 #define DMA_SBMR_BLEN_INDEX 1 #define DMA_SBMR_BLEN_WIDTH 7 +#define DMA_SBMR_RD_OSR_LMT_INDEX 16 +#define DMA_SBMR_RD_OSR_LMT_WIDTH 6 #define DMA_SBMR_UNDEF_INDEX 0 #define DMA_SBMR_UNDEF_WIDTH 1 +#define DMA_SBMR_WR_OSR_LMT_INDEX 24 +#define DMA_SBMR_WR_OSR_LMT_WIDTH 6 +#define DMA_TXEDMACR_TDPS_INDEX 0 +#define DMA_TXEDMACR_TDPS_WIDTH 3 /* DMA register values */ #define DMA_SBMR_BLEN_256 256 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index a51ece52905f..06f953e1e9b2 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -2114,18 +2114,38 @@ static int xgbe_flush_tx_queues(struct xgbe_prv_data *pdata) static void xgbe_config_dma_bus(struct xgbe_prv_data *pdata) { + unsigned int sbmr; + + sbmr = XGMAC_IOREAD(pdata, DMA_SBMR); + /* Set enhanced addressing mode */ - XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, EAME, 1); + XGMAC_SET_BITS(sbmr, DMA_SBMR, EAME, 1); /* Set the System Bus mode */ - XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, UNDEF, 1); - XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, BLEN, pdata->blen >> 2); + XGMAC_SET_BITS(sbmr, DMA_SBMR, UNDEF, 1); + XGMAC_SET_BITS(sbmr, DMA_SBMR, BLEN, pdata->blen >> 2); + XGMAC_SET_BITS(sbmr, DMA_SBMR, AAL, pdata->aal); + XGMAC_SET_BITS(sbmr, DMA_SBMR, RD_OSR_LMT, pdata->rd_osr_limit - 1); + XGMAC_SET_BITS(sbmr, DMA_SBMR, WR_OSR_LMT, pdata->wr_osr_limit - 1); + + XGMAC_IOWRITE(pdata, DMA_SBMR, sbmr); + + /* Set descriptor fetching threshold */ + if (pdata->vdata->tx_desc_prefetch) + XGMAC_IOWRITE_BITS(pdata, DMA_TXEDMACR, TDPS, + pdata->vdata->tx_desc_prefetch); + + if (pdata->vdata->rx_desc_prefetch) + XGMAC_IOWRITE_BITS(pdata, DMA_RXEDMACR, RDPS, + pdata->vdata->rx_desc_prefetch); } static void xgbe_config_dma_cache(struct xgbe_prv_data *pdata) { XGMAC_IOWRITE(pdata, DMA_AXIARCR, pdata->arcr); XGMAC_IOWRITE(pdata, DMA_AXIAWCR, pdata->awcr); + if (pdata->awarcr) + XGMAC_IOWRITE(pdata, DMA_AXIAWARCR, pdata->awarcr); } static void xgbe_config_mtl_mode(struct xgbe_prv_data *pdata) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index 8eec9f5991f5..500147d9e3c8 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -140,8 +140,11 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata) { DBGPR("-->xgbe_default_config\n"); - pdata->blen = DMA_SBMR_BLEN_256; + pdata->blen = DMA_SBMR_BLEN_64; pdata->pbl = DMA_PBL_128; + pdata->aal = 1; + pdata->rd_osr_limit = 8; + pdata->wr_osr_limit = 8; pdata->tx_sf_mode = MTL_TSF_ENABLE; pdata->tx_threshold = MTL_TX_THRESHOLD_64; pdata->tx_osp_mode = DMA_OSP_ENABLE; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index 1e7376887568..1e56ad7bd9a5 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -327,8 +327,9 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Set the DMA coherency values */ pdata->coherent = 1; - pdata->arcr = XGBE_DMA_OS_ARCR; - pdata->awcr = XGBE_DMA_OS_AWCR; + pdata->arcr = XGBE_DMA_PCI_ARCR; + pdata->awcr = XGBE_DMA_PCI_AWCR; + pdata->awarcr = XGBE_DMA_PCI_AWARCR; /* Set the maximum channels and queues */ reg = XP_IOREAD(pdata, XP_PROP_1); @@ -447,6 +448,8 @@ static const struct xgbe_version_data xgbe_v2a = { .ecc_support = 1, .i2c_support = 1, .irq_reissue_support = 1, + .tx_desc_prefetch = 5, + .rx_desc_prefetch = 5, }; static const struct xgbe_version_data xgbe_v2b = { @@ -459,6 +462,8 @@ static const struct xgbe_version_data xgbe_v2b = { .ecc_support = 1, .i2c_support = 1, .irq_reissue_support = 1, + .tx_desc_prefetch = 5, + .rx_desc_prefetch = 5, }; static const struct pci_device_id xgbe_pci_table[] = { diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 4bf82eb23ae6..0938294f640a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -171,6 +171,11 @@ #define XGBE_DMA_SYS_ARCR 0x00303030 #define XGBE_DMA_SYS_AWCR 0x30303030 +/* DMA cache settings - PCI device */ +#define XGBE_DMA_PCI_ARCR 0x00000003 +#define XGBE_DMA_PCI_AWCR 0x13131313 +#define XGBE_DMA_PCI_AWARCR 0x00000313 + /* DMA channel interrupt modes */ #define XGBE_IRQ_MODE_EDGE 0 #define XGBE_IRQ_MODE_LEVEL 1 @@ -921,6 +926,8 @@ struct xgbe_version_data { unsigned int ecc_support; unsigned int i2c_support; unsigned int irq_reissue_support; + unsigned int tx_desc_prefetch; + unsigned int rx_desc_prefetch; }; struct xgbe_prv_data { @@ -1000,6 +1007,7 @@ struct xgbe_prv_data { unsigned int coherent; unsigned int arcr; unsigned int awcr; + unsigned int awarcr; /* Service routine support */ struct workqueue_struct *dev_workqueue; @@ -1024,6 +1032,9 @@ struct xgbe_prv_data { /* Tx/Rx common settings */ unsigned int blen; unsigned int pbl; + unsigned int aal; + unsigned int rd_osr_limit; + unsigned int wr_osr_limit; /* Tx settings */ unsigned int tx_sf_mode; -- cgit v1.2.3 From 05fcd31cc472c5da6416d3bc2ab25599bbb9331f Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 28 Jun 2017 18:32:18 +0200 Subject: arcnet: add err_skb package for package status feedback We need to track the status of our queued packages. This way the driving process knows if failed packages need to be retransmitted. For this purpose we queue the transferred/failed packages back into the err_skb message queue added with some status information. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/arcdevice.h | 4 +++ drivers/net/arcnet/arcnet.c | 74 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/arcnet/arcdevice.h b/drivers/net/arcnet/arcdevice.h index 20bfb9ba83ea..cbb4f8566bbe 100644 --- a/drivers/net/arcnet/arcdevice.h +++ b/drivers/net/arcnet/arcdevice.h @@ -269,6 +269,10 @@ struct arcnet_local { struct timer_list timer; + struct net_device *dev; + int reply_status; + struct tasklet_struct reply_tasklet; + /* * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of * which can be used for either sending or receiving. The new dynamic diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 62ee439d5882..d87f4da29f11 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -51,6 +51,7 @@ #include #include #include +#include #include @@ -391,6 +392,52 @@ static void arcnet_timer(unsigned long data) } } +static void arcnet_reply_tasklet(unsigned long data) +{ + struct arcnet_local *lp = (struct arcnet_local *)data; + + struct sk_buff *ackskb, *skb; + struct sock_exterr_skb *serr; + struct sock *sk; + int ret; + + local_irq_disable(); + skb = lp->outgoing.skb; + if (!skb || !skb->sk) { + local_irq_enable(); + return; + } + + sock_hold(skb->sk); + sk = skb->sk; + ackskb = skb_clone_sk(skb); + sock_put(skb->sk); + + if (!ackskb) { + local_irq_enable(); + return; + } + + serr = SKB_EXT_ERR(ackskb); + memset(serr, 0, sizeof(*serr)); + serr->ee.ee_errno = ENOMSG; + serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS; + serr->ee.ee_data = skb_shinfo(skb)->tskey; + serr->ee.ee_info = lp->reply_status; + + /* finally erasing outgoing skb */ + dev_kfree_skb(lp->outgoing.skb); + lp->outgoing.skb = NULL; + + ackskb->dev = lp->dev; + + ret = sock_queue_err_skb(sk, ackskb); + if (ret) + kfree_skb(ackskb); + + local_irq_enable(); +}; + struct net_device *alloc_arcdev(const char *name) { struct net_device *dev; @@ -401,6 +448,7 @@ struct net_device *alloc_arcdev(const char *name) if (dev) { struct arcnet_local *lp = netdev_priv(dev); + lp->dev = dev; spin_lock_init(&lp->lock); init_timer(&lp->timer); lp->timer.data = (unsigned long) dev; @@ -436,6 +484,9 @@ int arcnet_open(struct net_device *dev) arc_cont(D_PROTO, "\n"); } + tasklet_init(&lp->reply_tasklet, arcnet_reply_tasklet, + (unsigned long)lp); + arc_printk(D_INIT, dev, "arcnet_open: resetting card.\n"); /* try to put the card in a defined state - if it fails the first @@ -527,6 +578,8 @@ int arcnet_close(struct net_device *dev) netif_stop_queue(dev); netif_carrier_off(dev); + tasklet_kill(&lp->reply_tasklet); + /* flush TX and disable RX */ lp->hw.intmask(dev, 0); lp->hw.command(dev, NOTXcmd); /* stop transmit */ @@ -635,13 +688,13 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb, txbuf = -1; if (txbuf != -1) { + lp->outgoing.skb = skb; if (proto->prepare_tx(dev, pkt, skb->len, txbuf) && !proto->ack_tx) { /* done right away and we don't want to acknowledge * the package later - forget about it now */ dev->stats.tx_bytes += skb->len; - dev_kfree_skb(skb); } else { /* do it the 'split' way */ lp->outgoing.proto = proto; @@ -842,8 +895,16 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) /* a transmit finished, and we're interested in it. */ if ((status & lp->intmask & TXFREEflag) || lp->timed_out) { + int ackstatus; lp->intmask &= ~(TXFREEflag | EXCNAKflag); + if (status & TXACKflag) + ackstatus = 2; + else if (lp->excnak_pending) + ackstatus = 1; + else + ackstatus = 0; + arc_printk(D_DURING, dev, "TX IRQ (stat=%Xh)\n", status); @@ -866,18 +927,11 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) if (lp->outgoing.proto && lp->outgoing.proto->ack_tx) { - int ackstatus; - - if (status & TXACKflag) - ackstatus = 2; - else if (lp->excnak_pending) - ackstatus = 1; - else - ackstatus = 0; - lp->outgoing.proto ->ack_tx(dev, ackstatus); } + lp->reply_status = ackstatus; + tasklet_hi_schedule(&lp->reply_tasklet); } if (lp->cur_tx != -1) release_arcbuf(dev, lp->cur_tx); -- cgit v1.2.3 From ede07a1fc7d70adfb290cfdace391295897023cb Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 28 Jun 2017 18:32:19 +0200 Subject: arcnet: com20020-pci: add attribute to readback backplane status We add the sysfs interface the read back the backplane status of the interface. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-pci.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 239de38fbd6a..dec300cac55f 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -93,6 +93,27 @@ static void led_recon_set(struct led_classdev *led_cdev, outb(!!value, priv->misc + ci->leds[card->index].red); } +static ssize_t backplane_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = to_net_dev(dev); + struct arcnet_local *lp = netdev_priv(net_dev); + + return sprintf(buf, "%s\n", lp->backplane ? "true" : "false"); +} +static DEVICE_ATTR_RO(backplane_mode); + +static struct attribute *com20020_state_attrs[] = { + &dev_attr_backplane_mode.attr, + NULL, +}; + +static struct attribute_group com20020_state_group = { + .name = NULL, + .attrs = com20020_state_attrs, +}; + static void com20020pci_remove(struct pci_dev *pdev); static int com20020pci_probe(struct pci_dev *pdev, @@ -168,6 +189,7 @@ static int com20020pci_probe(struct pci_dev *pdev, dev->base_addr = ioaddr; dev->dev_addr[0] = node; + dev->sysfs_groups[0] = &com20020_state_group; dev->irq = pdev->irq; lp->card_name = "PCI COM20020"; lp->card_flags = ci->flags; -- cgit v1.2.3 From 52ab12e4f99437a046962e6486b0efded52846af Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 28 Jun 2017 18:32:20 +0200 Subject: arcnet: com20020-pci: handle backplane mode depending on card type We read the backplane mode of each subcard from bits 2 and 3 of the misc register. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index dec300cac55f..f5854ab7dc32 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -199,6 +199,8 @@ static int com20020pci_probe(struct pci_dev *pdev, lp->timeout = timeout; lp->hw.owner = THIS_MODULE; + lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1; + /* Get the dev_id from the PLX rotary coder */ if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15)) dev->dev_id = 0xc; -- cgit v1.2.3 From a356ab1c3d46513067dddf9484c9f05e10279312 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 28 Jun 2017 18:32:21 +0200 Subject: arcnet: com20020-pci: add support for PCIFB2 card We add support for the PCIFB2 card from EAE. Beside other cards, this card has the backplane mode enabled by default. Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-pci.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers') diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index f5854ab7dc32..24deb88a37f0 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -201,6 +201,9 @@ static int com20020pci_probe(struct pci_dev *pdev, lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1; + if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15)) + lp->backplane = 1; + /* Get the dev_id from the PLX rotary coder */ if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15)) dev->dev_id = 0xc; @@ -385,6 +388,31 @@ static struct com20020_pci_card_info card_info_eae_ma1 = { .flags = ARC_CAN_10MBIT, }; +static struct com20020_pci_card_info card_info_eae_fb2 = { + .name = "EAE PLX-PCI FB2", + .devcount = 1, + .chan_map_tbl = { + { + .bar = 2, + .offset = 0x00, + .size = 0x08, + }, + }, + .misc_map = { + .bar = 2, + .offset = 0x10, + .size = 0x04, + }, + .leds = { + { + .green = 0x0, + .red = 0x1, + }, + }, + .rotary = 0x0, + .flags = ARC_CAN_10MBIT, +}; + static const struct pci_device_id com20020pci_id_table[] = { { 0x1571, 0xa001, @@ -530,6 +558,12 @@ static const struct pci_device_id com20020pci_id_table[] = { 0, 0, (kernel_ulong_t)&card_info_eae_ma1 }, + { + 0x10B5, 0x9050, + 0x10B5, 0x3294, + 0, 0, + (kernel_ulong_t)&card_info_eae_fb2 + }, { 0x14BA, 0x6000, PCI_ANY_ID, PCI_ANY_ID, -- cgit v1.2.3 From beef8516a4540b61ebb16d94ca0430b8f6760a54 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 28 Jun 2017 17:51:10 +0100 Subject: amd-xgbe: fix spelling mistake: "avialable" -> "available" Trivial fix to spelling mistake in netdev_err message Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 920566a3a599..67a2e52ad25d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -247,7 +247,7 @@ static int xgbe_set_pauseparam(struct net_device *netdev, if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) { netdev_err(netdev, - "autoneg disabled, pause autoneg not avialable\n"); + "autoneg disabled, pause autoneg not available\n"); return -EINVAL; } -- cgit v1.2.3 From 5df969c3b0c6df03d72e0e7502c4adc7838442f9 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 28 Jun 2017 19:55:54 -0500 Subject: ibmvnic: Fix assignment of RX/TX IRQ's The driver currently creates RX/TX queues during device probe, but assigns IRQ's to them during device open. On reset, however, IRQ's are assigned when resetting the queues. If there is a reset while the device is closed and the device is later opened, the driver will request IRQ's twice, causing the open to fail. This patch assigns the IRQ's in the ibmvnic_init function after the queues are reset or initialized, ensuring IRQ's are only requested once. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 87db1eb5cc44..a3e694679635 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -763,12 +763,6 @@ static int init_resources(struct ibmvnic_adapter *adapter) if (rc) return rc; - rc = init_sub_crq_irqs(adapter); - if (rc) { - netdev_err(netdev, "failed to initialize sub crq irqs\n"); - return -1; - } - rc = init_stats_token(adapter); if (rc) return rc; @@ -1803,7 +1797,6 @@ static int reset_sub_crq_queues(struct ibmvnic_adapter *adapter) return rc; } - rc = init_sub_crq_irqs(adapter); return rc; } @@ -3669,6 +3662,13 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) if (rc) { dev_err(dev, "Initialization of sub crqs failed\n"); release_crq_queue(adapter); + return rc; + } + + rc = init_sub_crq_irqs(adapter); + if (rc) { + dev_err(dev, "Failed to initialize sub crq irqs\n"); + release_crq_queue(adapter); } return rc; -- cgit v1.2.3 From eb60a73d00a7e1f069cd45d7b06ee46bc6b7dfb1 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 29 Jun 2017 11:14:50 +0530 Subject: net: ibm: ibmveth: constify dev_pm_ops structures. dev_pm_ops are not supposed to change at runtime. All functions working with dev_pm_ops provided by work with const dev_pm_ops. So mark the non-const structs as const. File size before: text data bss dec hex filename 15426 1256 0 16682 412a drivers/net/ethernet/ibm/ibmveth.o File size After adding 'const': text data bss dec hex filename 15618 1064 0 16682 412a drivers/net/ethernet/ibm/ibmveth.o Signed-off-by: Arvind Yadav Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmveth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 9a74c4e2e193..3e0a695537e2 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1914,7 +1914,7 @@ static struct vio_device_id ibmveth_device_table[] = { }; MODULE_DEVICE_TABLE(vio, ibmveth_device_table); -static struct dev_pm_ops ibmveth_pm_ops = { +static const struct dev_pm_ops ibmveth_pm_ops = { .resume = ibmveth_resume }; -- cgit v1.2.3 From d19724ec7b73d4b3935dc59be2f38fd09cde1e74 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 29 Jun 2017 11:21:00 +0530 Subject: net: smc91x: constify dev_pm_ops structures. dev_pm_ops are not supposed to change at runtime. All functions working with dev_pm_ops provided by work with const dev_pm_ops. So mark the non-const structs as const. File size before: text data bss dec hex filename 18709 401 0 19110 4aa6 drivers/net/ethernet/smsc/smc91x.o File size After adding 'const': text data bss dec hex filename 18901 201 0 19102 4a9e drivers/net/ethernet/smsc/smc91x.o Signed-off-by: Arvind Yadav Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/smc91x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 0d230b125c6c..080428762858 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -2485,7 +2485,7 @@ static int smc_drv_resume(struct device *dev) return 0; } -static struct dev_pm_ops smc_drv_pm_ops = { +static const struct dev_pm_ops smc_drv_pm_ops = { .suspend = smc_drv_suspend, .resume = smc_drv_resume, }; -- cgit v1.2.3 From ee27244b6653f54fb1a7601ff08d02889b699388 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 29 Jun 2017 11:26:06 +0530 Subject: net: freescale: gianfar : constify dev_pm_ops structures. dev_pm_ops are not supposed to change at runtime. All functions working with dev_pm_ops provided by work with const dev_pm_ops. So mark the non-const structs as const. File size before: text data bss dec hex filename 19057 392 0 19449 4bf9 drivers/net/ethernet/freescale/gianfar.o File size After adding 'const': text data bss dec hex filename 19249 192 0 19441 4bf1 drivers/net/ethernet/freescale/gianfar.o Signed-off-by: Arvind Yadav Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index a79e257bc338..c4b4b0a1bbf0 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1718,7 +1718,7 @@ static int gfar_restore(struct device *dev) return 0; } -static struct dev_pm_ops gfar_pm_ops = { +static const struct dev_pm_ops gfar_pm_ops = { .suspend = gfar_suspend, .resume = gfar_resume, .freeze = gfar_suspend, -- cgit v1.2.3 From f21ad61424f7c623eddbcf54425a86afb68ca55f Mon Sep 17 00:00:00 2001 From: Inbar Karmy Date: Thu, 29 Jun 2017 14:07:56 +0300 Subject: net/mlx4_en: Add dynamic variable to hold the number of user priorities (UP) Until this patch, the number of UPs was hard coded for eight. Replace this with a variable in struct "mlx4_en_port_profile". Currently, the variable will hold the maximum number of UP, as before. The patch creates an infrastructure to add an option for dynamic change of the actual number of TCs. Signed-off-by: Inbar Karmy Signed-off-by: Tariq Toukan Cc: Tarick Bedeir Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 12 +++++++----- drivers/net/ethernet/mellanox/mlx4/en_main.c | 3 ++- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 6 +++--- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 7 ++++--- 5 files changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index 1dae8e40fb25..91481f117daa 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -303,7 +303,7 @@ static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets) int has_ets_tc = 0; for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { - if (ets->prio_tc[i] >= MLX4_EN_NUM_UP) { + if (ets->prio_tc[i] >= priv->prof->num_up) { en_err(priv, "Bad priority in UP <=> TC mapping. TC: %d, UP: %d\n", i, ets->prio_tc[i]); return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index e97fbf327594..2b80a4a9945c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1750,7 +1750,8 @@ static void mlx4_en_get_channels(struct net_device *dev, channel->max_tx = MLX4_EN_MAX_TX_RING_P_UP; channel->rx_count = priv->rx_ring_num; - channel->tx_count = priv->tx_ring_num[TX] / MLX4_EN_NUM_UP; + channel->tx_count = priv->tx_ring_num[TX] / + priv->prof->num_up; } static int mlx4_en_set_channels(struct net_device *dev, @@ -1773,18 +1774,19 @@ static int mlx4_en_set_channels(struct net_device *dev, mutex_lock(&mdev->state_lock); xdp_count = priv->tx_ring_num[TX_XDP] ? channel->rx_count : 0; - if (channel->tx_count * MLX4_EN_NUM_UP + xdp_count > MAX_TX_RINGS) { + if (channel->tx_count * priv->prof->num_up + xdp_count > + MAX_TX_RINGS) { err = -EINVAL; en_err(priv, "Total number of TX and XDP rings (%d) exceeds the maximum supported (%d)\n", - channel->tx_count * MLX4_EN_NUM_UP + xdp_count, + channel->tx_count * priv->prof->num_up + xdp_count, MAX_TX_RINGS); goto out; } memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); new_prof.num_tx_rings_p_up = channel->tx_count; - new_prof.tx_ring_num[TX] = channel->tx_count * MLX4_EN_NUM_UP; + new_prof.tx_ring_num[TX] = channel->tx_count * priv->prof->num_up; new_prof.tx_ring_num[TX_XDP] = xdp_count; new_prof.rx_ring_num = channel->rx_count; @@ -1803,7 +1805,7 @@ static int mlx4_en_set_channels(struct net_device *dev, netif_set_real_num_rx_queues(dev, priv->rx_ring_num); if (netdev_get_num_tc(dev)) - mlx4_en_setup_tc(dev, MLX4_EN_NUM_UP); + mlx4_en_setup_tc(dev, priv->prof->num_up); en_warn(priv, "Using %d TX rings\n", priv->tx_ring_num[TX]); en_warn(priv, "Using %d RX rings\n", priv->rx_ring_num); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index 56cdf38d150e..a8eb856b0158 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -169,8 +169,9 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) params->prof[i].tx_ppp = pfctx; params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; + params->prof[i].num_up = MLX4_EN_NUM_UP_HIGH; params->prof[i].tx_ring_num[TX] = params->num_tx_rings_p_up * - MLX4_EN_NUM_UP; + params->prof[i].num_up; params->prof[i].rss_rings = 0; params->prof[i].inline_thold = inline_thold; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 9da76e3be2fc..e7f654623eab 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -60,7 +60,7 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up) int i; unsigned int offset = 0; - if (up && up != MLX4_EN_NUM_UP) + if (up && up != MLX4_EN_NUM_UP_HIGH) return -EINVAL; netdev_set_num_tc(dev, up); @@ -2780,7 +2780,7 @@ static int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) if (priv->tx_ring_num[TX] + xdp_ring_num > MAX_TX_RINGS) { tx_changed = 1; new_prof.tx_ring_num[TX] = - MAX_TX_RINGS - ALIGN(xdp_ring_num, MLX4_EN_NUM_UP); + MAX_TX_RINGS - ALIGN(xdp_ring_num, priv->prof->num_up); en_warn(priv, "Reducing the number of TX rings, to not exceed the max total rings number.\n"); } @@ -3271,7 +3271,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->flags |= MLX4_EN_DCB_ENABLED; priv->cee_config.pfc_state = false; - for (i = 0; i < MLX4_EN_NUM_UP; i++) + for (i = 0; i < MLX4_EN_NUM_UP_HIGH; i++) priv->cee_config.dcb_pfc[i] = pfc_disabled; if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) { diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 963b77d51b48..89885281d489 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -115,11 +115,11 @@ #define MLX4_EN_SMALL_PKT_SIZE 64 #define MLX4_EN_MIN_TX_RING_P_UP 1 #define MLX4_EN_MAX_TX_RING_P_UP 32 -#define MLX4_EN_NUM_UP 8 +#define MLX4_EN_NUM_UP_HIGH 8 #define MLX4_EN_DEF_RX_RING_SIZE 1024 #define MLX4_EN_DEF_TX_RING_SIZE MLX4_EN_DEF_RX_RING_SIZE #define MAX_TX_RINGS (MLX4_EN_MAX_TX_RING_P_UP * \ - MLX4_EN_NUM_UP) + MLX4_EN_NUM_UP_HIGH) #define MLX4_EN_DEFAULT_TX_WORK 256 @@ -386,6 +386,7 @@ struct mlx4_en_port_profile { u8 rx_ppp; u8 tx_pause; u8 tx_ppp; + u8 num_up; int rss_rings; int inline_thold; struct hwtstamp_config hwtstamp_config; @@ -485,7 +486,7 @@ enum dcb_pfc_type { struct mlx4_en_cee_config { bool pfc_state; - enum dcb_pfc_type dcb_pfc[MLX4_EN_NUM_UP]; + enum dcb_pfc_type dcb_pfc[MLX4_EN_NUM_UP_HIGH]; }; #endif -- cgit v1.2.3 From ec327f7a4340b635d89ca9667935adefa3905be1 Mon Sep 17 00:00:00 2001 From: Inbar Karmy Date: Thu, 29 Jun 2017 14:07:57 +0300 Subject: net/mlx4_en: Do not allocate redundant TX queues when TC is disabled Currently the number of TX queues that are allocated doesn't depend on the number of TCs, the module always loads with max num of UP per channel. In order to prevent the allocation of unnecessary memory, the module will load with minimum number of UPs per channel, and the user will be able to control the number of TX queues per channel by changing the number of TC to 8 using the tc command. The variable num_up will hold the information about the current number of UPs. Due to the change, needed to remove the lines that set the value of UP to be different than zero in the func "mlx4_en_select_queue", since now the num of TX queues that are allocated is only one per channel in default. In order not to force the UP to be zero in case of only one TC, added a condition before forcing it in the func "mlx4_en_fill_qp_context". Tested: After the module is loaded with minimum number of UP per channel, to increase num of TCs to 8, use: tc qdisc add dev ens8 root mqprio num_tc 8 In order to decrease the number of TCs to minimum number of UP per channel, use: tc qdisc del dev ens8 root Signed-off-by: Inbar Karmy Signed-off-by: Tariq Toukan Cc: Tarick Bedeir Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 6 +-- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 7 +-- drivers/net/ethernet/mellanox/mlx4/en_main.c | 3 +- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 54 +++++++++++++++++++++-- drivers/net/ethernet/mellanox/mlx4/en_resources.c | 3 +- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 6 +-- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 2 + 7 files changed, 65 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index 91481f117daa..5f41dc92aa68 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -238,7 +238,7 @@ static u8 mlx4_en_dcbnl_set_state(struct net_device *dev, u8 state) priv->flags &= ~MLX4_EN_FLAG_DCB_ENABLED; } - if (mlx4_en_setup_tc(dev, num_tcs)) + if (mlx4_en_alloc_tx_queue_per_tc(dev, num_tcs)) return 1; return 0; @@ -303,7 +303,7 @@ static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets) int has_ets_tc = 0; for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { - if (ets->prio_tc[i] >= priv->prof->num_up) { + if (ets->prio_tc[i] >= MLX4_EN_NUM_UP_HIGH) { en_err(priv, "Bad priority in UP <=> TC mapping. TC: %d, UP: %d\n", i, ets->prio_tc[i]); return -EINVAL; @@ -472,7 +472,7 @@ static u8 mlx4_en_dcbnl_setdcbx(struct net_device *dev, u8 mode) goto err; if (mlx4_en_dcbnl_ieee_setpfc(dev, &pfc)) goto err; - if (mlx4_en_setup_tc(dev, 0)) + if (mlx4_en_alloc_tx_queue_per_tc(dev, 0)) goto err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 2b80a4a9945c..c751a1d434ad 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1764,6 +1764,7 @@ static int mlx4_en_set_channels(struct net_device *dev, int port_up = 0; int xdp_count; int err = 0; + u8 up; if (!channel->tx_count || !channel->rx_count) return -EINVAL; @@ -1801,11 +1802,11 @@ static int mlx4_en_set_channels(struct net_device *dev, mlx4_en_safe_replace_resources(priv, tmp); - netif_set_real_num_tx_queues(dev, priv->tx_ring_num[TX]); netif_set_real_num_rx_queues(dev, priv->rx_ring_num); - if (netdev_get_num_tc(dev)) - mlx4_en_setup_tc(dev, priv->prof->num_up); + up = (priv->prof->num_up == MLX4_EN_NUM_UP_LOW) ? + 0 : priv->prof->num_up; + mlx4_en_setup_tc(dev, up); en_warn(priv, "Using %d TX rings\n", priv->tx_ring_num[TX]); en_warn(priv, "Using %d RX rings\n", priv->rx_ring_num); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index a8eb856b0158..2b0cbca4beb5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -169,7 +169,8 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) params->prof[i].tx_ppp = pfctx; params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; - params->prof[i].num_up = MLX4_EN_NUM_UP_HIGH; + params->prof[i].num_up = MLX4_EN_NUM_UP_LOW; + params->prof[i].num_tx_rings_p_up = params->num_tx_rings_p_up; params->prof[i].tx_ring_num[TX] = params->num_tx_rings_p_up * params->prof[i].num_up; params->prof[i].rss_rings = 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index e7f654623eab..3a291fc1780a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -64,7 +64,7 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up) return -EINVAL; netdev_set_num_tc(dev, up); - + netif_set_real_num_tx_queues(dev, priv->tx_ring_num[TX]); /* Partition Tx queues evenly amongst UP's */ for (i = 0; i < up; i++) { netdev_set_tc_queue(dev, i, priv->num_tx_rings_p_up, offset); @@ -86,6 +86,50 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up) return 0; } +int mlx4_en_alloc_tx_queue_per_tc(struct net_device *dev, u8 tc) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_port_profile new_prof; + struct mlx4_en_priv *tmp; + int port_up = 0; + int err = 0; + + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + mutex_lock(&mdev->state_lock); + memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); + new_prof.num_up = (tc == 0) ? MLX4_EN_NUM_UP_LOW : + MLX4_EN_NUM_UP_HIGH; + new_prof.tx_ring_num[TX] = new_prof.num_tx_rings_p_up * + new_prof.num_up; + err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); + if (err) + goto out; + + if (priv->port_up) { + port_up = 1; + mlx4_en_stop_port(dev, 1); + } + + mlx4_en_safe_replace_resources(priv, tmp); + if (port_up) { + err = mlx4_en_start_port(dev); + if (err) { + en_err(priv, "Failed starting port for setup TC\n"); + goto out; + } + } + + err = mlx4_en_setup_tc(dev, tc); +out: + mutex_unlock(&mdev->state_lock); + kfree(tmp); + return err; +} + static int __mlx4_en_setup_tc(struct net_device *dev, u32 handle, u32 chain_index, __be16 proto, struct tc_to_netdev *tc) @@ -93,9 +137,12 @@ static int __mlx4_en_setup_tc(struct net_device *dev, u32 handle, if (tc->type != TC_SETUP_MQPRIO) return -EINVAL; + if (tc->mqprio->num_tc && tc->mqprio->num_tc != MLX4_EN_NUM_UP_HIGH) + return -EINVAL; + tc->mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; - return mlx4_en_setup_tc(dev, tc->mqprio->num_tc); + return mlx4_en_alloc_tx_queue_per_tc(dev, tc->mqprio->num_tc); } #ifdef CONFIG_RFS_ACCEL @@ -2144,7 +2191,7 @@ static int mlx4_en_copy_priv(struct mlx4_en_priv *dst, memcpy(&dst->hwtstamp_config, &prof->hwtstamp_config, sizeof(dst->hwtstamp_config)); - dst->num_tx_rings_p_up = src->mdev->profile.num_tx_rings_p_up; + dst->num_tx_rings_p_up = prof->num_tx_rings_p_up; dst->rx_ring_num = prof->rx_ring_num; dst->flags = prof->flags; dst->mdev = src->mdev; @@ -2197,6 +2244,7 @@ static void mlx4_en_update_priv(struct mlx4_en_priv *dst, dst->tx_ring[t] = src->tx_ring[t]; dst->tx_cq[t] = src->tx_cq[t]; } + dst->num_tx_rings_p_up = src->num_tx_rings_p_up; dst->rx_ring_num = src->rx_ring_num; memcpy(dst->prof, src->prof, sizeof(struct mlx4_en_port_profile)); } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c index a6b0db0e0383..86d2d42d658d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c @@ -63,7 +63,8 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, context->local_qpn = cpu_to_be32(qpn); context->pri_path.ackto = 1 & 0x07; context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6; - if (user_prio >= 0) { + /* force user priority per tx ring */ + if (user_prio >= 0 && priv->prof->num_up == MLX4_EN_NUM_UP_HIGH) { context->pri_path.sched_queue |= user_prio << 3; context->pri_path.feup = MLX4_FEUP_FORCE_ETH_UP; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 7d69d939ee2d..4f3a9b27ce4a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -691,15 +691,11 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb, { struct mlx4_en_priv *priv = netdev_priv(dev); u16 rings_p_up = priv->num_tx_rings_p_up; - u8 up = 0; if (netdev_get_num_tc(dev)) return skb_tx_hash(dev, skb); - if (skb_vlan_tag_present(skb)) - up = skb_vlan_tag_get(skb) >> VLAN_PRIO_SHIFT; - - return fallback(dev, skb) % rings_p_up + up * rings_p_up; + return fallback(dev, skb) % rings_p_up; } static void mlx4_bf_copy(void __iomem *dst, const void *src, diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 89885281d489..d350b2158104 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -115,6 +115,7 @@ #define MLX4_EN_SMALL_PKT_SIZE 64 #define MLX4_EN_MIN_TX_RING_P_UP 1 #define MLX4_EN_MAX_TX_RING_P_UP 32 +#define MLX4_EN_NUM_UP_LOW 1 #define MLX4_EN_NUM_UP_HIGH 8 #define MLX4_EN_DEF_RX_RING_SIZE 1024 #define MLX4_EN_DEF_TX_RING_SIZE MLX4_EN_DEF_RX_RING_SIZE @@ -762,6 +763,7 @@ extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_pfc_ops; #endif int mlx4_en_setup_tc(struct net_device *dev, u8 up); +int mlx4_en_alloc_tx_queue_per_tc(struct net_device *dev, u8 tc); #ifdef CONFIG_RFS_ACCEL void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv); -- cgit v1.2.3 From b8a64f0e96c2b258321ee03975aeb0f5e88a055b Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 9 Jun 2017 13:08:47 +0100 Subject: brcmfmac: support 4-way handshake offloading for WPA/WPA2-PSK The firmware may have supplicant code built-in. This is detected by the driver and indicated in the wiphy features flags. User-space can use this flag to determine whether or not to provide the pre-shared key material in the nl80211 CONNECT command. Reviewed-by: Gautam (Gautam Kumar) Shukla Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 75 ++++++++++++++++++++-- .../broadcom/brcm80211/brcmfmac/cfg80211.h | 14 +++- .../wireless/broadcom/brcm80211/brcmfmac/feature.c | 1 + .../wireless/broadcom/brcm80211/brcmfmac/feature.h | 4 +- .../wireless/broadcom/brcm80211/brcmfmac/fweh.h | 30 +++++++++ .../wireless/broadcom/brcm80211/brcmfmac/fwil.h | 1 + .../broadcom/brcm80211/brcmfmac/fwil_types.h | 16 +++++ 7 files changed, 134 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 898c7b024c15..36945e0c8923 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1357,6 +1357,27 @@ static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e) return reason; } +static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) +{ + struct brcmf_wsec_pmk_le pmk; + int i, err; + + /* convert to firmware key format */ + pmk.key_len = cpu_to_le16(pmk_len << 1); + pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE); + for (i = 0; i < pmk_len; i++) + snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]); + + /* store psk in firmware */ + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK, + &pmk, sizeof(pmk)); + if (err < 0) + brcmf_err("failed to change PSK in firmware (len=%u)\n", + pmk_len); + + return err; +} + static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); @@ -1379,6 +1400,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0); + if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) { + brcmf_set_pmk(vif->ifp, NULL, 0); + vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE; + } brcmf_dbg(TRACE, "Exit\n"); } @@ -2012,6 +2037,23 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } + if (sme->crypto.psk) { + brcmf_dbg(INFO, "using PSK offload\n"); + + /* enable firmware supplicant for this interface */ + err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1); + if (err < 0) { + brcmf_err("failed to enable fw supplicant\n"); + goto done; + } + ifp->vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_PSK; + + err = brcmf_set_pmk(ifp, sme->crypto.psk, + BRCMF_WSEC_MAX_PSK_LEN); + if (err) + goto done; + } + /* Join with specific BSSID and cached SSID * If SSID is zero join based on BSSID only */ @@ -5247,16 +5289,30 @@ void brcmf_cfg80211_free_netdev(struct net_device *ndev) brcmf_free_vif(vif); } -static bool brcmf_is_linkup(const struct brcmf_event_msg *e) +static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif, + const struct brcmf_event_msg *e) { u32 event = e->event_code; u32 status = e->status; + if (event == BRCMF_E_PSK_SUP && + status == BRCMF_E_STATUS_FWSUP_COMPLETED) + set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state); if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { brcmf_dbg(CONN, "Processing set ssid\n"); - return true; + memcpy(vif->profile.bssid, e->addr, ETH_ALEN); + if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK) + return true; + + set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state); } + if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) && + test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) { + clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state); + clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state); + return true; + } return false; } @@ -5291,6 +5347,13 @@ static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg, return true; } + if (event == BRCMF_E_PSK_SUP && + status != BRCMF_E_STATUS_FWSUP_COMPLETED) { + brcmf_dbg(CONN, "Processing failed supplicant state: %u\n", + status); + return true; + } + return false; } @@ -5448,7 +5511,6 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, &ifp->vif->sme_state)) { if (completed) { brcmf_get_assoc_ies(cfg, ifp); - memcpy(profile->bssid, e->addr, ETH_ALEN); brcmf_update_bss_info(cfg, ifp); set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); @@ -5527,7 +5589,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, if (brcmf_is_apmode(ifp->vif)) { err = brcmf_notify_connect_status_ap(cfg, ndev, e, data); - } else if (brcmf_is_linkup(e)) { + } else if (brcmf_is_linkup(ifp->vif, e)) { brcmf_dbg(CONN, "Linkup\n"); if (brcmf_is_ibssmode(ifp->vif)) { brcmf_inform_ibss(cfg, ndev, e->addr); @@ -5695,6 +5757,8 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) brcmf_p2p_notify_action_tx_complete); brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, brcmf_p2p_notify_action_tx_complete); + brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP, + brcmf_notify_connect_status); } static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) @@ -6491,6 +6555,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; if (!ifp->drvr->settings->roamoff) wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 12ff15446c6c..9e7d3c6f625e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -115,6 +115,11 @@ struct brcmf_cfg80211_security { u32 cipher_group; }; +enum brcmf_profile_fwsup { + BRCMF_PROFILE_FWSUP_NONE, + BRCMF_PROFILE_FWSUP_PSK +}; + /** * struct brcmf_cfg80211_profile - profile information. * @@ -126,6 +131,7 @@ struct brcmf_cfg80211_profile { u8 bssid[ETH_ALEN]; struct brcmf_cfg80211_security sec; struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS]; + enum brcmf_profile_fwsup use_fwsup; }; /** @@ -133,16 +139,20 @@ struct brcmf_cfg80211_profile { * * @BRCMF_VIF_STATUS_READY: ready for operation. * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. - * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. + * @BRCMF_VIF_STATUS_CONNECTED: connected/joined successfully. * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress. * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. + * @BRCMF_VIF_STATUS_EAP_SUCCUSS: EAPOL handshake successful. + * @BRCMF_VIF_STATUS_ASSOC_SUCCESS: successful SET_SSID received. */ enum brcmf_vif_status { BRCMF_VIF_STATUS_READY, BRCMF_VIF_STATUS_CONNECTING, BRCMF_VIF_STATUS_CONNECTED, BRCMF_VIF_STATUS_DISCONNECTING, - BRCMF_VIF_STATUS_AP_CREATED + BRCMF_VIF_STATUS_AP_CREATED, + BRCMF_VIF_STATUS_EAP_SUCCESS, + BRCMF_VIF_STATUS_ASSOC_SUCCESS, }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 8c7ef59944f0..d21258d277ce 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -195,6 +195,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) drvr->settings->feature_disable); ifp->drvr->feat_flags &= ~drvr->settings->feature_disable; } + brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); /* set chip related quirks */ switch (drvr->bus_if->chip) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index c1dbd17506aa..1ab4f1617112 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -32,6 +32,7 @@ * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL. * MFP: 802.11w Management Frame Protection. * GSCAN: enhanced scan offload feature. + * FWSUP: Firmware supplicant. */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -46,7 +47,8 @@ BRCMF_FEAT_DEF(WOWL_GTK) \ BRCMF_FEAT_DEF(WOWL_ARP_ND) \ BRCMF_FEAT_DEF(MFP) \ - BRCMF_FEAT_DEF(GSCAN) + BRCMF_FEAT_DEF(GSCAN) \ + BRCMF_FEAT_DEF(FWSUP) /* * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h index 5fba4b49f3b3..816f80ea925b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h @@ -142,6 +142,16 @@ enum brcmf_fweh_event_code { #define BRCMF_E_STATUS_CS_ABORT 15 #define BRCMF_E_STATUS_ERROR 16 +/* status field values for PSK_SUP event */ +#define BRCMF_E_STATUS_FWSUP_WAIT_M1 4 +#define BRCMF_E_STATUS_FWSUP_PREP_M2 5 +#define BRCMF_E_STATUS_FWSUP_COMPLETED 6 +#define BRCMF_E_STATUS_FWSUP_TIMEOUT 7 +#define BRCMF_E_STATUS_FWSUP_WAIT_M3 8 +#define BRCMF_E_STATUS_FWSUP_PREP_M4 9 +#define BRCMF_E_STATUS_FWSUP_WAIT_G1 10 +#define BRCMF_E_STATUS_FWSUP_PREP_G2 11 + /* reason field values in struct brcmf_event_msg */ #define BRCMF_E_REASON_INITIAL_ASSOC 0 #define BRCMF_E_REASON_LOW_RSSI 1 @@ -161,6 +171,26 @@ enum brcmf_fweh_event_code { #define BRCMF_E_REASON_TDLS_PEER_CONNECTED 1 #define BRCMF_E_REASON_TDLS_PEER_DISCONNECTED 2 +/* reason field values for PSK_SUP event */ +#define BRCMF_E_REASON_FWSUP_OTHER 0 +#define BRCMF_E_REASON_FWSUP_DECRYPT_KEY_DATA 1 +#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP128 2 +#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP40 3 +#define BRCMF_E_REASON_FWSUP_UNSUP_KEY_LEN 4 +#define BRCMF_E_REASON_FWSUP_PW_KEY_CIPHER 5 +#define BRCMF_E_REASON_FWSUP_MSG3_TOO_MANY_IE 6 +#define BRCMF_E_REASON_FWSUP_MSG3_IE_MISMATCH 7 +#define BRCMF_E_REASON_FWSUP_NO_INSTALL_FLAG 8 +#define BRCMF_E_REASON_FWSUP_MSG3_NO_GTK 9 +#define BRCMF_E_REASON_FWSUP_GRP_KEY_CIPHER 10 +#define BRCMF_E_REASON_FWSUP_GRP_MSG1_NO_GTK 11 +#define BRCMF_E_REASON_FWSUP_GTK_DECRYPT_FAIL 12 +#define BRCMF_E_REASON_FWSUP_SEND_FAIL 13 +#define BRCMF_E_REASON_FWSUP_DEAUTH 14 +#define BRCMF_E_REASON_FWSUP_WPA_PSK_TMO 15 +#define BRCMF_E_REASON_FWSUP_WPA_PSK_M1_TMO 16 +#define BRCMF_E_REASON_FWSUP_WPA_PSK_M3_TMO 17 + /* action field values for brcmf_ifevent */ #define BRCMF_E_IF_ADD 1 #define BRCMF_E_IF_DEL 2 diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h index 3a9a76dd9222..63b1287e2e6d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h @@ -85,6 +85,7 @@ #define BRCMF_C_SET_SCAN_PASSIVE_TIME 258 #define BRCMF_C_GET_VAR 262 #define BRCMF_C_SET_VAR 263 +#define BRCMF_C_SET_WSEC_PMK 268 s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index b857d539b9ac..8391989b1882 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -45,6 +45,9 @@ #define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff #define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 +#define BRCMF_WSEC_MAX_PSK_LEN 32 +#define BRCMF_WSEC_PASSPHRASE BIT(0) + /* primary (ie tx) key */ #define BRCMF_PRIMARY_KEY (1 << 1) #define DOT11_BSSTYPE_ANY 2 @@ -470,6 +473,19 @@ struct brcmf_wsec_key_le { u8 ea[ETH_ALEN]; /* per station */ }; +/** + * struct brcmf_wsec_pmk_le - firmware pmk material. + * + * @key_len: number of octets in key material. + * @flags: key handling qualifiers. + * @key: PMK key material. + */ +struct brcmf_wsec_pmk_le { + __le16 key_len; + __le16 flags; + u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1]; +}; + /* Used to get specific STA parameters */ struct brcmf_scb_val_le { __le32 val; -- cgit v1.2.3 From 2526ff21aa77c205f72e8263335f20b7d7e636fc Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 9 Jun 2017 13:08:48 +0100 Subject: brcmfmac: support 4-way handshake offloading for 802.1X Adding callbacks for PMK provisioning. If firmware supports offloading it is indicated to user-space that 802.1X offload is supported. Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 61 ++++++++++++++++++++-- .../broadcom/brcm80211/brcmfmac/cfg80211.h | 3 +- 2 files changed, 60 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 36945e0c8923..0287db38fb9f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1717,6 +1717,7 @@ static s32 brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) { struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; s32 val; s32 err; const struct brcmf_tlv *rsn_ie; @@ -1727,6 +1728,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) u32 mfp; u16 count; + profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE; + if (!sme->crypto.n_akm_suites) return 0; @@ -1739,6 +1742,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) switch (sme->crypto.akm_suites[0]) { case WLAN_AKM_SUITE_8021X: val = WPA_AUTH_UNSPECIFIED; + if (sme->want_1x) + profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; break; case WLAN_AKM_SUITE_PSK: val = WPA_AUTH_PSK; @@ -1752,9 +1757,13 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) switch (sme->crypto.akm_suites[0]) { case WLAN_AKM_SUITE_8021X: val = WPA2_AUTH_UNSPECIFIED; + if (sme->want_1x) + profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; break; case WLAN_AKM_SUITE_8021X_SHA256: val = WPA2_AUTH_1X_SHA256; + if (sme->want_1x) + profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; break; case WLAN_AKM_SUITE_PSK_SHA256: val = WPA2_AUTH_PSK_SHA256; @@ -1769,6 +1778,9 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) } } + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X) + brcmf_dbg(INFO, "using 1X offload\n"); + if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) goto skip_mfp_config; /* The MFP mode (1 or 2) needs to be determined, parse IEs. The @@ -1941,6 +1953,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct ieee80211_channel *chan = sme->channel; struct brcmf_join_params join_params; size_t join_params_size; @@ -2038,16 +2051,24 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, } if (sme->crypto.psk) { + if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) { + err = -EINVAL; + goto done; + } brcmf_dbg(INFO, "using PSK offload\n"); + profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK; + } + if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) { /* enable firmware supplicant for this interface */ err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1); if (err < 0) { brcmf_err("failed to enable fw supplicant\n"); goto done; } - ifp->vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_PSK; + } + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) { err = brcmf_set_pmk(ifp, sme->crypto.psk, BRCMF_WSEC_MAX_PSK_LEN); if (err) @@ -5193,6 +5214,34 @@ brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev, } #endif +static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev, + const struct cfg80211_pmk_conf *conf) +{ + struct brcmf_if *ifp; + + brcmf_dbg(TRACE, "enter\n"); + + /* expect using firmware supplicant for 1X */ + ifp = netdev_priv(dev); + if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X)) + return -EINVAL; + + return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len); +} + +static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev, + const u8 *aa) +{ + struct brcmf_if *ifp; + + brcmf_dbg(TRACE, "enter\n"); + ifp = netdev_priv(dev); + if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X)) + return -EINVAL; + + return brcmf_set_pmk(ifp, NULL, 0); +} + static struct cfg80211_ops brcmf_cfg80211_ops = { .add_virtual_intf = brcmf_cfg80211_add_iface, .del_virtual_intf = brcmf_cfg80211_del_iface, @@ -5236,6 +5285,8 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { .crit_proto_stop = brcmf_cfg80211_crit_proto_stop, .tdls_oper = brcmf_cfg80211_tdls_oper, .update_connect_params = brcmf_cfg80211_update_conn_params, + .set_pmk = brcmf_cfg80211_set_pmk, + .del_pmk = brcmf_cfg80211_del_pmk, }; struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, @@ -5295,7 +5346,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif, u32 event = e->event_code; u32 status = e->status; - if (event == BRCMF_E_PSK_SUP && + if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK && + event == BRCMF_E_PSK_SUP && status == BRCMF_E_STATUS_FWSUP_COMPLETED) set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state); if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { @@ -6555,9 +6607,12 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; if (!ifp->drvr->settings->roamoff) wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) { wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X); + } wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 9e7d3c6f625e..7b2835e5e434 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -117,7 +117,8 @@ struct brcmf_cfg80211_security { enum brcmf_profile_fwsup { BRCMF_PROFILE_FWSUP_NONE, - BRCMF_PROFILE_FWSUP_PSK + BRCMF_PROFILE_FWSUP_PSK, + BRCMF_PROFILE_FWSUP_1X }; /** -- cgit v1.2.3 From 123fef3fd4ae6052bad5cf1623c49845d16a6c67 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 9 Jun 2017 13:08:49 +0100 Subject: brcmfmac: switch to using cfg80211_connect_done() The driver used cfg80211_connect_result() which is basically a wrapper around cfg80211_connect_done() passing a subset of the information that can be passed. For upcoming functionality this is not sufficient so switching to use cfg80211_connect_done(). Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 0287db38fb9f..dcde596c9eb9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -5556,26 +5556,28 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); + struct cfg80211_connect_resp_params conn_params; brcmf_dbg(TRACE, "Enter\n"); if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) { + memset(&conn_params, 0, sizeof(conn_params)); if (completed) { brcmf_get_assoc_ies(cfg, ifp); brcmf_update_bss_info(cfg, ifp); set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); + conn_params.status = WLAN_STATUS_SUCCESS; + } else { + conn_params.status = WLAN_STATUS_AUTH_TIMEOUT; } - cfg80211_connect_result(ndev, - (u8 *)profile->bssid, - conn_info->req_ie, - conn_info->req_ie_len, - conn_info->resp_ie, - conn_info->resp_ie_len, - completed ? WLAN_STATUS_SUCCESS : - WLAN_STATUS_AUTH_TIMEOUT, - GFP_KERNEL); + conn_params.bssid = profile->bssid; + conn_params.req_ie = conn_info->req_ie; + conn_params.req_ie_len = conn_info->req_ie_len; + conn_params.resp_ie = conn_info->resp_ie; + conn_params.resp_ie_len = conn_info->resp_ie_len; + cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL); brcmf_dbg(CONN, "Report connect result - connection %s\n", completed ? "succeeded" : "failed"); } -- cgit v1.2.3 From 8a063a27815a759b99ad710402da1ccd1b0987f7 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Wed, 28 Jun 2017 12:26:58 +0530 Subject: mwifiex: do not update MCS set from hostapd We should not copy the MCS set from hostapd RX-STBC. We have to just use the MCS set supported by the hardware. This fixes an issue, where mwifiex is advertising wrong MCS sets in beacons. Fixes: 474a41e94dfc ("mwifiex: update MCS set as per RX-STBC bit from hostapd") Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/fw.h | 5 ----- drivers/net/wireless/marvell/mwifiex/uap_cmd.c | 22 ---------------------- 2 files changed, 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index b4d915b9232c..9e75522d248a 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -247,11 +247,6 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define MWIFIEX_DEF_AMPDU IEEE80211_HT_AMPDU_PARM_FACTOR -#define GET_RXSTBC(x) (x & IEEE80211_HT_CAP_RX_STBC) -#define MWIFIEX_RX_STBC1 0x0100 -#define MWIFIEX_RX_STBC12 0x0200 -#define MWIFIEX_RX_STBC123 0x0300 - /* dev_cap bitmap * BIT * 0-16 reserved diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c index 35d8636bdb91..477c29c9f5d9 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c @@ -160,7 +160,6 @@ mwifiex_set_ht_params(struct mwifiex_private *priv, struct cfg80211_ap_settings *params) { const u8 *ht_ie; - u16 cap_info; if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) return; @@ -170,27 +169,6 @@ mwifiex_set_ht_params(struct mwifiex_private *priv, if (ht_ie) { memcpy(&bss_cfg->ht_cap, ht_ie + 2, sizeof(struct ieee80211_ht_cap)); - cap_info = le16_to_cpu(bss_cfg->ht_cap.cap_info); - memset(&bss_cfg->ht_cap.mcs, 0, - priv->adapter->number_of_antenna); - switch (GET_RXSTBC(cap_info)) { - case MWIFIEX_RX_STBC1: - /* HT_CAP 1X1 mode */ - bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff; - break; - case MWIFIEX_RX_STBC12: /* fall through */ - case MWIFIEX_RX_STBC123: - /* HT_CAP 2X2 mode */ - bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff; - bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff; - break; - default: - mwifiex_dbg(priv->adapter, WARN, - "Unsupported RX-STBC, default to 2x2\n"); - bss_cfg->ht_cap.mcs.rx_mask[0] = 0xff; - bss_cfg->ht_cap.mcs.rx_mask[1] = 0xff; - break; - } priv->ap_11n_enabled = 1; } else { memset(&bss_cfg->ht_cap, 0, sizeof(struct ieee80211_ht_cap)); -- cgit v1.2.3 From 7b4296148066f19b5960127ba579e358df501c22 Mon Sep 17 00:00:00 2001 From: Rafal Ozieblo Date: Thu, 29 Jun 2017 07:12:51 +0100 Subject: net: macb: Add support for PTP timestamps in DMA descriptors This patch adds support for PTP timestamps in DMA buffer descriptors. It checks capability at runtime and uses appropriate buffer descriptor. Signed-off-by: Rafal Ozieblo Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/Kconfig | 10 ++- drivers/net/ethernet/cadence/macb.c | 117 ++++++++++++++++++++++++++--------- drivers/net/ethernet/cadence/macb.h | 32 +++++++--- 3 files changed, 122 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig index 608bea171956..427d65a1a126 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -29,7 +29,15 @@ config MACB support for the MACB/GEM chip. To compile this driver as a module, choose M here: the module - will be called macb. + will be macb. + +config MACB_USE_HWSTAMP + bool "Use IEEE 1588 hwstamp" + depends on MACB + default y + imply PTP_1588_CLOCK + ---help--- + Enable IEEE 1588 Precision Time Protocol (PTP) support for MACB. config MACB_PCI tristate "Cadence PCI MACB/GEM support" diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 3ae9d8071ded..2d43a7619f58 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -79,33 +79,84 @@ #define MACB_HALT_TIMEOUT 1230 /* DMA buffer descriptor might be different size - * depends on hardware configuration. + * depends on hardware configuration: + * + * 1. dma address width 32 bits: + * word 1: 32 bit address of Data Buffer + * word 2: control + * + * 2. dma address width 64 bits: + * word 1: 32 bit address of Data Buffer + * word 2: control + * word 3: upper 32 bit address of Data Buffer + * word 4: unused + * + * 3. dma address width 32 bits with hardware timestamping: + * word 1: 32 bit address of Data Buffer + * word 2: control + * word 3: timestamp word 1 + * word 4: timestamp word 2 + * + * 4. dma address width 64 bits with hardware timestamping: + * word 1: 32 bit address of Data Buffer + * word 2: control + * word 3: upper 32 bit address of Data Buffer + * word 4: unused + * word 5: timestamp word 1 + * word 6: timestamp word 2 */ static unsigned int macb_dma_desc_get_size(struct macb *bp) { -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap == HW_DMA_CAP_64B) - return sizeof(struct macb_dma_desc) + sizeof(struct macb_dma_desc_64); +#ifdef MACB_EXT_DESC + unsigned int desc_size; + + switch (bp->hw_dma_cap) { + case HW_DMA_CAP_64B: + desc_size = sizeof(struct macb_dma_desc) + + sizeof(struct macb_dma_desc_64); + break; + case HW_DMA_CAP_PTP: + desc_size = sizeof(struct macb_dma_desc) + + sizeof(struct macb_dma_desc_ptp); + break; + case HW_DMA_CAP_64B_PTP: + desc_size = sizeof(struct macb_dma_desc) + + sizeof(struct macb_dma_desc_64) + + sizeof(struct macb_dma_desc_ptp); + break; + default: + desc_size = sizeof(struct macb_dma_desc); + } + return desc_size; #endif return sizeof(struct macb_dma_desc); } -static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int idx) +static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int desc_idx) { -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - /* Dma buffer descriptor is 4 words length (instead of 2 words) - * for 64b GEM. - */ - if (bp->hw_dma_cap == HW_DMA_CAP_64B) - idx <<= 1; +#ifdef MACB_EXT_DESC + switch (bp->hw_dma_cap) { + case HW_DMA_CAP_64B: + case HW_DMA_CAP_PTP: + desc_idx <<= 1; + break; + case HW_DMA_CAP_64B_PTP: + desc_idx *= 3; + break; + default: + break; + } + return desc_idx; #endif - return idx; + return desc_idx; } #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT static struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct macb_dma_desc *desc) { - return (struct macb_dma_desc_64 *)((void *)desc + sizeof(struct macb_dma_desc)); + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + return (struct macb_dma_desc_64 *)((void *)desc + sizeof(struct macb_dma_desc)); + return NULL; } #endif @@ -621,7 +672,7 @@ static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_ #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT struct macb_dma_desc_64 *desc_64; - if (bp->hw_dma_cap == HW_DMA_CAP_64B) { + if (bp->hw_dma_cap & HW_DMA_CAP_64B) { desc_64 = macb_64b_desc(bp, desc); desc_64->addrh = upper_32_bits(addr); } @@ -635,7 +686,7 @@ static dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc) #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT struct macb_dma_desc_64 *desc_64; - if (bp->hw_dma_cap == HW_DMA_CAP_64B) { + if (bp->hw_dma_cap & HW_DMA_CAP_64B) { desc_64 = macb_64b_desc(bp, desc); addr = ((u64)(desc_64->addrh) << 32); } @@ -734,7 +785,7 @@ static void macb_tx_error_task(struct work_struct *work) /* Reinitialize the TX desc queue */ queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap == HW_DMA_CAP_64B) + if (bp->hw_dma_cap & HW_DMA_CAP_64B) queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); #endif /* Make TX ring reflect state of hardware */ @@ -1942,8 +1993,12 @@ static void macb_configure_dma(struct macb *bp) dmacfg &= ~GEM_BIT(TXCOEN); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap == HW_DMA_CAP_64B) + if (bp->hw_dma_cap & HW_DMA_CAP_64B) dmacfg |= GEM_BIT(ADDR64); +#endif +#ifdef CONFIG_MACB_USE_HWSTAMP + if (bp->hw_dma_cap & HW_DMA_CAP_PTP) + dmacfg |= GEM_BIT(RXEXT) | GEM_BIT(TXEXT); #endif netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n", dmacfg); @@ -1992,13 +2047,13 @@ static void macb_init_hw(struct macb *bp) /* Initialize TX and RX buffers */ macb_writel(bp, RBQP, lower_32_bits(bp->rx_ring_dma)); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap == HW_DMA_CAP_64B) + if (bp->hw_dma_cap & HW_DMA_CAP_64B) macb_writel(bp, RBQPH, upper_32_bits(bp->rx_ring_dma)); #endif for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap == HW_DMA_CAP_64B) + if (bp->hw_dma_cap & HW_DMA_CAP_64B) queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); #endif @@ -2600,6 +2655,12 @@ static void macb_configure_caps(struct macb *bp, dcfg = gem_readl(bp, DCFG2); if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0) bp->caps |= MACB_CAPS_FIFO_MODE; + if (IS_ENABLED(CONFIG_MACB_USE_HWSTAMP) && gem_has_ptp(bp)) { + if (!GEM_BFEXT(TSU, gem_readl(bp, DCFG5))) + pr_err("GEM doesn't support hardware ptp.\n"); + else + bp->hw_dma_cap |= HW_DMA_CAP_PTP; + } } dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps); @@ -2737,7 +2798,7 @@ static int macb_init(struct platform_device *pdev) queue->IMR = GEM_IMR(hw_q - 1); queue->TBQP = GEM_TBQP(hw_q - 1); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap == HW_DMA_CAP_64B) + if (bp->hw_dma_cap & HW_DMA_CAP_64B) queue->TBQPH = GEM_TBQPH(hw_q - 1); #endif } else { @@ -2748,7 +2809,7 @@ static int macb_init(struct platform_device *pdev) queue->IMR = MACB_IMR; queue->TBQP = MACB_TBQP; #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap == HW_DMA_CAP_64B) + if (bp->hw_dma_cap & HW_DMA_CAP_64B) queue->TBQPH = MACB_TBQPH; #endif } @@ -3328,19 +3389,17 @@ static int macb_probe(struct platform_device *pdev) bp->wol |= MACB_WOL_HAS_MAGIC_PACKET; device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) { - dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); - bp->hw_dma_cap = HW_DMA_CAP_64B; - } else - bp->hw_dma_cap = HW_DMA_CAP_32B; -#endif - spin_lock_init(&bp->lock); /* setup capabilities */ macb_configure_caps(bp, macb_config); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) { + dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); + bp->hw_dma_cap |= HW_DMA_CAP_64B; + } +#endif platform_set_drvdata(pdev, dev); dev->irq = platform_get_irq(pdev, 0); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 2510661102ba..3aefa380f345 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -12,6 +12,10 @@ #include +#if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP) +#define MACB_EXT_DESC +#endif + #define MACB_GREGS_NBR 16 #define MACB_GREGS_VERSION 2 #define MACB_MAX_QUEUES 8 @@ -269,6 +273,10 @@ #define GEM_RXBS_SIZE 8 #define GEM_DDRP_OFFSET 24 /* disc_when_no_ahb */ #define GEM_DDRP_SIZE 1 +#define GEM_RXEXT_OFFSET 28 /* RX extended Buffer Descriptor mode */ +#define GEM_RXEXT_SIZE 1 +#define GEM_TXEXT_OFFSET 29 /* TX extended Buffer Descriptor mode */ +#define GEM_TXEXT_SIZE 1 #define GEM_ADDR64_OFFSET 30 /* Address bus width - 64b or 32b */ #define GEM_ADDR64_SIZE 1 @@ -425,6 +433,11 @@ #define GEM_TX_PKT_BUFF_OFFSET 21 #define GEM_TX_PKT_BUFF_SIZE 1 + +/* Bitfields in DCFG5. */ +#define GEM_TSU_OFFSET 8 +#define GEM_TSU_SIZE 1 + /* Bitfields in DCFG6. */ #define GEM_PBUF_LSO_OFFSET 27 #define GEM_PBUF_LSO_SIZE 1 @@ -546,16 +559,21 @@ struct macb_dma_desc { u32 ctrl; }; -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -enum macb_hw_dma_cap { - HW_DMA_CAP_32B, - HW_DMA_CAP_64B, -}; +#ifdef MACB_EXT_DESC +#define HW_DMA_CAP_32B 0 +#define HW_DMA_CAP_64B (1 << 0) +#define HW_DMA_CAP_PTP (1 << 1) +#define HW_DMA_CAP_64B_PTP (HW_DMA_CAP_64B | HW_DMA_CAP_PTP) struct macb_dma_desc_64 { u32 addrh; u32 resvd; }; + +struct macb_dma_desc_ptp { + u32 ts_1; + u32 ts_2; +}; #endif /* DMA descriptor bitfields */ @@ -955,8 +973,8 @@ struct macb { u32 wol; struct macb_ptp_info *ptp_info; /* macb-ptp interface */ -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - enum macb_hw_dma_cap hw_dma_cap; +#ifdef MACB_EXT_DESC + uint8_t hw_dma_cap; #endif }; -- cgit v1.2.3 From b83f1527d098c04424832b0a59d75046e26bfff1 Mon Sep 17 00:00:00 2001 From: Rafal Ozieblo Date: Thu, 29 Jun 2017 07:13:46 +0100 Subject: net: macb: macb.c changed to macb_main.c In case that macb is compiled as a module, macb.c has been renamed to macb_main.c to avoid naming confusion in Makefile. Signed-off-by: Rafal Ozieblo Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/Makefile | 1 + drivers/net/ethernet/cadence/macb.c | 3588 ------------------------------ drivers/net/ethernet/cadence/macb_main.c | 3588 ++++++++++++++++++++++++++++++ 3 files changed, 3589 insertions(+), 3588 deletions(-) delete mode 100644 drivers/net/ethernet/cadence/macb.c create mode 100644 drivers/net/ethernet/cadence/macb_main.c (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile index 4ba75594d5c5..31ea6e34147a 100644 --- a/drivers/net/ethernet/cadence/Makefile +++ b/drivers/net/ethernet/cadence/Makefile @@ -1,6 +1,7 @@ # # Makefile for the Atmel network device drivers. # +macb-y := macb_main.o obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MACB_PCI) += macb_pci.o diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c deleted file mode 100644 index 2d43a7619f58..000000000000 --- a/drivers/net/ethernet/cadence/macb.c +++ /dev/null @@ -1,3588 +0,0 @@ -/* - * Cadence MACB/GEM Ethernet Controller driver - * - * Copyright (C) 2004-2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "macb.h" - -#define MACB_RX_BUFFER_SIZE 128 -#define RX_BUFFER_MULTIPLE 64 /* bytes */ - -#define DEFAULT_RX_RING_SIZE 512 /* must be power of 2 */ -#define MIN_RX_RING_SIZE 64 -#define MAX_RX_RING_SIZE 8192 -#define RX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \ - * (bp)->rx_ring_size) - -#define DEFAULT_TX_RING_SIZE 512 /* must be power of 2 */ -#define MIN_TX_RING_SIZE 64 -#define MAX_TX_RING_SIZE 4096 -#define TX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \ - * (bp)->tx_ring_size) - -/* level of occupied TX descriptors under which we wake up TX process */ -#define MACB_TX_WAKEUP_THRESH(bp) (3 * (bp)->tx_ring_size / 4) - -#define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \ - | MACB_BIT(ISR_ROVR)) -#define MACB_TX_ERR_FLAGS (MACB_BIT(ISR_TUND) \ - | MACB_BIT(ISR_RLE) \ - | MACB_BIT(TXERR)) -#define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP)) - -/* Max length of transmit frame must be a multiple of 8 bytes */ -#define MACB_TX_LEN_ALIGN 8 -#define MACB_MAX_TX_LEN ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1))) -#define GEM_MAX_TX_LEN ((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1))) - -#define GEM_MTU_MIN_SIZE ETH_MIN_MTU -#define MACB_NETIF_LSO (NETIF_F_TSO | NETIF_F_UFO) - -#define MACB_WOL_HAS_MAGIC_PACKET (0x1 << 0) -#define MACB_WOL_ENABLED (0x1 << 1) - -/* Graceful stop timeouts in us. We should allow up to - * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions) - */ -#define MACB_HALT_TIMEOUT 1230 - -/* DMA buffer descriptor might be different size - * depends on hardware configuration: - * - * 1. dma address width 32 bits: - * word 1: 32 bit address of Data Buffer - * word 2: control - * - * 2. dma address width 64 bits: - * word 1: 32 bit address of Data Buffer - * word 2: control - * word 3: upper 32 bit address of Data Buffer - * word 4: unused - * - * 3. dma address width 32 bits with hardware timestamping: - * word 1: 32 bit address of Data Buffer - * word 2: control - * word 3: timestamp word 1 - * word 4: timestamp word 2 - * - * 4. dma address width 64 bits with hardware timestamping: - * word 1: 32 bit address of Data Buffer - * word 2: control - * word 3: upper 32 bit address of Data Buffer - * word 4: unused - * word 5: timestamp word 1 - * word 6: timestamp word 2 - */ -static unsigned int macb_dma_desc_get_size(struct macb *bp) -{ -#ifdef MACB_EXT_DESC - unsigned int desc_size; - - switch (bp->hw_dma_cap) { - case HW_DMA_CAP_64B: - desc_size = sizeof(struct macb_dma_desc) - + sizeof(struct macb_dma_desc_64); - break; - case HW_DMA_CAP_PTP: - desc_size = sizeof(struct macb_dma_desc) - + sizeof(struct macb_dma_desc_ptp); - break; - case HW_DMA_CAP_64B_PTP: - desc_size = sizeof(struct macb_dma_desc) - + sizeof(struct macb_dma_desc_64) - + sizeof(struct macb_dma_desc_ptp); - break; - default: - desc_size = sizeof(struct macb_dma_desc); - } - return desc_size; -#endif - return sizeof(struct macb_dma_desc); -} - -static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int desc_idx) -{ -#ifdef MACB_EXT_DESC - switch (bp->hw_dma_cap) { - case HW_DMA_CAP_64B: - case HW_DMA_CAP_PTP: - desc_idx <<= 1; - break; - case HW_DMA_CAP_64B_PTP: - desc_idx *= 3; - break; - default: - break; - } - return desc_idx; -#endif - return desc_idx; -} - -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -static struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct macb_dma_desc *desc) -{ - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - return (struct macb_dma_desc_64 *)((void *)desc + sizeof(struct macb_dma_desc)); - return NULL; -} -#endif - -/* Ring buffer accessors */ -static unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index) -{ - return index & (bp->tx_ring_size - 1); -} - -static struct macb_dma_desc *macb_tx_desc(struct macb_queue *queue, - unsigned int index) -{ - index = macb_tx_ring_wrap(queue->bp, index); - index = macb_adj_dma_desc_idx(queue->bp, index); - return &queue->tx_ring[index]; -} - -static struct macb_tx_skb *macb_tx_skb(struct macb_queue *queue, - unsigned int index) -{ - return &queue->tx_skb[macb_tx_ring_wrap(queue->bp, index)]; -} - -static dma_addr_t macb_tx_dma(struct macb_queue *queue, unsigned int index) -{ - dma_addr_t offset; - - offset = macb_tx_ring_wrap(queue->bp, index) * - macb_dma_desc_get_size(queue->bp); - - return queue->tx_ring_dma + offset; -} - -static unsigned int macb_rx_ring_wrap(struct macb *bp, unsigned int index) -{ - return index & (bp->rx_ring_size - 1); -} - -static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index) -{ - index = macb_rx_ring_wrap(bp, index); - index = macb_adj_dma_desc_idx(bp, index); - return &bp->rx_ring[index]; -} - -static void *macb_rx_buffer(struct macb *bp, unsigned int index) -{ - return bp->rx_buffers + bp->rx_buffer_size * - macb_rx_ring_wrap(bp, index); -} - -/* I/O accessors */ -static u32 hw_readl_native(struct macb *bp, int offset) -{ - return __raw_readl(bp->regs + offset); -} - -static void hw_writel_native(struct macb *bp, int offset, u32 value) -{ - __raw_writel(value, bp->regs + offset); -} - -static u32 hw_readl(struct macb *bp, int offset) -{ - return readl_relaxed(bp->regs + offset); -} - -static void hw_writel(struct macb *bp, int offset, u32 value) -{ - writel_relaxed(value, bp->regs + offset); -} - -/* Find the CPU endianness by using the loopback bit of NCR register. When the - * CPU is in big endian we need to program swapped mode for management - * descriptor access. - */ -static bool hw_is_native_io(void __iomem *addr) -{ - u32 value = MACB_BIT(LLB); - - __raw_writel(value, addr + MACB_NCR); - value = __raw_readl(addr + MACB_NCR); - - /* Write 0 back to disable everything */ - __raw_writel(0, addr + MACB_NCR); - - return value == MACB_BIT(LLB); -} - -static bool hw_is_gem(void __iomem *addr, bool native_io) -{ - u32 id; - - if (native_io) - id = __raw_readl(addr + MACB_MID); - else - id = readl_relaxed(addr + MACB_MID); - - return MACB_BFEXT(IDNUM, id) >= 0x2; -} - -static void macb_set_hwaddr(struct macb *bp) -{ - u32 bottom; - u16 top; - - bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr)); - macb_or_gem_writel(bp, SA1B, bottom); - top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4))); - macb_or_gem_writel(bp, SA1T, top); - - /* Clear unused address register sets */ - macb_or_gem_writel(bp, SA2B, 0); - macb_or_gem_writel(bp, SA2T, 0); - macb_or_gem_writel(bp, SA3B, 0); - macb_or_gem_writel(bp, SA3T, 0); - macb_or_gem_writel(bp, SA4B, 0); - macb_or_gem_writel(bp, SA4T, 0); -} - -static void macb_get_hwaddr(struct macb *bp) -{ - struct macb_platform_data *pdata; - u32 bottom; - u16 top; - u8 addr[6]; - int i; - - pdata = dev_get_platdata(&bp->pdev->dev); - - /* Check all 4 address register for valid address */ - for (i = 0; i < 4; i++) { - bottom = macb_or_gem_readl(bp, SA1B + i * 8); - top = macb_or_gem_readl(bp, SA1T + i * 8); - - if (pdata && pdata->rev_eth_addr) { - addr[5] = bottom & 0xff; - addr[4] = (bottom >> 8) & 0xff; - addr[3] = (bottom >> 16) & 0xff; - addr[2] = (bottom >> 24) & 0xff; - addr[1] = top & 0xff; - addr[0] = (top & 0xff00) >> 8; - } else { - addr[0] = bottom & 0xff; - addr[1] = (bottom >> 8) & 0xff; - addr[2] = (bottom >> 16) & 0xff; - addr[3] = (bottom >> 24) & 0xff; - addr[4] = top & 0xff; - addr[5] = (top >> 8) & 0xff; - } - - if (is_valid_ether_addr(addr)) { - memcpy(bp->dev->dev_addr, addr, sizeof(addr)); - return; - } - } - - dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); - eth_hw_addr_random(bp->dev); -} - -static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -{ - struct macb *bp = bus->priv; - int value; - - macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) - | MACB_BF(RW, MACB_MAN_READ) - | MACB_BF(PHYA, mii_id) - | MACB_BF(REGA, regnum) - | MACB_BF(CODE, MACB_MAN_CODE))); - - /* wait for end of transfer */ - while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) - cpu_relax(); - - value = MACB_BFEXT(DATA, macb_readl(bp, MAN)); - - return value; -} - -static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, - u16 value) -{ - struct macb *bp = bus->priv; - - macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) - | MACB_BF(RW, MACB_MAN_WRITE) - | MACB_BF(PHYA, mii_id) - | MACB_BF(REGA, regnum) - | MACB_BF(CODE, MACB_MAN_CODE) - | MACB_BF(DATA, value))); - - /* wait for end of transfer */ - while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) - cpu_relax(); - - return 0; -} - -/** - * macb_set_tx_clk() - Set a clock to a new frequency - * @clk Pointer to the clock to change - * @rate New frequency in Hz - * @dev Pointer to the struct net_device - */ -static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) -{ - long ferr, rate, rate_rounded; - - if (!clk) - return; - - switch (speed) { - case SPEED_10: - rate = 2500000; - break; - case SPEED_100: - rate = 25000000; - break; - case SPEED_1000: - rate = 125000000; - break; - default: - return; - } - - rate_rounded = clk_round_rate(clk, rate); - if (rate_rounded < 0) - return; - - /* RGMII allows 50 ppm frequency error. Test and warn if this limit - * is not satisfied. - */ - ferr = abs(rate_rounded - rate); - ferr = DIV_ROUND_UP(ferr, rate / 100000); - if (ferr > 5) - netdev_warn(dev, "unable to generate target frequency: %ld Hz\n", - rate); - - if (clk_set_rate(clk, rate_rounded)) - netdev_err(dev, "adjusting tx_clk failed.\n"); -} - -static void macb_handle_link_change(struct net_device *dev) -{ - struct macb *bp = netdev_priv(dev); - struct phy_device *phydev = dev->phydev; - unsigned long flags; - int status_change = 0; - - spin_lock_irqsave(&bp->lock, flags); - - if (phydev->link) { - if ((bp->speed != phydev->speed) || - (bp->duplex != phydev->duplex)) { - u32 reg; - - reg = macb_readl(bp, NCFGR); - reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); - if (macb_is_gem(bp)) - reg &= ~GEM_BIT(GBE); - - if (phydev->duplex) - reg |= MACB_BIT(FD); - if (phydev->speed == SPEED_100) - reg |= MACB_BIT(SPD); - if (phydev->speed == SPEED_1000 && - bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) - reg |= GEM_BIT(GBE); - - macb_or_gem_writel(bp, NCFGR, reg); - - bp->speed = phydev->speed; - bp->duplex = phydev->duplex; - status_change = 1; - } - } - - if (phydev->link != bp->link) { - if (!phydev->link) { - bp->speed = 0; - bp->duplex = -1; - } - bp->link = phydev->link; - - status_change = 1; - } - - spin_unlock_irqrestore(&bp->lock, flags); - - if (status_change) { - if (phydev->link) { - /* Update the TX clock rate if and only if the link is - * up and there has been a link change. - */ - macb_set_tx_clk(bp->tx_clk, phydev->speed, dev); - - netif_carrier_on(dev); - netdev_info(dev, "link up (%d/%s)\n", - phydev->speed, - phydev->duplex == DUPLEX_FULL ? - "Full" : "Half"); - } else { - netif_carrier_off(dev); - netdev_info(dev, "link down\n"); - } - } -} - -/* based on au1000_eth. c*/ -static int macb_mii_probe(struct net_device *dev) -{ - struct macb *bp = netdev_priv(dev); - struct macb_platform_data *pdata; - struct phy_device *phydev; - int phy_irq; - int ret; - - if (bp->phy_node) { - phydev = of_phy_connect(dev, bp->phy_node, - &macb_handle_link_change, 0, - bp->phy_interface); - if (!phydev) - return -ENODEV; - } else { - phydev = phy_find_first(bp->mii_bus); - if (!phydev) { - netdev_err(dev, "no PHY found\n"); - return -ENXIO; - } - - pdata = dev_get_platdata(&bp->pdev->dev); - if (pdata) { - if (gpio_is_valid(pdata->phy_irq_pin)) { - ret = devm_gpio_request(&bp->pdev->dev, - pdata->phy_irq_pin, "phy int"); - if (!ret) { - phy_irq = gpio_to_irq(pdata->phy_irq_pin); - phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq; - } - } else { - phydev->irq = PHY_POLL; - } - } - - /* attach the mac to the phy */ - ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, - bp->phy_interface); - if (ret) { - netdev_err(dev, "Could not attach to PHY\n"); - return ret; - } - } - - /* mask with MAC supported features */ - if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) - phydev->supported &= PHY_GBIT_FEATURES; - else - phydev->supported &= PHY_BASIC_FEATURES; - - if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF) - phydev->supported &= ~SUPPORTED_1000baseT_Half; - - phydev->advertising = phydev->supported; - - bp->link = 0; - bp->speed = 0; - bp->duplex = -1; - - return 0; -} - -static int macb_mii_init(struct macb *bp) -{ - struct macb_platform_data *pdata; - struct device_node *np; - int err = -ENXIO, i; - - /* Enable management port */ - macb_writel(bp, NCR, MACB_BIT(MPE)); - - bp->mii_bus = mdiobus_alloc(); - if (!bp->mii_bus) { - err = -ENOMEM; - goto err_out; - } - - bp->mii_bus->name = "MACB_mii_bus"; - bp->mii_bus->read = &macb_mdio_read; - bp->mii_bus->write = &macb_mdio_write; - snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", - bp->pdev->name, bp->pdev->id); - bp->mii_bus->priv = bp; - bp->mii_bus->parent = &bp->pdev->dev; - pdata = dev_get_platdata(&bp->pdev->dev); - - dev_set_drvdata(&bp->dev->dev, bp->mii_bus); - - np = bp->pdev->dev.of_node; - if (np) { - if (of_phy_is_fixed_link(np)) { - if (of_phy_register_fixed_link(np) < 0) { - dev_err(&bp->pdev->dev, - "broken fixed-link specification\n"); - goto err_out_unregister_bus; - } - bp->phy_node = of_node_get(np); - - err = mdiobus_register(bp->mii_bus); - } else { - /* try dt phy registration */ - err = of_mdiobus_register(bp->mii_bus, np); - - /* fallback to standard phy registration if no phy were - * found during dt phy registration - */ - if (!err && !phy_find_first(bp->mii_bus)) { - for (i = 0; i < PHY_MAX_ADDR; i++) { - struct phy_device *phydev; - - phydev = mdiobus_scan(bp->mii_bus, i); - if (IS_ERR(phydev) && - PTR_ERR(phydev) != -ENODEV) { - err = PTR_ERR(phydev); - break; - } - } - - if (err) - goto err_out_unregister_bus; - } - } - } else { - for (i = 0; i < PHY_MAX_ADDR; i++) - bp->mii_bus->irq[i] = PHY_POLL; - - if (pdata) - bp->mii_bus->phy_mask = pdata->phy_mask; - - err = mdiobus_register(bp->mii_bus); - } - - if (err) - goto err_out_free_mdiobus; - - err = macb_mii_probe(bp->dev); - if (err) - goto err_out_unregister_bus; - - return 0; - -err_out_unregister_bus: - mdiobus_unregister(bp->mii_bus); -err_out_free_mdiobus: - mdiobus_free(bp->mii_bus); -err_out: - return err; -} - -static void macb_update_stats(struct macb *bp) -{ - u32 *p = &bp->hw_stats.macb.rx_pause_frames; - u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1; - int offset = MACB_PFR; - - WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); - - for (; p < end; p++, offset += 4) - *p += bp->macb_reg_readl(bp, offset); -} - -static int macb_halt_tx(struct macb *bp) -{ - unsigned long halt_time, timeout; - u32 status; - - macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT)); - - timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT); - do { - halt_time = jiffies; - status = macb_readl(bp, TSR); - if (!(status & MACB_BIT(TGO))) - return 0; - - usleep_range(10, 250); - } while (time_before(halt_time, timeout)); - - return -ETIMEDOUT; -} - -static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb) -{ - if (tx_skb->mapping) { - if (tx_skb->mapped_as_page) - dma_unmap_page(&bp->pdev->dev, tx_skb->mapping, - tx_skb->size, DMA_TO_DEVICE); - else - dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, - tx_skb->size, DMA_TO_DEVICE); - tx_skb->mapping = 0; - } - - if (tx_skb->skb) { - dev_kfree_skb_any(tx_skb->skb); - tx_skb->skb = NULL; - } -} - -static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_t addr) -{ -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - struct macb_dma_desc_64 *desc_64; - - if (bp->hw_dma_cap & HW_DMA_CAP_64B) { - desc_64 = macb_64b_desc(bp, desc); - desc_64->addrh = upper_32_bits(addr); - } -#endif - desc->addr = lower_32_bits(addr); -} - -static dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc) -{ - dma_addr_t addr = 0; -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - struct macb_dma_desc_64 *desc_64; - - if (bp->hw_dma_cap & HW_DMA_CAP_64B) { - desc_64 = macb_64b_desc(bp, desc); - addr = ((u64)(desc_64->addrh) << 32); - } -#endif - addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr)); - return addr; -} - -static void macb_tx_error_task(struct work_struct *work) -{ - struct macb_queue *queue = container_of(work, struct macb_queue, - tx_error_task); - struct macb *bp = queue->bp; - struct macb_tx_skb *tx_skb; - struct macb_dma_desc *desc; - struct sk_buff *skb; - unsigned int tail; - unsigned long flags; - - netdev_vdbg(bp->dev, "macb_tx_error_task: q = %u, t = %u, h = %u\n", - (unsigned int)(queue - bp->queues), - queue->tx_tail, queue->tx_head); - - /* Prevent the queue IRQ handlers from running: each of them may call - * macb_tx_interrupt(), which in turn may call netif_wake_subqueue(). - * As explained below, we have to halt the transmission before updating - * TBQP registers so we call netif_tx_stop_all_queues() to notify the - * network engine about the macb/gem being halted. - */ - spin_lock_irqsave(&bp->lock, flags); - - /* Make sure nobody is trying to queue up new packets */ - netif_tx_stop_all_queues(bp->dev); - - /* Stop transmission now - * (in case we have just queued new packets) - * macb/gem must be halted to write TBQP register - */ - if (macb_halt_tx(bp)) - /* Just complain for now, reinitializing TX path can be good */ - netdev_err(bp->dev, "BUG: halt tx timed out\n"); - - /* Treat frames in TX queue including the ones that caused the error. - * Free transmit buffers in upper layer. - */ - for (tail = queue->tx_tail; tail != queue->tx_head; tail++) { - u32 ctrl; - - desc = macb_tx_desc(queue, tail); - ctrl = desc->ctrl; - tx_skb = macb_tx_skb(queue, tail); - skb = tx_skb->skb; - - if (ctrl & MACB_BIT(TX_USED)) { - /* skb is set for the last buffer of the frame */ - while (!skb) { - macb_tx_unmap(bp, tx_skb); - tail++; - tx_skb = macb_tx_skb(queue, tail); - skb = tx_skb->skb; - } - - /* ctrl still refers to the first buffer descriptor - * since it's the only one written back by the hardware - */ - if (!(ctrl & MACB_BIT(TX_BUF_EXHAUSTED))) { - netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n", - macb_tx_ring_wrap(bp, tail), - skb->data); - bp->dev->stats.tx_packets++; - bp->dev->stats.tx_bytes += skb->len; - } - } else { - /* "Buffers exhausted mid-frame" errors may only happen - * if the driver is buggy, so complain loudly about - * those. Statistics are updated by hardware. - */ - if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED)) - netdev_err(bp->dev, - "BUG: TX buffers exhausted mid-frame\n"); - - desc->ctrl = ctrl | MACB_BIT(TX_USED); - } - - macb_tx_unmap(bp, tx_skb); - } - - /* Set end of TX queue */ - desc = macb_tx_desc(queue, 0); - macb_set_addr(bp, desc, 0); - desc->ctrl = MACB_BIT(TX_USED); - - /* Make descriptor updates visible to hardware */ - wmb(); - - /* Reinitialize the TX desc queue */ - queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); -#endif - /* Make TX ring reflect state of hardware */ - queue->tx_head = 0; - queue->tx_tail = 0; - - /* Housework before enabling TX IRQ */ - macb_writel(bp, TSR, macb_readl(bp, TSR)); - queue_writel(queue, IER, MACB_TX_INT_FLAGS); - - /* Now we are ready to start transmission again */ - netif_tx_start_all_queues(bp->dev); - macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); - - spin_unlock_irqrestore(&bp->lock, flags); -} - -static void macb_tx_interrupt(struct macb_queue *queue) -{ - unsigned int tail; - unsigned int head; - u32 status; - struct macb *bp = queue->bp; - u16 queue_index = queue - bp->queues; - - status = macb_readl(bp, TSR); - macb_writel(bp, TSR, status); - - if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) - queue_writel(queue, ISR, MACB_BIT(TCOMP)); - - netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n", - (unsigned long)status); - - head = queue->tx_head; - for (tail = queue->tx_tail; tail != head; tail++) { - struct macb_tx_skb *tx_skb; - struct sk_buff *skb; - struct macb_dma_desc *desc; - u32 ctrl; - - desc = macb_tx_desc(queue, tail); - - /* Make hw descriptor updates visible to CPU */ - rmb(); - - ctrl = desc->ctrl; - - /* TX_USED bit is only set by hardware on the very first buffer - * descriptor of the transmitted frame. - */ - if (!(ctrl & MACB_BIT(TX_USED))) - break; - - /* Process all buffers of the current transmitted frame */ - for (;; tail++) { - tx_skb = macb_tx_skb(queue, tail); - skb = tx_skb->skb; - - /* First, update TX stats if needed */ - if (skb) { - netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", - macb_tx_ring_wrap(bp, tail), - skb->data); - bp->dev->stats.tx_packets++; - bp->dev->stats.tx_bytes += skb->len; - } - - /* Now we can safely release resources */ - macb_tx_unmap(bp, tx_skb); - - /* skb is set only for the last buffer of the frame. - * WARNING: at this point skb has been freed by - * macb_tx_unmap(). - */ - if (skb) - break; - } - } - - queue->tx_tail = tail; - if (__netif_subqueue_stopped(bp->dev, queue_index) && - CIRC_CNT(queue->tx_head, queue->tx_tail, - bp->tx_ring_size) <= MACB_TX_WAKEUP_THRESH(bp)) - netif_wake_subqueue(bp->dev, queue_index); -} - -static void gem_rx_refill(struct macb *bp) -{ - unsigned int entry; - struct sk_buff *skb; - dma_addr_t paddr; - struct macb_dma_desc *desc; - - while (CIRC_SPACE(bp->rx_prepared_head, bp->rx_tail, - bp->rx_ring_size) > 0) { - entry = macb_rx_ring_wrap(bp, bp->rx_prepared_head); - - /* Make hw descriptor updates visible to CPU */ - rmb(); - - bp->rx_prepared_head++; - desc = macb_rx_desc(bp, entry); - - if (!bp->rx_skbuff[entry]) { - /* allocate sk_buff for this free entry in ring */ - skb = netdev_alloc_skb(bp->dev, bp->rx_buffer_size); - if (unlikely(!skb)) { - netdev_err(bp->dev, - "Unable to allocate sk_buff\n"); - break; - } - - /* now fill corresponding descriptor entry */ - paddr = dma_map_single(&bp->pdev->dev, skb->data, - bp->rx_buffer_size, - DMA_FROM_DEVICE); - if (dma_mapping_error(&bp->pdev->dev, paddr)) { - dev_kfree_skb(skb); - break; - } - - bp->rx_skbuff[entry] = skb; - - if (entry == bp->rx_ring_size - 1) - paddr |= MACB_BIT(RX_WRAP); - macb_set_addr(bp, desc, paddr); - desc->ctrl = 0; - - /* properly align Ethernet header */ - skb_reserve(skb, NET_IP_ALIGN); - } else { - desc->addr &= ~MACB_BIT(RX_USED); - desc->ctrl = 0; - } - } - - /* Make descriptor updates visible to hardware */ - wmb(); - - netdev_vdbg(bp->dev, "rx ring: prepared head %d, tail %d\n", - bp->rx_prepared_head, bp->rx_tail); -} - -/* Mark DMA descriptors from begin up to and not including end as unused */ -static void discard_partial_frame(struct macb *bp, unsigned int begin, - unsigned int end) -{ - unsigned int frag; - - for (frag = begin; frag != end; frag++) { - struct macb_dma_desc *desc = macb_rx_desc(bp, frag); - - desc->addr &= ~MACB_BIT(RX_USED); - } - - /* Make descriptor updates visible to hardware */ - wmb(); - - /* When this happens, the hardware stats registers for - * whatever caused this is updated, so we don't have to record - * anything. - */ -} - -static int gem_rx(struct macb *bp, int budget) -{ - unsigned int len; - unsigned int entry; - struct sk_buff *skb; - struct macb_dma_desc *desc; - int count = 0; - - while (count < budget) { - u32 ctrl; - dma_addr_t addr; - bool rxused; - - entry = macb_rx_ring_wrap(bp, bp->rx_tail); - desc = macb_rx_desc(bp, entry); - - /* Make hw descriptor updates visible to CPU */ - rmb(); - - rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false; - addr = macb_get_addr(bp, desc); - ctrl = desc->ctrl; - - if (!rxused) - break; - - bp->rx_tail++; - count++; - - if (!(ctrl & MACB_BIT(RX_SOF) && ctrl & MACB_BIT(RX_EOF))) { - netdev_err(bp->dev, - "not whole frame pointed by descriptor\n"); - bp->dev->stats.rx_dropped++; - break; - } - skb = bp->rx_skbuff[entry]; - if (unlikely(!skb)) { - netdev_err(bp->dev, - "inconsistent Rx descriptor chain\n"); - bp->dev->stats.rx_dropped++; - break; - } - /* now everything is ready for receiving packet */ - bp->rx_skbuff[entry] = NULL; - len = ctrl & bp->rx_frm_len_mask; - - netdev_vdbg(bp->dev, "gem_rx %u (len %u)\n", entry, len); - - skb_put(skb, len); - dma_unmap_single(&bp->pdev->dev, addr, - bp->rx_buffer_size, DMA_FROM_DEVICE); - - skb->protocol = eth_type_trans(skb, bp->dev); - skb_checksum_none_assert(skb); - if (bp->dev->features & NETIF_F_RXCSUM && - !(bp->dev->flags & IFF_PROMISC) && - GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - bp->dev->stats.rx_packets++; - bp->dev->stats.rx_bytes += skb->len; - -#if defined(DEBUG) && defined(VERBOSE_DEBUG) - netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n", - skb->len, skb->csum); - print_hex_dump(KERN_DEBUG, " mac: ", DUMP_PREFIX_ADDRESS, 16, 1, - skb_mac_header(skb), 16, true); - print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_ADDRESS, 16, 1, - skb->data, 32, true); -#endif - - netif_receive_skb(skb); - } - - gem_rx_refill(bp); - - return count; -} - -static int macb_rx_frame(struct macb *bp, unsigned int first_frag, - unsigned int last_frag) -{ - unsigned int len; - unsigned int frag; - unsigned int offset; - struct sk_buff *skb; - struct macb_dma_desc *desc; - - desc = macb_rx_desc(bp, last_frag); - len = desc->ctrl & bp->rx_frm_len_mask; - - netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n", - macb_rx_ring_wrap(bp, first_frag), - macb_rx_ring_wrap(bp, last_frag), len); - - /* The ethernet header starts NET_IP_ALIGN bytes into the - * first buffer. Since the header is 14 bytes, this makes the - * payload word-aligned. - * - * Instead of calling skb_reserve(NET_IP_ALIGN), we just copy - * the two padding bytes into the skb so that we avoid hitting - * the slowpath in memcpy(), and pull them off afterwards. - */ - skb = netdev_alloc_skb(bp->dev, len + NET_IP_ALIGN); - if (!skb) { - bp->dev->stats.rx_dropped++; - for (frag = first_frag; ; frag++) { - desc = macb_rx_desc(bp, frag); - desc->addr &= ~MACB_BIT(RX_USED); - if (frag == last_frag) - break; - } - - /* Make descriptor updates visible to hardware */ - wmb(); - - return 1; - } - - offset = 0; - len += NET_IP_ALIGN; - skb_checksum_none_assert(skb); - skb_put(skb, len); - - for (frag = first_frag; ; frag++) { - unsigned int frag_len = bp->rx_buffer_size; - - if (offset + frag_len > len) { - if (unlikely(frag != last_frag)) { - dev_kfree_skb_any(skb); - return -1; - } - frag_len = len - offset; - } - skb_copy_to_linear_data_offset(skb, offset, - macb_rx_buffer(bp, frag), - frag_len); - offset += bp->rx_buffer_size; - desc = macb_rx_desc(bp, frag); - desc->addr &= ~MACB_BIT(RX_USED); - - if (frag == last_frag) - break; - } - - /* Make descriptor updates visible to hardware */ - wmb(); - - __skb_pull(skb, NET_IP_ALIGN); - skb->protocol = eth_type_trans(skb, bp->dev); - - bp->dev->stats.rx_packets++; - bp->dev->stats.rx_bytes += skb->len; - netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n", - skb->len, skb->csum); - netif_receive_skb(skb); - - return 0; -} - -static inline void macb_init_rx_ring(struct macb *bp) -{ - dma_addr_t addr; - struct macb_dma_desc *desc = NULL; - int i; - - addr = bp->rx_buffers_dma; - for (i = 0; i < bp->rx_ring_size; i++) { - desc = macb_rx_desc(bp, i); - macb_set_addr(bp, desc, addr); - desc->ctrl = 0; - addr += bp->rx_buffer_size; - } - desc->addr |= MACB_BIT(RX_WRAP); - bp->rx_tail = 0; -} - -static int macb_rx(struct macb *bp, int budget) -{ - bool reset_rx_queue = false; - int received = 0; - unsigned int tail; - int first_frag = -1; - - for (tail = bp->rx_tail; budget > 0; tail++) { - struct macb_dma_desc *desc = macb_rx_desc(bp, tail); - u32 ctrl; - - /* Make hw descriptor updates visible to CPU */ - rmb(); - - ctrl = desc->ctrl; - - if (!(desc->addr & MACB_BIT(RX_USED))) - break; - - if (ctrl & MACB_BIT(RX_SOF)) { - if (first_frag != -1) - discard_partial_frame(bp, first_frag, tail); - first_frag = tail; - } - - if (ctrl & MACB_BIT(RX_EOF)) { - int dropped; - - if (unlikely(first_frag == -1)) { - reset_rx_queue = true; - continue; - } - - dropped = macb_rx_frame(bp, first_frag, tail); - first_frag = -1; - if (unlikely(dropped < 0)) { - reset_rx_queue = true; - continue; - } - if (!dropped) { - received++; - budget--; - } - } - } - - if (unlikely(reset_rx_queue)) { - unsigned long flags; - u32 ctrl; - - netdev_err(bp->dev, "RX queue corruption: reset it\n"); - - spin_lock_irqsave(&bp->lock, flags); - - ctrl = macb_readl(bp, NCR); - macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE)); - - macb_init_rx_ring(bp); - macb_writel(bp, RBQP, bp->rx_ring_dma); - - macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); - - spin_unlock_irqrestore(&bp->lock, flags); - return received; - } - - if (first_frag != -1) - bp->rx_tail = first_frag; - else - bp->rx_tail = tail; - - return received; -} - -static int macb_poll(struct napi_struct *napi, int budget) -{ - struct macb *bp = container_of(napi, struct macb, napi); - int work_done; - u32 status; - - status = macb_readl(bp, RSR); - macb_writel(bp, RSR, status); - - work_done = 0; - - netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n", - (unsigned long)status, budget); - - work_done = bp->macbgem_ops.mog_rx(bp, budget); - if (work_done < budget) { - napi_complete_done(napi, work_done); - - /* Packets received while interrupts were disabled */ - status = macb_readl(bp, RSR); - if (status) { - if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) - macb_writel(bp, ISR, MACB_BIT(RCOMP)); - napi_reschedule(napi); - } else { - macb_writel(bp, IER, MACB_RX_INT_FLAGS); - } - } - - /* TODO: Handle errors */ - - return work_done; -} - -static irqreturn_t macb_interrupt(int irq, void *dev_id) -{ - struct macb_queue *queue = dev_id; - struct macb *bp = queue->bp; - struct net_device *dev = bp->dev; - u32 status, ctrl; - - status = queue_readl(queue, ISR); - - if (unlikely(!status)) - return IRQ_NONE; - - spin_lock(&bp->lock); - - while (status) { - /* close possible race with dev_close */ - if (unlikely(!netif_running(dev))) { - queue_writel(queue, IDR, -1); - if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) - queue_writel(queue, ISR, -1); - break; - } - - netdev_vdbg(bp->dev, "queue = %u, isr = 0x%08lx\n", - (unsigned int)(queue - bp->queues), - (unsigned long)status); - - if (status & MACB_RX_INT_FLAGS) { - /* There's no point taking any more interrupts - * until we have processed the buffers. The - * scheduling call may fail if the poll routine - * is already scheduled, so disable interrupts - * now. - */ - queue_writel(queue, IDR, MACB_RX_INT_FLAGS); - if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) - queue_writel(queue, ISR, MACB_BIT(RCOMP)); - - if (napi_schedule_prep(&bp->napi)) { - netdev_vdbg(bp->dev, "scheduling RX softirq\n"); - __napi_schedule(&bp->napi); - } - } - - if (unlikely(status & (MACB_TX_ERR_FLAGS))) { - queue_writel(queue, IDR, MACB_TX_INT_FLAGS); - schedule_work(&queue->tx_error_task); - - if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) - queue_writel(queue, ISR, MACB_TX_ERR_FLAGS); - - break; - } - - if (status & MACB_BIT(TCOMP)) - macb_tx_interrupt(queue); - - /* Link change detection isn't possible with RMII, so we'll - * add that if/when we get our hands on a full-blown MII PHY. - */ - - /* There is a hardware issue under heavy load where DMA can - * stop, this causes endless "used buffer descriptor read" - * interrupts but it can be cleared by re-enabling RX. See - * the at91 manual, section 41.3.1 or the Zynq manual - * section 16.7.4 for details. - */ - if (status & MACB_BIT(RXUBR)) { - ctrl = macb_readl(bp, NCR); - macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE)); - wmb(); - macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); - - if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) - queue_writel(queue, ISR, MACB_BIT(RXUBR)); - } - - if (status & MACB_BIT(ISR_ROVR)) { - /* We missed at least one packet */ - if (macb_is_gem(bp)) - bp->hw_stats.gem.rx_overruns++; - else - bp->hw_stats.macb.rx_overruns++; - - if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) - queue_writel(queue, ISR, MACB_BIT(ISR_ROVR)); - } - - if (status & MACB_BIT(HRESP)) { - /* TODO: Reset the hardware, and maybe move the - * netdev_err to a lower-priority context as well - * (work queue?) - */ - netdev_err(dev, "DMA bus error: HRESP not OK\n"); - - if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) - queue_writel(queue, ISR, MACB_BIT(HRESP)); - } - - status = queue_readl(queue, ISR); - } - - spin_unlock(&bp->lock); - - return IRQ_HANDLED; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* Polling receive - used by netconsole and other diagnostic tools - * to allow network i/o with interrupts disabled. - */ -static void macb_poll_controller(struct net_device *dev) -{ - struct macb *bp = netdev_priv(dev); - struct macb_queue *queue; - unsigned long flags; - unsigned int q; - - local_irq_save(flags); - for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) - macb_interrupt(dev->irq, queue); - local_irq_restore(flags); -} -#endif - -static unsigned int macb_tx_map(struct macb *bp, - struct macb_queue *queue, - struct sk_buff *skb, - unsigned int hdrlen) -{ - dma_addr_t mapping; - unsigned int len, entry, i, tx_head = queue->tx_head; - struct macb_tx_skb *tx_skb = NULL; - struct macb_dma_desc *desc; - unsigned int offset, size, count = 0; - unsigned int f, nr_frags = skb_shinfo(skb)->nr_frags; - unsigned int eof = 1, mss_mfs = 0; - u32 ctrl, lso_ctrl = 0, seq_ctrl = 0; - - /* LSO */ - if (skb_shinfo(skb)->gso_size != 0) { - if (ip_hdr(skb)->protocol == IPPROTO_UDP) - /* UDP - UFO */ - lso_ctrl = MACB_LSO_UFO_ENABLE; - else - /* TCP - TSO */ - lso_ctrl = MACB_LSO_TSO_ENABLE; - } - - /* First, map non-paged data */ - len = skb_headlen(skb); - - /* first buffer length */ - size = hdrlen; - - offset = 0; - while (len) { - entry = macb_tx_ring_wrap(bp, tx_head); - tx_skb = &queue->tx_skb[entry]; - - mapping = dma_map_single(&bp->pdev->dev, - skb->data + offset, - size, DMA_TO_DEVICE); - if (dma_mapping_error(&bp->pdev->dev, mapping)) - goto dma_error; - - /* Save info to properly release resources */ - tx_skb->skb = NULL; - tx_skb->mapping = mapping; - tx_skb->size = size; - tx_skb->mapped_as_page = false; - - len -= size; - offset += size; - count++; - tx_head++; - - size = min(len, bp->max_tx_length); - } - - /* Then, map paged data from fragments */ - for (f = 0; f < nr_frags; f++) { - const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; - - len = skb_frag_size(frag); - offset = 0; - while (len) { - size = min(len, bp->max_tx_length); - entry = macb_tx_ring_wrap(bp, tx_head); - tx_skb = &queue->tx_skb[entry]; - - mapping = skb_frag_dma_map(&bp->pdev->dev, frag, - offset, size, DMA_TO_DEVICE); - if (dma_mapping_error(&bp->pdev->dev, mapping)) - goto dma_error; - - /* Save info to properly release resources */ - tx_skb->skb = NULL; - tx_skb->mapping = mapping; - tx_skb->size = size; - tx_skb->mapped_as_page = true; - - len -= size; - offset += size; - count++; - tx_head++; - } - } - - /* Should never happen */ - if (unlikely(!tx_skb)) { - netdev_err(bp->dev, "BUG! empty skb!\n"); - return 0; - } - - /* This is the last buffer of the frame: save socket buffer */ - tx_skb->skb = skb; - - /* Update TX ring: update buffer descriptors in reverse order - * to avoid race condition - */ - - /* Set 'TX_USED' bit in buffer descriptor at tx_head position - * to set the end of TX queue - */ - i = tx_head; - entry = macb_tx_ring_wrap(bp, i); - ctrl = MACB_BIT(TX_USED); - desc = macb_tx_desc(queue, entry); - desc->ctrl = ctrl; - - if (lso_ctrl) { - if (lso_ctrl == MACB_LSO_UFO_ENABLE) - /* include header and FCS in value given to h/w */ - mss_mfs = skb_shinfo(skb)->gso_size + - skb_transport_offset(skb) + - ETH_FCS_LEN; - else /* TSO */ { - mss_mfs = skb_shinfo(skb)->gso_size; - /* TCP Sequence Number Source Select - * can be set only for TSO - */ - seq_ctrl = 0; - } - } - - do { - i--; - entry = macb_tx_ring_wrap(bp, i); - tx_skb = &queue->tx_skb[entry]; - desc = macb_tx_desc(queue, entry); - - ctrl = (u32)tx_skb->size; - if (eof) { - ctrl |= MACB_BIT(TX_LAST); - eof = 0; - } - if (unlikely(entry == (bp->tx_ring_size - 1))) - ctrl |= MACB_BIT(TX_WRAP); - - /* First descriptor is header descriptor */ - if (i == queue->tx_head) { - ctrl |= MACB_BF(TX_LSO, lso_ctrl); - ctrl |= MACB_BF(TX_TCP_SEQ_SRC, seq_ctrl); - } else - /* Only set MSS/MFS on payload descriptors - * (second or later descriptor) - */ - ctrl |= MACB_BF(MSS_MFS, mss_mfs); - - /* Set TX buffer descriptor */ - macb_set_addr(bp, desc, tx_skb->mapping); - /* desc->addr must be visible to hardware before clearing - * 'TX_USED' bit in desc->ctrl. - */ - wmb(); - desc->ctrl = ctrl; - } while (i != queue->tx_head); - - queue->tx_head = tx_head; - - return count; - -dma_error: - netdev_err(bp->dev, "TX DMA map failed\n"); - - for (i = queue->tx_head; i != tx_head; i++) { - tx_skb = macb_tx_skb(queue, i); - - macb_tx_unmap(bp, tx_skb); - } - - return 0; -} - -static netdev_features_t macb_features_check(struct sk_buff *skb, - struct net_device *dev, - netdev_features_t features) -{ - unsigned int nr_frags, f; - unsigned int hdrlen; - - /* Validate LSO compatibility */ - - /* there is only one buffer */ - if (!skb_is_nonlinear(skb)) - return features; - - /* length of header */ - hdrlen = skb_transport_offset(skb); - if (ip_hdr(skb)->protocol == IPPROTO_TCP) - hdrlen += tcp_hdrlen(skb); - - /* For LSO: - * When software supplies two or more payload buffers all payload buffers - * apart from the last must be a multiple of 8 bytes in size. - */ - if (!IS_ALIGNED(skb_headlen(skb) - hdrlen, MACB_TX_LEN_ALIGN)) - return features & ~MACB_NETIF_LSO; - - nr_frags = skb_shinfo(skb)->nr_frags; - /* No need to check last fragment */ - nr_frags--; - for (f = 0; f < nr_frags; f++) { - const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; - - if (!IS_ALIGNED(skb_frag_size(frag), MACB_TX_LEN_ALIGN)) - return features & ~MACB_NETIF_LSO; - } - return features; -} - -static inline int macb_clear_csum(struct sk_buff *skb) -{ - /* no change for packets without checksum offloading */ - if (skb->ip_summed != CHECKSUM_PARTIAL) - return 0; - - /* make sure we can modify the header */ - if (unlikely(skb_cow_head(skb, 0))) - return -1; - - /* initialize checksum field - * This is required - at least for Zynq, which otherwise calculates - * wrong UDP header checksums for UDP packets with UDP data len <=2 - */ - *(__sum16 *)(skb_checksum_start(skb) + skb->csum_offset) = 0; - return 0; -} - -static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - u16 queue_index = skb_get_queue_mapping(skb); - struct macb *bp = netdev_priv(dev); - struct macb_queue *queue = &bp->queues[queue_index]; - unsigned long flags; - unsigned int desc_cnt, nr_frags, frag_size, f; - unsigned int hdrlen; - bool is_lso, is_udp = 0; - - is_lso = (skb_shinfo(skb)->gso_size != 0); - - if (is_lso) { - is_udp = !!(ip_hdr(skb)->protocol == IPPROTO_UDP); - - /* length of headers */ - if (is_udp) - /* only queue eth + ip headers separately for UDP */ - hdrlen = skb_transport_offset(skb); - else - hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb); - if (skb_headlen(skb) < hdrlen) { - netdev_err(bp->dev, "Error - LSO headers fragmented!!!\n"); - /* if this is required, would need to copy to single buffer */ - return NETDEV_TX_BUSY; - } - } else - hdrlen = min(skb_headlen(skb), bp->max_tx_length); - -#if defined(DEBUG) && defined(VERBOSE_DEBUG) - netdev_vdbg(bp->dev, - "start_xmit: queue %hu len %u head %p data %p tail %p end %p\n", - queue_index, skb->len, skb->head, skb->data, - skb_tail_pointer(skb), skb_end_pointer(skb)); - print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1, - skb->data, 16, true); -#endif - - /* Count how many TX buffer descriptors are needed to send this - * socket buffer: skb fragments of jumbo frames may need to be - * split into many buffer descriptors. - */ - if (is_lso && (skb_headlen(skb) > hdrlen)) - /* extra header descriptor if also payload in first buffer */ - desc_cnt = DIV_ROUND_UP((skb_headlen(skb) - hdrlen), bp->max_tx_length) + 1; - else - desc_cnt = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length); - nr_frags = skb_shinfo(skb)->nr_frags; - for (f = 0; f < nr_frags; f++) { - frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]); - desc_cnt += DIV_ROUND_UP(frag_size, bp->max_tx_length); - } - - spin_lock_irqsave(&bp->lock, flags); - - /* This is a hard error, log it. */ - if (CIRC_SPACE(queue->tx_head, queue->tx_tail, - bp->tx_ring_size) < desc_cnt) { - netif_stop_subqueue(dev, queue_index); - spin_unlock_irqrestore(&bp->lock, flags); - netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n", - queue->tx_head, queue->tx_tail); - return NETDEV_TX_BUSY; - } - - if (macb_clear_csum(skb)) { - dev_kfree_skb_any(skb); - goto unlock; - } - - /* Map socket buffer for DMA transfer */ - if (!macb_tx_map(bp, queue, skb, hdrlen)) { - dev_kfree_skb_any(skb); - goto unlock; - } - - /* Make newly initialized descriptor visible to hardware */ - wmb(); - - skb_tx_timestamp(skb); - - macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); - - if (CIRC_SPACE(queue->tx_head, queue->tx_tail, bp->tx_ring_size) < 1) - netif_stop_subqueue(dev, queue_index); - -unlock: - spin_unlock_irqrestore(&bp->lock, flags); - - return NETDEV_TX_OK; -} - -static void macb_init_rx_buffer_size(struct macb *bp, size_t size) -{ - if (!macb_is_gem(bp)) { - bp->rx_buffer_size = MACB_RX_BUFFER_SIZE; - } else { - bp->rx_buffer_size = size; - - if (bp->rx_buffer_size % RX_BUFFER_MULTIPLE) { - netdev_dbg(bp->dev, - "RX buffer must be multiple of %d bytes, expanding\n", - RX_BUFFER_MULTIPLE); - bp->rx_buffer_size = - roundup(bp->rx_buffer_size, RX_BUFFER_MULTIPLE); - } - } - - netdev_dbg(bp->dev, "mtu [%u] rx_buffer_size [%zu]\n", - bp->dev->mtu, bp->rx_buffer_size); -} - -static void gem_free_rx_buffers(struct macb *bp) -{ - struct sk_buff *skb; - struct macb_dma_desc *desc; - dma_addr_t addr; - int i; - - if (!bp->rx_skbuff) - return; - - for (i = 0; i < bp->rx_ring_size; i++) { - skb = bp->rx_skbuff[i]; - - if (!skb) - continue; - - desc = macb_rx_desc(bp, i); - addr = macb_get_addr(bp, desc); - - dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size, - DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); - skb = NULL; - } - - kfree(bp->rx_skbuff); - bp->rx_skbuff = NULL; -} - -static void macb_free_rx_buffers(struct macb *bp) -{ - if (bp->rx_buffers) { - dma_free_coherent(&bp->pdev->dev, - bp->rx_ring_size * bp->rx_buffer_size, - bp->rx_buffers, bp->rx_buffers_dma); - bp->rx_buffers = NULL; - } -} - -static void macb_free_consistent(struct macb *bp) -{ - struct macb_queue *queue; - unsigned int q; - - bp->macbgem_ops.mog_free_rx_buffers(bp); - if (bp->rx_ring) { - dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES(bp), - bp->rx_ring, bp->rx_ring_dma); - bp->rx_ring = NULL; - } - - for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { - kfree(queue->tx_skb); - queue->tx_skb = NULL; - if (queue->tx_ring) { - dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES(bp), - queue->tx_ring, queue->tx_ring_dma); - queue->tx_ring = NULL; - } - } -} - -static int gem_alloc_rx_buffers(struct macb *bp) -{ - int size; - - size = bp->rx_ring_size * sizeof(struct sk_buff *); - bp->rx_skbuff = kzalloc(size, GFP_KERNEL); - if (!bp->rx_skbuff) - return -ENOMEM; - else - netdev_dbg(bp->dev, - "Allocated %d RX struct sk_buff entries at %p\n", - bp->rx_ring_size, bp->rx_skbuff); - return 0; -} - -static int macb_alloc_rx_buffers(struct macb *bp) -{ - int size; - - size = bp->rx_ring_size * bp->rx_buffer_size; - bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size, - &bp->rx_buffers_dma, GFP_KERNEL); - if (!bp->rx_buffers) - return -ENOMEM; - - netdev_dbg(bp->dev, - "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n", - size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers); - return 0; -} - -static int macb_alloc_consistent(struct macb *bp) -{ - struct macb_queue *queue; - unsigned int q; - int size; - - for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { - size = TX_RING_BYTES(bp); - queue->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size, - &queue->tx_ring_dma, - GFP_KERNEL); - if (!queue->tx_ring) - goto out_err; - netdev_dbg(bp->dev, - "Allocated TX ring for queue %u of %d bytes at %08lx (mapped %p)\n", - q, size, (unsigned long)queue->tx_ring_dma, - queue->tx_ring); - - size = bp->tx_ring_size * sizeof(struct macb_tx_skb); - queue->tx_skb = kmalloc(size, GFP_KERNEL); - if (!queue->tx_skb) - goto out_err; - } - - size = RX_RING_BYTES(bp); - bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size, - &bp->rx_ring_dma, GFP_KERNEL); - if (!bp->rx_ring) - goto out_err; - netdev_dbg(bp->dev, - "Allocated RX ring of %d bytes at %08lx (mapped %p)\n", - size, (unsigned long)bp->rx_ring_dma, bp->rx_ring); - - if (bp->macbgem_ops.mog_alloc_rx_buffers(bp)) - goto out_err; - - return 0; - -out_err: - macb_free_consistent(bp); - return -ENOMEM; -} - -static void gem_init_rings(struct macb *bp) -{ - struct macb_queue *queue; - struct macb_dma_desc *desc = NULL; - unsigned int q; - int i; - - for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { - for (i = 0; i < bp->tx_ring_size; i++) { - desc = macb_tx_desc(queue, i); - macb_set_addr(bp, desc, 0); - desc->ctrl = MACB_BIT(TX_USED); - } - desc->ctrl |= MACB_BIT(TX_WRAP); - queue->tx_head = 0; - queue->tx_tail = 0; - } - - bp->rx_tail = 0; - bp->rx_prepared_head = 0; - - gem_rx_refill(bp); -} - -static void macb_init_rings(struct macb *bp) -{ - int i; - struct macb_dma_desc *desc = NULL; - - macb_init_rx_ring(bp); - - for (i = 0; i < bp->tx_ring_size; i++) { - desc = macb_tx_desc(&bp->queues[0], i); - macb_set_addr(bp, desc, 0); - desc->ctrl = MACB_BIT(TX_USED); - } - bp->queues[0].tx_head = 0; - bp->queues[0].tx_tail = 0; - desc->ctrl |= MACB_BIT(TX_WRAP); -} - -static void macb_reset_hw(struct macb *bp) -{ - struct macb_queue *queue; - unsigned int q; - - /* Disable RX and TX (XXX: Should we halt the transmission - * more gracefully?) - */ - macb_writel(bp, NCR, 0); - - /* Clear the stats registers (XXX: Update stats first?) */ - macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); - - /* Clear all status flags */ - macb_writel(bp, TSR, -1); - macb_writel(bp, RSR, -1); - - /* Disable all interrupts */ - for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { - queue_writel(queue, IDR, -1); - queue_readl(queue, ISR); - if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) - queue_writel(queue, ISR, -1); - } -} - -static u32 gem_mdc_clk_div(struct macb *bp) -{ - u32 config; - unsigned long pclk_hz = clk_get_rate(bp->pclk); - - if (pclk_hz <= 20000000) - config = GEM_BF(CLK, GEM_CLK_DIV8); - else if (pclk_hz <= 40000000) - config = GEM_BF(CLK, GEM_CLK_DIV16); - else if (pclk_hz <= 80000000) - config = GEM_BF(CLK, GEM_CLK_DIV32); - else if (pclk_hz <= 120000000) - config = GEM_BF(CLK, GEM_CLK_DIV48); - else if (pclk_hz <= 160000000) - config = GEM_BF(CLK, GEM_CLK_DIV64); - else - config = GEM_BF(CLK, GEM_CLK_DIV96); - - return config; -} - -static u32 macb_mdc_clk_div(struct macb *bp) -{ - u32 config; - unsigned long pclk_hz; - - if (macb_is_gem(bp)) - return gem_mdc_clk_div(bp); - - pclk_hz = clk_get_rate(bp->pclk); - if (pclk_hz <= 20000000) - config = MACB_BF(CLK, MACB_CLK_DIV8); - else if (pclk_hz <= 40000000) - config = MACB_BF(CLK, MACB_CLK_DIV16); - else if (pclk_hz <= 80000000) - config = MACB_BF(CLK, MACB_CLK_DIV32); - else - config = MACB_BF(CLK, MACB_CLK_DIV64); - - return config; -} - -/* Get the DMA bus width field of the network configuration register that we - * should program. We find the width from decoding the design configuration - * register to find the maximum supported data bus width. - */ -static u32 macb_dbw(struct macb *bp) -{ - if (!macb_is_gem(bp)) - return 0; - - switch (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1))) { - case 4: - return GEM_BF(DBW, GEM_DBW128); - case 2: - return GEM_BF(DBW, GEM_DBW64); - case 1: - default: - return GEM_BF(DBW, GEM_DBW32); - } -} - -/* Configure the receive DMA engine - * - use the correct receive buffer size - * - set best burst length for DMA operations - * (if not supported by FIFO, it will fallback to default) - * - set both rx/tx packet buffers to full memory size - * These are configurable parameters for GEM. - */ -static void macb_configure_dma(struct macb *bp) -{ - u32 dmacfg; - - if (macb_is_gem(bp)) { - dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L); - dmacfg |= GEM_BF(RXBS, bp->rx_buffer_size / RX_BUFFER_MULTIPLE); - if (bp->dma_burst_length) - dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg); - dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L); - dmacfg &= ~GEM_BIT(ENDIA_PKT); - - if (bp->native_io) - dmacfg &= ~GEM_BIT(ENDIA_DESC); - else - dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */ - - if (bp->dev->features & NETIF_F_HW_CSUM) - dmacfg |= GEM_BIT(TXCOEN); - else - dmacfg &= ~GEM_BIT(TXCOEN); - -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - dmacfg |= GEM_BIT(ADDR64); -#endif -#ifdef CONFIG_MACB_USE_HWSTAMP - if (bp->hw_dma_cap & HW_DMA_CAP_PTP) - dmacfg |= GEM_BIT(RXEXT) | GEM_BIT(TXEXT); -#endif - netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n", - dmacfg); - gem_writel(bp, DMACFG, dmacfg); - } -} - -static void macb_init_hw(struct macb *bp) -{ - struct macb_queue *queue; - unsigned int q; - - u32 config; - - macb_reset_hw(bp); - macb_set_hwaddr(bp); - - config = macb_mdc_clk_div(bp); - if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) - config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); - config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ - config |= MACB_BIT(PAE); /* PAuse Enable */ - config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ - if (bp->caps & MACB_CAPS_JUMBO) - config |= MACB_BIT(JFRAME); /* Enable jumbo frames */ - else - config |= MACB_BIT(BIG); /* Receive oversized frames */ - if (bp->dev->flags & IFF_PROMISC) - config |= MACB_BIT(CAF); /* Copy All Frames */ - else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM) - config |= GEM_BIT(RXCOEN); - if (!(bp->dev->flags & IFF_BROADCAST)) - config |= MACB_BIT(NBC); /* No BroadCast */ - config |= macb_dbw(bp); - macb_writel(bp, NCFGR, config); - if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len) - gem_writel(bp, JML, bp->jumbo_max_len); - bp->speed = SPEED_10; - bp->duplex = DUPLEX_HALF; - bp->rx_frm_len_mask = MACB_RX_FRMLEN_MASK; - if (bp->caps & MACB_CAPS_JUMBO) - bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; - - macb_configure_dma(bp); - - /* Initialize TX and RX buffers */ - macb_writel(bp, RBQP, lower_32_bits(bp->rx_ring_dma)); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - macb_writel(bp, RBQPH, upper_32_bits(bp->rx_ring_dma)); -#endif - for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { - queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); -#endif - - /* Enable interrupts */ - queue_writel(queue, IER, - MACB_RX_INT_FLAGS | - MACB_TX_INT_FLAGS | - MACB_BIT(HRESP)); - } - - /* Enable TX and RX */ - macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE)); -} - -/* The hash address register is 64 bits long and takes up two - * locations in the memory map. The least significant bits are stored - * in EMAC_HSL and the most significant bits in EMAC_HSH. - * - * The unicast hash enable and the multicast hash enable bits in the - * network configuration register enable the reception of hash matched - * frames. The destination address is reduced to a 6 bit index into - * the 64 bit hash register using the following hash function. The - * hash function is an exclusive or of every sixth bit of the - * destination address. - * - * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] - * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] - * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] - * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] - * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] - * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] - * - * da[0] represents the least significant bit of the first byte - * received, that is, the multicast/unicast indicator, and da[47] - * represents the most significant bit of the last byte received. If - * the hash index, hi[n], points to a bit that is set in the hash - * register then the frame will be matched according to whether the - * frame is multicast or unicast. A multicast match will be signalled - * if the multicast hash enable bit is set, da[0] is 1 and the hash - * index points to a bit set in the hash register. A unicast match - * will be signalled if the unicast hash enable bit is set, da[0] is 0 - * and the hash index points to a bit set in the hash register. To - * receive all multicast frames, the hash register should be set with - * all ones and the multicast hash enable bit should be set in the - * network configuration register. - */ - -static inline int hash_bit_value(int bitnr, __u8 *addr) -{ - if (addr[bitnr / 8] & (1 << (bitnr % 8))) - return 1; - return 0; -} - -/* Return the hash index value for the specified address. */ -static int hash_get_index(__u8 *addr) -{ - int i, j, bitval; - int hash_index = 0; - - for (j = 0; j < 6; j++) { - for (i = 0, bitval = 0; i < 8; i++) - bitval ^= hash_bit_value(i * 6 + j, addr); - - hash_index |= (bitval << j); - } - - return hash_index; -} - -/* Add multicast addresses to the internal multicast-hash table. */ -static void macb_sethashtable(struct net_device *dev) -{ - struct netdev_hw_addr *ha; - unsigned long mc_filter[2]; - unsigned int bitnr; - struct macb *bp = netdev_priv(dev); - - mc_filter[0] = 0; - mc_filter[1] = 0; - - netdev_for_each_mc_addr(ha, dev) { - bitnr = hash_get_index(ha->addr); - mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); - } - - macb_or_gem_writel(bp, HRB, mc_filter[0]); - macb_or_gem_writel(bp, HRT, mc_filter[1]); -} - -/* Enable/Disable promiscuous and multicast modes. */ -static void macb_set_rx_mode(struct net_device *dev) -{ - unsigned long cfg; - struct macb *bp = netdev_priv(dev); - - cfg = macb_readl(bp, NCFGR); - - if (dev->flags & IFF_PROMISC) { - /* Enable promiscuous mode */ - cfg |= MACB_BIT(CAF); - - /* Disable RX checksum offload */ - if (macb_is_gem(bp)) - cfg &= ~GEM_BIT(RXCOEN); - } else { - /* Disable promiscuous mode */ - cfg &= ~MACB_BIT(CAF); - - /* Enable RX checksum offload only if requested */ - if (macb_is_gem(bp) && dev->features & NETIF_F_RXCSUM) - cfg |= GEM_BIT(RXCOEN); - } - - if (dev->flags & IFF_ALLMULTI) { - /* Enable all multicast mode */ - macb_or_gem_writel(bp, HRB, -1); - macb_or_gem_writel(bp, HRT, -1); - cfg |= MACB_BIT(NCFGR_MTI); - } else if (!netdev_mc_empty(dev)) { - /* Enable specific multicasts */ - macb_sethashtable(dev); - cfg |= MACB_BIT(NCFGR_MTI); - } else if (dev->flags & (~IFF_ALLMULTI)) { - /* Disable all multicast mode */ - macb_or_gem_writel(bp, HRB, 0); - macb_or_gem_writel(bp, HRT, 0); - cfg &= ~MACB_BIT(NCFGR_MTI); - } - - macb_writel(bp, NCFGR, cfg); -} - -static int macb_open(struct net_device *dev) -{ - struct macb *bp = netdev_priv(dev); - size_t bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN; - int err; - - netdev_dbg(bp->dev, "open\n"); - - /* carrier starts down */ - netif_carrier_off(dev); - - /* if the phy is not yet register, retry later*/ - if (!dev->phydev) - return -EAGAIN; - - /* RX buffers initialization */ - macb_init_rx_buffer_size(bp, bufsz); - - err = macb_alloc_consistent(bp); - if (err) { - netdev_err(dev, "Unable to allocate DMA memory (error %d)\n", - err); - return err; - } - - napi_enable(&bp->napi); - - bp->macbgem_ops.mog_init_rings(bp); - macb_init_hw(bp); - - /* schedule a link state check */ - phy_start(dev->phydev); - - netif_tx_start_all_queues(dev); - - if (bp->ptp_info) - bp->ptp_info->ptp_init(dev); - - return 0; -} - -static int macb_close(struct net_device *dev) -{ - struct macb *bp = netdev_priv(dev); - unsigned long flags; - - netif_tx_stop_all_queues(dev); - napi_disable(&bp->napi); - - if (dev->phydev) - phy_stop(dev->phydev); - - spin_lock_irqsave(&bp->lock, flags); - macb_reset_hw(bp); - netif_carrier_off(dev); - spin_unlock_irqrestore(&bp->lock, flags); - - macb_free_consistent(bp); - - if (bp->ptp_info) - bp->ptp_info->ptp_remove(dev); - - return 0; -} - -static int macb_change_mtu(struct net_device *dev, int new_mtu) -{ - if (netif_running(dev)) - return -EBUSY; - - dev->mtu = new_mtu; - - return 0; -} - -static void gem_update_stats(struct macb *bp) -{ - unsigned int i; - u32 *p = &bp->hw_stats.gem.tx_octets_31_0; - - for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { - u32 offset = gem_statistics[i].offset; - u64 val = bp->macb_reg_readl(bp, offset); - - bp->ethtool_stats[i] += val; - *p += val; - - if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) { - /* Add GEM_OCTTXH, GEM_OCTRXH */ - val = bp->macb_reg_readl(bp, offset + 4); - bp->ethtool_stats[i] += ((u64)val) << 32; - *(++p) += val; - } - } -} - -static struct net_device_stats *gem_get_stats(struct macb *bp) -{ - struct gem_stats *hwstat = &bp->hw_stats.gem; - struct net_device_stats *nstat = &bp->dev->stats; - - gem_update_stats(bp); - - nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors + - hwstat->rx_alignment_errors + - hwstat->rx_resource_errors + - hwstat->rx_overruns + - hwstat->rx_oversize_frames + - hwstat->rx_jabbers + - hwstat->rx_undersized_frames + - hwstat->rx_length_field_frame_errors); - nstat->tx_errors = (hwstat->tx_late_collisions + - hwstat->tx_excessive_collisions + - hwstat->tx_underrun + - hwstat->tx_carrier_sense_errors); - nstat->multicast = hwstat->rx_multicast_frames; - nstat->collisions = (hwstat->tx_single_collision_frames + - hwstat->tx_multiple_collision_frames + - hwstat->tx_excessive_collisions); - nstat->rx_length_errors = (hwstat->rx_oversize_frames + - hwstat->rx_jabbers + - hwstat->rx_undersized_frames + - hwstat->rx_length_field_frame_errors); - nstat->rx_over_errors = hwstat->rx_resource_errors; - nstat->rx_crc_errors = hwstat->rx_frame_check_sequence_errors; - nstat->rx_frame_errors = hwstat->rx_alignment_errors; - nstat->rx_fifo_errors = hwstat->rx_overruns; - nstat->tx_aborted_errors = hwstat->tx_excessive_collisions; - nstat->tx_carrier_errors = hwstat->tx_carrier_sense_errors; - nstat->tx_fifo_errors = hwstat->tx_underrun; - - return nstat; -} - -static void gem_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - struct macb *bp; - - bp = netdev_priv(dev); - gem_update_stats(bp); - memcpy(data, &bp->ethtool_stats, sizeof(u64) * GEM_STATS_LEN); -} - -static int gem_get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return GEM_STATS_LEN; - default: - return -EOPNOTSUPP; - } -} - -static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) -{ - unsigned int i; - - switch (sset) { - case ETH_SS_STATS: - for (i = 0; i < GEM_STATS_LEN; i++, p += ETH_GSTRING_LEN) - memcpy(p, gem_statistics[i].stat_string, - ETH_GSTRING_LEN); - break; - } -} - -static struct net_device_stats *macb_get_stats(struct net_device *dev) -{ - struct macb *bp = netdev_priv(dev); - struct net_device_stats *nstat = &bp->dev->stats; - struct macb_stats *hwstat = &bp->hw_stats.macb; - - if (macb_is_gem(bp)) - return gem_get_stats(bp); - - /* read stats from hardware */ - macb_update_stats(bp); - - /* Convert HW stats into netdevice stats */ - nstat->rx_errors = (hwstat->rx_fcs_errors + - hwstat->rx_align_errors + - hwstat->rx_resource_errors + - hwstat->rx_overruns + - hwstat->rx_oversize_pkts + - hwstat->rx_jabbers + - hwstat->rx_undersize_pkts + - hwstat->rx_length_mismatch); - nstat->tx_errors = (hwstat->tx_late_cols + - hwstat->tx_excessive_cols + - hwstat->tx_underruns + - hwstat->tx_carrier_errors + - hwstat->sqe_test_errors); - nstat->collisions = (hwstat->tx_single_cols + - hwstat->tx_multiple_cols + - hwstat->tx_excessive_cols); - nstat->rx_length_errors = (hwstat->rx_oversize_pkts + - hwstat->rx_jabbers + - hwstat->rx_undersize_pkts + - hwstat->rx_length_mismatch); - nstat->rx_over_errors = hwstat->rx_resource_errors + - hwstat->rx_overruns; - nstat->rx_crc_errors = hwstat->rx_fcs_errors; - nstat->rx_frame_errors = hwstat->rx_align_errors; - nstat->rx_fifo_errors = hwstat->rx_overruns; - /* XXX: What does "missed" mean? */ - nstat->tx_aborted_errors = hwstat->tx_excessive_cols; - nstat->tx_carrier_errors = hwstat->tx_carrier_errors; - nstat->tx_fifo_errors = hwstat->tx_underruns; - /* Don't know about heartbeat or window errors... */ - - return nstat; -} - -static int macb_get_regs_len(struct net_device *netdev) -{ - return MACB_GREGS_NBR * sizeof(u32); -} - -static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *p) -{ - struct macb *bp = netdev_priv(dev); - unsigned int tail, head; - u32 *regs_buff = p; - - regs->version = (macb_readl(bp, MID) & ((1 << MACB_REV_SIZE) - 1)) - | MACB_GREGS_VERSION; - - tail = macb_tx_ring_wrap(bp, bp->queues[0].tx_tail); - head = macb_tx_ring_wrap(bp, bp->queues[0].tx_head); - - regs_buff[0] = macb_readl(bp, NCR); - regs_buff[1] = macb_or_gem_readl(bp, NCFGR); - regs_buff[2] = macb_readl(bp, NSR); - regs_buff[3] = macb_readl(bp, TSR); - regs_buff[4] = macb_readl(bp, RBQP); - regs_buff[5] = macb_readl(bp, TBQP); - regs_buff[6] = macb_readl(bp, RSR); - regs_buff[7] = macb_readl(bp, IMR); - - regs_buff[8] = tail; - regs_buff[9] = head; - regs_buff[10] = macb_tx_dma(&bp->queues[0], tail); - regs_buff[11] = macb_tx_dma(&bp->queues[0], head); - - if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) - regs_buff[12] = macb_or_gem_readl(bp, USRIO); - if (macb_is_gem(bp)) - regs_buff[13] = gem_readl(bp, DMACFG); -} - -static void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) -{ - struct macb *bp = netdev_priv(netdev); - - wol->supported = 0; - wol->wolopts = 0; - - if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) { - wol->supported = WAKE_MAGIC; - - if (bp->wol & MACB_WOL_ENABLED) - wol->wolopts |= WAKE_MAGIC; - } -} - -static int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) -{ - struct macb *bp = netdev_priv(netdev); - - if (!(bp->wol & MACB_WOL_HAS_MAGIC_PACKET) || - (wol->wolopts & ~WAKE_MAGIC)) - return -EOPNOTSUPP; - - if (wol->wolopts & WAKE_MAGIC) - bp->wol |= MACB_WOL_ENABLED; - else - bp->wol &= ~MACB_WOL_ENABLED; - - device_set_wakeup_enable(&bp->pdev->dev, bp->wol & MACB_WOL_ENABLED); - - return 0; -} - -static void macb_get_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ring) -{ - struct macb *bp = netdev_priv(netdev); - - ring->rx_max_pending = MAX_RX_RING_SIZE; - ring->tx_max_pending = MAX_TX_RING_SIZE; - - ring->rx_pending = bp->rx_ring_size; - ring->tx_pending = bp->tx_ring_size; -} - -static int macb_set_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ring) -{ - struct macb *bp = netdev_priv(netdev); - u32 new_rx_size, new_tx_size; - unsigned int reset = 0; - - if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) - return -EINVAL; - - new_rx_size = clamp_t(u32, ring->rx_pending, - MIN_RX_RING_SIZE, MAX_RX_RING_SIZE); - new_rx_size = roundup_pow_of_two(new_rx_size); - - new_tx_size = clamp_t(u32, ring->tx_pending, - MIN_TX_RING_SIZE, MAX_TX_RING_SIZE); - new_tx_size = roundup_pow_of_two(new_tx_size); - - if ((new_tx_size == bp->tx_ring_size) && - (new_rx_size == bp->rx_ring_size)) { - /* nothing to do */ - return 0; - } - - if (netif_running(bp->dev)) { - reset = 1; - macb_close(bp->dev); - } - - bp->rx_ring_size = new_rx_size; - bp->tx_ring_size = new_tx_size; - - if (reset) - macb_open(bp->dev); - - return 0; -} - -static int macb_get_ts_info(struct net_device *netdev, - struct ethtool_ts_info *info) -{ - struct macb *bp = netdev_priv(netdev); - - if (bp->ptp_info) - return bp->ptp_info->get_ts_info(netdev, info); - - return ethtool_op_get_ts_info(netdev, info); -} - -static const struct ethtool_ops macb_ethtool_ops = { - .get_regs_len = macb_get_regs_len, - .get_regs = macb_get_regs, - .get_link = ethtool_op_get_link, - .get_ts_info = ethtool_op_get_ts_info, - .get_wol = macb_get_wol, - .set_wol = macb_set_wol, - .get_link_ksettings = phy_ethtool_get_link_ksettings, - .set_link_ksettings = phy_ethtool_set_link_ksettings, - .get_ringparam = macb_get_ringparam, - .set_ringparam = macb_set_ringparam, -}; - -static const struct ethtool_ops gem_ethtool_ops = { - .get_regs_len = macb_get_regs_len, - .get_regs = macb_get_regs, - .get_link = ethtool_op_get_link, - .get_ts_info = macb_get_ts_info, - .get_ethtool_stats = gem_get_ethtool_stats, - .get_strings = gem_get_ethtool_strings, - .get_sset_count = gem_get_sset_count, - .get_link_ksettings = phy_ethtool_get_link_ksettings, - .set_link_ksettings = phy_ethtool_set_link_ksettings, - .get_ringparam = macb_get_ringparam, - .set_ringparam = macb_set_ringparam, -}; - -static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct phy_device *phydev = dev->phydev; - struct macb *bp = netdev_priv(dev); - - if (!netif_running(dev)) - return -EINVAL; - - if (!phydev) - return -ENODEV; - - if (!bp->ptp_info) - return phy_mii_ioctl(phydev, rq, cmd); - - switch (cmd) { - case SIOCSHWTSTAMP: - return bp->ptp_info->set_hwtst(dev, rq, cmd); - case SIOCGHWTSTAMP: - return bp->ptp_info->get_hwtst(dev, rq); - default: - return phy_mii_ioctl(phydev, rq, cmd); - } -} - -static int macb_set_features(struct net_device *netdev, - netdev_features_t features) -{ - struct macb *bp = netdev_priv(netdev); - netdev_features_t changed = features ^ netdev->features; - - /* TX checksum offload */ - if ((changed & NETIF_F_HW_CSUM) && macb_is_gem(bp)) { - u32 dmacfg; - - dmacfg = gem_readl(bp, DMACFG); - if (features & NETIF_F_HW_CSUM) - dmacfg |= GEM_BIT(TXCOEN); - else - dmacfg &= ~GEM_BIT(TXCOEN); - gem_writel(bp, DMACFG, dmacfg); - } - - /* RX checksum offload */ - if ((changed & NETIF_F_RXCSUM) && macb_is_gem(bp)) { - u32 netcfg; - - netcfg = gem_readl(bp, NCFGR); - if (features & NETIF_F_RXCSUM && - !(netdev->flags & IFF_PROMISC)) - netcfg |= GEM_BIT(RXCOEN); - else - netcfg &= ~GEM_BIT(RXCOEN); - gem_writel(bp, NCFGR, netcfg); - } - - return 0; -} - -static const struct net_device_ops macb_netdev_ops = { - .ndo_open = macb_open, - .ndo_stop = macb_close, - .ndo_start_xmit = macb_start_xmit, - .ndo_set_rx_mode = macb_set_rx_mode, - .ndo_get_stats = macb_get_stats, - .ndo_do_ioctl = macb_ioctl, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = macb_change_mtu, - .ndo_set_mac_address = eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = macb_poll_controller, -#endif - .ndo_set_features = macb_set_features, - .ndo_features_check = macb_features_check, -}; - -/* Configure peripheral capabilities according to device tree - * and integration options used - */ -static void macb_configure_caps(struct macb *bp, - const struct macb_config *dt_conf) -{ - u32 dcfg; - - if (dt_conf) - bp->caps = dt_conf->caps; - - if (hw_is_gem(bp->regs, bp->native_io)) { - bp->caps |= MACB_CAPS_MACB_IS_GEM; - - dcfg = gem_readl(bp, DCFG1); - if (GEM_BFEXT(IRQCOR, dcfg) == 0) - bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE; - dcfg = gem_readl(bp, DCFG2); - if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0) - bp->caps |= MACB_CAPS_FIFO_MODE; - if (IS_ENABLED(CONFIG_MACB_USE_HWSTAMP) && gem_has_ptp(bp)) { - if (!GEM_BFEXT(TSU, gem_readl(bp, DCFG5))) - pr_err("GEM doesn't support hardware ptp.\n"); - else - bp->hw_dma_cap |= HW_DMA_CAP_PTP; - } - } - - dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps); -} - -static void macb_probe_queues(void __iomem *mem, - bool native_io, - unsigned int *queue_mask, - unsigned int *num_queues) -{ - unsigned int hw_q; - - *queue_mask = 0x1; - *num_queues = 1; - - /* is it macb or gem ? - * - * We need to read directly from the hardware here because - * we are early in the probe process and don't have the - * MACB_CAPS_MACB_IS_GEM flag positioned - */ - if (!hw_is_gem(mem, native_io)) - return; - - /* bit 0 is never set but queue 0 always exists */ - *queue_mask = readl_relaxed(mem + GEM_DCFG6) & 0xff; - - *queue_mask |= 0x1; - - for (hw_q = 1; hw_q < MACB_MAX_QUEUES; ++hw_q) - if (*queue_mask & (1 << hw_q)) - (*num_queues)++; -} - -static int macb_clk_init(struct platform_device *pdev, struct clk **pclk, - struct clk **hclk, struct clk **tx_clk, - struct clk **rx_clk) -{ - struct macb_platform_data *pdata; - int err; - - pdata = dev_get_platdata(&pdev->dev); - if (pdata) { - *pclk = pdata->pclk; - *hclk = pdata->hclk; - } else { - *pclk = devm_clk_get(&pdev->dev, "pclk"); - *hclk = devm_clk_get(&pdev->dev, "hclk"); - } - - if (IS_ERR(*pclk)) { - err = PTR_ERR(*pclk); - dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err); - return err; - } - - if (IS_ERR(*hclk)) { - err = PTR_ERR(*hclk); - dev_err(&pdev->dev, "failed to get hclk (%u)\n", err); - return err; - } - - *tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); - if (IS_ERR(*tx_clk)) - *tx_clk = NULL; - - *rx_clk = devm_clk_get(&pdev->dev, "rx_clk"); - if (IS_ERR(*rx_clk)) - *rx_clk = NULL; - - err = clk_prepare_enable(*pclk); - if (err) { - dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); - return err; - } - - err = clk_prepare_enable(*hclk); - if (err) { - dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err); - goto err_disable_pclk; - } - - err = clk_prepare_enable(*tx_clk); - if (err) { - dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); - goto err_disable_hclk; - } - - err = clk_prepare_enable(*rx_clk); - if (err) { - dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err); - goto err_disable_txclk; - } - - return 0; - -err_disable_txclk: - clk_disable_unprepare(*tx_clk); - -err_disable_hclk: - clk_disable_unprepare(*hclk); - -err_disable_pclk: - clk_disable_unprepare(*pclk); - - return err; -} - -static int macb_init(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - unsigned int hw_q, q; - struct macb *bp = netdev_priv(dev); - struct macb_queue *queue; - int err; - u32 val; - - bp->tx_ring_size = DEFAULT_TX_RING_SIZE; - bp->rx_ring_size = DEFAULT_RX_RING_SIZE; - - /* set the queue register mapping once for all: queue0 has a special - * register mapping but we don't want to test the queue index then - * compute the corresponding register offset at run time. - */ - for (hw_q = 0, q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) { - if (!(bp->queue_mask & (1 << hw_q))) - continue; - - queue = &bp->queues[q]; - queue->bp = bp; - if (hw_q) { - queue->ISR = GEM_ISR(hw_q - 1); - queue->IER = GEM_IER(hw_q - 1); - queue->IDR = GEM_IDR(hw_q - 1); - queue->IMR = GEM_IMR(hw_q - 1); - queue->TBQP = GEM_TBQP(hw_q - 1); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - queue->TBQPH = GEM_TBQPH(hw_q - 1); -#endif - } else { - /* queue0 uses legacy registers */ - queue->ISR = MACB_ISR; - queue->IER = MACB_IER; - queue->IDR = MACB_IDR; - queue->IMR = MACB_IMR; - queue->TBQP = MACB_TBQP; -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - queue->TBQPH = MACB_TBQPH; -#endif - } - - /* get irq: here we use the linux queue index, not the hardware - * queue index. the queue irq definitions in the device tree - * must remove the optional gaps that could exist in the - * hardware queue mask. - */ - queue->irq = platform_get_irq(pdev, q); - err = devm_request_irq(&pdev->dev, queue->irq, macb_interrupt, - IRQF_SHARED, dev->name, queue); - if (err) { - dev_err(&pdev->dev, - "Unable to request IRQ %d (error %d)\n", - queue->irq, err); - return err; - } - - INIT_WORK(&queue->tx_error_task, macb_tx_error_task); - q++; - } - - dev->netdev_ops = &macb_netdev_ops; - netif_napi_add(dev, &bp->napi, macb_poll, 64); - - /* setup appropriated routines according to adapter type */ - if (macb_is_gem(bp)) { - bp->max_tx_length = GEM_MAX_TX_LEN; - bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers; - bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers; - bp->macbgem_ops.mog_init_rings = gem_init_rings; - bp->macbgem_ops.mog_rx = gem_rx; - dev->ethtool_ops = &gem_ethtool_ops; - } else { - bp->max_tx_length = MACB_MAX_TX_LEN; - bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers; - bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers; - bp->macbgem_ops.mog_init_rings = macb_init_rings; - bp->macbgem_ops.mog_rx = macb_rx; - dev->ethtool_ops = &macb_ethtool_ops; - } - - /* Set features */ - dev->hw_features = NETIF_F_SG; - - /* Check LSO capability */ - if (GEM_BFEXT(PBUF_LSO, gem_readl(bp, DCFG6))) - dev->hw_features |= MACB_NETIF_LSO; - - /* Checksum offload is only available on gem with packet buffer */ - if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE)) - dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; - if (bp->caps & MACB_CAPS_SG_DISABLED) - dev->hw_features &= ~NETIF_F_SG; - dev->features = dev->hw_features; - - if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) { - val = 0; - if (bp->phy_interface == PHY_INTERFACE_MODE_RGMII) - val = GEM_BIT(RGMII); - else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII && - (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII)) - val = MACB_BIT(RMII); - else if (!(bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII)) - val = MACB_BIT(MII); - - if (bp->caps & MACB_CAPS_USRIO_HAS_CLKEN) - val |= MACB_BIT(CLKEN); - - macb_or_gem_writel(bp, USRIO, val); - } - - /* Set MII management clock divider */ - val = macb_mdc_clk_div(bp); - val |= macb_dbw(bp); - if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) - val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); - macb_writel(bp, NCFGR, val); - - return 0; -} - -#if defined(CONFIG_OF) -/* 1518 rounded up */ -#define AT91ETHER_MAX_RBUFF_SZ 0x600 -/* max number of receive buffers */ -#define AT91ETHER_MAX_RX_DESCR 9 - -/* Initialize and start the Receiver and Transmit subsystems */ -static int at91ether_start(struct net_device *dev) -{ - struct macb *lp = netdev_priv(dev); - struct macb_dma_desc *desc; - dma_addr_t addr; - u32 ctl; - int i; - - lp->rx_ring = dma_alloc_coherent(&lp->pdev->dev, - (AT91ETHER_MAX_RX_DESCR * - macb_dma_desc_get_size(lp)), - &lp->rx_ring_dma, GFP_KERNEL); - if (!lp->rx_ring) - return -ENOMEM; - - lp->rx_buffers = dma_alloc_coherent(&lp->pdev->dev, - AT91ETHER_MAX_RX_DESCR * - AT91ETHER_MAX_RBUFF_SZ, - &lp->rx_buffers_dma, GFP_KERNEL); - if (!lp->rx_buffers) { - dma_free_coherent(&lp->pdev->dev, - AT91ETHER_MAX_RX_DESCR * - macb_dma_desc_get_size(lp), - lp->rx_ring, lp->rx_ring_dma); - lp->rx_ring = NULL; - return -ENOMEM; - } - - addr = lp->rx_buffers_dma; - for (i = 0; i < AT91ETHER_MAX_RX_DESCR; i++) { - desc = macb_rx_desc(lp, i); - macb_set_addr(lp, desc, addr); - desc->ctrl = 0; - addr += AT91ETHER_MAX_RBUFF_SZ; - } - - /* Set the Wrap bit on the last descriptor */ - desc->addr |= MACB_BIT(RX_WRAP); - - /* Reset buffer index */ - lp->rx_tail = 0; - - /* Program address of descriptor list in Rx Buffer Queue register */ - macb_writel(lp, RBQP, lp->rx_ring_dma); - - /* Enable Receive and Transmit */ - ctl = macb_readl(lp, NCR); - macb_writel(lp, NCR, ctl | MACB_BIT(RE) | MACB_BIT(TE)); - - return 0; -} - -/* Open the ethernet interface */ -static int at91ether_open(struct net_device *dev) -{ - struct macb *lp = netdev_priv(dev); - u32 ctl; - int ret; - - /* Clear internal statistics */ - ctl = macb_readl(lp, NCR); - macb_writel(lp, NCR, ctl | MACB_BIT(CLRSTAT)); - - macb_set_hwaddr(lp); - - ret = at91ether_start(dev); - if (ret) - return ret; - - /* Enable MAC interrupts */ - macb_writel(lp, IER, MACB_BIT(RCOMP) | - MACB_BIT(RXUBR) | - MACB_BIT(ISR_TUND) | - MACB_BIT(ISR_RLE) | - MACB_BIT(TCOMP) | - MACB_BIT(ISR_ROVR) | - MACB_BIT(HRESP)); - - /* schedule a link state check */ - phy_start(dev->phydev); - - netif_start_queue(dev); - - return 0; -} - -/* Close the interface */ -static int at91ether_close(struct net_device *dev) -{ - struct macb *lp = netdev_priv(dev); - u32 ctl; - - /* Disable Receiver and Transmitter */ - ctl = macb_readl(lp, NCR); - macb_writel(lp, NCR, ctl & ~(MACB_BIT(TE) | MACB_BIT(RE))); - - /* Disable MAC interrupts */ - macb_writel(lp, IDR, MACB_BIT(RCOMP) | - MACB_BIT(RXUBR) | - MACB_BIT(ISR_TUND) | - MACB_BIT(ISR_RLE) | - MACB_BIT(TCOMP) | - MACB_BIT(ISR_ROVR) | - MACB_BIT(HRESP)); - - netif_stop_queue(dev); - - dma_free_coherent(&lp->pdev->dev, - AT91ETHER_MAX_RX_DESCR * - macb_dma_desc_get_size(lp), - lp->rx_ring, lp->rx_ring_dma); - lp->rx_ring = NULL; - - dma_free_coherent(&lp->pdev->dev, - AT91ETHER_MAX_RX_DESCR * AT91ETHER_MAX_RBUFF_SZ, - lp->rx_buffers, lp->rx_buffers_dma); - lp->rx_buffers = NULL; - - return 0; -} - -/* Transmit packet */ -static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct macb *lp = netdev_priv(dev); - - if (macb_readl(lp, TSR) & MACB_BIT(RM9200_BNQ)) { - netif_stop_queue(dev); - - /* Store packet information (to free when Tx completed) */ - lp->skb = skb; - lp->skb_length = skb->len; - lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(NULL, lp->skb_physaddr)) { - dev_kfree_skb_any(skb); - dev->stats.tx_dropped++; - netdev_err(dev, "%s: DMA mapping error\n", __func__); - return NETDEV_TX_OK; - } - - /* Set address of the data in the Transmit Address register */ - macb_writel(lp, TAR, lp->skb_physaddr); - /* Set length of the packet in the Transmit Control register */ - macb_writel(lp, TCR, skb->len); - - } else { - netdev_err(dev, "%s called, but device is busy!\n", __func__); - return NETDEV_TX_BUSY; - } - - return NETDEV_TX_OK; -} - -/* Extract received frame from buffer descriptors and sent to upper layers. - * (Called from interrupt context) - */ -static void at91ether_rx(struct net_device *dev) -{ - struct macb *lp = netdev_priv(dev); - struct macb_dma_desc *desc; - unsigned char *p_recv; - struct sk_buff *skb; - unsigned int pktlen; - - desc = macb_rx_desc(lp, lp->rx_tail); - while (desc->addr & MACB_BIT(RX_USED)) { - p_recv = lp->rx_buffers + lp->rx_tail * AT91ETHER_MAX_RBUFF_SZ; - pktlen = MACB_BF(RX_FRMLEN, desc->ctrl); - skb = netdev_alloc_skb(dev, pktlen + 2); - if (skb) { - skb_reserve(skb, 2); - skb_put_data(skb, p_recv, pktlen); - - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pktlen; - netif_rx(skb); - } else { - dev->stats.rx_dropped++; - } - - if (desc->ctrl & MACB_BIT(RX_MHASH_MATCH)) - dev->stats.multicast++; - - /* reset ownership bit */ - desc->addr &= ~MACB_BIT(RX_USED); - - /* wrap after last buffer */ - if (lp->rx_tail == AT91ETHER_MAX_RX_DESCR - 1) - lp->rx_tail = 0; - else - lp->rx_tail++; - - desc = macb_rx_desc(lp, lp->rx_tail); - } -} - -/* MAC interrupt handler */ -static irqreturn_t at91ether_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct macb *lp = netdev_priv(dev); - u32 intstatus, ctl; - - /* MAC Interrupt Status register indicates what interrupts are pending. - * It is automatically cleared once read. - */ - intstatus = macb_readl(lp, ISR); - - /* Receive complete */ - if (intstatus & MACB_BIT(RCOMP)) - at91ether_rx(dev); - - /* Transmit complete */ - if (intstatus & MACB_BIT(TCOMP)) { - /* The TCOM bit is set even if the transmission failed */ - if (intstatus & (MACB_BIT(ISR_TUND) | MACB_BIT(ISR_RLE))) - dev->stats.tx_errors++; - - if (lp->skb) { - dev_kfree_skb_irq(lp->skb); - lp->skb = NULL; - dma_unmap_single(NULL, lp->skb_physaddr, - lp->skb_length, DMA_TO_DEVICE); - dev->stats.tx_packets++; - dev->stats.tx_bytes += lp->skb_length; - } - netif_wake_queue(dev); - } - - /* Work-around for EMAC Errata section 41.3.1 */ - if (intstatus & MACB_BIT(RXUBR)) { - ctl = macb_readl(lp, NCR); - macb_writel(lp, NCR, ctl & ~MACB_BIT(RE)); - wmb(); - macb_writel(lp, NCR, ctl | MACB_BIT(RE)); - } - - if (intstatus & MACB_BIT(ISR_ROVR)) - netdev_err(dev, "ROVR error\n"); - - return IRQ_HANDLED; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void at91ether_poll_controller(struct net_device *dev) -{ - unsigned long flags; - - local_irq_save(flags); - at91ether_interrupt(dev->irq, dev); - local_irq_restore(flags); -} -#endif - -static const struct net_device_ops at91ether_netdev_ops = { - .ndo_open = at91ether_open, - .ndo_stop = at91ether_close, - .ndo_start_xmit = at91ether_start_xmit, - .ndo_get_stats = macb_get_stats, - .ndo_set_rx_mode = macb_set_rx_mode, - .ndo_set_mac_address = eth_mac_addr, - .ndo_do_ioctl = macb_ioctl, - .ndo_validate_addr = eth_validate_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = at91ether_poll_controller, -#endif -}; - -static int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk, - struct clk **hclk, struct clk **tx_clk, - struct clk **rx_clk) -{ - int err; - - *hclk = NULL; - *tx_clk = NULL; - *rx_clk = NULL; - - *pclk = devm_clk_get(&pdev->dev, "ether_clk"); - if (IS_ERR(*pclk)) - return PTR_ERR(*pclk); - - err = clk_prepare_enable(*pclk); - if (err) { - dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); - return err; - } - - return 0; -} - -static int at91ether_init(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct macb *bp = netdev_priv(dev); - int err; - u32 reg; - - dev->netdev_ops = &at91ether_netdev_ops; - dev->ethtool_ops = &macb_ethtool_ops; - - err = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt, - 0, dev->name, dev); - if (err) - return err; - - macb_writel(bp, NCR, 0); - - reg = MACB_BF(CLK, MACB_CLK_DIV32) | MACB_BIT(BIG); - if (bp->phy_interface == PHY_INTERFACE_MODE_RMII) - reg |= MACB_BIT(RM9200_RMII); - - macb_writel(bp, NCFGR, reg); - - return 0; -} - -static const struct macb_config at91sam9260_config = { - .caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, - .clk_init = macb_clk_init, - .init = macb_init, -}; - -static const struct macb_config pc302gem_config = { - .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, - .dma_burst_length = 16, - .clk_init = macb_clk_init, - .init = macb_init, -}; - -static const struct macb_config sama5d2_config = { - .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, - .dma_burst_length = 16, - .clk_init = macb_clk_init, - .init = macb_init, -}; - -static const struct macb_config sama5d3_config = { - .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE - | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, - .dma_burst_length = 16, - .clk_init = macb_clk_init, - .init = macb_init, -}; - -static const struct macb_config sama5d4_config = { - .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, - .dma_burst_length = 4, - .clk_init = macb_clk_init, - .init = macb_init, -}; - -static const struct macb_config emac_config = { - .clk_init = at91ether_clk_init, - .init = at91ether_init, -}; - -static const struct macb_config np4_config = { - .caps = MACB_CAPS_USRIO_DISABLED, - .clk_init = macb_clk_init, - .init = macb_init, -}; - -static const struct macb_config zynqmp_config = { - .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, - .dma_burst_length = 16, - .clk_init = macb_clk_init, - .init = macb_init, - .jumbo_max_len = 10240, -}; - -static const struct macb_config zynq_config = { - .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_NO_GIGABIT_HALF, - .dma_burst_length = 16, - .clk_init = macb_clk_init, - .init = macb_init, -}; - -static const struct of_device_id macb_dt_ids[] = { - { .compatible = "cdns,at32ap7000-macb" }, - { .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config }, - { .compatible = "cdns,macb" }, - { .compatible = "cdns,np4-macb", .data = &np4_config }, - { .compatible = "cdns,pc302-gem", .data = &pc302gem_config }, - { .compatible = "cdns,gem", .data = &pc302gem_config }, - { .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config }, - { .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config }, - { .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config }, - { .compatible = "cdns,at91rm9200-emac", .data = &emac_config }, - { .compatible = "cdns,emac", .data = &emac_config }, - { .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config}, - { .compatible = "cdns,zynq-gem", .data = &zynq_config }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, macb_dt_ids); -#endif /* CONFIG_OF */ - -static const struct macb_config default_gem_config = { - .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, - .dma_burst_length = 16, - .clk_init = macb_clk_init, - .init = macb_init, - .jumbo_max_len = 10240, -}; - -static int macb_probe(struct platform_device *pdev) -{ - const struct macb_config *macb_config = &default_gem_config; - int (*clk_init)(struct platform_device *, struct clk **, - struct clk **, struct clk **, struct clk **) - = macb_config->clk_init; - int (*init)(struct platform_device *) = macb_config->init; - struct device_node *np = pdev->dev.of_node; - struct device_node *phy_node; - struct clk *pclk, *hclk = NULL, *tx_clk = NULL, *rx_clk = NULL; - unsigned int queue_mask, num_queues; - struct macb_platform_data *pdata; - bool native_io; - struct phy_device *phydev; - struct net_device *dev; - struct resource *regs; - void __iomem *mem; - const char *mac; - struct macb *bp; - int err; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mem = devm_ioremap_resource(&pdev->dev, regs); - if (IS_ERR(mem)) - return PTR_ERR(mem); - - if (np) { - const struct of_device_id *match; - - match = of_match_node(macb_dt_ids, np); - if (match && match->data) { - macb_config = match->data; - clk_init = macb_config->clk_init; - init = macb_config->init; - } - } - - err = clk_init(pdev, &pclk, &hclk, &tx_clk, &rx_clk); - if (err) - return err; - - native_io = hw_is_native_io(mem); - - macb_probe_queues(mem, native_io, &queue_mask, &num_queues); - dev = alloc_etherdev_mq(sizeof(*bp), num_queues); - if (!dev) { - err = -ENOMEM; - goto err_disable_clocks; - } - - dev->base_addr = regs->start; - - SET_NETDEV_DEV(dev, &pdev->dev); - - bp = netdev_priv(dev); - bp->pdev = pdev; - bp->dev = dev; - bp->regs = mem; - bp->native_io = native_io; - if (native_io) { - bp->macb_reg_readl = hw_readl_native; - bp->macb_reg_writel = hw_writel_native; - } else { - bp->macb_reg_readl = hw_readl; - bp->macb_reg_writel = hw_writel; - } - bp->num_queues = num_queues; - bp->queue_mask = queue_mask; - if (macb_config) - bp->dma_burst_length = macb_config->dma_burst_length; - bp->pclk = pclk; - bp->hclk = hclk; - bp->tx_clk = tx_clk; - bp->rx_clk = rx_clk; - if (macb_config) - bp->jumbo_max_len = macb_config->jumbo_max_len; - - bp->wol = 0; - if (of_get_property(np, "magic-packet", NULL)) - bp->wol |= MACB_WOL_HAS_MAGIC_PACKET; - device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET); - - spin_lock_init(&bp->lock); - - /* setup capabilities */ - macb_configure_caps(bp, macb_config); - -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) { - dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); - bp->hw_dma_cap |= HW_DMA_CAP_64B; - } -#endif - platform_set_drvdata(pdev, dev); - - dev->irq = platform_get_irq(pdev, 0); - if (dev->irq < 0) { - err = dev->irq; - goto err_out_free_netdev; - } - - /* MTU range: 68 - 1500 or 10240 */ - dev->min_mtu = GEM_MTU_MIN_SIZE; - if (bp->caps & MACB_CAPS_JUMBO) - dev->max_mtu = gem_readl(bp, JML) - ETH_HLEN - ETH_FCS_LEN; - else - dev->max_mtu = ETH_DATA_LEN; - - mac = of_get_mac_address(np); - if (mac) - ether_addr_copy(bp->dev->dev_addr, mac); - else - macb_get_hwaddr(bp); - - /* Power up the PHY if there is a GPIO reset */ - phy_node = of_get_next_available_child(np, NULL); - if (phy_node) { - int gpio = of_get_named_gpio(phy_node, "reset-gpios", 0); - - if (gpio_is_valid(gpio)) { - bp->reset_gpio = gpio_to_desc(gpio); - gpiod_direction_output(bp->reset_gpio, 1); - } - } - of_node_put(phy_node); - - err = of_get_phy_mode(np); - if (err < 0) { - pdata = dev_get_platdata(&pdev->dev); - if (pdata && pdata->is_rmii) - bp->phy_interface = PHY_INTERFACE_MODE_RMII; - else - bp->phy_interface = PHY_INTERFACE_MODE_MII; - } else { - bp->phy_interface = err; - } - - /* IP specific init */ - err = init(pdev); - if (err) - goto err_out_free_netdev; - - err = macb_mii_init(bp); - if (err) - goto err_out_free_netdev; - - phydev = dev->phydev; - - netif_carrier_off(dev); - - err = register_netdev(dev); - if (err) { - dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); - goto err_out_unregister_mdio; - } - - phy_attached_info(phydev); - - netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n", - macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID), - dev->base_addr, dev->irq, dev->dev_addr); - - return 0; - -err_out_unregister_mdio: - phy_disconnect(dev->phydev); - mdiobus_unregister(bp->mii_bus); - mdiobus_free(bp->mii_bus); - - /* Shutdown the PHY if there is a GPIO reset */ - if (bp->reset_gpio) - gpiod_set_value(bp->reset_gpio, 0); - -err_out_free_netdev: - free_netdev(dev); - -err_disable_clocks: - clk_disable_unprepare(tx_clk); - clk_disable_unprepare(hclk); - clk_disable_unprepare(pclk); - clk_disable_unprepare(rx_clk); - - return err; -} - -static int macb_remove(struct platform_device *pdev) -{ - struct net_device *dev; - struct macb *bp; - - dev = platform_get_drvdata(pdev); - - if (dev) { - bp = netdev_priv(dev); - if (dev->phydev) - phy_disconnect(dev->phydev); - mdiobus_unregister(bp->mii_bus); - dev->phydev = NULL; - mdiobus_free(bp->mii_bus); - - /* Shutdown the PHY if there is a GPIO reset */ - if (bp->reset_gpio) - gpiod_set_value(bp->reset_gpio, 0); - - unregister_netdev(dev); - clk_disable_unprepare(bp->tx_clk); - clk_disable_unprepare(bp->hclk); - clk_disable_unprepare(bp->pclk); - clk_disable_unprepare(bp->rx_clk); - of_node_put(bp->phy_node); - free_netdev(dev); - } - - return 0; -} - -static int __maybe_unused macb_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct net_device *netdev = platform_get_drvdata(pdev); - struct macb *bp = netdev_priv(netdev); - - netif_carrier_off(netdev); - netif_device_detach(netdev); - - if (bp->wol & MACB_WOL_ENABLED) { - macb_writel(bp, IER, MACB_BIT(WOL)); - macb_writel(bp, WOL, MACB_BIT(MAG)); - enable_irq_wake(bp->queues[0].irq); - } else { - clk_disable_unprepare(bp->tx_clk); - clk_disable_unprepare(bp->hclk); - clk_disable_unprepare(bp->pclk); - clk_disable_unprepare(bp->rx_clk); - } - - return 0; -} - -static int __maybe_unused macb_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct net_device *netdev = platform_get_drvdata(pdev); - struct macb *bp = netdev_priv(netdev); - - if (bp->wol & MACB_WOL_ENABLED) { - macb_writel(bp, IDR, MACB_BIT(WOL)); - macb_writel(bp, WOL, 0); - disable_irq_wake(bp->queues[0].irq); - } else { - clk_prepare_enable(bp->pclk); - clk_prepare_enable(bp->hclk); - clk_prepare_enable(bp->tx_clk); - clk_prepare_enable(bp->rx_clk); - } - - netif_device_attach(netdev); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume); - -static struct platform_driver macb_driver = { - .probe = macb_probe, - .remove = macb_remove, - .driver = { - .name = "macb", - .of_match_table = of_match_ptr(macb_dt_ids), - .pm = &macb_pm_ops, - }, -}; - -module_platform_driver(macb_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver"); -MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); -MODULE_ALIAS("platform:macb"); diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c new file mode 100644 index 000000000000..2d43a7619f58 --- /dev/null +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -0,0 +1,3588 @@ +/* + * Cadence MACB/GEM Ethernet Controller driver + * + * Copyright (C) 2004-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "macb.h" + +#define MACB_RX_BUFFER_SIZE 128 +#define RX_BUFFER_MULTIPLE 64 /* bytes */ + +#define DEFAULT_RX_RING_SIZE 512 /* must be power of 2 */ +#define MIN_RX_RING_SIZE 64 +#define MAX_RX_RING_SIZE 8192 +#define RX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \ + * (bp)->rx_ring_size) + +#define DEFAULT_TX_RING_SIZE 512 /* must be power of 2 */ +#define MIN_TX_RING_SIZE 64 +#define MAX_TX_RING_SIZE 4096 +#define TX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \ + * (bp)->tx_ring_size) + +/* level of occupied TX descriptors under which we wake up TX process */ +#define MACB_TX_WAKEUP_THRESH(bp) (3 * (bp)->tx_ring_size / 4) + +#define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \ + | MACB_BIT(ISR_ROVR)) +#define MACB_TX_ERR_FLAGS (MACB_BIT(ISR_TUND) \ + | MACB_BIT(ISR_RLE) \ + | MACB_BIT(TXERR)) +#define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP)) + +/* Max length of transmit frame must be a multiple of 8 bytes */ +#define MACB_TX_LEN_ALIGN 8 +#define MACB_MAX_TX_LEN ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1))) +#define GEM_MAX_TX_LEN ((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1))) + +#define GEM_MTU_MIN_SIZE ETH_MIN_MTU +#define MACB_NETIF_LSO (NETIF_F_TSO | NETIF_F_UFO) + +#define MACB_WOL_HAS_MAGIC_PACKET (0x1 << 0) +#define MACB_WOL_ENABLED (0x1 << 1) + +/* Graceful stop timeouts in us. We should allow up to + * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions) + */ +#define MACB_HALT_TIMEOUT 1230 + +/* DMA buffer descriptor might be different size + * depends on hardware configuration: + * + * 1. dma address width 32 bits: + * word 1: 32 bit address of Data Buffer + * word 2: control + * + * 2. dma address width 64 bits: + * word 1: 32 bit address of Data Buffer + * word 2: control + * word 3: upper 32 bit address of Data Buffer + * word 4: unused + * + * 3. dma address width 32 bits with hardware timestamping: + * word 1: 32 bit address of Data Buffer + * word 2: control + * word 3: timestamp word 1 + * word 4: timestamp word 2 + * + * 4. dma address width 64 bits with hardware timestamping: + * word 1: 32 bit address of Data Buffer + * word 2: control + * word 3: upper 32 bit address of Data Buffer + * word 4: unused + * word 5: timestamp word 1 + * word 6: timestamp word 2 + */ +static unsigned int macb_dma_desc_get_size(struct macb *bp) +{ +#ifdef MACB_EXT_DESC + unsigned int desc_size; + + switch (bp->hw_dma_cap) { + case HW_DMA_CAP_64B: + desc_size = sizeof(struct macb_dma_desc) + + sizeof(struct macb_dma_desc_64); + break; + case HW_DMA_CAP_PTP: + desc_size = sizeof(struct macb_dma_desc) + + sizeof(struct macb_dma_desc_ptp); + break; + case HW_DMA_CAP_64B_PTP: + desc_size = sizeof(struct macb_dma_desc) + + sizeof(struct macb_dma_desc_64) + + sizeof(struct macb_dma_desc_ptp); + break; + default: + desc_size = sizeof(struct macb_dma_desc); + } + return desc_size; +#endif + return sizeof(struct macb_dma_desc); +} + +static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int desc_idx) +{ +#ifdef MACB_EXT_DESC + switch (bp->hw_dma_cap) { + case HW_DMA_CAP_64B: + case HW_DMA_CAP_PTP: + desc_idx <<= 1; + break; + case HW_DMA_CAP_64B_PTP: + desc_idx *= 3; + break; + default: + break; + } + return desc_idx; +#endif + return desc_idx; +} + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +static struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct macb_dma_desc *desc) +{ + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + return (struct macb_dma_desc_64 *)((void *)desc + sizeof(struct macb_dma_desc)); + return NULL; +} +#endif + +/* Ring buffer accessors */ +static unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index) +{ + return index & (bp->tx_ring_size - 1); +} + +static struct macb_dma_desc *macb_tx_desc(struct macb_queue *queue, + unsigned int index) +{ + index = macb_tx_ring_wrap(queue->bp, index); + index = macb_adj_dma_desc_idx(queue->bp, index); + return &queue->tx_ring[index]; +} + +static struct macb_tx_skb *macb_tx_skb(struct macb_queue *queue, + unsigned int index) +{ + return &queue->tx_skb[macb_tx_ring_wrap(queue->bp, index)]; +} + +static dma_addr_t macb_tx_dma(struct macb_queue *queue, unsigned int index) +{ + dma_addr_t offset; + + offset = macb_tx_ring_wrap(queue->bp, index) * + macb_dma_desc_get_size(queue->bp); + + return queue->tx_ring_dma + offset; +} + +static unsigned int macb_rx_ring_wrap(struct macb *bp, unsigned int index) +{ + return index & (bp->rx_ring_size - 1); +} + +static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index) +{ + index = macb_rx_ring_wrap(bp, index); + index = macb_adj_dma_desc_idx(bp, index); + return &bp->rx_ring[index]; +} + +static void *macb_rx_buffer(struct macb *bp, unsigned int index) +{ + return bp->rx_buffers + bp->rx_buffer_size * + macb_rx_ring_wrap(bp, index); +} + +/* I/O accessors */ +static u32 hw_readl_native(struct macb *bp, int offset) +{ + return __raw_readl(bp->regs + offset); +} + +static void hw_writel_native(struct macb *bp, int offset, u32 value) +{ + __raw_writel(value, bp->regs + offset); +} + +static u32 hw_readl(struct macb *bp, int offset) +{ + return readl_relaxed(bp->regs + offset); +} + +static void hw_writel(struct macb *bp, int offset, u32 value) +{ + writel_relaxed(value, bp->regs + offset); +} + +/* Find the CPU endianness by using the loopback bit of NCR register. When the + * CPU is in big endian we need to program swapped mode for management + * descriptor access. + */ +static bool hw_is_native_io(void __iomem *addr) +{ + u32 value = MACB_BIT(LLB); + + __raw_writel(value, addr + MACB_NCR); + value = __raw_readl(addr + MACB_NCR); + + /* Write 0 back to disable everything */ + __raw_writel(0, addr + MACB_NCR); + + return value == MACB_BIT(LLB); +} + +static bool hw_is_gem(void __iomem *addr, bool native_io) +{ + u32 id; + + if (native_io) + id = __raw_readl(addr + MACB_MID); + else + id = readl_relaxed(addr + MACB_MID); + + return MACB_BFEXT(IDNUM, id) >= 0x2; +} + +static void macb_set_hwaddr(struct macb *bp) +{ + u32 bottom; + u16 top; + + bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr)); + macb_or_gem_writel(bp, SA1B, bottom); + top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4))); + macb_or_gem_writel(bp, SA1T, top); + + /* Clear unused address register sets */ + macb_or_gem_writel(bp, SA2B, 0); + macb_or_gem_writel(bp, SA2T, 0); + macb_or_gem_writel(bp, SA3B, 0); + macb_or_gem_writel(bp, SA3T, 0); + macb_or_gem_writel(bp, SA4B, 0); + macb_or_gem_writel(bp, SA4T, 0); +} + +static void macb_get_hwaddr(struct macb *bp) +{ + struct macb_platform_data *pdata; + u32 bottom; + u16 top; + u8 addr[6]; + int i; + + pdata = dev_get_platdata(&bp->pdev->dev); + + /* Check all 4 address register for valid address */ + for (i = 0; i < 4; i++) { + bottom = macb_or_gem_readl(bp, SA1B + i * 8); + top = macb_or_gem_readl(bp, SA1T + i * 8); + + if (pdata && pdata->rev_eth_addr) { + addr[5] = bottom & 0xff; + addr[4] = (bottom >> 8) & 0xff; + addr[3] = (bottom >> 16) & 0xff; + addr[2] = (bottom >> 24) & 0xff; + addr[1] = top & 0xff; + addr[0] = (top & 0xff00) >> 8; + } else { + addr[0] = bottom & 0xff; + addr[1] = (bottom >> 8) & 0xff; + addr[2] = (bottom >> 16) & 0xff; + addr[3] = (bottom >> 24) & 0xff; + addr[4] = top & 0xff; + addr[5] = (top >> 8) & 0xff; + } + + if (is_valid_ether_addr(addr)) { + memcpy(bp->dev->dev_addr, addr, sizeof(addr)); + return; + } + } + + dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); + eth_hw_addr_random(bp->dev); +} + +static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct macb *bp = bus->priv; + int value; + + macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) + | MACB_BF(RW, MACB_MAN_READ) + | MACB_BF(PHYA, mii_id) + | MACB_BF(REGA, regnum) + | MACB_BF(CODE, MACB_MAN_CODE))); + + /* wait for end of transfer */ + while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) + cpu_relax(); + + value = MACB_BFEXT(DATA, macb_readl(bp, MAN)); + + return value; +} + +static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, + u16 value) +{ + struct macb *bp = bus->priv; + + macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) + | MACB_BF(RW, MACB_MAN_WRITE) + | MACB_BF(PHYA, mii_id) + | MACB_BF(REGA, regnum) + | MACB_BF(CODE, MACB_MAN_CODE) + | MACB_BF(DATA, value))); + + /* wait for end of transfer */ + while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) + cpu_relax(); + + return 0; +} + +/** + * macb_set_tx_clk() - Set a clock to a new frequency + * @clk Pointer to the clock to change + * @rate New frequency in Hz + * @dev Pointer to the struct net_device + */ +static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) +{ + long ferr, rate, rate_rounded; + + if (!clk) + return; + + switch (speed) { + case SPEED_10: + rate = 2500000; + break; + case SPEED_100: + rate = 25000000; + break; + case SPEED_1000: + rate = 125000000; + break; + default: + return; + } + + rate_rounded = clk_round_rate(clk, rate); + if (rate_rounded < 0) + return; + + /* RGMII allows 50 ppm frequency error. Test and warn if this limit + * is not satisfied. + */ + ferr = abs(rate_rounded - rate); + ferr = DIV_ROUND_UP(ferr, rate / 100000); + if (ferr > 5) + netdev_warn(dev, "unable to generate target frequency: %ld Hz\n", + rate); + + if (clk_set_rate(clk, rate_rounded)) + netdev_err(dev, "adjusting tx_clk failed.\n"); +} + +static void macb_handle_link_change(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + struct phy_device *phydev = dev->phydev; + unsigned long flags; + int status_change = 0; + + spin_lock_irqsave(&bp->lock, flags); + + if (phydev->link) { + if ((bp->speed != phydev->speed) || + (bp->duplex != phydev->duplex)) { + u32 reg; + + reg = macb_readl(bp, NCFGR); + reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); + if (macb_is_gem(bp)) + reg &= ~GEM_BIT(GBE); + + if (phydev->duplex) + reg |= MACB_BIT(FD); + if (phydev->speed == SPEED_100) + reg |= MACB_BIT(SPD); + if (phydev->speed == SPEED_1000 && + bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) + reg |= GEM_BIT(GBE); + + macb_or_gem_writel(bp, NCFGR, reg); + + bp->speed = phydev->speed; + bp->duplex = phydev->duplex; + status_change = 1; + } + } + + if (phydev->link != bp->link) { + if (!phydev->link) { + bp->speed = 0; + bp->duplex = -1; + } + bp->link = phydev->link; + + status_change = 1; + } + + spin_unlock_irqrestore(&bp->lock, flags); + + if (status_change) { + if (phydev->link) { + /* Update the TX clock rate if and only if the link is + * up and there has been a link change. + */ + macb_set_tx_clk(bp->tx_clk, phydev->speed, dev); + + netif_carrier_on(dev); + netdev_info(dev, "link up (%d/%s)\n", + phydev->speed, + phydev->duplex == DUPLEX_FULL ? + "Full" : "Half"); + } else { + netif_carrier_off(dev); + netdev_info(dev, "link down\n"); + } + } +} + +/* based on au1000_eth. c*/ +static int macb_mii_probe(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + struct macb_platform_data *pdata; + struct phy_device *phydev; + int phy_irq; + int ret; + + if (bp->phy_node) { + phydev = of_phy_connect(dev, bp->phy_node, + &macb_handle_link_change, 0, + bp->phy_interface); + if (!phydev) + return -ENODEV; + } else { + phydev = phy_find_first(bp->mii_bus); + if (!phydev) { + netdev_err(dev, "no PHY found\n"); + return -ENXIO; + } + + pdata = dev_get_platdata(&bp->pdev->dev); + if (pdata) { + if (gpio_is_valid(pdata->phy_irq_pin)) { + ret = devm_gpio_request(&bp->pdev->dev, + pdata->phy_irq_pin, "phy int"); + if (!ret) { + phy_irq = gpio_to_irq(pdata->phy_irq_pin); + phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq; + } + } else { + phydev->irq = PHY_POLL; + } + } + + /* attach the mac to the phy */ + ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, + bp->phy_interface); + if (ret) { + netdev_err(dev, "Could not attach to PHY\n"); + return ret; + } + } + + /* mask with MAC supported features */ + if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) + phydev->supported &= PHY_GBIT_FEATURES; + else + phydev->supported &= PHY_BASIC_FEATURES; + + if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF) + phydev->supported &= ~SUPPORTED_1000baseT_Half; + + phydev->advertising = phydev->supported; + + bp->link = 0; + bp->speed = 0; + bp->duplex = -1; + + return 0; +} + +static int macb_mii_init(struct macb *bp) +{ + struct macb_platform_data *pdata; + struct device_node *np; + int err = -ENXIO, i; + + /* Enable management port */ + macb_writel(bp, NCR, MACB_BIT(MPE)); + + bp->mii_bus = mdiobus_alloc(); + if (!bp->mii_bus) { + err = -ENOMEM; + goto err_out; + } + + bp->mii_bus->name = "MACB_mii_bus"; + bp->mii_bus->read = &macb_mdio_read; + bp->mii_bus->write = &macb_mdio_write; + snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + bp->pdev->name, bp->pdev->id); + bp->mii_bus->priv = bp; + bp->mii_bus->parent = &bp->pdev->dev; + pdata = dev_get_platdata(&bp->pdev->dev); + + dev_set_drvdata(&bp->dev->dev, bp->mii_bus); + + np = bp->pdev->dev.of_node; + if (np) { + if (of_phy_is_fixed_link(np)) { + if (of_phy_register_fixed_link(np) < 0) { + dev_err(&bp->pdev->dev, + "broken fixed-link specification\n"); + goto err_out_unregister_bus; + } + bp->phy_node = of_node_get(np); + + err = mdiobus_register(bp->mii_bus); + } else { + /* try dt phy registration */ + err = of_mdiobus_register(bp->mii_bus, np); + + /* fallback to standard phy registration if no phy were + * found during dt phy registration + */ + if (!err && !phy_find_first(bp->mii_bus)) { + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *phydev; + + phydev = mdiobus_scan(bp->mii_bus, i); + if (IS_ERR(phydev) && + PTR_ERR(phydev) != -ENODEV) { + err = PTR_ERR(phydev); + break; + } + } + + if (err) + goto err_out_unregister_bus; + } + } + } else { + for (i = 0; i < PHY_MAX_ADDR; i++) + bp->mii_bus->irq[i] = PHY_POLL; + + if (pdata) + bp->mii_bus->phy_mask = pdata->phy_mask; + + err = mdiobus_register(bp->mii_bus); + } + + if (err) + goto err_out_free_mdiobus; + + err = macb_mii_probe(bp->dev); + if (err) + goto err_out_unregister_bus; + + return 0; + +err_out_unregister_bus: + mdiobus_unregister(bp->mii_bus); +err_out_free_mdiobus: + mdiobus_free(bp->mii_bus); +err_out: + return err; +} + +static void macb_update_stats(struct macb *bp) +{ + u32 *p = &bp->hw_stats.macb.rx_pause_frames; + u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1; + int offset = MACB_PFR; + + WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); + + for (; p < end; p++, offset += 4) + *p += bp->macb_reg_readl(bp, offset); +} + +static int macb_halt_tx(struct macb *bp) +{ + unsigned long halt_time, timeout; + u32 status; + + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT)); + + timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT); + do { + halt_time = jiffies; + status = macb_readl(bp, TSR); + if (!(status & MACB_BIT(TGO))) + return 0; + + usleep_range(10, 250); + } while (time_before(halt_time, timeout)); + + return -ETIMEDOUT; +} + +static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb) +{ + if (tx_skb->mapping) { + if (tx_skb->mapped_as_page) + dma_unmap_page(&bp->pdev->dev, tx_skb->mapping, + tx_skb->size, DMA_TO_DEVICE); + else + dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, + tx_skb->size, DMA_TO_DEVICE); + tx_skb->mapping = 0; + } + + if (tx_skb->skb) { + dev_kfree_skb_any(tx_skb->skb); + tx_skb->skb = NULL; + } +} + +static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_t addr) +{ +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + struct macb_dma_desc_64 *desc_64; + + if (bp->hw_dma_cap & HW_DMA_CAP_64B) { + desc_64 = macb_64b_desc(bp, desc); + desc_64->addrh = upper_32_bits(addr); + } +#endif + desc->addr = lower_32_bits(addr); +} + +static dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc) +{ + dma_addr_t addr = 0; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + struct macb_dma_desc_64 *desc_64; + + if (bp->hw_dma_cap & HW_DMA_CAP_64B) { + desc_64 = macb_64b_desc(bp, desc); + addr = ((u64)(desc_64->addrh) << 32); + } +#endif + addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr)); + return addr; +} + +static void macb_tx_error_task(struct work_struct *work) +{ + struct macb_queue *queue = container_of(work, struct macb_queue, + tx_error_task); + struct macb *bp = queue->bp; + struct macb_tx_skb *tx_skb; + struct macb_dma_desc *desc; + struct sk_buff *skb; + unsigned int tail; + unsigned long flags; + + netdev_vdbg(bp->dev, "macb_tx_error_task: q = %u, t = %u, h = %u\n", + (unsigned int)(queue - bp->queues), + queue->tx_tail, queue->tx_head); + + /* Prevent the queue IRQ handlers from running: each of them may call + * macb_tx_interrupt(), which in turn may call netif_wake_subqueue(). + * As explained below, we have to halt the transmission before updating + * TBQP registers so we call netif_tx_stop_all_queues() to notify the + * network engine about the macb/gem being halted. + */ + spin_lock_irqsave(&bp->lock, flags); + + /* Make sure nobody is trying to queue up new packets */ + netif_tx_stop_all_queues(bp->dev); + + /* Stop transmission now + * (in case we have just queued new packets) + * macb/gem must be halted to write TBQP register + */ + if (macb_halt_tx(bp)) + /* Just complain for now, reinitializing TX path can be good */ + netdev_err(bp->dev, "BUG: halt tx timed out\n"); + + /* Treat frames in TX queue including the ones that caused the error. + * Free transmit buffers in upper layer. + */ + for (tail = queue->tx_tail; tail != queue->tx_head; tail++) { + u32 ctrl; + + desc = macb_tx_desc(queue, tail); + ctrl = desc->ctrl; + tx_skb = macb_tx_skb(queue, tail); + skb = tx_skb->skb; + + if (ctrl & MACB_BIT(TX_USED)) { + /* skb is set for the last buffer of the frame */ + while (!skb) { + macb_tx_unmap(bp, tx_skb); + tail++; + tx_skb = macb_tx_skb(queue, tail); + skb = tx_skb->skb; + } + + /* ctrl still refers to the first buffer descriptor + * since it's the only one written back by the hardware + */ + if (!(ctrl & MACB_BIT(TX_BUF_EXHAUSTED))) { + netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n", + macb_tx_ring_wrap(bp, tail), + skb->data); + bp->dev->stats.tx_packets++; + bp->dev->stats.tx_bytes += skb->len; + } + } else { + /* "Buffers exhausted mid-frame" errors may only happen + * if the driver is buggy, so complain loudly about + * those. Statistics are updated by hardware. + */ + if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED)) + netdev_err(bp->dev, + "BUG: TX buffers exhausted mid-frame\n"); + + desc->ctrl = ctrl | MACB_BIT(TX_USED); + } + + macb_tx_unmap(bp, tx_skb); + } + + /* Set end of TX queue */ + desc = macb_tx_desc(queue, 0); + macb_set_addr(bp, desc, 0); + desc->ctrl = MACB_BIT(TX_USED); + + /* Make descriptor updates visible to hardware */ + wmb(); + + /* Reinitialize the TX desc queue */ + queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); +#endif + /* Make TX ring reflect state of hardware */ + queue->tx_head = 0; + queue->tx_tail = 0; + + /* Housework before enabling TX IRQ */ + macb_writel(bp, TSR, macb_readl(bp, TSR)); + queue_writel(queue, IER, MACB_TX_INT_FLAGS); + + /* Now we are ready to start transmission again */ + netif_tx_start_all_queues(bp->dev); + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); + + spin_unlock_irqrestore(&bp->lock, flags); +} + +static void macb_tx_interrupt(struct macb_queue *queue) +{ + unsigned int tail; + unsigned int head; + u32 status; + struct macb *bp = queue->bp; + u16 queue_index = queue - bp->queues; + + status = macb_readl(bp, TSR); + macb_writel(bp, TSR, status); + + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, MACB_BIT(TCOMP)); + + netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n", + (unsigned long)status); + + head = queue->tx_head; + for (tail = queue->tx_tail; tail != head; tail++) { + struct macb_tx_skb *tx_skb; + struct sk_buff *skb; + struct macb_dma_desc *desc; + u32 ctrl; + + desc = macb_tx_desc(queue, tail); + + /* Make hw descriptor updates visible to CPU */ + rmb(); + + ctrl = desc->ctrl; + + /* TX_USED bit is only set by hardware on the very first buffer + * descriptor of the transmitted frame. + */ + if (!(ctrl & MACB_BIT(TX_USED))) + break; + + /* Process all buffers of the current transmitted frame */ + for (;; tail++) { + tx_skb = macb_tx_skb(queue, tail); + skb = tx_skb->skb; + + /* First, update TX stats if needed */ + if (skb) { + netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", + macb_tx_ring_wrap(bp, tail), + skb->data); + bp->dev->stats.tx_packets++; + bp->dev->stats.tx_bytes += skb->len; + } + + /* Now we can safely release resources */ + macb_tx_unmap(bp, tx_skb); + + /* skb is set only for the last buffer of the frame. + * WARNING: at this point skb has been freed by + * macb_tx_unmap(). + */ + if (skb) + break; + } + } + + queue->tx_tail = tail; + if (__netif_subqueue_stopped(bp->dev, queue_index) && + CIRC_CNT(queue->tx_head, queue->tx_tail, + bp->tx_ring_size) <= MACB_TX_WAKEUP_THRESH(bp)) + netif_wake_subqueue(bp->dev, queue_index); +} + +static void gem_rx_refill(struct macb *bp) +{ + unsigned int entry; + struct sk_buff *skb; + dma_addr_t paddr; + struct macb_dma_desc *desc; + + while (CIRC_SPACE(bp->rx_prepared_head, bp->rx_tail, + bp->rx_ring_size) > 0) { + entry = macb_rx_ring_wrap(bp, bp->rx_prepared_head); + + /* Make hw descriptor updates visible to CPU */ + rmb(); + + bp->rx_prepared_head++; + desc = macb_rx_desc(bp, entry); + + if (!bp->rx_skbuff[entry]) { + /* allocate sk_buff for this free entry in ring */ + skb = netdev_alloc_skb(bp->dev, bp->rx_buffer_size); + if (unlikely(!skb)) { + netdev_err(bp->dev, + "Unable to allocate sk_buff\n"); + break; + } + + /* now fill corresponding descriptor entry */ + paddr = dma_map_single(&bp->pdev->dev, skb->data, + bp->rx_buffer_size, + DMA_FROM_DEVICE); + if (dma_mapping_error(&bp->pdev->dev, paddr)) { + dev_kfree_skb(skb); + break; + } + + bp->rx_skbuff[entry] = skb; + + if (entry == bp->rx_ring_size - 1) + paddr |= MACB_BIT(RX_WRAP); + macb_set_addr(bp, desc, paddr); + desc->ctrl = 0; + + /* properly align Ethernet header */ + skb_reserve(skb, NET_IP_ALIGN); + } else { + desc->addr &= ~MACB_BIT(RX_USED); + desc->ctrl = 0; + } + } + + /* Make descriptor updates visible to hardware */ + wmb(); + + netdev_vdbg(bp->dev, "rx ring: prepared head %d, tail %d\n", + bp->rx_prepared_head, bp->rx_tail); +} + +/* Mark DMA descriptors from begin up to and not including end as unused */ +static void discard_partial_frame(struct macb *bp, unsigned int begin, + unsigned int end) +{ + unsigned int frag; + + for (frag = begin; frag != end; frag++) { + struct macb_dma_desc *desc = macb_rx_desc(bp, frag); + + desc->addr &= ~MACB_BIT(RX_USED); + } + + /* Make descriptor updates visible to hardware */ + wmb(); + + /* When this happens, the hardware stats registers for + * whatever caused this is updated, so we don't have to record + * anything. + */ +} + +static int gem_rx(struct macb *bp, int budget) +{ + unsigned int len; + unsigned int entry; + struct sk_buff *skb; + struct macb_dma_desc *desc; + int count = 0; + + while (count < budget) { + u32 ctrl; + dma_addr_t addr; + bool rxused; + + entry = macb_rx_ring_wrap(bp, bp->rx_tail); + desc = macb_rx_desc(bp, entry); + + /* Make hw descriptor updates visible to CPU */ + rmb(); + + rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false; + addr = macb_get_addr(bp, desc); + ctrl = desc->ctrl; + + if (!rxused) + break; + + bp->rx_tail++; + count++; + + if (!(ctrl & MACB_BIT(RX_SOF) && ctrl & MACB_BIT(RX_EOF))) { + netdev_err(bp->dev, + "not whole frame pointed by descriptor\n"); + bp->dev->stats.rx_dropped++; + break; + } + skb = bp->rx_skbuff[entry]; + if (unlikely(!skb)) { + netdev_err(bp->dev, + "inconsistent Rx descriptor chain\n"); + bp->dev->stats.rx_dropped++; + break; + } + /* now everything is ready for receiving packet */ + bp->rx_skbuff[entry] = NULL; + len = ctrl & bp->rx_frm_len_mask; + + netdev_vdbg(bp->dev, "gem_rx %u (len %u)\n", entry, len); + + skb_put(skb, len); + dma_unmap_single(&bp->pdev->dev, addr, + bp->rx_buffer_size, DMA_FROM_DEVICE); + + skb->protocol = eth_type_trans(skb, bp->dev); + skb_checksum_none_assert(skb); + if (bp->dev->features & NETIF_F_RXCSUM && + !(bp->dev->flags & IFF_PROMISC) && + GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + bp->dev->stats.rx_packets++; + bp->dev->stats.rx_bytes += skb->len; + +#if defined(DEBUG) && defined(VERBOSE_DEBUG) + netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n", + skb->len, skb->csum); + print_hex_dump(KERN_DEBUG, " mac: ", DUMP_PREFIX_ADDRESS, 16, 1, + skb_mac_header(skb), 16, true); + print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_ADDRESS, 16, 1, + skb->data, 32, true); +#endif + + netif_receive_skb(skb); + } + + gem_rx_refill(bp); + + return count; +} + +static int macb_rx_frame(struct macb *bp, unsigned int first_frag, + unsigned int last_frag) +{ + unsigned int len; + unsigned int frag; + unsigned int offset; + struct sk_buff *skb; + struct macb_dma_desc *desc; + + desc = macb_rx_desc(bp, last_frag); + len = desc->ctrl & bp->rx_frm_len_mask; + + netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n", + macb_rx_ring_wrap(bp, first_frag), + macb_rx_ring_wrap(bp, last_frag), len); + + /* The ethernet header starts NET_IP_ALIGN bytes into the + * first buffer. Since the header is 14 bytes, this makes the + * payload word-aligned. + * + * Instead of calling skb_reserve(NET_IP_ALIGN), we just copy + * the two padding bytes into the skb so that we avoid hitting + * the slowpath in memcpy(), and pull them off afterwards. + */ + skb = netdev_alloc_skb(bp->dev, len + NET_IP_ALIGN); + if (!skb) { + bp->dev->stats.rx_dropped++; + for (frag = first_frag; ; frag++) { + desc = macb_rx_desc(bp, frag); + desc->addr &= ~MACB_BIT(RX_USED); + if (frag == last_frag) + break; + } + + /* Make descriptor updates visible to hardware */ + wmb(); + + return 1; + } + + offset = 0; + len += NET_IP_ALIGN; + skb_checksum_none_assert(skb); + skb_put(skb, len); + + for (frag = first_frag; ; frag++) { + unsigned int frag_len = bp->rx_buffer_size; + + if (offset + frag_len > len) { + if (unlikely(frag != last_frag)) { + dev_kfree_skb_any(skb); + return -1; + } + frag_len = len - offset; + } + skb_copy_to_linear_data_offset(skb, offset, + macb_rx_buffer(bp, frag), + frag_len); + offset += bp->rx_buffer_size; + desc = macb_rx_desc(bp, frag); + desc->addr &= ~MACB_BIT(RX_USED); + + if (frag == last_frag) + break; + } + + /* Make descriptor updates visible to hardware */ + wmb(); + + __skb_pull(skb, NET_IP_ALIGN); + skb->protocol = eth_type_trans(skb, bp->dev); + + bp->dev->stats.rx_packets++; + bp->dev->stats.rx_bytes += skb->len; + netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n", + skb->len, skb->csum); + netif_receive_skb(skb); + + return 0; +} + +static inline void macb_init_rx_ring(struct macb *bp) +{ + dma_addr_t addr; + struct macb_dma_desc *desc = NULL; + int i; + + addr = bp->rx_buffers_dma; + for (i = 0; i < bp->rx_ring_size; i++) { + desc = macb_rx_desc(bp, i); + macb_set_addr(bp, desc, addr); + desc->ctrl = 0; + addr += bp->rx_buffer_size; + } + desc->addr |= MACB_BIT(RX_WRAP); + bp->rx_tail = 0; +} + +static int macb_rx(struct macb *bp, int budget) +{ + bool reset_rx_queue = false; + int received = 0; + unsigned int tail; + int first_frag = -1; + + for (tail = bp->rx_tail; budget > 0; tail++) { + struct macb_dma_desc *desc = macb_rx_desc(bp, tail); + u32 ctrl; + + /* Make hw descriptor updates visible to CPU */ + rmb(); + + ctrl = desc->ctrl; + + if (!(desc->addr & MACB_BIT(RX_USED))) + break; + + if (ctrl & MACB_BIT(RX_SOF)) { + if (first_frag != -1) + discard_partial_frame(bp, first_frag, tail); + first_frag = tail; + } + + if (ctrl & MACB_BIT(RX_EOF)) { + int dropped; + + if (unlikely(first_frag == -1)) { + reset_rx_queue = true; + continue; + } + + dropped = macb_rx_frame(bp, first_frag, tail); + first_frag = -1; + if (unlikely(dropped < 0)) { + reset_rx_queue = true; + continue; + } + if (!dropped) { + received++; + budget--; + } + } + } + + if (unlikely(reset_rx_queue)) { + unsigned long flags; + u32 ctrl; + + netdev_err(bp->dev, "RX queue corruption: reset it\n"); + + spin_lock_irqsave(&bp->lock, flags); + + ctrl = macb_readl(bp, NCR); + macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE)); + + macb_init_rx_ring(bp); + macb_writel(bp, RBQP, bp->rx_ring_dma); + + macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); + + spin_unlock_irqrestore(&bp->lock, flags); + return received; + } + + if (first_frag != -1) + bp->rx_tail = first_frag; + else + bp->rx_tail = tail; + + return received; +} + +static int macb_poll(struct napi_struct *napi, int budget) +{ + struct macb *bp = container_of(napi, struct macb, napi); + int work_done; + u32 status; + + status = macb_readl(bp, RSR); + macb_writel(bp, RSR, status); + + work_done = 0; + + netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n", + (unsigned long)status, budget); + + work_done = bp->macbgem_ops.mog_rx(bp, budget); + if (work_done < budget) { + napi_complete_done(napi, work_done); + + /* Packets received while interrupts were disabled */ + status = macb_readl(bp, RSR); + if (status) { + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + macb_writel(bp, ISR, MACB_BIT(RCOMP)); + napi_reschedule(napi); + } else { + macb_writel(bp, IER, MACB_RX_INT_FLAGS); + } + } + + /* TODO: Handle errors */ + + return work_done; +} + +static irqreturn_t macb_interrupt(int irq, void *dev_id) +{ + struct macb_queue *queue = dev_id; + struct macb *bp = queue->bp; + struct net_device *dev = bp->dev; + u32 status, ctrl; + + status = queue_readl(queue, ISR); + + if (unlikely(!status)) + return IRQ_NONE; + + spin_lock(&bp->lock); + + while (status) { + /* close possible race with dev_close */ + if (unlikely(!netif_running(dev))) { + queue_writel(queue, IDR, -1); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, -1); + break; + } + + netdev_vdbg(bp->dev, "queue = %u, isr = 0x%08lx\n", + (unsigned int)(queue - bp->queues), + (unsigned long)status); + + if (status & MACB_RX_INT_FLAGS) { + /* There's no point taking any more interrupts + * until we have processed the buffers. The + * scheduling call may fail if the poll routine + * is already scheduled, so disable interrupts + * now. + */ + queue_writel(queue, IDR, MACB_RX_INT_FLAGS); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, MACB_BIT(RCOMP)); + + if (napi_schedule_prep(&bp->napi)) { + netdev_vdbg(bp->dev, "scheduling RX softirq\n"); + __napi_schedule(&bp->napi); + } + } + + if (unlikely(status & (MACB_TX_ERR_FLAGS))) { + queue_writel(queue, IDR, MACB_TX_INT_FLAGS); + schedule_work(&queue->tx_error_task); + + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, MACB_TX_ERR_FLAGS); + + break; + } + + if (status & MACB_BIT(TCOMP)) + macb_tx_interrupt(queue); + + /* Link change detection isn't possible with RMII, so we'll + * add that if/when we get our hands on a full-blown MII PHY. + */ + + /* There is a hardware issue under heavy load where DMA can + * stop, this causes endless "used buffer descriptor read" + * interrupts but it can be cleared by re-enabling RX. See + * the at91 manual, section 41.3.1 or the Zynq manual + * section 16.7.4 for details. + */ + if (status & MACB_BIT(RXUBR)) { + ctrl = macb_readl(bp, NCR); + macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE)); + wmb(); + macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); + + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, MACB_BIT(RXUBR)); + } + + if (status & MACB_BIT(ISR_ROVR)) { + /* We missed at least one packet */ + if (macb_is_gem(bp)) + bp->hw_stats.gem.rx_overruns++; + else + bp->hw_stats.macb.rx_overruns++; + + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, MACB_BIT(ISR_ROVR)); + } + + if (status & MACB_BIT(HRESP)) { + /* TODO: Reset the hardware, and maybe move the + * netdev_err to a lower-priority context as well + * (work queue?) + */ + netdev_err(dev, "DMA bus error: HRESP not OK\n"); + + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, MACB_BIT(HRESP)); + } + + status = queue_readl(queue, ISR); + } + + spin_unlock(&bp->lock); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* Polling receive - used by netconsole and other diagnostic tools + * to allow network i/o with interrupts disabled. + */ +static void macb_poll_controller(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + struct macb_queue *queue; + unsigned long flags; + unsigned int q; + + local_irq_save(flags); + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) + macb_interrupt(dev->irq, queue); + local_irq_restore(flags); +} +#endif + +static unsigned int macb_tx_map(struct macb *bp, + struct macb_queue *queue, + struct sk_buff *skb, + unsigned int hdrlen) +{ + dma_addr_t mapping; + unsigned int len, entry, i, tx_head = queue->tx_head; + struct macb_tx_skb *tx_skb = NULL; + struct macb_dma_desc *desc; + unsigned int offset, size, count = 0; + unsigned int f, nr_frags = skb_shinfo(skb)->nr_frags; + unsigned int eof = 1, mss_mfs = 0; + u32 ctrl, lso_ctrl = 0, seq_ctrl = 0; + + /* LSO */ + if (skb_shinfo(skb)->gso_size != 0) { + if (ip_hdr(skb)->protocol == IPPROTO_UDP) + /* UDP - UFO */ + lso_ctrl = MACB_LSO_UFO_ENABLE; + else + /* TCP - TSO */ + lso_ctrl = MACB_LSO_TSO_ENABLE; + } + + /* First, map non-paged data */ + len = skb_headlen(skb); + + /* first buffer length */ + size = hdrlen; + + offset = 0; + while (len) { + entry = macb_tx_ring_wrap(bp, tx_head); + tx_skb = &queue->tx_skb[entry]; + + mapping = dma_map_single(&bp->pdev->dev, + skb->data + offset, + size, DMA_TO_DEVICE); + if (dma_mapping_error(&bp->pdev->dev, mapping)) + goto dma_error; + + /* Save info to properly release resources */ + tx_skb->skb = NULL; + tx_skb->mapping = mapping; + tx_skb->size = size; + tx_skb->mapped_as_page = false; + + len -= size; + offset += size; + count++; + tx_head++; + + size = min(len, bp->max_tx_length); + } + + /* Then, map paged data from fragments */ + for (f = 0; f < nr_frags; f++) { + const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; + + len = skb_frag_size(frag); + offset = 0; + while (len) { + size = min(len, bp->max_tx_length); + entry = macb_tx_ring_wrap(bp, tx_head); + tx_skb = &queue->tx_skb[entry]; + + mapping = skb_frag_dma_map(&bp->pdev->dev, frag, + offset, size, DMA_TO_DEVICE); + if (dma_mapping_error(&bp->pdev->dev, mapping)) + goto dma_error; + + /* Save info to properly release resources */ + tx_skb->skb = NULL; + tx_skb->mapping = mapping; + tx_skb->size = size; + tx_skb->mapped_as_page = true; + + len -= size; + offset += size; + count++; + tx_head++; + } + } + + /* Should never happen */ + if (unlikely(!tx_skb)) { + netdev_err(bp->dev, "BUG! empty skb!\n"); + return 0; + } + + /* This is the last buffer of the frame: save socket buffer */ + tx_skb->skb = skb; + + /* Update TX ring: update buffer descriptors in reverse order + * to avoid race condition + */ + + /* Set 'TX_USED' bit in buffer descriptor at tx_head position + * to set the end of TX queue + */ + i = tx_head; + entry = macb_tx_ring_wrap(bp, i); + ctrl = MACB_BIT(TX_USED); + desc = macb_tx_desc(queue, entry); + desc->ctrl = ctrl; + + if (lso_ctrl) { + if (lso_ctrl == MACB_LSO_UFO_ENABLE) + /* include header and FCS in value given to h/w */ + mss_mfs = skb_shinfo(skb)->gso_size + + skb_transport_offset(skb) + + ETH_FCS_LEN; + else /* TSO */ { + mss_mfs = skb_shinfo(skb)->gso_size; + /* TCP Sequence Number Source Select + * can be set only for TSO + */ + seq_ctrl = 0; + } + } + + do { + i--; + entry = macb_tx_ring_wrap(bp, i); + tx_skb = &queue->tx_skb[entry]; + desc = macb_tx_desc(queue, entry); + + ctrl = (u32)tx_skb->size; + if (eof) { + ctrl |= MACB_BIT(TX_LAST); + eof = 0; + } + if (unlikely(entry == (bp->tx_ring_size - 1))) + ctrl |= MACB_BIT(TX_WRAP); + + /* First descriptor is header descriptor */ + if (i == queue->tx_head) { + ctrl |= MACB_BF(TX_LSO, lso_ctrl); + ctrl |= MACB_BF(TX_TCP_SEQ_SRC, seq_ctrl); + } else + /* Only set MSS/MFS on payload descriptors + * (second or later descriptor) + */ + ctrl |= MACB_BF(MSS_MFS, mss_mfs); + + /* Set TX buffer descriptor */ + macb_set_addr(bp, desc, tx_skb->mapping); + /* desc->addr must be visible to hardware before clearing + * 'TX_USED' bit in desc->ctrl. + */ + wmb(); + desc->ctrl = ctrl; + } while (i != queue->tx_head); + + queue->tx_head = tx_head; + + return count; + +dma_error: + netdev_err(bp->dev, "TX DMA map failed\n"); + + for (i = queue->tx_head; i != tx_head; i++) { + tx_skb = macb_tx_skb(queue, i); + + macb_tx_unmap(bp, tx_skb); + } + + return 0; +} + +static netdev_features_t macb_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + unsigned int nr_frags, f; + unsigned int hdrlen; + + /* Validate LSO compatibility */ + + /* there is only one buffer */ + if (!skb_is_nonlinear(skb)) + return features; + + /* length of header */ + hdrlen = skb_transport_offset(skb); + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + hdrlen += tcp_hdrlen(skb); + + /* For LSO: + * When software supplies two or more payload buffers all payload buffers + * apart from the last must be a multiple of 8 bytes in size. + */ + if (!IS_ALIGNED(skb_headlen(skb) - hdrlen, MACB_TX_LEN_ALIGN)) + return features & ~MACB_NETIF_LSO; + + nr_frags = skb_shinfo(skb)->nr_frags; + /* No need to check last fragment */ + nr_frags--; + for (f = 0; f < nr_frags; f++) { + const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; + + if (!IS_ALIGNED(skb_frag_size(frag), MACB_TX_LEN_ALIGN)) + return features & ~MACB_NETIF_LSO; + } + return features; +} + +static inline int macb_clear_csum(struct sk_buff *skb) +{ + /* no change for packets without checksum offloading */ + if (skb->ip_summed != CHECKSUM_PARTIAL) + return 0; + + /* make sure we can modify the header */ + if (unlikely(skb_cow_head(skb, 0))) + return -1; + + /* initialize checksum field + * This is required - at least for Zynq, which otherwise calculates + * wrong UDP header checksums for UDP packets with UDP data len <=2 + */ + *(__sum16 *)(skb_checksum_start(skb) + skb->csum_offset) = 0; + return 0; +} + +static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + u16 queue_index = skb_get_queue_mapping(skb); + struct macb *bp = netdev_priv(dev); + struct macb_queue *queue = &bp->queues[queue_index]; + unsigned long flags; + unsigned int desc_cnt, nr_frags, frag_size, f; + unsigned int hdrlen; + bool is_lso, is_udp = 0; + + is_lso = (skb_shinfo(skb)->gso_size != 0); + + if (is_lso) { + is_udp = !!(ip_hdr(skb)->protocol == IPPROTO_UDP); + + /* length of headers */ + if (is_udp) + /* only queue eth + ip headers separately for UDP */ + hdrlen = skb_transport_offset(skb); + else + hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb); + if (skb_headlen(skb) < hdrlen) { + netdev_err(bp->dev, "Error - LSO headers fragmented!!!\n"); + /* if this is required, would need to copy to single buffer */ + return NETDEV_TX_BUSY; + } + } else + hdrlen = min(skb_headlen(skb), bp->max_tx_length); + +#if defined(DEBUG) && defined(VERBOSE_DEBUG) + netdev_vdbg(bp->dev, + "start_xmit: queue %hu len %u head %p data %p tail %p end %p\n", + queue_index, skb->len, skb->head, skb->data, + skb_tail_pointer(skb), skb_end_pointer(skb)); + print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1, + skb->data, 16, true); +#endif + + /* Count how many TX buffer descriptors are needed to send this + * socket buffer: skb fragments of jumbo frames may need to be + * split into many buffer descriptors. + */ + if (is_lso && (skb_headlen(skb) > hdrlen)) + /* extra header descriptor if also payload in first buffer */ + desc_cnt = DIV_ROUND_UP((skb_headlen(skb) - hdrlen), bp->max_tx_length) + 1; + else + desc_cnt = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length); + nr_frags = skb_shinfo(skb)->nr_frags; + for (f = 0; f < nr_frags; f++) { + frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]); + desc_cnt += DIV_ROUND_UP(frag_size, bp->max_tx_length); + } + + spin_lock_irqsave(&bp->lock, flags); + + /* This is a hard error, log it. */ + if (CIRC_SPACE(queue->tx_head, queue->tx_tail, + bp->tx_ring_size) < desc_cnt) { + netif_stop_subqueue(dev, queue_index); + spin_unlock_irqrestore(&bp->lock, flags); + netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n", + queue->tx_head, queue->tx_tail); + return NETDEV_TX_BUSY; + } + + if (macb_clear_csum(skb)) { + dev_kfree_skb_any(skb); + goto unlock; + } + + /* Map socket buffer for DMA transfer */ + if (!macb_tx_map(bp, queue, skb, hdrlen)) { + dev_kfree_skb_any(skb); + goto unlock; + } + + /* Make newly initialized descriptor visible to hardware */ + wmb(); + + skb_tx_timestamp(skb); + + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); + + if (CIRC_SPACE(queue->tx_head, queue->tx_tail, bp->tx_ring_size) < 1) + netif_stop_subqueue(dev, queue_index); + +unlock: + spin_unlock_irqrestore(&bp->lock, flags); + + return NETDEV_TX_OK; +} + +static void macb_init_rx_buffer_size(struct macb *bp, size_t size) +{ + if (!macb_is_gem(bp)) { + bp->rx_buffer_size = MACB_RX_BUFFER_SIZE; + } else { + bp->rx_buffer_size = size; + + if (bp->rx_buffer_size % RX_BUFFER_MULTIPLE) { + netdev_dbg(bp->dev, + "RX buffer must be multiple of %d bytes, expanding\n", + RX_BUFFER_MULTIPLE); + bp->rx_buffer_size = + roundup(bp->rx_buffer_size, RX_BUFFER_MULTIPLE); + } + } + + netdev_dbg(bp->dev, "mtu [%u] rx_buffer_size [%zu]\n", + bp->dev->mtu, bp->rx_buffer_size); +} + +static void gem_free_rx_buffers(struct macb *bp) +{ + struct sk_buff *skb; + struct macb_dma_desc *desc; + dma_addr_t addr; + int i; + + if (!bp->rx_skbuff) + return; + + for (i = 0; i < bp->rx_ring_size; i++) { + skb = bp->rx_skbuff[i]; + + if (!skb) + continue; + + desc = macb_rx_desc(bp, i); + addr = macb_get_addr(bp, desc); + + dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size, + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + skb = NULL; + } + + kfree(bp->rx_skbuff); + bp->rx_skbuff = NULL; +} + +static void macb_free_rx_buffers(struct macb *bp) +{ + if (bp->rx_buffers) { + dma_free_coherent(&bp->pdev->dev, + bp->rx_ring_size * bp->rx_buffer_size, + bp->rx_buffers, bp->rx_buffers_dma); + bp->rx_buffers = NULL; + } +} + +static void macb_free_consistent(struct macb *bp) +{ + struct macb_queue *queue; + unsigned int q; + + bp->macbgem_ops.mog_free_rx_buffers(bp); + if (bp->rx_ring) { + dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES(bp), + bp->rx_ring, bp->rx_ring_dma); + bp->rx_ring = NULL; + } + + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + kfree(queue->tx_skb); + queue->tx_skb = NULL; + if (queue->tx_ring) { + dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES(bp), + queue->tx_ring, queue->tx_ring_dma); + queue->tx_ring = NULL; + } + } +} + +static int gem_alloc_rx_buffers(struct macb *bp) +{ + int size; + + size = bp->rx_ring_size * sizeof(struct sk_buff *); + bp->rx_skbuff = kzalloc(size, GFP_KERNEL); + if (!bp->rx_skbuff) + return -ENOMEM; + else + netdev_dbg(bp->dev, + "Allocated %d RX struct sk_buff entries at %p\n", + bp->rx_ring_size, bp->rx_skbuff); + return 0; +} + +static int macb_alloc_rx_buffers(struct macb *bp) +{ + int size; + + size = bp->rx_ring_size * bp->rx_buffer_size; + bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size, + &bp->rx_buffers_dma, GFP_KERNEL); + if (!bp->rx_buffers) + return -ENOMEM; + + netdev_dbg(bp->dev, + "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n", + size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers); + return 0; +} + +static int macb_alloc_consistent(struct macb *bp) +{ + struct macb_queue *queue; + unsigned int q; + int size; + + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + size = TX_RING_BYTES(bp); + queue->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size, + &queue->tx_ring_dma, + GFP_KERNEL); + if (!queue->tx_ring) + goto out_err; + netdev_dbg(bp->dev, + "Allocated TX ring for queue %u of %d bytes at %08lx (mapped %p)\n", + q, size, (unsigned long)queue->tx_ring_dma, + queue->tx_ring); + + size = bp->tx_ring_size * sizeof(struct macb_tx_skb); + queue->tx_skb = kmalloc(size, GFP_KERNEL); + if (!queue->tx_skb) + goto out_err; + } + + size = RX_RING_BYTES(bp); + bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size, + &bp->rx_ring_dma, GFP_KERNEL); + if (!bp->rx_ring) + goto out_err; + netdev_dbg(bp->dev, + "Allocated RX ring of %d bytes at %08lx (mapped %p)\n", + size, (unsigned long)bp->rx_ring_dma, bp->rx_ring); + + if (bp->macbgem_ops.mog_alloc_rx_buffers(bp)) + goto out_err; + + return 0; + +out_err: + macb_free_consistent(bp); + return -ENOMEM; +} + +static void gem_init_rings(struct macb *bp) +{ + struct macb_queue *queue; + struct macb_dma_desc *desc = NULL; + unsigned int q; + int i; + + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + for (i = 0; i < bp->tx_ring_size; i++) { + desc = macb_tx_desc(queue, i); + macb_set_addr(bp, desc, 0); + desc->ctrl = MACB_BIT(TX_USED); + } + desc->ctrl |= MACB_BIT(TX_WRAP); + queue->tx_head = 0; + queue->tx_tail = 0; + } + + bp->rx_tail = 0; + bp->rx_prepared_head = 0; + + gem_rx_refill(bp); +} + +static void macb_init_rings(struct macb *bp) +{ + int i; + struct macb_dma_desc *desc = NULL; + + macb_init_rx_ring(bp); + + for (i = 0; i < bp->tx_ring_size; i++) { + desc = macb_tx_desc(&bp->queues[0], i); + macb_set_addr(bp, desc, 0); + desc->ctrl = MACB_BIT(TX_USED); + } + bp->queues[0].tx_head = 0; + bp->queues[0].tx_tail = 0; + desc->ctrl |= MACB_BIT(TX_WRAP); +} + +static void macb_reset_hw(struct macb *bp) +{ + struct macb_queue *queue; + unsigned int q; + + /* Disable RX and TX (XXX: Should we halt the transmission + * more gracefully?) + */ + macb_writel(bp, NCR, 0); + + /* Clear the stats registers (XXX: Update stats first?) */ + macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); + + /* Clear all status flags */ + macb_writel(bp, TSR, -1); + macb_writel(bp, RSR, -1); + + /* Disable all interrupts */ + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + queue_writel(queue, IDR, -1); + queue_readl(queue, ISR); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, -1); + } +} + +static u32 gem_mdc_clk_div(struct macb *bp) +{ + u32 config; + unsigned long pclk_hz = clk_get_rate(bp->pclk); + + if (pclk_hz <= 20000000) + config = GEM_BF(CLK, GEM_CLK_DIV8); + else if (pclk_hz <= 40000000) + config = GEM_BF(CLK, GEM_CLK_DIV16); + else if (pclk_hz <= 80000000) + config = GEM_BF(CLK, GEM_CLK_DIV32); + else if (pclk_hz <= 120000000) + config = GEM_BF(CLK, GEM_CLK_DIV48); + else if (pclk_hz <= 160000000) + config = GEM_BF(CLK, GEM_CLK_DIV64); + else + config = GEM_BF(CLK, GEM_CLK_DIV96); + + return config; +} + +static u32 macb_mdc_clk_div(struct macb *bp) +{ + u32 config; + unsigned long pclk_hz; + + if (macb_is_gem(bp)) + return gem_mdc_clk_div(bp); + + pclk_hz = clk_get_rate(bp->pclk); + if (pclk_hz <= 20000000) + config = MACB_BF(CLK, MACB_CLK_DIV8); + else if (pclk_hz <= 40000000) + config = MACB_BF(CLK, MACB_CLK_DIV16); + else if (pclk_hz <= 80000000) + config = MACB_BF(CLK, MACB_CLK_DIV32); + else + config = MACB_BF(CLK, MACB_CLK_DIV64); + + return config; +} + +/* Get the DMA bus width field of the network configuration register that we + * should program. We find the width from decoding the design configuration + * register to find the maximum supported data bus width. + */ +static u32 macb_dbw(struct macb *bp) +{ + if (!macb_is_gem(bp)) + return 0; + + switch (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1))) { + case 4: + return GEM_BF(DBW, GEM_DBW128); + case 2: + return GEM_BF(DBW, GEM_DBW64); + case 1: + default: + return GEM_BF(DBW, GEM_DBW32); + } +} + +/* Configure the receive DMA engine + * - use the correct receive buffer size + * - set best burst length for DMA operations + * (if not supported by FIFO, it will fallback to default) + * - set both rx/tx packet buffers to full memory size + * These are configurable parameters for GEM. + */ +static void macb_configure_dma(struct macb *bp) +{ + u32 dmacfg; + + if (macb_is_gem(bp)) { + dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L); + dmacfg |= GEM_BF(RXBS, bp->rx_buffer_size / RX_BUFFER_MULTIPLE); + if (bp->dma_burst_length) + dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg); + dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L); + dmacfg &= ~GEM_BIT(ENDIA_PKT); + + if (bp->native_io) + dmacfg &= ~GEM_BIT(ENDIA_DESC); + else + dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */ + + if (bp->dev->features & NETIF_F_HW_CSUM) + dmacfg |= GEM_BIT(TXCOEN); + else + dmacfg &= ~GEM_BIT(TXCOEN); + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + dmacfg |= GEM_BIT(ADDR64); +#endif +#ifdef CONFIG_MACB_USE_HWSTAMP + if (bp->hw_dma_cap & HW_DMA_CAP_PTP) + dmacfg |= GEM_BIT(RXEXT) | GEM_BIT(TXEXT); +#endif + netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n", + dmacfg); + gem_writel(bp, DMACFG, dmacfg); + } +} + +static void macb_init_hw(struct macb *bp) +{ + struct macb_queue *queue; + unsigned int q; + + u32 config; + + macb_reset_hw(bp); + macb_set_hwaddr(bp); + + config = macb_mdc_clk_div(bp); + if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) + config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); + config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ + config |= MACB_BIT(PAE); /* PAuse Enable */ + config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ + if (bp->caps & MACB_CAPS_JUMBO) + config |= MACB_BIT(JFRAME); /* Enable jumbo frames */ + else + config |= MACB_BIT(BIG); /* Receive oversized frames */ + if (bp->dev->flags & IFF_PROMISC) + config |= MACB_BIT(CAF); /* Copy All Frames */ + else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM) + config |= GEM_BIT(RXCOEN); + if (!(bp->dev->flags & IFF_BROADCAST)) + config |= MACB_BIT(NBC); /* No BroadCast */ + config |= macb_dbw(bp); + macb_writel(bp, NCFGR, config); + if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len) + gem_writel(bp, JML, bp->jumbo_max_len); + bp->speed = SPEED_10; + bp->duplex = DUPLEX_HALF; + bp->rx_frm_len_mask = MACB_RX_FRMLEN_MASK; + if (bp->caps & MACB_CAPS_JUMBO) + bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; + + macb_configure_dma(bp); + + /* Initialize TX and RX buffers */ + macb_writel(bp, RBQP, lower_32_bits(bp->rx_ring_dma)); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + macb_writel(bp, RBQPH, upper_32_bits(bp->rx_ring_dma)); +#endif + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); +#endif + + /* Enable interrupts */ + queue_writel(queue, IER, + MACB_RX_INT_FLAGS | + MACB_TX_INT_FLAGS | + MACB_BIT(HRESP)); + } + + /* Enable TX and RX */ + macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE)); +} + +/* The hash address register is 64 bits long and takes up two + * locations in the memory map. The least significant bits are stored + * in EMAC_HSL and the most significant bits in EMAC_HSH. + * + * The unicast hash enable and the multicast hash enable bits in the + * network configuration register enable the reception of hash matched + * frames. The destination address is reduced to a 6 bit index into + * the 64 bit hash register using the following hash function. The + * hash function is an exclusive or of every sixth bit of the + * destination address. + * + * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] + * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] + * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] + * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] + * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] + * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] + * + * da[0] represents the least significant bit of the first byte + * received, that is, the multicast/unicast indicator, and da[47] + * represents the most significant bit of the last byte received. If + * the hash index, hi[n], points to a bit that is set in the hash + * register then the frame will be matched according to whether the + * frame is multicast or unicast. A multicast match will be signalled + * if the multicast hash enable bit is set, da[0] is 1 and the hash + * index points to a bit set in the hash register. A unicast match + * will be signalled if the unicast hash enable bit is set, da[0] is 0 + * and the hash index points to a bit set in the hash register. To + * receive all multicast frames, the hash register should be set with + * all ones and the multicast hash enable bit should be set in the + * network configuration register. + */ + +static inline int hash_bit_value(int bitnr, __u8 *addr) +{ + if (addr[bitnr / 8] & (1 << (bitnr % 8))) + return 1; + return 0; +} + +/* Return the hash index value for the specified address. */ +static int hash_get_index(__u8 *addr) +{ + int i, j, bitval; + int hash_index = 0; + + for (j = 0; j < 6; j++) { + for (i = 0, bitval = 0; i < 8; i++) + bitval ^= hash_bit_value(i * 6 + j, addr); + + hash_index |= (bitval << j); + } + + return hash_index; +} + +/* Add multicast addresses to the internal multicast-hash table. */ +static void macb_sethashtable(struct net_device *dev) +{ + struct netdev_hw_addr *ha; + unsigned long mc_filter[2]; + unsigned int bitnr; + struct macb *bp = netdev_priv(dev); + + mc_filter[0] = 0; + mc_filter[1] = 0; + + netdev_for_each_mc_addr(ha, dev) { + bitnr = hash_get_index(ha->addr); + mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); + } + + macb_or_gem_writel(bp, HRB, mc_filter[0]); + macb_or_gem_writel(bp, HRT, mc_filter[1]); +} + +/* Enable/Disable promiscuous and multicast modes. */ +static void macb_set_rx_mode(struct net_device *dev) +{ + unsigned long cfg; + struct macb *bp = netdev_priv(dev); + + cfg = macb_readl(bp, NCFGR); + + if (dev->flags & IFF_PROMISC) { + /* Enable promiscuous mode */ + cfg |= MACB_BIT(CAF); + + /* Disable RX checksum offload */ + if (macb_is_gem(bp)) + cfg &= ~GEM_BIT(RXCOEN); + } else { + /* Disable promiscuous mode */ + cfg &= ~MACB_BIT(CAF); + + /* Enable RX checksum offload only if requested */ + if (macb_is_gem(bp) && dev->features & NETIF_F_RXCSUM) + cfg |= GEM_BIT(RXCOEN); + } + + if (dev->flags & IFF_ALLMULTI) { + /* Enable all multicast mode */ + macb_or_gem_writel(bp, HRB, -1); + macb_or_gem_writel(bp, HRT, -1); + cfg |= MACB_BIT(NCFGR_MTI); + } else if (!netdev_mc_empty(dev)) { + /* Enable specific multicasts */ + macb_sethashtable(dev); + cfg |= MACB_BIT(NCFGR_MTI); + } else if (dev->flags & (~IFF_ALLMULTI)) { + /* Disable all multicast mode */ + macb_or_gem_writel(bp, HRB, 0); + macb_or_gem_writel(bp, HRT, 0); + cfg &= ~MACB_BIT(NCFGR_MTI); + } + + macb_writel(bp, NCFGR, cfg); +} + +static int macb_open(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + size_t bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN; + int err; + + netdev_dbg(bp->dev, "open\n"); + + /* carrier starts down */ + netif_carrier_off(dev); + + /* if the phy is not yet register, retry later*/ + if (!dev->phydev) + return -EAGAIN; + + /* RX buffers initialization */ + macb_init_rx_buffer_size(bp, bufsz); + + err = macb_alloc_consistent(bp); + if (err) { + netdev_err(dev, "Unable to allocate DMA memory (error %d)\n", + err); + return err; + } + + napi_enable(&bp->napi); + + bp->macbgem_ops.mog_init_rings(bp); + macb_init_hw(bp); + + /* schedule a link state check */ + phy_start(dev->phydev); + + netif_tx_start_all_queues(dev); + + if (bp->ptp_info) + bp->ptp_info->ptp_init(dev); + + return 0; +} + +static int macb_close(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + unsigned long flags; + + netif_tx_stop_all_queues(dev); + napi_disable(&bp->napi); + + if (dev->phydev) + phy_stop(dev->phydev); + + spin_lock_irqsave(&bp->lock, flags); + macb_reset_hw(bp); + netif_carrier_off(dev); + spin_unlock_irqrestore(&bp->lock, flags); + + macb_free_consistent(bp); + + if (bp->ptp_info) + bp->ptp_info->ptp_remove(dev); + + return 0; +} + +static int macb_change_mtu(struct net_device *dev, int new_mtu) +{ + if (netif_running(dev)) + return -EBUSY; + + dev->mtu = new_mtu; + + return 0; +} + +static void gem_update_stats(struct macb *bp) +{ + unsigned int i; + u32 *p = &bp->hw_stats.gem.tx_octets_31_0; + + for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { + u32 offset = gem_statistics[i].offset; + u64 val = bp->macb_reg_readl(bp, offset); + + bp->ethtool_stats[i] += val; + *p += val; + + if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) { + /* Add GEM_OCTTXH, GEM_OCTRXH */ + val = bp->macb_reg_readl(bp, offset + 4); + bp->ethtool_stats[i] += ((u64)val) << 32; + *(++p) += val; + } + } +} + +static struct net_device_stats *gem_get_stats(struct macb *bp) +{ + struct gem_stats *hwstat = &bp->hw_stats.gem; + struct net_device_stats *nstat = &bp->dev->stats; + + gem_update_stats(bp); + + nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors + + hwstat->rx_alignment_errors + + hwstat->rx_resource_errors + + hwstat->rx_overruns + + hwstat->rx_oversize_frames + + hwstat->rx_jabbers + + hwstat->rx_undersized_frames + + hwstat->rx_length_field_frame_errors); + nstat->tx_errors = (hwstat->tx_late_collisions + + hwstat->tx_excessive_collisions + + hwstat->tx_underrun + + hwstat->tx_carrier_sense_errors); + nstat->multicast = hwstat->rx_multicast_frames; + nstat->collisions = (hwstat->tx_single_collision_frames + + hwstat->tx_multiple_collision_frames + + hwstat->tx_excessive_collisions); + nstat->rx_length_errors = (hwstat->rx_oversize_frames + + hwstat->rx_jabbers + + hwstat->rx_undersized_frames + + hwstat->rx_length_field_frame_errors); + nstat->rx_over_errors = hwstat->rx_resource_errors; + nstat->rx_crc_errors = hwstat->rx_frame_check_sequence_errors; + nstat->rx_frame_errors = hwstat->rx_alignment_errors; + nstat->rx_fifo_errors = hwstat->rx_overruns; + nstat->tx_aborted_errors = hwstat->tx_excessive_collisions; + nstat->tx_carrier_errors = hwstat->tx_carrier_sense_errors; + nstat->tx_fifo_errors = hwstat->tx_underrun; + + return nstat; +} + +static void gem_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct macb *bp; + + bp = netdev_priv(dev); + gem_update_stats(bp); + memcpy(data, &bp->ethtool_stats, sizeof(u64) * GEM_STATS_LEN); +} + +static int gem_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return GEM_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) +{ + unsigned int i; + + switch (sset) { + case ETH_SS_STATS: + for (i = 0; i < GEM_STATS_LEN; i++, p += ETH_GSTRING_LEN) + memcpy(p, gem_statistics[i].stat_string, + ETH_GSTRING_LEN); + break; + } +} + +static struct net_device_stats *macb_get_stats(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + struct net_device_stats *nstat = &bp->dev->stats; + struct macb_stats *hwstat = &bp->hw_stats.macb; + + if (macb_is_gem(bp)) + return gem_get_stats(bp); + + /* read stats from hardware */ + macb_update_stats(bp); + + /* Convert HW stats into netdevice stats */ + nstat->rx_errors = (hwstat->rx_fcs_errors + + hwstat->rx_align_errors + + hwstat->rx_resource_errors + + hwstat->rx_overruns + + hwstat->rx_oversize_pkts + + hwstat->rx_jabbers + + hwstat->rx_undersize_pkts + + hwstat->rx_length_mismatch); + nstat->tx_errors = (hwstat->tx_late_cols + + hwstat->tx_excessive_cols + + hwstat->tx_underruns + + hwstat->tx_carrier_errors + + hwstat->sqe_test_errors); + nstat->collisions = (hwstat->tx_single_cols + + hwstat->tx_multiple_cols + + hwstat->tx_excessive_cols); + nstat->rx_length_errors = (hwstat->rx_oversize_pkts + + hwstat->rx_jabbers + + hwstat->rx_undersize_pkts + + hwstat->rx_length_mismatch); + nstat->rx_over_errors = hwstat->rx_resource_errors + + hwstat->rx_overruns; + nstat->rx_crc_errors = hwstat->rx_fcs_errors; + nstat->rx_frame_errors = hwstat->rx_align_errors; + nstat->rx_fifo_errors = hwstat->rx_overruns; + /* XXX: What does "missed" mean? */ + nstat->tx_aborted_errors = hwstat->tx_excessive_cols; + nstat->tx_carrier_errors = hwstat->tx_carrier_errors; + nstat->tx_fifo_errors = hwstat->tx_underruns; + /* Don't know about heartbeat or window errors... */ + + return nstat; +} + +static int macb_get_regs_len(struct net_device *netdev) +{ + return MACB_GREGS_NBR * sizeof(u32); +} + +static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *p) +{ + struct macb *bp = netdev_priv(dev); + unsigned int tail, head; + u32 *regs_buff = p; + + regs->version = (macb_readl(bp, MID) & ((1 << MACB_REV_SIZE) - 1)) + | MACB_GREGS_VERSION; + + tail = macb_tx_ring_wrap(bp, bp->queues[0].tx_tail); + head = macb_tx_ring_wrap(bp, bp->queues[0].tx_head); + + regs_buff[0] = macb_readl(bp, NCR); + regs_buff[1] = macb_or_gem_readl(bp, NCFGR); + regs_buff[2] = macb_readl(bp, NSR); + regs_buff[3] = macb_readl(bp, TSR); + regs_buff[4] = macb_readl(bp, RBQP); + regs_buff[5] = macb_readl(bp, TBQP); + regs_buff[6] = macb_readl(bp, RSR); + regs_buff[7] = macb_readl(bp, IMR); + + regs_buff[8] = tail; + regs_buff[9] = head; + regs_buff[10] = macb_tx_dma(&bp->queues[0], tail); + regs_buff[11] = macb_tx_dma(&bp->queues[0], head); + + if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) + regs_buff[12] = macb_or_gem_readl(bp, USRIO); + if (macb_is_gem(bp)) + regs_buff[13] = gem_readl(bp, DMACFG); +} + +static void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct macb *bp = netdev_priv(netdev); + + wol->supported = 0; + wol->wolopts = 0; + + if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) { + wol->supported = WAKE_MAGIC; + + if (bp->wol & MACB_WOL_ENABLED) + wol->wolopts |= WAKE_MAGIC; + } +} + +static int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct macb *bp = netdev_priv(netdev); + + if (!(bp->wol & MACB_WOL_HAS_MAGIC_PACKET) || + (wol->wolopts & ~WAKE_MAGIC)) + return -EOPNOTSUPP; + + if (wol->wolopts & WAKE_MAGIC) + bp->wol |= MACB_WOL_ENABLED; + else + bp->wol &= ~MACB_WOL_ENABLED; + + device_set_wakeup_enable(&bp->pdev->dev, bp->wol & MACB_WOL_ENABLED); + + return 0; +} + +static void macb_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct macb *bp = netdev_priv(netdev); + + ring->rx_max_pending = MAX_RX_RING_SIZE; + ring->tx_max_pending = MAX_TX_RING_SIZE; + + ring->rx_pending = bp->rx_ring_size; + ring->tx_pending = bp->tx_ring_size; +} + +static int macb_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct macb *bp = netdev_priv(netdev); + u32 new_rx_size, new_tx_size; + unsigned int reset = 0; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + new_rx_size = clamp_t(u32, ring->rx_pending, + MIN_RX_RING_SIZE, MAX_RX_RING_SIZE); + new_rx_size = roundup_pow_of_two(new_rx_size); + + new_tx_size = clamp_t(u32, ring->tx_pending, + MIN_TX_RING_SIZE, MAX_TX_RING_SIZE); + new_tx_size = roundup_pow_of_two(new_tx_size); + + if ((new_tx_size == bp->tx_ring_size) && + (new_rx_size == bp->rx_ring_size)) { + /* nothing to do */ + return 0; + } + + if (netif_running(bp->dev)) { + reset = 1; + macb_close(bp->dev); + } + + bp->rx_ring_size = new_rx_size; + bp->tx_ring_size = new_tx_size; + + if (reset) + macb_open(bp->dev); + + return 0; +} + +static int macb_get_ts_info(struct net_device *netdev, + struct ethtool_ts_info *info) +{ + struct macb *bp = netdev_priv(netdev); + + if (bp->ptp_info) + return bp->ptp_info->get_ts_info(netdev, info); + + return ethtool_op_get_ts_info(netdev, info); +} + +static const struct ethtool_ops macb_ethtool_ops = { + .get_regs_len = macb_get_regs_len, + .get_regs = macb_get_regs, + .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, + .get_wol = macb_get_wol, + .set_wol = macb_set_wol, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, + .get_ringparam = macb_get_ringparam, + .set_ringparam = macb_set_ringparam, +}; + +static const struct ethtool_ops gem_ethtool_ops = { + .get_regs_len = macb_get_regs_len, + .get_regs = macb_get_regs, + .get_link = ethtool_op_get_link, + .get_ts_info = macb_get_ts_info, + .get_ethtool_stats = gem_get_ethtool_stats, + .get_strings = gem_get_ethtool_strings, + .get_sset_count = gem_get_sset_count, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, + .get_ringparam = macb_get_ringparam, + .set_ringparam = macb_set_ringparam, +}; + +static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct phy_device *phydev = dev->phydev; + struct macb *bp = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + if (!phydev) + return -ENODEV; + + if (!bp->ptp_info) + return phy_mii_ioctl(phydev, rq, cmd); + + switch (cmd) { + case SIOCSHWTSTAMP: + return bp->ptp_info->set_hwtst(dev, rq, cmd); + case SIOCGHWTSTAMP: + return bp->ptp_info->get_hwtst(dev, rq); + default: + return phy_mii_ioctl(phydev, rq, cmd); + } +} + +static int macb_set_features(struct net_device *netdev, + netdev_features_t features) +{ + struct macb *bp = netdev_priv(netdev); + netdev_features_t changed = features ^ netdev->features; + + /* TX checksum offload */ + if ((changed & NETIF_F_HW_CSUM) && macb_is_gem(bp)) { + u32 dmacfg; + + dmacfg = gem_readl(bp, DMACFG); + if (features & NETIF_F_HW_CSUM) + dmacfg |= GEM_BIT(TXCOEN); + else + dmacfg &= ~GEM_BIT(TXCOEN); + gem_writel(bp, DMACFG, dmacfg); + } + + /* RX checksum offload */ + if ((changed & NETIF_F_RXCSUM) && macb_is_gem(bp)) { + u32 netcfg; + + netcfg = gem_readl(bp, NCFGR); + if (features & NETIF_F_RXCSUM && + !(netdev->flags & IFF_PROMISC)) + netcfg |= GEM_BIT(RXCOEN); + else + netcfg &= ~GEM_BIT(RXCOEN); + gem_writel(bp, NCFGR, netcfg); + } + + return 0; +} + +static const struct net_device_ops macb_netdev_ops = { + .ndo_open = macb_open, + .ndo_stop = macb_close, + .ndo_start_xmit = macb_start_xmit, + .ndo_set_rx_mode = macb_set_rx_mode, + .ndo_get_stats = macb_get_stats, + .ndo_do_ioctl = macb_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = macb_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = macb_poll_controller, +#endif + .ndo_set_features = macb_set_features, + .ndo_features_check = macb_features_check, +}; + +/* Configure peripheral capabilities according to device tree + * and integration options used + */ +static void macb_configure_caps(struct macb *bp, + const struct macb_config *dt_conf) +{ + u32 dcfg; + + if (dt_conf) + bp->caps = dt_conf->caps; + + if (hw_is_gem(bp->regs, bp->native_io)) { + bp->caps |= MACB_CAPS_MACB_IS_GEM; + + dcfg = gem_readl(bp, DCFG1); + if (GEM_BFEXT(IRQCOR, dcfg) == 0) + bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE; + dcfg = gem_readl(bp, DCFG2); + if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0) + bp->caps |= MACB_CAPS_FIFO_MODE; + if (IS_ENABLED(CONFIG_MACB_USE_HWSTAMP) && gem_has_ptp(bp)) { + if (!GEM_BFEXT(TSU, gem_readl(bp, DCFG5))) + pr_err("GEM doesn't support hardware ptp.\n"); + else + bp->hw_dma_cap |= HW_DMA_CAP_PTP; + } + } + + dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps); +} + +static void macb_probe_queues(void __iomem *mem, + bool native_io, + unsigned int *queue_mask, + unsigned int *num_queues) +{ + unsigned int hw_q; + + *queue_mask = 0x1; + *num_queues = 1; + + /* is it macb or gem ? + * + * We need to read directly from the hardware here because + * we are early in the probe process and don't have the + * MACB_CAPS_MACB_IS_GEM flag positioned + */ + if (!hw_is_gem(mem, native_io)) + return; + + /* bit 0 is never set but queue 0 always exists */ + *queue_mask = readl_relaxed(mem + GEM_DCFG6) & 0xff; + + *queue_mask |= 0x1; + + for (hw_q = 1; hw_q < MACB_MAX_QUEUES; ++hw_q) + if (*queue_mask & (1 << hw_q)) + (*num_queues)++; +} + +static int macb_clk_init(struct platform_device *pdev, struct clk **pclk, + struct clk **hclk, struct clk **tx_clk, + struct clk **rx_clk) +{ + struct macb_platform_data *pdata; + int err; + + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + *pclk = pdata->pclk; + *hclk = pdata->hclk; + } else { + *pclk = devm_clk_get(&pdev->dev, "pclk"); + *hclk = devm_clk_get(&pdev->dev, "hclk"); + } + + if (IS_ERR(*pclk)) { + err = PTR_ERR(*pclk); + dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err); + return err; + } + + if (IS_ERR(*hclk)) { + err = PTR_ERR(*hclk); + dev_err(&pdev->dev, "failed to get hclk (%u)\n", err); + return err; + } + + *tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); + if (IS_ERR(*tx_clk)) + *tx_clk = NULL; + + *rx_clk = devm_clk_get(&pdev->dev, "rx_clk"); + if (IS_ERR(*rx_clk)) + *rx_clk = NULL; + + err = clk_prepare_enable(*pclk); + if (err) { + dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); + return err; + } + + err = clk_prepare_enable(*hclk); + if (err) { + dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err); + goto err_disable_pclk; + } + + err = clk_prepare_enable(*tx_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); + goto err_disable_hclk; + } + + err = clk_prepare_enable(*rx_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err); + goto err_disable_txclk; + } + + return 0; + +err_disable_txclk: + clk_disable_unprepare(*tx_clk); + +err_disable_hclk: + clk_disable_unprepare(*hclk); + +err_disable_pclk: + clk_disable_unprepare(*pclk); + + return err; +} + +static int macb_init(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + unsigned int hw_q, q; + struct macb *bp = netdev_priv(dev); + struct macb_queue *queue; + int err; + u32 val; + + bp->tx_ring_size = DEFAULT_TX_RING_SIZE; + bp->rx_ring_size = DEFAULT_RX_RING_SIZE; + + /* set the queue register mapping once for all: queue0 has a special + * register mapping but we don't want to test the queue index then + * compute the corresponding register offset at run time. + */ + for (hw_q = 0, q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) { + if (!(bp->queue_mask & (1 << hw_q))) + continue; + + queue = &bp->queues[q]; + queue->bp = bp; + if (hw_q) { + queue->ISR = GEM_ISR(hw_q - 1); + queue->IER = GEM_IER(hw_q - 1); + queue->IDR = GEM_IDR(hw_q - 1); + queue->IMR = GEM_IMR(hw_q - 1); + queue->TBQP = GEM_TBQP(hw_q - 1); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + queue->TBQPH = GEM_TBQPH(hw_q - 1); +#endif + } else { + /* queue0 uses legacy registers */ + queue->ISR = MACB_ISR; + queue->IER = MACB_IER; + queue->IDR = MACB_IDR; + queue->IMR = MACB_IMR; + queue->TBQP = MACB_TBQP; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + queue->TBQPH = MACB_TBQPH; +#endif + } + + /* get irq: here we use the linux queue index, not the hardware + * queue index. the queue irq definitions in the device tree + * must remove the optional gaps that could exist in the + * hardware queue mask. + */ + queue->irq = platform_get_irq(pdev, q); + err = devm_request_irq(&pdev->dev, queue->irq, macb_interrupt, + IRQF_SHARED, dev->name, queue); + if (err) { + dev_err(&pdev->dev, + "Unable to request IRQ %d (error %d)\n", + queue->irq, err); + return err; + } + + INIT_WORK(&queue->tx_error_task, macb_tx_error_task); + q++; + } + + dev->netdev_ops = &macb_netdev_ops; + netif_napi_add(dev, &bp->napi, macb_poll, 64); + + /* setup appropriated routines according to adapter type */ + if (macb_is_gem(bp)) { + bp->max_tx_length = GEM_MAX_TX_LEN; + bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers; + bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers; + bp->macbgem_ops.mog_init_rings = gem_init_rings; + bp->macbgem_ops.mog_rx = gem_rx; + dev->ethtool_ops = &gem_ethtool_ops; + } else { + bp->max_tx_length = MACB_MAX_TX_LEN; + bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers; + bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers; + bp->macbgem_ops.mog_init_rings = macb_init_rings; + bp->macbgem_ops.mog_rx = macb_rx; + dev->ethtool_ops = &macb_ethtool_ops; + } + + /* Set features */ + dev->hw_features = NETIF_F_SG; + + /* Check LSO capability */ + if (GEM_BFEXT(PBUF_LSO, gem_readl(bp, DCFG6))) + dev->hw_features |= MACB_NETIF_LSO; + + /* Checksum offload is only available on gem with packet buffer */ + if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE)) + dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; + if (bp->caps & MACB_CAPS_SG_DISABLED) + dev->hw_features &= ~NETIF_F_SG; + dev->features = dev->hw_features; + + if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) { + val = 0; + if (bp->phy_interface == PHY_INTERFACE_MODE_RGMII) + val = GEM_BIT(RGMII); + else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII && + (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII)) + val = MACB_BIT(RMII); + else if (!(bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII)) + val = MACB_BIT(MII); + + if (bp->caps & MACB_CAPS_USRIO_HAS_CLKEN) + val |= MACB_BIT(CLKEN); + + macb_or_gem_writel(bp, USRIO, val); + } + + /* Set MII management clock divider */ + val = macb_mdc_clk_div(bp); + val |= macb_dbw(bp); + if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) + val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); + macb_writel(bp, NCFGR, val); + + return 0; +} + +#if defined(CONFIG_OF) +/* 1518 rounded up */ +#define AT91ETHER_MAX_RBUFF_SZ 0x600 +/* max number of receive buffers */ +#define AT91ETHER_MAX_RX_DESCR 9 + +/* Initialize and start the Receiver and Transmit subsystems */ +static int at91ether_start(struct net_device *dev) +{ + struct macb *lp = netdev_priv(dev); + struct macb_dma_desc *desc; + dma_addr_t addr; + u32 ctl; + int i; + + lp->rx_ring = dma_alloc_coherent(&lp->pdev->dev, + (AT91ETHER_MAX_RX_DESCR * + macb_dma_desc_get_size(lp)), + &lp->rx_ring_dma, GFP_KERNEL); + if (!lp->rx_ring) + return -ENOMEM; + + lp->rx_buffers = dma_alloc_coherent(&lp->pdev->dev, + AT91ETHER_MAX_RX_DESCR * + AT91ETHER_MAX_RBUFF_SZ, + &lp->rx_buffers_dma, GFP_KERNEL); + if (!lp->rx_buffers) { + dma_free_coherent(&lp->pdev->dev, + AT91ETHER_MAX_RX_DESCR * + macb_dma_desc_get_size(lp), + lp->rx_ring, lp->rx_ring_dma); + lp->rx_ring = NULL; + return -ENOMEM; + } + + addr = lp->rx_buffers_dma; + for (i = 0; i < AT91ETHER_MAX_RX_DESCR; i++) { + desc = macb_rx_desc(lp, i); + macb_set_addr(lp, desc, addr); + desc->ctrl = 0; + addr += AT91ETHER_MAX_RBUFF_SZ; + } + + /* Set the Wrap bit on the last descriptor */ + desc->addr |= MACB_BIT(RX_WRAP); + + /* Reset buffer index */ + lp->rx_tail = 0; + + /* Program address of descriptor list in Rx Buffer Queue register */ + macb_writel(lp, RBQP, lp->rx_ring_dma); + + /* Enable Receive and Transmit */ + ctl = macb_readl(lp, NCR); + macb_writel(lp, NCR, ctl | MACB_BIT(RE) | MACB_BIT(TE)); + + return 0; +} + +/* Open the ethernet interface */ +static int at91ether_open(struct net_device *dev) +{ + struct macb *lp = netdev_priv(dev); + u32 ctl; + int ret; + + /* Clear internal statistics */ + ctl = macb_readl(lp, NCR); + macb_writel(lp, NCR, ctl | MACB_BIT(CLRSTAT)); + + macb_set_hwaddr(lp); + + ret = at91ether_start(dev); + if (ret) + return ret; + + /* Enable MAC interrupts */ + macb_writel(lp, IER, MACB_BIT(RCOMP) | + MACB_BIT(RXUBR) | + MACB_BIT(ISR_TUND) | + MACB_BIT(ISR_RLE) | + MACB_BIT(TCOMP) | + MACB_BIT(ISR_ROVR) | + MACB_BIT(HRESP)); + + /* schedule a link state check */ + phy_start(dev->phydev); + + netif_start_queue(dev); + + return 0; +} + +/* Close the interface */ +static int at91ether_close(struct net_device *dev) +{ + struct macb *lp = netdev_priv(dev); + u32 ctl; + + /* Disable Receiver and Transmitter */ + ctl = macb_readl(lp, NCR); + macb_writel(lp, NCR, ctl & ~(MACB_BIT(TE) | MACB_BIT(RE))); + + /* Disable MAC interrupts */ + macb_writel(lp, IDR, MACB_BIT(RCOMP) | + MACB_BIT(RXUBR) | + MACB_BIT(ISR_TUND) | + MACB_BIT(ISR_RLE) | + MACB_BIT(TCOMP) | + MACB_BIT(ISR_ROVR) | + MACB_BIT(HRESP)); + + netif_stop_queue(dev); + + dma_free_coherent(&lp->pdev->dev, + AT91ETHER_MAX_RX_DESCR * + macb_dma_desc_get_size(lp), + lp->rx_ring, lp->rx_ring_dma); + lp->rx_ring = NULL; + + dma_free_coherent(&lp->pdev->dev, + AT91ETHER_MAX_RX_DESCR * AT91ETHER_MAX_RBUFF_SZ, + lp->rx_buffers, lp->rx_buffers_dma); + lp->rx_buffers = NULL; + + return 0; +} + +/* Transmit packet */ +static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct macb *lp = netdev_priv(dev); + + if (macb_readl(lp, TSR) & MACB_BIT(RM9200_BNQ)) { + netif_stop_queue(dev); + + /* Store packet information (to free when Tx completed) */ + lp->skb = skb; + lp->skb_length = skb->len; + lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(NULL, lp->skb_physaddr)) { + dev_kfree_skb_any(skb); + dev->stats.tx_dropped++; + netdev_err(dev, "%s: DMA mapping error\n", __func__); + return NETDEV_TX_OK; + } + + /* Set address of the data in the Transmit Address register */ + macb_writel(lp, TAR, lp->skb_physaddr); + /* Set length of the packet in the Transmit Control register */ + macb_writel(lp, TCR, skb->len); + + } else { + netdev_err(dev, "%s called, but device is busy!\n", __func__); + return NETDEV_TX_BUSY; + } + + return NETDEV_TX_OK; +} + +/* Extract received frame from buffer descriptors and sent to upper layers. + * (Called from interrupt context) + */ +static void at91ether_rx(struct net_device *dev) +{ + struct macb *lp = netdev_priv(dev); + struct macb_dma_desc *desc; + unsigned char *p_recv; + struct sk_buff *skb; + unsigned int pktlen; + + desc = macb_rx_desc(lp, lp->rx_tail); + while (desc->addr & MACB_BIT(RX_USED)) { + p_recv = lp->rx_buffers + lp->rx_tail * AT91ETHER_MAX_RBUFF_SZ; + pktlen = MACB_BF(RX_FRMLEN, desc->ctrl); + skb = netdev_alloc_skb(dev, pktlen + 2); + if (skb) { + skb_reserve(skb, 2); + skb_put_data(skb, p_recv, pktlen); + + skb->protocol = eth_type_trans(skb, dev); + dev->stats.rx_packets++; + dev->stats.rx_bytes += pktlen; + netif_rx(skb); + } else { + dev->stats.rx_dropped++; + } + + if (desc->ctrl & MACB_BIT(RX_MHASH_MATCH)) + dev->stats.multicast++; + + /* reset ownership bit */ + desc->addr &= ~MACB_BIT(RX_USED); + + /* wrap after last buffer */ + if (lp->rx_tail == AT91ETHER_MAX_RX_DESCR - 1) + lp->rx_tail = 0; + else + lp->rx_tail++; + + desc = macb_rx_desc(lp, lp->rx_tail); + } +} + +/* MAC interrupt handler */ +static irqreturn_t at91ether_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct macb *lp = netdev_priv(dev); + u32 intstatus, ctl; + + /* MAC Interrupt Status register indicates what interrupts are pending. + * It is automatically cleared once read. + */ + intstatus = macb_readl(lp, ISR); + + /* Receive complete */ + if (intstatus & MACB_BIT(RCOMP)) + at91ether_rx(dev); + + /* Transmit complete */ + if (intstatus & MACB_BIT(TCOMP)) { + /* The TCOM bit is set even if the transmission failed */ + if (intstatus & (MACB_BIT(ISR_TUND) | MACB_BIT(ISR_RLE))) + dev->stats.tx_errors++; + + if (lp->skb) { + dev_kfree_skb_irq(lp->skb); + lp->skb = NULL; + dma_unmap_single(NULL, lp->skb_physaddr, + lp->skb_length, DMA_TO_DEVICE); + dev->stats.tx_packets++; + dev->stats.tx_bytes += lp->skb_length; + } + netif_wake_queue(dev); + } + + /* Work-around for EMAC Errata section 41.3.1 */ + if (intstatus & MACB_BIT(RXUBR)) { + ctl = macb_readl(lp, NCR); + macb_writel(lp, NCR, ctl & ~MACB_BIT(RE)); + wmb(); + macb_writel(lp, NCR, ctl | MACB_BIT(RE)); + } + + if (intstatus & MACB_BIT(ISR_ROVR)) + netdev_err(dev, "ROVR error\n"); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void at91ether_poll_controller(struct net_device *dev) +{ + unsigned long flags; + + local_irq_save(flags); + at91ether_interrupt(dev->irq, dev); + local_irq_restore(flags); +} +#endif + +static const struct net_device_ops at91ether_netdev_ops = { + .ndo_open = at91ether_open, + .ndo_stop = at91ether_close, + .ndo_start_xmit = at91ether_start_xmit, + .ndo_get_stats = macb_get_stats, + .ndo_set_rx_mode = macb_set_rx_mode, + .ndo_set_mac_address = eth_mac_addr, + .ndo_do_ioctl = macb_ioctl, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = at91ether_poll_controller, +#endif +}; + +static int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk, + struct clk **hclk, struct clk **tx_clk, + struct clk **rx_clk) +{ + int err; + + *hclk = NULL; + *tx_clk = NULL; + *rx_clk = NULL; + + *pclk = devm_clk_get(&pdev->dev, "ether_clk"); + if (IS_ERR(*pclk)) + return PTR_ERR(*pclk); + + err = clk_prepare_enable(*pclk); + if (err) { + dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); + return err; + } + + return 0; +} + +static int at91ether_init(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(dev); + int err; + u32 reg; + + dev->netdev_ops = &at91ether_netdev_ops; + dev->ethtool_ops = &macb_ethtool_ops; + + err = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt, + 0, dev->name, dev); + if (err) + return err; + + macb_writel(bp, NCR, 0); + + reg = MACB_BF(CLK, MACB_CLK_DIV32) | MACB_BIT(BIG); + if (bp->phy_interface == PHY_INTERFACE_MODE_RMII) + reg |= MACB_BIT(RM9200_RMII); + + macb_writel(bp, NCFGR, reg); + + return 0; +} + +static const struct macb_config at91sam9260_config = { + .caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, + .clk_init = macb_clk_init, + .init = macb_init, +}; + +static const struct macb_config pc302gem_config = { + .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = macb_init, +}; + +static const struct macb_config sama5d2_config = { + .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = macb_init, +}; + +static const struct macb_config sama5d3_config = { + .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE + | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = macb_init, +}; + +static const struct macb_config sama5d4_config = { + .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, + .dma_burst_length = 4, + .clk_init = macb_clk_init, + .init = macb_init, +}; + +static const struct macb_config emac_config = { + .clk_init = at91ether_clk_init, + .init = at91ether_init, +}; + +static const struct macb_config np4_config = { + .caps = MACB_CAPS_USRIO_DISABLED, + .clk_init = macb_clk_init, + .init = macb_init, +}; + +static const struct macb_config zynqmp_config = { + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = macb_init, + .jumbo_max_len = 10240, +}; + +static const struct macb_config zynq_config = { + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_NO_GIGABIT_HALF, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = macb_init, +}; + +static const struct of_device_id macb_dt_ids[] = { + { .compatible = "cdns,at32ap7000-macb" }, + { .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config }, + { .compatible = "cdns,macb" }, + { .compatible = "cdns,np4-macb", .data = &np4_config }, + { .compatible = "cdns,pc302-gem", .data = &pc302gem_config }, + { .compatible = "cdns,gem", .data = &pc302gem_config }, + { .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config }, + { .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config }, + { .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config }, + { .compatible = "cdns,at91rm9200-emac", .data = &emac_config }, + { .compatible = "cdns,emac", .data = &emac_config }, + { .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config}, + { .compatible = "cdns,zynq-gem", .data = &zynq_config }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, macb_dt_ids); +#endif /* CONFIG_OF */ + +static const struct macb_config default_gem_config = { + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = macb_init, + .jumbo_max_len = 10240, +}; + +static int macb_probe(struct platform_device *pdev) +{ + const struct macb_config *macb_config = &default_gem_config; + int (*clk_init)(struct platform_device *, struct clk **, + struct clk **, struct clk **, struct clk **) + = macb_config->clk_init; + int (*init)(struct platform_device *) = macb_config->init; + struct device_node *np = pdev->dev.of_node; + struct device_node *phy_node; + struct clk *pclk, *hclk = NULL, *tx_clk = NULL, *rx_clk = NULL; + unsigned int queue_mask, num_queues; + struct macb_platform_data *pdata; + bool native_io; + struct phy_device *phydev; + struct net_device *dev; + struct resource *regs; + void __iomem *mem; + const char *mac; + struct macb *bp; + int err; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mem = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(mem)) + return PTR_ERR(mem); + + if (np) { + const struct of_device_id *match; + + match = of_match_node(macb_dt_ids, np); + if (match && match->data) { + macb_config = match->data; + clk_init = macb_config->clk_init; + init = macb_config->init; + } + } + + err = clk_init(pdev, &pclk, &hclk, &tx_clk, &rx_clk); + if (err) + return err; + + native_io = hw_is_native_io(mem); + + macb_probe_queues(mem, native_io, &queue_mask, &num_queues); + dev = alloc_etherdev_mq(sizeof(*bp), num_queues); + if (!dev) { + err = -ENOMEM; + goto err_disable_clocks; + } + + dev->base_addr = regs->start; + + SET_NETDEV_DEV(dev, &pdev->dev); + + bp = netdev_priv(dev); + bp->pdev = pdev; + bp->dev = dev; + bp->regs = mem; + bp->native_io = native_io; + if (native_io) { + bp->macb_reg_readl = hw_readl_native; + bp->macb_reg_writel = hw_writel_native; + } else { + bp->macb_reg_readl = hw_readl; + bp->macb_reg_writel = hw_writel; + } + bp->num_queues = num_queues; + bp->queue_mask = queue_mask; + if (macb_config) + bp->dma_burst_length = macb_config->dma_burst_length; + bp->pclk = pclk; + bp->hclk = hclk; + bp->tx_clk = tx_clk; + bp->rx_clk = rx_clk; + if (macb_config) + bp->jumbo_max_len = macb_config->jumbo_max_len; + + bp->wol = 0; + if (of_get_property(np, "magic-packet", NULL)) + bp->wol |= MACB_WOL_HAS_MAGIC_PACKET; + device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET); + + spin_lock_init(&bp->lock); + + /* setup capabilities */ + macb_configure_caps(bp, macb_config); + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) { + dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); + bp->hw_dma_cap |= HW_DMA_CAP_64B; + } +#endif + platform_set_drvdata(pdev, dev); + + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq < 0) { + err = dev->irq; + goto err_out_free_netdev; + } + + /* MTU range: 68 - 1500 or 10240 */ + dev->min_mtu = GEM_MTU_MIN_SIZE; + if (bp->caps & MACB_CAPS_JUMBO) + dev->max_mtu = gem_readl(bp, JML) - ETH_HLEN - ETH_FCS_LEN; + else + dev->max_mtu = ETH_DATA_LEN; + + mac = of_get_mac_address(np); + if (mac) + ether_addr_copy(bp->dev->dev_addr, mac); + else + macb_get_hwaddr(bp); + + /* Power up the PHY if there is a GPIO reset */ + phy_node = of_get_next_available_child(np, NULL); + if (phy_node) { + int gpio = of_get_named_gpio(phy_node, "reset-gpios", 0); + + if (gpio_is_valid(gpio)) { + bp->reset_gpio = gpio_to_desc(gpio); + gpiod_direction_output(bp->reset_gpio, 1); + } + } + of_node_put(phy_node); + + err = of_get_phy_mode(np); + if (err < 0) { + pdata = dev_get_platdata(&pdev->dev); + if (pdata && pdata->is_rmii) + bp->phy_interface = PHY_INTERFACE_MODE_RMII; + else + bp->phy_interface = PHY_INTERFACE_MODE_MII; + } else { + bp->phy_interface = err; + } + + /* IP specific init */ + err = init(pdev); + if (err) + goto err_out_free_netdev; + + err = macb_mii_init(bp); + if (err) + goto err_out_free_netdev; + + phydev = dev->phydev; + + netif_carrier_off(dev); + + err = register_netdev(dev); + if (err) { + dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); + goto err_out_unregister_mdio; + } + + phy_attached_info(phydev); + + netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n", + macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID), + dev->base_addr, dev->irq, dev->dev_addr); + + return 0; + +err_out_unregister_mdio: + phy_disconnect(dev->phydev); + mdiobus_unregister(bp->mii_bus); + mdiobus_free(bp->mii_bus); + + /* Shutdown the PHY if there is a GPIO reset */ + if (bp->reset_gpio) + gpiod_set_value(bp->reset_gpio, 0); + +err_out_free_netdev: + free_netdev(dev); + +err_disable_clocks: + clk_disable_unprepare(tx_clk); + clk_disable_unprepare(hclk); + clk_disable_unprepare(pclk); + clk_disable_unprepare(rx_clk); + + return err; +} + +static int macb_remove(struct platform_device *pdev) +{ + struct net_device *dev; + struct macb *bp; + + dev = platform_get_drvdata(pdev); + + if (dev) { + bp = netdev_priv(dev); + if (dev->phydev) + phy_disconnect(dev->phydev); + mdiobus_unregister(bp->mii_bus); + dev->phydev = NULL; + mdiobus_free(bp->mii_bus); + + /* Shutdown the PHY if there is a GPIO reset */ + if (bp->reset_gpio) + gpiod_set_value(bp->reset_gpio, 0); + + unregister_netdev(dev); + clk_disable_unprepare(bp->tx_clk); + clk_disable_unprepare(bp->hclk); + clk_disable_unprepare(bp->pclk); + clk_disable_unprepare(bp->rx_clk); + of_node_put(bp->phy_node); + free_netdev(dev); + } + + return 0; +} + +static int __maybe_unused macb_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *netdev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(netdev); + + netif_carrier_off(netdev); + netif_device_detach(netdev); + + if (bp->wol & MACB_WOL_ENABLED) { + macb_writel(bp, IER, MACB_BIT(WOL)); + macb_writel(bp, WOL, MACB_BIT(MAG)); + enable_irq_wake(bp->queues[0].irq); + } else { + clk_disable_unprepare(bp->tx_clk); + clk_disable_unprepare(bp->hclk); + clk_disable_unprepare(bp->pclk); + clk_disable_unprepare(bp->rx_clk); + } + + return 0; +} + +static int __maybe_unused macb_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *netdev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(netdev); + + if (bp->wol & MACB_WOL_ENABLED) { + macb_writel(bp, IDR, MACB_BIT(WOL)); + macb_writel(bp, WOL, 0); + disable_irq_wake(bp->queues[0].irq); + } else { + clk_prepare_enable(bp->pclk); + clk_prepare_enable(bp->hclk); + clk_prepare_enable(bp->tx_clk); + clk_prepare_enable(bp->rx_clk); + } + + netif_device_attach(netdev); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume); + +static struct platform_driver macb_driver = { + .probe = macb_probe, + .remove = macb_remove, + .driver = { + .name = "macb", + .of_match_table = of_match_ptr(macb_dt_ids), + .pm = &macb_pm_ops, + }, +}; + +module_platform_driver(macb_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver"); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); +MODULE_ALIAS("platform:macb"); -- cgit v1.2.3 From ab91f0a9b5f4b9b5b341fdc0ed457121e69c20e1 Mon Sep 17 00:00:00 2001 From: Rafal Ozieblo Date: Thu, 29 Jun 2017 07:14:16 +0100 Subject: net: macb: Add hardware PTP support This patch is based on original Harini's patch and Andrei's patch, implemented in a separate file to ease the review/maintanance and integration with other platforms. This driver supports GEM-GXL: - Register ptp clock framework - Initialize PTP related registers - HW time stamp on the PTP Ethernet packets are received using the SO_TIMESTAMPING API. Time stamps are obtained from the dma buffer descriptors - add macb_ptp to compilation chain Signed-off-by: Rafal Ozieblo Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/Makefile | 4 + drivers/net/ethernet/cadence/macb.h | 126 ++++++++ drivers/net/ethernet/cadence/macb_main.c | 90 +++++- drivers/net/ethernet/cadence/macb_ptp.c | 518 +++++++++++++++++++++++++++++++ 4 files changed, 732 insertions(+), 6 deletions(-) create mode 100755 drivers/net/ethernet/cadence/macb_ptp.c (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile index 31ea6e34147a..1d66ddb68969 100644 --- a/drivers/net/ethernet/cadence/Makefile +++ b/drivers/net/ethernet/cadence/Makefile @@ -3,5 +3,9 @@ # macb-y := macb_main.o +ifeq ($(CONFIG_MACB_USE_HWSTAMP),y) +macb-y += macb_ptp.o +endif + obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MACB_PCI) += macb_pci.o diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 3aefa380f345..c93f3a2dc6c1 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -11,6 +11,8 @@ #define _MACB_H #include +#include +#include #if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP) #define MACB_EXT_DESC @@ -90,6 +92,10 @@ #define GEM_SA3T 0x009C /* Specific3 Top */ #define GEM_SA4B 0x00A0 /* Specific4 Bottom */ #define GEM_SA4T 0x00A4 /* Specific4 Top */ +#define GEM_EFTSH 0x00e8 /* PTP Event Frame Transmitted Seconds Register 47:32 */ +#define GEM_EFRSH 0x00ec /* PTP Event Frame Received Seconds Register 47:32 */ +#define GEM_PEFTSH 0x00f0 /* PTP Peer Event Frame Transmitted Seconds Register 47:32 */ +#define GEM_PEFRSH 0x00f4 /* PTP Peer Event Frame Received Seconds Register 47:32 */ #define GEM_OTX 0x0100 /* Octets transmitted */ #define GEM_OCTTXL 0x0100 /* Octets transmitted [31:0] */ #define GEM_OCTTXH 0x0104 /* Octets transmitted [47:32] */ @@ -159,6 +165,9 @@ #define GEM_DCFG6 0x0294 /* Design Config 6 */ #define GEM_DCFG7 0x0298 /* Design Config 7 */ +#define GEM_TXBDCTRL 0x04cc /* TX Buffer Descriptor control register */ +#define GEM_RXBDCTRL 0x04d0 /* RX Buffer Descriptor control register */ + #define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2)) #define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2)) #define GEM_TBQPH(hw_q) (0x04C8) @@ -195,6 +204,8 @@ #define MACB_TZQ_OFFSET 12 /* Transmit zero quantum pause frame */ #define MACB_TZQ_SIZE 1 #define MACB_SRTSM_OFFSET 15 +#define MACB_OSSMODE_OFFSET 24 /* Enable One Step Synchro Mode */ +#define MACB_OSSMODE_SIZE 1 /* Bitfields in NCFGR */ #define MACB_SPD_OFFSET 0 /* Speed */ @@ -452,6 +463,52 @@ #define GEM_NSINCR_OFFSET 0 #define GEM_NSINCR_SIZE 8 +/* Bitfields in TSH */ +#define GEM_TSH_OFFSET 0 /* TSU timer value (s). MSB [47:32] of seconds timer count */ +#define GEM_TSH_SIZE 16 + +/* Bitfields in TSL */ +#define GEM_TSL_OFFSET 0 /* TSU timer value (s). LSB [31:0] of seconds timer count */ +#define GEM_TSL_SIZE 32 + +/* Bitfields in TN */ +#define GEM_TN_OFFSET 0 /* TSU timer value (ns) */ +#define GEM_TN_SIZE 30 + +/* Bitfields in TXBDCTRL */ +#define GEM_TXTSMODE_OFFSET 4 /* TX Descriptor Timestamp Insertion mode */ +#define GEM_TXTSMODE_SIZE 2 + +/* Bitfields in RXBDCTRL */ +#define GEM_RXTSMODE_OFFSET 4 /* RX Descriptor Timestamp Insertion mode */ +#define GEM_RXTSMODE_SIZE 2 + +/* Transmit DMA buffer descriptor Word 1 */ +#define GEM_DMA_TXVALID_OFFSET 23 /* timestamp has been captured in the Buffer Descriptor */ +#define GEM_DMA_TXVALID_SIZE 1 + +/* Receive DMA buffer descriptor Word 0 */ +#define GEM_DMA_RXVALID_OFFSET 2 /* indicates a valid timestamp in the Buffer Descriptor */ +#define GEM_DMA_RXVALID_SIZE 1 + +/* DMA buffer descriptor Word 2 (32 bit addressing) or Word 4 (64 bit addressing) */ +#define GEM_DMA_SECL_OFFSET 30 /* Timestamp seconds[1:0] */ +#define GEM_DMA_SECL_SIZE 2 +#define GEM_DMA_NSEC_OFFSET 0 /* Timestamp nanosecs [29:0] */ +#define GEM_DMA_NSEC_SIZE 30 + +/* DMA buffer descriptor Word 3 (32 bit addressing) or Word 5 (64 bit addressing) */ + +/* New hardware supports 12 bit precision of timestamp in DMA buffer descriptor. + * Old hardware supports only 6 bit precision but it is enough for PTP. + * Less accuracy is used always instead of checking hardware version. + */ +#define GEM_DMA_SECH_OFFSET 0 /* Timestamp seconds[5:2] */ +#define GEM_DMA_SECH_SIZE 4 +#define GEM_DMA_SEC_WIDTH (GEM_DMA_SECH_SIZE + GEM_DMA_SECL_SIZE) +#define GEM_DMA_SEC_TOP (1 << GEM_DMA_SEC_WIDTH) +#define GEM_DMA_SEC_MASK (GEM_DMA_SEC_TOP - 1) + /* Bitfields in ADJ */ #define GEM_ADDSUB_OFFSET 31 #define GEM_ADDSUB_SIZE 1 @@ -527,6 +584,8 @@ #define queue_readl(queue, reg) (queue)->bp->macb_reg_readl((queue)->bp, (queue)->reg) #define queue_writel(queue, reg, value) (queue)->bp->macb_reg_writel((queue)->bp, (queue)->reg, (value)) +#define PTP_TS_BUFFER_SIZE 128 /* must be power of 2 */ + /* Conditional GEM/MACB macros. These perform the operation to the correct * register dependent on whether the device is a GEM or a MACB. For registers * and bitfields that are common across both devices, use macb_{read,write}l @@ -574,6 +633,11 @@ struct macb_dma_desc_ptp { u32 ts_1; u32 ts_2; }; + +struct gem_tx_ts { + struct sk_buff *skb; + struct macb_dma_desc_ptp desc_ptp; +}; #endif /* DMA descriptor bitfields */ @@ -889,6 +953,11 @@ struct macb_config { int jumbo_max_len; }; +struct tsu_incr { + u32 sub_ns; + u32 ns; +}; + struct macb_queue { struct macb *bp; int irq; @@ -905,6 +974,12 @@ struct macb_queue { struct macb_tx_skb *tx_skb; dma_addr_t tx_ring_dma; struct work_struct tx_error_task; + +#ifdef CONFIG_MACB_USE_HWSTAMP + struct work_struct tx_ts_task; + unsigned int tx_ts_head, tx_ts_tail; + struct gem_tx_ts tx_timestamps[PTP_TS_BUFFER_SIZE]; +#endif }; struct macb { @@ -976,8 +1051,59 @@ struct macb { #ifdef MACB_EXT_DESC uint8_t hw_dma_cap; #endif + spinlock_t tsu_clk_lock; /* gem tsu clock locking */ + unsigned int tsu_rate; + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_clock_info; + struct tsu_incr tsu_incr; + struct hwtstamp_config tstamp_config; }; +#ifdef CONFIG_MACB_USE_HWSTAMP +#define GEM_TSEC_SIZE (GEM_TSH_SIZE + GEM_TSL_SIZE) +#define TSU_SEC_MAX_VAL (((u64)1 << GEM_TSEC_SIZE) - 1) +#define TSU_NSEC_MAX_VAL ((1 << GEM_TN_SIZE) - 1) + +enum macb_bd_control { + TSTAMP_DISABLED, + TSTAMP_FRAME_PTP_EVENT_ONLY, + TSTAMP_ALL_PTP_FRAMES, + TSTAMP_ALL_FRAMES, +}; + +void gem_ptp_init(struct net_device *ndev); +void gem_ptp_remove(struct net_device *ndev); +int gem_ptp_txstamp(struct macb_queue *queue, struct sk_buff *skb, struct macb_dma_desc *des); +void gem_ptp_rxstamp(struct macb *bp, struct sk_buff *skb, struct macb_dma_desc *desc); +static inline int gem_ptp_do_txstamp(struct macb_queue *queue, struct sk_buff *skb, struct macb_dma_desc *desc) +{ + if (queue->bp->tstamp_config.tx_type == TSTAMP_DISABLED) + return -ENOTSUPP; + + return gem_ptp_txstamp(queue, skb, desc); +} + +static inline void gem_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb, struct macb_dma_desc *desc) +{ + if (bp->tstamp_config.rx_filter == TSTAMP_DISABLED) + return; + + gem_ptp_rxstamp(bp, skb, desc); +} +int gem_get_hwtst(struct net_device *dev, struct ifreq *rq); +int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd); +#else +static inline void gem_ptp_init(struct net_device *ndev) { } +static inline void gem_ptp_remove(struct net_device *ndev) { } + +static inline int gem_ptp_do_txstamp(struct macb_queue *queue, struct sk_buff *skb, struct macb_dma_desc *desc) +{ + return -1; +} + +static inline void gem_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb, struct macb_dma_desc *desc) { } +#endif + static inline bool macb_is_gem(struct macb *bp) { return !!(bp->caps & MACB_CAPS_MACB_IS_GEM); diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 2d43a7619f58..41e5711544fc 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -847,6 +847,12 @@ static void macb_tx_interrupt(struct macb_queue *queue) /* First, update TX stats if needed */ if (skb) { + if (gem_ptp_do_txstamp(queue, skb, desc) == 0) { + /* skb now belongs to timestamp buffer + * and will be removed later + */ + tx_skb->skb = NULL; + } netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", macb_tx_ring_wrap(bp, tail), skb->data); @@ -1013,6 +1019,8 @@ static int gem_rx(struct macb *bp, int budget) bp->dev->stats.rx_packets++; bp->dev->stats.rx_bytes += skb->len; + gem_ptp_do_rxstamp(bp, skb, desc); + #if defined(DEBUG) && defined(VERBOSE_DEBUG) netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n", skb->len, skb->csum); @@ -1334,7 +1342,6 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) queue_writel(queue, ISR, MACB_BIT(HRESP)); } - status = queue_readl(queue, ISR); } @@ -1664,7 +1671,6 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Make newly initialized descriptor visible to hardware */ wmb(); - skb_tx_timestamp(skb); macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); @@ -2522,6 +2528,70 @@ static int macb_set_ringparam(struct net_device *netdev, return 0; } +#ifdef CONFIG_MACB_USE_HWSTAMP +static unsigned int gem_get_tsu_rate(struct macb *bp) +{ + struct clk *tsu_clk; + unsigned int tsu_rate; + + tsu_clk = devm_clk_get(&bp->pdev->dev, "tsu_clk"); + if (!IS_ERR(tsu_clk)) + tsu_rate = clk_get_rate(tsu_clk); + /* try pclk instead */ + else if (!IS_ERR(bp->pclk)) { + tsu_clk = bp->pclk; + tsu_rate = clk_get_rate(tsu_clk); + } else + return -ENOTSUPP; + return tsu_rate; +} + +static s32 gem_get_ptp_max_adj(void) +{ + return 64000000; +} + +static int gem_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *info) +{ + struct macb *bp = netdev_priv(dev); + + if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0) { + ethtool_op_get_ts_info(dev, info); + return 0; + } + + info->so_timestamping = + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->tx_types = + (1 << HWTSTAMP_TX_ONESTEP_SYNC) | + (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON); + info->rx_filters = + (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_ALL); + + info->phc_index = bp->ptp_clock ? ptp_clock_index(bp->ptp_clock) : -1; + + return 0; +} + +static struct macb_ptp_info gem_ptp_info = { + .ptp_init = gem_ptp_init, + .ptp_remove = gem_ptp_remove, + .get_ptp_max_adj = gem_get_ptp_max_adj, + .get_tsu_rate = gem_get_tsu_rate, + .get_ts_info = gem_get_ts_info, + .get_hwtst = gem_get_hwtst, + .set_hwtst = gem_set_hwtst, +}; +#endif + static int macb_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info) { @@ -2655,12 +2725,16 @@ static void macb_configure_caps(struct macb *bp, dcfg = gem_readl(bp, DCFG2); if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0) bp->caps |= MACB_CAPS_FIFO_MODE; - if (IS_ENABLED(CONFIG_MACB_USE_HWSTAMP) && gem_has_ptp(bp)) { +#ifdef CONFIG_MACB_USE_HWSTAMP + if (gem_has_ptp(bp)) { if (!GEM_BFEXT(TSU, gem_readl(bp, DCFG5))) pr_err("GEM doesn't support hardware ptp.\n"); - else + else { bp->hw_dma_cap |= HW_DMA_CAP_PTP; + bp->ptp_info = &gem_ptp_info; + } } +#endif } dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps); @@ -3266,7 +3340,9 @@ static const struct macb_config np4_config = { }; static const struct macb_config zynqmp_config = { - .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | + MACB_CAPS_JUMBO | + MACB_CAPS_GEM_HAS_PTP, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, @@ -3300,7 +3376,9 @@ MODULE_DEVICE_TABLE(of, macb_dt_ids); #endif /* CONFIG_OF */ static const struct macb_config default_gem_config = { - .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | + MACB_CAPS_JUMBO | + MACB_CAPS_GEM_HAS_PTP, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c new file mode 100755 index 000000000000..67cca08472b7 --- /dev/null +++ b/drivers/net/ethernet/cadence/macb_ptp.c @@ -0,0 +1,518 @@ +/** + * 1588 PTP support for Cadence GEM device. + * + * Copyright (C) 2017 Cadence Design Systems - http://www.cadence.com + * + * Authors: Rafal Ozieblo + * Bartosz Folta + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macb.h" + +#define GEM_PTP_TIMER_NAME "gem-ptp-timer" + +static struct macb_dma_desc_ptp *macb_ptp_desc(struct macb *bp, + struct macb_dma_desc *desc) +{ + if (bp->hw_dma_cap == HW_DMA_CAP_PTP) + return (struct macb_dma_desc_ptp *) + ((u8 *)desc + sizeof(struct macb_dma_desc)); + if (bp->hw_dma_cap == HW_DMA_CAP_64B_PTP) + return (struct macb_dma_desc_ptp *) + ((u8 *)desc + sizeof(struct macb_dma_desc) + + sizeof(struct macb_dma_desc_64)); + return NULL; +} + +static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + struct macb *bp = container_of(ptp, struct macb, ptp_clock_info); + unsigned long flags; + long first, second; + u32 secl, sech; + + spin_lock_irqsave(&bp->tsu_clk_lock, flags); + first = gem_readl(bp, TN); + secl = gem_readl(bp, TSL); + sech = gem_readl(bp, TSH); + second = gem_readl(bp, TN); + + /* test for nsec rollover */ + if (first > second) { + /* if so, use later read & re-read seconds + * (assume all done within 1s) + */ + ts->tv_nsec = gem_readl(bp, TN); + secl = gem_readl(bp, TSL); + sech = gem_readl(bp, TSH); + } else { + ts->tv_nsec = first; + } + + spin_unlock_irqrestore(&bp->tsu_clk_lock, flags); + ts->tv_sec = (((u64)sech << GEM_TSL_SIZE) | secl) + & TSU_SEC_MAX_VAL; + return 0; +} + +static int gem_tsu_set_time(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct macb *bp = container_of(ptp, struct macb, ptp_clock_info); + unsigned long flags; + u32 ns, sech, secl; + + secl = (u32)ts->tv_sec; + sech = (ts->tv_sec >> GEM_TSL_SIZE) & ((1 << GEM_TSH_SIZE) - 1); + ns = ts->tv_nsec; + + spin_lock_irqsave(&bp->tsu_clk_lock, flags); + + /* TSH doesn't latch the time and no atomicity! */ + gem_writel(bp, TN, 0); /* clear to avoid overflow */ + gem_writel(bp, TSH, sech); + /* write lower bits 2nd, for synchronized secs update */ + gem_writel(bp, TSL, secl); + gem_writel(bp, TN, ns); + + spin_unlock_irqrestore(&bp->tsu_clk_lock, flags); + + return 0; +} + +static int gem_tsu_incr_set(struct macb *bp, struct tsu_incr *incr_spec) +{ + unsigned long flags; + + /* tsu_timer_incr register must be written after + * the tsu_timer_incr_sub_ns register and the write operation + * will cause the value written to the tsu_timer_incr_sub_ns register + * to take effect. + */ + spin_lock_irqsave(&bp->tsu_clk_lock, flags); + gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, incr_spec->sub_ns)); + gem_writel(bp, TI, GEM_BF(NSINCR, incr_spec->ns)); + spin_unlock_irqrestore(&bp->tsu_clk_lock, flags); + + return 0; +} + +static int gem_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct macb *bp = container_of(ptp, struct macb, ptp_clock_info); + struct tsu_incr incr_spec; + bool neg_adj = false; + u32 word; + u64 adj; + + if (scaled_ppm < 0) { + neg_adj = true; + scaled_ppm = -scaled_ppm; + } + + /* Adjustment is relative to base frequency */ + incr_spec.sub_ns = bp->tsu_incr.sub_ns; + incr_spec.ns = bp->tsu_incr.ns; + + /* scaling: unused(8bit) | ns(8bit) | fractions(16bit) */ + word = ((u64)incr_spec.ns << GEM_SUBNSINCR_SIZE) + incr_spec.sub_ns; + adj = (u64)scaled_ppm * word; + /* Divide with rounding, equivalent to floating dividing: + * (temp / USEC_PER_SEC) + 0.5 + */ + adj += (USEC_PER_SEC >> 1); + adj >>= GEM_SUBNSINCR_SIZE; /* remove fractions */ + adj = div_u64(adj, USEC_PER_SEC); + adj = neg_adj ? (word - adj) : (word + adj); + + incr_spec.ns = (adj >> GEM_SUBNSINCR_SIZE) + & ((1 << GEM_NSINCR_SIZE) - 1); + incr_spec.sub_ns = adj & ((1 << GEM_SUBNSINCR_SIZE) - 1); + gem_tsu_incr_set(bp, &incr_spec); + return 0; +} + +static int gem_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct macb *bp = container_of(ptp, struct macb, ptp_clock_info); + struct timespec64 now, then = ns_to_timespec64(delta); + u32 adj, sign = 0; + + if (delta < 0) { + sign = 1; + delta = -delta; + } + + if (delta > TSU_NSEC_MAX_VAL) { + gem_tsu_get_time(&bp->ptp_clock_info, &now); + if (sign) + now = timespec64_sub(now, then); + else + now = timespec64_add(now, then); + + gem_tsu_set_time(&bp->ptp_clock_info, + (const struct timespec64 *)&now); + } else { + adj = (sign << GEM_ADDSUB_OFFSET) | delta; + + gem_writel(bp, TA, adj); + } + + return 0; +} + +static int gem_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + return -EOPNOTSUPP; +} + +static struct ptp_clock_info gem_ptp_caps_template = { + .owner = THIS_MODULE, + .name = GEM_PTP_TIMER_NAME, + .max_adj = 0, + .n_alarm = 0, + .n_ext_ts = 0, + .n_per_out = 0, + .n_pins = 0, + .pps = 1, + .adjfine = gem_ptp_adjfine, + .adjtime = gem_ptp_adjtime, + .gettime64 = gem_tsu_get_time, + .settime64 = gem_tsu_set_time, + .enable = gem_ptp_enable, +}; + +static void gem_ptp_init_timer(struct macb *bp) +{ + u32 rem = 0; + u64 adj; + + bp->tsu_incr.ns = div_u64_rem(NSEC_PER_SEC, bp->tsu_rate, &rem); + if (rem) { + adj = rem; + adj <<= GEM_SUBNSINCR_SIZE; + bp->tsu_incr.sub_ns = div_u64(adj, bp->tsu_rate); + } else { + bp->tsu_incr.sub_ns = 0; + } +} + +static void gem_ptp_init_tsu(struct macb *bp) +{ + struct timespec64 ts; + + /* 1. get current system time */ + ts = ns_to_timespec64(ktime_to_ns(ktime_get_real())); + + /* 2. set ptp timer */ + gem_tsu_set_time(&bp->ptp_clock_info, &ts); + + /* 3. set PTP timer increment value to BASE_INCREMENT */ + gem_tsu_incr_set(bp, &bp->tsu_incr); + + gem_writel(bp, TA, 0); +} + +static void gem_ptp_clear_timer(struct macb *bp) +{ + bp->tsu_incr.sub_ns = 0; + bp->tsu_incr.ns = 0; + + gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, 0)); + gem_writel(bp, TI, GEM_BF(NSINCR, 0)); + gem_writel(bp, TA, 0); +} + +static int gem_hw_timestamp(struct macb *bp, u32 dma_desc_ts_1, + u32 dma_desc_ts_2, struct timespec64 *ts) +{ + struct timespec64 tsu; + + ts->tv_sec = (GEM_BFEXT(DMA_SECH, dma_desc_ts_2) << GEM_DMA_SECL_SIZE) | + GEM_BFEXT(DMA_SECL, dma_desc_ts_1); + ts->tv_nsec = GEM_BFEXT(DMA_NSEC, dma_desc_ts_1); + + /* TSU overlapping workaround + * The timestamp only contains lower few bits of seconds, + * so add value from 1588 timer + */ + gem_tsu_get_time(&bp->ptp_clock_info, &tsu); + + /* If the top bit is set in the timestamp, + * but not in 1588 timer, it has rolled over, + * so subtract max size + */ + if ((ts->tv_sec & (GEM_DMA_SEC_TOP >> 1)) && + !(tsu.tv_sec & (GEM_DMA_SEC_TOP >> 1))) + ts->tv_sec -= GEM_DMA_SEC_TOP; + + ts->tv_sec += ((~GEM_DMA_SEC_MASK) & tsu.tv_sec); + + return 0; +} + +void gem_ptp_rxstamp(struct macb *bp, struct sk_buff *skb, + struct macb_dma_desc *desc) +{ + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + struct macb_dma_desc_ptp *desc_ptp; + struct timespec64 ts; + + if (GEM_BFEXT(DMA_RXVALID, desc->addr)) { + desc_ptp = macb_ptp_desc(bp, desc); + gem_hw_timestamp(bp, desc_ptp->ts_1, desc_ptp->ts_2, &ts); + memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); + shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); + } +} + +static void gem_tstamp_tx(struct macb *bp, struct sk_buff *skb, + struct macb_dma_desc_ptp *desc_ptp) +{ + struct skb_shared_hwtstamps shhwtstamps; + struct timespec64 ts; + + gem_hw_timestamp(bp, desc_ptp->ts_1, desc_ptp->ts_2, &ts); + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); + skb_tstamp_tx(skb, &shhwtstamps); +} + +int gem_ptp_txstamp(struct macb_queue *queue, struct sk_buff *skb, + struct macb_dma_desc *desc) +{ + unsigned long tail = READ_ONCE(queue->tx_ts_tail); + unsigned long head = queue->tx_ts_head; + struct macb_dma_desc_ptp *desc_ptp; + struct gem_tx_ts *tx_timestamp; + + if (!GEM_BFEXT(DMA_TXVALID, desc->ctrl)) + return -EINVAL; + + if (CIRC_SPACE(head, tail, PTP_TS_BUFFER_SIZE) == 0) + return -ENOMEM; + + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + desc_ptp = macb_ptp_desc(queue->bp, desc); + tx_timestamp = &queue->tx_timestamps[head]; + tx_timestamp->skb = skb; + tx_timestamp->desc_ptp.ts_1 = desc_ptp->ts_1; + tx_timestamp->desc_ptp.ts_2 = desc_ptp->ts_2; + /* move head */ + smp_store_release(&queue->tx_ts_head, + (head + 1) & (PTP_TS_BUFFER_SIZE - 1)); + + schedule_work(&queue->tx_ts_task); + return 0; +} + +static void gem_tx_timestamp_flush(struct work_struct *work) +{ + struct macb_queue *queue = + container_of(work, struct macb_queue, tx_ts_task); + unsigned long head, tail; + struct gem_tx_ts *tx_ts; + + /* take current head */ + head = smp_load_acquire(&queue->tx_ts_head); + tail = queue->tx_ts_tail; + + while (CIRC_CNT(head, tail, PTP_TS_BUFFER_SIZE)) { + tx_ts = &queue->tx_timestamps[tail]; + gem_tstamp_tx(queue->bp, tx_ts->skb, &tx_ts->desc_ptp); + /* cleanup */ + dev_kfree_skb_any(tx_ts->skb); + /* remove old tail */ + smp_store_release(&queue->tx_ts_tail, + (tail + 1) & (PTP_TS_BUFFER_SIZE - 1)); + tail = queue->tx_ts_tail; + } +} + +void gem_ptp_init(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + struct macb_queue *queue; + unsigned int q; + + bp->ptp_clock_info = gem_ptp_caps_template; + + /* nominal frequency and maximum adjustment in ppb */ + bp->tsu_rate = bp->ptp_info->get_tsu_rate(bp); + bp->ptp_clock_info.max_adj = bp->ptp_info->get_ptp_max_adj(); + gem_ptp_init_timer(bp); + bp->ptp_clock = ptp_clock_register(&bp->ptp_clock_info, &dev->dev); + if (IS_ERR(bp->ptp_clock)) { + pr_err("ptp clock register failed: %ld\n", + PTR_ERR(bp->ptp_clock)); + bp->ptp_clock = NULL; + return; + } else if (bp->ptp_clock == NULL) { + pr_err("ptp clock register failed\n"); + return; + } + + spin_lock_init(&bp->tsu_clk_lock); + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + queue->tx_ts_head = 0; + queue->tx_ts_tail = 0; + INIT_WORK(&queue->tx_ts_task, gem_tx_timestamp_flush); + } + + gem_ptp_init_tsu(bp); + + dev_info(&bp->pdev->dev, "%s ptp clock registered.\n", + GEM_PTP_TIMER_NAME); +} + +void gem_ptp_remove(struct net_device *ndev) +{ + struct macb *bp = netdev_priv(ndev); + + if (bp->ptp_clock) + ptp_clock_unregister(bp->ptp_clock); + + gem_ptp_clear_timer(bp); + + dev_info(&bp->pdev->dev, "%s ptp clock unregistered.\n", + GEM_PTP_TIMER_NAME); +} + +static int gem_ptp_set_ts_mode(struct macb *bp, + enum macb_bd_control tx_bd_control, + enum macb_bd_control rx_bd_control) +{ + gem_writel(bp, TXBDCTRL, GEM_BF(TXTSMODE, tx_bd_control)); + gem_writel(bp, RXBDCTRL, GEM_BF(RXTSMODE, rx_bd_control)); + + return 0; +} + +int gem_get_hwtst(struct net_device *dev, struct ifreq *rq) +{ + struct hwtstamp_config *tstamp_config; + struct macb *bp = netdev_priv(dev); + + tstamp_config = &bp->tstamp_config; + if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0) + return -EOPNOTSUPP; + + if (copy_to_user(rq->ifr_data, tstamp_config, sizeof(*tstamp_config))) + return -EFAULT; + else + return 0; +} + +static int gem_ptp_set_one_step_sync(struct macb *bp, u8 enable) +{ + u32 reg_val; + + reg_val = macb_readl(bp, NCR); + + if (enable) + macb_writel(bp, NCR, reg_val | MACB_BIT(OSSMODE)); + else + macb_writel(bp, NCR, reg_val & ~MACB_BIT(OSSMODE)); + + return 0; +} + +int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + enum macb_bd_control tx_bd_control = TSTAMP_DISABLED; + enum macb_bd_control rx_bd_control = TSTAMP_DISABLED; + struct hwtstamp_config *tstamp_config; + struct macb *bp = netdev_priv(dev); + u32 regval; + + tstamp_config = &bp->tstamp_config; + if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0) + return -EOPNOTSUPP; + + if (copy_from_user(tstamp_config, ifr->ifr_data, + sizeof(*tstamp_config))) + return -EFAULT; + + /* reserved for future extensions */ + if (tstamp_config->flags) + return -EINVAL; + + switch (tstamp_config->tx_type) { + case HWTSTAMP_TX_OFF: + break; + case HWTSTAMP_TX_ONESTEP_SYNC: + if (gem_ptp_set_one_step_sync(bp, 1) != 0) + return -ERANGE; + case HWTSTAMP_TX_ON: + tx_bd_control = TSTAMP_ALL_FRAMES; + break; + default: + return -ERANGE; + } + + switch (tstamp_config->rx_filter) { + case HWTSTAMP_FILTER_NONE: + break; + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + break; + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + break; + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + rx_bd_control = TSTAMP_ALL_PTP_FRAMES; + tstamp_config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + regval = macb_readl(bp, NCR); + macb_writel(bp, NCR, (regval | MACB_BIT(SRTSM))); + break; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_ALL: + rx_bd_control = TSTAMP_ALL_FRAMES; + tstamp_config->rx_filter = HWTSTAMP_FILTER_ALL; + break; + default: + tstamp_config->rx_filter = HWTSTAMP_FILTER_NONE; + return -ERANGE; + } + + if (gem_ptp_set_ts_mode(bp, tx_bd_control, rx_bd_control) != 0) + return -ERANGE; + + if (copy_to_user(ifr->ifr_data, tstamp_config, sizeof(*tstamp_config))) + return -EFAULT; + else + return 0; +} + -- cgit v1.2.3 From 633547973ffc32fd2c815639d4675e1531f0896f Mon Sep 17 00:00:00 2001 From: "Reshetova, Elena" Date: Fri, 30 Jun 2017 13:07:58 +0300 Subject: net: convert sk_buff.users from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Signed-off-by: David S. Miller --- drivers/infiniband/hw/nes/nes_cm.c | 4 ++-- drivers/isdn/mISDN/socket.c | 2 +- drivers/net/rionet.c | 2 +- drivers/s390/net/ctcm_main.c | 26 +++++++++++++------------- drivers/s390/net/netiucv.c | 10 +++++----- drivers/s390/net/qeth_core_main.c | 4 ++-- 6 files changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 30b256a2c54e..de4025deaa4a 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -742,7 +742,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, if (type == NES_TIMER_TYPE_SEND) { new_send->seq_num = ntohl(tcp_hdr(skb)->seq); - atomic_inc(&new_send->skb->users); + refcount_inc(&new_send->skb->users); spin_lock_irqsave(&cm_node->retrans_list_lock, flags); cm_node->send_entry = new_send; add_ref_cm_node(cm_node); @@ -924,7 +924,7 @@ static void nes_cm_timer_tick(unsigned long pass) flags); break; } - atomic_inc(&send_entry->skb->users); + refcount_inc(&send_entry->skb->users); cm_packets_retrans++; nes_debug(NES_DBG_CM, "Retransmitting send_entry %p " "for node %p, jiffies = %lu, time to send = " diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 99e5f9751e8b..c5603d1a07d6 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -155,7 +155,7 @@ mISDN_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, copied = skb->len + MISDN_HEADER_LEN; if (len < copied) { if (flags & MSG_PEEK) - atomic_dec(&skb->users); + refcount_dec(&skb->users); else skb_queue_head(&sk->sk_receive_queue, skb); return -ENOSPC; diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 300bb1479b3a..e9f101c9bae2 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -201,7 +201,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) rionet_queue_tx_msg(skb, ndev, nets[rnet->mport->id].active[i]); if (count) - atomic_inc(&skb->users); + refcount_inc(&skb->users); count++; } } else if (RIONET_MAC_MATCH(eth->h_dest)) { diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 99121352c57b..e8782a8619f7 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -483,7 +483,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb) spin_unlock_irqrestore(&ch->collect_lock, saveflags); return -EBUSY; } else { - atomic_inc(&skb->users); + refcount_inc(&skb->users); header.length = l; header.type = be16_to_cpu(skb->protocol); header.unused = 0; @@ -500,7 +500,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb) * Protect skb against beeing free'd by upper * layers. */ - atomic_inc(&skb->users); + refcount_inc(&skb->users); ch->prof.txlen += skb->len; header.length = skb->len + LL_HEADER_LENGTH; header.type = be16_to_cpu(skb->protocol); @@ -517,14 +517,14 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb) if (hi) { nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); if (!nskb) { - atomic_dec(&skb->users); + refcount_dec(&skb->users); skb_pull(skb, LL_HEADER_LENGTH + 2); ctcm_clear_busy(ch->netdev); return -ENOMEM; } else { skb_put_data(nskb, skb->data, skb->len); - atomic_inc(&nskb->users); - atomic_dec(&skb->users); + refcount_inc(&nskb->users); + refcount_dec(&skb->users); dev_kfree_skb_irq(skb); skb = nskb; } @@ -542,7 +542,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb) * Remove our header. It gets added * again on retransmit. */ - atomic_dec(&skb->users); + refcount_dec(&skb->users); skb_pull(skb, LL_HEADER_LENGTH + 2); ctcm_clear_busy(ch->netdev); return -ENOMEM; @@ -553,7 +553,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb) ch->ccw[1].count = skb->len; skb_copy_from_linear_data(skb, skb_put(ch->trans_skb, skb->len), skb->len); - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_irq(skb); ccw_idx = 0; } else { @@ -679,7 +679,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) if ((fsm_getstate(ch->fsm) != CTC_STATE_TXIDLE) || grp->in_sweep) { spin_lock_irqsave(&ch->collect_lock, saveflags); - atomic_inc(&skb->users); + refcount_inc(&skb->users); p_header = kmalloc(PDU_HEADER_LENGTH, gfp_type()); if (!p_header) { @@ -716,7 +716,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) * Protect skb against beeing free'd by upper * layers. */ - atomic_inc(&skb->users); + refcount_inc(&skb->users); /* * IDAL support in CTCM is broken, so we have to @@ -729,8 +729,8 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) goto nomem_exit; } else { skb_put_data(nskb, skb->data, skb->len); - atomic_inc(&nskb->users); - atomic_dec(&skb->users); + refcount_inc(&nskb->users); + refcount_dec(&skb->users); dev_kfree_skb_irq(skb); skb = nskb; } @@ -810,7 +810,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) ch->trans_skb->len = 0; ch->ccw[1].count = skb->len; skb_put_data(ch->trans_skb, skb->data, skb->len); - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_irq(skb); ccw_idx = 0; CTCM_PR_DBGDATA("%s(%s): trans_skb len: %04x\n" @@ -855,7 +855,7 @@ nomem_exit: "%s(%s): MEMORY allocation ERROR\n", CTCM_FUNTAIL, ch->id); rc = -ENOMEM; - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_any(skb); fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev); done: diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 7db427c0a6a4..1579695f4e64 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -743,7 +743,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) conn->prof.tx_pending--; if (single_flag) { if ((skb = skb_dequeue(&conn->commit_queue))) { - atomic_dec(&skb->users); + refcount_dec(&skb->users); if (privptr) { privptr->stats.tx_packets++; privptr->stats.tx_bytes += @@ -766,7 +766,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) txbytes += skb->len; txpackets++; stat_maxcq++; - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_any(skb); } if (conn->collect_len > conn->prof.maxmulti) @@ -958,7 +958,7 @@ static void netiucv_purge_skb_queue(struct sk_buff_head *q) struct sk_buff *skb; while ((skb = skb_dequeue(q))) { - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_any(skb); } } @@ -1176,7 +1176,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, IUCV_DBF_TEXT(data, 2, "EBUSY from netiucv_transmit_skb\n"); } else { - atomic_inc(&skb->users); + refcount_inc(&skb->users); skb_queue_tail(&conn->collect_queue, skb); conn->collect_len += l; rc = 0; @@ -1245,7 +1245,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, } else { if (copied) dev_kfree_skb(skb); - atomic_inc(&nskb->users); + refcount_inc(&nskb->users); skb_queue_tail(&conn->commit_queue, nskb); } } diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3b657d5b7e49..aec06e10b969 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1242,7 +1242,7 @@ static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR); } } - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_any(skb); skb = skb_dequeue(&buf->skb_list); } @@ -3975,7 +3975,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, int flush_cnt = 0, hdr_len, large_send = 0; buffer = buf->buffer; - atomic_inc(&skb->users); + refcount_inc(&skb->users); skb_queue_tail(&buf->skb_list, skb); /*check first on TSO ....*/ -- cgit v1.2.3 From 14afee4b6092fde451ee17604e5f5c89da33e71e Mon Sep 17 00:00:00 2001 From: "Reshetova, Elena" Date: Fri, 30 Jun 2017 13:08:00 +0300 Subject: net: convert sock.sk_wmem_alloc from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Signed-off-by: David S. Miller --- drivers/atm/fore200e.c | 12 +----------- drivers/atm/he.c | 2 +- drivers/atm/idt77252.c | 4 ++-- 3 files changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 7584ae1ded85..f0433adcd8fc 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -924,12 +924,7 @@ fore200e_tx_irq(struct fore200e* fore200e) else { dev_kfree_skb_any(entry->skb); } -#if 1 - /* race fixed by the above incarnation mechanism, but... */ - if (atomic_read(&sk_atm(vcc)->sk_wmem_alloc) < 0) { - atomic_set(&sk_atm(vcc)->sk_wmem_alloc, 0); - } -#endif + /* check error condition */ if (*entry->status & STATUS_ERROR) atomic_inc(&vcc->stats->tx_err); @@ -1130,13 +1125,9 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp return -ENOMEM; } - ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0); - vcc->push(vcc, skb); atomic_inc(&vcc->stats->rx); - ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0); - return 0; } @@ -1572,7 +1563,6 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) unsigned long flags; ASSERT(vcc); - ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0); ASSERT(fore200e); ASSERT(fore200e_vcc); diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 461da2bce8ef..37ee21c5a5ca 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -2395,7 +2395,7 @@ he_close(struct atm_vcc *vcc) * TBRQ, the host issues the close command to the adapter. */ - while (((tx_inuse = atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) && + while (((tx_inuse = refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) && (retry < MAX_RETRY)) { msleep(sleep); if (sleep < 250) diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 4e64de380bda..60bacba03d17 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -724,7 +724,7 @@ push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb) struct sock *sk = sk_atm(vcc); vc->estimator->cells += (skb->len + 47) / 48; - if (atomic_read(&sk->sk_wmem_alloc) > + if (refcount_read(&sk->sk_wmem_alloc) > (sk->sk_sndbuf >> 1)) { u32 cps = vc->estimator->maxcps; @@ -2009,7 +2009,7 @@ idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags) atomic_inc(&vcc->stats->tx_err); return -ENOMEM; } - atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); + refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); skb_put_data(skb, cell, 52); -- cgit v1.2.3 From 8f15df600dff00c8f28c8588bdd4dca55dff690b Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 29 Jun 2017 22:08:12 +0200 Subject: nfp: add phys_switch_id support Add phys_switch_id support by allowing lookup of SWITCHDEV_ATTR_ID_PORT_PARENT_ID via the nfp_repr_port_attr_get switchdev operation. This is visible to user-space in the phys_switch_id attribute of a netdev. e.g. cd /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 find . -name phys_switch_id | xargs grep . ./net/eth3/phys_switch_id:00154d1300bd ./net/eth4/phys_switch_id:00154d1300bd ./net/eth2/phys_switch_id:00154d1300bd grep: ./net/eth5/phys_switch_id: Operation not supported In the above eth2 and eth3 and representor netdevs for the first and second physical port. eth4 is the representor for the PF. And eth5 is the PF netdev. Signed-off-by: Simon Horman Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 3 +++ drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 2 ++ drivers/net/ethernet/netronome/nfp/nfp_port.c | 29 ++++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/nfp_port.h | 2 ++ 4 files changed, 36 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 2e728543e840..b5834525c5f0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -64,6 +64,7 @@ #include #include +#include #include #include "nfpcore/nfp_nsp.h" @@ -3703,6 +3704,8 @@ static void nfp_net_netdev_init(struct nfp_net *nn) netdev->netdev_ops = &nfp_net_netdev_ops; netdev->watchdog_timeo = msecs_to_jiffies(5 * 1000); + SWITCHDEV_SET_OPS(netdev, &nfp_port_switchdev_ops); + /* MTU range: 68 - hw-specific max */ netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = nn->max_mtu; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 046b89eb4cf2..bc9108071e5b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "nfpcore/nfp_cpp.h" #include "nfpcore/nfp_nsp.h" @@ -299,6 +300,7 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, repr->dst->u.port_info.lower_dev = pf_netdev; netdev->netdev_ops = &nfp_repr_netdev_ops; + SWITCHDEV_SET_OPS(netdev, &nfp_port_switchdev_ops); err = register_netdev(netdev); if (err) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 0b44952945d8..3aa834fb2250 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -32,6 +32,7 @@ */ #include +#include #include "nfpcore/nfp_cpp.h" #include "nfpcore/nfp_nsp.h" @@ -59,6 +60,34 @@ struct nfp_port *nfp_port_from_netdev(struct net_device *netdev) return NULL; } +static int +nfp_port_attr_get(struct net_device *netdev, struct switchdev_attr *attr) +{ + struct nfp_port *port; + + port = nfp_port_from_netdev(netdev); + if (!port) + return -EOPNOTSUPP; + + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: { + const u8 *serial; + /* N.B: attr->u.ppid.id is binary data */ + attr->u.ppid.id_len = nfp_cpp_serial(port->app->cpp, &serial); + memcpy(&attr->u.ppid.id, serial, attr->u.ppid.id_len); + break; + } + default: + return -EOPNOTSUPP; + } + + return 0; +} + +const struct switchdev_ops nfp_port_switchdev_ops = { + .switchdev_port_attr_get = nfp_port_attr_get, +}; + struct nfp_port * nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 57d852a4ca59..1ceef5d4a744 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -106,6 +106,8 @@ struct nfp_port { struct list_head port_list; }; +extern const struct switchdev_ops nfp_port_switchdev_ops; + struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); struct nfp_port * nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id); -- cgit v1.2.3 From 8a2768732a4dfdaabdbea18603330922fb0ee773 Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Thu, 29 Jun 2017 22:08:13 +0200 Subject: nfp: provide infrastructure for offloading flower based TC filters Adds a flower based TC offload handler for representor devices, this is in addition to the bpf based offload handler. The changes in this patch will be used in a follow-up patch to add tc flower offload to the NFP. The flower app enables tc offloads on representors by default. Signed-off-by: Pieter Jansen van Vuuren Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 3 +- drivers/net/ethernet/netronome/nfp/flower/main.c | 20 ++++ drivers/net/ethernet/netronome/nfp/flower/main.h | 45 ++++++++ .../net/ethernet/netronome/nfp/flower/offload.c | 127 +++++++++++++++++++++ .../net/ethernet/netronome/nfp/nfp_net_common.c | 14 +-- drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 6 + drivers/net/ethernet/netronome/nfp/nfp_port.c | 15 +++ drivers/net/ethernet/netronome/nfp/nfp_port.h | 4 + 8 files changed, 220 insertions(+), 14 deletions(-) create mode 100644 drivers/net/ethernet/netronome/nfp/flower/main.h create mode 100644 drivers/net/ethernet/netronome/nfp/flower/offload.c (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 43bdbc228969..d7afd2b410fe 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -32,7 +32,8 @@ nfp-objs := \ ifeq ($(CONFIG_NFP_APP_FLOWER),y) nfp-objs += \ flower/cmsg.o \ - flower/main.o + flower/main.o \ + flower/offload.o endif ifeq ($(CONFIG_BPF_SYSCALL),y) diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index ab68a8f58862..7bf994ceb9c1 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -37,7 +37,9 @@ #include #include +#include "main.h" #include "../nfpcore/nfp_cpp.h" +#include "../nfpcore/nfp_nffw.h" #include "../nfpcore/nfp_nsp.h" #include "../nfp_app.h" #include "../nfp_main.h" @@ -46,6 +48,8 @@ #include "../nfp_port.h" #include "./cmsg.h" +#define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL + /** * struct nfp_flower_priv - Flower APP per-vNIC priv data * @nn: Pointer to vNIC @@ -313,6 +317,8 @@ err_invalid_port: static int nfp_flower_init(struct nfp_app *app) { const struct nfp_pf *pf = app->pf; + u64 version; + int err; if (!pf->eth_tbl) { nfp_warn(app->cpp, "FlowerNIC requires eth table\n"); @@ -329,6 +335,18 @@ static int nfp_flower_init(struct nfp_app *app) return -EINVAL; } + version = nfp_rtsym_read_le(app->pf->rtbl, "hw_flower_version", &err); + if (err) { + nfp_warn(app->cpp, "FlowerNIC requires hw_flower_version memory symbol\n"); + return err; + } + + /* We need to ensure hardware has enough flower capabilities. */ + if (version != NFP_FLOWER_ALLOWED_VER) { + nfp_warn(app->cpp, "FlowerNIC: unsupported firmware version\n"); + return -EINVAL; + } + app->priv = kzalloc(sizeof(struct nfp_flower_priv), GFP_KERNEL); if (!app->priv) return -ENOMEM; @@ -367,4 +385,6 @@ const struct nfp_app_type app_flower = { .eswitch_mode_get = eswitch_mode_get, .repr_get = nfp_flower_repr_get, + + .setup_tc = nfp_flower_setup_tc, }; diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h new file mode 100644 index 000000000000..c7a19527875e --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __NFP_FLOWER_H__ +#define __NFP_FLOWER_H__ 1 + +#include + +struct tc_to_netdev; +struct net_device; +struct nfp_app; + +int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev, + u32 handle, __be16 proto, struct tc_to_netdev *tc); +#endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c new file mode 100644 index 000000000000..2fe0353292fc --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "cmsg.h" +#include "main.h" +#include "../nfpcore/nfp_cpp.h" +#include "../nfpcore/nfp_nsp.h" +#include "../nfp_app.h" +#include "../nfp_main.h" +#include "../nfp_net.h" +#include "../nfp_port.h" + +/** + * nfp_flower_add_offload() - Adds a new flow to hardware. + * @app: Pointer to the APP handle + * @netdev: netdev structure. + * @flow: TC flower classifier offload structure. + * + * Adds a new flow to the repeated hash structure and action payload. + * + * Return: negative value on error, 0 if configured successfully. + */ +static int +nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, + struct tc_cls_flower_offload *flow) +{ + return -EOPNOTSUPP; +} + +/** + * nfp_flower_del_offload() - Removes a flow from hardware. + * @app: Pointer to the APP handle + * @netdev: netdev structure. + * @flow: TC flower classifier offload structure + * + * Removes a flow from the repeated hash structure and clears the + * action payload. + * + * Return: negative value on error, 0 if removed successfully. + */ +static int +nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, + struct tc_cls_flower_offload *flow) +{ + return -EOPNOTSUPP; +} + +/** + * nfp_flower_get_stats() - Populates flow stats obtained from hardware. + * @app: Pointer to the APP handle + * @flow: TC flower classifier offload structure + * + * Populates a flow statistics structure which which corresponds to a + * specific flow. + * + * Return: negative value on error, 0 if stats populated successfully. + */ +static int +nfp_flower_get_stats(struct nfp_app *app, struct tc_cls_flower_offload *flow) +{ + return -EOPNOTSUPP; +} + +static int +nfp_flower_repr_offload(struct nfp_app *app, struct net_device *netdev, + struct tc_cls_flower_offload *flower) +{ + switch (flower->command) { + case TC_CLSFLOWER_REPLACE: + return nfp_flower_add_offload(app, netdev, flower); + case TC_CLSFLOWER_DESTROY: + return nfp_flower_del_offload(app, netdev, flower); + case TC_CLSFLOWER_STATS: + return nfp_flower_get_stats(app, flower); + } + + return -EOPNOTSUPP; +} + +int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev, + u32 handle, __be16 proto, struct tc_to_netdev *tc) +{ + if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS)) + return -EOPNOTSUPP; + + if (!eth_proto_is_802_3(proto)) + return -EOPNOTSUPP; + + if (tc->type != TC_SETUP_CLSFLOWER) + return -EINVAL; + + return nfp_flower_repr_offload(app, netdev, tc->cls_flower); +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index b5834525c5f0..30f82b41d400 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3097,18 +3097,6 @@ static void nfp_net_stat64(struct net_device *netdev, } } -static int -nfp_net_setup_tc(struct net_device *netdev, u32 handle, u32 chain_index, - __be16 proto, struct tc_to_netdev *tc) -{ - struct nfp_net *nn = netdev_priv(netdev); - - if (chain_index) - return -EOPNOTSUPP; - - return nfp_app_setup_tc(nn->app, netdev, handle, proto, tc); -} - static int nfp_net_set_features(struct net_device *netdev, netdev_features_t features) { @@ -3424,7 +3412,7 @@ const struct net_device_ops nfp_net_netdev_ops = { .ndo_get_stats64 = nfp_net_stat64, .ndo_vlan_rx_add_vid = nfp_net_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = nfp_net_vlan_rx_kill_vid, - .ndo_setup_tc = nfp_net_setup_tc, + .ndo_setup_tc = nfp_port_setup_tc, .ndo_tx_timeout = nfp_net_tx_timeout, .ndo_set_rx_mode = nfp_net_set_rx_mode, .ndo_change_mtu = nfp_net_change_mtu, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index bc9108071e5b..8ec5474f4b18 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -258,6 +258,7 @@ const struct net_device_ops nfp_repr_netdev_ops = { .ndo_has_offload_stats = nfp_repr_has_offload_stats, .ndo_get_offload_stats = nfp_repr_get_offload_stats, .ndo_get_phys_port_name = nfp_port_get_phys_port_name, + .ndo_setup_tc = nfp_port_setup_tc, }; static void nfp_repr_clean(struct nfp_repr *repr) @@ -302,6 +303,11 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, netdev->netdev_ops = &nfp_repr_netdev_ops; SWITCHDEV_SET_OPS(netdev, &nfp_port_switchdev_ops); + if (nfp_app_has_tc(app)) { + netdev->features |= NETIF_F_HW_TC; + netdev->hw_features |= NETIF_F_HW_TC; + } + err = register_netdev(netdev); if (err) goto err_clean; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 3aa834fb2250..776e54dd5dd0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -88,6 +88,21 @@ const struct switchdev_ops nfp_port_switchdev_ops = { .switchdev_port_attr_get = nfp_port_attr_get, }; +int nfp_port_setup_tc(struct net_device *netdev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc) +{ + struct nfp_port *port; + + if (chain_index) + return -EOPNOTSUPP; + + port = nfp_port_from_netdev(netdev); + if (!port) + return -EOPNOTSUPP; + + return nfp_app_setup_tc(port->app, netdev, handle, proto, tc); +} + struct nfp_port * nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.h b/drivers/net/ethernet/netronome/nfp/nfp_port.h index 1ceef5d4a744..a33d22e18f94 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.h @@ -36,6 +36,7 @@ #include +struct tc_to_netdev; struct net_device; struct nfp_app; struct nfp_pf; @@ -108,6 +109,9 @@ struct nfp_port { extern const struct switchdev_ops nfp_port_switchdev_ops; +int nfp_port_setup_tc(struct net_device *netdev, u32 handle, u32 chain_index, + __be16 proto, struct tc_to_netdev *tc); + struct nfp_port *nfp_port_from_netdev(struct net_device *netdev); struct nfp_port * nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id); -- cgit v1.2.3 From af9d842c13549cf306259b7b9c932c6c885ba94b Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Thu, 29 Jun 2017 22:08:14 +0200 Subject: nfp: extend flower add flow offload Extends the flower flow add function by calculating which match fields are present in the flower offload structure and allocating the appropriate space to describe these. Signed-off-by: Pieter Jansen van Vuuren Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 141 ++++++++++++++++++ drivers/net/ethernet/netronome/nfp/flower/main.h | 24 +++ .../net/ethernet/netronome/nfp/flower/offload.c | 161 ++++++++++++++++++++- 3 files changed, 325 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index c10ae7631941..1b1888e8dc14 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -40,6 +40,147 @@ #include "../nfp_app.h" +#define NFP_FLOWER_LAYER_META BIT(0) +#define NFP_FLOWER_LAYER_PORT BIT(1) +#define NFP_FLOWER_LAYER_MAC BIT(2) +#define NFP_FLOWER_LAYER_TP BIT(3) +#define NFP_FLOWER_LAYER_IPV4 BIT(4) +#define NFP_FLOWER_LAYER_IPV6 BIT(5) +#define NFP_FLOWER_LAYER_CT BIT(6) +#define NFP_FLOWER_LAYER_VXLAN BIT(7) + +#define NFP_FLOWER_LAYER_ETHER BIT(3) +#define NFP_FLOWER_LAYER_ARP BIT(4) + +/* Metadata without L2 (1W/4B) + * ---------------------------------------------------------------- + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | key_layers | mask_id | reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct nfp_flower_meta_one { + u8 nfp_flow_key_layer; + u8 mask_id; + u16 reserved; +}; + +/* Metadata with L2 (1W/4B) + * ---------------------------------------------------------------- + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | key_type | mask_id | PCP |p| vlan outermost VID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ^ ^ + * NOTE: | TCI | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct nfp_flower_meta_two { + u8 nfp_flow_key_layer; + u8 mask_id; + __be16 tci; +}; + +/* Port details (1W/4B) + * ---------------------------------------------------------------- + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | port_ingress | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct nfp_flower_in_port { + __be32 in_port; +}; + +/* L2 details (4W/16B) + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | mac_addr_dst, 31 - 0 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | mac_addr_dst, 47 - 32 | mac_addr_src, 15 - 0 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | mac_addr_src, 47 - 16 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | mpls outermost label | TC |B| reserved |q| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct nfp_flower_mac_mpls { + u8 mac_dst[6]; + u8 mac_src[6]; + __be32 mpls_lse; +}; + +/* L4 ports (for UDP, TCP, SCTP) (1W/4B) + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | port_src | port_dst | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct nfp_flower_tp_ports { + __be16 port_src; + __be16 port_dst; +}; + +/* L3 IPv4 details (3W/12B) + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | DSCP |ECN| protocol | reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv4_addr_src | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv4_addr_dst | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct nfp_flower_ipv4 { + u8 tos; + u8 proto; + u8 ttl; + u8 reserved; + __be32 ipv4_src; + __be32 ipv4_dst; +}; + +/* L3 IPv6 details (10W/40B) + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | DSCP |ECN| protocol | reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv6_exthdr | res | ipv6_flow_label | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv6_addr_src, 31 - 0 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv6_addr_src, 63 - 32 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv6_addr_src, 95 - 64 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv6_addr_src, 127 - 96 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv6_addr_dst, 31 - 0 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv6_addr_dst, 63 - 32 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv6_addr_dst, 95 - 64 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ipv6_addr_dst, 127 - 96 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct nfp_flower_ipv6 { + u8 tos; + u8 proto; + u8 ttl; + u8 reserved; + __be32 ipv6_flow_label_exthdr; + struct in6_addr ipv6_src; + struct in6_addr ipv6_dst; +}; + /* The base header for a control message packet. * Defines an 8-bit version, and an 8-bit type, padded * to a 32-bit word. Rest of the packet is type-specific. diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index c7a19527875e..ba3e14c3ec26 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -40,6 +40,30 @@ struct tc_to_netdev; struct net_device; struct nfp_app; +struct nfp_fl_key_ls { + u32 key_layer_two; + u8 key_layer; + int key_size; +}; + +struct nfp_fl_rule_metadata { + u8 key_len; + u8 mask_len; + u8 act_len; + u8 flags; + __be32 host_ctx_id; + __be64 host_cookie __packed; + __be64 flow_version __packed; + __be32 shortcut; +}; + +struct nfp_fl_payload { + struct nfp_fl_rule_metadata meta; + char *unmasked_data; + char *mask_data; + char *action_data; +}; + int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev, u32 handle, __be16 proto, struct tc_to_netdev *tc); #endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 2fe0353292fc..fb9f73ab16c9 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -44,6 +44,138 @@ #include "../nfp_net.h" #include "../nfp_port.h" +static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f) +{ + return dissector_uses_key(f->dissector, + FLOW_DISSECTOR_KEY_IPV4_ADDRS) || + dissector_uses_key(f->dissector, + FLOW_DISSECTOR_KEY_IPV6_ADDRS) || + dissector_uses_key(f->dissector, + FLOW_DISSECTOR_KEY_PORTS) || + dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ICMP); +} + +static int +nfp_flower_calculate_key_layers(struct nfp_fl_key_ls *ret_key_ls, + struct tc_cls_flower_offload *flow) +{ + struct flow_dissector_key_control *mask_enc_ctl; + struct flow_dissector_key_basic *mask_basic; + struct flow_dissector_key_basic *key_basic; + u32 key_layer_two; + u8 key_layer; + int key_size; + + mask_enc_ctl = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_ENC_CONTROL, + flow->mask); + + mask_basic = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_BASIC, + flow->mask); + + key_basic = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_BASIC, + flow->key); + key_layer_two = 0; + key_layer = NFP_FLOWER_LAYER_PORT | NFP_FLOWER_LAYER_MAC; + key_size = sizeof(struct nfp_flower_meta_one) + + sizeof(struct nfp_flower_in_port) + + sizeof(struct nfp_flower_mac_mpls); + + /* We are expecting a tunnel. For now we ignore offloading. */ + if (mask_enc_ctl->addr_type) + return -EOPNOTSUPP; + + if (mask_basic->n_proto) { + /* Ethernet type is present in the key. */ + switch (key_basic->n_proto) { + case cpu_to_be16(ETH_P_IP): + key_layer |= NFP_FLOWER_LAYER_IPV4; + key_size += sizeof(struct nfp_flower_ipv4); + break; + + case cpu_to_be16(ETH_P_IPV6): + key_layer |= NFP_FLOWER_LAYER_IPV6; + key_size += sizeof(struct nfp_flower_ipv6); + break; + + /* Currently we do not offload ARP + * because we rely on it to get to the host. + */ + case cpu_to_be16(ETH_P_ARP): + return -EOPNOTSUPP; + + /* Will be included in layer 2. */ + case cpu_to_be16(ETH_P_8021Q): + break; + + default: + /* Other ethtype - we need check the masks for the + * remainder of the key to ensure we can offload. + */ + if (nfp_flower_check_higher_than_mac(flow)) + return -EOPNOTSUPP; + break; + } + } + + if (mask_basic->ip_proto) { + /* Ethernet type is present in the key. */ + switch (key_basic->ip_proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_SCTP: + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + key_layer |= NFP_FLOWER_LAYER_TP; + key_size += sizeof(struct nfp_flower_tp_ports); + break; + default: + /* Other ip proto - we need check the masks for the + * remainder of the key to ensure we can offload. + */ + return -EOPNOTSUPP; + } + } + + ret_key_ls->key_layer = key_layer; + ret_key_ls->key_layer_two = key_layer_two; + ret_key_ls->key_size = key_size; + + return 0; +} + +static struct nfp_fl_payload * +nfp_flower_allocate_new(struct nfp_fl_key_ls *key_layer) +{ + struct nfp_fl_payload *flow_pay; + + flow_pay = kmalloc(sizeof(*flow_pay), GFP_KERNEL); + if (!flow_pay) + return NULL; + + flow_pay->meta.key_len = key_layer->key_size; + flow_pay->unmasked_data = kmalloc(key_layer->key_size, GFP_KERNEL); + if (!flow_pay->unmasked_data) + goto err_free_flow; + + flow_pay->meta.mask_len = key_layer->key_size; + flow_pay->mask_data = kmalloc(key_layer->key_size, GFP_KERNEL); + if (!flow_pay->mask_data) + goto err_free_unmasked; + + flow_pay->meta.flags = 0; + + return flow_pay; + +err_free_unmasked: + kfree(flow_pay->unmasked_data); +err_free_flow: + kfree(flow_pay); + return NULL; +} + /** * nfp_flower_add_offload() - Adds a new flow to hardware. * @app: Pointer to the APP handle @@ -58,7 +190,34 @@ static int nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, struct tc_cls_flower_offload *flow) { - return -EOPNOTSUPP; + struct nfp_fl_payload *flow_pay; + struct nfp_fl_key_ls *key_layer; + int err; + + key_layer = kmalloc(sizeof(*key_layer), GFP_KERNEL); + if (!key_layer) + return -ENOMEM; + + err = nfp_flower_calculate_key_layers(key_layer, flow); + if (err) + goto err_free_key_ls; + + flow_pay = nfp_flower_allocate_new(key_layer); + if (!flow_pay) { + err = -ENOMEM; + goto err_free_key_ls; + } + + /* TODO: Complete flower_add_offload. */ + err = -EOPNOTSUPP; + + kfree(flow_pay->mask_data); + kfree(flow_pay->unmasked_data); + kfree(flow_pay); + +err_free_key_ls: + kfree(key_layer); + return err; } /** -- cgit v1.2.3 From 5571e8c9f2419c19916d4a707ba359602e0a85d7 Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Thu, 29 Jun 2017 22:08:15 +0200 Subject: nfp: extend flower matching capabilities Extends matching capabilities for flower offloads to include vlan, layer 2, layer 3 and layer 4 type matches. This includes both exact and wildcard matching. Signed-off-by: Pieter Jansen van Vuuren Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 1 + drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 4 + drivers/net/ethernet/netronome/nfp/flower/main.h | 5 + drivers/net/ethernet/netronome/nfp/flower/match.c | 292 +++++++++++++++++++++ .../net/ethernet/netronome/nfp/flower/offload.c | 6 +- drivers/net/ethernet/netronome/nfp/nfp_net_repr.h | 9 + 6 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/netronome/nfp/flower/match.c (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index d7afd2b410fe..018cef3fa10a 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -33,6 +33,7 @@ ifeq ($(CONFIG_NFP_APP_FLOWER),y) nfp-objs += \ flower/cmsg.o \ flower/main.o \ + flower/match.o \ flower/offload.o endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index 1b1888e8dc14..1956c1acf39f 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -52,6 +52,10 @@ #define NFP_FLOWER_LAYER_ETHER BIT(3) #define NFP_FLOWER_LAYER_ARP BIT(4) +#define NFP_FLOWER_MASK_VLAN_PRIO GENMASK(15, 13) +#define NFP_FLOWER_MASK_VLAN_CFI BIT(12) +#define NFP_FLOWER_MASK_VLAN_VID GENMASK(11, 0) + /* Metadata without L2 (1W/4B) * ---------------------------------------------------------------- * 3 2 1 diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index ba3e14c3ec26..5ba7e5194708 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -66,4 +66,9 @@ struct nfp_fl_payload { int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev, u32 handle, __be16 proto, struct tc_to_netdev *tc); +int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow, + struct nfp_fl_key_ls *key_ls, + struct net_device *netdev, + struct nfp_fl_payload *nfp_flow); + #endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/match.c b/drivers/net/ethernet/netronome/nfp/flower/match.c new file mode 100644 index 000000000000..0e08404480ef --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/flower/match.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "cmsg.h" +#include "main.h" + +static void +nfp_flower_compile_meta_tci(struct nfp_flower_meta_two *frame, + struct tc_cls_flower_offload *flow, u8 key_type, + bool mask_version) +{ + struct flow_dissector_key_vlan *flow_vlan; + u16 tmp_tci; + + /* Populate the metadata frame. */ + frame->nfp_flow_key_layer = key_type; + frame->mask_id = ~0; + + if (mask_version) { + frame->tci = cpu_to_be16(~0); + return; + } + + flow_vlan = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_VLAN, + flow->key); + + /* Populate the tci field. */ + if (!flow_vlan->vlan_id) { + tmp_tci = 0; + } else { + tmp_tci = FIELD_PREP(NFP_FLOWER_MASK_VLAN_PRIO, + flow_vlan->vlan_priority) | + FIELD_PREP(NFP_FLOWER_MASK_VLAN_VID, + flow_vlan->vlan_id) | + NFP_FLOWER_MASK_VLAN_CFI; + } + frame->tci = cpu_to_be16(tmp_tci); +} + +static void +nfp_flower_compile_meta(struct nfp_flower_meta_one *frame, u8 key_type) +{ + frame->nfp_flow_key_layer = key_type; + frame->mask_id = 0; + frame->reserved = 0; +} + +static int +nfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port, + bool mask_version) +{ + if (mask_version) { + frame->in_port = cpu_to_be32(~0); + return 0; + } + + frame->in_port = cpu_to_be32(cmsg_port); + + return 0; +} + +static void +nfp_flower_compile_mac(struct nfp_flower_mac_mpls *frame, + struct tc_cls_flower_offload *flow, + bool mask_version) +{ + struct fl_flow_key *target = mask_version ? flow->mask : flow->key; + struct flow_dissector_key_eth_addrs *flow_mac; + + flow_mac = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_ETH_ADDRS, + target); + + memset(frame, 0, sizeof(struct nfp_flower_mac_mpls)); + + /* Populate mac frame. */ + ether_addr_copy(frame->mac_dst, &flow_mac->dst[0]); + ether_addr_copy(frame->mac_src, &flow_mac->src[0]); + + if (mask_version) + frame->mpls_lse = cpu_to_be32(~0); +} + +static void +nfp_flower_compile_tport(struct nfp_flower_tp_ports *frame, + struct tc_cls_flower_offload *flow, + bool mask_version) +{ + struct fl_flow_key *target = mask_version ? flow->mask : flow->key; + struct flow_dissector_key_ports *flow_tp; + + flow_tp = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_PORTS, + target); + + frame->port_src = flow_tp->src; + frame->port_dst = flow_tp->dst; +} + +static void +nfp_flower_compile_ipv4(struct nfp_flower_ipv4 *frame, + struct tc_cls_flower_offload *flow, + bool mask_version) +{ + struct fl_flow_key *target = mask_version ? flow->mask : flow->key; + struct flow_dissector_key_ipv4_addrs *flow_ipv4; + struct flow_dissector_key_basic *flow_basic; + + flow_ipv4 = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_IPV4_ADDRS, + target); + + flow_basic = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_BASIC, + target); + + /* Populate IPv4 frame. */ + frame->reserved = 0; + frame->ipv4_src = flow_ipv4->src; + frame->ipv4_dst = flow_ipv4->dst; + frame->proto = flow_basic->ip_proto; + /* Wildcard TOS/TTL for now. */ + frame->tos = 0; + frame->ttl = 0; +} + +static void +nfp_flower_compile_ipv6(struct nfp_flower_ipv6 *frame, + struct tc_cls_flower_offload *flow, + bool mask_version) +{ + struct fl_flow_key *target = mask_version ? flow->mask : flow->key; + struct flow_dissector_key_ipv6_addrs *flow_ipv6; + struct flow_dissector_key_basic *flow_basic; + + flow_ipv6 = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_IPV6_ADDRS, + target); + + flow_basic = skb_flow_dissector_target(flow->dissector, + FLOW_DISSECTOR_KEY_BASIC, + target); + + /* Populate IPv6 frame. */ + frame->reserved = 0; + frame->ipv6_src = flow_ipv6->src; + frame->ipv6_dst = flow_ipv6->dst; + frame->proto = flow_basic->ip_proto; + /* Wildcard LABEL/TOS/TTL for now. */ + frame->ipv6_flow_label_exthdr = 0; + frame->tos = 0; + frame->ttl = 0; +} + +int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow, + struct nfp_fl_key_ls *key_ls, + struct net_device *netdev, + struct nfp_fl_payload *nfp_flow) +{ + int err; + u8 *ext; + u8 *msk; + + memset(nfp_flow->unmasked_data, 0, key_ls->key_size); + memset(nfp_flow->mask_data, 0, key_ls->key_size); + + ext = nfp_flow->unmasked_data; + msk = nfp_flow->mask_data; + if (NFP_FLOWER_LAYER_PORT & key_ls->key_layer) { + /* Populate Exact Metadata. */ + nfp_flower_compile_meta_tci((struct nfp_flower_meta_two *)ext, + flow, key_ls->key_layer, false); + /* Populate Mask Metadata. */ + nfp_flower_compile_meta_tci((struct nfp_flower_meta_two *)msk, + flow, key_ls->key_layer, true); + ext += sizeof(struct nfp_flower_meta_two); + msk += sizeof(struct nfp_flower_meta_two); + + /* Populate Exact Port data. */ + err = nfp_flower_compile_port((struct nfp_flower_in_port *)ext, + nfp_repr_get_port_id(netdev), + false); + if (err) + return err; + + /* Populate Mask Port Data. */ + err = nfp_flower_compile_port((struct nfp_flower_in_port *)msk, + nfp_repr_get_port_id(netdev), + true); + if (err) + return err; + + ext += sizeof(struct nfp_flower_in_port); + msk += sizeof(struct nfp_flower_in_port); + } else { + /* Populate Exact Metadata. */ + nfp_flower_compile_meta((struct nfp_flower_meta_one *)ext, + key_ls->key_layer); + /* Populate Mask Metadata. */ + nfp_flower_compile_meta((struct nfp_flower_meta_one *)msk, + key_ls->key_layer); + ext += sizeof(struct nfp_flower_meta_one); + msk += sizeof(struct nfp_flower_meta_one); + } + + if (NFP_FLOWER_LAYER_META & key_ls->key_layer) { + /* Additional Metadata Fields. + * Currently unsupported. + */ + return -EOPNOTSUPP; + } + + if (NFP_FLOWER_LAYER_MAC & key_ls->key_layer) { + /* Populate Exact MAC Data. */ + nfp_flower_compile_mac((struct nfp_flower_mac_mpls *)ext, + flow, false); + /* Populate Mask MAC Data. */ + nfp_flower_compile_mac((struct nfp_flower_mac_mpls *)msk, + flow, true); + ext += sizeof(struct nfp_flower_mac_mpls); + msk += sizeof(struct nfp_flower_mac_mpls); + } + + if (NFP_FLOWER_LAYER_TP & key_ls->key_layer) { + /* Populate Exact TP Data. */ + nfp_flower_compile_tport((struct nfp_flower_tp_ports *)ext, + flow, false); + /* Populate Mask TP Data. */ + nfp_flower_compile_tport((struct nfp_flower_tp_ports *)msk, + flow, true); + ext += sizeof(struct nfp_flower_tp_ports); + msk += sizeof(struct nfp_flower_tp_ports); + } + + if (NFP_FLOWER_LAYER_IPV4 & key_ls->key_layer) { + /* Populate Exact IPv4 Data. */ + nfp_flower_compile_ipv4((struct nfp_flower_ipv4 *)ext, + flow, false); + /* Populate Mask IPv4 Data. */ + nfp_flower_compile_ipv4((struct nfp_flower_ipv4 *)msk, + flow, true); + ext += sizeof(struct nfp_flower_ipv4); + msk += sizeof(struct nfp_flower_ipv4); + } + + if (NFP_FLOWER_LAYER_IPV6 & key_ls->key_layer) { + /* Populate Exact IPv4 Data. */ + nfp_flower_compile_ipv6((struct nfp_flower_ipv6 *)ext, + flow, false); + /* Populate Mask IPv4 Data. */ + nfp_flower_compile_ipv6((struct nfp_flower_ipv6 *)msk, + flow, true); + ext += sizeof(struct nfp_flower_ipv6); + msk += sizeof(struct nfp_flower_ipv6); + } + + return 0; +} diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index fb9f73ab16c9..5cddc4d561fd 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -208,13 +208,17 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, goto err_free_key_ls; } + err = nfp_flower_compile_flow_match(flow, key_layer, netdev, flow_pay); + if (err) + goto err_destroy_flow; + /* TODO: Complete flower_add_offload. */ err = -EOPNOTSUPP; +err_destroy_flow: kfree(flow_pay->mask_data); kfree(flow_pay->unmasked_data); kfree(flow_pay); - err_free_key_ls: kfree(key_layer); return err; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h index 6a6727816010..32179cad062a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.h @@ -38,6 +38,8 @@ struct metadata_dst; struct nfp_net; struct nfp_port; +#include + /** * struct nfp_reprs - container for representor netdevs * @num_reprs: Number of elements in reprs array @@ -104,6 +106,13 @@ static inline bool nfp_netdev_is_nfp_repr(struct net_device *netdev) return netdev->netdev_ops == &nfp_repr_netdev_ops; } +static inline int nfp_repr_get_port_id(struct net_device *netdev) +{ + struct nfp_repr *priv = netdev_priv(netdev); + + return priv->dst->u.port_info.port_id; +} + void nfp_repr_inc_rx_stats(struct net_device *netdev, unsigned int len); int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, u32 cmsg_port_id, struct nfp_port *port, -- cgit v1.2.3 From 1a1e586f54bfe54a0ba7ea0ac9b8c7b1d3e655f6 Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Thu, 29 Jun 2017 22:08:16 +0200 Subject: nfp: add basic action capabilities to flower offloads Adds push vlan, pop vlan, output and drop action capabilities to flower offloads. Signed-off-by: Pieter Jansen van Vuuren Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 1 + drivers/net/ethernet/netronome/nfp/flower/action.c | 211 +++++++++++++++++++++ drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 45 +++++ drivers/net/ethernet/netronome/nfp/flower/main.h | 3 + .../net/ethernet/netronome/nfp/flower/offload.c | 11 ++ 5 files changed, 271 insertions(+) create mode 100644 drivers/net/ethernet/netronome/nfp/flower/action.c (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 018cef3fa10a..1ba0ea78adc3 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -31,6 +31,7 @@ nfp-objs := \ ifeq ($(CONFIG_NFP_APP_FLOWER),y) nfp-objs += \ + flower/action.o \ flower/cmsg.o \ flower/main.o \ flower/match.o \ diff --git a/drivers/net/ethernet/netronome/nfp/flower/action.c b/drivers/net/ethernet/netronome/nfp/flower/action.c new file mode 100644 index 000000000000..db9750695dc7 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/flower/action.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "cmsg.h" +#include "main.h" +#include "../nfp_net_repr.h" + +static void nfp_fl_pop_vlan(struct nfp_fl_pop_vlan *pop_vlan) +{ + size_t act_size = sizeof(struct nfp_fl_pop_vlan); + u16 tmp_pop_vlan_op; + + tmp_pop_vlan_op = + FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) | + FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_POP_VLAN); + + pop_vlan->a_op = cpu_to_be16(tmp_pop_vlan_op); + pop_vlan->reserved = 0; +} + +static void +nfp_fl_push_vlan(struct nfp_fl_push_vlan *push_vlan, + const struct tc_action *action) +{ + size_t act_size = sizeof(struct nfp_fl_push_vlan); + struct tcf_vlan *vlan = to_vlan(action); + u16 tmp_push_vlan_tci; + u16 tmp_push_vlan_op; + + tmp_push_vlan_op = + FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) | + FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_PUSH_VLAN); + + push_vlan->a_op = cpu_to_be16(tmp_push_vlan_op); + /* Set action push vlan parameters. */ + push_vlan->reserved = 0; + push_vlan->vlan_tpid = tcf_vlan_push_proto(action); + + tmp_push_vlan_tci = + FIELD_PREP(NFP_FL_PUSH_VLAN_PRIO, vlan->tcfv_push_prio) | + FIELD_PREP(NFP_FL_PUSH_VLAN_VID, vlan->tcfv_push_vid) | + NFP_FL_PUSH_VLAN_CFI; + push_vlan->vlan_tci = cpu_to_be16(tmp_push_vlan_tci); +} + +static int +nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action, + struct nfp_fl_payload *nfp_flow, bool last, + struct net_device *in_dev) +{ + size_t act_size = sizeof(struct nfp_fl_output); + struct net_device *out_dev; + u16 tmp_output_op; + int ifindex; + + /* Set action opcode to output action. */ + tmp_output_op = + FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) | + FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_OUTPUT); + + output->a_op = cpu_to_be16(tmp_output_op); + + /* Set action output parameters. */ + output->flags = cpu_to_be16(last ? NFP_FL_OUT_FLAGS_LAST : 0); + + ifindex = tcf_mirred_ifindex(action); + out_dev = __dev_get_by_index(dev_net(in_dev), ifindex); + if (!out_dev) + return -EOPNOTSUPP; + + /* Only offload egress ports are on the same device as the ingress + * port. + */ + if (!switchdev_port_same_parent_id(in_dev, out_dev)) + return -EOPNOTSUPP; + + output->port = cpu_to_be32(nfp_repr_get_port_id(out_dev)); + if (!output->port) + return -EOPNOTSUPP; + + nfp_flow->meta.shortcut = output->port; + + return 0; +} + +static int +nfp_flower_loop_action(const struct tc_action *a, + struct nfp_fl_payload *nfp_fl, int *a_len, + struct net_device *netdev) +{ + struct nfp_fl_push_vlan *psh_v; + struct nfp_fl_pop_vlan *pop_v; + struct nfp_fl_output *output; + int err; + + if (is_tcf_gact_shot(a)) { + nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_DROP); + } else if (is_tcf_mirred_egress_redirect(a)) { + if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ) + return -EOPNOTSUPP; + + output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len]; + err = nfp_fl_output(output, a, nfp_fl, true, netdev); + if (err) + return err; + + *a_len += sizeof(struct nfp_fl_output); + } else if (is_tcf_mirred_egress_mirror(a)) { + if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ) + return -EOPNOTSUPP; + + output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len]; + err = nfp_fl_output(output, a, nfp_fl, false, netdev); + if (err) + return err; + + *a_len += sizeof(struct nfp_fl_output); + } else if (is_tcf_vlan(a) && tcf_vlan_action(a) == TCA_VLAN_ACT_POP) { + if (*a_len + sizeof(struct nfp_fl_pop_vlan) > NFP_FL_MAX_A_SIZ) + return -EOPNOTSUPP; + + pop_v = (struct nfp_fl_pop_vlan *)&nfp_fl->action_data[*a_len]; + nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_POPV); + + nfp_fl_pop_vlan(pop_v); + *a_len += sizeof(struct nfp_fl_pop_vlan); + } else if (is_tcf_vlan(a) && tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) { + if (*a_len + sizeof(struct nfp_fl_push_vlan) > NFP_FL_MAX_A_SIZ) + return -EOPNOTSUPP; + + psh_v = (struct nfp_fl_push_vlan *)&nfp_fl->action_data[*a_len]; + nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL); + + nfp_fl_push_vlan(psh_v, a); + *a_len += sizeof(struct nfp_fl_push_vlan); + } else { + /* Currently we do not handle any other actions. */ + return -EOPNOTSUPP; + } + + return 0; +} + +int nfp_flower_compile_action(struct tc_cls_flower_offload *flow, + struct net_device *netdev, + struct nfp_fl_payload *nfp_flow) +{ + int act_len, act_cnt, err; + const struct tc_action *a; + LIST_HEAD(actions); + + memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ); + nfp_flow->meta.act_len = 0; + act_len = 0; + act_cnt = 0; + + tcf_exts_to_list(flow->exts, &actions); + list_for_each_entry(a, &actions, list) { + err = nfp_flower_loop_action(a, nfp_flow, &act_len, netdev); + if (err) + return err; + act_cnt++; + } + + /* We optimise when the action list is small, this can unfortunately + * not happen once we have more than one action in the action list. + */ + if (act_cnt > 1) + nfp_flow->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL); + + nfp_flow->meta.act_len = act_len; + + return 0; +} diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index 1956c1acf39f..8700eb9430c5 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -56,6 +56,51 @@ #define NFP_FLOWER_MASK_VLAN_CFI BIT(12) #define NFP_FLOWER_MASK_VLAN_VID GENMASK(11, 0) +#define NFP_FL_SC_ACT_DROP 0x80000000 +#define NFP_FL_SC_ACT_USER 0x7D000000 +#define NFP_FL_SC_ACT_POPV 0x6A000000 +#define NFP_FL_SC_ACT_NULL 0x00000000 + +/* The maximum action list size (in bytes) supported by the NFP. + */ +#define NFP_FL_MAX_A_SIZ 1216 +#define NFP_FL_LW_SIZ 2 + +/* Action opcodes */ +#define NFP_FL_ACTION_OPCODE_OUTPUT 0 +#define NFP_FL_ACTION_OPCODE_PUSH_VLAN 1 +#define NFP_FL_ACTION_OPCODE_POP_VLAN 2 +#define NFP_FL_ACTION_OPCODE_NUM 32 + +#define NFP_FL_ACT_JMP_ID GENMASK(15, 8) +#define NFP_FL_ACT_LEN_LW GENMASK(7, 0) + +#define NFP_FL_OUT_FLAGS_LAST BIT(15) +#define NFP_FL_OUT_FLAGS_USE_TUN BIT(4) +#define NFP_FL_OUT_FLAGS_TYPE_IDX GENMASK(2, 0) + +#define NFP_FL_PUSH_VLAN_PRIO GENMASK(15, 13) +#define NFP_FL_PUSH_VLAN_CFI BIT(12) +#define NFP_FL_PUSH_VLAN_VID GENMASK(11, 0) + +struct nfp_fl_output { + __be16 a_op; + __be16 flags; + __be32 port; +}; + +struct nfp_fl_push_vlan { + __be16 a_op; + __be16 reserved; + __be16 vlan_tpid; + __be16 vlan_tci; +}; + +struct nfp_fl_pop_vlan { + __be16 a_op; + __be16 reserved; +}; + /* Metadata without L2 (1W/4B) * ---------------------------------------------------------------- * 3 2 1 diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 5ba7e5194708..7c9530504752 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -70,5 +70,8 @@ int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow, struct nfp_fl_key_ls *key_ls, struct net_device *netdev, struct nfp_fl_payload *nfp_flow); +int nfp_flower_compile_action(struct tc_cls_flower_offload *flow, + struct net_device *netdev, + struct nfp_fl_payload *nfp_flow); #endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 5cddc4d561fd..de687a9e4759 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -165,10 +165,16 @@ nfp_flower_allocate_new(struct nfp_fl_key_ls *key_layer) if (!flow_pay->mask_data) goto err_free_unmasked; + flow_pay->action_data = kmalloc(NFP_FL_MAX_A_SIZ, GFP_KERNEL); + if (!flow_pay->action_data) + goto err_free_mask; + flow_pay->meta.flags = 0; return flow_pay; +err_free_mask: + kfree(flow_pay->mask_data); err_free_unmasked: kfree(flow_pay->unmasked_data); err_free_flow: @@ -212,10 +218,15 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, if (err) goto err_destroy_flow; + err = nfp_flower_compile_action(flow, netdev, flow_pay); + if (err) + goto err_destroy_flow; + /* TODO: Complete flower_add_offload. */ err = -EOPNOTSUPP; err_destroy_flow: + kfree(flow_pay->action_data); kfree(flow_pay->mask_data); kfree(flow_pay->unmasked_data); kfree(flow_pay); -- cgit v1.2.3 From 43f84b72c50d40c3eb2f59070e40ef51bfd483cc Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Thu, 29 Jun 2017 22:08:17 +0200 Subject: nfp: add metadata to each flow offload Adds metadata describing the mask id of each flow and keeps track of flows installed in hardware. Previously a flow could not be removed from hardware as there was no way of knowing if that a specific flow was installed. This is solved by storing the offloaded flows in a hash table. Signed-off-by: Pieter Jansen van Vuuren Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/Makefile | 1 + drivers/net/ethernet/netronome/nfp/flower/main.c | 21 +- drivers/net/ethernet/netronome/nfp/flower/main.h | 54 ++++ .../net/ethernet/netronome/nfp/flower/metadata.c | 318 +++++++++++++++++++++ .../net/ethernet/netronome/nfp/flower/offload.c | 31 +- 5 files changed, 412 insertions(+), 13 deletions(-) create mode 100644 drivers/net/ethernet/netronome/nfp/flower/metadata.c (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile index 1ba0ea78adc3..b8e1358868bd 100644 --- a/drivers/net/ethernet/netronome/nfp/Makefile +++ b/drivers/net/ethernet/netronome/nfp/Makefile @@ -35,6 +35,7 @@ nfp-objs += \ flower/cmsg.o \ flower/main.o \ flower/match.o \ + flower/metadata.o \ flower/offload.o endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 7bf994ceb9c1..5fe6d3582597 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -50,14 +51,6 @@ #define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL -/** - * struct nfp_flower_priv - Flower APP per-vNIC priv data - * @nn: Pointer to vNIC - */ -struct nfp_flower_priv { - struct nfp_net *nn; -}; - static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn) { return "FLOWER"; @@ -347,16 +340,24 @@ static int nfp_flower_init(struct nfp_app *app) return -EINVAL; } - app->priv = kzalloc(sizeof(struct nfp_flower_priv), GFP_KERNEL); + app->priv = vzalloc(sizeof(struct nfp_flower_priv)); if (!app->priv) return -ENOMEM; + err = nfp_flower_metadata_init(app); + if (err) + goto err_free_app_priv; + return 0; + +err_free_app_priv: + vfree(app->priv); + return err; } static void nfp_flower_clean(struct nfp_app *app) { - kfree(app->priv); + vfree(app->priv); app->priv = NULL; } diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 7c9530504752..61a80becf3b2 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -34,12 +34,50 @@ #ifndef __NFP_FLOWER_H__ #define __NFP_FLOWER_H__ 1 +#include +#include +#include #include struct tc_to_netdev; struct net_device; struct nfp_app; +#define NFP_FLOWER_HASH_BITS 19 +#define NFP_FLOWER_MASK_ENTRY_RS 256 +#define NFP_FLOWER_MASK_ELEMENT_RS 1 +#define NFP_FLOWER_MASK_HASH_BITS 10 + +#define NFP_FL_META_FLAG_NEW_MASK 128 +#define NFP_FL_META_FLAG_LAST_MASK 1 + +#define NFP_FL_MASK_REUSE_TIME_NS 40000 +#define NFP_FL_MASK_ID_LOCATION 1 + +struct nfp_fl_mask_id { + struct circ_buf mask_id_free_list; + struct timespec64 *last_used; + u8 init_unallocated; +}; + +/** + * struct nfp_flower_priv - Flower APP per-vNIC priv data + * @nn: Pointer to vNIC + * @mask_id_seed: Seed used for mask hash table + * @flower_version: HW version of flower + * @mask_ids: List of free mask ids + * @mask_table: Hash table used to store masks + * @flow_table: Hash table used to store flower rules + */ +struct nfp_flower_priv { + struct nfp_net *nn; + u32 mask_id_seed; + u64 flower_version; + struct nfp_fl_mask_id mask_ids; + DECLARE_HASHTABLE(mask_table, NFP_FLOWER_MASK_HASH_BITS); + DECLARE_HASHTABLE(flow_table, NFP_FLOWER_HASH_BITS); +}; + struct nfp_fl_key_ls { u32 key_layer_two; u8 key_layer; @@ -59,11 +97,17 @@ struct nfp_fl_rule_metadata { struct nfp_fl_payload { struct nfp_fl_rule_metadata meta; + unsigned long tc_flower_cookie; + struct hlist_node link; + struct rcu_head rcu; char *unmasked_data; char *mask_data; char *action_data; }; +int nfp_flower_metadata_init(struct nfp_app *app); +void nfp_flower_metadata_cleanup(struct nfp_app *app); + int nfp_flower_setup_tc(struct nfp_app *app, struct net_device *netdev, u32 handle, __be16 proto, struct tc_to_netdev *tc); int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow, @@ -73,5 +117,15 @@ int nfp_flower_compile_flow_match(struct tc_cls_flower_offload *flow, int nfp_flower_compile_action(struct tc_cls_flower_offload *flow, struct net_device *netdev, struct nfp_fl_payload *nfp_flow); +int nfp_compile_flow_metadata(struct nfp_app *app, + struct tc_cls_flower_offload *flow, + struct nfp_fl_payload *nfp_flow); +int nfp_modify_flow_metadata(struct nfp_app *app, + struct nfp_fl_payload *nfp_flow); + +struct nfp_fl_payload * +nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie); +struct nfp_fl_payload * +nfp_flower_remove_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie); #endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c new file mode 100644 index 000000000000..8a359ef3cc27 --- /dev/null +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2017 Netronome Systems, Inc. + * + * This software is dual licensed under the GNU General License Version 2, + * June 1991 as shown in the file COPYING in the top-level directory of this + * source tree or the BSD 2-Clause License provided below. You have the + * option to license this software under the complete terms of either license. + * + * The BSD 2-Clause License: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "cmsg.h" +#include "main.h" +#include "../nfp_app.h" + +struct nfp_mask_id_table { + struct hlist_node link; + u32 hash_key; + u32 ref_cnt; + u8 mask_id; +}; + +/* Must be called with either RTNL or rcu_read_lock */ +struct nfp_fl_payload * +nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie) +{ + struct nfp_flower_priv *priv = app->priv; + struct nfp_fl_payload *flower_entry; + + hash_for_each_possible_rcu(priv->flow_table, flower_entry, link, + tc_flower_cookie) + if (flower_entry->tc_flower_cookie == tc_flower_cookie) + return flower_entry; + + return NULL; +} + +static int nfp_release_mask_id(struct nfp_app *app, u8 mask_id) +{ + struct nfp_flower_priv *priv = app->priv; + struct circ_buf *ring; + struct timespec64 now; + + ring = &priv->mask_ids.mask_id_free_list; + /* Checking if buffer is full. */ + if (CIRC_SPACE(ring->head, ring->tail, NFP_FLOWER_MASK_ENTRY_RS) == 0) + return -ENOBUFS; + + memcpy(&ring->buf[ring->head], &mask_id, NFP_FLOWER_MASK_ELEMENT_RS); + ring->head = (ring->head + NFP_FLOWER_MASK_ELEMENT_RS) % + (NFP_FLOWER_MASK_ENTRY_RS * NFP_FLOWER_MASK_ELEMENT_RS); + + getnstimeofday64(&now); + priv->mask_ids.last_used[mask_id] = now; + + return 0; +} + +static int nfp_mask_alloc(struct nfp_app *app, u8 *mask_id) +{ + struct nfp_flower_priv *priv = app->priv; + struct timespec64 delta, now; + struct circ_buf *ring; + u8 temp_id, freed_id; + + ring = &priv->mask_ids.mask_id_free_list; + freed_id = NFP_FLOWER_MASK_ENTRY_RS - 1; + /* Checking for unallocated entries first. */ + if (priv->mask_ids.init_unallocated > 0) { + *mask_id = priv->mask_ids.init_unallocated; + priv->mask_ids.init_unallocated--; + return 0; + } + + /* Checking if buffer is empty. */ + if (ring->head == ring->tail) + goto err_not_found; + + memcpy(&temp_id, &ring->buf[ring->tail], NFP_FLOWER_MASK_ELEMENT_RS); + *mask_id = temp_id; + + getnstimeofday64(&now); + delta = timespec64_sub(now, priv->mask_ids.last_used[*mask_id]); + + if (timespec64_to_ns(&delta) < NFP_FL_MASK_REUSE_TIME_NS) + goto err_not_found; + + memcpy(&ring->buf[ring->tail], &freed_id, NFP_FLOWER_MASK_ELEMENT_RS); + ring->tail = (ring->tail + NFP_FLOWER_MASK_ELEMENT_RS) % + (NFP_FLOWER_MASK_ENTRY_RS * NFP_FLOWER_MASK_ELEMENT_RS); + + return 0; + +err_not_found: + *mask_id = freed_id; + return -ENOENT; +} + +static int +nfp_add_mask_table(struct nfp_app *app, char *mask_data, u32 mask_len) +{ + struct nfp_flower_priv *priv = app->priv; + struct nfp_mask_id_table *mask_entry; + unsigned long hash_key; + u8 mask_id; + + if (nfp_mask_alloc(app, &mask_id)) + return -ENOENT; + + mask_entry = kmalloc(sizeof(*mask_entry), GFP_KERNEL); + if (!mask_entry) { + nfp_release_mask_id(app, mask_id); + return -ENOMEM; + } + + INIT_HLIST_NODE(&mask_entry->link); + mask_entry->mask_id = mask_id; + hash_key = jhash(mask_data, mask_len, priv->mask_id_seed); + mask_entry->hash_key = hash_key; + mask_entry->ref_cnt = 1; + hash_add(priv->mask_table, &mask_entry->link, hash_key); + + return mask_id; +} + +static struct nfp_mask_id_table * +nfp_search_mask_table(struct nfp_app *app, char *mask_data, u32 mask_len) +{ + struct nfp_flower_priv *priv = app->priv; + struct nfp_mask_id_table *mask_entry; + unsigned long hash_key; + + hash_key = jhash(mask_data, mask_len, priv->mask_id_seed); + + hash_for_each_possible(priv->mask_table, mask_entry, link, hash_key) + if (mask_entry->hash_key == hash_key) + return mask_entry; + + return NULL; +} + +static int +nfp_find_in_mask_table(struct nfp_app *app, char *mask_data, u32 mask_len) +{ + struct nfp_mask_id_table *mask_entry; + + mask_entry = nfp_search_mask_table(app, mask_data, mask_len); + if (!mask_entry) + return -ENOENT; + + mask_entry->ref_cnt++; + + /* Casting u8 to int for later use. */ + return mask_entry->mask_id; +} + +static bool +nfp_check_mask_add(struct nfp_app *app, char *mask_data, u32 mask_len, + u8 *meta_flags, u8 *mask_id) +{ + int id; + + id = nfp_find_in_mask_table(app, mask_data, mask_len); + if (id < 0) { + id = nfp_add_mask_table(app, mask_data, mask_len); + if (id < 0) + return false; + *meta_flags |= NFP_FL_META_FLAG_NEW_MASK; + } + *mask_id = id; + + return true; +} + +static bool +nfp_check_mask_remove(struct nfp_app *app, char *mask_data, u32 mask_len, + u8 *meta_flags, u8 *mask_id) +{ + struct nfp_mask_id_table *mask_entry; + + mask_entry = nfp_search_mask_table(app, mask_data, mask_len); + if (!mask_entry) + return false; + + *mask_id = mask_entry->mask_id; + mask_entry->ref_cnt--; + if (!mask_entry->ref_cnt) { + hash_del(&mask_entry->link); + nfp_release_mask_id(app, *mask_id); + kfree(mask_entry); + if (meta_flags) + *meta_flags |= NFP_FL_META_FLAG_LAST_MASK; + } + + return true; +} + +int nfp_compile_flow_metadata(struct nfp_app *app, + struct tc_cls_flower_offload *flow, + struct nfp_fl_payload *nfp_flow) +{ + struct nfp_flower_priv *priv = app->priv; + struct nfp_fl_payload *check_entry; + u8 new_mask_id; + + new_mask_id = 0; + if (!nfp_check_mask_add(app, nfp_flow->mask_data, + nfp_flow->meta.mask_len, + &nfp_flow->meta.flags, &new_mask_id)) + return -ENOENT; + + nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version); + priv->flower_version++; + + /* Update flow payload with mask ids. */ + nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id; + + check_entry = nfp_flower_search_fl_table(app, flow->cookie); + if (check_entry) { + if (!nfp_check_mask_remove(app, nfp_flow->mask_data, + nfp_flow->meta.mask_len, + NULL, &new_mask_id)) + return -EINVAL; + + return -EEXIST; + } + + return 0; +} + +int nfp_modify_flow_metadata(struct nfp_app *app, + struct nfp_fl_payload *nfp_flow) +{ + struct nfp_flower_priv *priv = app->priv; + u8 new_mask_id = 0; + + nfp_check_mask_remove(app, nfp_flow->mask_data, + nfp_flow->meta.mask_len, &nfp_flow->meta.flags, + &new_mask_id); + + nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version); + priv->flower_version++; + + /* Update flow payload with mask ids. */ + nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id; + + return 0; +} + +int nfp_flower_metadata_init(struct nfp_app *app) +{ + struct nfp_flower_priv *priv = app->priv; + + hash_init(priv->mask_table); + hash_init(priv->flow_table); + get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed)); + + /* Init ring buffer and unallocated mask_ids. */ + priv->mask_ids.mask_id_free_list.buf = + kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS, + NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL); + if (!priv->mask_ids.mask_id_free_list.buf) + return -ENOMEM; + + priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1; + + /* Init timestamps for mask id*/ + priv->mask_ids.last_used = + kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS, + sizeof(*priv->mask_ids.last_used), GFP_KERNEL); + if (!priv->mask_ids.last_used) + goto err_free_mask_id; + + return 0; + +err_free_mask_id: + kfree(priv->mask_ids.mask_id_free_list.buf); + return -ENOMEM; +} + +void nfp_flower_metadata_cleanup(struct nfp_app *app) +{ + struct nfp_flower_priv *priv = app->priv; + + if (!priv) + return; + + kfree(priv->mask_ids.mask_id_free_list.buf); + kfree(priv->mask_ids.last_used); +} diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index de687a9e4759..04603d832adf 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -196,6 +196,7 @@ static int nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, struct tc_cls_flower_offload *flow) { + struct nfp_flower_priv *priv = app->priv; struct nfp_fl_payload *flow_pay; struct nfp_fl_key_ls *key_layer; int err; @@ -222,8 +223,18 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, if (err) goto err_destroy_flow; - /* TODO: Complete flower_add_offload. */ - err = -EOPNOTSUPP; + err = nfp_compile_flow_metadata(app, flow, flow_pay); + if (err) + goto err_destroy_flow; + + INIT_HLIST_NODE(&flow_pay->link); + flow_pay->tc_flower_cookie = flow->cookie; + hash_add_rcu(priv->flow_table, &flow_pay->link, flow->cookie); + + /* Deallocate flow payload when flower rule has been destroyed. */ + kfree(key_layer); + + return 0; err_destroy_flow: kfree(flow_pay->action_data); @@ -250,7 +261,21 @@ static int nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, struct tc_cls_flower_offload *flow) { - return -EOPNOTSUPP; + struct nfp_fl_payload *nfp_flow; + int err; + + nfp_flow = nfp_flower_search_fl_table(app, flow->cookie); + if (!nfp_flow) + return -ENOENT; + + err = nfp_modify_flow_metadata(app, nfp_flow); + + hash_del_rcu(&nfp_flow->link); + kfree(nfp_flow->action_data); + kfree(nfp_flow->mask_data); + kfree(nfp_flow->unmasked_data); + kfree_rcu(nfp_flow, rcu); + return err; } /** -- cgit v1.2.3 From abfcdc1de9bf38cdde6792a165c75d9037ea35fe Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Thu, 29 Jun 2017 22:08:18 +0200 Subject: nfp: add a stats handler for flower offloads Previously there was no way of updating flow rule stats after they have been offloaded to hardware. This is solved by keeping track of stats received from hardware and providing this to the TC handler on request. Signed-off-by: Pieter Jansen van Vuuren Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 5 - drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 5 + drivers/net/ethernet/netronome/nfp/flower/main.h | 28 +++++ .../net/ethernet/netronome/nfp/flower/metadata.c | 124 ++++++++++++++++++++- .../net/ethernet/netronome/nfp/flower/offload.c | 17 ++- 5 files changed, 171 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c index 916a6196d2ba..0f5410aa66d6 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c @@ -52,11 +52,6 @@ nfp_flower_cmsg_get_hdr(struct sk_buff *skb) return (struct nfp_flower_cmsg_hdr *)skb->data; } -static void *nfp_flower_cmsg_get_data(struct sk_buff *skb) -{ - return (unsigned char *)skb->data + NFP_FLOWER_CMSG_HLEN; -} - static struct sk_buff * nfp_flower_cmsg_alloc(struct nfp_app *app, unsigned int size, enum nfp_flower_cmsg_type_port type) diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index 8700eb9430c5..ee543ff3a9d8 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -300,6 +300,11 @@ nfp_flower_cmsg_pcie_port(u8 nfp_pcie, enum nfp_flower_cmsg_port_vnic_type type, NFP_FLOWER_CMSG_PORT_TYPE_PCIE_PORT); } +static inline void *nfp_flower_cmsg_get_data(struct sk_buff *skb) +{ + return (unsigned char *)skb->data + NFP_FLOWER_CMSG_HLEN; +} + int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok); void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb); diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.h b/drivers/net/ethernet/netronome/nfp/flower/main.h index 61a80becf3b2..9e64c048e83f 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.h +++ b/drivers/net/ethernet/netronome/nfp/flower/main.h @@ -43,6 +43,9 @@ struct tc_to_netdev; struct net_device; struct nfp_app; +#define NFP_FL_STATS_ENTRY_RS BIT(20) +#define NFP_FL_STATS_ELEM_RS 4 +#define NFP_FL_REPEATED_HASH_MAX BIT(17) #define NFP_FLOWER_HASH_BITS 19 #define NFP_FLOWER_MASK_ENTRY_RS 256 #define NFP_FLOWER_MASK_ELEMENT_RS 1 @@ -60,11 +63,18 @@ struct nfp_fl_mask_id { u8 init_unallocated; }; +struct nfp_fl_stats_id { + struct circ_buf free_list; + u32 init_unalloc; + u8 repeated_em_count; +}; + /** * struct nfp_flower_priv - Flower APP per-vNIC priv data * @nn: Pointer to vNIC * @mask_id_seed: Seed used for mask hash table * @flower_version: HW version of flower + * @stats_ids: List of free stats ids * @mask_ids: List of free mask ids * @mask_table: Hash table used to store masks * @flow_table: Hash table used to store flower rules @@ -73,6 +83,7 @@ struct nfp_flower_priv { struct nfp_net *nn; u32 mask_id_seed; u64 flower_version; + struct nfp_fl_stats_id stats_ids; struct nfp_fl_mask_id mask_ids; DECLARE_HASHTABLE(mask_table, NFP_FLOWER_MASK_HASH_BITS); DECLARE_HASHTABLE(flow_table, NFP_FLOWER_HASH_BITS); @@ -95,16 +106,31 @@ struct nfp_fl_rule_metadata { __be32 shortcut; }; +struct nfp_fl_stats { + u64 pkts; + u64 bytes; + u64 used; +}; + struct nfp_fl_payload { struct nfp_fl_rule_metadata meta; unsigned long tc_flower_cookie; struct hlist_node link; struct rcu_head rcu; + spinlock_t lock; /* lock stats */ + struct nfp_fl_stats stats; char *unmasked_data; char *mask_data; char *action_data; }; +struct nfp_fl_stats_frame { + __be32 stats_con_id; + __be32 pkt_count; + __be64 byte_count; + __be64 stats_cookie; +}; + int nfp_flower_metadata_init(struct nfp_app *app); void nfp_flower_metadata_cleanup(struct nfp_app *app); @@ -128,4 +154,6 @@ nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie); struct nfp_fl_payload * nfp_flower_remove_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie); +void nfp_flower_rx_flow_stats(struct nfp_app *app, struct sk_buff *skb); + #endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index 8a359ef3cc27..fec0ff2ca94f 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -48,6 +48,55 @@ struct nfp_mask_id_table { u8 mask_id; }; +static int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id) +{ + struct nfp_flower_priv *priv = app->priv; + struct circ_buf *ring; + + ring = &priv->stats_ids.free_list; + /* Check if buffer is full. */ + if (!CIRC_SPACE(ring->head, ring->tail, NFP_FL_STATS_ENTRY_RS * + NFP_FL_STATS_ELEM_RS - + NFP_FL_STATS_ELEM_RS + 1)) + return -ENOBUFS; + + memcpy(&ring->buf[ring->head], &stats_context_id, NFP_FL_STATS_ELEM_RS); + ring->head = (ring->head + NFP_FL_STATS_ELEM_RS) % + (NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS); + + return 0; +} + +static int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id) +{ + struct nfp_flower_priv *priv = app->priv; + u32 freed_stats_id, temp_stats_id; + struct circ_buf *ring; + + ring = &priv->stats_ids.free_list; + freed_stats_id = NFP_FL_STATS_ENTRY_RS; + /* Check for unallocated entries first. */ + if (priv->stats_ids.init_unalloc > 0) { + *stats_context_id = priv->stats_ids.init_unalloc - 1; + priv->stats_ids.init_unalloc--; + return 0; + } + + /* Check if buffer is empty. */ + if (ring->head == ring->tail) { + *stats_context_id = freed_stats_id; + return -ENOENT; + } + + memcpy(&temp_stats_id, &ring->buf[ring->tail], NFP_FL_STATS_ELEM_RS); + *stats_context_id = temp_stats_id; + memcpy(&ring->buf[ring->tail], &freed_stats_id, NFP_FL_STATS_ELEM_RS); + ring->tail = (ring->tail + NFP_FL_STATS_ELEM_RS) % + (NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS); + + return 0; +} + /* Must be called with either RTNL or rcu_read_lock */ struct nfp_fl_payload * nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie) @@ -63,6 +112,46 @@ nfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie) return NULL; } +static void +nfp_flower_update_stats(struct nfp_app *app, struct nfp_fl_stats_frame *stats) +{ + struct nfp_fl_payload *nfp_flow; + unsigned long flower_cookie; + + flower_cookie = be64_to_cpu(stats->stats_cookie); + + rcu_read_lock(); + nfp_flow = nfp_flower_search_fl_table(app, flower_cookie); + if (!nfp_flow) + goto exit_rcu_unlock; + + if (nfp_flow->meta.host_ctx_id != stats->stats_con_id) + goto exit_rcu_unlock; + + spin_lock(&nfp_flow->lock); + nfp_flow->stats.pkts += be32_to_cpu(stats->pkt_count); + nfp_flow->stats.bytes += be64_to_cpu(stats->byte_count); + nfp_flow->stats.used = jiffies; + spin_unlock(&nfp_flow->lock); + +exit_rcu_unlock: + rcu_read_unlock(); +} + +void nfp_flower_rx_flow_stats(struct nfp_app *app, struct sk_buff *skb) +{ + unsigned int msg_len = skb->len - NFP_FLOWER_CMSG_HLEN; + struct nfp_fl_stats_frame *stats_frame; + unsigned char *msg; + int i; + + msg = nfp_flower_cmsg_get_data(skb); + + stats_frame = (struct nfp_fl_stats_frame *)msg; + for (i = 0; i < msg_len / sizeof(*stats_frame); i++) + nfp_flower_update_stats(app, stats_frame + i); +} + static int nfp_release_mask_id(struct nfp_app *app, u8 mask_id) { struct nfp_flower_priv *priv = app->priv; @@ -230,21 +319,37 @@ int nfp_compile_flow_metadata(struct nfp_app *app, struct nfp_flower_priv *priv = app->priv; struct nfp_fl_payload *check_entry; u8 new_mask_id; + u32 stats_cxt; + + if (nfp_get_stats_entry(app, &stats_cxt)) + return -ENOENT; + + nfp_flow->meta.host_ctx_id = cpu_to_be32(stats_cxt); + nfp_flow->meta.host_cookie = cpu_to_be64(flow->cookie); new_mask_id = 0; if (!nfp_check_mask_add(app, nfp_flow->mask_data, nfp_flow->meta.mask_len, - &nfp_flow->meta.flags, &new_mask_id)) + &nfp_flow->meta.flags, &new_mask_id)) { + if (nfp_release_stats_entry(app, stats_cxt)) + return -EINVAL; return -ENOENT; + } nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version); priv->flower_version++; /* Update flow payload with mask ids. */ nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id; + nfp_flow->stats.pkts = 0; + nfp_flow->stats.bytes = 0; + nfp_flow->stats.used = jiffies; check_entry = nfp_flower_search_fl_table(app, flow->cookie); if (check_entry) { + if (nfp_release_stats_entry(app, stats_cxt)) + return -EINVAL; + if (!nfp_check_mask_remove(app, nfp_flow->mask_data, nfp_flow->meta.mask_len, NULL, &new_mask_id)) @@ -261,6 +366,7 @@ int nfp_modify_flow_metadata(struct nfp_app *app, { struct nfp_flower_priv *priv = app->priv; u8 new_mask_id = 0; + u32 temp_ctx_id; nfp_check_mask_remove(app, nfp_flow->mask_data, nfp_flow->meta.mask_len, &nfp_flow->meta.flags, @@ -272,7 +378,10 @@ int nfp_modify_flow_metadata(struct nfp_app *app, /* Update flow payload with mask ids. */ nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id; - return 0; + /* Release the stats ctx id. */ + temp_ctx_id = be32_to_cpu(nfp_flow->meta.host_ctx_id); + + return nfp_release_stats_entry(app, temp_ctx_id); } int nfp_flower_metadata_init(struct nfp_app *app) @@ -299,8 +408,18 @@ int nfp_flower_metadata_init(struct nfp_app *app) if (!priv->mask_ids.last_used) goto err_free_mask_id; + /* Init ring buffer and unallocated stats_ids. */ + priv->stats_ids.free_list.buf = + vmalloc(NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS); + if (!priv->stats_ids.free_list.buf) + goto err_free_last_used; + + priv->stats_ids.init_unalloc = NFP_FL_REPEATED_HASH_MAX; + return 0; +err_free_last_used: + kfree(priv->stats_ids.free_list.buf); err_free_mask_id: kfree(priv->mask_ids.mask_id_free_list.buf); return -ENOMEM; @@ -315,4 +434,5 @@ void nfp_flower_metadata_cleanup(struct nfp_app *app) kfree(priv->mask_ids.mask_id_free_list.buf); kfree(priv->mask_ids.last_used); + vfree(priv->stats_ids.free_list.buf); } diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 04603d832adf..1a2e2b9b75a3 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -170,6 +170,7 @@ nfp_flower_allocate_new(struct nfp_fl_key_ls *key_layer) goto err_free_mask; flow_pay->meta.flags = 0; + spin_lock_init(&flow_pay->lock); return flow_pay; @@ -291,7 +292,21 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, static int nfp_flower_get_stats(struct nfp_app *app, struct tc_cls_flower_offload *flow) { - return -EOPNOTSUPP; + struct nfp_fl_payload *nfp_flow; + + nfp_flow = nfp_flower_search_fl_table(app, flow->cookie); + if (!nfp_flow) + return -EINVAL; + + spin_lock_bh(&nfp_flow->lock); + tcf_exts_stats_update(flow->exts, nfp_flow->stats.bytes, + nfp_flow->stats.pkts, nfp_flow->stats.used); + + nfp_flow->stats.pkts = 0; + nfp_flow->stats.bytes = 0; + spin_unlock_bh(&nfp_flow->lock); + + return 0; } static int -- cgit v1.2.3 From 81f3ddf2547d40c3d4878aa66ce837177665ce3c Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Thu, 29 Jun 2017 22:08:19 +0200 Subject: nfp: add control message passing capabilities to flower offloads Previously the flower offloads never sends messages to the hardware, and never registers a handler for receiving messages from hardware. This patch enables the flower offloads to send control messages to hardware when adding and removing flow rules. Additionally it registers a control message rx handler for receiving stats updates from hardware for each offloaded flow. Additionally this patch adds 4 control message types; Add, modify and delete flow, as well as flow stats. It also allows nfp_flower_cmsg_get_data() to be used outside of cmsg.c. Signed-off-by: Pieter Jansen van Vuuren Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/cmsg.c | 6 ++- drivers/net/ethernet/netronome/nfp/flower/cmsg.h | 6 +++ .../net/ethernet/netronome/nfp/flower/offload.c | 59 ++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c index 0f5410aa66d6..dd7fa9cf225f 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.c +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.c @@ -36,6 +36,7 @@ #include #include +#include "main.h" #include "../nfpcore/nfp_cpp.h" #include "../nfp_net_repr.h" #include "./cmsg.h" @@ -52,7 +53,7 @@ nfp_flower_cmsg_get_hdr(struct sk_buff *skb) return (struct nfp_flower_cmsg_hdr *)skb->data; } -static struct sk_buff * +struct sk_buff * nfp_flower_cmsg_alloc(struct nfp_app *app, unsigned int size, enum nfp_flower_cmsg_type_port type) { @@ -143,6 +144,9 @@ void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb) case NFP_FLOWER_CMSG_TYPE_PORT_MOD: nfp_flower_cmsg_portmod_rx(app, skb); break; + case NFP_FLOWER_CMSG_TYPE_FLOW_STATS: + nfp_flower_rx_flow_stats(app, skb); + break; default: nfp_flower_cmsg_warn(app, "Cannot handle invalid repr control type %u\n", type); diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index ee543ff3a9d8..cf738de170ab 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -245,7 +245,10 @@ struct nfp_flower_cmsg_hdr { /* Types defined for port related control messages */ enum nfp_flower_cmsg_type_port { + NFP_FLOWER_CMSG_TYPE_FLOW_ADD = 0, + NFP_FLOWER_CMSG_TYPE_FLOW_DEL = 2, NFP_FLOWER_CMSG_TYPE_PORT_MOD = 8, + NFP_FLOWER_CMSG_TYPE_FLOW_STATS = 15, NFP_FLOWER_CMSG_TYPE_PORT_ECHO = 16, NFP_FLOWER_CMSG_TYPE_MAX = 32, }; @@ -307,5 +310,8 @@ static inline void *nfp_flower_cmsg_get_data(struct sk_buff *skb) int nfp_flower_cmsg_portmod(struct nfp_repr *repr, bool carrier_ok); void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb); +struct sk_buff * +nfp_flower_cmsg_alloc(struct nfp_app *app, unsigned int size, + enum nfp_flower_cmsg_type_port type); #endif diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 1a2e2b9b75a3..4ad10bd5e139 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -44,6 +44,52 @@ #include "../nfp_net.h" #include "../nfp_port.h" +static int +nfp_flower_xmit_flow(struct net_device *netdev, + struct nfp_fl_payload *nfp_flow, u8 mtype) +{ + u32 meta_len, key_len, mask_len, act_len, tot_len; + struct nfp_repr *priv = netdev_priv(netdev); + struct sk_buff *skb; + unsigned char *msg; + + meta_len = sizeof(struct nfp_fl_rule_metadata); + key_len = nfp_flow->meta.key_len; + mask_len = nfp_flow->meta.mask_len; + act_len = nfp_flow->meta.act_len; + + tot_len = meta_len + key_len + mask_len + act_len; + + /* Convert to long words as firmware expects + * lengths in units of NFP_FL_LW_SIZ. + */ + nfp_flow->meta.key_len >>= NFP_FL_LW_SIZ; + nfp_flow->meta.mask_len >>= NFP_FL_LW_SIZ; + nfp_flow->meta.act_len >>= NFP_FL_LW_SIZ; + + skb = nfp_flower_cmsg_alloc(priv->app, tot_len, mtype); + if (!skb) + return -ENOMEM; + + msg = nfp_flower_cmsg_get_data(skb); + memcpy(msg, &nfp_flow->meta, meta_len); + memcpy(&msg[meta_len], nfp_flow->unmasked_data, key_len); + memcpy(&msg[meta_len + key_len], nfp_flow->mask_data, mask_len); + memcpy(&msg[meta_len + key_len + mask_len], + nfp_flow->action_data, act_len); + + /* Convert back to bytes as software expects + * lengths in units of bytes. + */ + nfp_flow->meta.key_len <<= NFP_FL_LW_SIZ; + nfp_flow->meta.mask_len <<= NFP_FL_LW_SIZ; + nfp_flow->meta.act_len <<= NFP_FL_LW_SIZ; + + nfp_ctrl_tx(priv->app->ctrl, skb); + + return 0; +} + static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f) { return dissector_uses_key(f->dissector, @@ -228,6 +274,11 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev, if (err) goto err_destroy_flow; + err = nfp_flower_xmit_flow(netdev, flow_pay, + NFP_FLOWER_CMSG_TYPE_FLOW_ADD); + if (err) + goto err_destroy_flow; + INIT_HLIST_NODE(&flow_pay->link); flow_pay->tc_flower_cookie = flow->cookie; hash_add_rcu(priv->flow_table, &flow_pay->link, flow->cookie); @@ -270,7 +321,15 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev, return -ENOENT; err = nfp_modify_flow_metadata(app, nfp_flow); + if (err) + goto err_free_flow; + err = nfp_flower_xmit_flow(netdev, nfp_flow, + NFP_FLOWER_CMSG_TYPE_FLOW_DEL); + if (err) + goto err_free_flow; + +err_free_flow: hash_del_rcu(&nfp_flow->link); kfree(nfp_flow->action_data); kfree(nfp_flow->mask_data); -- cgit v1.2.3 From 4120dab09574e29e7576895342896ccb21b336e7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 30 Jun 2017 11:59:22 +0100 Subject: net/mlx5: fix spelling mistake: "Allodating" -> "Allocating" Trivial fix to spelling mistake in mlx5_core_dbg debug message Signed-off-by: Colin Ian King Reviewed-by: Ilan Tayari Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c index 4d0db481f6c4..de2aed44ab85 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/gid.c @@ -101,7 +101,7 @@ int mlx5_core_reserved_gid_alloc(struct mlx5_core_dev *dev, int *gid_index) if (index < 0) return index; - mlx5_core_dbg(dev, "Allodating reserved GID %u\n", index); + mlx5_core_dbg(dev, "Allocating reserved GID %u\n", index); *gid_index = index; return 0; } -- cgit v1.2.3 From 4e2e347b77d8bd724bfd2e10a84551cb9099ccd7 Mon Sep 17 00:00:00 2001 From: Jon Cooper Date: Fri, 30 Jun 2017 15:54:33 +0100 Subject: sfc: change Unknown MCDI event message to print full event. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index b9422450deb8..00cd6a205034 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1389,8 +1389,9 @@ void efx_mcdi_process_event(struct efx_channel *channel, MCDI_EVENT_FIELD(*event, PROXY_RESPONSE_RC)); break; default: - netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n", - code); + netif_err(efx, hw, efx->net_dev, + "Unknown MCDI event " EFX_QWORD_FMT "\n", + EFX_QWORD_VAL(*event)); } } -- cgit v1.2.3 From 53172d9bc4b44c037a305d3248c7160e5ad51341 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 30 Jun 2017 15:55:28 +0100 Subject: sfc: correct comment on efx_mcdi_process_event Fix out-of-date comment. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 00cd6a205034..3df872f56289 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1301,7 +1301,7 @@ static void efx_mcdi_abandon(struct efx_nic *efx) efx_schedule_reset(efx, RESET_TYPE_MCDI_TIMEOUT); } -/* Called from falcon_process_eventq for MCDI events */ +/* Called from efx_farch_ev_process and efx_ef10_ev_process for MCDI events */ void efx_mcdi_process_event(struct efx_channel *channel, efx_qword_t *event) { -- cgit v1.2.3 From c851a9dc4359c6b19722de568e9f543c1c23481c Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:21 +0300 Subject: qed: Introduce iWARP personality iWARP personality introduced the need for differentiating in several places in the code whether we are RoCE, iWARP or either. This leads to introducing new macros for querying the personality. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 26 +++++++++++++++++++++++--- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 8 ++++---- drivers/net/ethernet/qlogic/qed/qed_dev.c | 12 +++++------- drivers/net/ethernet/qlogic/qed/qed_l2.c | 3 +-- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_main.c | 17 ++++++++--------- 6 files changed, 42 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 14b08ee9e3ad..22e1171c317e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -210,14 +210,16 @@ struct qed_tunn_update_params { /* The PCI personality is not quite synonymous to protocol ID: * 1. All personalities need CORE connections - * 2. The Ethernet personality may support also the RoCE protocol + * 2. The Ethernet personality may support also the RoCE/iWARP protocol */ enum qed_pci_personality { QED_PCI_ETH, QED_PCI_FCOE, QED_PCI_ISCSI, QED_PCI_ETH_ROCE, - QED_PCI_DEFAULT /* default in shmem */ + QED_PCI_ETH_IWARP, + QED_PCI_ETH_RDMA, + QED_PCI_DEFAULT, /* default in shmem */ }; /* All VFs are symmetric, all counters are PF + all VFs */ @@ -277,6 +279,7 @@ enum qed_dev_cap { QED_DEV_CAP_FCOE, QED_DEV_CAP_ISCSI, QED_DEV_CAP_ROCE, + QED_DEV_CAP_IWARP, }; enum qed_wol_support { @@ -286,7 +289,24 @@ enum qed_wol_support { struct qed_hw_info { /* PCI personality */ - enum qed_pci_personality personality; + enum qed_pci_personality personality; +#define QED_IS_RDMA_PERSONALITY(dev) \ + ((dev)->hw_info.personality == QED_PCI_ETH_ROCE || \ + (dev)->hw_info.personality == QED_PCI_ETH_IWARP || \ + (dev)->hw_info.personality == QED_PCI_ETH_RDMA) +#define QED_IS_ROCE_PERSONALITY(dev) \ + ((dev)->hw_info.personality == QED_PCI_ETH_ROCE || \ + (dev)->hw_info.personality == QED_PCI_ETH_RDMA) +#define QED_IS_IWARP_PERSONALITY(dev) \ + ((dev)->hw_info.personality == QED_PCI_ETH_IWARP || \ + (dev)->hw_info.personality == QED_PCI_ETH_RDMA) +#define QED_IS_L2_PERSONALITY(dev) \ + ((dev)->hw_info.personality == QED_PCI_ETH || \ + QED_IS_RDMA_PERSONALITY(dev)) +#define QED_IS_FCOE_PERSONALITY(dev) \ + ((dev)->hw_info.personality == QED_PCI_FCOE) +#define QED_IS_ISCSI_PERSONALITY(dev) \ + ((dev)->hw_info.personality == QED_PCI_ISCSI) /* Resource Allocation scheme results */ u32 resc_start[QED_MAX_RESC]; diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index e201214764db..38716f77c21d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -853,7 +853,7 @@ u32 qed_cxt_cfg_ilt_compute_excess(struct qed_hwfn *p_hwfn, u32 used_lines) if (!excess_lines) return 0; - if (p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + if (!QED_IS_RDMA_PERSONALITY(p_hwfn)) return 0; p_mngr = p_hwfn->p_cxt_mngr; @@ -1033,7 +1033,7 @@ static int qed_ilt_blk_alloc(struct qed_hwfn *p_hwfn, u32 lines, line, sz_left, lines_to_skip = 0; /* Special handling for RoCE that supports dynamic allocation */ - if ((p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) && + if (QED_IS_RDMA_PERSONALITY(p_hwfn) && ((ilt_client == ILT_CLI_CDUT) || ilt_client == ILT_CLI_TSDM)) return 0; @@ -1833,7 +1833,7 @@ static void qed_tm_init_pf(struct qed_hwfn *p_hwfn) tm_offset += tm_iids.pf_tids[i]; } - if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) + if (QED_IS_RDMA_PERSONALITY(p_hwfn)) active_seg_mask = 0; STORE_RT_REG(p_hwfn, TM_REG_PF_ENABLE_TASK_RT_OFFSET, active_seg_mask); @@ -2344,7 +2344,7 @@ qed_cxt_dynamic_ilt_alloc(struct qed_hwfn *p_hwfn, last_cid_allocated - 1); if (!p_hwfn->b_rdma_enabled_in_prs) { - /* Enable RoCE search */ + /* Enable RDMA search */ qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 1); p_hwfn->b_rdma_enabled_in_prs = true; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 49667ad9042d..68e61823bfc0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -936,7 +936,7 @@ int qed_resc_alloc(struct qed_dev *cdev) /* EQ */ n_eqes = qed_chain_get_capacity(&p_hwfn->p_spq->chain); - if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) { + if (QED_IS_RDMA_PERSONALITY(p_hwfn)) { num_cons = qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ROCE, NULL) * 2; @@ -2057,7 +2057,7 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) qed_int_get_num_sbs(p_hwfn, &sb_cnt); if (IS_ENABLED(CONFIG_QED_RDMA) && - p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) { + QED_IS_RDMA_PERSONALITY(p_hwfn)) { /* Roce CNQ each requires: 1 status block + 1 CNQ. We divide * the status blocks equally between L2 / RoCE but with * consideration as to how many l2 queues / cnqs we have. @@ -2068,9 +2068,7 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) non_l2_sbs = feat_num[QED_RDMA_CNQ]; } - - if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE || - p_hwfn->hw_info.personality == QED_PCI_ETH) { + if (QED_IS_L2_PERSONALITY(p_hwfn)) { /* Start by allocating VF queues, then PF's */ feat_num[QED_VF_L2_QUE] = min_t(u32, RESC_NUM(p_hwfn, QED_L2_QUEUE), @@ -2083,12 +2081,12 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn) QED_VF_L2_QUE)); } - if (p_hwfn->hw_info.personality == QED_PCI_FCOE) + if (QED_IS_FCOE_PERSONALITY(p_hwfn)) feat_num[QED_FCOE_CQ] = min_t(u32, sb_cnt.cnt, RESC_NUM(p_hwfn, QED_CMDQS_CQS)); - if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) + if (QED_IS_ISCSI_PERSONALITY(p_hwfn)) feat_num[QED_ISCSI_CQ] = min_t(u32, sb_cnt.cnt, RESC_NUM(p_hwfn, QED_CMDQS_CQS)); diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index e57699bfbdfa..27ea54ba7e1b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -79,8 +79,7 @@ int qed_l2_alloc(struct qed_hwfn *p_hwfn) unsigned long **pp_qids; u32 i; - if (p_hwfn->hw_info.personality != QED_PCI_ETH && - p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + if (!QED_IS_L2_PERSONALITY(p_hwfn)) return 0; p_l2_info = kzalloc(sizeof(*p_l2_info), GFP_KERNEL); diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 17f9b0a7b553..be66f19d577d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -1421,7 +1421,7 @@ int qed_ll2_establish_connection(void *cxt, u8 connection_handle) if (rc) goto out; - if (p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE) + if (!QED_IS_RDMA_PERSONALITY(p_hwfn)) qed_wr(p_hwfn, p_ptt, PRS_REG_USE_LIGHT_L2, 1); qed_ll2_establish_connection_ooo(p_hwfn, p_ll2_conn); diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 16cc30b11cce..b11399606990 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -237,6 +237,8 @@ err0: int qed_fill_dev_info(struct qed_dev *cdev, struct qed_dev_info *dev_info) { + struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); + struct qed_hw_info *hw_info = &p_hwfn->hw_info; struct qed_tunnel_info *tun = &cdev->tunnel; struct qed_ptt *ptt; @@ -260,11 +262,10 @@ int qed_fill_dev_info(struct qed_dev *cdev, dev_info->pci_mem_start = cdev->pci_params.mem_start; dev_info->pci_mem_end = cdev->pci_params.mem_end; dev_info->pci_irq = cdev->pci_params.irq; - dev_info->rdma_supported = (cdev->hwfns[0].hw_info.personality == - QED_PCI_ETH_ROCE); + dev_info->rdma_supported = QED_IS_RDMA_PERSONALITY(p_hwfn); dev_info->is_mf_default = IS_MF_DEFAULT(&cdev->hwfns[0]); dev_info->dev_type = cdev->type; - ether_addr_copy(dev_info->hw_mac, cdev->hwfns[0].hw_info.hw_mac_addr); + ether_addr_copy(dev_info->hw_mac, hw_info->hw_mac_addr); if (IS_PF(cdev)) { dev_info->fw_major = FW_MAJOR_VERSION; @@ -274,8 +275,7 @@ int qed_fill_dev_info(struct qed_dev *cdev, dev_info->mf_mode = cdev->mf_mode; dev_info->tx_switching = true; - if (QED_LEADING_HWFN(cdev)->hw_info.b_wol_support == - QED_WOL_SUPPORT_PME) + if (hw_info->b_wol_support == QED_WOL_SUPPORT_PME) dev_info->wol_support = true; dev_info->abs_pf_id = QED_LEADING_HWFN(cdev)->abs_pf_id; @@ -304,7 +304,7 @@ int qed_fill_dev_info(struct qed_dev *cdev, &dev_info->mfw_rev, NULL); } - dev_info->mtu = QED_LEADING_HWFN(cdev)->hw_info.mtu; + dev_info->mtu = hw_info->mtu; return 0; } @@ -790,7 +790,7 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev, cdev->num_hwfns; if (!IS_ENABLED(CONFIG_QED_RDMA) || - QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH_ROCE) + !QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) return 0; for_each_hwfn(cdev, i) @@ -931,8 +931,7 @@ static void qed_update_pf_params(struct qed_dev *cdev, /* In case we might support RDMA, don't allow qede to be greedy * with the L2 contexts. Allow for 64 queues [rx, tx, xdp] per hwfn. */ - if (QED_LEADING_HWFN(cdev)->hw_info.personality == - QED_PCI_ETH_ROCE) { + if (QED_IS_RDMA_PERSONALITY(QED_LEADING_HWFN(cdev))) { u16 *num_cons; num_cons = ¶ms->eth_pf_params.num_cons; -- cgit v1.2.3 From 67b40dccc45ff5d488aad17114e80e00029fd854 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:22 +0300 Subject: qed: Implement iWARP initialization, teardown and qp operations This patch adds iWARP support for flows that have common code between RoCE and iWARP, such as initialization, teardown and qp setup verbs: create, destroy, modify, query. It introduces the iWARP specific files qed_iwarp.[ch] and iwarp_common.h Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/Makefile | 2 +- drivers/net/ethernet/qlogic/qed/qed_dev.c | 9 +- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 1 + drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 531 ++++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_iwarp.h | 85 +++++ drivers/net/ethernet/qlogic/qed/qed_rdma.c | 133 +++++-- drivers/net/ethernet/qlogic/qed/qed_rdma.h | 3 + drivers/net/ethernet/qlogic/qed/qed_roce.c | 20 ++ drivers/net/ethernet/qlogic/qed/qed_sp.h | 5 +- 9 files changed, 749 insertions(+), 40 deletions(-) create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iwarp.c create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iwarp.h (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile index 67452380b60e..82dd47068e18 100644 --- a/drivers/net/ethernet/qlogic/qed/Makefile +++ b/drivers/net/ethernet/qlogic/qed/Makefile @@ -5,6 +5,6 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \ qed_selftest.o qed_dcbx.o qed_debug.o qed_ptp.o qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o qed-$(CONFIG_QED_LL2) += qed_ll2.o -qed-$(CONFIG_QED_RDMA) += qed_roce.o qed_rdma.o +qed-$(CONFIG_QED_RDMA) += qed_roce.o qed_rdma.o qed_iwarp.o qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o qed_ooo.o qed-$(CONFIG_QED_FCOE) += qed_fcoe.o diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 68e61823bfc0..6c8505dc5c31 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -937,8 +937,15 @@ int qed_resc_alloc(struct qed_dev *cdev) /* EQ */ n_eqes = qed_chain_get_capacity(&p_hwfn->p_spq->chain); if (QED_IS_RDMA_PERSONALITY(p_hwfn)) { + enum protocol_type rdma_proto; + + if (QED_IS_ROCE_PERSONALITY(p_hwfn)) + rdma_proto = PROTOCOLID_ROCE; + else + rdma_proto = PROTOCOLID_IWARP; + num_cons = qed_cxt_get_proto_cid_count(p_hwfn, - PROTOCOLID_ROCE, + rdma_proto, NULL) * 2; n_eqes += num_cons + 2 * MAX_NUM_VFS_BB; } else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) { diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 3bf3614b3084..31fb0bffa098 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c new file mode 100644 index 000000000000..a8bd5f8edec6 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -0,0 +1,531 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015-2017 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "qed_cxt.h" +#include "qed_hw.h" +#include "qed_rdma.h" +#include "qed_reg_addr.h" +#include "qed_sp.h" + +#define QED_IWARP_ORD_DEFAULT 32 +#define QED_IWARP_IRD_DEFAULT 32 +#define QED_IWARP_RCV_WND_SIZE_DEF (256 * 1024) +#define QED_IWARP_RCV_WND_SIZE_MIN (64 * 1024) +#define QED_IWARP_TS_EN BIT(0) +#define QED_IWARP_PARAM_CRC_NEEDED (1) +#define QED_IWARP_PARAM_P2P (1) + +static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn, + u8 fw_event_code, u16 echo, + union event_ring_data *data, + u8 fw_return_code); + +/* Override devinfo with iWARP specific values */ +void qed_iwarp_init_devinfo(struct qed_hwfn *p_hwfn) +{ + struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev; + + dev->max_inline = IWARP_REQ_MAX_INLINE_DATA_SIZE; + dev->max_qp = min_t(u32, + IWARP_MAX_QPS, + p_hwfn->p_rdma_info->num_qps); + + dev->max_cq = dev->max_qp; + + dev->max_qp_resp_rd_atomic_resc = QED_IWARP_IRD_DEFAULT; + dev->max_qp_req_rd_atomic_resc = QED_IWARP_ORD_DEFAULT; +} + +void qed_iwarp_init_hw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + p_hwfn->rdma_prs_search_reg = PRS_REG_SEARCH_TCP; + qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 1); + p_hwfn->b_rdma_enabled_in_prs = true; +} + +static void qed_iwarp_cid_cleaned(struct qed_hwfn *p_hwfn, u32 cid) +{ + cid -= qed_cxt_get_proto_cid_start(p_hwfn, p_hwfn->p_rdma_info->proto); + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->cid_map, cid); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); +} + +static int qed_iwarp_alloc_cid(struct qed_hwfn *p_hwfn, u32 *cid) +{ + int rc; + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + rc = qed_rdma_bmap_alloc_id(p_hwfn, &p_hwfn->p_rdma_info->cid_map, cid); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + if (rc) { + DP_NOTICE(p_hwfn, "Failed in allocating iwarp cid\n"); + return rc; + } + *cid += qed_cxt_get_proto_cid_start(p_hwfn, p_hwfn->p_rdma_info->proto); + + rc = qed_cxt_dynamic_ilt_alloc(p_hwfn, QED_ELEM_CXT, *cid); + if (rc) + qed_iwarp_cid_cleaned(p_hwfn, *cid); + + return rc; +} + +int qed_iwarp_create_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + struct qed_rdma_create_qp_out_params *out_params) +{ + struct iwarp_create_qp_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + u16 physical_queue; + u32 cid; + int rc; + + qp->shared_queue = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + IWARP_SHARED_QUEUE_PAGE_SIZE, + &qp->shared_queue_phys_addr, + GFP_KERNEL); + if (!qp->shared_queue) + return -ENOMEM; + + out_params->sq_pbl_virt = (u8 *)qp->shared_queue + + IWARP_SHARED_QUEUE_PAGE_SQ_PBL_OFFSET; + out_params->sq_pbl_phys = qp->shared_queue_phys_addr + + IWARP_SHARED_QUEUE_PAGE_SQ_PBL_OFFSET; + out_params->rq_pbl_virt = (u8 *)qp->shared_queue + + IWARP_SHARED_QUEUE_PAGE_RQ_PBL_OFFSET; + out_params->rq_pbl_phys = qp->shared_queue_phys_addr + + IWARP_SHARED_QUEUE_PAGE_RQ_PBL_OFFSET; + + rc = qed_iwarp_alloc_cid(p_hwfn, &cid); + if (rc) + goto err1; + + qp->icid = (u16)cid; + + memset(&init_data, 0, sizeof(init_data)); + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.cid = qp->icid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + IWARP_RAMROD_CMD_ID_CREATE_QP, + PROTOCOLID_IWARP, &init_data); + if (rc) + goto err2; + + p_ramrod = &p_ent->ramrod.iwarp_create_qp; + + SET_FIELD(p_ramrod->flags, + IWARP_CREATE_QP_RAMROD_DATA_FMR_AND_RESERVED_EN, + qp->fmr_and_reserved_lkey); + + SET_FIELD(p_ramrod->flags, + IWARP_CREATE_QP_RAMROD_DATA_SIGNALED_COMP, qp->signal_all); + + SET_FIELD(p_ramrod->flags, + IWARP_CREATE_QP_RAMROD_DATA_RDMA_RD_EN, + qp->incoming_rdma_read_en); + + SET_FIELD(p_ramrod->flags, + IWARP_CREATE_QP_RAMROD_DATA_RDMA_WR_EN, + qp->incoming_rdma_write_en); + + SET_FIELD(p_ramrod->flags, + IWARP_CREATE_QP_RAMROD_DATA_ATOMIC_EN, + qp->incoming_atomic_en); + + SET_FIELD(p_ramrod->flags, + IWARP_CREATE_QP_RAMROD_DATA_SRQ_FLG, qp->use_srq); + + p_ramrod->pd = qp->pd; + p_ramrod->sq_num_pages = qp->sq_num_pages; + p_ramrod->rq_num_pages = qp->rq_num_pages; + + p_ramrod->qp_handle_for_cqe.hi = cpu_to_le32(qp->qp_handle.hi); + p_ramrod->qp_handle_for_cqe.lo = cpu_to_le32(qp->qp_handle.lo); + + p_ramrod->cq_cid_for_sq = + cpu_to_le32((p_hwfn->hw_info.opaque_fid << 16) | qp->sq_cq_id); + p_ramrod->cq_cid_for_rq = + cpu_to_le32((p_hwfn->hw_info.opaque_fid << 16) | qp->rq_cq_id); + + p_ramrod->dpi = cpu_to_le16(qp->dpi); + + physical_queue = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD); + p_ramrod->physical_q0 = cpu_to_le16(physical_queue); + physical_queue = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_ACK); + p_ramrod->physical_q1 = cpu_to_le16(physical_queue); + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + if (rc) + goto err2; + + return rc; + +err2: + qed_iwarp_cid_cleaned(p_hwfn, cid); +err1: + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + IWARP_SHARED_QUEUE_PAGE_SIZE, + qp->shared_queue, qp->shared_queue_phys_addr); + + return rc; +} + +static int qed_iwarp_modify_fw(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) +{ + struct iwarp_modify_qp_ramrod_data *p_ramrod; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + int rc; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + IWARP_RAMROD_CMD_ID_MODIFY_QP, + p_hwfn->p_rdma_info->proto, &init_data); + if (rc) + return rc; + + p_ramrod = &p_ent->ramrod.iwarp_modify_qp; + SET_FIELD(p_ramrod->flags, IWARP_MODIFY_QP_RAMROD_DATA_STATE_TRANS_EN, + 0x1); + if (qp->iwarp_state == QED_IWARP_QP_STATE_CLOSING) + p_ramrod->transition_to_state = IWARP_MODIFY_QP_STATE_CLOSING; + else + p_ramrod->transition_to_state = IWARP_MODIFY_QP_STATE_ERROR; + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QP(0x%x)rc=%d\n", qp->icid, rc); + + return rc; +} + +enum qed_iwarp_qp_state qed_roce2iwarp_state(enum qed_roce_qp_state state) +{ + switch (state) { + case QED_ROCE_QP_STATE_RESET: + case QED_ROCE_QP_STATE_INIT: + case QED_ROCE_QP_STATE_RTR: + return QED_IWARP_QP_STATE_IDLE; + case QED_ROCE_QP_STATE_RTS: + return QED_IWARP_QP_STATE_RTS; + case QED_ROCE_QP_STATE_SQD: + return QED_IWARP_QP_STATE_CLOSING; + case QED_ROCE_QP_STATE_ERR: + return QED_IWARP_QP_STATE_ERROR; + case QED_ROCE_QP_STATE_SQE: + return QED_IWARP_QP_STATE_TERMINATE; + default: + return QED_IWARP_QP_STATE_ERROR; + } +} + +static enum qed_roce_qp_state +qed_iwarp2roce_state(enum qed_iwarp_qp_state state) +{ + switch (state) { + case QED_IWARP_QP_STATE_IDLE: + return QED_ROCE_QP_STATE_INIT; + case QED_IWARP_QP_STATE_RTS: + return QED_ROCE_QP_STATE_RTS; + case QED_IWARP_QP_STATE_TERMINATE: + return QED_ROCE_QP_STATE_SQE; + case QED_IWARP_QP_STATE_CLOSING: + return QED_ROCE_QP_STATE_SQD; + case QED_IWARP_QP_STATE_ERROR: + return QED_ROCE_QP_STATE_ERR; + default: + return QED_ROCE_QP_STATE_ERR; + } +} + +const char *iwarp_state_names[] = { + "IDLE", + "RTS", + "TERMINATE", + "CLOSING", + "ERROR", +}; + +int +qed_iwarp_modify_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + enum qed_iwarp_qp_state new_state, bool internal) +{ + enum qed_iwarp_qp_state prev_iw_state; + bool modify_fw = false; + int rc = 0; + + /* modify QP can be called from upper-layer or as a result of async + * RST/FIN... therefore need to protect + */ + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.qp_lock); + prev_iw_state = qp->iwarp_state; + + if (prev_iw_state == new_state) { + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.qp_lock); + return 0; + } + + switch (prev_iw_state) { + case QED_IWARP_QP_STATE_IDLE: + switch (new_state) { + case QED_IWARP_QP_STATE_RTS: + qp->iwarp_state = QED_IWARP_QP_STATE_RTS; + break; + case QED_IWARP_QP_STATE_ERROR: + qp->iwarp_state = QED_IWARP_QP_STATE_ERROR; + if (!internal) + modify_fw = true; + break; + default: + break; + } + break; + case QED_IWARP_QP_STATE_RTS: + switch (new_state) { + case QED_IWARP_QP_STATE_CLOSING: + if (!internal) + modify_fw = true; + + qp->iwarp_state = QED_IWARP_QP_STATE_CLOSING; + break; + case QED_IWARP_QP_STATE_ERROR: + if (!internal) + modify_fw = true; + qp->iwarp_state = QED_IWARP_QP_STATE_ERROR; + break; + default: + break; + } + break; + case QED_IWARP_QP_STATE_ERROR: + switch (new_state) { + case QED_IWARP_QP_STATE_IDLE: + + qp->iwarp_state = new_state; + break; + case QED_IWARP_QP_STATE_CLOSING: + /* could happen due to race... do nothing.... */ + break; + default: + rc = -EINVAL; + } + break; + case QED_IWARP_QP_STATE_TERMINATE: + case QED_IWARP_QP_STATE_CLOSING: + qp->iwarp_state = new_state; + break; + default: + break; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QP(0x%x) %s --> %s%s\n", + qp->icid, + iwarp_state_names[prev_iw_state], + iwarp_state_names[qp->iwarp_state], + internal ? "internal" : ""); + + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.qp_lock); + + if (modify_fw) + rc = qed_iwarp_modify_fw(p_hwfn, qp); + + return rc; +} + +int qed_iwarp_fw_destroy(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) +{ + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + int rc; + + /* Get SPQ entry */ + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + IWARP_RAMROD_CMD_ID_DESTROY_QP, + p_hwfn->p_rdma_info->proto, &init_data); + if (rc) + return rc; + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QP(0x%x) rc = %d\n", qp->icid, rc); + + return rc; +} + +int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) +{ + int rc = 0; + + if (qp->iwarp_state != QED_IWARP_QP_STATE_ERROR) { + rc = qed_iwarp_modify_qp(p_hwfn, qp, + QED_IWARP_QP_STATE_ERROR, false); + if (rc) + return rc; + } + + rc = qed_iwarp_fw_destroy(p_hwfn, qp); + + if (qp->shared_queue) + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + IWARP_SHARED_QUEUE_PAGE_SIZE, + qp->shared_queue, qp->shared_queue_phys_addr); + + return rc; +} + +#define QED_IWARP_MAX_CID_CLEAN_TIME 100 +#define QED_IWARP_MAX_NO_PROGRESS_CNT 5 + +/* This function waits for all the bits of a bmap to be cleared, as long as + * there is progress ( i.e. the number of bits left to be cleared decreases ) + * the function continues. + */ +static int +qed_iwarp_wait_cid_map_cleared(struct qed_hwfn *p_hwfn, struct qed_bmap *bmap) +{ + int prev_weight = 0; + int wait_count = 0; + int weight = 0; + + weight = bitmap_weight(bmap->bitmap, bmap->max_count); + prev_weight = weight; + + while (weight) { + msleep(QED_IWARP_MAX_CID_CLEAN_TIME); + + weight = bitmap_weight(bmap->bitmap, bmap->max_count); + + if (prev_weight == weight) { + wait_count++; + } else { + prev_weight = weight; + wait_count = 0; + } + + if (wait_count > QED_IWARP_MAX_NO_PROGRESS_CNT) { + DP_NOTICE(p_hwfn, + "%s bitmap wait timed out (%d cids pending)\n", + bmap->name, weight); + return -EBUSY; + } + } + return 0; +} + +static int qed_iwarp_wait_for_all_cids(struct qed_hwfn *p_hwfn) +{ + /* Now wait for all cids to be completed */ + return qed_iwarp_wait_cid_map_cleared(p_hwfn, + &p_hwfn->p_rdma_info->cid_map); +} + +int qed_iwarp_alloc(struct qed_hwfn *p_hwfn) +{ + spin_lock_init(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + return 0; +} + +void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn) +{ +} + +int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_rdma_start_in_params *params) +{ + struct qed_iwarp_info *iwarp_info; + u32 rcv_wnd_size; + int rc = 0; + + iwarp_info = &p_hwfn->p_rdma_info->iwarp; + + iwarp_info->tcp_flags = QED_IWARP_TS_EN; + rcv_wnd_size = QED_IWARP_RCV_WND_SIZE_DEF; + + /* value 0 is used for ilog2(QED_IWARP_RCV_WND_SIZE_MIN) */ + iwarp_info->rcv_wnd_scale = ilog2(rcv_wnd_size) - + ilog2(QED_IWARP_RCV_WND_SIZE_MIN); + iwarp_info->crc_needed = QED_IWARP_PARAM_CRC_NEEDED; + iwarp_info->mpa_rev = MPA_NEGOTIATION_TYPE_ENHANCED; + + iwarp_info->peer2peer = QED_IWARP_PARAM_P2P; + + spin_lock_init(&p_hwfn->p_rdma_info->iwarp.qp_lock); + + qed_spq_register_async_cb(p_hwfn, PROTOCOLID_IWARP, + qed_iwarp_async_event); + + return rc; +} + +int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + int rc; + + rc = qed_iwarp_wait_for_all_cids(p_hwfn); + if (rc) + return rc; + + qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_IWARP); + + return 0; +} + +static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn, + u8 fw_event_code, u16 echo, + union event_ring_data *data, + u8 fw_return_code) +{ + return 0; +} + +void +qed_iwarp_query_qp(struct qed_rdma_qp *qp, + struct qed_rdma_query_qp_out_params *out_params) +{ + out_params->state = qed_iwarp2roce_state(qp->iwarp_state); +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h new file mode 100644 index 000000000000..05e5e45be6cf --- /dev/null +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h @@ -0,0 +1,85 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015-2017 QLogic Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and /or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _QED_IWARP_H +#define _QED_IWARP_H + +enum qed_iwarp_qp_state { + QED_IWARP_QP_STATE_IDLE, + QED_IWARP_QP_STATE_RTS, + QED_IWARP_QP_STATE_TERMINATE, + QED_IWARP_QP_STATE_CLOSING, + QED_IWARP_QP_STATE_ERROR, +}; + +enum qed_iwarp_qp_state qed_roce2iwarp_state(enum qed_roce_qp_state state); + +struct qed_iwarp_info { + spinlock_t iw_lock; /* for iwarp resources */ + spinlock_t qp_lock; /* for teardown races */ + u32 rcv_wnd_scale; + u16 max_mtu; + u8 mac_addr[ETH_ALEN]; + u8 crc_needed; + u8 tcp_flags; + u8 peer2peer; + enum mpa_negotiation_mode mpa_rev; + enum mpa_rtr_type rtr_type; +}; + +int qed_iwarp_alloc(struct qed_hwfn *p_hwfn); + +int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_rdma_start_in_params *params); + +int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); + +void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn); + +void qed_iwarp_init_devinfo(struct qed_hwfn *p_hwfn); + +void qed_iwarp_init_hw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); + +int qed_iwarp_create_qp(struct qed_hwfn *p_hwfn, + struct qed_rdma_qp *qp, + struct qed_rdma_create_qp_out_params *out_params); + +int qed_iwarp_modify_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp, + enum qed_iwarp_qp_state new_state, bool internal); + +int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp); + +int qed_iwarp_fw_destroy(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp); + +void qed_iwarp_query_qp(struct qed_rdma_qp *qp, + struct qed_rdma_query_qp_out_params *out_params); + +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c index df76e212f86e..ee6887f8c260 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -161,7 +161,10 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn, num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto, NULL); - p_rdma_info->num_qps = num_cons / 2; + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) + p_rdma_info->num_qps = num_cons; + else + p_rdma_info->num_qps = num_cons / 2; /* 2 cids per qp */ num_tasks = qed_cxt_get_proto_tid_count(p_hwfn, PROTOCOLID_ROCE); @@ -252,6 +255,13 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn, "Failed to allocate real cid bitmap, rc = %d\n", rc); goto free_cid_map; } + + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) + rc = qed_iwarp_alloc(p_hwfn); + + if (rc) + goto free_cid_map; + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Allocation successful\n"); return 0; @@ -329,6 +339,9 @@ static void qed_rdma_resc_free(struct qed_hwfn *p_hwfn) { struct qed_rdma_info *p_rdma_info = p_hwfn->p_rdma_info; + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) + qed_iwarp_resc_free(p_hwfn); + qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->cid_map, 1); qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->pd_map, 1); qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->dpi_map, 1); @@ -470,6 +483,9 @@ static void qed_rdma_init_devinfo(struct qed_hwfn *p_hwfn, if (pci_status_control & PCI_EXP_DEVCTL2_LTR_EN) SET_FIELD(dev->dev_caps, QED_RDMA_DEV_CAP_ATOMIC_OP, 1); + + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) + qed_iwarp_init_devinfo(p_hwfn); } static void qed_rdma_init_port(struct qed_hwfn *p_hwfn) @@ -490,29 +506,17 @@ static void qed_rdma_init_port(struct qed_hwfn *p_hwfn) static int qed_rdma_init_hw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 ll2_ethertype_en; + int rc = 0; DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Initializing HW\n"); p_hwfn->b_rdma_enabled_in_prs = false; - qed_wr(p_hwfn, p_ptt, PRS_REG_ROCE_DEST_QP_MAX_PF, 0); - - p_hwfn->rdma_prs_search_reg = PRS_REG_SEARCH_ROCE; - - /* We delay writing to this reg until first cid is allocated. See - * qed_cxt_dynamic_ilt_alloc function for more details - */ - ll2_ethertype_en = qed_rd(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN); - qed_wr(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN, - (ll2_ethertype_en | 0x01)); - - if (qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_ROCE) % 2) { - DP_NOTICE(p_hwfn, "The first RoCE's cid should be even\n"); - return -EINVAL; - } + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) + qed_iwarp_init_hw(p_hwfn, p_ptt); + else + rc = qed_roce_init_hw(p_hwfn, p_ptt); - DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Initializing HW - Done\n"); - return 0; + return rc; } static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn, @@ -544,7 +548,10 @@ static int qed_rdma_start_fw(struct qed_hwfn *p_hwfn, if (rc) return rc; - p_ramrod = &p_ent->ramrod.roce_init_func.rdma; + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) + p_ramrod = &p_ent->ramrod.iwarp_init_func.rdma; + else + p_ramrod = &p_ent->ramrod.roce_init_func.rdma; p_params_header = &p_ramrod->params_header; p_params_header->cnq_start_offset = (u8)RESC_START(p_hwfn, @@ -641,7 +648,15 @@ static int qed_rdma_setup(struct qed_hwfn *p_hwfn, if (rc) return rc; - qed_roce_setup(p_hwfn); + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) { + rc = qed_iwarp_setup(p_hwfn, p_ptt, params); + if (rc) + return rc; + } else { + rc = qed_roce_setup(p_hwfn); + if (rc) + return rc; + } return qed_rdma_start_fw(p_hwfn, params, p_ptt); } @@ -675,7 +690,16 @@ int qed_rdma_stop(void *rdma_cxt) qed_wr(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN, (ll2_ethertype_en & 0xFFFE)); - qed_roce_stop(p_hwfn); + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) { + rc = qed_iwarp_stop(p_hwfn, p_ptt); + if (rc) { + qed_ptt_release(p_hwfn, p_ptt); + return rc; + } + } else { + qed_roce_stop(p_hwfn); + } + qed_ptt_release(p_hwfn, p_ptt); /* Get SPQ entry */ @@ -810,7 +834,9 @@ static int qed_fill_rdma_dev_info(struct qed_dev *cdev, memset(info, 0, sizeof(*info)); - info->rdma_type = QED_RDMA_TYPE_ROCE; + info->rdma_type = QED_IS_ROCE_PERSONALITY(p_hwfn) ? + QED_RDMA_TYPE_ROCE : QED_RDMA_TYPE_IWARP; + info->user_dpm_enabled = (p_hwfn->db_bar_no_edpm == 0); qed_fill_dev_info(cdev, &info->common); @@ -1112,7 +1138,7 @@ static int qed_rdma_query_qp(void *rdma_cxt, struct qed_rdma_query_qp_out_params *out_params) { struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; - int rc; + int rc = 0; DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); @@ -1138,7 +1164,10 @@ static int qed_rdma_query_qp(void *rdma_cxt, out_params->max_dest_rd_atomic = qp->max_rd_atomic_resp; out_params->sqd_async = qp->sqd_async; - rc = qed_roce_query_qp(p_hwfn, qp, out_params); + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) + qed_iwarp_query_qp(qp, out_params); + else + rc = qed_roce_query_qp(p_hwfn, qp, out_params); DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Query QP, rc = %d\n", rc); return rc; @@ -1151,7 +1180,10 @@ static int qed_rdma_destroy_qp(void *rdma_cxt, struct qed_rdma_qp *qp) DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "icid = %08x\n", qp->icid); - rc = qed_roce_destroy_qp(p_hwfn, qp); + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) + rc = qed_iwarp_destroy_qp(p_hwfn, qp); + else + rc = qed_roce_destroy_qp(p_hwfn, qp); /* free qp params struct */ kfree(qp); @@ -1190,20 +1222,27 @@ qed_rdma_create_qp(void *rdma_cxt, return NULL; } + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) { + if (in_params->sq_num_pages * sizeof(struct regpair) > + IWARP_SHARED_QUEUE_PAGE_SQ_PBL_MAX_SIZE) { + DP_NOTICE(p_hwfn->cdev, + "Sq num pages: %d exceeds maximum\n", + in_params->sq_num_pages); + return NULL; + } + if (in_params->rq_num_pages * sizeof(struct regpair) > + IWARP_SHARED_QUEUE_PAGE_RQ_PBL_MAX_SIZE) { + DP_NOTICE(p_hwfn->cdev, + "Rq num pages: %d exceeds maximum\n", + in_params->rq_num_pages); + return NULL; + } + } + qp = kzalloc(sizeof(*qp), GFP_KERNEL); if (!qp) return NULL; - rc = qed_roce_alloc_cid(p_hwfn, &qp->icid); - qp->qpid = ((0xFF << 16) | qp->icid); - - DP_INFO(p_hwfn, "ROCE qpid=%x\n", qp->qpid); - - if (rc) { - kfree(qp); - return NULL; - } - qp->cur_state = QED_ROCE_QP_STATE_RESET; qp->qp_handle.hi = cpu_to_le32(in_params->qp_handle_hi); qp->qp_handle.lo = cpu_to_le32(in_params->qp_handle_lo); @@ -1226,6 +1265,19 @@ qed_rdma_create_qp(void *rdma_cxt, qp->e2e_flow_control_en = qp->use_srq ? false : true; qp->stats_queue = in_params->stats_queue; + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) { + rc = qed_iwarp_create_qp(p_hwfn, qp, out_params); + qp->qpid = qp->icid; + } else { + rc = qed_roce_alloc_cid(p_hwfn, &qp->icid); + qp->qpid = ((0xFF << 16) | qp->icid); + } + + if (rc) { + kfree(qp); + return NULL; + } + out_params->icid = qp->icid; out_params->qp_id = qp->qpid; @@ -1324,7 +1376,14 @@ static int qed_rdma_modify_qp(void *rdma_cxt, qp->cur_state); } - rc = qed_roce_modify_qp(p_hwfn, qp, prev_state, params); + if (QED_IS_IWARP_PERSONALITY(p_hwfn)) { + enum qed_iwarp_qp_state new_state = + qed_roce2iwarp_state(qp->cur_state); + + rc = qed_iwarp_modify_qp(p_hwfn, qp, new_state, 0); + } else { + rc = qed_roce_modify_qp(p_hwfn, qp, prev_state, params); + } DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Modify QP, rc = %d\n", rc); return rc; diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.h b/drivers/net/ethernet/qlogic/qed/qed_rdma.h index d91e5c4069a6..90e4e0f13727 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.h +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.h @@ -42,6 +42,7 @@ #include "qed.h" #include "qed_dev_api.h" #include "qed_hsi.h" +#include "qed_iwarp.h" #include "qed_roce.h" #define QED_RDMA_MAX_FMR (RDMA_MAX_TIDS) @@ -97,6 +98,7 @@ struct qed_rdma_info { u16 queue_zone_base; u16 max_queue_zones; enum protocol_type proto; + struct qed_iwarp_info iwarp; }; struct qed_rdma_qp { @@ -105,6 +107,7 @@ struct qed_rdma_qp { u32 qpid; u16 icid; enum qed_roce_qp_state cur_state; + enum qed_iwarp_qp_state iwarp_state; bool use_srq; bool signal_all; bool fmr_and_reserved_lkey; diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index e53adc3d009b..fb7c2d1562ae 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -1149,3 +1149,23 @@ int qed_roce_setup(struct qed_hwfn *p_hwfn) qed_roce_async_event); } +int qed_roce_init_hw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + u32 ll2_ethertype_en; + + qed_wr(p_hwfn, p_ptt, PRS_REG_ROCE_DEST_QP_MAX_PF, 0); + + p_hwfn->rdma_prs_search_reg = PRS_REG_SEARCH_ROCE; + + ll2_ethertype_en = qed_rd(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN); + qed_wr(p_hwfn, p_ptt, PRS_REG_LIGHT_L2_ETHERTYPE_EN, + (ll2_ethertype_en | 0x01)); + + if (qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_ROCE) % 2) { + DP_NOTICE(p_hwfn, "The first RoCE's cid should be even\n"); + return -EINVAL; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Initializing HW - Done\n"); + return 0; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index 56c95fb9a26d..c3752c56e54d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -104,12 +104,15 @@ union ramrod_data { struct roce_query_qp_req_ramrod_data roce_query_qp_req; struct roce_destroy_qp_resp_ramrod_data roce_destroy_qp_resp; struct roce_destroy_qp_req_ramrod_data roce_destroy_qp_req; + struct roce_init_func_ramrod_data roce_init_func; struct rdma_create_cq_ramrod_data rdma_create_cq; struct rdma_destroy_cq_ramrod_data rdma_destroy_cq; struct rdma_srq_create_ramrod_data rdma_create_srq; struct rdma_srq_destroy_ramrod_data rdma_destroy_srq; struct rdma_srq_modify_ramrod_data rdma_modify_srq; - struct roce_init_func_ramrod_data roce_init_func; + struct iwarp_create_qp_ramrod_data iwarp_create_qp; + struct iwarp_modify_qp_ramrod_data iwarp_modify_qp; + struct iwarp_init_func_ramrod_data iwarp_init_func; struct fcoe_init_ramrod_params fcoe_init; struct fcoe_conn_offload_ramrod_params fcoe_conn_ofld; struct fcoe_conn_terminate_ramrod_params fcoe_conn_terminate; -- cgit v1.2.3 From 526d1d05e456c9cfc077694d18b5f521e2338f18 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:23 +0300 Subject: qed: Rename some ll2 related defines Make some names more generic as they will be used by iWARP too. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 2 +- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 29 ++++++++++++++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 22e1171c317e..fd8cd5e17121 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -779,7 +779,7 @@ static inline u8 qed_concrete_to_sw_fid(struct qed_dev *cdev, } #define PURE_LB_TC 8 -#define OOO_LB_TC 9 +#define PKT_LB_TC 9 int qed_configure_vport_wfq(struct qed_dev *cdev, u16 vp_id, u32 rate); void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev, diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index be66f19d577d..e235fb267ab9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -309,7 +309,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) list_del(&p_pkt->list_entry); b_last_packet = list_empty(&p_tx->active_descq); list_add_tail(&p_pkt->list_entry, &p_tx->free_descq); - if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) { + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) { struct qed_ooo_buffer *p_buffer; p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; @@ -532,7 +532,7 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) list_move_tail(&p_pkt->list_entry, &p_rx->free_descq); - if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) { + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) { struct qed_ooo_buffer *p_buffer; p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; @@ -893,8 +893,7 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->drop_ttl0_flg = p_ll2_conn->input.rx_drop_ttl0_flg; p_ramrod->inner_vlan_removal_en = p_ll2_conn->input.rx_vlan_removal_en; p_ramrod->queue_id = p_ll2_conn->queue_id; - p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_ISCSI_OOO) ? 0 - : 1; + p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_OOO) ? 0 : 1; if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) && p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE)) { @@ -924,7 +923,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, if (!QED_LL2_TX_REGISTERED(p_ll2_conn)) return 0; - if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) p_ll2_conn->tx_stats_en = 0; else p_ll2_conn->tx_stats_en = 1; @@ -955,10 +954,10 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->pbl_size = cpu_to_le16(pbl_size); switch (p_ll2_conn->input.tx_tc) { - case LB_TC: + case PURE_LB_TC: pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LB); break; - case OOO_LB_TC: + case PKT_LB_TC: pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OOO); break; default: @@ -973,7 +972,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->conn_type = PROTOCOLID_FCOE; break; case QED_LL2_TYPE_ISCSI: - case QED_LL2_TYPE_ISCSI_OOO: + case QED_LL2_TYPE_OOO: p_ramrod->conn_type = PROTOCOLID_ISCSI; break; case QED_LL2_TYPE_ROCE: @@ -1142,7 +1141,7 @@ qed_ll2_acquire_connection_ooo(struct qed_hwfn *p_hwfn, u16 buf_idx; int rc = 0; - if (p_ll2_info->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_info->input.conn_type != QED_LL2_TYPE_OOO) return rc; /* Correct number of requested OOO buffers if needed */ @@ -1280,7 +1279,7 @@ int qed_ll2_acquire_connection(void *cxt, struct qed_ll2_acquire_data *data) goto q_allocate_fail; /* Register callbacks for the Rx/Tx queues */ - if (data->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) { + if (data->input.conn_type == QED_LL2_TYPE_OOO) { comp_rx_cb = qed_ll2_lb_rxq_completion; comp_tx_cb = qed_ll2_lb_txq_completion; } else { @@ -1339,7 +1338,7 @@ static void qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_conn) { - if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_OOO) return; qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); @@ -1794,7 +1793,7 @@ int qed_ll2_terminate_connection(void *cxt, u8 connection_handle) qed_ll2_rxq_flush(p_hwfn, connection_handle); } - if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_FCOE) { @@ -1816,7 +1815,7 @@ static void qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn, { struct qed_ooo_buffer *p_buffer; - if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->input.conn_type != QED_LL2_TYPE_OOO) return; qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); @@ -2063,7 +2062,7 @@ static void qed_ll2_set_conn_data(struct qed_dev *cdev, ll2_cbs.cookie = QED_LEADING_HWFN(cdev); if (lb) { - data->input.tx_tc = OOO_LB_TC; + data->input.tx_tc = PKT_LB_TC; data->input.tx_dest = QED_LL2_TX_DEST_LB; } else { data->input.tx_tc = 0; @@ -2080,7 +2079,7 @@ static int qed_ll2_start_ooo(struct qed_dev *cdev, int rc; qed_ll2_set_conn_data(cdev, &data, params, - QED_LL2_TYPE_ISCSI_OOO, handle, true); + QED_LL2_TYPE_OOO, handle, true); rc = qed_ll2_acquire_connection(hwfn, &data); if (rc) { -- cgit v1.2.3 From cc4ad324e7e247bb4979791dd4f2ff11419d9742 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:24 +0300 Subject: qed: Add iWARP support in ll2 connections Add a new connection type for iWARP ll2 connections for setting correct ll2 filters and connection type to FW. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index e235fb267ab9..c06ad4f0758e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -896,7 +896,8 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_OOO) ? 0 : 1; if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) && - p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE)) { + p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE) && + (conn_type != QED_LL2_TYPE_IWARP)) { p_ramrod->mf_si_bcast_accept_all = 1; p_ramrod->mf_si_mcast_accept_all = 1; } else { @@ -972,12 +973,20 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->conn_type = PROTOCOLID_FCOE; break; case QED_LL2_TYPE_ISCSI: - case QED_LL2_TYPE_OOO: p_ramrod->conn_type = PROTOCOLID_ISCSI; break; case QED_LL2_TYPE_ROCE: p_ramrod->conn_type = PROTOCOLID_ROCE; break; + case QED_LL2_TYPE_IWARP: + p_ramrod->conn_type = PROTOCOLID_IWARP; + break; + case QED_LL2_TYPE_OOO: + if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) + p_ramrod->conn_type = PROTOCOLID_ISCSI; + else + p_ramrod->conn_type = PROTOCOLID_IWARP; + break; default: p_ramrod->conn_type = PROTOCOLID_ETH; DP_NOTICE(p_hwfn, "Unknown connection type: %d\n", conn_type); -- cgit v1.2.3 From b5c29ca7dab75f29a7df6e82285742f830d8ed1a Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:25 +0300 Subject: qed: iWARP CM - setup a ll2 connection for handling SYN packets iWARP handles incoming SYN packets using the ll2 interface. This patch implements ll2 setup and teardown. Additional ll2 connections will be used in the future which are not part of this patch series. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 211 +++++++++++++++++++++++++++- drivers/net/ethernet/qlogic/qed/qed_iwarp.h | 12 ++ 2 files changed, 220 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index a8bd5f8edec6..f3b4b32100f5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -29,8 +29,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include +#include #include "qed_cxt.h" #include "qed_hw.h" +#include "qed_ll2.h" #include "qed_rdma.h" #include "qed_reg_addr.h" #include "qed_sp.h" @@ -474,12 +477,214 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn) { } +static int +qed_iwarp_ll2_post_rx(struct qed_hwfn *p_hwfn, + struct qed_iwarp_ll2_buff *buf, u8 handle) +{ + int rc; + + rc = qed_ll2_post_rx_buffer(p_hwfn, handle, buf->data_phys_addr, + (u16)buf->buff_size, buf, 1); + if (rc) { + DP_NOTICE(p_hwfn, + "Failed to repost rx buffer to ll2 rc = %d, handle=%d\n", + rc, handle); + dma_free_coherent(&p_hwfn->cdev->pdev->dev, buf->buff_size, + buf->data, buf->data_phys_addr); + kfree(buf); + } + + return rc; +} + +static void +qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data) +{ + struct qed_iwarp_ll2_buff *buf = data->cookie; + struct qed_hwfn *p_hwfn = cxt; + + if (GET_FIELD(data->parse_flags, + PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED) && + GET_FIELD(data->parse_flags, PARSING_AND_ERR_FLAGS_L4CHKSMERROR)) { + DP_NOTICE(p_hwfn, "Syn packet received with checksum error\n"); + goto err; + } + + /* Process SYN packet - added later on in series */ + +err: + qed_iwarp_ll2_post_rx(p_hwfn, buf, + p_hwfn->p_rdma_info->iwarp.ll2_syn_handle); +} + +static void qed_iwarp_ll2_rel_rx_pkt(void *cxt, u8 connection_handle, + void *cookie, dma_addr_t rx_buf_addr, + bool b_last_packet) +{ + struct qed_iwarp_ll2_buff *buffer = cookie; + struct qed_hwfn *p_hwfn = cxt; + + dma_free_coherent(&p_hwfn->cdev->pdev->dev, buffer->buff_size, + buffer->data, buffer->data_phys_addr); + kfree(buffer); +} + +static void qed_iwarp_ll2_comp_tx_pkt(void *cxt, u8 connection_handle, + void *cookie, dma_addr_t first_frag_addr, + bool b_last_fragment, bool b_last_packet) +{ + struct qed_iwarp_ll2_buff *buffer = cookie; + struct qed_hwfn *p_hwfn = cxt; + + /* this was originally an rx packet, post it back */ + qed_iwarp_ll2_post_rx(p_hwfn, buffer, connection_handle); +} + +static void qed_iwarp_ll2_rel_tx_pkt(void *cxt, u8 connection_handle, + void *cookie, dma_addr_t first_frag_addr, + bool b_last_fragment, bool b_last_packet) +{ + struct qed_iwarp_ll2_buff *buffer = cookie; + struct qed_hwfn *p_hwfn = cxt; + + if (!buffer) + return; + + dma_free_coherent(&p_hwfn->cdev->pdev->dev, buffer->buff_size, + buffer->data, buffer->data_phys_addr); + + kfree(buffer); +} + +static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + struct qed_iwarp_info *iwarp_info = &p_hwfn->p_rdma_info->iwarp; + int rc = 0; + + if (iwarp_info->ll2_syn_handle != QED_IWARP_HANDLE_INVAL) { + rc = qed_ll2_terminate_connection(p_hwfn, + iwarp_info->ll2_syn_handle); + if (rc) + DP_INFO(p_hwfn, "Failed to terminate syn connection\n"); + + qed_ll2_release_connection(p_hwfn, iwarp_info->ll2_syn_handle); + iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL; + } + + qed_llh_remove_mac_filter(p_hwfn, + p_ptt, p_hwfn->p_rdma_info->iwarp.mac_addr); + return rc; +} + +static int +qed_iwarp_ll2_alloc_buffers(struct qed_hwfn *p_hwfn, + int num_rx_bufs, int buff_size, u8 ll2_handle) +{ + struct qed_iwarp_ll2_buff *buffer; + int rc = 0; + int i; + + for (i = 0; i < num_rx_bufs; i++) { + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) { + rc = -ENOMEM; + break; + } + + buffer->data = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + buff_size, + &buffer->data_phys_addr, + GFP_KERNEL); + if (!buffer->data) { + kfree(buffer); + rc = -ENOMEM; + break; + } + + buffer->buff_size = buff_size; + rc = qed_iwarp_ll2_post_rx(p_hwfn, buffer, ll2_handle); + if (rc) + /* buffers will be deallocated by qed_ll2 */ + break; + } + return rc; +} + +#define QED_IWARP_MAX_BUF_SIZE(mtu) \ + ALIGN((mtu) + ETH_HLEN + 2 * VLAN_HLEN + 2 + ETH_CACHE_LINE_SIZE, \ + ETH_CACHE_LINE_SIZE) + +static int +qed_iwarp_ll2_start(struct qed_hwfn *p_hwfn, + struct qed_rdma_start_in_params *params, + struct qed_ptt *p_ptt) +{ + struct qed_iwarp_info *iwarp_info; + struct qed_ll2_acquire_data data; + struct qed_ll2_cbs cbs; + int rc = 0; + + iwarp_info = &p_hwfn->p_rdma_info->iwarp; + iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL; + + iwarp_info->max_mtu = params->max_mtu; + + ether_addr_copy(p_hwfn->p_rdma_info->iwarp.mac_addr, params->mac_addr); + + rc = qed_llh_add_mac_filter(p_hwfn, p_ptt, params->mac_addr); + if (rc) + return rc; + + /* Start SYN connection */ + cbs.rx_comp_cb = qed_iwarp_ll2_comp_syn_pkt; + cbs.rx_release_cb = qed_iwarp_ll2_rel_rx_pkt; + cbs.tx_comp_cb = qed_iwarp_ll2_comp_tx_pkt; + cbs.tx_release_cb = qed_iwarp_ll2_rel_tx_pkt; + cbs.cookie = p_hwfn; + + memset(&data, 0, sizeof(data)); + data.input.conn_type = QED_LL2_TYPE_IWARP; + data.input.mtu = QED_IWARP_MAX_SYN_PKT_SIZE; + data.input.rx_num_desc = QED_IWARP_LL2_SYN_RX_SIZE; + data.input.tx_num_desc = QED_IWARP_LL2_SYN_TX_SIZE; + data.input.tx_max_bds_per_packet = 1; /* will never be fragmented */ + data.input.tx_tc = PKT_LB_TC; + data.input.tx_dest = QED_LL2_TX_DEST_LB; + data.p_connection_handle = &iwarp_info->ll2_syn_handle; + data.cbs = &cbs; + + rc = qed_ll2_acquire_connection(p_hwfn, &data); + if (rc) { + DP_NOTICE(p_hwfn, "Failed to acquire LL2 connection\n"); + qed_llh_remove_mac_filter(p_hwfn, p_ptt, params->mac_addr); + return rc; + } + + rc = qed_ll2_establish_connection(p_hwfn, iwarp_info->ll2_syn_handle); + if (rc) { + DP_NOTICE(p_hwfn, "Failed to establish LL2 connection\n"); + goto err; + } + + rc = qed_iwarp_ll2_alloc_buffers(p_hwfn, + QED_IWARP_LL2_SYN_RX_SIZE, + QED_IWARP_MAX_SYN_PKT_SIZE, + iwarp_info->ll2_syn_handle); + if (rc) + goto err; + + return rc; +err: + qed_iwarp_ll2_stop(p_hwfn, p_ptt); + + return rc; +} + int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_rdma_start_in_params *params) { struct qed_iwarp_info *iwarp_info; u32 rcv_wnd_size; - int rc = 0; iwarp_info = &p_hwfn->p_rdma_info->iwarp; @@ -499,7 +704,7 @@ int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, qed_spq_register_async_cb(p_hwfn, PROTOCOLID_IWARP, qed_iwarp_async_event); - return rc; + return qed_iwarp_ll2_start(p_hwfn, params, p_ptt); } int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) @@ -512,7 +717,7 @@ int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) qed_spq_unregister_async_cb(p_hwfn, PROTOCOLID_IWARP); - return 0; + return qed_iwarp_ll2_stop(p_hwfn, p_ptt); } static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h index 05e5e45be6cf..068b8594f1c5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h @@ -42,6 +42,17 @@ enum qed_iwarp_qp_state { enum qed_iwarp_qp_state qed_roce2iwarp_state(enum qed_roce_qp_state state); +#define QED_IWARP_LL2_SYN_TX_SIZE (128) +#define QED_IWARP_LL2_SYN_RX_SIZE (256) +#define QED_IWARP_MAX_SYN_PKT_SIZE (128) +#define QED_IWARP_HANDLE_INVAL (0xff) + +struct qed_iwarp_ll2_buff { + void *data; + dma_addr_t data_phys_addr; + u32 buff_size; +}; + struct qed_iwarp_info { spinlock_t iw_lock; /* for iwarp resources */ spinlock_t qp_lock; /* for teardown races */ @@ -50,6 +61,7 @@ struct qed_iwarp_info { u8 mac_addr[ETH_ALEN]; u8 crc_needed; u8 tcp_flags; + u8 ll2_syn_handle; u8 peer2peer; enum mpa_negotiation_mode mpa_rev; enum mpa_rtr_type rtr_type; -- cgit v1.2.3 From 65a91a6cdb868a28b919ca133c0f9d9dfd9a635a Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:26 +0300 Subject: qed: iWARP CM add listener functions and initial SYN processing This patch adds the ability to add and remove listeners and identify whether the SYN packet received is intended for iWARP or not. If a listener is not found the SYN packet is posted back to the chip. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 269 +++++++++++++++++++++++++++- drivers/net/ethernet/qlogic/qed/qed_iwarp.h | 23 +++ drivers/net/ethernet/qlogic/qed/qed_rdma.c | 2 + 3 files changed, 291 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index f3b4b32100f5..2bab57c6bae8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -31,6 +31,10 @@ */ #include #include +#include +#include +#include +#include #include "qed_cxt.h" #include "qed_hw.h" #include "qed_ll2.h" @@ -477,6 +481,31 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn) { } +static void +qed_iwarp_print_cm_info(struct qed_hwfn *p_hwfn, + struct qed_iwarp_cm_info *cm_info) +{ + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "ip_version = %d\n", + cm_info->ip_version); + + if (cm_info->ip_version == QED_TCP_IPV4) + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "remote_ip %pI4h:%x, local_ip %pI4h:%x vlan=%x\n", + cm_info->remote_ip, cm_info->remote_port, + cm_info->local_ip, cm_info->local_port, + cm_info->vlan); + else + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "remote_ip %pI6h:%x, local_ip %pI6h:%x vlan=%x\n", + cm_info->remote_ip, cm_info->remote_port, + cm_info->local_ip, cm_info->local_port, + cm_info->vlan); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "private_data_len = %x ord = %d, ird = %d\n", + cm_info->private_data_len, cm_info->ord, cm_info->ird); +} + static int qed_iwarp_ll2_post_rx(struct qed_hwfn *p_hwfn, struct qed_iwarp_ll2_buff *buf, u8 handle) @@ -497,11 +526,147 @@ qed_iwarp_ll2_post_rx(struct qed_hwfn *p_hwfn, return rc; } +static struct qed_iwarp_listener * +qed_iwarp_get_listener(struct qed_hwfn *p_hwfn, + struct qed_iwarp_cm_info *cm_info) +{ + struct qed_iwarp_listener *listener = NULL; + static const u32 ip_zero[4] = { 0, 0, 0, 0 }; + bool found = false; + + qed_iwarp_print_cm_info(p_hwfn, cm_info); + + list_for_each_entry(listener, + &p_hwfn->p_rdma_info->iwarp.listen_list, + list_entry) { + if (listener->port == cm_info->local_port) { + if (!memcmp(listener->ip_addr, + ip_zero, sizeof(ip_zero))) { + found = true; + break; + } + + if (!memcmp(listener->ip_addr, + cm_info->local_ip, + sizeof(cm_info->local_ip)) && + (listener->vlan == cm_info->vlan)) { + found = true; + break; + } + } + } + + if (found) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "listener found = %p\n", + listener); + return listener; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "listener not found\n"); + return NULL; +} + +static int +qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn, + struct qed_iwarp_cm_info *cm_info, + void *buf, + u8 *remote_mac_addr, + u8 *local_mac_addr, + int *payload_len, int *tcp_start_offset) +{ + struct vlan_ethhdr *vethh; + bool vlan_valid = false; + struct ipv6hdr *ip6h; + struct ethhdr *ethh; + struct tcphdr *tcph; + struct iphdr *iph; + int eth_hlen; + int ip_hlen; + int eth_type; + int i; + + ethh = buf; + eth_type = ntohs(ethh->h_proto); + if (eth_type == ETH_P_8021Q) { + vlan_valid = true; + vethh = (struct vlan_ethhdr *)ethh; + cm_info->vlan = ntohs(vethh->h_vlan_TCI) & VLAN_VID_MASK; + eth_type = ntohs(vethh->h_vlan_encapsulated_proto); + } + + eth_hlen = ETH_HLEN + (vlan_valid ? sizeof(u32) : 0); + + memcpy(remote_mac_addr, ethh->h_source, ETH_ALEN); + + memcpy(local_mac_addr, ethh->h_dest, ETH_ALEN); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "eth_type =%d source mac: %pM\n", + eth_type, ethh->h_source); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "eth_hlen=%d destination mac: %pM\n", + eth_hlen, ethh->h_dest); + + iph = (struct iphdr *)((u8 *)(ethh) + eth_hlen); + + if (eth_type == ETH_P_IP) { + cm_info->local_ip[0] = ntohl(iph->daddr); + cm_info->remote_ip[0] = ntohl(iph->saddr); + cm_info->ip_version = TCP_IPV4; + + ip_hlen = (iph->ihl) * sizeof(u32); + *payload_len = ntohs(iph->tot_len) - ip_hlen; + } else if (eth_type == ETH_P_IPV6) { + ip6h = (struct ipv6hdr *)iph; + for (i = 0; i < 4; i++) { + cm_info->local_ip[i] = + ntohl(ip6h->daddr.in6_u.u6_addr32[i]); + cm_info->remote_ip[i] = + ntohl(ip6h->saddr.in6_u.u6_addr32[i]); + } + cm_info->ip_version = TCP_IPV6; + + ip_hlen = sizeof(*ip6h); + *payload_len = ntohs(ip6h->payload_len); + } else { + DP_NOTICE(p_hwfn, "Unexpected ethertype on ll2 %x\n", eth_type); + return -EINVAL; + } + + tcph = (struct tcphdr *)((u8 *)iph + ip_hlen); + + if (!tcph->syn) { + DP_NOTICE(p_hwfn, + "Only SYN type packet expected on this ll2 conn, iph->ihl=%d source=%d dest=%d\n", + iph->ihl, tcph->source, tcph->dest); + return -EINVAL; + } + + cm_info->local_port = ntohs(tcph->dest); + cm_info->remote_port = ntohs(tcph->source); + + qed_iwarp_print_cm_info(p_hwfn, cm_info); + + *tcp_start_offset = eth_hlen + ip_hlen; + + return 0; +} + static void qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data) { struct qed_iwarp_ll2_buff *buf = data->cookie; + struct qed_iwarp_listener *listener; + struct qed_ll2_tx_pkt_info tx_pkt; + struct qed_iwarp_cm_info cm_info; struct qed_hwfn *p_hwfn = cxt; + u8 remote_mac_addr[ETH_ALEN]; + u8 local_mac_addr[ETH_ALEN]; + int tcp_start_offset; + u8 ll2_syn_handle; + int payload_len; + int rc; + + memset(&cm_info, 0, sizeof(cm_info)); if (GET_FIELD(data->parse_flags, PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED) && @@ -510,11 +675,52 @@ qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data) goto err; } - /* Process SYN packet - added later on in series */ + rc = qed_iwarp_parse_rx_pkt(p_hwfn, &cm_info, (u8 *)(buf->data) + + data->u.placement_offset, remote_mac_addr, + local_mac_addr, &payload_len, + &tcp_start_offset); + if (rc) + goto err; + + /* Check if there is a listener for this 4-tuple+vlan */ + ll2_syn_handle = p_hwfn->p_rdma_info->iwarp.ll2_syn_handle; + listener = qed_iwarp_get_listener(p_hwfn, &cm_info); + if (!listener) { + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "SYN received on tuple not listened on parse_flags=%d packet len=%d\n", + data->parse_flags, data->length.packet_length); + + memset(&tx_pkt, 0, sizeof(tx_pkt)); + tx_pkt.num_of_bds = 1; + tx_pkt.vlan = data->vlan; + + if (GET_FIELD(data->parse_flags, + PARSING_AND_ERR_FLAGS_TAG8021QEXIST)) + SET_FIELD(tx_pkt.bd_flags, + CORE_TX_BD_DATA_VLAN_INSERTION, 1); + + tx_pkt.l4_hdr_offset_w = (data->length.packet_length) >> 2; + tx_pkt.tx_dest = QED_LL2_TX_DEST_LB; + tx_pkt.first_frag = buf->data_phys_addr + + data->u.placement_offset; + tx_pkt.first_frag_len = data->length.packet_length; + tx_pkt.cookie = buf; + + rc = qed_ll2_prepare_tx_packet(p_hwfn, ll2_syn_handle, + &tx_pkt, true); + + if (rc) { + DP_NOTICE(p_hwfn, + "Can't post SYN back to chip rc=%d\n", rc); + goto err; + } + return; + } + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Received syn on listening port\n"); err: - qed_iwarp_ll2_post_rx(p_hwfn, buf, - p_hwfn->p_rdma_info->iwarp.ll2_syn_handle); + qed_iwarp_ll2_post_rx(p_hwfn, buf, ll2_syn_handle); } static void qed_iwarp_ll2_rel_rx_pkt(void *cxt, u8 connection_handle, @@ -700,6 +906,7 @@ int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, iwarp_info->peer2peer = QED_IWARP_PARAM_P2P; spin_lock_init(&p_hwfn->p_rdma_info->iwarp.qp_lock); + INIT_LIST_HEAD(&p_hwfn->p_rdma_info->iwarp.listen_list); qed_spq_register_async_cb(p_hwfn, PROTOCOLID_IWARP, qed_iwarp_async_event); @@ -728,6 +935,62 @@ static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn, return 0; } +int +qed_iwarp_create_listen(void *rdma_cxt, + struct qed_iwarp_listen_in *iparams, + struct qed_iwarp_listen_out *oparams) +{ + struct qed_hwfn *p_hwfn = rdma_cxt; + struct qed_iwarp_listener *listener; + + listener = kzalloc(sizeof(*listener), GFP_KERNEL); + if (!listener) + return -ENOMEM; + + listener->ip_version = iparams->ip_version; + memcpy(listener->ip_addr, iparams->ip_addr, sizeof(listener->ip_addr)); + listener->port = iparams->port; + listener->vlan = iparams->vlan; + + listener->event_cb = iparams->event_cb; + listener->cb_context = iparams->cb_context; + listener->max_backlog = iparams->max_backlog; + oparams->handle = listener; + + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + list_add_tail(&listener->list_entry, + &p_hwfn->p_rdma_info->iwarp.listen_list); + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "callback=%p handle=%p ip=%x:%x:%x:%x port=0x%x vlan=0x%x\n", + listener->event_cb, + listener, + listener->ip_addr[0], + listener->ip_addr[1], + listener->ip_addr[2], + listener->ip_addr[3], listener->port, listener->vlan); + + return 0; +} + +int qed_iwarp_destroy_listen(void *rdma_cxt, void *handle) +{ + struct qed_iwarp_listener *listener = handle; + struct qed_hwfn *p_hwfn = rdma_cxt; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "handle=%p\n", handle); + + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + list_del(&listener->list_entry); + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + kfree(listener); + + return 0; +} + void qed_iwarp_query_qp(struct qed_rdma_qp *qp, struct qed_rdma_query_qp_out_params *out_params) diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h index 068b8594f1c5..29005ac83a6a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h @@ -54,6 +54,7 @@ struct qed_iwarp_ll2_buff { }; struct qed_iwarp_info { + struct list_head listen_list; /* qed_iwarp_listener */ spinlock_t iw_lock; /* for iwarp resources */ spinlock_t qp_lock; /* for teardown races */ u32 rcv_wnd_scale; @@ -67,6 +68,21 @@ struct qed_iwarp_info { enum mpa_rtr_type rtr_type; }; +struct qed_iwarp_listener { + struct list_head list_entry; + + /* The event_cb function is called for connection requests. + * The cb_context is passed to the event_cb function. + */ + iwarp_event_handler event_cb; + void *cb_context; + u32 max_backlog; + u32 ip_addr[4]; + u16 port; + u16 vlan; + u8 ip_version; +}; + int qed_iwarp_alloc(struct qed_hwfn *p_hwfn); int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, @@ -94,4 +110,11 @@ int qed_iwarp_fw_destroy(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp); void qed_iwarp_query_qp(struct qed_rdma_qp *qp, struct qed_rdma_query_qp_out_params *out_params); +int +qed_iwarp_create_listen(void *rdma_cxt, + struct qed_iwarp_listen_in *iparams, + struct qed_iwarp_listen_out *oparams); + +int qed_iwarp_destroy_listen(void *rdma_cxt, void *handle); + #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c index ee6887f8c260..29de915007a0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -1772,6 +1772,8 @@ static const struct qed_rdma_ops qed_rdma_ops_pass = { .ll2_set_fragment_of_tx_packet = &qed_ll2_set_fragment_of_tx_packet, .ll2_set_mac_filter = &qed_roce_ll2_set_mac_filter, .ll2_get_stats = &qed_ll2_get_stats, + .iwarp_create_listen = &qed_iwarp_create_listen, + .iwarp_destroy_listen = &qed_iwarp_destroy_listen, }; const struct qed_rdma_ops *qed_get_rdma_ops(void) -- cgit v1.2.3 From 456a584947d5b92d5e5a62cc68125ab5f150aa8c Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:27 +0300 Subject: qed: iWARP CM add passive side connect This patch implements the passive side connect. It addresses pre-allocating resources, creating a connection element upon valid SYN packet received. Calling upper layer and implementation of the accept/reject calls. Error handling is not part of this patch. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 2 + drivers/net/ethernet/qlogic/qed/qed_dev.c | 11 + drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 939 +++++++++++++++++++++++++++- drivers/net/ethernet/qlogic/qed/qed_iwarp.h | 62 ++ drivers/net/ethernet/qlogic/qed/qed_l2.c | 13 - drivers/net/ethernet/qlogic/qed/qed_rdma.h | 2 + drivers/net/ethernet/qlogic/qed/qed_sp.h | 2 + 7 files changed, 1012 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index fd8cd5e17121..91003bc6f00b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -789,6 +789,8 @@ void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev, void qed_clean_wfq_db(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); int qed_device_num_engines(struct qed_dev *cdev); int qed_device_get_port_id(struct qed_dev *cdev); +void qed_set_fw_mac_addr(__le16 *fw_msb, + __le16 *fw_mid, __le16 *fw_lsb, u8 *mac); #define QED_LEADING_HWFN(dev) (&dev->hwfns[0]) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 6c8505dc5c31..4060a6ad9be3 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -4127,3 +4127,14 @@ int qed_device_get_port_id(struct qed_dev *cdev) { return (QED_LEADING_HWFN(cdev)->abs_pf_id) % qed_device_num_ports(cdev); } + +void qed_set_fw_mac_addr(__le16 *fw_msb, + __le16 *fw_mid, __le16 *fw_lsb, u8 *mac) +{ + ((u8 *)fw_msb)[0] = mac[1]; + ((u8 *)fw_msb)[1] = mac[0]; + ((u8 *)fw_mid)[0] = mac[3]; + ((u8 *)fw_mid)[1] = mac[2]; + ((u8 *)fw_lsb)[0] = mac[5]; + ((u8 *)fw_lsb)[1] = mac[4]; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index 2bab57c6bae8..a6dadae1f998 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -44,9 +44,30 @@ #define QED_IWARP_ORD_DEFAULT 32 #define QED_IWARP_IRD_DEFAULT 32 +#define QED_IWARP_MAX_FW_MSS 4120 + +#define QED_EP_SIG 0xecabcdef + +struct mpa_v2_hdr { + __be16 ird; + __be16 ord; +}; + +#define MPA_V2_PEER2PEER_MODEL 0x8000 +#define MPA_V2_SEND_RTR 0x4000 /* on ird */ +#define MPA_V2_READ_RTR 0x4000 /* on ord */ +#define MPA_V2_WRITE_RTR 0x8000 +#define MPA_V2_IRD_ORD_MASK 0x3FFF + +#define MPA_REV2(_mpa_rev) ((_mpa_rev) == MPA_NEGOTIATION_TYPE_ENHANCED) + +#define QED_IWARP_INVALID_TCP_CID 0xffffffff #define QED_IWARP_RCV_WND_SIZE_DEF (256 * 1024) #define QED_IWARP_RCV_WND_SIZE_MIN (64 * 1024) +#define TIMESTAMP_HEADER_SIZE (12) + #define QED_IWARP_TS_EN BIT(0) +#define QED_IWARP_DA_EN BIT(1) #define QED_IWARP_PARAM_CRC_NEEDED (1) #define QED_IWARP_PARAM_P2P (1) @@ -63,7 +84,8 @@ void qed_iwarp_init_devinfo(struct qed_hwfn *p_hwfn) dev->max_inline = IWARP_REQ_MAX_INLINE_DATA_SIZE; dev->max_qp = min_t(u32, IWARP_MAX_QPS, - p_hwfn->p_rdma_info->num_qps); + p_hwfn->p_rdma_info->num_qps) - + QED_IWARP_PREALLOC_CNT; dev->max_cq = dev->max_qp; @@ -78,12 +100,22 @@ void qed_iwarp_init_hw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) p_hwfn->b_rdma_enabled_in_prs = true; } +/* We have two cid maps, one for tcp which should be used only from passive + * syn processing and replacing a pre-allocated ep in the list. The second + * for active tcp and for QPs. + */ static void qed_iwarp_cid_cleaned(struct qed_hwfn *p_hwfn, u32 cid) { cid -= qed_cxt_get_proto_cid_start(p_hwfn, p_hwfn->p_rdma_info->proto); spin_lock_bh(&p_hwfn->p_rdma_info->lock); - qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->cid_map, cid); + + if (cid < QED_IWARP_PREALLOC_CNT) + qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->tcp_cid_map, + cid); + else + qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->cid_map, cid); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); } @@ -107,6 +139,45 @@ static int qed_iwarp_alloc_cid(struct qed_hwfn *p_hwfn, u32 *cid) return rc; } +static void qed_iwarp_set_tcp_cid(struct qed_hwfn *p_hwfn, u32 cid) +{ + cid -= qed_cxt_get_proto_cid_start(p_hwfn, p_hwfn->p_rdma_info->proto); + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + qed_bmap_set_id(p_hwfn, &p_hwfn->p_rdma_info->tcp_cid_map, cid); + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); +} + +/* This function allocates a cid for passive tcp (called from syn receive) + * the reason it's separate from the regular cid allocation is because it + * is assured that these cids already have ilt allocated. They are preallocated + * to ensure that we won't need to allocate memory during syn processing + */ +static int qed_iwarp_alloc_tcp_cid(struct qed_hwfn *p_hwfn, u32 *cid) +{ + int rc; + + spin_lock_bh(&p_hwfn->p_rdma_info->lock); + + rc = qed_rdma_bmap_alloc_id(p_hwfn, + &p_hwfn->p_rdma_info->tcp_cid_map, cid); + + spin_unlock_bh(&p_hwfn->p_rdma_info->lock); + + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "can't allocate iwarp tcp cid max-count=%d\n", + p_hwfn->p_rdma_info->tcp_cid_map.max_count); + + *cid = QED_IWARP_INVALID_TCP_CID; + return rc; + } + + *cid += qed_cxt_get_proto_cid_start(p_hwfn, + p_hwfn->p_rdma_info->proto); + return 0; +} + int qed_iwarp_create_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp, struct qed_rdma_create_qp_out_params *out_params) @@ -403,6 +474,26 @@ int qed_iwarp_fw_destroy(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) return rc; } +static void qed_iwarp_destroy_ep(struct qed_hwfn *p_hwfn, + struct qed_iwarp_ep *ep, + bool remove_from_active_list) +{ + dma_free_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(*ep->ep_buffer_virt), + ep->ep_buffer_virt, ep->ep_buffer_phys); + + if (remove_from_active_list) { + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + list_del(&ep->list_entry); + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + } + + if (ep->qp) + ep->qp->ep = NULL; + + kfree(ep); +} + int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) { int rc = 0; @@ -424,6 +515,507 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) return rc; } +static int +qed_iwarp_create_ep(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep **ep_out) +{ + struct qed_iwarp_ep *ep; + int rc; + + ep = kzalloc(sizeof(*ep), GFP_KERNEL); + if (!ep) + return -ENOMEM; + + ep->state = QED_IWARP_EP_INIT; + + ep->ep_buffer_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + sizeof(*ep->ep_buffer_virt), + &ep->ep_buffer_phys, + GFP_KERNEL); + if (!ep->ep_buffer_virt) { + rc = -ENOMEM; + goto err; + } + + ep->sig = QED_EP_SIG; + + *ep_out = ep; + + return 0; + +err: + kfree(ep); + return rc; +} + +static void +qed_iwarp_print_tcp_ramrod(struct qed_hwfn *p_hwfn, + struct iwarp_tcp_offload_ramrod_data *p_tcp_ramrod) +{ + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "local_mac=%x %x %x, remote_mac=%x %x %x\n", + p_tcp_ramrod->tcp.local_mac_addr_lo, + p_tcp_ramrod->tcp.local_mac_addr_mid, + p_tcp_ramrod->tcp.local_mac_addr_hi, + p_tcp_ramrod->tcp.remote_mac_addr_lo, + p_tcp_ramrod->tcp.remote_mac_addr_mid, + p_tcp_ramrod->tcp.remote_mac_addr_hi); + + if (p_tcp_ramrod->tcp.ip_version == TCP_IPV4) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "local_ip=%pI4h:%x, remote_ip=%pI4h%x, vlan=%x\n", + p_tcp_ramrod->tcp.local_ip, + p_tcp_ramrod->tcp.local_port, + p_tcp_ramrod->tcp.remote_ip, + p_tcp_ramrod->tcp.remote_port, + p_tcp_ramrod->tcp.vlan_id); + } else { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "local_ip=%pI6h:%x, remote_ip=%pI6h:%x, vlan=%x\n", + p_tcp_ramrod->tcp.local_ip, + p_tcp_ramrod->tcp.local_port, + p_tcp_ramrod->tcp.remote_ip, + p_tcp_ramrod->tcp.remote_port, + p_tcp_ramrod->tcp.vlan_id); + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "flow_label=%x, ttl=%x, tos_or_tc=%x, mss=%x, rcv_wnd_scale=%x, connect_mode=%x, flags=%x\n", + p_tcp_ramrod->tcp.flow_label, + p_tcp_ramrod->tcp.ttl, + p_tcp_ramrod->tcp.tos_or_tc, + p_tcp_ramrod->tcp.mss, + p_tcp_ramrod->tcp.rcv_wnd_scale, + p_tcp_ramrod->tcp.connect_mode, + p_tcp_ramrod->tcp.flags); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "syn_ip_payload_length=%x, lo=%x, hi=%x\n", + p_tcp_ramrod->tcp.syn_ip_payload_length, + p_tcp_ramrod->tcp.syn_phy_addr_lo, + p_tcp_ramrod->tcp.syn_phy_addr_hi); +} + +static int +qed_iwarp_tcp_offload(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) +{ + struct qed_iwarp_info *iwarp_info = &p_hwfn->p_rdma_info->iwarp; + struct iwarp_tcp_offload_ramrod_data *p_tcp_ramrod; + struct tcp_offload_params_opt2 *tcp; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + dma_addr_t async_output_phys; + dma_addr_t in_pdata_phys; + u16 physical_q; + u8 tcp_flags; + int rc; + int i; + + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = ep->tcp_cid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_CB; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + IWARP_RAMROD_CMD_ID_TCP_OFFLOAD, + PROTOCOLID_IWARP, &init_data); + if (rc) + return rc; + + p_tcp_ramrod = &p_ent->ramrod.iwarp_tcp_offload; + + in_pdata_phys = ep->ep_buffer_phys + + offsetof(struct qed_iwarp_ep_memory, in_pdata); + DMA_REGPAIR_LE(p_tcp_ramrod->iwarp.incoming_ulp_buffer.addr, + in_pdata_phys); + + p_tcp_ramrod->iwarp.incoming_ulp_buffer.len = + cpu_to_le16(sizeof(ep->ep_buffer_virt->in_pdata)); + + async_output_phys = ep->ep_buffer_phys + + offsetof(struct qed_iwarp_ep_memory, async_output); + DMA_REGPAIR_LE(p_tcp_ramrod->iwarp.async_eqe_output_buf, + async_output_phys); + + p_tcp_ramrod->iwarp.handle_for_async.hi = cpu_to_le32(PTR_HI(ep)); + p_tcp_ramrod->iwarp.handle_for_async.lo = cpu_to_le32(PTR_LO(ep)); + + physical_q = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD); + p_tcp_ramrod->iwarp.physical_q0 = cpu_to_le16(physical_q); + physical_q = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_ACK); + p_tcp_ramrod->iwarp.physical_q1 = cpu_to_le16(physical_q); + p_tcp_ramrod->iwarp.mpa_mode = iwarp_info->mpa_rev; + + tcp = &p_tcp_ramrod->tcp; + qed_set_fw_mac_addr(&tcp->remote_mac_addr_hi, + &tcp->remote_mac_addr_mid, + &tcp->remote_mac_addr_lo, ep->remote_mac_addr); + qed_set_fw_mac_addr(&tcp->local_mac_addr_hi, &tcp->local_mac_addr_mid, + &tcp->local_mac_addr_lo, ep->local_mac_addr); + + tcp->vlan_id = cpu_to_le16(ep->cm_info.vlan); + + tcp_flags = p_hwfn->p_rdma_info->iwarp.tcp_flags; + tcp->flags = 0; + SET_FIELD(tcp->flags, TCP_OFFLOAD_PARAMS_OPT2_TS_EN, + !!(tcp_flags & QED_IWARP_TS_EN)); + + SET_FIELD(tcp->flags, TCP_OFFLOAD_PARAMS_OPT2_DA_EN, + !!(tcp_flags & QED_IWARP_DA_EN)); + + tcp->ip_version = ep->cm_info.ip_version; + + for (i = 0; i < 4; i++) { + tcp->remote_ip[i] = cpu_to_le32(ep->cm_info.remote_ip[i]); + tcp->local_ip[i] = cpu_to_le32(ep->cm_info.local_ip[i]); + } + + tcp->remote_port = cpu_to_le16(ep->cm_info.remote_port); + tcp->local_port = cpu_to_le16(ep->cm_info.local_port); + tcp->mss = cpu_to_le16(ep->mss); + tcp->flow_label = 0; + tcp->ttl = 0x40; + tcp->tos_or_tc = 0; + + tcp->rcv_wnd_scale = (u8)p_hwfn->p_rdma_info->iwarp.rcv_wnd_scale; + tcp->connect_mode = ep->connect_mode; + + if (ep->connect_mode == TCP_CONNECT_PASSIVE) { + tcp->syn_ip_payload_length = + cpu_to_le16(ep->syn_ip_payload_length); + tcp->syn_phy_addr_hi = DMA_HI_LE(ep->syn_phy_addr); + tcp->syn_phy_addr_lo = DMA_LO_LE(ep->syn_phy_addr); + } + + qed_iwarp_print_tcp_ramrod(p_hwfn, p_tcp_ramrod); + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "EP(0x%x) Offload completed rc=%d\n", ep->tcp_cid, rc); + + return rc; +} + +static void +qed_iwarp_mpa_received(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) +{ + struct qed_iwarp_info *iwarp_info = &p_hwfn->p_rdma_info->iwarp; + struct qed_iwarp_cm_event_params params; + struct mpa_v2_hdr *mpa_v2; + union async_output *async_data; + u16 mpa_ord, mpa_ird; + u8 mpa_hdr_size = 0; + u8 mpa_rev; + + async_data = &ep->ep_buffer_virt->async_output; + + mpa_rev = async_data->mpa_request.mpa_handshake_mode; + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "private_data_len=%x handshake_mode=%x private_data=(%x)\n", + async_data->mpa_request.ulp_data_len, + mpa_rev, *((u32 *)((u8 *)ep->ep_buffer_virt->in_pdata))); + + if (mpa_rev == MPA_NEGOTIATION_TYPE_ENHANCED) { + /* Read ord/ird values from private data buffer */ + mpa_v2 = (struct mpa_v2_hdr *)ep->ep_buffer_virt->in_pdata; + mpa_hdr_size = sizeof(*mpa_v2); + + mpa_ord = ntohs(mpa_v2->ord); + mpa_ird = ntohs(mpa_v2->ird); + + /* Temprary store in cm_info incoming ord/ird requested, later + * replace with negotiated value during accept + */ + ep->cm_info.ord = (u8)min_t(u16, + (mpa_ord & MPA_V2_IRD_ORD_MASK), + QED_IWARP_ORD_DEFAULT); + + ep->cm_info.ird = (u8)min_t(u16, + (mpa_ird & MPA_V2_IRD_ORD_MASK), + QED_IWARP_IRD_DEFAULT); + + /* Peer2Peer negotiation */ + ep->rtr_type = MPA_RTR_TYPE_NONE; + if (mpa_ird & MPA_V2_PEER2PEER_MODEL) { + if (mpa_ord & MPA_V2_WRITE_RTR) + ep->rtr_type |= MPA_RTR_TYPE_ZERO_WRITE; + + if (mpa_ord & MPA_V2_READ_RTR) + ep->rtr_type |= MPA_RTR_TYPE_ZERO_READ; + + if (mpa_ird & MPA_V2_SEND_RTR) + ep->rtr_type |= MPA_RTR_TYPE_ZERO_SEND; + + ep->rtr_type &= iwarp_info->rtr_type; + + /* if we're left with no match send our capabilities */ + if (ep->rtr_type == MPA_RTR_TYPE_NONE) + ep->rtr_type = iwarp_info->rtr_type; + } + + ep->mpa_rev = MPA_NEGOTIATION_TYPE_ENHANCED; + } else { + ep->cm_info.ord = QED_IWARP_ORD_DEFAULT; + ep->cm_info.ird = QED_IWARP_IRD_DEFAULT; + ep->mpa_rev = MPA_NEGOTIATION_TYPE_BASIC; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "MPA_NEGOTIATE (v%d): ORD: 0x%x IRD: 0x%x rtr:0x%x ulp_data_len = %x mpa_hdr_size = %x\n", + mpa_rev, ep->cm_info.ord, ep->cm_info.ird, ep->rtr_type, + async_data->mpa_request.ulp_data_len, mpa_hdr_size); + + /* Strip mpa v2 hdr from private data before sending to upper layer */ + ep->cm_info.private_data = ep->ep_buffer_virt->in_pdata + mpa_hdr_size; + + ep->cm_info.private_data_len = async_data->mpa_request.ulp_data_len - + mpa_hdr_size; + + params.event = QED_IWARP_EVENT_MPA_REQUEST; + params.cm_info = &ep->cm_info; + params.ep_context = ep; + params.status = 0; + + ep->state = QED_IWARP_EP_MPA_REQ_RCVD; + ep->event_cb(ep->cb_context, ¶ms); +} + +static int +qed_iwarp_mpa_offload(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) +{ + struct iwarp_mpa_offload_ramrod_data *p_mpa_ramrod; + struct qed_sp_init_data init_data; + dma_addr_t async_output_phys; + struct qed_spq_entry *p_ent; + dma_addr_t out_pdata_phys; + dma_addr_t in_pdata_phys; + struct qed_rdma_qp *qp; + bool reject; + int rc; + + if (!ep) + return -EINVAL; + + qp = ep->qp; + reject = !qp; + + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = reject ? ep->tcp_cid : qp->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + IWARP_RAMROD_CMD_ID_MPA_OFFLOAD, + PROTOCOLID_IWARP, &init_data); + if (rc) + return rc; + + p_mpa_ramrod = &p_ent->ramrod.iwarp_mpa_offload; + out_pdata_phys = ep->ep_buffer_phys + + offsetof(struct qed_iwarp_ep_memory, out_pdata); + DMA_REGPAIR_LE(p_mpa_ramrod->common.outgoing_ulp_buffer.addr, + out_pdata_phys); + p_mpa_ramrod->common.outgoing_ulp_buffer.len = + ep->cm_info.private_data_len; + p_mpa_ramrod->common.crc_needed = p_hwfn->p_rdma_info->iwarp.crc_needed; + + p_mpa_ramrod->common.out_rq.ord = ep->cm_info.ord; + p_mpa_ramrod->common.out_rq.ird = ep->cm_info.ird; + + p_mpa_ramrod->tcp_cid = p_hwfn->hw_info.opaque_fid << 16 | ep->tcp_cid; + + in_pdata_phys = ep->ep_buffer_phys + + offsetof(struct qed_iwarp_ep_memory, in_pdata); + p_mpa_ramrod->tcp_connect_side = ep->connect_mode; + DMA_REGPAIR_LE(p_mpa_ramrod->incoming_ulp_buffer.addr, + in_pdata_phys); + p_mpa_ramrod->incoming_ulp_buffer.len = + cpu_to_le16(sizeof(ep->ep_buffer_virt->in_pdata)); + async_output_phys = ep->ep_buffer_phys + + offsetof(struct qed_iwarp_ep_memory, async_output); + DMA_REGPAIR_LE(p_mpa_ramrod->async_eqe_output_buf, + async_output_phys); + p_mpa_ramrod->handle_for_async.hi = cpu_to_le32(PTR_HI(ep)); + p_mpa_ramrod->handle_for_async.lo = cpu_to_le32(PTR_LO(ep)); + + if (!reject) { + DMA_REGPAIR_LE(p_mpa_ramrod->shared_queue_addr, + qp->shared_queue_phys_addr); + p_mpa_ramrod->stats_counter_id = + RESC_START(p_hwfn, QED_RDMA_STATS_QUEUE) + qp->stats_queue; + } else { + p_mpa_ramrod->common.reject = 1; + } + + p_mpa_ramrod->mode = ep->mpa_rev; + SET_FIELD(p_mpa_ramrod->rtr_pref, + IWARP_MPA_OFFLOAD_RAMROD_DATA_RTR_SUPPORTED, ep->rtr_type); + + ep->state = QED_IWARP_EP_MPA_OFFLOADED; + rc = qed_spq_post(p_hwfn, p_ent, NULL); + if (!reject) + ep->cid = qp->icid; /* Now they're migrated. */ + + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "QP(0x%x) EP(0x%x) MPA Offload rc = %d IRD=0x%x ORD=0x%x rtr_type=%d mpa_rev=%d reject=%d\n", + reject ? 0xffff : qp->icid, + ep->tcp_cid, + rc, + ep->cm_info.ird, + ep->cm_info.ord, ep->rtr_type, ep->mpa_rev, reject); + return rc; +} + +static void +qed_iwarp_return_ep(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) +{ + ep->state = QED_IWARP_EP_INIT; + if (ep->qp) + ep->qp->ep = NULL; + ep->qp = NULL; + memset(&ep->cm_info, 0, sizeof(ep->cm_info)); + + if (ep->tcp_cid == QED_IWARP_INVALID_TCP_CID) { + /* We don't care about the return code, it's ok if tcp_cid + * remains invalid...in this case we'll defer allocation + */ + qed_iwarp_alloc_tcp_cid(p_hwfn, &ep->tcp_cid); + } + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + list_del(&ep->list_entry); + list_add_tail(&ep->list_entry, + &p_hwfn->p_rdma_info->iwarp.ep_free_list); + + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); +} + +#define QED_IWARP_CONNECT_MODE_STRING(ep) \ + ((ep)->connect_mode == TCP_CONNECT_PASSIVE) ? "Passive" : "Active" + +/* Called as a result of the event: + * IWARP_EVENT_TYPE_ASYNC_MPA_HANDSHAKE_COMPLETE + */ +static void +qed_iwarp_mpa_complete(struct qed_hwfn *p_hwfn, + struct qed_iwarp_ep *ep, u8 fw_return_code) +{ + struct qed_iwarp_cm_event_params params; + + params.event = QED_IWARP_EVENT_PASSIVE_COMPLETE; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "MPA_NEGOTIATE (v%d): ORD: 0x%x IRD: 0x%x\n", + ep->mpa_rev, ep->cm_info.ord, ep->cm_info.ird); + + params.cm_info = &ep->cm_info; + + params.ep_context = ep; + + ep->state = QED_IWARP_EP_CLOSED; + + switch (fw_return_code) { + case RDMA_RETURN_OK: + ep->qp->max_rd_atomic_req = ep->cm_info.ord; + ep->qp->max_rd_atomic_resp = ep->cm_info.ird; + qed_iwarp_modify_qp(p_hwfn, ep->qp, QED_IWARP_QP_STATE_RTS, 1); + ep->state = QED_IWARP_EP_ESTABLISHED; + params.status = 0; + break; + default: + params.status = -ECONNRESET; + break; + } + + ep->event_cb(ep->cb_context, ¶ms); +} + +static void +qed_iwarp_mpa_v2_set_private(struct qed_hwfn *p_hwfn, + struct qed_iwarp_ep *ep, u8 *mpa_data_size) +{ + struct mpa_v2_hdr *mpa_v2_params; + u16 mpa_ird, mpa_ord; + + *mpa_data_size = 0; + if (MPA_REV2(ep->mpa_rev)) { + mpa_v2_params = + (struct mpa_v2_hdr *)ep->ep_buffer_virt->out_pdata; + *mpa_data_size = sizeof(*mpa_v2_params); + + mpa_ird = (u16)ep->cm_info.ird; + mpa_ord = (u16)ep->cm_info.ord; + + if (ep->rtr_type != MPA_RTR_TYPE_NONE) { + mpa_ird |= MPA_V2_PEER2PEER_MODEL; + + if (ep->rtr_type & MPA_RTR_TYPE_ZERO_SEND) + mpa_ird |= MPA_V2_SEND_RTR; + + if (ep->rtr_type & MPA_RTR_TYPE_ZERO_WRITE) + mpa_ord |= MPA_V2_WRITE_RTR; + + if (ep->rtr_type & MPA_RTR_TYPE_ZERO_READ) + mpa_ord |= MPA_V2_READ_RTR; + } + + mpa_v2_params->ird = htons(mpa_ird); + mpa_v2_params->ord = htons(mpa_ord); + + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "MPA_NEGOTIATE Header: [%x ord:%x ird] %x ord:%x ird:%x peer2peer:%x rtr_send:%x rtr_write:%x rtr_read:%x\n", + mpa_v2_params->ird, + mpa_v2_params->ord, + *((u32 *)mpa_v2_params), + mpa_ord & MPA_V2_IRD_ORD_MASK, + mpa_ird & MPA_V2_IRD_ORD_MASK, + !!(mpa_ird & MPA_V2_PEER2PEER_MODEL), + !!(mpa_ird & MPA_V2_SEND_RTR), + !!(mpa_ord & MPA_V2_WRITE_RTR), + !!(mpa_ord & MPA_V2_READ_RTR)); + } +} + +static struct qed_iwarp_ep *qed_iwarp_get_free_ep(struct qed_hwfn *p_hwfn) +{ + struct qed_iwarp_ep *ep = NULL; + int rc; + + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + if (list_empty(&p_hwfn->p_rdma_info->iwarp.ep_free_list)) { + DP_ERR(p_hwfn, "Ep list is empty\n"); + goto out; + } + + ep = list_first_entry(&p_hwfn->p_rdma_info->iwarp.ep_free_list, + struct qed_iwarp_ep, list_entry); + + /* in some cases we could have failed allocating a tcp cid when added + * from accept / failure... retry now..this is not the common case. + */ + if (ep->tcp_cid == QED_IWARP_INVALID_TCP_CID) { + rc = qed_iwarp_alloc_tcp_cid(p_hwfn, &ep->tcp_cid); + + /* if we fail we could look for another entry with a valid + * tcp_cid, but since we don't expect to reach this anyway + * it's not worth the handling + */ + if (rc) { + ep->tcp_cid = QED_IWARP_INVALID_TCP_CID; + ep = NULL; + goto out; + } + } + + list_del(&ep->list_entry); + +out: + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + return ep; +} + #define QED_IWARP_MAX_CID_CLEAN_TIME 100 #define QED_IWARP_MAX_NO_PROGRESS_CNT 5 @@ -465,20 +1057,213 @@ qed_iwarp_wait_cid_map_cleared(struct qed_hwfn *p_hwfn, struct qed_bmap *bmap) static int qed_iwarp_wait_for_all_cids(struct qed_hwfn *p_hwfn) { + int rc; + int i; + + rc = qed_iwarp_wait_cid_map_cleared(p_hwfn, + &p_hwfn->p_rdma_info->tcp_cid_map); + if (rc) + return rc; + + /* Now free the tcp cids from the main cid map */ + for (i = 0; i < QED_IWARP_PREALLOC_CNT; i++) + qed_bmap_release_id(p_hwfn, &p_hwfn->p_rdma_info->cid_map, i); + /* Now wait for all cids to be completed */ return qed_iwarp_wait_cid_map_cleared(p_hwfn, &p_hwfn->p_rdma_info->cid_map); } +static void qed_iwarp_free_prealloc_ep(struct qed_hwfn *p_hwfn) +{ + struct qed_iwarp_ep *ep; + + while (!list_empty(&p_hwfn->p_rdma_info->iwarp.ep_free_list)) { + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + ep = list_first_entry(&p_hwfn->p_rdma_info->iwarp.ep_free_list, + struct qed_iwarp_ep, list_entry); + + if (!ep) { + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + break; + } + list_del(&ep->list_entry); + + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + if (ep->tcp_cid != QED_IWARP_INVALID_TCP_CID) + qed_iwarp_cid_cleaned(p_hwfn, ep->tcp_cid); + + qed_iwarp_destroy_ep(p_hwfn, ep, false); + } +} + +static int qed_iwarp_prealloc_ep(struct qed_hwfn *p_hwfn, bool init) +{ + struct qed_iwarp_ep *ep; + int rc = 0; + int count; + u32 cid; + int i; + + count = init ? QED_IWARP_PREALLOC_CNT : 1; + for (i = 0; i < count; i++) { + rc = qed_iwarp_create_ep(p_hwfn, &ep); + if (rc) + return rc; + + /* During initialization we allocate from the main pool, + * afterwards we allocate only from the tcp_cid. + */ + if (init) { + rc = qed_iwarp_alloc_cid(p_hwfn, &cid); + if (rc) + goto err; + qed_iwarp_set_tcp_cid(p_hwfn, cid); + } else { + /* We don't care about the return code, it's ok if + * tcp_cid remains invalid...in this case we'll + * defer allocation + */ + qed_iwarp_alloc_tcp_cid(p_hwfn, &cid); + } + + ep->tcp_cid = cid; + + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + list_add_tail(&ep->list_entry, + &p_hwfn->p_rdma_info->iwarp.ep_free_list); + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + } + + return rc; + +err: + qed_iwarp_destroy_ep(p_hwfn, ep, false); + + return rc; +} + int qed_iwarp_alloc(struct qed_hwfn *p_hwfn) { + int rc; + + /* Allocate bitmap for tcp cid. These are used by passive side + * to ensure it can allocate a tcp cid during dpc that was + * pre-acquired and doesn't require dynamic allocation of ilt + */ + rc = qed_rdma_bmap_alloc(p_hwfn, &p_hwfn->p_rdma_info->tcp_cid_map, + QED_IWARP_PREALLOC_CNT, "TCP_CID"); + if (rc) { + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Failed to allocate tcp cid, rc = %d\n", rc); + return rc; + } + + INIT_LIST_HEAD(&p_hwfn->p_rdma_info->iwarp.ep_free_list); spin_lock_init(&p_hwfn->p_rdma_info->iwarp.iw_lock); - return 0; + return qed_iwarp_prealloc_ep(p_hwfn, true); } void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn) { + qed_rdma_bmap_free(p_hwfn, &p_hwfn->p_rdma_info->tcp_cid_map, 1); +} + +int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams) +{ + struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct qed_iwarp_ep *ep; + u8 mpa_data_size = 0; + int rc; + + ep = (struct qed_iwarp_ep *)iparams->ep_context; + if (!ep) { + DP_ERR(p_hwfn, "Ep Context receive in accept is NULL\n"); + return -EINVAL; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QP(0x%x) EP(0x%x)\n", + iparams->qp->icid, ep->tcp_cid); + + if ((iparams->ord > QED_IWARP_ORD_DEFAULT) || + (iparams->ird > QED_IWARP_IRD_DEFAULT)) { + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "QP(0x%x) EP(0x%x) ERROR: Invalid ord(0x%x)/ird(0x%x)\n", + iparams->qp->icid, + ep->tcp_cid, iparams->ord, iparams->ord); + return -EINVAL; + } + + qed_iwarp_prealloc_ep(p_hwfn, false); + + ep->cb_context = iparams->cb_context; + ep->qp = iparams->qp; + ep->qp->ep = ep; + + if (ep->mpa_rev == MPA_NEGOTIATION_TYPE_ENHANCED) { + /* Negotiate ord/ird: if upperlayer requested ord larger than + * ird advertised by remote, we need to decrease our ord + */ + if (iparams->ord > ep->cm_info.ird) + iparams->ord = ep->cm_info.ird; + + if ((ep->rtr_type & MPA_RTR_TYPE_ZERO_READ) && + (iparams->ird == 0)) + iparams->ird = 1; + } + + /* Update cm_info ord/ird to be negotiated values */ + ep->cm_info.ord = iparams->ord; + ep->cm_info.ird = iparams->ird; + + qed_iwarp_mpa_v2_set_private(p_hwfn, ep, &mpa_data_size); + + ep->cm_info.private_data = ep->ep_buffer_virt->out_pdata; + ep->cm_info.private_data_len = iparams->private_data_len + + mpa_data_size; + + memcpy((u8 *)ep->ep_buffer_virt->out_pdata + mpa_data_size, + iparams->private_data, iparams->private_data_len); + + rc = qed_iwarp_mpa_offload(p_hwfn, ep); + if (rc) + qed_iwarp_modify_qp(p_hwfn, + iparams->qp, QED_IWARP_QP_STATE_ERROR, 1); + + return rc; +} + +int qed_iwarp_reject(void *rdma_cxt, struct qed_iwarp_reject_in *iparams) +{ + struct qed_hwfn *p_hwfn = rdma_cxt; + struct qed_iwarp_ep *ep; + u8 mpa_data_size = 0; + + ep = iparams->ep_context; + if (!ep) { + DP_ERR(p_hwfn, "Ep Context receive in reject is NULL\n"); + return -EINVAL; + } + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "EP(0x%x)\n", ep->tcp_cid); + + ep->cb_context = iparams->cb_context; + ep->qp = NULL; + + qed_iwarp_mpa_v2_set_private(p_hwfn, ep, &mpa_data_size); + + ep->cm_info.private_data = ep->ep_buffer_virt->out_pdata; + ep->cm_info.private_data_len = iparams->private_data_len + + mpa_data_size; + + memcpy((u8 *)ep->ep_buffer_virt->out_pdata + mpa_data_size, + iparams->private_data, iparams->private_data_len); + + return qed_iwarp_mpa_offload(p_hwfn, ep); } static void @@ -526,6 +1311,38 @@ qed_iwarp_ll2_post_rx(struct qed_hwfn *p_hwfn, return rc; } +static bool +qed_iwarp_ep_exists(struct qed_hwfn *p_hwfn, struct qed_iwarp_cm_info *cm_info) +{ + struct qed_iwarp_ep *ep = NULL; + bool found = false; + + list_for_each_entry(ep, + &p_hwfn->p_rdma_info->iwarp.ep_list, + list_entry) { + if ((ep->cm_info.local_port == cm_info->local_port) && + (ep->cm_info.remote_port == cm_info->remote_port) && + (ep->cm_info.vlan == cm_info->vlan) && + !memcmp(&ep->cm_info.local_ip, cm_info->local_ip, + sizeof(cm_info->local_ip)) && + !memcmp(&ep->cm_info.remote_ip, cm_info->remote_ip, + sizeof(cm_info->remote_ip))) { + found = true; + break; + } + } + + if (found) { + DP_NOTICE(p_hwfn, + "SYN received on active connection - dropping\n"); + qed_iwarp_print_cm_info(p_hwfn, cm_info); + + return true; + } + + return false; +} + static struct qed_iwarp_listener * qed_iwarp_get_listener(struct qed_hwfn *p_hwfn, struct qed_iwarp_cm_info *cm_info) @@ -596,9 +1413,8 @@ qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn, eth_hlen = ETH_HLEN + (vlan_valid ? sizeof(u32) : 0); - memcpy(remote_mac_addr, ethh->h_source, ETH_ALEN); - - memcpy(local_mac_addr, ethh->h_dest, ETH_ALEN); + ether_addr_copy(remote_mac_addr, ethh->h_source); + ether_addr_copy(local_mac_addr, ethh->h_dest); DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "eth_type =%d source mac: %pM\n", eth_type, ethh->h_source); @@ -661,9 +1477,12 @@ qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data) struct qed_hwfn *p_hwfn = cxt; u8 remote_mac_addr[ETH_ALEN]; u8 local_mac_addr[ETH_ALEN]; + struct qed_iwarp_ep *ep; int tcp_start_offset; + u8 ts_hdr_size = 0; u8 ll2_syn_handle; int payload_len; + u32 hdr_size; int rc; memset(&cm_info, 0, sizeof(cm_info)); @@ -719,6 +1538,49 @@ qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data) } DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Received syn on listening port\n"); + /* There may be an open ep on this connection if this is a syn + * retrasnmit... need to make sure there isn't... + */ + if (qed_iwarp_ep_exists(p_hwfn, &cm_info)) + goto err; + + ep = qed_iwarp_get_free_ep(p_hwfn); + if (!ep) + goto err; + + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + list_add_tail(&ep->list_entry, &p_hwfn->p_rdma_info->iwarp.ep_list); + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + ether_addr_copy(ep->remote_mac_addr, remote_mac_addr); + ether_addr_copy(ep->local_mac_addr, local_mac_addr); + + memcpy(&ep->cm_info, &cm_info, sizeof(ep->cm_info)); + + if (p_hwfn->p_rdma_info->iwarp.tcp_flags & QED_IWARP_TS_EN) + ts_hdr_size = TIMESTAMP_HEADER_SIZE; + + hdr_size = ((cm_info.ip_version == QED_TCP_IPV4) ? 40 : 60) + + ts_hdr_size; + ep->mss = p_hwfn->p_rdma_info->iwarp.max_mtu - hdr_size; + ep->mss = min_t(u16, QED_IWARP_MAX_FW_MSS, ep->mss); + + ep->event_cb = listener->event_cb; + ep->cb_context = listener->cb_context; + ep->connect_mode = TCP_CONNECT_PASSIVE; + + ep->syn = buf; + ep->syn_ip_payload_length = (u16)payload_len; + ep->syn_phy_addr = buf->data_phys_addr + data->u.placement_offset + + tcp_start_offset; + + rc = qed_iwarp_tcp_offload(p_hwfn, ep); + if (rc) { + qed_iwarp_return_ep(p_hwfn, ep); + goto err; + } + + return; err: qed_iwarp_ll2_post_rx(p_hwfn, buf, ll2_syn_handle); } @@ -905,7 +1767,12 @@ int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, iwarp_info->peer2peer = QED_IWARP_PARAM_P2P; + iwarp_info->rtr_type = MPA_RTR_TYPE_ZERO_SEND | + MPA_RTR_TYPE_ZERO_WRITE | + MPA_RTR_TYPE_ZERO_READ; + spin_lock_init(&p_hwfn->p_rdma_info->iwarp.qp_lock); + INIT_LIST_HEAD(&p_hwfn->p_rdma_info->iwarp.ep_list); INIT_LIST_HEAD(&p_hwfn->p_rdma_info->iwarp.listen_list); qed_spq_register_async_cb(p_hwfn, PROTOCOLID_IWARP, @@ -918,6 +1785,7 @@ int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { int rc; + qed_iwarp_free_prealloc_ep(p_hwfn); rc = qed_iwarp_wait_for_all_cids(p_hwfn); if (rc) return rc; @@ -927,11 +1795,70 @@ int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) return qed_iwarp_ll2_stop(p_hwfn, p_ptt); } +void +qed_iwarp_connect_complete(struct qed_hwfn *p_hwfn, + struct qed_iwarp_ep *ep, u8 fw_return_code) +{ + /* Done with the SYN packet, post back to ll2 rx */ + qed_iwarp_ll2_post_rx(p_hwfn, ep->syn, + p_hwfn->p_rdma_info->iwarp.ll2_syn_handle); + ep->syn = NULL; + + /* If connect failed - upper layer doesn't know about it */ + qed_iwarp_mpa_received(p_hwfn, ep); +} + +static inline bool +qed_iwarp_check_ep_ok(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) +{ + if (!ep || (ep->sig != QED_EP_SIG)) { + DP_ERR(p_hwfn, "ERROR ON ASYNC ep=%p\n", ep); + return false; + } + + return true; +} + static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn, u8 fw_event_code, u16 echo, union event_ring_data *data, u8 fw_return_code) { + struct regpair *fw_handle = &data->rdma_data.async_handle; + struct qed_iwarp_ep *ep = NULL; + u16 cid; + + ep = (struct qed_iwarp_ep *)(uintptr_t)HILO_64(fw_handle->hi, + fw_handle->lo); + + switch (fw_event_code) { + case IWARP_EVENT_TYPE_ASYNC_CONNECT_COMPLETE: + /* Async completion after TCP 3-way handshake */ + if (!qed_iwarp_check_ep_ok(p_hwfn, ep)) + return -EINVAL; + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "EP(0x%x) IWARP_EVENT_TYPE_ASYNC_CONNECT_COMPLETE fw_ret_code=%d\n", + ep->tcp_cid, fw_return_code); + qed_iwarp_connect_complete(p_hwfn, ep, fw_return_code); + break; + case IWARP_EVENT_TYPE_ASYNC_MPA_HANDSHAKE_COMPLETE: + if (!qed_iwarp_check_ep_ok(p_hwfn, ep)) + return -EINVAL; + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "QP(0x%x) IWARP_EVENT_TYPE_ASYNC_MPA_HANDSHAKE_COMPLETE fw_ret_code=%d\n", + ep->cid, fw_return_code); + qed_iwarp_mpa_complete(p_hwfn, ep, fw_return_code); + break; + case IWARP_EVENT_TYPE_ASYNC_CID_CLEANED: + cid = (u16)le32_to_cpu(fw_handle->lo); + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "(0x%x)IWARP_EVENT_TYPE_ASYNC_CID_CLEANED\n", cid); + qed_iwarp_cid_cleaned(p_hwfn, cid); + + break; + } return 0; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h index 29005ac83a6a..bedac98c834c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h @@ -42,6 +42,8 @@ enum qed_iwarp_qp_state { enum qed_iwarp_qp_state qed_roce2iwarp_state(enum qed_roce_qp_state state); +#define QED_IWARP_PREALLOC_CNT (256) + #define QED_IWARP_LL2_SYN_TX_SIZE (128) #define QED_IWARP_LL2_SYN_RX_SIZE (256) #define QED_IWARP_MAX_SYN_PKT_SIZE (128) @@ -55,6 +57,8 @@ struct qed_iwarp_ll2_buff { struct qed_iwarp_info { struct list_head listen_list; /* qed_iwarp_listener */ + struct list_head ep_list; /* qed_iwarp_ep */ + struct list_head ep_free_list; /* pre-allocated ep's */ spinlock_t iw_lock; /* for iwarp resources */ spinlock_t qp_lock; /* for teardown races */ u32 rcv_wnd_scale; @@ -68,6 +72,61 @@ struct qed_iwarp_info { enum mpa_rtr_type rtr_type; }; +enum qed_iwarp_ep_state { + QED_IWARP_EP_INIT, + QED_IWARP_EP_MPA_REQ_RCVD, + QED_IWARP_EP_MPA_OFFLOADED, + QED_IWARP_EP_ESTABLISHED, + QED_IWARP_EP_CLOSED +}; + +union async_output { + struct iwarp_eqe_data_mpa_async_completion mpa_response; + struct iwarp_eqe_data_tcp_async_completion mpa_request; +}; + +#define QED_MAX_PRIV_DATA_LEN (512) +struct qed_iwarp_ep_memory { + u8 in_pdata[QED_MAX_PRIV_DATA_LEN]; + u8 out_pdata[QED_MAX_PRIV_DATA_LEN]; + union async_output async_output; +}; + +/* Endpoint structure represents a TCP connection. This connection can be + * associated with a QP or not (in which case QP==NULL) + */ +struct qed_iwarp_ep { + struct list_head list_entry; + struct qed_rdma_qp *qp; + struct qed_iwarp_ep_memory *ep_buffer_virt; + dma_addr_t ep_buffer_phys; + enum qed_iwarp_ep_state state; + int sig; + struct qed_iwarp_cm_info cm_info; + enum tcp_connect_mode connect_mode; + enum mpa_rtr_type rtr_type; + enum mpa_negotiation_mode mpa_rev; + u32 tcp_cid; + u32 cid; + u16 mss; + u8 remote_mac_addr[6]; + u8 local_mac_addr[6]; + bool mpa_reply_processed; + + /* For Passive side - syn packet related data */ + u16 syn_ip_payload_length; + struct qed_iwarp_ll2_buff *syn; + dma_addr_t syn_phy_addr; + + /* The event_cb function is called for asynchrounous events associated + * with the ep. It is initialized at different entry points depending + * on whether the ep is the tcp connection active side or passive side + * The cb_context is passed to the event_cb function. + */ + iwarp_event_handler event_cb; + void *cb_context; +}; + struct qed_iwarp_listener { struct list_head list_entry; @@ -115,6 +174,9 @@ qed_iwarp_create_listen(void *rdma_cxt, struct qed_iwarp_listen_in *iparams, struct qed_iwarp_listen_out *oparams); +int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams); + +int qed_iwarp_reject(void *rdma_cxt, struct qed_iwarp_reject_in *iparams); int qed_iwarp_destroy_listen(void *rdma_cxt, void *handle); #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 27ea54ba7e1b..0ba5ec8a9814 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -1227,19 +1227,6 @@ static enum eth_filter_action qed_filter_action(enum qed_filter_opcode opcode) return action; } -static void qed_set_fw_mac_addr(__le16 *fw_msb, - __le16 *fw_mid, - __le16 *fw_lsb, - u8 *mac) -{ - ((u8 *)fw_msb)[0] = mac[1]; - ((u8 *)fw_msb)[1] = mac[0]; - ((u8 *)fw_mid)[0] = mac[3]; - ((u8 *)fw_mid)[1] = mac[2]; - ((u8 *)fw_lsb)[0] = mac[5]; - ((u8 *)fw_lsb)[1] = mac[4]; -} - static int qed_filter_ucast_common(struct qed_hwfn *p_hwfn, u16 opaque_fid, diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.h b/drivers/net/ethernet/qlogic/qed/qed_rdma.h index 90e4e0f13727..18ec9cbd84f5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.h +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.h @@ -85,6 +85,7 @@ struct qed_rdma_info { struct qed_bmap qp_map; struct qed_bmap srq_map; struct qed_bmap cid_map; + struct qed_bmap tcp_cid_map; struct qed_bmap real_cid_map; struct qed_bmap dpi_map; struct qed_bmap toggle_bits; @@ -167,6 +168,7 @@ struct qed_rdma_qp { void *shared_queue; dma_addr_t shared_queue_phys_addr; + struct qed_iwarp_ep *ep; }; #if IS_ENABLED(CONFIG_QED_RDMA) diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index c3752c56e54d..ab4ad8a1e2a5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -111,6 +111,8 @@ union ramrod_data { struct rdma_srq_destroy_ramrod_data rdma_destroy_srq; struct rdma_srq_modify_ramrod_data rdma_modify_srq; struct iwarp_create_qp_ramrod_data iwarp_create_qp; + struct iwarp_tcp_offload_ramrod_data iwarp_tcp_offload; + struct iwarp_mpa_offload_ramrod_data iwarp_mpa_offload; struct iwarp_modify_qp_ramrod_data iwarp_modify_qp; struct iwarp_init_func_ramrod_data iwarp_init_func; struct fcoe_init_ramrod_params fcoe_init; -- cgit v1.2.3 From 4b0fdd7c8b757125ac7996617d914bbdb9e0348c Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:28 +0300 Subject: qed: iWARP CM add active side connect This patch implements the active side connect. Offload a connection, process MPA reply and send RTR. In some of the common passive/active functions, the active side will work in blocking mode. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 240 ++++++++++++++++++++++++++-- drivers/net/ethernet/qlogic/qed/qed_iwarp.h | 7 + drivers/net/ethernet/qlogic/qed/qed_rdma.c | 4 + 3 files changed, 239 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index a6dadae1f998..a5da9fc6f454 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -611,7 +611,10 @@ qed_iwarp_tcp_offload(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) memset(&init_data, 0, sizeof(init_data)); init_data.cid = ep->tcp_cid; init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_CB; + if (ep->connect_mode == TCP_CONNECT_PASSIVE) + init_data.comp_mode = QED_SPQ_MODE_CB; + else + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; rc = qed_sp_init_request(p_hwfn, &p_ent, IWARP_RAMROD_CMD_ID_TCP_OFFLOAD, @@ -711,7 +714,7 @@ qed_iwarp_mpa_received(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "private_data_len=%x handshake_mode=%x private_data=(%x)\n", async_data->mpa_request.ulp_data_len, - mpa_rev, *((u32 *)((u8 *)ep->ep_buffer_virt->in_pdata))); + mpa_rev, *((u32 *)(ep->ep_buffer_virt->in_pdata))); if (mpa_rev == MPA_NEGOTIATION_TYPE_ENHANCED) { /* Read ord/ird values from private data buffer */ @@ -801,7 +804,10 @@ qed_iwarp_mpa_offload(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) init_data.cid = reject ? ep->tcp_cid : qp->icid; init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; - init_data.comp_mode = QED_SPQ_MODE_EBLOCK; + if (ep->connect_mode == TCP_CONNECT_ACTIVE) + init_data.comp_mode = QED_SPQ_MODE_CB; + else + init_data.comp_mode = QED_SPQ_MODE_EBLOCK; rc = qed_sp_init_request(p_hwfn, &p_ent, IWARP_RAMROD_CMD_ID_MPA_OFFLOAD, @@ -890,6 +896,59 @@ qed_iwarp_return_ep(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); } +void +qed_iwarp_parse_private_data(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) +{ + struct mpa_v2_hdr *mpa_v2_params; + union async_output *async_data; + u16 mpa_ird, mpa_ord; + u8 mpa_data_size = 0; + + if (MPA_REV2(p_hwfn->p_rdma_info->iwarp.mpa_rev)) { + mpa_v2_params = + (struct mpa_v2_hdr *)(ep->ep_buffer_virt->in_pdata); + mpa_data_size = sizeof(*mpa_v2_params); + mpa_ird = ntohs(mpa_v2_params->ird); + mpa_ord = ntohs(mpa_v2_params->ord); + + ep->cm_info.ird = (u8)(mpa_ord & MPA_V2_IRD_ORD_MASK); + ep->cm_info.ord = (u8)(mpa_ird & MPA_V2_IRD_ORD_MASK); + } + async_data = &ep->ep_buffer_virt->async_output; + + ep->cm_info.private_data = ep->ep_buffer_virt->in_pdata + mpa_data_size; + ep->cm_info.private_data_len = async_data->mpa_response.ulp_data_len - + mpa_data_size; +} + +void +qed_iwarp_mpa_reply_arrived(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep) +{ + struct qed_iwarp_cm_event_params params; + + if (ep->connect_mode == TCP_CONNECT_PASSIVE) { + DP_NOTICE(p_hwfn, + "MPA reply event not expected on passive side!\n"); + return; + } + + params.event = QED_IWARP_EVENT_ACTIVE_MPA_REPLY; + + qed_iwarp_parse_private_data(p_hwfn, ep); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "MPA_NEGOTIATE (v%d): ORD: 0x%x IRD: 0x%x\n", + ep->mpa_rev, ep->cm_info.ord, ep->cm_info.ird); + + params.cm_info = &ep->cm_info; + params.ep_context = ep; + params.status = 0; + + ep->mpa_reply_processed = true; + + ep->event_cb(ep->cb_context, ¶ms); +} + #define QED_IWARP_CONNECT_MODE_STRING(ep) \ ((ep)->connect_mode == TCP_CONNECT_PASSIVE) ? "Passive" : "Active" @@ -902,7 +961,13 @@ qed_iwarp_mpa_complete(struct qed_hwfn *p_hwfn, { struct qed_iwarp_cm_event_params params; - params.event = QED_IWARP_EVENT_PASSIVE_COMPLETE; + if (ep->connect_mode == TCP_CONNECT_ACTIVE) + params.event = QED_IWARP_EVENT_ACTIVE_COMPLETE; + else + params.event = QED_IWARP_EVENT_PASSIVE_COMPLETE; + + if (ep->connect_mode == TCP_CONNECT_ACTIVE && !ep->mpa_reply_processed) + qed_iwarp_parse_private_data(p_hwfn, ep); DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "MPA_NEGOTIATE (v%d): ORD: 0x%x IRD: 0x%x\n", @@ -977,6 +1042,102 @@ qed_iwarp_mpa_v2_set_private(struct qed_hwfn *p_hwfn, } } +int qed_iwarp_connect(void *rdma_cxt, + struct qed_iwarp_connect_in *iparams, + struct qed_iwarp_connect_out *oparams) +{ + struct qed_hwfn *p_hwfn = rdma_cxt; + struct qed_iwarp_info *iwarp_info; + struct qed_iwarp_ep *ep; + u8 mpa_data_size = 0; + u8 ts_hdr_size = 0; + u32 cid; + int rc; + + if ((iparams->cm_info.ord > QED_IWARP_ORD_DEFAULT) || + (iparams->cm_info.ird > QED_IWARP_IRD_DEFAULT)) { + DP_NOTICE(p_hwfn, + "QP(0x%x) ERROR: Invalid ord(0x%x)/ird(0x%x)\n", + iparams->qp->icid, iparams->cm_info.ord, + iparams->cm_info.ird); + + return -EINVAL; + } + + iwarp_info = &p_hwfn->p_rdma_info->iwarp; + + /* Allocate ep object */ + rc = qed_iwarp_alloc_cid(p_hwfn, &cid); + if (rc) + return rc; + + rc = qed_iwarp_create_ep(p_hwfn, &ep); + if (rc) + goto err; + + ep->tcp_cid = cid; + + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + list_add_tail(&ep->list_entry, &p_hwfn->p_rdma_info->iwarp.ep_list); + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + ep->qp = iparams->qp; + ep->qp->ep = ep; + ether_addr_copy(ep->remote_mac_addr, iparams->remote_mac_addr); + ether_addr_copy(ep->local_mac_addr, iparams->local_mac_addr); + memcpy(&ep->cm_info, &iparams->cm_info, sizeof(ep->cm_info)); + + ep->cm_info.ord = iparams->cm_info.ord; + ep->cm_info.ird = iparams->cm_info.ird; + + ep->rtr_type = iwarp_info->rtr_type; + if (!iwarp_info->peer2peer) + ep->rtr_type = MPA_RTR_TYPE_NONE; + + if ((ep->rtr_type & MPA_RTR_TYPE_ZERO_READ) && (ep->cm_info.ord == 0)) + ep->cm_info.ord = 1; + + ep->mpa_rev = iwarp_info->mpa_rev; + + qed_iwarp_mpa_v2_set_private(p_hwfn, ep, &mpa_data_size); + + ep->cm_info.private_data = ep->ep_buffer_virt->out_pdata; + ep->cm_info.private_data_len = iparams->cm_info.private_data_len + + mpa_data_size; + + memcpy((u8 *)ep->ep_buffer_virt->out_pdata + mpa_data_size, + iparams->cm_info.private_data, + iparams->cm_info.private_data_len); + + if (p_hwfn->p_rdma_info->iwarp.tcp_flags & QED_IWARP_TS_EN) + ts_hdr_size = TIMESTAMP_HEADER_SIZE; + + ep->mss = iparams->mss - ts_hdr_size; + ep->mss = min_t(u16, QED_IWARP_MAX_FW_MSS, ep->mss); + + ep->event_cb = iparams->event_cb; + ep->cb_context = iparams->cb_context; + ep->connect_mode = TCP_CONNECT_ACTIVE; + + oparams->ep_context = ep; + + rc = qed_iwarp_tcp_offload(p_hwfn, ep); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QP(0x%x) EP(0x%x) rc = %d\n", + iparams->qp->icid, ep->tcp_cid, rc); + + if (rc) { + qed_iwarp_destroy_ep(p_hwfn, ep, true); + goto err; + } + + return rc; +err: + qed_iwarp_cid_cleaned(p_hwfn, cid); + + return rc; +} + static struct qed_iwarp_ep *qed_iwarp_get_free_ep(struct qed_hwfn *p_hwfn) { struct qed_iwarp_ep *ep = NULL; @@ -1174,12 +1335,12 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn) int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams) { - struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt; + struct qed_hwfn *p_hwfn = rdma_cxt; struct qed_iwarp_ep *ep; u8 mpa_data_size = 0; int rc; - ep = (struct qed_iwarp_ep *)iparams->ep_context; + ep = iparams->ep_context; if (!ep) { DP_ERR(p_hwfn, "Ep Context receive in accept is NULL\n"); return -EINVAL; @@ -1799,13 +1960,19 @@ void qed_iwarp_connect_complete(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep, u8 fw_return_code) { - /* Done with the SYN packet, post back to ll2 rx */ - qed_iwarp_ll2_post_rx(p_hwfn, ep->syn, - p_hwfn->p_rdma_info->iwarp.ll2_syn_handle); - ep->syn = NULL; + u8 ll2_syn_handle = p_hwfn->p_rdma_info->iwarp.ll2_syn_handle; + + if (ep->connect_mode == TCP_CONNECT_PASSIVE) { + /* Done with the SYN packet, post back to ll2 rx */ + qed_iwarp_ll2_post_rx(p_hwfn, ep->syn, ll2_syn_handle); - /* If connect failed - upper layer doesn't know about it */ - qed_iwarp_mpa_received(p_hwfn, ep); + ep->syn = NULL; + + /* If connect failed - upper layer doesn't know about it */ + qed_iwarp_mpa_received(p_hwfn, ep); + } else { + qed_iwarp_mpa_offload(p_hwfn, ep); + } } static inline bool @@ -1842,6 +2009,16 @@ static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn, ep->tcp_cid, fw_return_code); qed_iwarp_connect_complete(p_hwfn, ep, fw_return_code); break; + /* Async event for active side only */ + case IWARP_EVENT_TYPE_ASYNC_ENHANCED_MPA_REPLY_ARRIVED: + if (!qed_iwarp_check_ep_ok(p_hwfn, ep)) + return -EINVAL; + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "QP(0x%x) IWARP_EVENT_TYPE_ASYNC_MPA_HANDSHAKE_MPA_REPLY_ARRIVED fw_ret_code=%d\n", + ep->cid, fw_return_code); + qed_iwarp_mpa_reply_arrived(p_hwfn, ep); + break; case IWARP_EVENT_TYPE_ASYNC_MPA_HANDSHAKE_COMPLETE: if (!qed_iwarp_check_ep_ok(p_hwfn, ep)) return -EINVAL; @@ -1918,6 +2095,45 @@ int qed_iwarp_destroy_listen(void *rdma_cxt, void *handle) return 0; } +int qed_iwarp_send_rtr(void *rdma_cxt, struct qed_iwarp_send_rtr_in *iparams) +{ + struct qed_hwfn *p_hwfn = rdma_cxt; + struct qed_sp_init_data init_data; + struct qed_spq_entry *p_ent; + struct qed_iwarp_ep *ep; + struct qed_rdma_qp *qp; + int rc; + + ep = iparams->ep_context; + if (!ep) { + DP_ERR(p_hwfn, "Ep Context receive in send_rtr is NULL\n"); + return -EINVAL; + } + + qp = ep->qp; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "QP(0x%x) EP(0x%x)\n", + qp->icid, ep->tcp_cid); + + memset(&init_data, 0, sizeof(init_data)); + init_data.cid = qp->icid; + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; + init_data.comp_mode = QED_SPQ_MODE_CB; + + rc = qed_sp_init_request(p_hwfn, &p_ent, + IWARP_RAMROD_CMD_ID_MPA_OFFLOAD_SEND_RTR, + PROTOCOLID_IWARP, &init_data); + + if (rc) + return rc; + + rc = qed_spq_post(p_hwfn, p_ent, NULL); + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "rc = 0x%x\n", rc); + + return rc; +} + void qed_iwarp_query_qp(struct qed_rdma_qp *qp, struct qed_rdma_query_qp_out_params *out_params) diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h index bedac98c834c..148ef3c33a5d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h @@ -169,6 +169,11 @@ int qed_iwarp_fw_destroy(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp); void qed_iwarp_query_qp(struct qed_rdma_qp *qp, struct qed_rdma_query_qp_out_params *out_params); +int +qed_iwarp_connect(void *rdma_cxt, + struct qed_iwarp_connect_in *iparams, + struct qed_iwarp_connect_out *oparams); + int qed_iwarp_create_listen(void *rdma_cxt, struct qed_iwarp_listen_in *iparams, @@ -179,4 +184,6 @@ int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams); int qed_iwarp_reject(void *rdma_cxt, struct qed_iwarp_reject_in *iparams); int qed_iwarp_destroy_listen(void *rdma_cxt, void *handle); +int qed_iwarp_send_rtr(void *rdma_cxt, struct qed_iwarp_send_rtr_in *iparams); + #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c index 29de915007a0..6fb99518a61f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -1772,8 +1772,12 @@ static const struct qed_rdma_ops qed_rdma_ops_pass = { .ll2_set_fragment_of_tx_packet = &qed_ll2_set_fragment_of_tx_packet, .ll2_set_mac_filter = &qed_roce_ll2_set_mac_filter, .ll2_get_stats = &qed_ll2_get_stats, + .iwarp_connect = &qed_iwarp_connect, .iwarp_create_listen = &qed_iwarp_create_listen, .iwarp_destroy_listen = &qed_iwarp_destroy_listen, + .iwarp_accept = &qed_iwarp_accept, + .iwarp_reject = &qed_iwarp_reject, + .iwarp_send_rtr = &qed_iwarp_send_rtr, }; const struct qed_rdma_ops *qed_get_rdma_ops(void) -- cgit v1.2.3 From fc4c6065e661224df3db50780219ac53fee56e2b Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:29 +0300 Subject: qed: iWARP implement disconnect flows This patch takes care of active/passive disconnect flows. Disconnect flows can be initiated remotely, in which case a async event will arrive from peer and indicated to qedr driver. These are referred to as exceptions. When a QP is destroyed, it needs to check that it's associated ep has been closed. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 90 ++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index a5da9fc6f454..84bcda314cd2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -496,6 +496,8 @@ static void qed_iwarp_destroy_ep(struct qed_hwfn *p_hwfn, int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) { + struct qed_iwarp_ep *ep = qp->ep; + int wait_count = 0; int rc = 0; if (qp->iwarp_state != QED_IWARP_QP_STATE_ERROR) { @@ -505,6 +507,18 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) return rc; } + /* Make sure ep is closed before returning and freeing memory. */ + if (ep) { + while (ep->state != QED_IWARP_EP_CLOSED && wait_count++ < 200) + msleep(100); + + if (ep->state != QED_IWARP_EP_CLOSED) + DP_NOTICE(p_hwfn, "ep state close timeout state=%x\n", + ep->state); + + qed_iwarp_destroy_ep(p_hwfn, ep, false); + } + rc = qed_iwarp_fw_destroy(p_hwfn, qp); if (qp->shared_queue) @@ -1956,6 +1970,61 @@ int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) return qed_iwarp_ll2_stop(p_hwfn, p_ptt); } +void qed_iwarp_qp_in_error(struct qed_hwfn *p_hwfn, + struct qed_iwarp_ep *ep, u8 fw_return_code) +{ + struct qed_iwarp_cm_event_params params; + + qed_iwarp_modify_qp(p_hwfn, ep->qp, QED_IWARP_QP_STATE_ERROR, true); + + params.event = QED_IWARP_EVENT_CLOSE; + params.ep_context = ep; + params.cm_info = &ep->cm_info; + params.status = (fw_return_code == IWARP_QP_IN_ERROR_GOOD_CLOSE) ? + 0 : -ECONNRESET; + + ep->state = QED_IWARP_EP_CLOSED; + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + list_del(&ep->list_entry); + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + + ep->event_cb(ep->cb_context, ¶ms); +} + +void qed_iwarp_exception_received(struct qed_hwfn *p_hwfn, + struct qed_iwarp_ep *ep, int fw_ret_code) +{ + struct qed_iwarp_cm_event_params params; + bool event_cb = false; + + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "EP(0x%x) fw_ret_code=%d\n", + ep->cid, fw_ret_code); + + switch (fw_ret_code) { + case IWARP_EXCEPTION_DETECTED_LLP_CLOSED: + params.status = 0; + params.event = QED_IWARP_EVENT_DISCONNECT; + event_cb = true; + break; + case IWARP_EXCEPTION_DETECTED_LLP_RESET: + params.status = -ECONNRESET; + params.event = QED_IWARP_EVENT_DISCONNECT; + event_cb = true; + break; + default: + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "Unhandled exception received...fw_ret_code=%d\n", + fw_ret_code); + break; + } + + if (event_cb) { + params.ep_context = ep; + params.cm_info = &ep->cm_info; + ep->event_cb(ep->cb_context, ¶ms); + } +} + void qed_iwarp_connect_complete(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep, u8 fw_return_code) @@ -2009,8 +2078,27 @@ static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn, ep->tcp_cid, fw_return_code); qed_iwarp_connect_complete(p_hwfn, ep, fw_return_code); break; - /* Async event for active side only */ + case IWARP_EVENT_TYPE_ASYNC_EXCEPTION_DETECTED: + if (!qed_iwarp_check_ep_ok(p_hwfn, ep)) + return -EINVAL; + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "QP(0x%x) IWARP_EVENT_TYPE_ASYNC_EXCEPTION_DETECTED fw_ret_code=%d\n", + ep->cid, fw_return_code); + qed_iwarp_exception_received(p_hwfn, ep, fw_return_code); + break; + case IWARP_EVENT_TYPE_ASYNC_QP_IN_ERROR_STATE: + /* Async completion for Close Connection ramrod */ + if (!qed_iwarp_check_ep_ok(p_hwfn, ep)) + return -EINVAL; + DP_VERBOSE(p_hwfn, + QED_MSG_RDMA, + "QP(0x%x) IWARP_EVENT_TYPE_ASYNC_QP_IN_ERROR_STATE fw_ret_code=%d\n", + ep->cid, fw_return_code); + qed_iwarp_qp_in_error(p_hwfn, ep, fw_return_code); + break; case IWARP_EVENT_TYPE_ASYNC_ENHANCED_MPA_REPLY_ARRIVED: + /* Async event for active side only */ if (!qed_iwarp_check_ep_ok(p_hwfn, ep)) return -EINVAL; DP_VERBOSE(p_hwfn, -- cgit v1.2.3 From 9816b614346925feac1198e33d2dc5201c4ef74e Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:30 +0300 Subject: qed: iWARP CM add error handling This patch introduces error handling for errors that occurred during connection establishment. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 183 +++++++++++++++++++++++++++- 1 file changed, 181 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index 84bcda314cd2..5cd20da2d4e0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -1001,12 +1001,75 @@ qed_iwarp_mpa_complete(struct qed_hwfn *p_hwfn, ep->state = QED_IWARP_EP_ESTABLISHED; params.status = 0; break; + case IWARP_CONN_ERROR_MPA_TIMEOUT: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA timeout\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid); + params.status = -EBUSY; + break; + case IWARP_CONN_ERROR_MPA_ERROR_REJECT: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA Reject\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid); + params.status = -ECONNREFUSED; + break; + case IWARP_CONN_ERROR_MPA_RST: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA reset(tcp cid: 0x%x)\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid, + ep->tcp_cid); + params.status = -ECONNRESET; + break; + case IWARP_CONN_ERROR_MPA_FIN: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA received FIN\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid); + params.status = -ECONNREFUSED; + break; + case IWARP_CONN_ERROR_MPA_INSUF_IRD: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA insufficient ird\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid); + params.status = -ECONNREFUSED; + break; + case IWARP_CONN_ERROR_MPA_RTR_MISMATCH: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA RTR MISMATCH\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid); + params.status = -ECONNREFUSED; + break; + case IWARP_CONN_ERROR_MPA_INVALID_PACKET: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA Invalid Packet\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid); + params.status = -ECONNREFUSED; + break; + case IWARP_CONN_ERROR_MPA_LOCAL_ERROR: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA Local Error\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid); + params.status = -ECONNREFUSED; + break; + case IWARP_CONN_ERROR_MPA_TERMINATE: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA TERMINATE\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid); + params.status = -ECONNREFUSED; + break; default: params.status = -ECONNRESET; break; } ep->event_cb(ep->cb_context, ¶ms); + + /* on passive side, if there is no associated QP (REJECT) we need to + * return the ep to the pool, (in the regular case we add an element + * in accept instead of this one. + * In both cases we need to remove it from the ep_list. + */ + if (fw_return_code != RDMA_RETURN_OK) { + ep->tcp_cid = QED_IWARP_INVALID_TCP_CID; + if ((ep->connect_mode == TCP_CONNECT_PASSIVE) && + (!ep->qp)) { /* Rejected */ + qed_iwarp_return_ep(p_hwfn, ep); + } else { + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + list_del(&ep->list_entry); + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + } + } } static void @@ -2011,6 +2074,42 @@ void qed_iwarp_exception_received(struct qed_hwfn *p_hwfn, params.event = QED_IWARP_EVENT_DISCONNECT; event_cb = true; break; + case IWARP_EXCEPTION_DETECTED_RQ_EMPTY: + params.event = QED_IWARP_EVENT_RQ_EMPTY; + event_cb = true; + break; + case IWARP_EXCEPTION_DETECTED_IRQ_FULL: + params.event = QED_IWARP_EVENT_IRQ_FULL; + event_cb = true; + break; + case IWARP_EXCEPTION_DETECTED_LLP_TIMEOUT: + params.event = QED_IWARP_EVENT_LLP_TIMEOUT; + event_cb = true; + break; + case IWARP_EXCEPTION_DETECTED_REMOTE_PROTECTION_ERROR: + params.event = QED_IWARP_EVENT_REMOTE_PROTECTION_ERROR; + event_cb = true; + break; + case IWARP_EXCEPTION_DETECTED_CQ_OVERFLOW: + params.event = QED_IWARP_EVENT_CQ_OVERFLOW; + event_cb = true; + break; + case IWARP_EXCEPTION_DETECTED_LOCAL_CATASTROPHIC: + params.event = QED_IWARP_EVENT_QP_CATASTROPHIC; + event_cb = true; + break; + case IWARP_EXCEPTION_DETECTED_LOCAL_ACCESS_ERROR: + params.event = QED_IWARP_EVENT_LOCAL_ACCESS_ERROR; + event_cb = true; + break; + case IWARP_EXCEPTION_DETECTED_REMOTE_OPERATION_ERROR: + params.event = QED_IWARP_EVENT_REMOTE_OPERATION_ERROR; + event_cb = true; + break; + case IWARP_EXCEPTION_DETECTED_TERMINATE_RECEIVED: + params.event = QED_IWARP_EVENT_TERMINATE_RECEIVED; + event_cb = true; + break; default: DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Unhandled exception received...fw_ret_code=%d\n", @@ -2025,6 +2124,66 @@ void qed_iwarp_exception_received(struct qed_hwfn *p_hwfn, } } +static void +qed_iwarp_tcp_connect_unsuccessful(struct qed_hwfn *p_hwfn, + struct qed_iwarp_ep *ep, u8 fw_return_code) +{ + struct qed_iwarp_cm_event_params params; + + memset(¶ms, 0, sizeof(params)); + params.event = QED_IWARP_EVENT_ACTIVE_COMPLETE; + params.ep_context = ep; + params.cm_info = &ep->cm_info; + ep->state = QED_IWARP_EP_CLOSED; + + switch (fw_return_code) { + case IWARP_CONN_ERROR_TCP_CONNECT_INVALID_PACKET: + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "%s(0x%x) TCP connect got invalid packet\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->tcp_cid); + params.status = -ECONNRESET; + break; + case IWARP_CONN_ERROR_TCP_CONNECTION_RST: + DP_VERBOSE(p_hwfn, QED_MSG_RDMA, + "%s(0x%x) TCP Connection Reset\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->tcp_cid); + params.status = -ECONNRESET; + break; + case IWARP_CONN_ERROR_TCP_CONNECT_TIMEOUT: + DP_NOTICE(p_hwfn, "%s(0x%x) TCP timeout\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->tcp_cid); + params.status = -EBUSY; + break; + case IWARP_CONN_ERROR_MPA_NOT_SUPPORTED_VER: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA not supported VER\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->tcp_cid); + params.status = -ECONNREFUSED; + break; + case IWARP_CONN_ERROR_MPA_INVALID_PACKET: + DP_NOTICE(p_hwfn, "%s(0x%x) MPA Invalid Packet\n", + QED_IWARP_CONNECT_MODE_STRING(ep), ep->tcp_cid); + params.status = -ECONNRESET; + break; + default: + DP_ERR(p_hwfn, + "%s(0x%x) Unexpected return code tcp connect: %d\n", + QED_IWARP_CONNECT_MODE_STRING(ep), + ep->tcp_cid, fw_return_code); + params.status = -ECONNRESET; + break; + } + + if (ep->connect_mode == TCP_CONNECT_PASSIVE) { + ep->tcp_cid = QED_IWARP_INVALID_TCP_CID; + qed_iwarp_return_ep(p_hwfn, ep); + } else { + ep->event_cb(ep->cb_context, ¶ms); + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + list_del(&ep->list_entry); + spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); + } +} + void qed_iwarp_connect_complete(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep, u8 fw_return_code) @@ -2038,9 +2197,17 @@ qed_iwarp_connect_complete(struct qed_hwfn *p_hwfn, ep->syn = NULL; /* If connect failed - upper layer doesn't know about it */ - qed_iwarp_mpa_received(p_hwfn, ep); + if (fw_return_code == RDMA_RETURN_OK) + qed_iwarp_mpa_received(p_hwfn, ep); + else + qed_iwarp_tcp_connect_unsuccessful(p_hwfn, ep, + fw_return_code); } else { - qed_iwarp_mpa_offload(p_hwfn, ep); + if (fw_return_code == RDMA_RETURN_OK) + qed_iwarp_mpa_offload(p_hwfn, ep); + else + qed_iwarp_tcp_connect_unsuccessful(p_hwfn, ep, + fw_return_code); } } @@ -2123,6 +2290,18 @@ static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn, qed_iwarp_cid_cleaned(p_hwfn, cid); break; + case IWARP_EVENT_TYPE_ASYNC_CQ_OVERFLOW: + DP_NOTICE(p_hwfn, "IWARP_EVENT_TYPE_ASYNC_CQ_OVERFLOW\n"); + + p_hwfn->p_rdma_info->events.affiliated_event( + p_hwfn->p_rdma_info->events.context, + QED_IWARP_EVENT_CQ_OVERFLOW, + (void *)fw_handle); + break; + default: + DP_ERR(p_hwfn, "Received unexpected async iwarp event %d\n", + fw_event_code); + return -EINVAL; } return 0; } -- cgit v1.2.3 From 5d7dc9620d35ce1f503e2062aa324447e557e3f2 Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:31 +0300 Subject: qed: Add iWARP protocol support in context allocation When computing how much memory is required for the different hw clients iWARP protocol should be taken into account Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 38716f77c21d..af106be8cc08 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -246,14 +246,16 @@ struct qed_cxt_mngr { static bool src_proto(enum protocol_type type) { return type == PROTOCOLID_ISCSI || - type == PROTOCOLID_FCOE; + type == PROTOCOLID_FCOE || + type == PROTOCOLID_IWARP; } static bool tm_cid_proto(enum protocol_type type) { return type == PROTOCOLID_ISCSI || type == PROTOCOLID_FCOE || - type == PROTOCOLID_ROCE; + type == PROTOCOLID_ROCE || + type == PROTOCOLID_IWARP; } static bool tm_tid_proto(enum protocol_type type) @@ -2068,6 +2070,11 @@ static void qed_rdma_set_pf_params(struct qed_hwfn *p_hwfn, num_srqs = min_t(u32, 32 * 1024, p_params->num_srqs); switch (p_hwfn->hw_info.personality) { + case QED_PCI_ETH_IWARP: + /* Each QP requires one connection */ + num_cons = min_t(u32, IWARP_MAX_QPS, p_params->num_qps); + proto = PROTOCOLID_IWARP; + break; case QED_PCI_ETH_ROCE: num_qps = min_t(u32, ROCE_MAX_QPS, p_params->num_qps); num_cons = num_qps * 2; /* each QP requires two connections */ @@ -2103,6 +2110,8 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 rdma_tasks) qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_CORE, core_cids, 0); switch (p_hwfn->hw_info.personality) { + case QED_PCI_ETH_RDMA: + case QED_PCI_ETH_IWARP: case QED_PCI_ETH_ROCE: { qed_rdma_set_pf_params(p_hwfn, -- cgit v1.2.3 From 93c45984d385bddf156735991ee0cd15c0753e4d Mon Sep 17 00:00:00 2001 From: "Kalderon, Michal" Date: Sun, 2 Jul 2017 10:29:32 +0300 Subject: qed: Add iWARP support for physical queue allocation iWARP has different physical queue requirements than RoCE Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 4060a6ad9be3..6c87bed13bd2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -216,6 +216,10 @@ static u32 qed_get_pq_flags(struct qed_hwfn *p_hwfn) case QED_PCI_ETH_ROCE: flags |= PQ_FLAGS_MCOS | PQ_FLAGS_OFLD | PQ_FLAGS_LLT; break; + case QED_PCI_ETH_IWARP: + flags |= PQ_FLAGS_MCOS | PQ_FLAGS_ACK | PQ_FLAGS_OOO | + PQ_FLAGS_OFLD; + break; default: DP_ERR(p_hwfn, "unknown personality %d\n", p_hwfn->hw_info.personality); -- cgit v1.2.3 From e1069bbfcf3bcf4feb264397f3451184fd66b907 Mon Sep 17 00:00:00 2001 From: Jim Baxter Date: Wed, 28 Jun 2017 21:35:29 +0100 Subject: net: cdc_ncm: Reduce memory use when kernel memory low MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CDC-NCM driver can require large amounts of memory to create skb's and this can be a problem when the memory becomes fragmented. This especially affects embedded systems that have constrained resources but wish to maximise the throughput of CDC-NCM with 16KiB NTB's. The issue is after running for a while the kernel memory can become fragmented and it needs compacting. If the NTB allocation is needed before the memory has been compacted the atomic allocation can fail which can cause increased latency, large re-transmissions or disconnections depending upon the data being transmitted at the time. This situation occurs for less than a second until the kernel has compacted the memory but the failed devices can take a lot longer to recover from the failed TX packets. To ease this temporary situation I modified the CDC-NCM TX path to temporarily switch into a reduced memory mode which allocates an NTB that will fit into a USB_CDC_NCM_NTB_MIN_OUT_SIZE (default 2048 Bytes) sized memory block and only transmit NTB's with a single network frame until the memory situation is resolved. Each time this issue occurs we wait for an increasing number of reduced size allocations before requesting a full size one to not put additional pressure on a low memory system. Once the memory is compacted the CDC-NCM data can resume transmitting at the normal tx_max rate once again. Signed-off-by: Jim Baxter Reviewed-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ncm.c | 54 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 2067743f51ca..d103a1d4fb36 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -89,6 +89,8 @@ static const struct cdc_ncm_stats cdc_ncm_gstrings_stats[] = { CDC_NCM_SIMPLE_STAT(rx_ntbs), }; +#define CDC_NCM_LOW_MEM_MAX_CNT 10 + static int cdc_ncm_get_sset_count(struct net_device __always_unused *netdev, int sset) { switch (sset) { @@ -1055,10 +1057,10 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_ /* align new NDP */ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) - cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); + cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size); /* verify that there is room for the NDP and the datagram (reserve) */ - if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size) + if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size) return NULL; /* link to it */ @@ -1111,13 +1113,41 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) /* allocate a new OUT skb */ if (!skb_out) { - skb_out = alloc_skb(ctx->tx_max, GFP_ATOMIC); + if (ctx->tx_low_mem_val == 0) { + ctx->tx_curr_size = ctx->tx_max; + skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC); + /* If the memory allocation fails we will wait longer + * each time before attempting another full size + * allocation again to not overload the system + * further. + */ + if (skb_out == NULL) { + ctx->tx_low_mem_max_cnt = min(ctx->tx_low_mem_max_cnt + 1, + (unsigned)CDC_NCM_LOW_MEM_MAX_CNT); + ctx->tx_low_mem_val = ctx->tx_low_mem_max_cnt; + } + } if (skb_out == NULL) { - if (skb != NULL) { - dev_kfree_skb_any(skb); - dev->net->stats.tx_dropped++; + /* See if a very small allocation is possible. + * We will send this packet immediately and hope + * that there is more memory available later. + */ + if (skb) + ctx->tx_curr_size = max(skb->len, + (u32)USB_CDC_NCM_NTB_MIN_OUT_SIZE); + else + ctx->tx_curr_size = USB_CDC_NCM_NTB_MIN_OUT_SIZE; + skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC); + + /* No allocation possible so we will abort */ + if (skb_out == NULL) { + if (skb != NULL) { + dev_kfree_skb_any(skb); + dev->net->stats.tx_dropped++; + } + goto exit_no_skb; } - goto exit_no_skb; + ctx->tx_low_mem_val--; } /* fill out the initial 16-bit NTB header */ nth16 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth16)); @@ -1148,10 +1178,10 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) ndp16 = cdc_ncm_ndp(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder); /* align beginning of next frame */ - cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max); + cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_curr_size); /* check if we had enough room left for both NDP and frame */ - if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) { + if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_curr_size) { if (n == 0) { /* won't fit, MTU problem? */ dev_kfree_skb_any(skb); @@ -1227,7 +1257,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) /* If requested, put NDP at end of frame. */ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; - cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); + cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size); nth16->wNdpIndex = cpu_to_le16(skb_out->len); skb_put_data(skb_out, ctx->delayed_ndp16, ctx->max_ndp_size); @@ -1246,9 +1276,9 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) */ if (!(dev->driver_info->flags & FLAG_SEND_ZLP) && skb_out->len > ctx->min_tx_pkt) { - padding_count = ctx->tx_max - skb_out->len; + padding_count = ctx->tx_curr_size - skb_out->len; skb_put_zero(skb_out, padding_count); - } else if (skb_out->len < ctx->tx_max && + } else if (skb_out->len < ctx->tx_curr_size && (skb_out->len % dev->maxpacket) == 0) { skb_put_u8(skb_out, 0); /* force short packet */ } -- cgit v1.2.3 From 6992c6c5dd4756e665824d4bc29f15b85c2907e0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 30 Jun 2017 16:24:35 +1000 Subject: net/mlx5: fix memcpy limit? Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c index 5cb855fd618f..e37453d838db 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c @@ -191,7 +191,7 @@ int mlx5_fpga_query_qp(struct mlx5_core_dev *dev, if (ret) return ret; - memcpy(fpga_qpc, MLX5_ADDR_OF(fpga_query_qp_out, in, fpga_qpc), + memcpy(fpga_qpc, MLX5_ADDR_OF(fpga_query_qp_out, out, fpga_qpc), MLX5_FLD_SZ_BYTES(fpga_query_qp_out, fpga_qpc)); return ret; } -- cgit v1.2.3 From f0f9b4ed23381d97cde2ac64248198bc43608e6d Mon Sep 17 00:00:00 2001 From: Lin Yun Sheng Date: Fri, 30 Jun 2017 17:44:15 +0800 Subject: net: phy: Add phy loopback support in net phy framework This patch add set_loopback in phy_driver, which is used by MAC driver to enable or disable phy loopback. it also add a generic genphy_loopback function, which use BMCR loopback bit to enable or disable loopback. Signed-off-by: Lin Yun Sheng Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 1 + drivers/net/phy/phy_device.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 8400403b3f62..5d314f143aea 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -2171,6 +2171,7 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .set_loopback = genphy_loopback, }, { .phy_id = MARVELL_PHY_ID_88E1540, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index acf00f071c9a..1790f7fec125 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1136,6 +1136,39 @@ int phy_resume(struct phy_device *phydev) } EXPORT_SYMBOL(phy_resume); +int phy_loopback(struct phy_device *phydev, bool enable) +{ + struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver); + int ret = 0; + + mutex_lock(&phydev->lock); + + if (enable && phydev->loopback_enabled) { + ret = -EBUSY; + goto out; + } + + if (!enable && !phydev->loopback_enabled) { + ret = -EINVAL; + goto out; + } + + if (phydev->drv && phydrv->set_loopback) + ret = phydrv->set_loopback(phydev, enable); + else + ret = -EOPNOTSUPP; + + if (ret) + goto out; + + phydev->loopback_enabled = enable; + +out: + mutex_unlock(&phydev->lock); + return ret; +} +EXPORT_SYMBOL(phy_loopback); + /* Generic PHY support and helper functions */ /** @@ -1584,6 +1617,23 @@ int genphy_resume(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_resume); +int genphy_loopback(struct phy_device *phydev, bool enable) +{ + int value; + + value = phy_read(phydev, MII_BMCR); + if (value < 0) + return value; + + if (enable) + value |= BMCR_LOOPBACK; + else + value &= ~BMCR_LOOPBACK; + + return phy_write(phydev, MII_BMCR, value); +} +EXPORT_SYMBOL(genphy_loopback); + static int __set_phy_supported(struct phy_device *phydev, u32 max_speed) { /* The default values for phydev->supported are provided by the PHY @@ -1829,6 +1879,7 @@ static struct phy_driver genphy_driver = { .read_status = genphy_read_status, .suspend = genphy_suspend, .resume = genphy_resume, + .set_loopback = genphy_loopback, }; static int __init phy_init(void) -- cgit v1.2.3 From 67cd9a997f1bfb5dedf407ad540232912bd04b10 Mon Sep 17 00:00:00 2001 From: Lin Yun Sheng Date: Fri, 30 Jun 2017 17:44:16 +0800 Subject: net: hns: Use phy_driver to setup Phy loopback Use function set_loopback in phy_driver to setup phy loopback when doing ethtool self test. Signed-off-by: Lin Yun Sheng Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hnae.h | 1 + drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 105 ++++++++--------------- 2 files changed, 35 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h index 04211ac73b36..7ba653af19cb 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.h +++ b/drivers/net/ethernet/hisilicon/hns/hnae.h @@ -360,6 +360,7 @@ enum hnae_loop { MAC_INTERNALLOOP_MAC = 0, MAC_INTERNALLOOP_SERDES, MAC_INTERNALLOOP_PHY, + MAC_LOOP_PHY_NONE, MAC_LOOP_NONE, }; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index 00e57bbaf122..a8db27e86a11 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -259,67 +259,27 @@ static const char hns_nic_test_strs[][ETH_GSTRING_LEN] = { static int hns_nic_config_phy_loopback(struct phy_device *phy_dev, u8 en) { -#define COPPER_CONTROL_REG 0 -#define PHY_POWER_DOWN BIT(11) -#define PHY_LOOP_BACK BIT(14) - u16 val = 0; - - if (phy_dev->is_c45) /* c45 branch adding for XGE PHY */ - return -ENOTSUPP; + int err; if (en) { - /* speed : 1000M */ - phy_write(phy_dev, HNS_PHY_PAGE_REG, 2); - phy_write(phy_dev, 21, 0x1046); - - phy_write(phy_dev, HNS_PHY_PAGE_REG, 0); - /* Force Master */ - phy_write(phy_dev, 9, 0x1F00); - - /* Soft-reset */ - phy_write(phy_dev, 0, 0x9140); - /* If autoneg disabled,two soft-reset operations */ - phy_write(phy_dev, 0, 0x9140); - - phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA); - - /* Default is 0x0400 */ - phy_write(phy_dev, 1, 0x418); - - /* Force 1000M Link, Default is 0x0200 */ - phy_write(phy_dev, 7, 0x20C); - - /* Powerup Fiber */ - phy_write(phy_dev, HNS_PHY_PAGE_REG, 1); - val = phy_read(phy_dev, COPPER_CONTROL_REG); - val &= ~PHY_POWER_DOWN; - phy_write(phy_dev, COPPER_CONTROL_REG, val); - - /* Enable Phy Loopback */ - phy_write(phy_dev, HNS_PHY_PAGE_REG, 0); - val = phy_read(phy_dev, COPPER_CONTROL_REG); - val |= PHY_LOOP_BACK; - val &= ~PHY_POWER_DOWN; - phy_write(phy_dev, COPPER_CONTROL_REG, val); + /* Doing phy loopback in offline state, phy resuming is + * needed to power up the device. + */ + err = phy_resume(phy_dev); + if (err) + goto out; + + err = phy_loopback(phy_dev, true); } else { - phy_write(phy_dev, HNS_PHY_PAGE_REG, 0xFA); - phy_write(phy_dev, 1, 0x400); - phy_write(phy_dev, 7, 0x200); - - phy_write(phy_dev, HNS_PHY_PAGE_REG, 1); - val = phy_read(phy_dev, COPPER_CONTROL_REG); - val |= PHY_POWER_DOWN; - phy_write(phy_dev, COPPER_CONTROL_REG, val); - - phy_write(phy_dev, HNS_PHY_PAGE_REG, 0); - phy_write(phy_dev, 9, 0xF00); - - val = phy_read(phy_dev, COPPER_CONTROL_REG); - val &= ~PHY_LOOP_BACK; - val |= PHY_POWER_DOWN; - phy_write(phy_dev, COPPER_CONTROL_REG, val); + err = phy_loopback(phy_dev, false); + if (err) + goto out; + + err = phy_suspend(phy_dev); } - return 0; + +out: + return err; } static int __lb_setup(struct net_device *ndev, @@ -332,10 +292,9 @@ static int __lb_setup(struct net_device *ndev, switch (loop) { case MAC_INTERNALLOOP_PHY: - if ((phy_dev) && (!phy_dev->is_c45)) { - ret = hns_nic_config_phy_loopback(phy_dev, 0x1); - ret |= h->dev->ops->set_loopback(h, loop, 0x1); - } + ret = hns_nic_config_phy_loopback(phy_dev, 0x1); + if (!ret) + ret = h->dev->ops->set_loopback(h, loop, 0x1); break; case MAC_INTERNALLOOP_MAC: if ((h->dev->ops->set_loopback) && @@ -346,17 +305,17 @@ static int __lb_setup(struct net_device *ndev, if (h->dev->ops->set_loopback) ret = h->dev->ops->set_loopback(h, loop, 0x1); break; + case MAC_LOOP_PHY_NONE: + ret = hns_nic_config_phy_loopback(phy_dev, 0x0); case MAC_LOOP_NONE: - if ((phy_dev) && (!phy_dev->is_c45)) - ret |= hns_nic_config_phy_loopback(phy_dev, 0x0); - - if (h->dev->ops->set_loopback) { + if (!ret && h->dev->ops->set_loopback) { if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII) - ret |= h->dev->ops->set_loopback(h, + ret = h->dev->ops->set_loopback(h, MAC_INTERNALLOOP_MAC, 0x0); - ret |= h->dev->ops->set_loopback(h, - MAC_INTERNALLOOP_SERDES, 0x0); + if (!ret) + ret = h->dev->ops->set_loopback(h, + MAC_INTERNALLOOP_SERDES, 0x0); } break; default: @@ -582,13 +541,16 @@ static int __lb_run_test(struct net_device *ndev, return ret_val; } -static int __lb_down(struct net_device *ndev) +static int __lb_down(struct net_device *ndev, enum hnae_loop loop) { struct hns_nic_priv *priv = netdev_priv(ndev); struct hnae_handle *h = priv->ae_handle; int ret; - ret = __lb_setup(ndev, MAC_LOOP_NONE); + if (loop == MAC_INTERNALLOOP_PHY) + ret = __lb_setup(ndev, MAC_LOOP_PHY_NONE); + else + ret = __lb_setup(ndev, MAC_LOOP_NONE); if (ret) netdev_err(ndev, "%s: __lb_setup return error(%d)!\n", __func__, @@ -644,7 +606,8 @@ static void hns_nic_self_test(struct net_device *ndev, if (!data[test_index]) { data[test_index] = __lb_run_test( ndev, (enum hnae_loop)st_param[i][0]); - (void)__lb_down(ndev); + (void)__lb_down(ndev, + (enum hnae_loop)st_param[i][0]); } if (data[test_index]) -- cgit v1.2.3 From 889ce937c98f1f969137a8a2ee78627c1537d4b3 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Fri, 30 Jun 2017 15:50:00 +0200 Subject: vxlan: correctly set vxlan->net when creating the device in a netns Commit a985343ba906 ("vxlan: refactor verification and application of configuration") modified vxlan device creation, and replaced the assignment of vxlan->net to src_net with dev_net(netdev) in ->setup(). But dev_net(netdev) is not the same as src_net. At the time ->setup() is called, dev_net hasn't been set yet, so we end up creating the socket for the vxlan device in init_net. Fix this by bringing back the assignment of vxlan->net during device creation. Fixes: a985343ba906 ("vxlan: refactor verification and application of configuration") Signed-off-by: Sabrina Dubroca Reviewed-by: Matthias Schiffer Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index fd0ff97e3d81..47d6e65851aa 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2656,7 +2656,6 @@ static void vxlan_setup(struct net_device *dev) vxlan->age_timer.data = (unsigned long) vxlan; vxlan->dev = dev; - vxlan->net = dev_net(dev); gro_cells_init(&vxlan->gro_cells, dev); @@ -3028,7 +3027,9 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf, static void vxlan_config_apply(struct net_device *dev, struct vxlan_config *conf, - struct net_device *lowerdev, bool changelink) + struct net_device *lowerdev, + struct net *src_net, + bool changelink) { struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst *dst = &vxlan->default_dst; @@ -3044,6 +3045,8 @@ static void vxlan_config_apply(struct net_device *dev, if (conf->mtu) dev->mtu = conf->mtu; + + vxlan->net = src_net; } dst->remote_vni = conf->vni; @@ -3086,7 +3089,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, if (ret) return ret; - vxlan_config_apply(dev, conf, lowerdev, changelink); + vxlan_config_apply(dev, conf, lowerdev, src_net, changelink); return 0; } -- cgit v1.2.3 From a68491f895a937778bb25b0795830797239de31f Mon Sep 17 00:00:00 2001 From: Tore Anderson Date: Sat, 1 Jul 2017 15:20:02 +0200 Subject: net: cdc_mbim: apply "NDP to end" quirk to HP lt4132 The HP lt4132 LTE/HSPA+ 4G Module (03f0:a31d) is a rebranded Huawei ME906s-158 device. It, like the ME906s-158, requires the "NDP to end" quirk for correct operation. Signed-off-by: Tore Anderson Signed-off-by: David S. Miller --- drivers/net/usb/cdc_mbim.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 18fa45fc979b..7220cd620717 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -643,6 +643,13 @@ static const struct usb_device_id mbim_devs[] = { .driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end, }, + /* The HP lt4132 (03f0:a31d) is a rebranded Huawei ME906s-158, + * therefore it too requires the above "NDP to end" quirk. + */ + { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end, + }, + /* Telit LE922A6 in MBIM composition */ { USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x1041, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle, -- cgit v1.2.3 From bba5850c8b11ce849434434a7f77fb59ac7248e7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 3 Jul 2017 02:29:57 -0700 Subject: ctcm_fsms: Convert skb->user accesses to refcount_t Reported-by: kbuild test robot Signed-off-by: David S. Miller --- drivers/s390/net/ctcm_fsms.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c index e9847ce3860d..570ae3b7adf6 100644 --- a/drivers/s390/net/ctcm_fsms.c +++ b/drivers/s390/net/ctcm_fsms.c @@ -217,7 +217,7 @@ void ctcm_purge_skb_queue(struct sk_buff_head *q) CTCM_DBF_TEXT(TRACE, CTC_DBF_DEBUG, __func__); while ((skb = skb_dequeue(q))) { - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_any(skb); } } @@ -271,7 +271,7 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg) priv->stats.tx_bytes += 2; first = 0; } - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_irq(skb); } spin_lock(&ch->collect_lock); @@ -297,7 +297,7 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg) skb_put(ch->trans_skb, skb->len), skb->len); priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len - LL_HEADER_LENGTH; - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_irq(skb); i++; } @@ -1248,7 +1248,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg) priv->stats.tx_bytes += 2; first = 0; } - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_irq(skb); } spin_lock(&ch->collect_lock); @@ -1298,7 +1298,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg) data_space -= skb->len; priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; - atomic_dec(&skb->users); + refcount_dec(&skb->users); dev_kfree_skb_any(skb); peekskb = skb_peek(&ch->collect_queue); if (peekskb->len > data_space) @@ -1795,7 +1795,7 @@ static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg) fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); goto done; } else { - atomic_inc(&skb->users); + refcount_inc(&skb->users); skb_queue_tail(&wch->io_queue, skb); } -- cgit v1.2.3 From c1c1d86bdea45880c1843087d40498127d4293c9 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 2 Jul 2017 18:57:28 +0300 Subject: net/mlxfw: Properly handle dependancy with non-loadable mlx5 If mlx5 is set to be built-in and mlxfw as a module, we get a link error: drivers/built-in.o: In function `mlx5_firmware_flash': (.text+0x5aed72): undefined reference to `mlxfw_firmware_flash' Since we don't want to mandate selecting mlxfw for mlx5 users, we use the IS_REACHABLE macro to make sure that a stub is exposed to the caller. Signed-off-by: Or Gerlitz Reported-by: Jakub Kicinski Reported-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxfw/mlxfw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h index 9ca85383aa35..7a712b6b09ec 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h @@ -96,7 +96,7 @@ struct mlxfw_dev { u16 psid_size; }; -#if IS_ENABLED(CONFIG_MLXFW) +#if IS_REACHABLE(CONFIG_MLXFW) int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, const struct firmware *firmware); #else -- cgit v1.2.3 From 69e766612c4bcb79e19cebed9eed61d4222c1d47 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Sun, 2 Jul 2017 19:00:57 +0200 Subject: vxlan: fix hlist corruption It's not a good idea to add the same hlist_node to two different hash lists. This leads to various hard to debug memory corruptions. Fixes: b1be00a6c39f ("vxlan: support both IPv4 and IPv6 sockets in a single vxlan device") Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 47d6e65851aa..b04e103350fb 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -229,25 +229,25 @@ static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family, static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, int ifindex, __be32 vni) { - struct vxlan_dev *vxlan; + struct vxlan_dev_node *node; /* For flow based devices, map all packets to VNI 0 */ if (vs->flags & VXLAN_F_COLLECT_METADATA) vni = 0; - hlist_for_each_entry_rcu(vxlan, vni_head(vs, vni), hlist) { - if (vxlan->default_dst.remote_vni != vni) + hlist_for_each_entry_rcu(node, vni_head(vs, vni), hlist) { + if (node->vxlan->default_dst.remote_vni != vni) continue; if (IS_ENABLED(CONFIG_IPV6)) { - const struct vxlan_config *cfg = &vxlan->cfg; + const struct vxlan_config *cfg = &node->vxlan->cfg; if ((cfg->flags & VXLAN_F_IPV6_LINKLOCAL) && cfg->remote_ifindex != ifindex) continue; } - return vxlan; + return node->vxlan; } return NULL; @@ -2387,17 +2387,22 @@ static void vxlan_vs_del_dev(struct vxlan_dev *vxlan) struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); spin_lock(&vn->sock_lock); - hlist_del_init_rcu(&vxlan->hlist); + hlist_del_init_rcu(&vxlan->hlist4.hlist); +#if IS_ENABLED(CONFIG_IPV6) + hlist_del_init_rcu(&vxlan->hlist6.hlist); +#endif spin_unlock(&vn->sock_lock); } -static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan) +static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan, + struct vxlan_dev_node *node) { struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); __be32 vni = vxlan->default_dst.remote_vni; + node->vxlan = vxlan; spin_lock(&vn->sock_lock); - hlist_add_head_rcu(&vxlan->hlist, vni_head(vs, vni)); + hlist_add_head_rcu(&node->hlist, vni_head(vs, vni)); spin_unlock(&vn->sock_lock); } @@ -2849,6 +2854,7 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) { struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); struct vxlan_sock *vs = NULL; + struct vxlan_dev_node *node; if (!vxlan->cfg.no_share) { spin_lock(&vn->sock_lock); @@ -2866,12 +2872,16 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) if (IS_ERR(vs)) return PTR_ERR(vs); #if IS_ENABLED(CONFIG_IPV6) - if (ipv6) + if (ipv6) { rcu_assign_pointer(vxlan->vn6_sock, vs); - else + node = &vxlan->hlist6; + } else #endif + { rcu_assign_pointer(vxlan->vn4_sock, vs); - vxlan_vs_add_dev(vs, vxlan); + node = &vxlan->hlist4; + } + vxlan_vs_add_dev(vs, vxlan, node); return 0; } -- cgit v1.2.3 From 4b4c21fad6ae6bd58ff1566f23b0f4f70fdc9a30 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Sun, 2 Jul 2017 19:00:58 +0200 Subject: geneve: fix hlist corruption It's not a good idea to add the same hlist_node to two different hash lists. This leads to various hard to debug memory corruptions. Fixes: 8ed66f0e8235 ("geneve: implement support for IPv6-based tunnels") Cc: John W. Linville Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- drivers/net/geneve.c | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index eb77201cb718..de8156c6b292 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -45,9 +45,17 @@ struct geneve_net { static unsigned int geneve_net_id; +struct geneve_dev_node { + struct hlist_node hlist; + struct geneve_dev *geneve; +}; + /* Pseudo network device */ struct geneve_dev { - struct hlist_node hlist; /* vni hash table */ + struct geneve_dev_node hlist4; /* vni hash table for IPv4 socket */ +#if IS_ENABLED(CONFIG_IPV6) + struct geneve_dev_node hlist6; /* vni hash table for IPv6 socket */ +#endif struct net *net; /* netns for packet i/o */ struct net_device *dev; /* netdev for geneve tunnel */ struct ip_tunnel_info info; @@ -123,16 +131,16 @@ static struct geneve_dev *geneve_lookup(struct geneve_sock *gs, __be32 addr, u8 vni[]) { struct hlist_head *vni_list_head; - struct geneve_dev *geneve; + struct geneve_dev_node *node; __u32 hash; /* Find the device for this VNI */ hash = geneve_net_vni_hash(vni); vni_list_head = &gs->vni_list[hash]; - hlist_for_each_entry_rcu(geneve, vni_list_head, hlist) { - if (eq_tun_id_and_vni((u8 *)&geneve->info.key.tun_id, vni) && - addr == geneve->info.key.u.ipv4.dst) - return geneve; + hlist_for_each_entry_rcu(node, vni_list_head, hlist) { + if (eq_tun_id_and_vni((u8 *)&node->geneve->info.key.tun_id, vni) && + addr == node->geneve->info.key.u.ipv4.dst) + return node->geneve; } return NULL; } @@ -142,16 +150,16 @@ static struct geneve_dev *geneve6_lookup(struct geneve_sock *gs, struct in6_addr addr6, u8 vni[]) { struct hlist_head *vni_list_head; - struct geneve_dev *geneve; + struct geneve_dev_node *node; __u32 hash; /* Find the device for this VNI */ hash = geneve_net_vni_hash(vni); vni_list_head = &gs->vni_list[hash]; - hlist_for_each_entry_rcu(geneve, vni_list_head, hlist) { - if (eq_tun_id_and_vni((u8 *)&geneve->info.key.tun_id, vni) && - ipv6_addr_equal(&addr6, &geneve->info.key.u.ipv6.dst)) - return geneve; + hlist_for_each_entry_rcu(node, vni_list_head, hlist) { + if (eq_tun_id_and_vni((u8 *)&node->geneve->info.key.tun_id, vni) && + ipv6_addr_equal(&addr6, &node->geneve->info.key.u.ipv6.dst)) + return node->geneve; } return NULL; } @@ -591,6 +599,7 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6) { struct net *net = geneve->net; struct geneve_net *gn = net_generic(net, geneve_net_id); + struct geneve_dev_node *node; struct geneve_sock *gs; __u8 vni[3]; __u32 hash; @@ -609,15 +618,20 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6) out: gs->collect_md = geneve->collect_md; #if IS_ENABLED(CONFIG_IPV6) - if (ipv6) + if (ipv6) { rcu_assign_pointer(geneve->sock6, gs); - else + node = &geneve->hlist6; + } else #endif + { rcu_assign_pointer(geneve->sock4, gs); + node = &geneve->hlist4; + } + node->geneve = geneve; tunnel_id_to_vni(geneve->info.key.tun_id, vni); hash = geneve_net_vni_hash(vni); - hlist_add_head_rcu(&geneve->hlist, &gs->vni_list[hash]); + hlist_add_head_rcu(&node->hlist, &gs->vni_list[hash]); return 0; } @@ -644,8 +658,10 @@ static int geneve_stop(struct net_device *dev) { struct geneve_dev *geneve = netdev_priv(dev); - if (!hlist_unhashed(&geneve->hlist)) - hlist_del_rcu(&geneve->hlist); + hlist_del_init_rcu(&geneve->hlist4.hlist); +#if IS_ENABLED(CONFIG_IPV6) + hlist_del_init_rcu(&geneve->hlist6.hlist); +#endif geneve_sock_release(geneve); return 0; } -- cgit v1.2.3 From 5614fd84ebe2fb56af51e8eab0524ce4966b67c0 Mon Sep 17 00:00:00 2001 From: Christos Gkekas Date: Sun, 2 Jul 2017 23:16:11 +0100 Subject: netxen_nic: Remove unused pointer hdr in netxen_setup_minidump() Pointer hdr in netxen_setup_minidump() is set but never used, thus should be removed. Signed-off-by: Christos Gkekas Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c index e30676515529..6cec2a6a3dcc 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c @@ -174,7 +174,6 @@ netxen_setup_minidump(struct netxen_adapter *adapter) { int err = 0, i; u32 *template, *tmp_buf; - struct netxen_minidump_template_hdr *hdr; err = netxen_get_minidump_template_size(adapter); if (err) { adapter->mdump.fw_supports_md = 0; @@ -218,8 +217,6 @@ netxen_setup_minidump(struct netxen_adapter *adapter) template = (u32 *) adapter->mdump.md_template; for (i = 0; i < adapter->mdump.md_template_size/sizeof(u32); i++) *template++ = __le32_to_cpu(*tmp_buf++); - hdr = (struct netxen_minidump_template_hdr *) - adapter->mdump.md_template; adapter->mdump.md_capture_buff = NULL; adapter->mdump.fw_supports_md = 1; adapter->mdump.md_enabled = 0; -- cgit v1.2.3 From 3b68067bd2752a76868f36bf79f745451cef2a05 Mon Sep 17 00:00:00 2001 From: Zhu Yanjun Date: Mon, 3 Jul 2017 01:35:19 -0400 Subject: mlx4_en: make mlx4_log_num_mgm_entry_size static The variable mlx4_log_num_mgm_entry_size is only called in main.c. CC: Joe Jin CC: Junxiao Bi Signed-off-by: Zhu Yanjun Reviewed-by: Yuval Shaia Reviewed-by: Leon Romanovsky Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 2 +- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 457e070bca46..a27c9c13a36e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -91,7 +91,7 @@ module_param_array(probe_vf, byte, &probe_vfs_argc, 0444); MODULE_PARM_DESC(probe_vf, "number of vfs to probe by pf driver (num_vfs > 0)\n" "probe_vf=port1,port2,port1+2"); -int mlx4_log_num_mgm_entry_size = MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE; +static int mlx4_log_num_mgm_entry_size = MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE; module_param_named(log_num_mgm_entry_size, mlx4_log_num_mgm_entry_size, int, 0444); MODULE_PARM_DESC(log_num_mgm_entry_size, "log mgm size, that defines the num" diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 6ea2b7a0c34d..30616cd0140d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -230,7 +230,6 @@ do { \ #define mlx4_warn(mdev, format, ...) \ dev_warn(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__) -extern int mlx4_log_num_mgm_entry_size; extern int log_mtts_per_seg; extern int mlx4_internal_err_reset; -- cgit v1.2.3 From 25f4535a94c2b38d09912d7e8bab371c9e97be38 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Mon, 3 Jul 2017 21:55:25 +0300 Subject: qed: initialize ll2_syn_handle at start of function Fix compilation warning qed_iwarp.c:1721:5: warning: ll2_syn_handle may be used uninitialized in this function Signed-off-by: Michal Kalderon Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index 5cd20da2d4e0..b251ebaec4db 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -1724,7 +1724,7 @@ qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data) int rc; memset(&cm_info, 0, sizeof(cm_info)); - + ll2_syn_handle = p_hwfn->p_rdma_info->iwarp.ll2_syn_handle; if (GET_FIELD(data->parse_flags, PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED) && GET_FIELD(data->parse_flags, PARSING_AND_ERR_FLAGS_L4CHKSMERROR)) { @@ -1740,7 +1740,6 @@ qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data) goto err; /* Check if there is a listener for this 4-tuple+vlan */ - ll2_syn_handle = p_hwfn->p_rdma_info->iwarp.ll2_syn_handle; listener = qed_iwarp_get_listener(p_hwfn, &cm_info); if (!listener) { DP_VERBOSE(p_hwfn, -- cgit v1.2.3 From 8d32e0624392bb4abfbe122f754757a4cb326d7f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 4 Jul 2017 11:17:36 +0800 Subject: net: ethernet: mediatek: fixed deadlock captured by lockdep Lockdep found an inconsistent lock state when mtk_get_stats64 is called in user context while NAPI updates MAC statistics in softirq. Use spin_trylock_bh/spin_unlock_bh fix following lockdep warning. [ 81.321030] WARNING: inconsistent lock state [ 81.325266] 4.12.0-rc1-00035-gd9dda65 #32 Not tainted [ 81.330273] -------------------------------- [ 81.334505] inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. [ 81.340464] ksoftirqd/0/7 [HC0[0]:SC1[1]:HE1:SE0] takes: [ 81.345731] (&syncp->seq#2){+.?...}, at: [] mtk_handle_status_irq.part.6+0x70/0x84 [ 81.354219] {SOFTIRQ-ON-W} state was registered at: [ 81.359062] lock_acquire+0xfc/0x2b0 [ 81.362696] mtk_stats_update_mac+0x60/0x2c0 [ 81.367017] mtk_get_stats64+0x17c/0x18c [ 81.370995] dev_get_stats+0x48/0xbc [ 81.374628] rtnl_fill_stats+0x48/0x128 [ 81.378520] rtnl_fill_ifinfo+0x4ac/0xd1c [ 81.382584] rtmsg_ifinfo_build_skb+0x7c/0xe0 [ 81.386991] rtmsg_ifinfo.part.5+0x24/0x54 [ 81.391139] rtmsg_ifinfo+0x24/0x28 [ 81.394685] __dev_notify_flags+0xa4/0xac [ 81.398749] dev_change_flags+0x50/0x58 [ 81.402640] devinet_ioctl+0x768/0x85c [ 81.406444] inet_ioctl+0x1a4/0x1d0 [ 81.409990] sock_ioctl+0x16c/0x33c [ 81.413538] do_vfs_ioctl+0xb4/0xa34 [ 81.417169] SyS_ioctl+0x44/0x6c [ 81.420458] ret_fast_syscall+0x0/0x1c [ 81.424260] irq event stamp: 3354692 [ 81.427806] hardirqs last enabled at (3354692): [] net_rx_action+0xc0/0x504 [ 81.435660] hardirqs last disabled at (3354691): [] net_rx_action+0x8c/0x504 [ 81.443515] softirqs last enabled at (3354106): [] __do_softirq+0x4b4/0x614 [ 81.451370] softirqs last disabled at (3354109): [] run_ksoftirqd+0x44/0x80 [ 81.459134] [ 81.459134] other info that might help us debug this: [ 81.465608] Possible unsafe locking scenario: [ 81.465608] [ 81.471478] CPU0 [ 81.473900] ---- [ 81.476321] lock(&syncp->seq#2); [ 81.479701] [ 81.482294] lock(&syncp->seq#2); [ 81.485847] [ 81.485847] *** DEADLOCK *** [ 81.485847] [ 81.491720] 1 lock held by ksoftirqd/0/7: [ 81.495693] #0: (&(&mac->hw_stats->stats_lock)->rlock){+.+...}, at: [] mtk_handle_status_irq.part.6+0x48/0x84 [ 81.506579] [ 81.506579] stack backtrace: [ 81.510904] CPU: 0 PID: 7 Comm: ksoftirqd/0 Not tainted 4.12.0-rc1-00035-gd9dda65 #32 [ 81.518668] Hardware name: Mediatek Cortex-A7 (Device Tree) [ 81.524208] [] (unwind_backtrace) from [] (show_stack+0x20/0x24) [ 81.531899] [] (show_stack) from [] (dump_stack+0xb4/0xe0) [ 81.539072] [] (dump_stack) from [] (print_usage_bug+0x234/0x2e0) [ 81.546846] [] (print_usage_bug) from [] (mark_lock+0x63c/0x7bc) [ 81.554532] [] (mark_lock) from [] (__lock_acquire+0x654/0x1bfc) [ 81.562217] [] (__lock_acquire) from [] (lock_acquire+0xfc/0x2b0) [ 81.569990] [] (lock_acquire) from [] (mtk_stats_update_mac+0x60/0x2c0) [ 81.578283] [] (mtk_stats_update_mac) from [] (mtk_handle_status_irq.part.6+0x70/0x84) [ 81.587865] [] (mtk_handle_status_irq.part.6) from [] (mtk_napi_tx+0x358/0x37c) [ 81.596845] [] (mtk_napi_tx) from [] (net_rx_action+0x244/0x504) [ 81.604533] [] (net_rx_action) from [] (__do_softirq+0x134/0x614) [ 81.612306] [] (__do_softirq) from [] (run_ksoftirqd+0x44/0x80) [ 81.619907] [] (run_ksoftirqd) from [] (smpboot_thread_fn+0x14c/0x25c) [ 81.628110] [] (smpboot_thread_fn) from [] (kthread+0x150/0x180) [ 81.635798] [] (kthread) from [] (ret_from_fork+0x14/0x24) Signed-off-by: Sean Wang Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index adaaafc20532..41a5c5d2ac89 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -493,9 +493,9 @@ static void mtk_get_stats64(struct net_device *dev, unsigned int start; if (netif_running(dev) && netif_device_present(dev)) { - if (spin_trylock(&hw_stats->stats_lock)) { + if (spin_trylock_bh(&hw_stats->stats_lock)) { mtk_stats_update_mac(mac); - spin_unlock(&hw_stats->stats_lock); + spin_unlock_bh(&hw_stats->stats_lock); } } @@ -2184,9 +2184,9 @@ static void mtk_get_ethtool_stats(struct net_device *dev, return; if (netif_running(dev) && netif_device_present(dev)) { - if (spin_trylock(&hwstats->stats_lock)) { + if (spin_trylock_bh(&hwstats->stats_lock)) { mtk_stats_update_mac(mac); - spin_unlock(&hwstats->stats_lock); + spin_unlock_bh(&hwstats->stats_lock); } } -- cgit v1.2.3 From 66af846fe54b780f8f5bd9a62aee081bd2ace582 Mon Sep 17 00:00:00 2001 From: "Reshetova, Elena" Date: Tue, 4 Jul 2017 15:52:59 +0300 Subject: net, vxlan: convert vxlan_sock.refcnt from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index b04e103350fb..96aa7e6cf214 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1034,11 +1034,11 @@ static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev) /* The vxlan_sock is only used by dev, leaving group has * no effect on other vxlan devices. */ - if (family == AF_INET && sock4 && atomic_read(&sock4->refcnt) == 1) + if (family == AF_INET && sock4 && refcount_read(&sock4->refcnt) == 1) return false; #if IS_ENABLED(CONFIG_IPV6) sock6 = rtnl_dereference(dev->vn6_sock); - if (family == AF_INET6 && sock6 && atomic_read(&sock6->refcnt) == 1) + if (family == AF_INET6 && sock6 && refcount_read(&sock6->refcnt) == 1) return false; #endif @@ -1075,7 +1075,7 @@ static bool __vxlan_sock_release_prep(struct vxlan_sock *vs) if (!vs) return false; - if (!atomic_dec_and_test(&vs->refcnt)) + if (!refcount_dec_and_test(&vs->refcnt)) return false; vn = net_generic(sock_net(vs->sock->sk), vxlan_net_id); @@ -2825,7 +2825,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6, } vs->sock = sock; - atomic_set(&vs->refcnt, 1); + refcount_set(&vs->refcnt, 1); vs->flags = (flags & VXLAN_F_RCV_FLAGS); spin_lock(&vn->sock_lock); @@ -2860,7 +2860,7 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) spin_lock(&vn->sock_lock); vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET, vxlan->cfg.dst_port, vxlan->cfg.flags); - if (vs && !atomic_add_unless(&vs->refcnt, 1, 0)) { + if (vs && !refcount_inc_not_zero(&vs->refcnt)) { spin_unlock(&vn->sock_lock); return -EBUSY; } -- cgit v1.2.3 From 42af627b400f32e5b17023f39c4fc24107ca8c3d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 4 Jul 2017 16:09:59 +0100 Subject: net: macb: remove extraneous return when MACB_EXT_DESC is defined When macro MACB_EXT_DESC is defined we end up with two identical return statements and just one is sufficient. Remove the extra return. Detected by CoverityScan, CID#1449361 ("Structurally dead code") Signed-off-by: Colin Ian King Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb_main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 41e5711544fc..e69ebdd65658 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -146,7 +146,6 @@ static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int desc_idx default: break; } - return desc_idx; #endif return desc_idx; } -- cgit v1.2.3 From 2eb333c4b442c4bcab79ada53019d4a47f252e46 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 4 Jul 2017 02:27:19 -0700 Subject: nfp: improve order of interfaces in breakout mode For historical reasons we enumerate the vNICs in order. This means that if user configures breakout on a multiport card, the first interface of the second port will have its MAC address changed. What's worse, when moved from static information (HWInfo) to using management FW (NSP), more features started depending on the port ids. Right now in case of breakout first subport of the second port and second subport of the first port will have their link info swapped. Revise the ordering scheme so that first subport maintains its address. Side effect of this change is that we will use base lane ids in devlink (i.e. 40G ports will be 4 ids apart), e.g.: pci/0000:04:00.0/0: type eth netdev p6p1 pci/0000:04:00.0/4: type eth netdev p6p2 Note that behaviour of phys_port_id is not changed since there is a separate id number for the subport there. Fixes: ec8b1fbe682d ("nfp: support port splitting via devlink") Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_main.h | 2 -- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 10 +++++----- drivers/net/ethernet/netronome/nfp/nfp_port.c | 14 +++++++------- 3 files changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index a08cfba7e68e..365252ab4660 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -149,8 +149,6 @@ void nfp_net_pci_remove(struct nfp_pf *pf); int nfp_hwmon_register(struct nfp_pf *pf); void nfp_hwmon_unregister(struct nfp_pf *pf); -struct nfp_eth_table_port * -nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id); void nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_port *port, unsigned int id); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index c85a2f18c4df..bfcdada29cc0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -126,13 +126,13 @@ nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_port *port, unsigned int id) ether_addr_copy(port->netdev->perm_addr, mac_addr); } -struct nfp_eth_table_port * -nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id) +static struct nfp_eth_table_port * +nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int index) { int i; for (i = 0; eth_tbl && i < eth_tbl->count; i++) - if (eth_tbl->ports[i].eth_index == id) + if (eth_tbl->ports[i].index == index) return ð_tbl->ports[i]; return NULL; @@ -202,7 +202,7 @@ static void nfp_net_pf_free_vnics(struct nfp_pf *pf) static struct nfp_net * nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev, void __iomem *ctrl_bar, void __iomem *qc_bar, - int stride, unsigned int eth_id) + int stride, unsigned int id) { u32 tx_base, rx_base, n_tx_rings, n_rx_rings; struct nfp_net *nn; @@ -228,7 +228,7 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, bool needs_netdev, nn->stride_tx = stride; if (needs_netdev) { - err = nfp_app_vnic_init(pf->app, nn, eth_id); + err = nfp_app_vnic_init(pf->app, nn, id); if (err) { nfp_net_free(nn); return ERR_PTR(err); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_port.c b/drivers/net/ethernet/netronome/nfp/nfp_port.c index 776e54dd5dd0..e42644dbb865 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_port.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_port.c @@ -184,24 +184,24 @@ nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len) int nfp_port_init_phy_port(struct nfp_pf *pf, struct nfp_app *app, struct nfp_port *port, unsigned int id) { - port->eth_id = id; - port->eth_port = nfp_net_find_port(pf->eth_tbl, id); - /* Check if vNIC has external port associated and cfg is OK */ - if (!port->eth_port) { + if (!pf->eth_tbl || id >= pf->eth_tbl->count) { nfp_err(app->cpp, - "NSP port entries don't match vNICs (no entry for port #%d)\n", + "NSP port entries don't match vNICs (no entry %d)\n", id); return -EINVAL; } - if (port->eth_port->override_changed) { + if (pf->eth_tbl->ports[id].override_changed) { nfp_warn(app->cpp, "Config changed for port #%d, reboot required before port will be operational\n", - id); + pf->eth_tbl->ports[id].index); port->type = NFP_PORT_INVALID; return 0; } + port->eth_port = &pf->eth_tbl->ports[id]; + port->eth_id = pf->eth_tbl->ports[id].index; + return 0; } -- cgit v1.2.3 From cb2cda484840730f0f7683286fa2a25dc1dbecf0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 4 Jul 2017 02:27:20 -0700 Subject: nfp: remove legacy MAC address lookup The legacy MAC address lookup doesn't work well with breakout cables. We are probably better off picking random addresses than the wrong ones in the theoretical scenario where management FW didn't tell us what the port config is. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/flower/main.c | 3 +- drivers/net/ethernet/netronome/nfp/nfp_app_nic.c | 2 +- drivers/net/ethernet/netronome/nfp/nfp_main.h | 3 +- drivers/net/ethernet/netronome/nfp/nfp_net_main.c | 34 ++++------------------- 4 files changed, 8 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 5fe6d3582597..fc10f27e0a0c 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -245,8 +245,7 @@ nfp_flower_spawn_phy_reprs(struct nfp_app *app, struct nfp_flower_priv *priv) } SET_NETDEV_DEV(reprs->reprs[phys_port], &priv->nn->pdev->dev); - nfp_net_get_mac_addr(app->pf, port, - eth_tbl->ports[i].eth_index); + nfp_net_get_mac_addr(app->pf, port); cmsg_port_id = nfp_flower_cmsg_phys_port(phys_port); err = nfp_repr_init(app, reprs->reprs[phys_port], diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c index c11a6c34e217..4e37c81f9eaf 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c @@ -69,7 +69,7 @@ int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn, if (err) return err < 0 ? err : 0; - nfp_net_get_mac_addr(app->pf, nn->port, id); + nfp_net_get_mac_addr(app->pf, nn->port); return 0; } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h index 365252ab4660..6922410806db 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h @@ -149,8 +149,7 @@ void nfp_net_pci_remove(struct nfp_pf *pf); int nfp_hwmon_register(struct nfp_pf *pf); void nfp_hwmon_unregister(struct nfp_pf *pf); -void -nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_port *port, unsigned int id); +void nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_port *port); bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c index bfcdada29cc0..5797dbf2b507 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c @@ -84,46 +84,22 @@ static int nfp_is_ready(struct nfp_pf *pf) * nfp_net_get_mac_addr() - Get the MAC address. * @pf: NFP PF handle * @port: NFP port structure - * @id: NFP port id * * First try to get the MAC address from NSP ETH table. If that - * fails try HWInfo. As a last resort generate a random address. + * fails generate a random address. */ -void -nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_port *port, unsigned int id) +void nfp_net_get_mac_addr(struct nfp_pf *pf, struct nfp_port *port) { struct nfp_eth_table_port *eth_port; - u8 mac_addr[ETH_ALEN]; - const char *mac_str; - char name[32]; eth_port = __nfp_port_get_eth_port(port); - if (eth_port) { - ether_addr_copy(port->netdev->dev_addr, eth_port->mac_addr); - ether_addr_copy(port->netdev->perm_addr, eth_port->mac_addr); - return; - } - - snprintf(name, sizeof(name), "eth%d.mac", id); - - mac_str = nfp_hwinfo_lookup(pf->hwinfo, name); - if (!mac_str) { - nfp_warn(pf->cpp, "Can't lookup MAC address. Generate\n"); - eth_hw_addr_random(port->netdev); - return; - } - - if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - &mac_addr[0], &mac_addr[1], &mac_addr[2], - &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) { - nfp_warn(pf->cpp, "Can't parse MAC address (%s). Generate.\n", - mac_str); + if (!eth_port) { eth_hw_addr_random(port->netdev); return; } - ether_addr_copy(port->netdev->dev_addr, mac_addr); - ether_addr_copy(port->netdev->perm_addr, mac_addr); + ether_addr_copy(port->netdev->dev_addr, eth_port->mac_addr); + ether_addr_copy(port->netdev->perm_addr, eth_port->mac_addr); } static struct nfp_eth_table_port * -- cgit v1.2.3 From 64a919a9440fe080b0ad1814ce86366010d4a9ef Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 4 Jul 2017 02:27:21 -0700 Subject: nfp: default to chained metadata prepend format ABI 4.x introduced the chained metadata format and made it the only one possible. There are cases, however, where the old format is preferred - mostly to make interoperation with VFs using ABI 3.x easier for the datapath. In ABI 5.x we allowed for more flexibility by selecting the metadata format based on capabilities. The default was left to non-chained. In case of fallback traffic, there is no capability telling the driver there may be chained metadata. With a very stripped- -down FW the default old metadata format would be selected making the driver drop all fallback traffic. This patch changes the default selection in the driver. It should not hurt with old firmwares, because if they don't advertise RSS they will not produce metadata anyway. New firmwares advertising ABI 5.x, however, can depend on the driver defaulting to chained format. Fixes: f9380629fafc ("nfp: advertise support for NFD ABI 0.5") Suggested-by: Michael Rapson Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 30f82b41d400..18750ff0ede6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3719,10 +3719,17 @@ int nfp_net_init(struct nfp_net *nn) nn->cap = nn_readl(nn, NFP_NET_CFG_CAP); nn->max_mtu = nn_readl(nn, NFP_NET_CFG_MAX_MTU); - /* Chained metadata is signalled by capabilities except in version 4 */ + /* ABI 4.x and ctrl vNIC always use chained metadata, in other cases + * we allow use of non-chained metadata if RSS(v1) is the only + * advertised capability requiring metadata. + */ nn->dp.chained_metadata_format = nn->fw_ver.major == 4 || !nn->dp.netdev || + !(nn->cap & NFP_NET_CFG_CTRL_RSS) || nn->cap & NFP_NET_CFG_CTRL_CHAIN_META; + /* RSS(v1) uses non-chained metadata format, except in ABI 4.x where + * it has the same meaning as RSSv2. + */ if (nn->dp.chained_metadata_format && nn->fw_ver.major != 4) nn->cap &= ~NFP_NET_CFG_CTRL_RSS; -- cgit v1.2.3 From a456950445a075f5c28a331474dc71e4133ccd3b Mon Sep 17 00:00:00 2001 From: Atul Gupta Date: Tue, 4 Jul 2017 16:46:20 +0530 Subject: cxgb4: time stamping interface for PTP Supports hardware and software time stamping via the Linux SO_TIMESTAMPING socket option. Cc: Richard Cochran Signed-off-by: Atul Gupta Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/Makefile | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 9 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 76 +++++++++- drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c | 194 ++++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.h | 74 +++++++++ drivers/net/ethernet/chelsio/cxgb4/sge.c | 173 ++++++++++++++++++++- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 28 ++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 2 + drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 50 ++++++ 9 files changed, 595 insertions(+), 13 deletions(-) create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.h (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index c6b71f656992..817212702f0a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o -cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o cxgb4_uld.o sched.o cxgb4_filter.o cxgb4_tc_u32.o +cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o cxgb4_uld.o sched.o cxgb4_filter.o cxgb4_tc_u32.o cxgb4_ptp.o cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 451c138ff6ea..dd6e5a35c910 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include "t4_chip_type.h" #include "cxgb4_uld.h" @@ -510,6 +512,7 @@ struct port_info { #endif /* CONFIG_CHELSIO_T4_FCOE */ bool rxtstamp; /* Enable TS */ struct hwtstamp_config tstamp_config; + bool ptp_enable; struct sched_table *sched_tbl; }; @@ -705,6 +708,7 @@ struct sge_uld_txq_info { struct sge { struct sge_eth_txq ethtxq[MAX_ETH_QSETS]; + struct sge_eth_txq ptptxq; struct sge_ctrl_txq ctrlq[MAX_CTRL_QUEUES]; struct sge_eth_rxq ethrxq[MAX_ETH_QSETS]; @@ -869,6 +873,11 @@ struct adapter { * used for all 4 filters. */ + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_clock_info; + struct sk_buff *ptp_tx_skb; + /* ptp lock */ + spinlock_t ptp_lock; spinlock_t stats_lock; spinlock_t win0_lock ____cacheline_aligned_in_smp; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index f41507e040da..584aa606d1f7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -79,6 +79,7 @@ #include "l2t.h" #include "sched.h" #include "cxgb4_tc_u32.h" +#include "cxgb4_ptp.h" char cxgb4_driver_name[] = KBUILD_MODNAME; @@ -872,6 +873,14 @@ static int setup_sge_queues(struct adapter *adap) goto freeout; } + if (!is_t4(adap->params.chip)) { + err = t4_sge_alloc_eth_txq(adap, &s->ptptxq, adap->port[0], + netdev_get_tx_queue(adap->port[0], 0) + , s->fw_evtq.cntxt_id); + if (err) + goto freeout; + } + t4_write_reg(adap, is_t4(adap->params.chip) ? MPS_TRC_RSS_CONTROL_A : MPS_T5_TRC_RSS_CONTROL_A, @@ -2438,6 +2447,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) unsigned int mbox; int ret = 0, prtad, devad; struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data; switch (cmd) { @@ -2475,18 +2485,69 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) sizeof(pi->tstamp_config))) return -EFAULT; - switch (pi->tstamp_config.rx_filter) { - case HWTSTAMP_FILTER_NONE: + if (!is_t4(adapter->params.chip)) { + switch (pi->tstamp_config.tx_type) { + case HWTSTAMP_TX_OFF: + case HWTSTAMP_TX_ON: + break; + default: + return -ERANGE; + } + + switch (pi->tstamp_config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + pi->rxtstamp = false; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + cxgb4_ptprx_timestamping(pi, pi->port_id, + PTP_TS_L4); + break; + case HWTSTAMP_FILTER_PTP_V2_EVENT: + cxgb4_ptprx_timestamping(pi, pi->port_id, + PTP_TS_L2_L4); + break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + pi->rxtstamp = true; + break; + default: + pi->tstamp_config.rx_filter = + HWTSTAMP_FILTER_NONE; + return -ERANGE; + } + + if ((pi->tstamp_config.tx_type == HWTSTAMP_TX_OFF) && + (pi->tstamp_config.rx_filter == + HWTSTAMP_FILTER_NONE)) { + if (cxgb4_ptp_txtype(adapter, pi->port_id) >= 0) + pi->ptp_enable = false; + } + + if (pi->tstamp_config.rx_filter != + HWTSTAMP_FILTER_NONE) { + if (cxgb4_ptp_redirect_rx_packet(adapter, + pi) >= 0) + pi->ptp_enable = true; + } + } else { + /* For T4 Adapters */ + switch (pi->tstamp_config.rx_filter) { + case HWTSTAMP_FILTER_NONE: pi->rxtstamp = false; break; - case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_ALL: pi->rxtstamp = true; break; - default: - pi->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; + default: + pi->tstamp_config.rx_filter = + HWTSTAMP_FILTER_NONE; return -ERANGE; + } } - return copy_to_user(req->ifr_data, &pi->tstamp_config, sizeof(pi->tstamp_config)) ? -EFAULT : 0; @@ -4240,6 +4301,9 @@ static void cfg_queues(struct adapter *adap) for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) s->ctrlq[i].q.size = 512; + if (!is_t4(adap->params.chip)) + s->ptptxq.q.size = 8; + init_rspq(adap, &s->fw_evtq, 0, 1, 1024, 64); init_rspq(adap, &s->intrq, 0, 1, 512, 64); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c new file mode 100644 index 000000000000..0efcbad2d2d6 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c @@ -0,0 +1,194 @@ +/* + * cxgb4_ptp.c:Chelsio PTP support for T5/T6 + * + * Copyright (c) 2003-2017 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Written by: Atul Gupta (atul.gupta@chelsio.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cxgb4.h" +#include "t4_hw.h" +#include "t4_regs.h" +#include "t4_msg.h" +#include "t4fw_api.h" +#include "cxgb4_ptp.h" + +/** + * cxgb4_ptp_is_ptp_tx - determine whether TX packet is PTP or not + * @skb: skb of outgoing ptp request + * + */ +bool cxgb4_ptp_is_ptp_tx(struct sk_buff *skb) +{ + struct udphdr *uh; + + uh = udp_hdr(skb); + return skb->len >= PTP_MIN_LENGTH && + skb->len <= PTP_IN_TRANSMIT_PACKET_MAXNUM && + likely(skb->protocol == htons(ETH_P_IP)) && + ip_hdr(skb)->protocol == IPPROTO_UDP && + uh->dest == htons(PTP_EVENT_PORT); +} + +bool is_ptp_enabled(struct sk_buff *skb, struct net_device *dev) +{ + struct port_info *pi; + + pi = netdev_priv(dev); + return (pi->ptp_enable && cxgb4_xmit_with_hwtstamp(skb) && + cxgb4_ptp_is_ptp_tx(skb)); +} + +/** + * cxgb4_ptp_is_ptp_rx - determine whether RX packet is PTP or not + * @skb: skb of incoming ptp request + * + */ +bool cxgb4_ptp_is_ptp_rx(struct sk_buff *skb) +{ + struct udphdr *uh = (struct udphdr *)(skb->data + ETH_HLEN + + IPV4_HLEN(skb->data)); + + return uh->dest == htons(PTP_EVENT_PORT) && + uh->source == htons(PTP_EVENT_PORT); +} + +/** + * cxgb4_ptp_read_hwstamp - read timestamp for TX event PTP message + * @adapter: board private structure + * @pi: port private structure + * + */ +void cxgb4_ptp_read_hwstamp(struct adapter *adapter, struct port_info *pi) +{ + struct skb_shared_hwtstamps *skb_ts = NULL; + u64 tx_ts; + + skb_ts = skb_hwtstamps(adapter->ptp_tx_skb); + + tx_ts = t4_read_reg(adapter, + T5_PORT_REG(pi->port_id, MAC_PORT_TX_TS_VAL_LO)); + + tx_ts |= (u64)t4_read_reg(adapter, + T5_PORT_REG(pi->port_id, + MAC_PORT_TX_TS_VAL_HI)) << 32; + skb_ts->hwtstamp = ns_to_ktime(tx_ts); + skb_tstamp_tx(adapter->ptp_tx_skb, skb_ts); + dev_kfree_skb_any(adapter->ptp_tx_skb); + spin_lock(&adapter->ptp_lock); + adapter->ptp_tx_skb = NULL; + spin_unlock(&adapter->ptp_lock); +} + +/** + * cxgb4_ptprx_timestamping - Enable Timestamp for RX PTP event message + * @pi: port private structure + * @port: pot number + * @mode: RX mode + * + */ +int cxgb4_ptprx_timestamping(struct port_info *pi, u8 port, u16 mode) +{ + struct adapter *adapter = pi->adapter; + struct fw_ptp_cmd c; + int err; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F | + FW_PTP_CMD_PORTID_V(port)); + c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); + c.u.init.sc = FW_PTP_SC_RXTIME_STAMP; + c.u.init.mode = cpu_to_be16(mode); + + err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); + if (err < 0) + dev_err(adapter->pdev_dev, + "PTP: %s error %d\n", __func__, -err); + return err; +} + +int cxgb4_ptp_txtype(struct adapter *adapter, u8 port) +{ + struct fw_ptp_cmd c; + int err; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F | + FW_PTP_CMD_PORTID_V(port)); + c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); + c.u.init.sc = FW_PTP_SC_TX_TYPE; + c.u.init.mode = cpu_to_be16(PTP_TS_NONE); + + err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); + if (err < 0) + dev_err(adapter->pdev_dev, + "PTP: %s error %d\n", __func__, -err); + + return err; +} + +int cxgb4_ptp_redirect_rx_packet(struct adapter *adapter, struct port_info *pi) +{ + struct sge *s = &adapter->sge; + struct sge_eth_rxq *receive_q = &s->ethrxq[pi->first_qset]; + struct fw_ptp_cmd c; + int err; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F | + FW_PTP_CMD_PORTID_V(pi->port_id)); + + c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); + c.u.init.sc = FW_PTP_SC_RDRX_TYPE; + c.u.init.txchan = pi->tx_chan; + c.u.init.absid = cpu_to_be16(receive_q->rspq.abs_id); + + err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); + if (err < 0) + dev_err(adapter->pdev_dev, + "PTP: %s error %d\n", __func__, -err); + return err; +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.h new file mode 100644 index 000000000000..cccfae84bb84 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.h @@ -0,0 +1,74 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2017 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __CXGB4_PTP_H__ +#define __CXGB4_PTP_H__ + +/* Maximum parts-per-billion adjustment that is acceptable */ +#define MAX_PTP_FREQ_ADJ 1000000 +#define PTP_CLOCK_MAX_ADJTIME 10000000 /* 10 ms */ + +#define PTP_MIN_LENGTH 63 +#define PTP_IN_TRANSMIT_PACKET_MAXNUM 240 +#define PTP_EVENT_PORT 319 + +enum ptp_rx_filter_mode { + PTP_TS_NONE = 0, + PTP_TS_L2, + PTP_TS_L4, + PTP_TS_L2_L4 +}; + +struct port_info; + +static inline bool cxgb4_xmit_with_hwtstamp(struct sk_buff *skb) +{ + return skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP; +} + +static inline void cxgb4_xmit_hwtstamp_pending(struct sk_buff *skb) +{ + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; +} + +void cxgb4_ptp_init(struct adapter *adap); +void cxgb4_ptp_stop(struct adapter *adap); +bool cxgb4_ptp_is_ptp_tx(struct sk_buff *skb); +bool cxgb4_ptp_is_ptp_rx(struct sk_buff *skb); +int cxgb4_ptprx_timestamping(struct port_info *pi, u8 port, u16 mode); +int cxgb4_ptp_redirect_rx_packet(struct adapter *adap, struct port_info *pi); +int cxgb4_ptp_txtype(struct adapter *adap, u8 port_id); +void cxgb4_ptp_read_hwstamp(struct adapter *adap, struct port_info *pi); +bool is_ptp_enabled(struct sk_buff *skb, struct net_device *dev); +#endif /* __CXGB4_PTP_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index f05f0d400324..ede12209f20b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -52,6 +52,7 @@ #include "t4_values.h" #include "t4_msg.h" #include "t4fw_api.h" +#include "cxgb4_ptp.h" /* * Rx buffer size. We use largish buffers if possible but settle for single @@ -1162,7 +1163,7 @@ cxgb_fcoe_offload(struct sk_buff *skb, struct adapter *adap, */ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) { - u32 wr_mid, ctrl0; + u32 wr_mid, ctrl0, op; u64 cntrl, *end; int qidx, credits; unsigned int flits, ndesc; @@ -1175,6 +1176,7 @@ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t addr[MAX_SKB_FRAGS + 1]; bool immediate = false; int len, max_pkt_len; + bool ptp_enabled = is_ptp_enabled(skb, dev); #ifdef CONFIG_CHELSIO_T4_FCOE int err; #endif /* CONFIG_CHELSIO_T4_FCOE */ @@ -1198,15 +1200,31 @@ out_free: dev_kfree_skb_any(skb); pi = netdev_priv(dev); adap = pi->adapter; qidx = skb_get_queue_mapping(skb); - q = &adap->sge.ethtxq[qidx + pi->first_qset]; + if (ptp_enabled) { + spin_lock(&adap->ptp_lock); + if (!(adap->ptp_tx_skb)) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + adap->ptp_tx_skb = skb_get(skb); + } else { + spin_unlock(&adap->ptp_lock); + goto out_free; + } + q = &adap->sge.ptptxq; + } else { + q = &adap->sge.ethtxq[qidx + pi->first_qset]; + } + skb_tx_timestamp(skb); reclaim_completed_tx(adap, &q->q, true); cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F; #ifdef CONFIG_CHELSIO_T4_FCOE err = cxgb_fcoe_offload(skb, adap, pi, &cntrl); - if (unlikely(err == -ENOTSUPP)) + if (unlikely(err == -ENOTSUPP)) { + if (ptp_enabled) + spin_unlock(&adap->ptp_lock); goto out_free; + } #endif /* CONFIG_CHELSIO_T4_FCOE */ flits = calc_tx_flits(skb); @@ -1218,6 +1236,8 @@ out_free: dev_kfree_skb_any(skb); dev_err(adap->pdev_dev, "%s: Tx ring %u full while queue awake!\n", dev->name, qidx); + if (ptp_enabled) + spin_unlock(&adap->ptp_lock); return NETDEV_TX_BUSY; } @@ -1227,6 +1247,8 @@ out_free: dev_kfree_skb_any(skb); if (!immediate && unlikely(map_skb(adap->pdev_dev, skb, addr) < 0)) { q->mapping_err++; + if (ptp_enabled) + spin_unlock(&adap->ptp_lock); goto out_free; } @@ -1279,7 +1301,11 @@ out_free: dev_kfree_skb_any(skb); q->tx_cso += ssi->gso_segs; } else { len += sizeof(*cpl); - wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) | + if (ptp_enabled) + op = FW_PTP_TX_PKT_WR; + else + op = FW_ETH_TX_PKT_WR; + wr->op_immdlen = htonl(FW_WR_OP_V(op) | FW_WR_IMMDLEN_V(len)); cpl = (void *)(wr + 1); if (skb->ip_summed == CHECKSUM_PARTIAL) { @@ -1301,6 +1327,8 @@ out_free: dev_kfree_skb_any(skb); ctrl0 = TXPKT_OPCODE_V(CPL_TX_PKT_XT) | TXPKT_INTF_V(pi->tx_chan) | TXPKT_PF_V(adap->pf); + if (ptp_enabled) + ctrl0 |= TXPKT_TSTAMP_F; #ifdef CONFIG_CHELSIO_T4_DCB if (is_t4(adap->params.chip)) ctrl0 |= TXPKT_OVLAN_IDX_V(q->dcb_prio); @@ -1332,6 +1360,8 @@ out_free: dev_kfree_skb_any(skb); txq_advance(&q->q, ndesc); ring_tx_db(adap, &q->q, ndesc); + if (ptp_enabled) + spin_unlock(&adap->ptp_lock); return NETDEV_TX_OK; } @@ -2023,6 +2053,92 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, rxq->stats.rx_cso++; } +enum { + RX_NON_PTP_PKT = 0, + RX_PTP_PKT_SUC = 1, + RX_PTP_PKT_ERR = 2 +}; + +/** + * t4_systim_to_hwstamp - read hardware time stamp + * @adap: the adapter + * @skb: the packet + * + * Read Time Stamp from MPS packet and insert in skb which + * is forwarded to PTP application + */ +static noinline int t4_systim_to_hwstamp(struct adapter *adapter, + struct sk_buff *skb) +{ + struct skb_shared_hwtstamps *hwtstamps; + struct cpl_rx_mps_pkt *cpl = NULL; + unsigned char *data; + int offset; + + cpl = (struct cpl_rx_mps_pkt *)skb->data; + if (!(CPL_RX_MPS_PKT_TYPE_G(ntohl(cpl->op_to_r1_hi)) & + X_CPL_RX_MPS_PKT_TYPE_PTP)) + return RX_PTP_PKT_ERR; + + data = skb->data + sizeof(*cpl); + skb_pull(skb, 2 * sizeof(u64) + sizeof(struct cpl_rx_mps_pkt)); + offset = ETH_HLEN + IPV4_HLEN(skb->data) + UDP_HLEN; + if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(short)) + return RX_PTP_PKT_ERR; + + hwtstamps = skb_hwtstamps(skb); + memset(hwtstamps, 0, sizeof(*hwtstamps)); + hwtstamps->hwtstamp = ns_to_ktime(be64_to_cpu(*((u64 *)data))); + + return RX_PTP_PKT_SUC; +} + +/** + * t4_rx_hststamp - Recv PTP Event Message + * @adap: the adapter + * @rsp: the response queue descriptor holding the RX_PKT message + * @skb: the packet + * + * PTP enabled and MPS packet, read HW timestamp + */ +static int t4_rx_hststamp(struct adapter *adapter, const __be64 *rsp, + struct sge_eth_rxq *rxq, struct sk_buff *skb) +{ + int ret; + + if (unlikely((*(u8 *)rsp == CPL_RX_MPS_PKT) && + !is_t4(adapter->params.chip))) { + ret = t4_systim_to_hwstamp(adapter, skb); + if (ret == RX_PTP_PKT_ERR) { + kfree_skb(skb); + rxq->stats.rx_drops++; + } + return ret; + } + return RX_NON_PTP_PKT; +} + +/** + * t4_tx_hststamp - Loopback PTP Transmit Event Message + * @adap: the adapter + * @skb: the packet + * @dev: the ingress net device + * + * Read hardware timestamp for the loopback PTP Tx event message + */ +static int t4_tx_hststamp(struct adapter *adapter, struct sk_buff *skb, + struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + + if (!is_t4(adapter->params.chip) && adapter->ptp_tx_skb) { + cxgb4_ptp_read_hwstamp(adapter, pi); + kfree_skb(skb); + return 0; + } + return 1; +} + /** * t4_ethrx_handler - process an ingress ethernet packet * @q: the response queue that received the packet @@ -2038,11 +2154,13 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, struct sk_buff *skb; const struct cpl_rx_pkt *pkt; struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); + struct adapter *adapter = q->adap; struct sge *s = &q->adap->sge; int cpl_trace_pkt = is_t4(q->adap->params.chip) ? CPL_TRACE_PKT : CPL_TRACE_PKT_T5; u16 err_vec; struct port_info *pi; + int ret = 0; if (unlikely(*(u8 *)rsp == cpl_trace_pkt)) return handle_trace_pkt(q->adap, si); @@ -2068,8 +2186,25 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, rxq->stats.rx_drops++; return 0; } + pi = netdev_priv(q->netdev); + + /* Handle PTP Event Rx packet */ + if (unlikely(pi->ptp_enable)) { + ret = t4_rx_hststamp(adapter, rsp, rxq, skb); + if (ret == RX_PTP_PKT_ERR) + return 0; + } + if (likely(!ret)) + __skb_pull(skb, s->pktshift); /* remove ethernet header pad */ + + /* Handle the PTP Event Tx Loopback packet */ + if (unlikely(pi->ptp_enable && !ret && + (pkt->l2info & htonl(RXF_UDP_F)) && + cxgb4_ptp_is_ptp_rx(skb))) { + if (!t4_tx_hststamp(adapter, skb, q->netdev)) + return 0; + } - __skb_pull(skb, s->pktshift); /* remove ethernet header padding */ skb->protocol = eth_type_trans(skb, q->netdev); skb_record_rx_queue(skb, q->idx); if (skb->dev->features & NETIF_F_RXHASH) @@ -2078,7 +2213,6 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, rxq->stats.pkts++; - pi = netdev_priv(skb->dev); if (pi->rxtstamp) cxgb4_sgetim_to_hwtstamp(q->adap, skb_hwtstamps(skb), si->sgetstamp); @@ -2502,6 +2636,20 @@ static void sge_tx_timer_cb(unsigned long data) tasklet_schedule(&txq->qresume_tsk); } + if (!is_t4(adap->params.chip)) { + struct sge_eth_txq *q = &s->ptptxq; + int avail; + + spin_lock(&adap->ptp_lock); + avail = reclaimable(&q->q); + + if (avail) { + free_tx_desc(adap, &q->q, avail, false); + q->q.in_use -= avail; + } + spin_unlock(&adap->ptp_lock); + } + budget = MAX_TIMER_TX_RECLAIM; i = s->ethtxq_rover; do { @@ -3068,6 +3216,19 @@ void t4_free_sge_resources(struct adapter *adap) if (adap->sge.intrq.desc) free_rspq_fl(adap, &adap->sge.intrq, NULL); + if (!is_t4(adap->params.chip)) { + etq = &adap->sge.ptptxq; + if (etq->q.desc) { + t4_eth_eq_free(adap, adap->mbox, adap->pf, 0, + etq->q.cntxt_id); + spin_lock_bh(&adap->ptp_lock); + free_tx_desc(adap, &etq->q, etq->q.in_use, true); + spin_unlock_bh(&adap->ptp_lock); + kfree(etq->q.sdesc); + free_txq(adap, &etq->q); + } + } + /* clear the reverse egress queue map */ memset(adap->sge.egr_map, 0, adap->sge.egr_sz * sizeof(*adap->sge.egr_map)); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 8098c93cd16e..b0ff78da8aa2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -92,6 +92,7 @@ enum { CPL_RDMA_TERMINATE = 0xA2, CPL_RDMA_WRITE = 0xA4, CPL_SGE_EGR_UPDATE = 0xA5, + CPL_RX_MPS_PKT = 0xAF, CPL_TRACE_PKT = 0xB0, CPL_ISCSI_DATA = 0xB2, @@ -807,6 +808,10 @@ struct cpl_tx_pkt { #define TXPKT_INS_OVLAN_V(x) ((x) << TXPKT_INS_OVLAN_S) #define TXPKT_INS_OVLAN_F TXPKT_INS_OVLAN_V(1U) +#define TXPKT_TSTAMP_S 23 +#define TXPKT_TSTAMP_V(x) ((x) << TXPKT_TSTAMP_S) +#define TXPKT_TSTAMP_F TXPKT_TSTAMP_V(1ULL) + #define TXPKT_OPCODE_S 24 #define TXPKT_OPCODE_V(x) ((x) << TXPKT_OPCODE_S) @@ -1875,4 +1880,27 @@ struct cpl_rx_phys_dsgl { (((x) >> CPL_RX_PHYS_DSGL_NOOFSGENTR_S) & \ CPL_RX_PHYS_DSGL_NOOFSGENTR_M) +struct cpl_rx_mps_pkt { + __be32 op_to_r1_hi; + __be32 r1_lo_length; +}; + +#define CPL_RX_MPS_PKT_OP_S 24 +#define CPL_RX_MPS_PKT_OP_M 0xff +#define CPL_RX_MPS_PKT_OP_V(x) ((x) << CPL_RX_MPS_PKT_OP_S) +#define CPL_RX_MPS_PKT_OP_G(x) \ + (((x) >> CPL_RX_MPS_PKT_OP_S) & CPL_RX_MPS_PKT_OP_M) + +#define CPL_RX_MPS_PKT_TYPE_S 20 +#define CPL_RX_MPS_PKT_TYPE_M 0xf +#define CPL_RX_MPS_PKT_TYPE_V(x) ((x) << CPL_RX_MPS_PKT_TYPE_S) +#define CPL_RX_MPS_PKT_TYPE_G(x) \ + (((x) >> CPL_RX_MPS_PKT_TYPE_S) & CPL_RX_MPS_PKT_TYPE_M) + +enum { + X_CPL_RX_MPS_PKT_TYPE_PAUSE = 1 << 0, + X_CPL_RX_MPS_PKT_TYPE_PPP = 1 << 1, + X_CPL_RX_MPS_PKT_TYPE_QFC = 1 << 2, + X_CPL_RX_MPS_PKT_TYPE_PTP = 1 << 3 +}; #endif /* __T4_MSG_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 3884336ce23c..dac90837842b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -1799,6 +1799,8 @@ #define MPS_PORT_STAT_RX_PORT_LESS_64B_H 0x614 #define MAC_PORT_MAGIC_MACID_LO 0x824 #define MAC_PORT_MAGIC_MACID_HI 0x828 +#define MAC_PORT_TX_TS_VAL_LO 0x928 +#define MAC_PORT_TX_TS_VAL_HI 0x92c #define MAC_PORT_EPIO_DATA0_A 0x8c0 #define MAC_PORT_EPIO_DATA1_A 0x8c4 diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index f2ffc1f6b8be..0ebed64d62d3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -103,6 +103,7 @@ enum fw_wr_opcodes { FW_RI_FR_NSMR_TPTE_WR = 0x20, FW_RI_INV_LSTAG_WR = 0x1a, FW_ISCSI_TX_DATA_WR = 0x45, + FW_PTP_TX_PKT_WR = 0x46, FW_CRYPTO_LOOKASIDE_WR = 0X6d, FW_LASTC2E_WR = 0x70 }; @@ -685,6 +686,7 @@ enum fw_cmd_opcodes { FW_SCHED_CMD = 0x24, FW_DEVLOG_CMD = 0x25, FW_CLIP_CMD = 0x28, + FW_PTP_CMD = 0x3e, FW_LASTC2E_CMD = 0x40, FW_ERROR_CMD = 0x80, FW_DEBUG_CMD = 0x81, @@ -2802,6 +2804,54 @@ struct fw_port_lb_stats_cmd { } u; }; +enum fw_ptp_subop { + /* none */ + FW_PTP_SC_INIT_TIMER = 0x00, + FW_PTP_SC_TX_TYPE = 0x01, + /* init */ + FW_PTP_SC_RXTIME_STAMP = 0x08, + FW_PTP_SC_RDRX_TYPE = 0x09, + /* ts */ + FW_PTP_SC_ADJ_FREQ = 0x10, + FW_PTP_SC_ADJ_TIME = 0x11, + FW_PTP_SC_ADJ_FTIME = 0x12, + FW_PTP_SC_WALL_CLOCK = 0x13, + FW_PTP_SC_GET_TIME = 0x14, + FW_PTP_SC_SET_TIME = 0x15, +}; + +struct fw_ptp_cmd { + __be32 op_to_portid; + __be32 retval_len16; + union fw_ptp { + struct fw_ptp_sc { + __u8 sc; + __u8 r3[7]; + } scmd; + struct fw_ptp_init { + __u8 sc; + __u8 txchan; + __be16 absid; + __be16 mode; + __be16 r3; + } init; + struct fw_ptp_ts { + __u8 sc; + __u8 sign; + __be16 r3; + __be32 ppb; + __be64 tm; + } ts; + } u; + __be64 r3; +}; + +#define FW_PTP_CMD_PORTID_S 0 +#define FW_PTP_CMD_PORTID_M 0xf +#define FW_PTP_CMD_PORTID_V(x) ((x) << FW_PTP_CMD_PORTID_S) +#define FW_PTP_CMD_PORTID_G(x) \ + (((x) >> FW_PTP_CMD_PORTID_S) & FW_PTP_CMD_PORTID_M) + struct fw_rss_ind_tbl_cmd { __be32 op_to_viid; __be32 retval_len16; -- cgit v1.2.3 From 9c33e4208bce512e1708781711b2846f463d2eb4 Mon Sep 17 00:00:00 2001 From: Atul Gupta Date: Tue, 4 Jul 2017 16:46:21 +0530 Subject: cxgb4: Add PTP Hardware Clock (PHC) support Add PTP IEEE-1588 support and make it accessible via PHC subsystem. The functionality is enabled for T5/T6 adapters. Driver interfaces with Firmware to program and adjust the clock offset. Cc: Richard Cochran Signed-off-by: Atul Gupta Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 6 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c | 281 ++++++++++++++++++++++++ 2 files changed, 287 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 584aa606d1f7..86f92e31e8aa 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -5202,6 +5202,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) mutex_unlock(&uld_mutex); } + if (!is_t4(adapter->params.chip)) + cxgb4_ptp_init(adapter); + print_adapter_info(adapter); setup_fw_sge_queues(adapter); return 0; @@ -5311,6 +5314,9 @@ static void remove_one(struct pci_dev *pdev) debugfs_remove_recursive(adapter->debugfs_root); + if (!is_t4(adapter->params.chip)) + cxgb4_ptp_stop(adapter); + /* If we allocated filters, free up state associated with any * valid filters ... */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c index 0efcbad2d2d6..50517cfd9671 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c @@ -192,3 +192,284 @@ int cxgb4_ptp_redirect_rx_packet(struct adapter *adapter, struct port_info *pi) "PTP: %s error %d\n", __func__, -err); return err; } + +/** + * @ptp: ptp clock structure + * @ppb: Desired frequency change in parts per billion + * + * Adjust the frequency of the PHC cycle counter by the indicated ppb from + * the base frequency. + */ +static int cxgb4_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + struct adapter *adapter = (struct adapter *)container_of(ptp, + struct adapter, ptp_clock_info); + struct fw_ptp_cmd c; + int err; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F | + FW_PTP_CMD_PORTID_V(0)); + c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); + c.u.ts.sc = FW_PTP_SC_ADJ_FREQ; + c.u.ts.sign = (ppb < 0) ? 1 : 0; + if (ppb < 0) + ppb = -ppb; + c.u.ts.ppb = cpu_to_be32(ppb); + + err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); + if (err < 0) + dev_err(adapter->pdev_dev, + "PTP: %s error %d\n", __func__, -err); + + return err; +} + +/** + * cxgb4_ptp_fineadjtime - Shift the time of the hardware clock + * @ptp: ptp clock structure + * @delta: Desired change in nanoseconds + * + * Adjust the timer by resetting the timecounter structure. + */ +static int cxgb4_ptp_fineadjtime(struct adapter *adapter, s64 delta) +{ + struct fw_ptp_cmd c; + int err; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F | + FW_PTP_CMD_PORTID_V(0)); + c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); + c.u.ts.sc = FW_PTP_SC_ADJ_FTIME; + c.u.ts.tm = cpu_to_be64(delta); + + err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); + if (err < 0) + dev_err(adapter->pdev_dev, + "PTP: %s error %d\n", __func__, -err); + return err; +} + +/** + * cxgb4_ptp_adjtime - Shift the time of the hardware clock + * @ptp: ptp clock structure + * @delta: Desired change in nanoseconds + * + * Adjust the timer by resetting the timecounter structure. + */ +static int cxgb4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct adapter *adapter = + (struct adapter *)container_of(ptp, struct adapter, + ptp_clock_info); + struct fw_ptp_cmd c; + s64 sign = 1; + int err; + + if (delta < 0) + sign = -1; + + if (delta * sign > PTP_CLOCK_MAX_ADJTIME) { + memset(&c, 0, sizeof(c)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F | + FW_PTP_CMD_PORTID_V(0)); + c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); + c.u.ts.sc = FW_PTP_SC_ADJ_TIME; + c.u.ts.sign = (delta < 0) ? 1 : 0; + if (delta < 0) + delta = -delta; + c.u.ts.tm = cpu_to_be64(delta); + + err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); + if (err < 0) + dev_err(adapter->pdev_dev, + "PTP: %s error %d\n", __func__, -err); + } else { + err = cxgb4_ptp_fineadjtime(adapter, delta); + } + + return err; +} + +/** + * cxgb4_ptp_gettime - Reads the current time from the hardware clock + * @ptp: ptp clock structure + * @ts: timespec structure to hold the current time value + * + * Read the timecounter and return the correct value in ns after converting + * it into a struct timespec. + */ +static int cxgb4_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + struct adapter *adapter = (struct adapter *)container_of(ptp, + struct adapter, ptp_clock_info); + struct fw_ptp_cmd c; + u64 ns; + int err; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_READ_F | + FW_PTP_CMD_PORTID_V(0)); + c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); + c.u.ts.sc = FW_PTP_SC_GET_TIME; + + err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), &c); + if (err < 0) { + dev_err(adapter->pdev_dev, + "PTP: %s error %d\n", __func__, -err); + return err; + } + + /* convert to timespec*/ + ns = be64_to_cpu(c.u.ts.tm); + *ts = ns_to_timespec64(ns); + + return err; +} + +/** + * cxgb4_ptp_settime - Set the current time on the hardware clock + * @ptp: ptp clock structure + * @ts: timespec containing the new time for the cycle counter + * + * Reset value to new base value instead of the kernel + * wall timer value. + */ +static int cxgb4_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct adapter *adapter = (struct adapter *)container_of(ptp, + struct adapter, ptp_clock_info); + struct fw_ptp_cmd c; + u64 ns; + int err; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F | + FW_PTP_CMD_PORTID_V(0)); + c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); + c.u.ts.sc = FW_PTP_SC_SET_TIME; + + ns = timespec64_to_ns(ts); + c.u.ts.tm = cpu_to_be64(ns); + + err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); + if (err < 0) + dev_err(adapter->pdev_dev, + "PTP: %s error %d\n", __func__, -err); + + return err; +} + +static void cxgb4_init_ptp_timer(struct adapter *adapter) +{ + struct fw_ptp_cmd c; + int err; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F | + FW_PTP_CMD_PORTID_V(0)); + c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); + c.u.scmd.sc = FW_PTP_SC_INIT_TIMER; + + err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL); + if (err < 0) + dev_err(adapter->pdev_dev, + "PTP: %s error %d\n", __func__, -err); +} + +/** + * cxgb4_ptp_enable - enable or disable an ancillary feature + * @ptp: ptp clock structure + * @request: Desired resource to enable or disable + * @on: Caller passes one to enable or zero to disable + * + * Enable (or disable) ancillary features of the PHC subsystem. + * Currently, no ancillary features are supported. + */ +static int cxgb4_ptp_enable(struct ptp_clock_info __always_unused *ptp, + struct ptp_clock_request __always_unused *request, + int __always_unused on) +{ + return -ENOTSUPP; +} + +static const struct ptp_clock_info cxgb4_ptp_clock_info = { + .owner = THIS_MODULE, + .name = "cxgb4_clock", + .max_adj = MAX_PTP_FREQ_ADJ, + .n_alarm = 0, + .n_ext_ts = 0, + .n_per_out = 0, + .pps = 0, + .adjfreq = cxgb4_ptp_adjfreq, + .adjtime = cxgb4_ptp_adjtime, + .gettime64 = cxgb4_ptp_gettime, + .settime64 = cxgb4_ptp_settime, + .enable = cxgb4_ptp_enable, +}; + +/** + * cxgb4_ptp_init - initialize PTP for devices which support it + * @adapter: board private structure + * + * This function performs the required steps for enabling PTP support. + */ +void cxgb4_ptp_init(struct adapter *adapter) +{ + struct timespec64 now; + /* no need to create a clock device if we already have one */ + if (!IS_ERR_OR_NULL(adapter->ptp_clock)) + return; + + adapter->ptp_tx_skb = NULL; + adapter->ptp_clock_info = cxgb4_ptp_clock_info; + spin_lock_init(&adapter->ptp_lock); + + adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info, + &adapter->pdev->dev); + if (!adapter->ptp_clock) { + dev_err(adapter->pdev_dev, + "PTP %s Clock registration has failed\n", __func__); + return; + } + + now = ktime_to_timespec64(ktime_get_real()); + cxgb4_init_ptp_timer(adapter); + if (cxgb4_ptp_settime(&adapter->ptp_clock_info, &now) < 0) { + ptp_clock_unregister(adapter->ptp_clock); + adapter->ptp_clock = NULL; + } +} + +/** + * cxgb4_ptp_remove - disable PTP device and stop the overflow check + * @adapter: board private structure + * + * Stop the PTP support. + */ +void cxgb4_ptp_stop(struct adapter *adapter) +{ + if (adapter->ptp_tx_skb) { + dev_kfree_skb_any(adapter->ptp_tx_skb); + adapter->ptp_tx_skb = NULL; + } + + if (adapter->ptp_clock) { + ptp_clock_unregister(adapter->ptp_clock); + adapter->ptp_clock = NULL; + } +} -- cgit v1.2.3 From c3ff08eba94ec92417bd78c0d0ad567c483eca85 Mon Sep 17 00:00:00 2001 From: Atul Gupta Date: Tue, 4 Jul 2017 16:46:22 +0530 Subject: cxgb4: Support for get_ts_info ethtool method Cc: Richard Cochran Signed-off-by: Atul Gupta Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c index e9bab72253bb..26eb00a45db1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -1113,14 +1113,31 @@ static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) static int get_ts_info(struct net_device *dev, struct ethtool_ts_info *ts_info) { + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE; ts_info->so_timestamping |= SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE; - ts_info->phc_index = -1; + ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON); + + ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); + + if (adapter->ptp_clock) + ts_info->phc_index = ptp_clock_index(adapter->ptp_clock); + else + ts_info->phc_index = -1; return 0; } -- cgit v1.2.3 From 371444764b9882d754d1e67dd212c932359a2293 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 4 Jul 2017 16:23:24 +0530 Subject: net: phy: dp83867: add workaround for incorrect RX_CTRL pin strap The data manual for DP83867IR/CR, SNLS484E[1], revised march 2017, advises that strapping RX_DV/RX_CTRL pin in mode 1 and 2 is not supported (see note below Table 5 (4-Level Strap Pins)). There are some boards which have the pin strapped this way and need software workaround suggested by the data manual. Bit[7] of Configuration Register 4 (address 0x0031) must be cleared to 0. This ensures proper operation of the PHY. Implement driver support for device-tree property meant to advertise the wrong strapping. [1] http://www.ti.com/lit/ds/snls484e/snls484e.pdf Signed-off-by: Murali Karicheri [nsekhar@ti.com: rebase to mainline, code simplification] Signed-off-by: Sekhar Nori Signed-off-by: David S. Miller --- drivers/net/phy/dp83867.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index b57f20e552ba..c1ab976cc800 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -91,6 +91,7 @@ struct dp83867_private { int fifo_depth; int io_impedance; int port_mirroring; + bool rxctrl_strap_quirk; }; static int dp83867_ack_interrupt(struct phy_device *phydev) @@ -164,6 +165,9 @@ static int dp83867_of_init(struct phy_device *phydev) else if (of_property_read_bool(of_node, "ti,min-output-impedance")) dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN; + dp83867->rxctrl_strap_quirk = of_property_read_bool(of_node, + "ti,dp83867-rxctrl-strap-quirk"); + ret = of_property_read_u32(of_node, "ti,rx-internal-delay", &dp83867->rx_id_delay); if (ret && @@ -214,6 +218,13 @@ static int dp83867_config_init(struct phy_device *phydev) dp83867 = (struct dp83867_private *)phydev->priv; } + /* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */ + if (dp83867->rxctrl_strap_quirk) { + val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4); + val &= ~BIT(7); + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4, val); + } + if (phy_interface_is_rgmii(phydev)) { val = phy_read(phydev, MII_DP83867_PHYCTRL); if (val < 0) -- cgit v1.2.3